commit a7fd79192623d101a8445ee76ec4187763885be2 Author: Ivailo Monev Date: Thu Nov 13 19:30:51 2014 +0200 initial import diff --git a/.krazy b/.krazy new file mode 100644 index 00000000..83ba0507 --- /dev/null +++ b/.krazy @@ -0,0 +1,5 @@ +#kcheckpass is mostly C, so let's not check there. +IGNORESUBS kcheckpass + +#no code in these +IGNORESUBS cursors diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..3d4287c2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,360 @@ +project(KDEBASE_WORKSPACE) +# set_package_properties appeared in cmake 2.8.6 +# TODO: Remove when kdelibs >= 4.10 will be required +cmake_minimum_required(VERSION 2.8.6 FATAL_ERROR) + +# Used e.g. in KDE4WorkspaceConfig.cmake, Alex +set(KDE4WORKSPACE_VERSION_MAJOR 4) +set(KDE4WORKSPACE_VERSION_MINOR 11) +set(KDE4WORKSPACE_VERSION_PATCH 14) +set(KDE4WORKSPACE_VERSION ${KDE4WORKSPACE_VERSION_MAJOR}.${KDE4WORKSPACE_VERSION_MINOR}.${KDE4WORKSPACE_VERSION_PATCH} ) + +# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH} ) + +#search packages used by KDE +set(QT_MIN_VERSION "4.8.0") + +find_package(KDE4 4.9.4 REQUIRED) +include(KDE4Defaults) + +option(WITH_XINERAMA "Xinerama support for multi-headed X displays" ON) + +find_package(Strigi) + +set_package_properties(Strigi PROPERTIES DESCRIPTION "Desktop indexing and search support" + URL "http://strigi.sourceforge.net" + TYPE REQUIRED + ) + +find_package(ZLIB) +set_package_properties(ZLIB PROPERTIES DESCRIPTION "Support for gzip compressed files and data streams" + URL "http://www.zlib.net" + TYPE REQUIRED + ) + +find_package(KActivities 6.0.0 CONFIG) +set_package_properties(KActivities PROPERTIES DESCRIPTION "Interface library for the activity manager" + URL "https://projects.kde.org/kactivities" + TYPE REQUIRED + ) + +find_package(DBusMenuQt 0.6.0) +set_package_properties(DBusMenuQt PROPERTIES DESCRIPTION "Support for notification area menus via the DBusMenu protocol" + URL "https://launchpad.net/libdbusmenu-qt" + TYPE REQUIRED + ) + +find_package(QImageBlitz) +set_package_properties(QImageBlitz PROPERTIES DESCRIPTION "An image effects library" + URL "http://sourceforge.net/projects/qimageblitz" + TYPE REQUIRED + ) + +find_package(KDeclarative QUIET CONFIG) +set_package_properties(KDeclarative PROPERTIES DESCRIPTION "KDE Declarative (QML) support from kdelibs" + URL "http://www.kde.org" + TYPE REQUIRED + PURPOSE "Required for building ksmserver" + ) + +macro_optional_find_package(OpenGL) +set_package_properties(OpenGL PROPERTIES DESCRIPTION "The OpenGL libraries" + URL "http://www.opengl.org" + TYPE OPTIONAL + ) +macro_optional_find_package(OpenGLES) +set_package_properties(OpenGLES PROPERTIES DESCRIPTION "The OpenGLES libraries" + URL "http://www.khronos.org/opengles" + TYPE OPTIONAL + ) +macro_optional_find_package(UDev) +set_package_properties(UDev PROPERTIES DESCRIPTION "The UDev Libraries" + TYPE OPTIONAL + PURPOSE "Allows support for UPower backend in PowerDevil - STRONGLY RECOMMENDED" + ) + +macro_optional_find_package(Wayland) +set_package_properties(Wayland PROPERTIES DESCRIPTION "The Wayland Client and Server libraries" + URL "http://wayland.freedesktop.org" + TYPE OPTIONAL + PURPOSE "Required for building KWin with Wayland support" + ) +if(Q_WS_X11) + find_package(XCB REQUIRED) + set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding" + URL "http://xcb.freedesktop.org" + TYPE REQUIRED + ) + + find_package(X11_XCB) + set_package_properties(X11_XCB PROPERTIES DESCRIPTION "XCB X11 protocol client library" + TYPE REQUIRED + ) + + find_package(X11 REQUIRED) + set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" + URL "http://www.x.org" + TYPE REQUIRED + ) + + add_feature_info("Automated testing of X clients" X11_XTest_FOUND + "The X11 Testing Resource extension library is useful for automated testing of X clients") + add_feature_info("libXau" X11_Xau_FOUND "The X11 Authorization Protocol library may be used by KDM") + add_feature_info("LibXdmcp" X11_Xdmcp_FOUND "The X Display Manager Control Protocol library may be used by KDM") + if(NOT X11_Xkbfile_FOUND) + message(FATAL_ERROR "The X11 keyboard layout library was not found. Required for building keyboard modules.") + endif() + if(NOT X11_Xcomposite_FOUND) + message(FATAL_ERROR "The X11 composite library was not found. Required for building the plasma tray and notifications widgets.") + endif() + if(NOT X11_Xdamage_FOUND) + message(FATAL_ERROR "The X11 damaged region extension library was not found. Required for compositing support in KWin.") + endif() + if(NOT X11_Xrender_FOUND) + message(FATAL_ERROR " The X Rendering Extension client library was not found. Required for XRender Compositing backend in KWin.") + endif() + if(NOT X11_Xfixes_FOUND) + message(FATAL_ERROR "The X11 miscellaneous 'fixes' extension library was not found. Required for XRender Compositing backend in KWin.") + endif() + if(NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "The X11 RandR extension library was not found. Required for Multi Screen Support.") + endif() + if(NOT OPENGL_FOUND AND NOT OPENGLES_FOUND) + message(FATAL_ERROR "Either OpenGL or OpenGL ES 2.0 are required for Compositing support in KWin.") + endif() + if(NOT X11_Xcursor_FOUND) + message(FATAL_ERROR "The X11 cursor management library was not found. Required for desktop effects support in KWin.") + endif() +endif(Q_WS_X11) + +macro_optional_find_package(GLIB2 2.0) +set_package_properties(GLIB2 PROPERTIES DESCRIPTION "Low-level core library for data structure handling, portability wrappers, etc." + URL "http://www.gtk.org" + TYPE OPTIONAL + PURPOSE "Needed to build the kxkb keyboard map control program and provide XMMS support in the Now Playing Plasma data engine" + ) + +macro_optional_find_package(Fontconfig) +set_package_properties(Fontconfig PROPERTIES DESCRIPTION "Font access configuration library" + URL "http://www.freedesktop.org/wiki/Software/fontconfig" + TYPE OPTIONAL + PURPOSE "Needed to build font configuration and installation tools" + ) + +#### Python support ( plasma scriptengines ) #### +macro_optional_find_package(PythonLibrary) +set_package_properties(PythonLibrary PROPERTIES DESCRIPTION "Python scripting language" + URL "http://python.org" + TYPE OPTIONAL + PURPOSE "Needed to build plasma scriptengine for python." + ) + +macro_optional_find_package(Soprano 2.7.56) +set_package_properties(Soprano PROPERTIES DESCRIPTION "Semantic Desktop Storing" + URL "http://soprano.sourceforge.net" + TYPE OPTIONAL + PURPOSE "Required to build Nepomuk features." + ) + +macro_optional_find_package(NepomukCore QUIET CONFIG) +set_package_properties(NepomukCore PROPERTIES DESCRIPTION "Nepomuk Core Library" + URL "https://projects.kde.org/nepomuk-core" + TYPE OPTIONAL + PURPOSE "Required to build Nepomuk features." + ) + +macro_optional_find_package(Boost 1.34.0 MODULE) +set_package_properties(Boost PROPERTIES DESCRIPTION "Boost C++ Libraries" + URL "http://www.boost.org" + TYPE OPTIONAL + PURPOSE "Required to build certain Plasma DataEngines (Akonadi, RSS, Calendar)" + ) + +macro_optional_find_package(Akonadi QUIET CONFIG) +set_package_properties(Akonadi PROPERTIES DESCRIPTION "An extensible cross-desktop storage service for PIM data" + URL "http://pim.kde.org/akonadi" + TYPE OPTIONAL + PURPOSE "Required to build certain Plasma DataEngines (Akonadi, Calendar)" + ) + +macro_optional_find_package(KdepimLibs 4.10.68 QUIET CONFIG) +set_package_properties(KdepimLibs PROPERTIES DESCRIPTION "The KDEPIM libraries" + URL "http://pim.kde.org" + TYPE OPTIONAL + PURPOSE "Required to build certain Plasma DataEngines (Akonadi, Calendar)" + ) + +macro_optional_find_package(QJSON) +set_package_properties(QJSON PROPERTIES DESCRIPTION "Library to manage JSON objects with Qt" + URL "http://qjson.sourceforge.net/" + TYPE OPTIONAL + PURPOSE "Required to build Chrome/Chromium support for Plasma Bookmarks Runners" + ) + + +include(ConfigureChecks.cmake) +if(NOT WIN32) + configure_file(config-unix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-unix.h ) + configure_file(config-X11.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-X11.h ) + if(NOT CMAKE_INSTALL_PREFIX STREQUAL "/usr") + set(EXPORT_XCURSOR_PATH "XCURSOR_PATH=${CMAKE_INSTALL_PREFIX}/share/icons:$XCURSOR_PATH\":~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons\"; export XCURSOR_PATH") + endif(NOT CMAKE_INSTALL_PREFIX STREQUAL "/usr") + configure_file(startkde.cmake ${CMAKE_CURRENT_BINARY_DIR}/startkde @ONLY) +endif(NOT WIN32) +configure_file(config-workspace.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-workspace.h ) + +add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS} -DHAVE_CONFIG_H=1) +add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) +include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} ${KACTIVITIES_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/libs) + +add_definitions(-DDISABLE_NEPOMUK_LEGACY) + +# libs +add_subdirectory(cmake) +add_subdirectory(libs) + +# system settings (kcontrol replacement) +if(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop") + macro_optional_add_subdirectory( systemsettings ) +endif(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop") + +# core apps +if(NOT WIN32) + macro_optional_add_subdirectory( kcheckpass ) + macro_optional_add_subdirectory( kwin ) + macro_optional_add_subdirectory( ksmserver ) + + find_package(JPEG REQUIRED) + find_package(PNG REQUIRED) + macro_optional_add_subdirectory( ksplash ) + + macro_optional_add_subdirectory( powerdevil ) + macro_optional_add_subdirectory( qguiplatformplugin_kde ) + if (NOT CMAKE_SYSTEM_NAME MATCHES Darwin) + macro_optional_add_subdirectory( ksysguard ) + endif (NOT CMAKE_SYSTEM_NAME MATCHES Darwin) +endif(NOT WIN32) + +if(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop") + macro_optional_add_subdirectory(kcontrol) + macro_optional_add_subdirectory(klipper) + macro_optional_add_subdirectory(kmenuedit) + macro_optional_add_subdirectory(krunner) + macro_optional_add_subdirectory(solid-actions-kcm) + macro_optional_add_subdirectory(kstartupconfig) + macro_optional_add_subdirectory(freespacenotifier) + macro_optional_add_subdirectory(kscreensaver) + macro_optional_add_subdirectory(kinfocenter) + + # data + macro_optional_add_subdirectory(doc) + + if (Q_WS_X11) + macro_optional_add_subdirectory(ktouchpadenabler) + endif (Q_WS_X11) + + if(NOT WIN32) + macro_optional_add_subdirectory(kcminit) + macro_optional_add_subdirectory(khotkeys) + macro_optional_add_subdirectory(kwrited) + macro_optional_add_subdirectory(ksystraycmd) + macro_optional_add_subdirectory(appmenu) + endif(NOT WIN32) + + if(X11_Xau_FOUND AND X11_Xdmcp_FOUND) + macro_optional_add_subdirectory( kdm ) + else(X11_Xau_FOUND AND X11_Xdmcp_FOUND) + message(STATUS "Xau lib or Xdmcp lib was missing. kdm will not compile") + endif(X11_Xau_FOUND AND X11_Xdmcp_FOUND) +endif(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop") + +if(NOT WIN32) + # data + macro_optional_add_subdirectory(cursors) +endif(NOT WIN32) + +macro_optional_add_subdirectory(plasma) +macro_optional_add_subdirectory(statusnotifierwatcher) +macro_optional_add_subdirectory(kstyles) + +########### install files ############### +if(NOT WIN32) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/startkde DESTINATION ${BIN_INSTALL_DIR}) +endif(NOT WIN32) + +feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) + +# make the libraries installed from kdebase/workspace available to other projects +# by creating and installing a KDE4WorkspaceConfig.cmake file, which will +# be searched and found by kdelibs/cmake/modules/FindKDE4Workspace.cmake. Alex + +# now create the KDE4WorkspaceConfig.cmake file, which will be loaded by +# kdelibs/cmake/modules/FindKDE4Workspace.cmake and which has to contain all information +# about the libraries installed from kdebase/workspace/libs/ anybody would like to have. Alex + +# we need the absolute directories where stuff will be installed too +# but since the variables which contain the destinations can be relative +# or absolute paths, we need this macro to make them all absoulte, Alex +macro(MAKE_INSTALL_PATH_ABSOLUTE out in) + if (IS_ABSOLUTE "${in}") # IS_ABSOLUTE is new since cmake 2.4.8 + set(${out} "${in}") + else (IS_ABSOLUTE "${in}") + set(${out} "\${KDE4WORKSPACE_INSTALL_DIR}/${in}") + endif (IS_ABSOLUTE "${in}") +endmacro(MAKE_INSTALL_PATH_ABSOLUTE out in) + +make_install_path_absolute(KDE4WORKSPACE_LIB_DIR ${LIB_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_LIBEXEC_DIR ${LIBEXEC_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_INCLUDE_DIR ${INCLUDE_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_BIN_DIR ${BIN_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_SBIN_DIR ${SBIN_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_DATA_DIR ${DATA_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_HTML_DIR ${HTML_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_CONFIG_DIR ${CONFIG_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_ICON_DIR ${ICON_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_KCFG_DIR ${KCFG_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_LOCALE_DIR ${LOCALE_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_MIME_DIR ${MIME_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_SOUND_DIR ${SOUND_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_TEMPLATES_DIR ${TEMPLATES_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_WALLPAPER_DIR ${WALLPAPER_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_KCONF_UPDATE_DIR ${KCONF_UPDATE_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_AUTOSTART_DIR ${AUTOSTART_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_XDG_APPS_DIR ${XDG_APPS_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_XDG_DIRECTORY_DIR ${XDG_DIRECTORY_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_SYSCONF_DIR ${SYSCONF_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_MAN_DIR ${MAN_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_INFO_DIR ${INFO_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_DBUS_INTERFACES_DIR ${DBUS_INTERFACES_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_DBUS_SERVICES_DIR ${DBUS_SERVICES_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_SERVICES_DIR ${SERVICES_INSTALL_DIR}) +make_install_path_absolute(KDE4WORKSPACE_SERVICETYPES_DIR ${SERVICETYPES_INSTALL_DIR}) + +set(KDE4WORKSPACE_TARGET_PREFIX KDE4Workspace__) + +configure_file(KDE4WorkspaceConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/KDE4WorkspaceConfig.cmake" @ONLY) + +# this file will be installed too and will be used by cmake when searching for the Config.cmake file to check the version of kdepimlibs, Alex +macro_write_basic_cmake_version_file(${CMAKE_CURRENT_BINARY_DIR}/KDE4WorkspaceConfigVersion.cmake + ${KDE4WORKSPACE_VERSION_MAJOR} ${KDE4WORKSPACE_VERSION_MINOR} ${KDE4WORKSPACE_VERSION_PATCH}) + +set(_KDE4WorkspaceConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/KDE4Workspace/cmake) +# places where find_package() looks for FooConfig.cmake files: +# CMake >= 2.6.0 looks in lib/Foo*/cmake/, CMake >= 2.6.3 also looks in +# lib/cmake/Foo*/, which packagers prefer. So they can set the KDE4_USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR +# option to have kdepimlibs install its Config file there. Alex +if(KDE4_USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) + set(_KDE4WorkspaceConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/KDE4Workspace) +endif(KDE4_USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KDE4WorkspaceConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/KDE4WorkspaceConfigVersion.cmake + DESTINATION ${_KDE4WorkspaceConfig_INSTALL_DIR}) + +install(EXPORT kdeworkspaceLibraryTargets + NAMESPACE ${KDE4WORKSPACE_TARGET_PREFIX} + DESTINATION ${_KDE4WorkspaceConfig_INSTALL_DIR} + FILE KDE4WorkspaceLibraryTargets.cmake ) + + diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..5185fd3f --- /dev/null +++ b/COPYING @@ -0,0 +1,346 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + 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 Library 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. + + + Copyright (C) 19yy + + 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) 19yy 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. + + , 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 Library General +Public License instead of this License. diff --git a/COPYING.DOC b/COPYING.DOC new file mode 100644 index 00000000..4a0fe1c8 --- /dev/null +++ b/COPYING.DOC @@ -0,0 +1,397 @@ + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 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. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document 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. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation 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. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 00000000..2d2d780e --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/CTestConfig.cmake b/CTestConfig.cmake new file mode 100644 index 00000000..7db6e84d --- /dev/null +++ b/CTestConfig.cmake @@ -0,0 +1,13 @@ +## This file should be placed in the root directory of your project. +## Then modify the CMakeLists.txt file in the root directory of your +## project to incorporate the testing dashboard. +## # The following are required to uses Dart and the Cdash dashboard +## ENABLE_TESTING() +## INCLUDE(CTest) +set(CTEST_PROJECT_NAME "kdebase-workspace") +set(CTEST_NIGHTLY_START_TIME "20:00:00 CET") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=kdebase-workspace") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake new file mode 100644 index 00000000..6f53e4b8 --- /dev/null +++ b/ConfigureChecks.cmake @@ -0,0 +1,102 @@ +include(UnixAuth) +set_package_properties(PAM PROPERTIES DESCRIPTION "PAM Libraries" + URL "https://www.kernel.org/pub/linux/libs/pam/" + TYPE OPTIONAL + PURPOSE "Required for screen unlocking and optionally used by the KDM log in manager" + ) +include(CheckTypeSize) +include(FindPkgConfig) + +macro_optional_find_package(XKB) # kxkb, kdm + +if (PAM_FOUND) + set(KDE4_COMMON_PAM_SERVICE "kde" CACHE STRING "The PAM service to use unless overridden for a particular app.") + + macro(define_pam_service APP) + string(TOUPPER ${APP}_PAM_SERVICE var) + set(cvar KDE4_${var}) + set(${cvar} "${KDE4_COMMON_PAM_SERVICE}" CACHE STRING "The PAM service for ${APP}.") + mark_as_advanced(${cvar}) + set(${var} "\"${${cvar}}\"") + endmacro(define_pam_service) + + macro(install_pam_service APP) + string(TOUPPER KDE4_${APP}_PAM_SERVICE cvar) + install(CODE " + set(DESTDIR_VALUE \"\$ENV{DESTDIR}\") + if (NOT DESTDIR_VALUE) + exec_program(\"${KDEBASE_WORKSPACE_SOURCE_DIR}/mkpamserv\" ARGS ${${cvar}} RETURN_VALUE ret) + if (NOT ret) + exec_program(\"${KDEBASE_WORKSPACE_SOURCE_DIR}/mkpamserv\" ARGS -P ${${cvar}}-np) + endif (NOT ret) + endif (NOT DESTDIR_VALUE) + ") + endmacro(install_pam_service) + + define_pam_service(KDM) + define_pam_service(kscreensaver) + +else (PAM_FOUND) + + macro(install_pam_service APP) + endmacro(install_pam_service) + +endif (PAM_FOUND) + +find_program(some_x_program NAMES iceauth xrdb xterm) +if (NOT some_x_program) + set(some_x_program /usr/bin/xrdb) + message("Warning: Could not determine X binary directory. Assuming /usr/bin.") +endif (NOT some_x_program) +get_filename_component(proto_xbindir "${some_x_program}" PATH) +get_filename_component(XBINDIR "${proto_xbindir}" ABSOLUTE) +get_filename_component(xrootdir "${XBINDIR}" PATH) +set(XLIBDIR "${xrootdir}/lib/X11") + +check_function_exists(getpassphrase HAVE_GETPASSPHRASE) +check_function_exists(vsyslog HAVE_VSYSLOG) +check_function_exists(statvfs HAVE_STATVFS) + +check_include_files(limits.h HAVE_LIMITS_H) +check_include_files(sys/time.h HAVE_SYS_TIME_H) # ksmserver, ksplashml, sftp +check_include_files(stdint.h HAVE_STDINT_H) # kcontrol/kfontinst +check_include_files("sys/stat.h;sys/vfs.h" HAVE_SYS_VFS_H) # statvfs for plasma/solid +check_include_files("sys/stat.h;sys/statvfs.h" HAVE_SYS_STATVFS_H) # statvfs for plasma/solid +check_include_files(sys/param.h HAVE_SYS_PARAM_H) +check_include_files("sys/param.h;sys/mount.h" HAVE_SYS_MOUNT_H) +check_include_files("sys/types.h;sys/statfs.h" HAVE_SYS_STATFS_H) +check_include_files(unistd.h HAVE_UNISTD_H) +check_include_files(malloc.h HAVE_MALLOC_H) +check_function_exists(statfs HAVE_STATFS) +macro_bool_to_01(FONTCONFIG_FOUND HAVE_FONTCONFIG) # kcontrol/{fonts,kfontinst} +macro_bool_to_01(FREETYPE_FOUND HAVE_FREETYPE) # kcontrol/fonts +macro_bool_to_01(OPENGL_FOUND HAVE_OPENGL) # kwin +macro_bool_to_01(X11_XShm_FOUND HAVE_XSHM) # kwin, ksplash +macro_bool_to_01(X11_XTest_FOUND HAVE_XTEST) # khotkeys, kxkb, kdm +macro_bool_to_01(X11_Xcomposite_FOUND HAVE_XCOMPOSITE) # kicker, kwin +macro_bool_to_01(X11_Xcursor_FOUND HAVE_XCURSOR) # many uses +macro_bool_to_01(X11_Xdamage_FOUND HAVE_XDAMAGE) # kwin +macro_bool_to_01(X11_Xfixes_FOUND HAVE_XFIXES) # klipper, kicker, kwin +if(WITH_XINERAMA) + macro_bool_to_01(X11_Xinerama_FOUND HAVE_XINERAMA) +else(WITH_XINERAMA) + set(HAVE_XINERAMA 0) +endif(WITH_XINERAMA) +macro_bool_to_01(X11_Xrandr_FOUND HAVE_XRANDR) # kwin +macro_bool_to_01(X11_Xrender_FOUND HAVE_XRENDER) # kcontrol/style, kicker +macro_bool_to_01(X11_xf86misc_FOUND HAVE_XF86MISC) # kdesktop and kcontrol/lock +macro_bool_to_01(X11_dpms_FOUND HAVE_DPMS) # kdesktop +macro_bool_to_01(X11_XSync_FOUND HAVE_XSYNC) # kwin + +set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) +check_type_size("struct ucred" STRUCT_UCRED) # kio_fonts + +check_function_exists(getpeereid HAVE_GETPEEREID) # kdesu +check_function_exists(setpriority HAVE_SETPRIORITY) # kscreenlocker + +set(CMAKE_REQUIRED_INCLUDES ${X11_Xrandr_INCLUDE_PATH}/Xrandr.h) +set(CMAKE_REQUIRED_LIBRARIES ${X11_Xrandr_LIB}) +check_function_exists(XRRGetScreenSizeRange XRANDR_1_2_FOUND) +macro_bool_to_01(XRANDR_1_2_FOUND HAS_RANDR_1_2) +check_function_exists(XRRGetScreenResourcesCurrent XRANDR_1_3_FOUND) +macro_bool_to_01(XRANDR_1_3_FOUND HAS_RANDR_1_3) diff --git a/KDE4WorkspaceConfig.cmake.in b/KDE4WorkspaceConfig.cmake.in new file mode 100644 index 00000000..5f2e24e2 --- /dev/null +++ b/KDE4WorkspaceConfig.cmake.in @@ -0,0 +1,70 @@ +# KDE4WorkspaceConfig.cmake is generated by CMake from kdebase/workspace/KDE4WorkspaceConfig.cmake.in + +# Do we have a version number for kdebase/workspace ? Alex +set(KDE4WORKSPACE_VERSION_MAJOR @KDE4WORKSPACE_VERSION_MAJOR@) +set(KDE4WORKSPACE_VERSION_MINOR @KDE4WORKSPACE_VERSION_MINOR@) +set(KDE4WORKSPACE_VERSION_PATCH @KDE4WORKSPACE_VERSION_PATCH@) +set(KDE4WORKSPACE_VERSION "${KDE4WORKSPACE_VERSION_MAJOR}.${KDE4WORKSPACE_VERSION_MINOR}.${KDE4WORKSPACE_VERSION_PATCH}") + +# set the directories +if(NOT KDE4WORKSPACE_INSTALL_DIR) + set(KDE4WORKSPACE_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@") +endif(NOT KDE4WORKSPACE_INSTALL_DIR) + +set(KDE4WORKSPACE_LIB_DIR "@KDE4WORKSPACE_LIB_DIR@") +set(KDE4WORKSPACE_LIBEXEC_DIR "@KDE4WORKSPACE_LIBEXEC_DIR@") +set(KDE4WORKSPACE_INCLUDE_DIR "@KDE4WORKSPACE_INCLUDE_DIR@") +set(KDE4WORKSPACE_BIN_DIR "@KDE4WORKSPACE_BIN_DIR@") +set(KDE4WORKSPACE_SBIN_DIR "@KDE4WORKSPACE_SBIN_DIR@") +set(KDE4WORKSPACE_DATA_DIR "@KDE4WORKSPACE_DATA_DIR@") +set(KDE4WORKSPACE_HTML_DIR "@KDE4WORKSPACE_HTML_DIR@") +set(KDE4WORKSPACE_CONFIG_DIR "@KDE4WORKSPACE_CONFIG_DIR@") +set(KDE4WORKSPACE_ICON_DIR "@KDE4WORKSPACE_ICON_DIR@") +set(KDE4WORKSPACE_KCFG_DIR "@KDE4WORKSPACE_KCFG_DIR@") +set(KDE4WORKSPACE_LOCALE_DIR "@KDE4WORKSPACE_LOCALE_DIR@") +set(KDE4WORKSPACE_MIME_DIR "@KDE4WORKSPACE_MIME_DIR@") +set(KDE4WORKSPACE_SOUND_DIR "@KDE4WORKSPACE_SOUND_DIR@") +set(KDE4WORKSPACE_TEMPLATES_DIR "@KDE4WORKSPACE_TEMPLATES_DIR@") +set(KDE4WORKSPACE_WALLPAPER_DIR "@KDE4WORKSPACE_WALLPAPER_DIR@") +set(KDE4WORKSPACE_KCONF_UPDATE_DIR "@KDE4WORKSPACE_KCONF_UPDATE_DIR@") +set(KDE4WORKSPACE_AUTOSTART_DIR "@KDE4WORKSPACE_AUTOSTART_DIR@") +set(KDE4WORKSPACE_XDG_APPS_DIR "@KDE4WORKSPACE_XDG_APPS_DIR@") +set(KDE4WORKSPACE_XDG_DIRECTORY_DIR "@KDE4WORKSPACE_XDG_DIRECTORY_DIR@") +set(KDE4WORKSPACE_SYSCONF_DIR "@KDE4WORKSPACE_SYSCONF_DIR@") +set(KDE4WORKSPACE_MAN_DIR "@KDE4WORKSPACE_MAN_DIR@") +set(KDE4WORKSPACE_INFO_DIR "@KDE4WORKSPACE_INFO_DIR@") +set(KDE4WORKSPACE_DBUS_INTERFACES_DIR "@KDE4WORKSPACE_DBUS_INTERFACES_DIR@") +set(KDE4WORKSPACE_DBUS_SERVICES_DIR "@KDE4WORKSPACE_DBUS_SERVICES_DIR@") +set(KDE4WORKSPACE_SERVICES_DIR "@KDE4WORKSPACE_SERVICES_DIR@") +set(KDE4WORKSPACE_SERVICETYPES_DIR "@KDE4WORKSPACE_SERVICETYPES_DIR@") + +# the exports file exports +set(KDE4WORKSPACE_TARGET_PREFIX @KDE4WORKSPACE_TARGET_PREFIX@) + +# Make sure to load the exported targets only once +# For the rest of this script it doesn't matter that much +if(NOT TARGET @KDE4WORKSPACE_TARGET_PREFIX@plasmaclock) + get_filename_component(_currentDir "${CMAKE_CURRENT_LIST_FILE}" PATH) + include("${_currentDir}/KDE4WorkspaceLibraryTargets.cmake") +endif(NOT TARGET @KDE4WORKSPACE_TARGET_PREFIX@plasmaclock) + +macro(_KDE4WORKSPACE_Set_Lib_Vars _prefix _lib) + set(KDE4WORKSPACE_${_prefix}_LIBRARY ${KDE4WORKSPACE_TARGET_PREFIX}${_lib}) + set(KDE4WORKSPACE_${_prefix}_LIBS ${KDE4WORKSPACE_TARGET_PREFIX}${_lib}) +endmacro(_KDE4WORKSPACE_Set_Lib_Vars) + + +_kde4workspace_set_lib_vars( TASKMANAGER taskmanager) +_kde4workspace_set_lib_vars( KWORKSPACE kworkspace) +_kde4workspace_set_lib_vars( PROCESSUI processui) +_kde4workspace_set_lib_vars( LSOFUI lsofui) +_kde4workspace_set_lib_vars( PLASMACLOCK plasmaclock) +_kde4workspace_set_lib_vars( NEPOMUKQUERYCLIENT nepomukqueryclient) +_kde4workspace_set_lib_vars( NEPOMUKQUERY nepomukquery) +_kde4workspace_set_lib_vars( KSCREENSAVER kscreensaver) +_kde4workspace_set_lib_vars( WEATHERION weather_ion) +_kde4workspace_set_lib_vars( KWINEFFECTS kwineffects) +_kde4workspace_set_lib_vars( KDECORATIONS kdecorations) +_kde4workspace_set_lib_vars( KSGRD ksgrd) +_kde4workspace_set_lib_vars( KEPHAL kephal) + diff --git a/Mainpage.dox b/Mainpage.dox new file mode 100644 index 00000000..332640ad --- /dev/null +++ b/Mainpage.dox @@ -0,0 +1,51 @@ +/** @mainpage The KDE Workspace + +This is where the components that are only used when KDE is providing +a complete desktop environment live. + +Of particular importance are KWin, the +KDE window manager, and Plasma, which +provides the workspace interface. + +If you are developing Plasma plugins (Plasmoids), you are probably interested +in the libplasma documentation. + +Other components that reside here are: +- KCheckPass, a simple program for checking whether a password is correct +- KCMInit, which allows KDE control modules to do initialization at the + start of a KDE session, for example setting the keyboard repeat rate +- KDM, the login manager for KDE +- KHotKeys, a daemon that allows actions to be performed when certain + combinations of keys are pressed +- Klipper, the KDE clipboard manager +- KMenuEdit, the manager for the desktop menu (the K menu) +- KRunner, which provides the launch ("run command") dialog, screensaver + activation and screen locking and control of application startup notification +- KScreenSaver, which provides pretty screensavers and is launched by + KRunner +- KSMServer, the KDE session manager +- KSplash, the KDE splashscreen program +- KStartupConfig, which allows configuration files to be used in startkde + without linking to KDE libraries +- KTip, that little window that pops up when you start KDE with the Tip of + the Day +- SystemSettings, the KDE configuration program +- Various Solid components useful in a + KDE session +- StartKDE, the script that starts a KDE session +- Some wallpapers, and a basic K menu setup + +@warning The applications and libraries in Workspace are only required to work +with X11. They will not be used on Windows or MacOS, or in other desktop +environments (such as GNOME). Applications should not depend on Workspace +unless they are a desktop component, such as a screensaver or a plasmoid. + + +@licenses +@gpl + + +*/ + +// DOXYGEN_SET_PROJECT_NAME = Workspace +// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/README b/README new file mode 100644 index 00000000..fc6f1eae --- /dev/null +++ b/README @@ -0,0 +1 @@ +KDE Workspace consisting of what is the desktop. The applications and libraries included aren't required to be portable and probably will only work with X11. On other desktops such as OS X and Windows, users wouldn't run these applications, but use the native ones instead. The typical application shouldn't have dependencies in workspace unless they are a component such as a screen-saver or panel applet. diff --git a/README.pam b/README.pam new file mode 100644 index 00000000..2e302fe3 --- /dev/null +++ b/README.pam @@ -0,0 +1,72 @@ +KDE can be configured to support the PAM ("Pluggable Authentication +Modules") system for password checking by the display manager kdm and +by the screen saver kscreensaver (for unlocking the display). + +PAM is a flexible application-transparent configurable user-authentication +system found on FreeBSD, Solaris, and Linux (and maybe other unixes). + +Information about PAM may be found on its homepage + http://www.kernel.org/pub/linux/libs/pam/ +(Despite the location, this information is NOT Linux-specific.) + + +Known Solaris Issues: +-------------------- + +For compiling PAM support on Solaris, PAM_MESSAGE_CONST must NOT +be defined. This should now be handled automatically by the +configure script. + + +Using PAM +--------- + +By default, PAM is automatically used, if it is found. Use +./configure --without-pam to disable it. + +If PAM is found, KDE usually uses the PAM service "kde". You may +override it for all KDE programs by using --with-pam= and/or +individually by using --with--pam=, where is +one of kdm, kcp and kss (for kdm, kcheckpass and kscreensaver). + +"make install" will attempt to create suitable service definitions; either +by putting files into /etc/pam.d/ or by adding text to /etc/pam.conf. The +services are just copies of the "login" service. +You may want to edit these definitions to meet your needs. +There are also two example service definitions in this directory - +kde.pamd and kscreensaver.pamd - but don't just copy them! +If the services are misconfigured, you will NOT be able to login via KDM +and/or unlock a locked screen! + +If there is ever any doubt about which PAM service a program was +compiled with, it can be determined by examining the PAM-generated +entries in the system log associated with kdm logins or kscreensaver +authentication failures. + + +PAM configuration files have four types of entries for each service: + +type used by kdm used by kscreensaver +---- ----------- -------------------- +auth x x +account x +password x +session x + +There may be more than one entry of each type. Check existing PAM +configuration files and PAM documentation on your system for guidance as +to what entries to make. If you call a PAM service that is not +configured, the default action of PAM is likely to be denial of service. + +Note: kdm implements PAM "session" support, which is not implemented in +certain PAM-aware xdm's that it may be replacing (e.g., the Red Hat +Linux 5.x xdm did not implement it). This may be configured to carry out +actions when a user opens or closes an kdm session, if a suitable PAM +module is available (e.g., mount and unmount user-specific filesystems). + +Note 2: Screensavers typically only authenticate a user to allow her to +continue working. They may also renew tokens etc., where supported. +See the Linux PAM Administrators guide, which is part of the PAM +distribution, for more details. + + diff --git a/appmenu/CMakeLists.txt b/appmenu/CMakeLists.txt new file mode 100644 index 00000000..1b597c43 --- /dev/null +++ b/appmenu/CMakeLists.txt @@ -0,0 +1,37 @@ +include_directories( + ${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} + ) + +include_directories(${DBUSMENUQT_INCLUDE_DIR}) + +set(kded_appmenu_SRCS + appmenu.cpp + menuimporter.cpp + appmenu_dbus.cpp + menubutton.cpp + menuwidget.cpp + menubar.cpp + topmenubar.cpp + glowbar.cpp + verticalmenu.cpp + shadows.cpp + ) + +qt4_add_dbus_adaptor(kded_appmenu_SRCS com.canonical.AppMenu.Registrar.xml + menuimporter.h MenuImporter menuimporteradaptor MenuImporterAdaptor) + +qt4_add_dbus_adaptor(kded_appmenu_SRCS org.kde.kded.appmenu.xml + appmenu_dbus.h AppmenuDBus appmenuadaptor AppmenuAdaptor) + +kde4_add_plugin(kded_appmenu ${kded_appmenu_SRCS}) + +target_link_libraries(kded_appmenu ${KDE4_KIO_LIBS} ${X11_LIBRARIES} ${DBUSMENUQT_LIBRARIES} ${KDE4_PLASMA_LIBS}) + +install(TARGETS kded_appmenu DESTINATION ${PLUGIN_INSTALL_DIR} ) + +########### install files ############### + +install( FILES appmenu.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded ) +install( FILES com.canonical.AppMenu.Registrar.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} ) +install( FILES org.kde.kded.appmenu.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} ) diff --git a/appmenu/appmenu.cpp b/appmenu/appmenu.cpp new file mode 100644 index 00000000..4d2edd09 --- /dev/null +++ b/appmenu/appmenu.cpp @@ -0,0 +1,399 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "appmenu.h" +#include "kdbusimporter.h" +#include "menuimporteradaptor.h" +#include "appmenuadaptor.h" +#include "appmenu_dbus.h" +#include "topmenubar.h" +#include "verticalmenu.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +K_PLUGIN_FACTORY(AppMenuFactory, + registerPlugin(); + ) +K_EXPORT_PLUGIN(AppMenuFactory("appmenu")) + +AppMenuModule::AppMenuModule(QObject* parent, const QList&) + : KDEDModule(parent), + m_parent(parent), + m_menuImporter(0), + m_appmenuDBus(new AppmenuDBus(parent)), + m_menubar(0), + m_menu(0), + m_screenTimer(new QTimer(this)), + m_waitingAction(0), + m_currentScreen(-1) +{ + reconfigure(); + + m_appmenuDBus->connectToBus(); + + m_currentScreen = currentScreen(); + + connect(m_appmenuDBus, SIGNAL(appShowMenu(int, int, WId)), SLOT(slotShowMenu(int, int, WId))); + connect(m_appmenuDBus, SIGNAL(moduleReconfigure()), SLOT(reconfigure())); + + // transfer our signals to dbus + connect(this, SIGNAL(showRequest(qulonglong)), m_appmenuDBus, SIGNAL(showRequest(qulonglong))); + connect(this, SIGNAL(menuAvailable(qulonglong)), m_appmenuDBus, SIGNAL(menuAvailable(qulonglong))); + connect(this, SIGNAL(clearMenus()), m_appmenuDBus, SIGNAL(clearMenus())); + connect(this, SIGNAL(menuHidden(qulonglong)), m_appmenuDBus, SIGNAL(menuHidden(qulonglong))); + connect(this, SIGNAL(WindowRegistered(qulonglong, const QString&, const QDBusObjectPath&)), + m_appmenuDBus, SIGNAL(WindowRegistered(qulonglong, const QString&, const QDBusObjectPath&))); + connect(this, SIGNAL(WindowUnregistered(qulonglong)), m_appmenuDBus, SIGNAL(WindowUnregistered(qulonglong))); +} + +AppMenuModule::~AppMenuModule() +{ + emit clearMenus(); + hideMenubar(); + if (m_menubar) { + delete m_menubar; + } + delete m_menuImporter; + delete m_appmenuDBus; +} + +void AppMenuModule::slotShowMenu(int x, int y, WId id) +{ + static KDBusMenuImporter *importer = 0; + + if (!m_menuImporter) { + return; + } + + // If menu visible, hide it + if (m_menu && m_menu->isVisible()) { + m_menu->hide(); + return; + } + + //dbus call by user (for khotkey shortcut) + if (x == -1 || y == -1) { + // We do not know kwin button position, so tell kwin to show menu + emit showRequest(KWindowSystem::self()->activeWindow()); + return; + } + + importer = getImporter(id); + + if (!importer) { + return; + } + + QMenu *menu = importer->menu(); + + // Window do not have menu + if (!menu) { + return; + } + + m_menu = new VerticalMenu(); + m_menu->setParentWid(id); + // Populate menu + foreach (QAction *action, menu->actions()) { + m_menu->addAction(action); + } + m_menu->popup(QPoint(x, y)); + // Activate waiting action if exist + if (m_waitingAction) { + m_menu->setActiveAction(m_waitingAction); + m_waitingAction = 0; + } + connect(m_menu, SIGNAL(aboutToHide()), this, SLOT(slotAboutToHide())); +} + +void AppMenuModule::slotAboutToHide() +{ + if (m_menu) { + emit menuHidden(m_menu->parentWid()); + m_menu->deleteLater(); + m_menu = 0; + } +} + +// New window registered +void AppMenuModule::slotWindowRegistered(WId id, const QString& service, const QDBusObjectPath& path) +{ + KDBusMenuImporter* importer = m_importers.take(id); + if (importer) { + delete importer; + } + + // Application already active so check if we need create menubar + if ( m_menuStyle == "TopMenuBar" && id == KWindowSystem::self()->activeWindow()) { + slotActiveWindowChanged(id); + } else if (m_menuStyle == "ButtonVertical") { + KWindowInfo info = KWindowSystem::windowInfo(id, 0, NET::WM2WindowClass); + // Tell Kwin menu is available + emit menuAvailable(id); + // FIXME: https://bugs.kde.org/show_bug.cgi?id=317926 + if (info.windowClassName() != "kmix") { + getImporter(id); + } + } + + // Send a signal on bus for others dbus interface registrars + emit WindowRegistered(id, service, path); +} + +// Window unregistered +void AppMenuModule::slotWindowUnregistered(WId id) +{ + KDBusMenuImporter* importer = m_importers.take(id); + + // Send a signal on bus for others dbus interface registrars + emit WindowUnregistered(id); + + if (importer) { + delete importer; + } + + if (m_menubar && m_menubar->parentWid() == id) { + hideMenubar(); + } +} + +// Keyboard activation requested, transmit it to menu +void AppMenuModule::slotActionActivationRequested(QAction* a) +{ + // If we have a topmenubar, activate action + if (m_menubar) { + m_menubar->setActiveAction(a); + m_menubar->show(); + } else { // else send request to kwin or others dbus interface registrars + m_waitingAction = a; + emit showRequest(KWindowSystem::self()->activeWindow()); + } +} + +// Current window change, update menubar +// See comments in slotWindowRegistered() for why we get importers here +void AppMenuModule::slotActiveWindowChanged(WId id) +{ + KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMWindowType); + unsigned long mask = NET::AllTypesMask; + + m_currentScreen = currentScreen(); + + if (id == 0) {// Ignore root window + return; + } else if (info.windowType(mask) & NET::Dock) { // Hide immediatly menubar for docks (krunner) + hideMenubar(); + return; + } + + if (!m_menuImporter->serviceExist(id)) { // No menu exist, check for another menu for application + WId recursiveId = m_menuImporter->recursiveMenuId(id); + if (recursiveId) { + id = recursiveId; + } + } + + KDBusMenuImporter *importer = getImporter(id); + if (!importer) { + hideMenubar(); + return; + } + + QMenu *menu = importer->menu(); + + if(menu) { + showMenuBar(menu); + m_menubar->setParentWid(id); + } else { + hideMenubar(); + } +} + +void AppMenuModule::slotShowCurrentWindowMenu() +{ + slotActiveWindowChanged(KWindowSystem::self()->activeWindow()); +} + +void AppMenuModule::slotCurrentScreenChanged() +{ + if (m_currentScreen != currentScreen()) { + if (m_menubar) { + m_menubar->setParentWid(0); + } + slotActiveWindowChanged(KWindowSystem::self()->activeWindow()); + } +} + +void AppMenuModule::slotBarNeedResize() +{ + if (m_menubar) { + m_menubar->updateSize(); + m_menubar->move(centeredMenubarPos()); + } +} + +// reload settings +void AppMenuModule::reconfigure() +{ + KConfig config( "kdeglobals", KConfig::FullConfig ); + KConfigGroup configGroup = config.group("Appmenu Style"); + m_menuStyle = configGroup.readEntry("Style", "InApplication"); + + m_waitingAction = 0; + + // hide menubar if exist + hideMenubar(); + if (m_menubar) { + delete m_menubar; + m_menubar = 0; + } + + slotAboutToHide(); // hide vertical menu if exist + + // Disconnect all options specifics signals + disconnect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(slotActiveWindowChanged(WId))); + disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(slotShowCurrentWindowMenu())); + disconnect(m_screenTimer, SIGNAL(timeout()), this, SLOT(slotCurrentScreenChanged())); + + m_screenTimer->stop(); + + // Tell kwin to clean its titlebar + emit clearMenus(); + + if (m_menuStyle == "InApplication") { + if (m_menuImporter) { + delete m_menuImporter; + m_menuImporter = 0; + } + return; + } + + // Setup a menu importer if needed + if (!m_menuImporter) { + m_menuImporter = new MenuImporter(m_parent); + connect(m_menuImporter, SIGNAL(WindowRegistered(WId, const QString&, const QDBusObjectPath&)), + SLOT(slotWindowRegistered(WId, const QString&, const QDBusObjectPath&))); + connect(m_menuImporter, SIGNAL(WindowUnregistered(WId)), + SLOT(slotWindowUnregistered(WId))); + m_menuImporter->connectToBus(); + } + + if( m_menuStyle == "ButtonVertical" ) { + foreach(WId id, m_menuImporter->ids()) { + emit menuAvailable(id); + } + } + + // Setup top menubar if needed + if (m_menuStyle == "TopMenuBar") { + m_menubar = new TopMenuBar(); + connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(slotActiveWindowChanged(WId))); + connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(slotShowCurrentWindowMenu())); + connect(m_screenTimer, SIGNAL(timeout()), this, SLOT(slotCurrentScreenChanged())); + connect(m_menubar, SIGNAL(needResize()), SLOT(slotBarNeedResize())); + m_screenTimer->start(1000); + slotShowCurrentWindowMenu(); + } +} + +KDBusMenuImporter* AppMenuModule::getImporter(WId id) +{ + KDBusMenuImporter* importer = 0; + if (m_importers.contains(id)) { // importer already exist + importer = m_importers.value(id); + } else if (m_menuImporter->serviceExist(id)) { // get importer + importer = new KDBusMenuImporter(id, m_menuImporter->serviceForWindow(id), &m_icons, + m_menuImporter->pathForWindow(id), this); + if (importer) { + QMetaObject::invokeMethod(importer, "updateMenu", Qt::DirectConnection); + connect(importer, SIGNAL(actionActivationRequested(QAction*)), + SLOT(slotActionActivationRequested(QAction*))); + m_importers.insert(id, importer); + } + } + return importer; +} + +void AppMenuModule::showMenuBar(QMenu *menu) +{ + if (!menu) { + return; + } + + m_menubar->setMenu(menu); + if (menu->actions().length()) { + m_menubar->enableMouseTracking(); + } +} + +void AppMenuModule::hideMenubar() +{ + if (!m_menubar) { + return; + } + + m_menubar->enableMouseTracking(false); + if (m_menubar->isVisible()) { + m_menubar->hide(); + } +} + +int AppMenuModule::currentScreen() +{ + KWindowInfo info = KWindowSystem::windowInfo(KWindowSystem::self()->activeWindow(), + NET::WMGeometry); + int x = info.geometry().x(); + int y = info.geometry().y(); + + QDesktopWidget *desktop = QApplication::desktop(); + return desktop->screenNumber(QPoint(x,y)); +} + + +QPoint AppMenuModule::centeredMenubarPos() +{ + QDesktopWidget *desktop = QApplication::desktop(); + m_currentScreen = currentScreen(); + QRect screen = desktop->availableGeometry(m_currentScreen); + int x = screen.center().x() - m_menubar->sizeHint().width()/2; + return QPoint(x, screen.topLeft().y()); +} + + +#include "appmenu.moc" diff --git a/appmenu/appmenu.desktop b/appmenu/appmenu.desktop new file mode 100644 index 00000000..242c5feb --- /dev/null +++ b/appmenu/appmenu.desktop @@ -0,0 +1,96 @@ +[Desktop Entry] +Type=Service +Name=Application menus daemon +Name[bs]=Demon za aplikacijske menije +Name[ca]=Dimoni de menús d'aplicació +Name[ca@valencia]=Dimoni de menús d'aplicació +Name[cs]=Démon nabídky aplikací +Name[da]=Dæmon til programmenuer +Name[de]=Dienst für Anwendungsmenüs +Name[el]=Δαίμων για τα μενού των εφαρμογών +Name[en_GB]=Application menus daemon +Name[es]=Demonio de menús de aplicación +Name[et]=Rakenduste menüü deemon +Name[eu]=Aplikazio-menuen daimona +Name[fi]=Sovellusvalikkopalvelu +Name[fr]=Démon de menus des applications +Name[gl]=Daemon de menús do programa +Name[he]=תהליך רקע של תפריט היישומים +Name[hu]=Alkalmazás menük démon +Name[ia]=Demone de menus de application +Name[it]=Demone dei menu delle applicazioni +Name[kk]=Қолданба мәзірінің қызметі +Name[ko]=프로그램 메뉴 데몬 +Name[lt]=Programos meniu tarnyba +Name[mr]=अनुप्रयोग मेन्यू डीमन +Name[nb]=Daemon for programmenyer +Name[nds]=Programmmenü-Dämoon +Name[nl]=Daemon voor menu van toepassingen +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਮੈਨੂ ਡੈਮਨ +Name[pl]=Demon menu programów +Name[pt]=Servidor dos menus da aplicação +Name[pt_BR]=Servidor dos menus do aplicativo +Name[ro]=Demon pentru meniurile aplicațiilor +Name[ru]=Фоновая служба меню приложений +Name[sk]=Démon ponúk aplikácie +Name[sl]=Ozadnji program za programske menije +Name[sr]=Демон програмских менија +Name[sr@ijekavian]=Демон програмских менија +Name[sr@ijekavianlatin]=Demon programskih menija +Name[sr@latin]=Demon programskih menija +Name[sv]=Demon för programmenyer +Name[tr]=Uygulama menü araçları +Name[uk]=Фонова служба меню програм +Name[x-test]=xxApplication menus daemonxx +Name[zh_CN]=应用程序菜单守护程序 +Name[zh_TW]=應用程式選單伺服程式應用程式選單伺服程式 +Comment=Transfers application's menu to the desktop +Comment[bs]=Prebacuje aplikacijski meni na radnu površinu +Comment[ca]=Transfereix els menús d'aplicació a l'escriptori +Comment[ca@valencia]=Transfereix els menús d'aplicació a l'escriptori +Comment[cs]=Přesouvá nabídku aplikací na plochu +Comment[da]=Overfører programmets menu til skrivebordet +Comment[de]=Überträgt Anwendungsmenüs auf die Arbeitsfläche +Comment[el]=Μεταφέρει το μενού της εφαρμογής στην επιφάνεια εργασίας +Comment[en_GB]=Transfers application's menu to the desktop +Comment[es]=Transfiere el menú de aplicaciones al escritorio +Comment[et]=Rakenduste menüü paigutamine töölauale +Comment[eu]=Aplikazioen menua mahaigainera transferitzen du +Comment[fi]=Siirtää sovelluksen valikon työpöydälle +Comment[fr]=Transfère le menu des applications sur le bureau +Comment[gl]=Transfire o menú do programa ao escritorio +Comment[he]=מעביר את התפריטים של היישום אל שולחן העבודה +Comment[hu]=Átviszi az alkalmazás menüjét az asztalra +Comment[ia]=Il transfere menu de applicationes al scriptorio +Comment[it]=Trasferisce al desktop i menu delle applicazioni +Comment[kk]=Қолданбаның мәзірін үстел бетіне тапсыру +Comment[ko]=프로그램 메뉴를 데스크톱으로 보내기 +Comment[lt]=Perkelia programos meniu į darbastalį +Comment[mr]=अनुप्रयोग मेन्यूचे डेस्कटॉपवर स्थानान्तरण +Comment[nb]=Overfører programmets meny til skrivebordet +Comment[nds]=Dat Programmmenü na den Schriefdisch överdregen +Comment[nl]=Brengt het menu van de toepassing over naar het bureaublad +Comment[pa]=ਐਪਲੀਕੇਸ਼ਨ ਦੇ ਮੇਨੂ ਨੂੰ ਡੈਸਕਟਾਪ ਉੱਤੇ ਭੇਜੋ +Comment[pl]=Przenosi menu aplikacji na pulpit +Comment[pt]=Transfere o menu da aplicação para o ecrã +Comment[pt_BR]=Transfere o menu do aplicativo para a área de trabalho +Comment[ro]=Transferă meniul aplicațiilor către birou +Comment[ru]=Перемещает меню приложения на рабочий стол +Comment[sk]=Presunúť ponuky aplikácie na plochu +Comment[sl]=Prenese programski meni na namizje +Comment[sr]=Пребацује меније програма на површ +Comment[sr@ijekavian]=Пребацује меније програма на површ +Comment[sr@ijekavianlatin]=Prebacuje menije programa na površ +Comment[sr@latin]=Prebacuje menije programa na površ +Comment[sv]=Överför programmets meny till skrivbordet +Comment[tr]=Uygulamanın menüsünü masaüstüne aktarır +Comment[uk]=Передає меню програм на стільницю +Comment[x-test]=xxTransfers application's menu to the desktopxx +Comment[zh_CN]=将应用程序的菜单转移到桌面上 +Comment[zh_TW]=將應用程式選單傳送到桌面 +X-KDE-ServiceTypes=KDEDModule +X-KDE-Library=appmenu +X-KDE-DBus-ModuleName=appmenu +X-KDE-Kded-autoload=true +X-KDE-Kded-load-on-demand=false + diff --git a/appmenu/appmenu.h b/appmenu/appmenu.h new file mode 100644 index 00000000..b079d4cb --- /dev/null +++ b/appmenu/appmenu.h @@ -0,0 +1,154 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef APPMENUMODULE_H +#define APPMENUMODULE_H + +#include +#include "menuimporter.h" +#include "gtkicons.h" + +class QDBusPendingCallWatcher; +class KDBusMenuImporter; +class AppmenuDBus; +class TopMenuBar; +class VerticalMenu; + +class AppMenuModule : public KDEDModule, + protected QDBusContext +{ + Q_OBJECT +public: + AppMenuModule(QObject* parent, const QList& list); + virtual ~AppMenuModule(); + +Q_SIGNALS: + /** + * We do not know where is menu decoration button, so tell kwin to show menu + */ + void showRequest(qulonglong); + /** + * This signal is emitted whenever application menu becomes available + */ + void menuAvailable(qulonglong); + /** + * This signal is emitted whenever menus are unavailables + */ + void clearMenus(); + /** + * This signal is emitted whenever popup menu/menubar is hidden + * Useful for decorations to know if menu button should be release + */ + void menuHidden(qulonglong); + /** + * This signal is emitted whenever a window register to appmenu + */ + void WindowRegistered(qulonglong wid, const QString& service, const QDBusObjectPath&); + /** + * This signal is emitted whenever a window unregister from appmenu + */ + void WindowUnregistered(qulonglong wid); + +private Q_SLOTS: + /** + * Show menu at QPoint(x,y) for id + * if x or y == -1, show in application window + */ + void slotShowMenu(int x, int y, WId); + /** + * Send menuHidden signal over bus when menu is about to hide + */ + void slotAboutToHide(); + /** + * New window registered to appmenu + * Emit WindowRegistered signal over bus + */ + void slotWindowRegistered(WId id, const QString& service, const QDBusObjectPath& path); + /** + * Window unregistered from appmenu + * Emit WindowUnregistered signal over bus + */ + void slotWindowUnregistered(WId id); + /** + * Open a action in current menu + */ + void slotActionActivationRequested(QAction* a); + /** + * Active window changed, show menubar for id + */ + void slotActiveWindowChanged(WId id); + /** + * Update menubar with current window menu + */ + void slotShowCurrentWindowMenu(); + /** + * Current screen changed, update menubar + */ + void slotCurrentScreenChanged(); + /** + * Resize menubar + */ + void slotBarNeedResize(); + /** + * Reconfigure module + */ + void reconfigure(); + +private: + /** + * return an importer for window id + */ + KDBusMenuImporter* getImporter(WId id); + /** + * Show menubar and update it with menu + */ + void showMenuBar(QMenu *menu); + /** + * Hide menubar + */ + void hideMenubar(); + /** + * Return current screen + */ + int currentScreen(); + /** + * Return position of menubar for being centered on screen + */ + QPoint centeredMenubarPos(); + + QObject* m_parent; + MenuImporter* m_menuImporter; + AppmenuDBus* m_appmenuDBus; + QHash m_importers; + GtkIcons m_icons; + QString m_menuStyle; + TopMenuBar* m_menubar; + VerticalMenu* m_menu; + QTimer* m_screenTimer; + QAction *m_waitingAction; + int m_currentScreen; +}; + +#endif diff --git a/appmenu/appmenu_dbus.cpp b/appmenu/appmenu_dbus.cpp new file mode 100644 index 00000000..3b627323 --- /dev/null +++ b/appmenu/appmenu_dbus.cpp @@ -0,0 +1,69 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "appmenu_dbus.h" +#include "kdbusimporter.h" +#include "appmenuadaptor.h" + +#include +#include +#include +#include + +static const char* DBUS_SERVICE = "org.kde.kded"; +static const char* DBUS_OBJECT_PATH = "/modules/appmenu"; + +AppmenuDBus::AppmenuDBus(QObject* parent) +: QObject(parent) +{ +} + +AppmenuDBus::~AppmenuDBus() +{ +} + +bool AppmenuDBus::connectToBus(const QString& service, const QString& path) +{ + m_service = service.isEmpty() ? DBUS_SERVICE : service; + QString newPath = path.isEmpty() ? DBUS_OBJECT_PATH : path; + + if (!QDBusConnection::sessionBus().registerService(m_service)) { + return false; + } + new AppmenuAdaptor(this); + QDBusConnection::sessionBus().registerObject(newPath, this); + + return true; +} + +void AppmenuDBus::showMenu(int x, int y, WId id) +{ + emit appShowMenu(x, y, id); +} + +void AppmenuDBus::reconfigure() +{ + emit moduleReconfigure(); +} \ No newline at end of file diff --git a/appmenu/appmenu_dbus.h b/appmenu/appmenu_dbus.h new file mode 100644 index 00000000..2d5bb7e3 --- /dev/null +++ b/appmenu/appmenu_dbus.h @@ -0,0 +1,100 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef APPMENU_DBUS_H +#define APPMENU_DBUS_H + +// Qt +#include +#include +#include +#include +#include + +class KDBusMenuImporter; + +class AppmenuDBus : public QObject, protected QDBusContext +{ + Q_OBJECT + +public: + AppmenuDBus(QObject*); + ~AppmenuDBus(); + + bool connectToBus(const QString& service = QString(), const QString& path = QString()); + + /** + * DBus method showing menu at QPoint(x,y) for id + * if x or y == -1, show in application window + */ + void showMenu(int x, int y, WId id); + /** + * DBus method reconfiguring kded module + */ + void reconfigure(); + +Q_SIGNALS: + /** + * This signal is emitted on showMenu() request + */ + void appShowMenu(int x, int y, WId id); + /** + * This signal is emitted on reconfigure() request + */ + void moduleReconfigure(); + + // Dbus signals + /** + * This signal is emitted whenever kded want to show menu + * We do not know where is menu decoration button, so tell kwin to show menu + */ + void showRequest(qulonglong); + /** + * This signal is emitted whenever application menu becomes available + */ + void menuAvailable(qulonglong); + /** + * This signal is emitted whenever menus are unavailables + */ + void clearMenus(); + /** + * This signal is emitted whenever popup menu/menubar is hidden + * Useful for decorations to know if menu button should be release + */ + void menuHidden(qulonglong); + /** + * This signal is emitted whenever a window register to appmenu + */ + void WindowRegistered(qulonglong wid, const QString& service, const QDBusObjectPath&); + /** + * This signal is emitted whenever a window unregister from appmenu + */ + void WindowUnregistered(qulonglong wid); + +private: + QString m_service; +}; + +#endif // APPMENU_DBUS_H diff --git a/appmenu/com.canonical.AppMenu.Registrar.xml b/appmenu/com.canonical.AppMenu.Registrar.xml new file mode 100644 index 00000000..bc2be43c --- /dev/null +++ b/appmenu/com.canonical.AppMenu.Registrar.xml @@ -0,0 +1,56 @@ + + + + + + An interface to register a menu from an application's window to be displayed in another + window.  This manages that association between XWindow Window IDs and the dbus + address and object that provides the menu using the dbusmenu dbus interface. + + + + + The XWindow ID of the window + + + The object on the dbus interface implementing the dbusmenu interface + + + + + A method to allow removing a window from the database. Windows will also be removed + when the client drops off DBus so this is not required. It is polite though. And + important for testing. + + + The XWindow ID of the window + + + + Gets the registered menu for a given window ID. + + The XWindow ID of the window to get + + + The address of the connection on DBus (e.g. :1.23 or org.example.service) + + + The path to the object which implements the com.canonical.dbusmenu interface. + + + + diff --git a/appmenu/glowbar.cpp b/appmenu/glowbar.cpp new file mode 100644 index 00000000..680c8cda --- /dev/null +++ b/appmenu/glowbar.cpp @@ -0,0 +1,109 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "glowbar.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +GlowBar::GlowBar() + : QWidget(0), + m_svg(new Plasma::Svg(this)) +{ + m_svg->setImagePath("widgets/glowbar"); + + setWindowFlags(Qt::Tool | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint); + setAttribute(Qt::WA_TranslucentBackground); + setAutoFillBackground(false); + KWindowSystem::setType(winId(), NET::Dock); + + QPalette pal = palette(); + pal.setColor(backgroundRole(), Qt::transparent); + setPalette(pal); + + setInputMask(); +} + +GlowBar::~GlowBar() +{ +} + +void GlowBar::paintEvent(QPaintEvent*) +{ + QPixmap l, r, c; + QPoint pixmapPosition(0, 0); + + m_buffer.fill(QColor(0, 0, 0, int(qreal(255)*0.3))); + QPainter p(&m_buffer); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + l = m_svg->pixmap("bottomleft"); + r = m_svg->pixmap("bottomright"); + c = m_svg->pixmap("bottom"); + p.drawPixmap(pixmapPosition, l); + p.drawTiledPixmap(QRect(l.width(), pixmapPosition.y(), width() - l.width() - r.width(), c.height()), c); + p.drawPixmap(QPoint(width() - r.width(), pixmapPosition.y()), r); + p.end(); + p.begin(this); + p.drawPixmap(QPoint(0, 0), m_buffer); +} + +void GlowBar::setPixmap(const QPoint pos, uint width) +{ + QRect zone = QRect(pos, QSize(width, 10)); + setGeometry(zone); + m_buffer = QPixmap(zone.size()); +} + +void GlowBar::setInputMask() +{ + // Create an empty input mask to achieve click-through effect + // Thanks to MacSlow for this! + Pixmap mask; + + mask = XCreatePixmap(QX11Info::display(), + winId(), + 1, /* width */ + 1, /* height */ + 1 /* depth */); + XShapeCombineMask(QX11Info::display(), + winId(), + ShapeInput, + 0, /* x-offset */ + 0, /* y-offset */ + mask, + ShapeSet); + XFreePixmap(QX11Info::display(), mask); +} +#include "glowbar.moc" diff --git a/appmenu/glowbar.h b/appmenu/glowbar.h new file mode 100644 index 00000000..2d86fc47 --- /dev/null +++ b/appmenu/glowbar.h @@ -0,0 +1,51 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef GLOWBAR__H +#define GLOWBAR__H + +#include + +namespace Plasma +{ + class Svg; +} + +class GlowBar : public QWidget +{ +Q_OBJECT +public: + GlowBar(); + ~GlowBar(); + + void paintEvent(QPaintEvent*); + + void setPixmap(const QPoint pos, uint width); +private: + void setInputMask(); + Plasma::Svg *m_svg; + QPixmap m_buffer; +}; +#endif \ No newline at end of file diff --git a/appmenu/gtkicons.h b/appmenu/gtkicons.h new file mode 100644 index 00000000..d11d73de --- /dev/null +++ b/appmenu/gtkicons.h @@ -0,0 +1,146 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef GTKICONS_H +#define GTKICONS_H + +#include + +class GtkIcons : public QMap +{ + public: + GtkIcons( void ) : QMap () + { + insert(QString("gnome-fs-directory"), QString("folder.png")); + insert(QString("gnome-fs-regular.png"), QString("application-x-zerosize.png")); + insert(QString("gtk-about"), QString("help-about.png")); + insert(QString("gtk-add"), QString("list-add.png")); + insert(QString("gtk-apply"), QString("dialog-ok-apply.png ok-apply.png apply.png")); + insert(QString("gtk-bold"), QString("format-text-bold.png")); + insert(QString("gtk-cancel"), QString("dialog-cancel.png cancel.png")); + insert(QString("gtk-cdrom"), QString("media-optical.png")); + insert(QString("gtk-clear"), QString("edit-clear.png")); + insert(QString("gtk-close"), QString("window-close.png")); + insert(QString("gtk-color-picker"), QString("color-picker.png")); + insert(QString("gtk-connect"), QString("network-connect.png")); + insert(QString("gtk-convert"), QString("document-export.png")); + insert(QString("gtk-copy"), QString("edit-copy.png")); + insert(QString("gtk-cut"), QString("edit-cut.png")); + insert(QString("gtk-delete"), QString("edit-delete.png")); + insert(QString("gtk-dialog-authentication"), QString("dialog-password.png document-encrypt.png object-locked.png")); + insert(QString("gtk-dialog-error"), QString("dialog-error.png")); + insert(QString("gtk-dialog-info"), QString("dialog-information.png")); + insert(QString("gtk-dialog-question"), QString("dialog-information.png")); + insert(QString("gtk-dialog-warning"), QString("dialog-warning.png")); + insert(QString("gtk-directory"), QString("folder.png")); + insert(QString("gtk-disconnect"), QString("network-disconnect.png")); + insert(QString("gtk-dnd"), QString("application-x-zerosize.png")); + insert(QString("gtk-dnd-multiple"), QString("document-multiple.png")); + insert(QString("gtk-edit"), QString("document-properties.png")); + insert(QString("gtk-execute"), QString("fork.png")); + insert(QString("gtk-file"), QString("application-x-zerosize.png")); + insert(QString("gtk-find"), QString("edit-find.png")); + insert(QString("gtk-find-and-replace"), QString("edit-find-replace.png")); + insert(QString("gtk-floppy"), QString("media-floppy.png")); + insert(QString("gtk-fullscreen"), QString("view-fullscreen.png")); + insert(QString("gtk-goto-bottom"), QString("go-bottom.png")); + insert(QString("gtk-goto-first"), QString("go-first.png")); + insert(QString("gtk-goto-last"), QString("go-last.png")); + insert(QString("gtk-goto-top"), QString("go-top.png")); + insert(QString("gtk-go-back"), QString("go-previous.png")); + insert(QString("gtk-go-back-ltr"), QString("go-previous.png")); + insert(QString("gtk-go-back-rtl"), QString("go-next.png")); + insert(QString("gtk-go-down"), QString("go-down.png")); + insert(QString("gtk-go-forward"), QString("go-next.png")); + insert(QString("gtk-go-forward-ltr"), QString("go-next.png")); + insert(QString("gtk-go-forward-rtl"), QString("go-previous.png")); + insert(QString("gtk-go-up"), QString("go-up.png")); + insert(QString("gtk-harddisk"), QString("drive-harddisk.png")); + insert(QString("gtk-help"), QString("help-contents.png")); + insert(QString("gtk-home"), QString("go-home.png")); + insert(QString("gtk-indent"), QString("format-indent-more.png")); + insert(QString("gtk-index"), QString("help-contents.png")); + insert(QString("gtk-info"), QString("help-about.png")); + insert(QString("gtk-italic"), QString("format-text-italic.png")); + insert(QString("gtk-jump-to"), QString("go-jump.png")); + insert(QString("gtk-justify-center"), QString("format-justify-center.png")); + insert(QString("gtk-justify-fill"), QString("format-justify-fill.png")); + insert(QString("gtk-justify-left"), QString("format-justify-left.png")); + insert(QString("gtk-justify-right"), QString("format-justify-right.png")); + insert(QString("gtk-leave-fullscreen"), QString("view-restore.png")); + insert(QString("gtk-media-forward"), QString("media-seek-forward.png")); + insert(QString("gtk-media-next"), QString("media-skip-forward.png")); + insert(QString("gtk-media-pause"), QString("media-playback-pause.png")); + insert(QString("gtk-media-play"), QString("media-playback-start.png")); + insert(QString("gtk-media-previous"), QString("media-skip-backward.png")); + insert(QString("gtk-media-record"), QString("media-record.png")); + insert(QString("gtk-media-rewind"), QString("media-seek-backward.png")); + insert(QString("gtk-media-stop"), QString("media-playback-stop.png")); + insert(QString("gtk-missing-image"), QString("unknown.png")); + insert(QString("gtk-network"), QString("network-server.png")); + insert(QString("gtk-new"), QString("document-new.png")); + insert(QString("gtk-no"), QString("edit-delete.png")); + insert(QString("gtk-ok"), QString("dialog-ok.png ok.png")); + insert(QString("gtk-open"), QString("document-open.png")); + insert(QString("gtk-paste"), QString("edit-paste.png")); + insert(QString("gtk-preferences"), QString("configure.png")); + insert(QString("gtk-print"), QString("document-print.png")); + insert(QString("gtk-print-preview"), QString("document-print-preview.png")); + insert(QString("gtk-properties"), QString("document-properties.png")); + insert(QString("gtk-quit"), QString("application-exit.png")); + insert(QString("gtk-redo"), QString("edit-redo.png")); + insert(QString("gtk-refresh"), QString("view-refresh.png")); + insert(QString("gtk-remove"), QString("edit-delete.png")); + insert(QString("gtk-revert-to-saved"), QString("document-revert.png")); + insert(QString("gtk-save"), QString("document-save.png")); + insert(QString("gtk-save-as"), QString("document-save-as.png")); + insert(QString("gtk-select-all"), QString("edit-select-all.png")); + insert(QString("gtk-select-color"), QString("color-picker.png")); + insert(QString("gtk-select-font"), QString("preferences-desktop-font.png")); + insert(QString("gtk-sort-ascending"), QString("view-sort-ascending.png")); + insert(QString("gtk-sort-descending"), QString("view-sort-descending.png")); + insert(QString("gtk-spell-check"), QString("tools-check-spelling.png")); + insert(QString("gtk-stop"), QString("process-stop.png")); + insert(QString("gtk-strikethrough"), QString("format-text-strikethrough.png")); + insert(QString("gtk-undelete"), QString("edit-undo.png")); + insert(QString("gtk-underline"), QString("format-text-underline.png")); + insert(QString("gtk-undo"), QString("edit-undo.png")); + insert(QString("gtk-unindent"), QString("format-indent-less.png")); + insert(QString("gtk-yes"), QString("dialog-ok.png ok.png")); + insert(QString("gtk-zoom-100"), QString("zoom-original.png")); + insert(QString("gtk-zoom-fit"), QString("zoom-fit-best.png")); + insert(QString("gtk-zoom-in"), QString("zoom-in.png")); + insert(QString("gtk-zoom-out"), QString("zoom-out.png")); + insert(QString("stock_edit-bookmark"), QString("bookmarks-organize.png")); + insert(QString("gimp-edit"), QString("edit.png")); + insert(QString("gimp-info"), QString("dialog-information.png")); + insert(QString("gimp-reset"), QString("reload.png")); + insert(QString("gimp-warning"), QString("dialog-warning.png")); + insert(QString("gimp-tool-options"), QString("tool.png")); + insert(QString("gimp-images"), QString("image.png")); + } +}; + +#endif // GTKICONS_H \ No newline at end of file diff --git a/appmenu/kdbusimporter.h b/appmenu/kdbusimporter.h new file mode 100644 index 00000000..986783b7 --- /dev/null +++ b/appmenu/kdbusimporter.h @@ -0,0 +1,75 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef KDBUSMENUIMPORTER_H +#define KDBUSMENUIMPORTER_H + +#include "gtkicons.h" + +#include +#include + +#include + +#include + +class KDBusMenuImporter : public DBusMenuImporter +{ + +public: + KDBusMenuImporter(WId wid, const QString &service, GtkIcons *icons, const QString &path, QObject *parent) + : DBusMenuImporter(service, path, parent) + , m_service(service) + , m_path(path) + , m_WId(wid) + { + m_icons = icons; + } + + QString service() const { return m_service; } + QString path() const { return m_path; } + WId wid() const { return m_WId; } + +protected: + virtual QIcon iconForName(const QString &name) + { + KIcon icon; + if(m_icons->contains(name)){ + icon = KIcon(m_icons->value(name)); + } + else if(!KIconLoader::global()->iconPath(name, 1, true ).isNull()){ + icon = KIcon(name); + } + return icon; + } + +private: + GtkIcons *m_icons; + QString m_service; + QString m_path; + WId m_WId; +}; + +#endif //KDBUSMENUIMPORTER_H \ No newline at end of file diff --git a/appmenu/menubar.cpp b/appmenu/menubar.cpp new file mode 100644 index 00000000..4c20e201 --- /dev/null +++ b/appmenu/menubar.cpp @@ -0,0 +1,166 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "menubar.h" +#include "shadows.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MenuBar::MenuBar() + : QGraphicsView(), + m_hideTimer(new QTimer(this)), + m_background(new Plasma::FrameSvg(this)), + m_shadows(new Shadows(this)), + m_scene(new QGraphicsScene(this)), + m_container(new MenuWidget(this)) +{ + qreal left, top, right, bottom; + + //Setup the window properties + setWindowFlags(Qt::Tool|Qt::X11BypassWindowManagerHint|Qt::WindowStaysOnTopHint); + setAttribute(Qt::WA_TranslucentBackground); + KWindowSystem::setType(winId(), NET::Dock); + setFrameStyle(QFrame::NoFrame); + viewport()->setAutoFillBackground(false); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + //Setup the widgets + m_background->setImagePath("widgets/tooltip"); + m_background->setEnabledBorders(Plasma::FrameSvg::BottomBorder|Plasma::FrameSvg::LeftBorder|Plasma::FrameSvg::RightBorder); + + m_container->initLayout(); + + m_scene->addItem(m_container); + + setScene(m_scene); + + m_background->getMargins(left, top, right, bottom); + m_container->layout()->setContentsMargins(left, top, right, bottom); + + resize(sizeHint()); + + connect(m_container, SIGNAL(aboutToHide()), this, SLOT(slotAboutToHide())); + connect(m_container, SIGNAL(needResize()), this, SIGNAL(needResize())); + connect(m_hideTimer, SIGNAL(timeout()), this, SLOT(slotAboutToHide())); + + connect(KWindowSystem::self(), SIGNAL(compositingChanged(bool)), this, SLOT(slotCompositingChanged(bool))); +} + +MenuBar::~MenuBar() +{ +} + +QSize MenuBar::sizeHint() const +{ + QSizeF size = m_container->minimumSize(); + return QSize(size.width(), size.height() - m_container->contentBottomMargin()); +} + +void MenuBar::show() +{ + // Add shadow for better readability + if (! Plasma::WindowEffects::isEffectAvailable(Plasma::WindowEffects::BlurBehind)) { + QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(); + shadow->setBlurRadius(5); + shadow->setOffset(QPointF(1, 1)); + shadow->setColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor)); + setGraphicsEffect(shadow); + } else { + setGraphicsEffect(0); + } + m_hideTimer->start(1000); + QGraphicsView::show(); + +} + +void MenuBar::hide() +{ + emit aboutToHide(); + m_hideTimer->stop(); + QGraphicsView::hide(); +} + +void MenuBar::slotAboutToHide() +{ + if (m_container->aMenuIsVisible()) { // MenuBar::m_hideTimer + m_hideTimer->stop(); // menu is visible, menubar will be hidden by another aboutToHide() signal + } + else if (!cursorInMenuBar()) { //MenuWidget::AboutToHide signal + hide(); + } else if (!m_hideTimer->isActive()){ //use click on menubar button while a popup was shown + m_hideTimer->start(1000); + } +} + +void MenuBar::slotCompositingChanged(bool) +{ + updateMask(); +} + +bool MenuBar::cursorInMenuBar() +{ + return QRect(pos(), size()).contains(QCursor::pos()); +} + +void MenuBar::drawBackground(QPainter *painter, const QRectF &/*rectF*/) +{ + painter->save(); + painter->setCompositionMode(QPainter::CompositionMode_Source); + m_background->paintFrame(painter); + painter->restore(); +} + +void MenuBar::resizeEvent(QResizeEvent*) +{ + m_background->resizeFrame(size()); + m_scene->setSceneRect(0, 0, width(), height()); + updateMask(); +} + +void MenuBar::updateMask() +{ + // Enable the mask only when compositing is disabled; + // As this operation is quite slow, it would be nice to find some + // way to workaround it for no-compositing users. + if (KWindowSystem::compositingActive()) { + clearMask(); + Plasma::WindowEffects::overrideShadow(winId(), true); + Plasma::WindowEffects::enableBlurBehind(winId(), true, m_background->mask()); + m_shadows->addWindow(this, Plasma::FrameSvg::BottomBorder|Plasma::FrameSvg::LeftBorder|Plasma::FrameSvg::RightBorder); + } else { + setMask(m_background->mask()); + } +} \ No newline at end of file diff --git a/appmenu/menubar.h b/appmenu/menubar.h new file mode 100644 index 00000000..69ca1ebe --- /dev/null +++ b/appmenu/menubar.h @@ -0,0 +1,87 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MENUBAR__H +#define MENUBAR__H + +#include "menuwidget.h" + +#include + +class QMenu; +class Shadows; + +namespace Plasma +{ + class FrameSvg; +} + +class MenuBar : public QGraphicsView +{ +Q_OBJECT +public: + MenuBar(); + ~MenuBar(); + + /** + * Set root menu + */ + void setMenu(QMenu *menu) { m_container->setMenu(menu); } + /** + * Auto open menu items on mouse over + */ + void autoOpen() { m_container->autoOpen(); } + /** + * Set action as active menubar action + */ + void setActiveAction(QAction *action) { m_container->setActiveAction(action); } + + virtual QSize sizeHint() const; + virtual void show(); + virtual void hide(); + +private Q_SLOTS: + void slotAboutToHide(); + void slotCompositingChanged(bool); +Q_SIGNALS: + void needResize(); + void aboutToHide(); +protected: + /** + * Return true if cursor in menubar + */ + virtual bool cursorInMenuBar(); + virtual void drawBackground(QPainter* painter, const QRectF &rectF); + virtual void resizeEvent(QResizeEvent* event); +private: + void updateMask(); + QTimer* m_hideTimer; + Plasma::FrameSvg* m_background; + Shadows *m_shadows; + QGraphicsScene* m_scene; + MenuWidget* m_container; +}; + +#endif diff --git a/appmenu/menubutton.cpp b/appmenu/menubutton.cpp new file mode 100644 index 00000000..10c143a3 --- /dev/null +++ b/appmenu/menubutton.cpp @@ -0,0 +1,85 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "menubutton.h" + +#include +#include +#include + +#include + +MenuButton::MenuButton(QGraphicsWidget *parent): + Plasma::ToolButton(parent), + m_enterEvent(false), + m_menu(0) +{ + QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect(); + shadow->setBlurRadius(5); + shadow->setOffset(QPointF(1, 1)); + shadow->setColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor)); + setGraphicsEffect(shadow); +} + +void MenuButton::setHovered(bool hovered) +{ + if (hovered) { + hoverEnterEvent(0); + } else { + hoverLeaveEvent(0); + } +} + +QSizeF MenuButton::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const +{ + QSizeF sh = Plasma::ToolButton::sizeHint(which, constraint); + if (which == Qt::MinimumSize || which == Qt::PreferredSize) { + sh.setHeight(nativeWidget()->fontMetrics().height() + bottomMargin()); + } + return sh; +} + +qreal MenuButton::bottomMargin() const +{ + qreal left, right, top, bottom; + getContentsMargins(&left, &right, &top, &bottom); + return bottom; +} + +void MenuButton::hoverEnterEvent(QGraphicsSceneHoverEvent *e) +{ + m_enterEvent = true; + Plasma::ToolButton::hoverEnterEvent(e); +} + +void MenuButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *e) +{ + if (m_enterEvent) { + m_enterEvent = false; + Plasma::ToolButton::hoverLeaveEvent(e); + } +} + +#include "menubutton.moc" \ No newline at end of file diff --git a/appmenu/menubutton.h b/appmenu/menubutton.h new file mode 100644 index 00000000..a7702dcf --- /dev/null +++ b/appmenu/menubutton.h @@ -0,0 +1,54 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MENUBUTTON__H +#define MENUBUTTON__H + +#include +#include + +class QMenu; + +class MenuButton : public Plasma::ToolButton +{ +Q_OBJECT +public: + MenuButton(QGraphicsWidget *parent); + + void setHovered(bool hovered); + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF& constraint) const; + qreal bottomMargin() const; + + void setMenu(QMenu *menu) { m_menu = menu; } + QMenu* menu() { return m_menu; } +protected: + void hoverEnterEvent(QGraphicsSceneHoverEvent *); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *); +private: + bool m_enterEvent; + QMenu *m_menu; +}; +#endif diff --git a/appmenu/menuimporter.cpp b/appmenu/menuimporter.cpp new file mode 100644 index 00000000..b55b7d3b --- /dev/null +++ b/appmenu/menuimporter.cpp @@ -0,0 +1,224 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "menuimporter.h" +#include "menuimporteradaptor.h" + +#include +#include +#include +#include + +#include +#include +#include + +static const char* DBUS_SERVICE = "com.canonical.AppMenu.Registrar"; +static const char* DBUS_OBJECT_PATH = "/com/canonical/AppMenu/Registrar"; + +// Marshalling code for DBusMenuLayoutItem +QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &obj) +{ + argument.beginStructure(); + argument << obj.id << obj.properties; + argument.beginArray(qMetaTypeId()); + Q_FOREACH(const DBusMenuLayoutItem& child, obj.children) { + argument << QDBusVariant(QVariant::fromValue(child)); + } + argument.endArray(); + argument.endStructure(); + return argument; +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &obj) +{ + argument.beginStructure(); + argument >> obj.id >> obj.properties; + argument.beginArray(); + while (!argument.atEnd()) { + QDBusVariant dbusVariant; + argument >> dbusVariant; + QDBusArgument childArgument = dbusVariant.variant().value(); + + DBusMenuLayoutItem child; + childArgument >> child; + obj.children.append(child); + } + argument.endArray(); + argument.endStructure(); + return argument; +} + +MenuImporter::MenuImporter(QObject* parent) +: QObject(parent) +, m_serviceWatcher(new QDBusServiceWatcher(this)) +{ + qDBusRegisterMetaType(); + m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); + m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); + connect(m_serviceWatcher, SIGNAL(serviceUnregistered(const QString&)), SLOT(slotServiceUnregistered(const QString&))); + + QDBusConnection::sessionBus().connect("", "", "com.canonical.dbusmenu", "LayoutUpdated", + this, SLOT(slotLayoutUpdated(uint,int))); +} + +MenuImporter::~MenuImporter() +{ + QDBusConnection::sessionBus().unregisterService(DBUS_SERVICE); + QDBusConnection::sessionBus().disconnect("", "", "com.canonical.dbusmenu", "LayoutUpdated", + this, SLOT(slotLayoutUpdated(uint,int))); +} + +bool MenuImporter::connectToBus() +{ + if (!QDBusConnection::sessionBus().registerService(DBUS_SERVICE)) { + return false; + } + new MenuImporterAdaptor(this); + QDBusConnection::sessionBus().registerObject(DBUS_OBJECT_PATH, this); + + return true; +} + +WId MenuImporter::recursiveMenuId(WId id) +{ + KWindowInfo info = KWindowSystem::windowInfo(id, 0, NET::WM2WindowClass); + QString classClass = info.windowClassClass(); + WId classId = 0; + + // First look at transient windows + WId tid = KWindowSystem::transientFor(id); + while (tid) { + if (serviceExist(tid)) { + classId = tid; + break; + } + tid = KWindowSystem::transientFor(tid); + } + + if (classId == 0) { + // Look at friends windows + QHashIterator i(m_windowClasses); + while (i.hasNext()) { + i.next(); + if (i.value() == classClass) { + classId = i.key(); + } + } + } + + return classId; +} + +void MenuImporter::RegisterWindow(WId id, const QDBusObjectPath& path) +{ + KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMWindowType); + unsigned long mask = NET::AllTypesMask; + + // Menu can try to register, right click in gimp for exemple + if (info.windowType(mask) & (NET::Menu|NET::DropdownMenu||NET::PopupMenu)) { + return; + } + + if (path.path().isEmpty()) //prevent bad dbusmenu usage + return; + + QString service = message().service(); + + info = KWindowSystem::windowInfo(id, 0, NET::WM2WindowClass); + QString classClass = info.windowClassClass(); + m_windowClasses.insert(id, classClass); + m_menuServices.insert(id, service); + m_menuPaths.insert(id, path); + if (! m_serviceWatcher->watchedServices().contains(service)) { + m_serviceWatcher->addWatchedService(service); + } + emit WindowRegistered(id, service, path); +} + +void MenuImporter::UnregisterWindow(WId id) +{ + m_menuServices.remove(id); + m_menuPaths.remove(id); + m_windowClasses.remove(id); + + emit WindowUnregistered(id); +} + +QString MenuImporter::GetMenuForWindow(WId id, QDBusObjectPath& path) +{ + path = m_menuPaths.value(id); + return m_menuServices.value(id); +} + +void MenuImporter::slotServiceUnregistered(const QString& service) +{ + WId id = m_menuServices.key(service); + m_menuServices.remove(id); + m_menuPaths.remove(id); + m_windowClasses.remove(id); + emit WindowUnregistered(id); + m_serviceWatcher->removeWatchedService(service); +} + +void MenuImporter::slotLayoutUpdated(uint /*revision*/, int parentId) +{ + // Fake unity-panel-service weird behavior of calling aboutToShow on + // startup. This is necessary for Firefox menubar to work correctly at + // startup. + // See: https://bugs.launchpad.net/plasma-idget-menubar/+bug/878165 + + if (parentId == 0) { //root menu + fakeUnityAboutToShow(); + } +} + +void MenuImporter::fakeUnityAboutToShow() +{ + QDBusInterface iface(message().service(), message().path(), "com.canonical.dbusmenu"); + QDBusPendingCall call = iface.asyncCall("GetLayout", 0, 1, QStringList()); + QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(call, this); + watcher->setProperty("service", message().service()); + watcher->setProperty("path", message().path()); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + SLOT(finishFakeUnityAboutToShow(QDBusPendingCallWatcher*))); +} + +void MenuImporter::finishFakeUnityAboutToShow(QDBusPendingCallWatcher* watcher) +{ + QDBusPendingReply reply = *watcher; + if (reply.isError()) { + kWarning() << "Call to GetLayout failed:" << reply.error().message(); + return; + } + QString service = watcher->property("service").toString(); + QString path = watcher->property("path").toString(); + DBusMenuLayoutItem root = reply.argumentAt<1>(); + + QDBusInterface iface(service, path, "com.canonical.dbusmenu"); + Q_FOREACH(const DBusMenuLayoutItem& dbusMenuItem, root.children) { + iface.asyncCall("AboutToShow", dbusMenuItem.id); + } +} diff --git a/appmenu/menuimporter.h b/appmenu/menuimporter.h new file mode 100644 index 00000000..adfc5422 --- /dev/null +++ b/appmenu/menuimporter.h @@ -0,0 +1,98 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MENUIMPORTER_H +#define MENUIMPORTER_H + +// Qt +#include +#include +#include +#include // For WId + +class QDBusObjectPath; +class QDBusPendingCallWatcher; +class QDBusServiceWatcher; +class QMenu; + +/** + * Represents an item with its children. GetLayout() returns a + * DBusMenuLayoutItemList. + */ +struct DBusMenuLayoutItem +{ + int id; + QVariantMap properties; + QList children; +}; +Q_DECLARE_METATYPE(DBusMenuLayoutItem) + +class MenuImporter : public QObject, protected QDBusContext +{ + Q_OBJECT + +public: + MenuImporter(QObject*); + ~MenuImporter(); + + bool connectToBus(); + + bool serviceExist(WId id) { return m_menuServices.contains(id); } + QString serviceForWindow(WId id) { return m_menuServices.value(id); } + + bool pathExist(WId id) { return m_menuPaths.contains(id); } + QString pathForWindow(WId id) { return m_menuPaths.value(id).path(); } + + QList ids() { return m_menuServices.keys(); } + + /** + * Return id of first transient/friend window with a menu available + */ + WId recursiveMenuId(WId id); + +Q_SIGNALS: + void WindowRegistered(WId id, const QString& service, const QDBusObjectPath&); + void WindowUnregistered(WId id); + +public Q_SLOTS: + Q_NOREPLY void RegisterWindow(WId id, const QDBusObjectPath& path); + Q_NOREPLY void UnregisterWindow(WId id); + QString GetMenuForWindow(WId id, QDBusObjectPath& path); + +private Q_SLOTS: + void slotServiceUnregistered(const QString& service); + void slotLayoutUpdated(uint revision, int parentId); + void finishFakeUnityAboutToShow(QDBusPendingCallWatcher*); + +private: + QDBusServiceWatcher* m_serviceWatcher; + QHash m_menuServices; + QHash m_menuPaths; + QHash m_windowClasses; + + void fakeUnityAboutToShow(); +}; + +#endif /* MENUIMPORTER_H */ diff --git a/appmenu/menuwidget.cpp b/appmenu/menuwidget.cpp new file mode 100644 index 00000000..0a3b4f2a --- /dev/null +++ b/appmenu/menuwidget.cpp @@ -0,0 +1,387 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "menuwidget.h" + +#include +#include +#include +#include + +#include +#include +#include + +MenuWidget::MenuWidget(QGraphicsView *view) : + QGraphicsWidget(), + m_mouseTimer(new QTimer(this)), + m_actionTimer(new QTimer(this)), + m_view(view), + m_layout(new QGraphicsLinearLayout(this)), + m_currentButton(0), + m_contentBottomMargin(0), + m_mousePosition(-1, -1), + m_visibleMenu(0), + m_menu(0) +{ + connect(m_actionTimer, SIGNAL(timeout()), SLOT(slotUpdateActions())); + connect(m_mouseTimer, SIGNAL(timeout()), SLOT(slotCheckActiveItem())); +} + +MenuWidget::~MenuWidget() +{ + while (!m_buttons.isEmpty()) { + delete m_buttons.front(); + m_buttons.pop_front(); + } +} + +void MenuWidget::setMenu(QMenu *menu) +{ + if (m_menu) { + disconnect(m_menu, SIGNAL(destroyed()), this, SLOT(slotMenuDestroyed())); + m_menu->removeEventFilter(this); + } + if (menu) { + if (m_mouseTimer->isActive()) { + m_mouseTimer->stop(); + } + m_visibleMenu = 0; + m_menu = menu; + connect(m_menu, SIGNAL(destroyed()), SLOT(slotMenuDestroyed()), Qt::UniqueConnection); + m_menu->installEventFilter(this); + slotUpdateActions(); + } +} + +void MenuWidget::initLayout() +{ + MenuButton* button = 0; + + if (!m_menu) { + return; + } + + foreach (QAction* action, m_menu->actions()) + { + button = createButton(action); + if (button) { + m_layout->addItem(button); + button->setMenu(action->menu()); + m_buttons << button; + } + } + + //Assume all buttons have same margins + if (button) { + m_contentBottomMargin = button->bottomMargin(); + } +} + +bool MenuWidget::eventFilter(QObject* object, QEvent* event) +{ + bool filtered; + if (object == m_menu) { + filtered = menuEventFilter(event); + } else { + filtered = subMenuEventFilter(static_cast(object), event); + } + return filtered ? true : QGraphicsWidget::eventFilter(object, event); +} + +bool MenuWidget::menuEventFilter(QEvent* event) +{ + switch (event->type()) { + case QEvent::ActionAdded: + case QEvent::ActionRemoved: + case QEvent::ActionChanged: + // Try to limit layout updates + m_actionTimer->start(500); + break; + default: + break; + } + return false; +} + +bool MenuWidget::subMenuEventFilter(QObject* object, QEvent* event) +{ + QMenu *menu = static_cast(object); + + if (event->type() == QEvent::KeyPress) { + menu->removeEventFilter(this); + QApplication::sendEvent(menu, event); + menu->installEventFilter(this); + if (!event->isAccepted()) { + QKeyEvent* keyEvent = static_cast(event); + switch (keyEvent->key()) { + case Qt::Key_Left: + showLeftRightMenu(false); + break; + case Qt::Key_Right: + showLeftRightMenu(true); + break; + case Qt::Key_Escape: + menu->hide(); + break; + default: + break; + } + } + return true; + } + return false; +} + +void MenuWidget::slotMenuDestroyed() +{ + m_menu = 0; + m_visibleMenu = 0; + m_currentButton = 0; +} + +void MenuWidget::slotCheckActiveItem() +{ + MenuButton* buttonBelow = 0; + QPoint pos = m_view->mapFromGlobal(QCursor::pos()); + QGraphicsItem* item = m_view->itemAt(pos); + + if (pos == m_mousePosition) { + return; + } else { + m_mousePosition = pos; + } + + if (item) { + buttonBelow = qobject_cast(item->toGraphicsObject()); + } + + if (!buttonBelow) { + return; + } + + if (buttonBelow != m_currentButton) { + if (m_currentButton && m_currentButton->nativeWidget()) { + m_currentButton->nativeWidget()->setDown(false); + m_currentButton->setHovered(false); + } + m_currentButton = buttonBelow; + if (m_currentButton->nativeWidget()) { + m_currentButton->nativeWidget()->setDown(true); + } + m_visibleMenu = showMenu(); + } +} + +void MenuWidget::slotMenuAboutToHide() +{ + if (m_currentButton && m_currentButton->nativeWidget()) { + m_currentButton->nativeWidget()->setDown(false); + } + + if (m_mouseTimer->isActive()) { + m_mouseTimer->stop(); + } + m_visibleMenu = 0; + emit aboutToHide(); +} + +void MenuWidget::slotButtonClicked() +{ + m_currentButton = qobject_cast(sender()); + + if (m_currentButton && m_currentButton->nativeWidget()) { + m_currentButton->nativeWidget()->setDown(true); + } + m_visibleMenu = showMenu(); + // Start auto navigation after click + if (!m_mouseTimer->isActive()) + m_mouseTimer->start(100); +} + +void MenuWidget::slotUpdateActions() +{ + if (m_visibleMenu) { + return; // Later + } + + m_actionTimer->stop(); + m_currentButton = 0; + foreach (MenuButton *button, m_buttons) { + disconnect(button, SIGNAL(clicked()), this, SLOT(slotButtonClicked())); + m_layout->removeItem(button); + button->hide(); + m_buttons.removeOne(button); + delete button; + } + initLayout(); + // Menu may be empty on application startup + // slotUpdateActions will be called later by eventFilter() + if (m_menu && m_menu->actions().length()) { + emit needResize(); + } +} + +void MenuWidget::setActiveAction(QAction *action) +{ + if (!m_menu) { + return; + } + + m_currentButton = m_buttons.first(); + + if (action) { + QMenu *menu; + int i = 0; + foreach (MenuButton *button, m_buttons) { + menu = m_menu->actions()[i]->menu(); + if (menu && menu == action->menu()) { + m_currentButton = button; + break; + } + if (++i >= m_menu->actions().length()) { + break; + } + } + } + m_currentButton->nativeWidget()->animateClick(); +} + +void MenuWidget::hide() +{ + if (m_mouseTimer->isActive()) { + m_mouseTimer->stop(); + } + QGraphicsWidget::hide(); +} + +MenuButton* MenuWidget::createButton(QAction *action) +{ + if( action->isSeparator() || !action->menu() || !action->isVisible()) { + return 0; + } + + action->setShortcut(QKeySequence()); + MenuButton *button = new MenuButton(this); + button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); + button->setText(action->text()); + connect(button, SIGNAL(clicked()), SLOT(slotButtonClicked())); + return button; +} + +QMenu* MenuWidget::showMenu() +{ + QMenu *menu = 0; + + if (m_visibleMenu) { + disconnect(m_visibleMenu, SIGNAL(aboutToHide()), this, SLOT(slotMenuAboutToHide())); + m_visibleMenu->hide(); + } + + if (m_currentButton && m_menu) { + menu = m_currentButton->menu(); + } + + // Last chance to get menu + // Some applications like Firefox have empties menus on layout updates + // They should populate this menu later but in fact, they use another object + // So, we check here directly the button name, may fail with menubar with buttons with same name (test apps) + if (menu && menu->actions().length() == 0) { + foreach (QAction *action, m_menu->actions()) { + if (action->text() == m_currentButton->text()) { + menu = action->menu(); + break; + } + } + } + + if (menu) { + QPoint globalPos = m_view->mapToGlobal(QPoint(0,0)); + QPointF parentPos = m_currentButton->mapFromParent(QPoint(0,0)); + QRect screen = KApplication::desktop()->screenGeometry(); + int x = globalPos.x() - parentPos.x(); + int y = globalPos.y() + m_currentButton->size().height() - parentPos.y(); + + menu->popup(QPoint(x, y)); + + // Fix offscreen menu + if (menu->size().height() + y > screen.height() + screen.y()) { + y = globalPos.y() - parentPos.y() - menu->size().height(); + if (menu->size().width() + x > screen.width() + screen.x()) + x = screen.width() + screen.x() - menu->size().width(); + else if (menu->size().width() + x < screen.x()) + x = screen.x(); + menu->move(x, y); + } + + connect(menu, SIGNAL(aboutToHide()), this, SLOT(slotMenuAboutToHide())); + + installEventFilterForAll(menu, this); + } + return menu; +} + +void MenuWidget::showLeftRightMenu(bool next) +{ + if (!m_currentButton) { + return; + } + + int index = m_buttons.indexOf(m_currentButton); + if (index == -1) { + kWarning() << "Couldn't find button!"; + return; + } + if (next) { + index = (index + 1) % m_buttons.count(); + } else { + index = (index == 0 ? m_buttons.count() : index) - 1; + } + + if (m_currentButton && m_currentButton->nativeWidget()) { + m_currentButton->nativeWidget()->setDown(false); + } + m_currentButton = m_buttons.at(index); + if (m_currentButton && m_currentButton->nativeWidget()) { + m_currentButton->nativeWidget()->setDown(true); + } + m_visibleMenu = showMenu(); +} + +void MenuWidget::installEventFilterForAll(QMenu *menu, QObject *object) +{ + if (!menu) { + return; + } + + menu->installEventFilter(this); + + foreach (QAction *action, menu->actions()) { + if (action->menu()) + installEventFilterForAll(action->menu(), object); + } +} + +#include "menuwidget.moc" \ No newline at end of file diff --git a/appmenu/menuwidget.h b/appmenu/menuwidget.h new file mode 100644 index 00000000..1f47a83a --- /dev/null +++ b/appmenu/menuwidget.h @@ -0,0 +1,143 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MENUWIDGET__H +#define MENUWIDGET__H + +#include "menubutton.h" + +#include +#include + +class QGraphicsLinearLayout; +class QGraphicsView; + +class MenuWidget : public QGraphicsWidget +{ +Q_OBJECT +public: + MenuWidget(QGraphicsView *view = 0); + ~MenuWidget(); + + /** + * Set root menu + */ + void setMenu(QMenu *menu); + /** + * Init layout with root menu + */ + void initLayout(); + /** + * True if a menu is visible in menuwidget + */ + bool aMenuIsVisible() { return m_visibleMenu; } + /** + * Activate action, or first action if null + */ + void setActiveAction(QAction *action); + + /** + * Auto open menu items on mouse over + */ + void autoOpen() { m_mouseTimer->start(100); } + + /** + * Return content bottom margin + */ + qreal contentBottomMargin() { return m_contentBottomMargin; } + + void hide(); + +protected: + /** + * Use to get keyboard events + */ + virtual bool eventFilter(QObject*, QEvent*); + /** + * Filter events on main menu + */ + bool menuEventFilter(QEvent* event); + /** + * Filter events on submenus + */ + bool subMenuEventFilter(QObject* object, QEvent* event); +private Q_SLOTS: + /** + * Clean menu if destroyed + */ + void slotMenuDestroyed(); + /** + * Check hovered item and active it + */ + void slotCheckActiveItem(); + /** + * A menu is hidding + */ + void slotMenuAboutToHide(); + /** + * Menubar button clicked + */ + void slotButtonClicked(); + /** + * Update pending actions + */ + void slotUpdateActions(); +Q_SIGNALS: + void needResize(); + void aboutToHide(); +private: + /** + * Return a button based on action + */ + MenuButton* createButton(QAction *action); + /** + * Show current button menu + * return showed menu + */ + QMenu* showMenu(); + /** + * Show next menu if next, otherwise previous + */ + void showLeftRightMenu(bool next); + /** + * Install event filter for menu and it submenus + */ + void installEventFilterForAll(QMenu *menu, QObject *object); + + //Follow mouse position + QTimer *m_mouseTimer; + //Update actions + QTimer *m_actionTimer; + QGraphicsView *m_view; + QGraphicsLinearLayout *m_layout; + QList m_buttons; + MenuButton *m_currentButton; + qreal m_contentBottomMargin; + QPoint m_mousePosition; + QMenu *m_visibleMenu; + QMenu *m_menu; +}; + +#endif //MENUWIDGET__H diff --git a/appmenu/org.kde.kded.appmenu.xml b/appmenu/org.kde.kded.appmenu.xml new file mode 100644 index 00000000..8056fba3 --- /dev/null +++ b/appmenu/org.kde.kded.appmenu.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/appmenu/shadows.cpp b/appmenu/shadows.cpp new file mode 100644 index 00000000..bcf27d9d --- /dev/null +++ b/appmenu/shadows.cpp @@ -0,0 +1,381 @@ +/* +* Copyright 2011 by Aaron Seigo +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License version 2, +* or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "shadows.h" + +#include +#include + +#ifdef Q_WS_X11 +#include +#include +#include +#include +#endif + +#include +#include + +class Shadows::Private +{ +public: + Private(Shadows *shadows) + : q(shadows), + m_managePixmaps(false) + { + } + + ~Private() + { + clearPixmaps(); + } + + void clearPixmaps(); + void setupPixmaps(); + void initPixmap(const QString &element); + QPixmap initEmptyPixmap(const QSize &size); + void updateShadow(const QWidget *window, Plasma::FrameSvg::EnabledBorders); + void clearShadow(const QWidget *window); + void updateShadows(); + void windowDestroyed(QObject *deletedObject); + void setupData(Plasma::FrameSvg::EnabledBorders enabledBorders); + + Shadows *q; + QList m_shadowPixmaps; + + QPixmap m_emptyCornerPix; + QPixmap m_emptyCornerLeftPix; + QPixmap m_emptyCornerTopPix; + QPixmap m_emptyCornerRightPix; + QPixmap m_emptyCornerBottomPix; + QPixmap m_emptyVerticalPix; + QPixmap m_emptyHorizontalPix; + + QHash > data; + QHash m_windows; + bool m_managePixmaps; +}; + +class ShadowsSingleton +{ +public: + ShadowsSingleton() + { + } + + Shadows self; +}; + +K_GLOBAL_STATIC(ShadowsSingleton, privateShadowsSelf) + +Shadows::Shadows(QObject *parent, const QString &prefix) + : Plasma::Svg(parent), + d(new Private(this)) +{ + setImagePath(prefix); + connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateShadows())); +} + +Shadows *Shadows::self() +{ + return &privateShadowsSelf->self; +} + +void Shadows::addWindow(const QWidget *window, Plasma::FrameSvg::EnabledBorders enabledBorders) +{ + if (!window || !window->isWindow()) { + return; + } + + d->m_windows[window] = enabledBorders; + d->updateShadow(window, enabledBorders); + connect(window, SIGNAL(destroyed(QObject*)), + this, SLOT(windowDestroyed(QObject*)), Qt::UniqueConnection); +} + +void Shadows::removeWindow(const QWidget *window) +{ + if (!d->m_windows.contains(window)) { + return; + } + + d->m_windows.remove(window); + disconnect(window, 0, this, 0); + d->clearShadow(window); + + if (d->m_windows.isEmpty()) { + d->clearPixmaps(); + } +} + +void Shadows::Private::windowDestroyed(QObject *deletedObject) +{ + m_windows.remove(static_cast(deletedObject)); + + if (m_windows.isEmpty()) { + clearPixmaps(); + } +} + +void Shadows::Private::updateShadows() +{ + setupPixmaps(); + QHash::const_iterator i; + for (i = m_windows.constBegin(); i != m_windows.constEnd(); ++i) { + updateShadow(i.key(), i.value()); + } +} + +void Shadows::Private::initPixmap(const QString &element) +{ +#ifdef Q_WS_X11 + QPixmap pix = q->pixmap(element); + if (!pix.isNull() && pix.handle() == 0) { + Pixmap xPix = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), pix.width(), pix.height(), 32); + QPixmap tempPix = QPixmap::fromX11Pixmap(xPix, QPixmap::ExplicitlyShared); + tempPix.fill(Qt::transparent); + QPainter p(&tempPix); + p.drawPixmap(QPoint(0, 0), pix); + m_shadowPixmaps << tempPix; + m_managePixmaps = true; + } else { + m_shadowPixmaps << pix; + } +#endif +} + +QPixmap Shadows::Private::initEmptyPixmap(const QSize &size) +{ + Pixmap emptyXPix = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), size.width(), size.height(), 32); + QPixmap tempEmptyPix = QPixmap::fromX11Pixmap(emptyXPix, QPixmap::ExplicitlyShared); + tempEmptyPix.fill(Qt::transparent); + return tempEmptyPix; +} + +void Shadows::Private::setupPixmaps() +{ + clearPixmaps(); + initPixmap("shadow-top"); + initPixmap("shadow-topright"); + initPixmap("shadow-right"); + initPixmap("shadow-bottomright"); + initPixmap("shadow-bottom"); + initPixmap("shadow-bottomleft"); + initPixmap("shadow-left"); + initPixmap("shadow-topleft"); + + m_emptyCornerPix = initEmptyPixmap(QSize(1,1)); + m_emptyCornerLeftPix = initEmptyPixmap(QSize(q->elementSize("shadow-topleft").width(), 1)); + m_emptyCornerTopPix = initEmptyPixmap(QSize(1, q->elementSize("shadow-topleft").height())); + m_emptyCornerRightPix = initEmptyPixmap(QSize(q->elementSize("shadow-bottomright").width(), 1)); + m_emptyCornerBottomPix = initEmptyPixmap(QSize(1, q->elementSize("shadow-bottomright").height())); + m_emptyVerticalPix = initEmptyPixmap(QSize(1, q->elementSize("shadow-left").height())); + m_emptyHorizontalPix = initEmptyPixmap(QSize(q->elementSize("shadow-top").width(), 1)); + +} + + +void Shadows::Private::setupData(Plasma::FrameSvg::EnabledBorders enabledBorders) +{ +#ifdef Q_WS_X11 + //shadow-top + if (enabledBorders & Plasma::FrameSvg::TopBorder) { + data[enabledBorders] << m_shadowPixmaps[0].handle(); + } else { + data[enabledBorders] << m_emptyHorizontalPix.handle(); + } + + //shadow-topright + if (enabledBorders & Plasma::FrameSvg::TopBorder && + enabledBorders & Plasma::FrameSvg::RightBorder) { + data[enabledBorders] << m_shadowPixmaps[1].handle(); + } else if (enabledBorders & Plasma::FrameSvg::TopBorder) { + data[enabledBorders] << m_emptyCornerTopPix.handle(); + } else if (enabledBorders & Plasma::FrameSvg::RightBorder) { + data[enabledBorders] << m_emptyCornerRightPix.handle(); + } else { + data[enabledBorders] << m_emptyCornerPix.handle(); + } + + //shadow-right + if (enabledBorders & Plasma::FrameSvg::RightBorder) { + data[enabledBorders] << m_shadowPixmaps[2].handle(); + } else { + data[enabledBorders] << m_emptyVerticalPix.handle(); + } + + //shadow-bottomright + if (enabledBorders & Plasma::FrameSvg::BottomBorder && + enabledBorders & Plasma::FrameSvg::RightBorder) { + data[enabledBorders] << m_shadowPixmaps[3].handle(); + } else if (enabledBorders & Plasma::FrameSvg::BottomBorder) { + data[enabledBorders] << m_emptyCornerBottomPix.handle(); + } else if (enabledBorders & Plasma::FrameSvg::RightBorder) { + data[enabledBorders] << m_emptyCornerRightPix.handle(); + } else { + data[enabledBorders] << m_emptyCornerPix.handle(); + } + + //shadow-bottom + if (enabledBorders & Plasma::FrameSvg::BottomBorder) { + data[enabledBorders] << m_shadowPixmaps[4].handle(); + } else { + data[enabledBorders] << m_emptyHorizontalPix.handle(); + } + + //shadow-bottomleft + if (enabledBorders & Plasma::FrameSvg::BottomBorder && + enabledBorders & Plasma::FrameSvg::LeftBorder) { + data[enabledBorders] << m_shadowPixmaps[5].handle(); + } else if (enabledBorders & Plasma::FrameSvg::BottomBorder) { + data[enabledBorders] << m_emptyCornerBottomPix.handle(); + } else if (enabledBorders & Plasma::FrameSvg::LeftBorder) { + data[enabledBorders] << m_emptyCornerLeftPix.handle(); + } else { + data[enabledBorders] << m_emptyCornerPix.handle(); + } + + //shadow-left + if (enabledBorders & Plasma::FrameSvg::LeftBorder) { + data[enabledBorders] << m_shadowPixmaps[6].handle(); + } else { + data[enabledBorders] << m_emptyVerticalPix.handle(); + } + + //shadow-topleft + if (enabledBorders & Plasma::FrameSvg::TopBorder && + enabledBorders & Plasma::FrameSvg::LeftBorder) { + data[enabledBorders] << m_shadowPixmaps[7].handle(); + } else if (enabledBorders & Plasma::FrameSvg::TopBorder) { + data[enabledBorders] << m_emptyCornerTopPix.handle(); + } else if (enabledBorders & Plasma::FrameSvg::LeftBorder) { + data[enabledBorders] << m_emptyCornerLeftPix.handle(); + } else { + data[enabledBorders] << m_emptyCornerPix.handle(); + } +#endif + + int left, top, right, bottom = 0; + + QSize marginHint; + if (enabledBorders & Plasma::FrameSvg::TopBorder) { + marginHint = q->elementSize("shadow-hint-top-margin"); + if (marginHint.isValid()) { + top = marginHint.height(); + } else { + top = m_shadowPixmaps[0].height(); // top + } + } else { + top = 1; + } + + if (enabledBorders & Plasma::FrameSvg::RightBorder) { + marginHint = q->elementSize("shadow-hint-right-margin"); + if (marginHint.isValid()) { + right = marginHint.width(); + } else { + right = m_shadowPixmaps[2].width(); // right + } + } else { + right = 1; + } + + if (enabledBorders & Plasma::FrameSvg::BottomBorder) { + marginHint = q->elementSize("shadow-hint-bottom-margin"); + if (marginHint.isValid()) { + bottom = marginHint.height(); + } else { + bottom = m_shadowPixmaps[4].height(); // bottom + } + } else { + bottom = 1; + } + + if (enabledBorders & Plasma::FrameSvg::LeftBorder) { + marginHint = q->elementSize("shadow-hint-left-margin"); + if (marginHint.isValid()) { + left = marginHint.width(); + } else { + left = m_shadowPixmaps[6].width(); // left + } + } else { + left = 1; + } + + data[enabledBorders] << top << right << bottom << left; +} + +void Shadows::Private::clearPixmaps() +{ +#ifdef Q_WS_X11 + if (m_managePixmaps) { + foreach (const QPixmap &pixmap, m_shadowPixmaps) { + XFreePixmap(QX11Info::display(), pixmap.handle()); + } + + XFreePixmap(QX11Info::display(), m_emptyCornerPix.handle()); + XFreePixmap(QX11Info::display(), m_emptyCornerBottomPix.handle()); + XFreePixmap(QX11Info::display(), m_emptyCornerLeftPix.handle()); + XFreePixmap(QX11Info::display(), m_emptyCornerRightPix.handle()); + XFreePixmap(QX11Info::display(), m_emptyCornerTopPix.handle()); + XFreePixmap(QX11Info::display(), m_emptyVerticalPix.handle()); + XFreePixmap(QX11Info::display(), m_emptyHorizontalPix.handle()); + + m_managePixmaps = false; + } +#endif + m_shadowPixmaps.clear(); + data.clear(); +} + +void Shadows::Private::updateShadow(const QWidget *window, Plasma::FrameSvg::EnabledBorders enabledBorders) +{ +#ifdef Q_WS_X11 + if (m_shadowPixmaps.isEmpty()) { + setupPixmaps(); + } + + if (!data.contains(enabledBorders)) { + setupData(enabledBorders); + } + + Display *dpy = QX11Info::display(); + Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SHADOW", False); + + //kDebug() << "going to set the shadow of" << winId() << "to" << data; + XChangeProperty(dpy, window->winId(), atom, XA_CARDINAL, 32, PropModeReplace, + reinterpret_cast(data[enabledBorders].constData()), data[enabledBorders].size()); +#endif +} + +void Shadows::Private::clearShadow(const QWidget *window) +{ +#ifdef Q_WS_X11 + Display *dpy = QX11Info::display(); + Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SHADOW", False); + XDeleteProperty(dpy, window->winId(), atom); +#endif +} + +bool Shadows::enabled() const +{ + return hasElement("shadow-left"); +} + +#include "shadows.moc" + diff --git a/appmenu/shadows.h b/appmenu/shadows.h new file mode 100644 index 00000000..afbc49ef --- /dev/null +++ b/appmenu/shadows.h @@ -0,0 +1,51 @@ +/* +* Copyright 2011 by Aaron Seigo +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License version 2, +* or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SHADOWS_H +#define SHADOWS_H + +#include + +#include "plasma/framesvg.h" +#include "plasma/svg.h" + + +class Shadows : public Plasma::Svg +{ + Q_OBJECT + +public: + explicit Shadows(QObject *parent = 0, const QString &prefix = "widgets/panel-background"); + + static Shadows *self(); + + void addWindow(const QWidget *window, Plasma::FrameSvg::EnabledBorders enabledBorders = Plasma::FrameSvg::AllBorders); + void removeWindow(const QWidget *window); + + bool enabled() const; + +private: + class Private; + Private * const d; + + Q_PRIVATE_SLOT(d, void updateShadows()) + Q_PRIVATE_SLOT(d, void windowDestroyed(QObject *deletedObject)) +}; + +#endif + diff --git a/appmenu/topmenubar.cpp b/appmenu/topmenubar.cpp new file mode 100644 index 00000000..2ae19b38 --- /dev/null +++ b/appmenu/topmenubar.cpp @@ -0,0 +1,176 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "topmenubar.h" +#include "glowbar.h" + +//KDE +#include +#include + +// Qt +#include +#include +#include +#include +#include +#include + +TopMenuBar::TopMenuBar() + : MenuBar(), + m_prevCursorPos(-1, -1), + m_mouseTracker(new QTimer(this)), + m_hideGlowTimer(new QTimer(this)), + m_glowBar(new GlowBar()) +{ + connect(this, SIGNAL(aboutToHide()), this, SLOT(slotAboutToHide())); + connect(m_mouseTracker, SIGNAL(timeout()), this, SLOT(slotMouseTracker())); + connect(m_hideGlowTimer, SIGNAL(timeout()), this, SLOT(slotHideGlowBar())); +} + +TopMenuBar::~TopMenuBar() +{ + delete m_mouseTracker; + delete m_hideGlowTimer; + hideGlowBar(); + delete m_glowBar; +} + +void TopMenuBar::enableMouseTracking(bool enable) +{ + if (enable) { + if (!cursorInMenuBar()) { + showGlowBar(); + } + m_mouseTracker->start(250); + } else { + hideGlowBar(); + m_mouseTracker->stop(); + } +} + +void TopMenuBar::updateSize() +{ + // Enable mouse tracking on resize if needed + if (!m_mouseTracker->isActive() && !cursorInMenuBar()) { + enableMouseTracking(); + } + resize(sizeHint()); +} + +void TopMenuBar::move(QPoint p) +{ + MenuBar::move(p); + if (m_glowBar) { + m_glowBar->move(p); + m_glowBar->setPixmap(triggerRect().topLeft(), triggerRect().width()); + } +} + +bool TopMenuBar::cursorInMenuBar() +{ + if (m_mouseTracker->isActive()) { + return triggerRect().contains(QCursor::pos()); + } else { + return MenuBar::cursorInMenuBar(); + } +} + +void TopMenuBar::slotAboutToHide() +{ + enableMouseTracking(); +} + +void TopMenuBar::slotMouseTracker() +{ + QPoint cursorPos = QCursor::pos(); + + // reset timer + if (cursorPos != m_prevCursorPos && m_hideGlowTimer->isActive()) { + m_hideGlowTimer->stop(); + m_hideGlowTimer->start(10000); + } + + if (cursorInMenuBar()) { // show menubar + m_mouseTracker->stop(); + hideGlowBar(); + show(); + } else if(cursorPos != m_prevCursorPos) { // change glowbar opacity + qreal opacity = glowBarOpacity(); + QPropertyAnimation *anim = new QPropertyAnimation(m_glowBar, "windowOpacity"); + anim->setStartValue(m_glowBar->windowOpacity()); + anim->setEndValue(opacity); + anim->setDuration(200); + anim->start(QAbstractAnimation::DeleteWhenStopped); + // Show menubar if auto hidden + if (!m_glowBar->isVisible()) { + m_glowBar->show(); + } + } + m_prevCursorPos = cursorPos; +} + +void TopMenuBar::slotHideGlowBar() +{ + if (m_prevCursorPos == QCursor::pos()) { + hideGlowBar(); + } else { + m_hideGlowTimer->start(10000); + } +} + +void TopMenuBar::showGlowBar() +{ + if (m_glowBar) { + m_hideGlowTimer->start(10000); + m_glowBar->setWindowOpacity(glowBarOpacity()); + m_glowBar->show(); + } +} + +void TopMenuBar::hideGlowBar() +{ + if (m_glowBar) { + m_glowBar->hide(); + } +} + +qreal TopMenuBar::glowBarOpacity() +{ + QPoint cursorPos = QCursor::pos(); + QDesktopWidget *desktop = QApplication::desktop(); + int screen = desktop->screenNumber(cursorPos); + QRect desktopRect = desktop->availableGeometry(screen); + return 1.0 - ((cursorPos.y() - desktopRect.y())/qreal(desktopRect.height())*2.0); +} + +QRect TopMenuBar::triggerRect() +{ + QPoint triggerPoint = QPoint(x(), y()); + QSize triggerSize = QSize(sizeHint().width(), 5); + return QRect(triggerPoint, triggerSize); +} + +#include "topmenubar.moc" \ No newline at end of file diff --git a/appmenu/topmenubar.h b/appmenu/topmenubar.h new file mode 100644 index 00000000..8712cfd7 --- /dev/null +++ b/appmenu/topmenubar.h @@ -0,0 +1,81 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef TOPMENUBAR__H +#define TOPMENUBAR__H + +#include "menubar.h" + +class QTimer; +class GlowBar; + +class TopMenuBar : public MenuBar +{ +Q_OBJECT +public: + TopMenuBar(); + ~TopMenuBar(); + + /** + * Start mouse tracking (hide/show on mouse event) + */ + void enableMouseTracking(bool enable = true); + + /** + * Set menubar parent window id + */ + void setParentWid(WId id) { m_wid = id; } + /** + * Get menubar parent window id + */ + WId parentWid() { return m_wid; } + /** + * resize menu bar to feet content + */ + void updateSize(); + /** + * Move menubar and glow bar at position + */ + void move(QPoint p); +protected: + bool cursorInMenuBar(); +private Q_SLOTS: + void slotAboutToHide(); + void slotMouseTracker(); + void slotHideGlowBar(); +private: + void showGlowBar(); + void hideGlowBar(); + qreal glowBarOpacity(); + QRect triggerRect(); + + WId m_wid; + QPoint m_prevCursorPos; + QTimer* m_mouseTracker; + QTimer* m_hideGlowTimer; + GlowBar* m_glowBar; +}; + +#endif diff --git a/appmenu/verticalmenu.cpp b/appmenu/verticalmenu.cpp new file mode 100644 index 00000000..17f0d9bc --- /dev/null +++ b/appmenu/verticalmenu.cpp @@ -0,0 +1,79 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "verticalmenu.h" + +#include +#include +#include +#include +#include + +VerticalMenu::VerticalMenu(QWidget* parent) : QMenu(parent) +{ +} + +VerticalMenu::~VerticalMenu() +{ +} + +QMenu *VerticalMenu::leafMenu() +{ + QMenu *leaf = this; + while (true) { + QAction *act = leaf->activeAction(); + if (act && act->menu() && act->menu()->isVisible()) { + leaf = act->menu(); + continue; + } + return leaf == this ? 0 : leaf; + } + return 0; // make gcc happy +} + +void VerticalMenu::paintEvent(QPaintEvent *pe) +{ + QMenu::paintEvent(pe); + if (QWidget::mouseGrabber() == this) + return; + if (QWidget::mouseGrabber()) + QWidget::mouseGrabber()->releaseMouse(); + grabMouse(); + grabKeyboard(); +} + +#define FORWARD(_EVENT_, _TYPE_) \ +void VerticalMenu::_EVENT_##Event(Q##_TYPE_##Event *e) \ +{ \ + if (QMenu *leaf = leafMenu()) \ + QCoreApplication::sendEvent(leaf, e); \ + else \ + QMenu::_EVENT_##Event(e); \ +} \ + +FORWARD(keyPress, Key) +FORWARD(keyRelease, Key) + +#include "verticalmenu.moc" \ No newline at end of file diff --git a/appmenu/verticalmenu.h b/appmenu/verticalmenu.h new file mode 100644 index 00000000..1b28ce27 --- /dev/null +++ b/appmenu/verticalmenu.h @@ -0,0 +1,56 @@ +/* + This file is part of the KDE project. + + Copyright (c) 2011 Lionel Chauvin + Copyright (c) 2011,2012 Cédric Bellegarde + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef VERTICALMENU_H +#define VERTICALMENU_H + +#include + +class VerticalMenu : public QMenu +{ +Q_OBJECT +public: + VerticalMenu(QWidget * parent = 0); + ~VerticalMenu(); + + /** + * Set menu parent window id + */ + void setParentWid(WId id) { m_wid = id; } + /** + * Get menu parent window id + */ + WId parentWid() { return m_wid; } +protected: + void keyPressEvent(QKeyEvent*); + void keyReleaseEvent(QKeyEvent*); + void paintEvent(QPaintEvent*); +private: + QMenu *leafMenu(); +private: + WId m_wid; +}; + +#endif //VERTICALMENU_H diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 00000000..38a9971a --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_subdirectory(modules) + diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt new file mode 100644 index 00000000..117b3a55 --- /dev/null +++ b/cmake/modules/CMakeLists.txt @@ -0,0 +1,17 @@ +# install the cmake files + +# don't glob for the files, since we don't want to +# install e.g. FindLibKNotification-1.cmake +set(cmakeFiles FindCkConnector.cmake + FindDBus.cmake + FindLibXKlavier.cmake + FindOpenGLES.cmake + FindPAM.cmake + FindSensors.cmake + PkgConfigGetVar.cmake + UnixAuth.cmake ) + +set(module_install_dir ${DATA_INSTALL_DIR}/cmake/modules ) + +install( FILES ${cmakeFiles} DESTINATION ${module_install_dir} ) + diff --git a/cmake/modules/COPYING-CMAKE-SCRIPTS b/cmake/modules/COPYING-CMAKE-SCRIPTS new file mode 100644 index 00000000..4b417765 --- /dev/null +++ b/cmake/modules/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cmake/modules/FindCkConnector.cmake b/cmake/modules/FindCkConnector.cmake new file mode 100644 index 00000000..5130ca0a --- /dev/null +++ b/cmake/modules/FindCkConnector.cmake @@ -0,0 +1,59 @@ +# - Try to find the ConsoleKit connector library (libck-connector) +# Once done this will define +# +# CKCONNECTOR_FOUND - system has the CK Connector +# CKCONNECTOR_INCLUDE_DIR - the CK Connector include directory +# CKCONNECTOR_LIBRARIES - the libraries needed to use CK Connector + +# Copyright (c) 2008, Kevin Kofler, +# modeled after FindLibArt.cmake: +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) + + # in cache already + SET(CKCONNECTOR_FOUND TRUE) + +else (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) + + IF (NOT WIN32) + FIND_PACKAGE(PkgConfig) + IF (PKG_CONFIG_FOUND) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + pkg_check_modules(_CKCONNECTOR_PC QUIET ck-connector) + ENDIF (PKG_CONFIG_FOUND) + ENDIF (NOT WIN32) + + FIND_PATH(CKCONNECTOR_INCLUDE_DIR ck-connector.h + ${_CKCONNECTOR_PC_INCLUDE_DIRS} + ) + + FIND_LIBRARY(CKCONNECTOR_LIBRARIES NAMES ck-connector + PATHS + ${_CKCONNECTOR_PC_LIBDIR} + ) + + + if (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) + set(CKCONNECTOR_FOUND TRUE) + endif (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) + + + if (CKCONNECTOR_FOUND) + if (NOT CkConnector_FIND_QUIETLY) + message(STATUS "Found ck-connector: ${CKCONNECTOR_LIBRARIES}") + endif (NOT CkConnector_FIND_QUIETLY) + else (CKCONNECTOR_FOUND) + if (CkConnector_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find ck-connector") + endif (CkConnector_FIND_REQUIRED) + endif (CKCONNECTOR_FOUND) + + MARK_AS_ADVANCED(CKCONNECTOR_INCLUDE_DIR CKCONNECTOR_LIBRARIES) + +endif (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) diff --git a/cmake/modules/FindDBus.cmake b/cmake/modules/FindDBus.cmake new file mode 100644 index 00000000..f227cc29 --- /dev/null +++ b/cmake/modules/FindDBus.cmake @@ -0,0 +1,72 @@ +# - Try to find the low-level D-Bus library +# Once done this will define +# +# DBUS_FOUND - system has D-Bus +# DBUS_INCLUDE_DIR - the D-Bus include directory +# DBUS_ARCH_INCLUDE_DIR - the D-Bus architecture-specific include directory +# DBUS_LIBRARIES - the libraries needed to use D-Bus + +# Copyright (c) 2008, Kevin Kofler, +# modeled after FindLibArt.cmake: +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + # in cache already + SET(DBUS_FOUND TRUE) + +else (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + IF (NOT WIN32) + FIND_PACKAGE(PkgConfig) + IF (PKG_CONFIG_FOUND) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + pkg_check_modules(_DBUS_PC QUIET dbus-1) + ENDIF (PKG_CONFIG_FOUND) + ENDIF (NOT WIN32) + + FIND_PATH(DBUS_INCLUDE_DIR dbus/dbus.h + ${_DBUS_PC_INCLUDE_DIRS} + /usr/include + /usr/include/dbus-1.0 + /usr/local/include + ) + + FIND_PATH(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h + ${_DBUS_PC_INCLUDE_DIRS} + /usr/lib${LIB_SUFFIX}/include + /usr/lib${LIB_SUFFIX}/dbus-1.0/include + /usr/lib64/include + /usr/lib64/dbus-1.0/include + /usr/lib/include + /usr/lib/dbus-1.0/include + ) + + FIND_LIBRARY(DBUS_LIBRARIES NAMES dbus-1 dbus + PATHS + ${_DBUS_PC_LIBDIR} + ) + + + if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + set(DBUS_FOUND TRUE) + endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + + if (DBUS_FOUND) + if (NOT DBus_FIND_QUIETLY) + message(STATUS "Found D-Bus: ${DBUS_LIBRARIES}") + endif (NOT DBus_FIND_QUIETLY) + else (DBUS_FOUND) + if (DBus_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find D-Bus") + endif (DBus_FIND_REQUIRED) + endif (DBUS_FOUND) + + MARK_AS_ADVANCED(DBUS_INCLUDE_DIR DBUS_ARCH_INCLUDE_DIR DBUS_LIBRARIES) + +endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) diff --git a/cmake/modules/FindLibXKlavier.cmake b/cmake/modules/FindLibXKlavier.cmake new file mode 100644 index 00000000..7afd77a3 --- /dev/null +++ b/cmake/modules/FindLibXKlavier.cmake @@ -0,0 +1,29 @@ +# - Try to find LibXKlavier +# Once done this will define +# +# LIBXKLAVIER_FOUND - system has LibXKlavier +# LIBXKLAVIER_LDFLAGS - the libraries needed to use LibXKlavier +# LIBXKLAVIER_CFLAGS - Compiler switches required for using LibXKlavier +# LIBXKLAVIER_VERSION - Version of LibXKlavier + +if (LIBXKLAVIER_CFLAGS AND LIBXKLAVIER_LDFLAGS) + + # in cache already + SET(LIBXKLAVIER_FOUND TRUE) + +else (LIBXKLAVIER_CFLAGS AND LIBXKLAVIER_LDFLAGS) + + IF (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + INCLUDE(UsePkgConfig) + + pkg_check_modules(LIBXKLAVIER libxklavier>=3.0) + ENDIF (NOT WIN32) + + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXKlavier DEFAULT_MSG LIBXKLAVIER_CFLAGS LIBXKLAVIER_LDFLAGS) + + MARK_AS_ADVANCED(LIBXKLAVIER_CFLAGS LIBXKLAVIER_LDFLAGS LIBXKLAVIER_VERSION) + +endif (LIBXKLAVIER_CFLAGS AND LIBXKLAVIER_LDFLAGS) diff --git a/cmake/modules/FindOpenGLES.cmake b/cmake/modules/FindOpenGLES.cmake new file mode 100644 index 00000000..60b07e29 --- /dev/null +++ b/cmake/modules/FindOpenGLES.cmake @@ -0,0 +1,52 @@ +# - Try to find OpenGLES +# Once done this will define +# +# OPENGLES_FOUND - system has OpenGLES and EGL +# OPENGL_EGL_FOUND - system has EGL +# OPENGLES_INCLUDE_DIR - the GLES include directory +# OPENGLES_LIBRARY - the GLES library +# OPENGLES_EGL_INCLUDE_DIR - the EGL include directory +# OPENGLES_EGL_LIBRARY - the EGL library +# OPENGLES_LIBRARIES - all libraries needed for OpenGLES +# OPENGLES_INCLUDES - all includes needed for OpenGLES + +FIND_PATH(OPENGLES_INCLUDE_DIR GLES2/gl2.h + /usr/openwin/share/include + /opt/graphics/OpenGL/include /usr/X11R6/include + /usr/include +) + +FIND_LIBRARY(OPENGLES_LIBRARY + NAMES GLESv2 + PATHS /opt/graphics/OpenGL/lib + /usr/openwin/lib + /usr/shlib /usr/X11R6/lib + /usr/lib +) + +FIND_PATH(OPENGLES_EGL_INCLUDE_DIR EGL/egl.h + /usr/openwin/share/include + /opt/graphics/OpenGL/include /usr/X11R6/include + /usr/include +) + +FIND_LIBRARY(OPENGLES_EGL_LIBRARY + NAMES EGL + PATHS /usr/shlib /usr/X11R6/lib + /usr/lib +) + +SET(OPENGL_EGL_FOUND "NO") +IF(OPENGLES_EGL_LIBRARY AND OPENGLES_EGL_INCLUDE_DIR) + SET(OPENGL_EGL_FOUND "YES") +ENDIF() + +SET(OPENGLES_FOUND "NO") +IF(OPENGLES_LIBRARY AND OPENGLES_INCLUDE_DIR AND + OPENGLES_EGL_LIBRARY AND OPENGLES_EGL_INCLUDE_DIR) + SET(OPENGLES_LIBRARIES ${OPENGLES_LIBRARY} ${OPENGLES_LIBRARIES} + ${OPENGLES_EGL_LIBRARY}) + SET(OPENGLES_INCLUDES ${OPENGLES_INCLUDE_DIR} ${OPENGLES_EGL_INCLUDE_DIR}) + SET(OPENGLES_FOUND "YES") +ENDIF() + diff --git a/cmake/modules/FindPAM.cmake b/cmake/modules/FindPAM.cmake new file mode 100644 index 00000000..34998365 --- /dev/null +++ b/cmake/modules/FindPAM.cmake @@ -0,0 +1,74 @@ +# - Try to find the PAM libraries +# Once done this will define +# +# PAM_FOUND - system has pam +# PAM_INCLUDE_DIR - the pam include directory +# PAM_LIBRARIES - libpam library + +if (PAM_INCLUDE_DIR AND PAM_LIBRARY) + # Already in cache, be silent + set(PAM_FIND_QUIETLY TRUE) +endif (PAM_INCLUDE_DIR AND PAM_LIBRARY) + +find_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h pam/pam_appl.h) +find_library(PAM_LIBRARY pam) +find_library(DL_LIBRARY dl) + +if (PAM_INCLUDE_DIR AND PAM_LIBRARY) + set(PAM_FOUND TRUE) + if (DL_LIBRARY) + set(PAM_LIBRARIES ${PAM_LIBRARY} ${DL_LIBRARY}) + else (DL_LIBRARY) + set(PAM_LIBRARIES ${PAM_LIBRARY}) + endif (DL_LIBRARY) + + if (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h) + # darwin claims to be something special + set(HAVE_PAM_PAM_APPL_H 1) + endif (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h) + + if (NOT DEFINED PAM_MESSAGE_CONST) + include(CheckCXXSourceCompiles) + # XXX does this work with plain c? + check_cxx_source_compiles(" +#if ${HAVE_PAM_PAM_APPL_H}+0 +# include +#else +# include +#endif + +static int PAM_conv( + int num_msg, + const struct pam_message **msg, /* this is the culprit */ + struct pam_response **resp, + void *ctx) +{ + return 0; +} + +int main(void) +{ + struct pam_conv PAM_conversation = { + &PAM_conv, /* this bombs out if the above does not match */ + 0 + }; + + return 0; +} +" PAM_MESSAGE_CONST) + endif (NOT DEFINED PAM_MESSAGE_CONST) + set(PAM_MESSAGE_CONST ${PAM_MESSAGE_CONST} CACHE BOOL "PAM expects a conversation function with const pam_message") + +endif (PAM_INCLUDE_DIR AND PAM_LIBRARY) + +if (PAM_FOUND) + if (NOT PAM_FIND_QUIETLY) + message(STATUS "Found PAM: ${PAM_LIBRARIES}") + endif (NOT PAM_FIND_QUIETLY) +else (PAM_FOUND) + if (PAM_FIND_REQUIRED) + message(FATAL_ERROR "PAM was not found") + endif(PAM_FIND_REQUIRED) +endif (PAM_FOUND) + +mark_as_advanced(PAM_INCLUDE_DIR PAM_LIBRARY DL_LIBRARY PAM_MESSAGE_CONST) diff --git a/cmake/modules/FindPCIUTILS.cmake b/cmake/modules/FindPCIUTILS.cmake new file mode 100644 index 00000000..0dd99660 --- /dev/null +++ b/cmake/modules/FindPCIUTILS.cmake @@ -0,0 +1,29 @@ +# - Try to find the pciutils directory library +# Once done this will define +# +# PCIUTILS_FOUND - system has PCIUtils +# PCIUTILS_INCLUDE_DIR - the PCIUTILS include directory +# PCIUTILS_LIBRARIES - The libraries needed to use PCIUtils + +if(PCIUTILS_INCLUDE_DIR AND PCIUTILS_LIBRARIES) + set(PCIUTILS_FIND_QUIETLY TRUE) +endif(PCIUTILS_INCLUDE_DIR AND PCIUTILS_LIBRARIES) + +FIND_PATH(PCIUTILS_INCLUDE_DIR pci/pci.h) + +FIND_LIBRARY(PCIUTILS_LIBRARY NAMES pci) +if(PCIUTILS_LIBRARY) + FIND_LIBRARY(RESOLV_LIBRARY NAMES resolv) + if(RESOLV_LIBRARY) + set(PCIUTILS_LIBRARIES ${PCIUTILS_LIBRARY} ${RESOLV_LIBRARY}) + else(RESOLV_LIBRARY) + set(PCIUTILS_LIBRARIES ${PCIUTILS_LIBRARY}) + endif(RESOLV_LIBRARY) +endif(PCIUTILS_LIBRARY) + + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCIUTILS DEFAULT_MSG PCIUTILS_LIBRARIES PCIUTILS_INCLUDE_DIR) + +MARK_AS_ADVANCED(PCIUTILS_INCLUDE_DIR PCIUTILS_LIBRARIES) + diff --git a/cmake/modules/FindQJSON.cmake b/cmake/modules/FindQJSON.cmake new file mode 100644 index 00000000..fad59050 --- /dev/null +++ b/cmake/modules/FindQJSON.cmake @@ -0,0 +1,36 @@ +# Find QJSON - JSON handling library for Qt +# +# This module defines +# QJSON_FOUND - whether the qsjon library was found +# QJSON_LIBRARIES - the qjson library +# QJSON_INCLUDE_DIR - the include path of the qjson library +# +# Copyright (C) 2012 Raphael Kubo da Costa +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# QJSON v0.7.2+ provides a QJSONConfig.cmake, which should be used if found. +find_package(QJSON QUIET NO_MODULE) + +if (QJSON_FOUND) + set(REQUIRED_LIBS QJSON_CONFIG) +else (QJSON_FOUND) + find_package(PkgConfig) + pkg_check_modules(PC_QJSON QJson>=0.5) + + find_library(QJSON_LIBRARIES + NAMES qjson + HINTS ${PC_QJSON_LIBDIR} ${PC_QJSON_LIBRARY_DIRS} + ) + + find_path(QJSON_INCLUDE_DIR + NAMES qjson/parser.h + HINTS ${PC_QJSON_INCLUDEDIR} ${PC_QJSON_INCLUDE_DIRS} + ) + + set(REQUIRED_LIBS QJSON_LIBRARIES QJSON_INCLUDE_DIR) +endif (QJSON_FOUND) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(QJSON DEFAULT_MSG ${REQUIRED_LIBS}) diff --git a/cmake/modules/FindQalculate.cmake b/cmake/modules/FindQalculate.cmake new file mode 100644 index 00000000..707a9f7c --- /dev/null +++ b/cmake/modules/FindQalculate.cmake @@ -0,0 +1,52 @@ +# - Try to find libqalculate +# Input variables +# +# QALCULATE_MIN_VERSION - minimal version of libqalculate +# QALCULATE_FIND_REQUIRED - fail if can't find libqalculate +# +# Once done this will define +# +# QALCULATE_FOUND - system has libqalculate +# QALCULATE_CFLAGS - libqalculate cflags +# QALCULATE_LIBRARIES - libqalculate libraries +# +# Copyright (c) 2007, Vladimir Kuznetsov, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if(QALCULATE_CFLAGS AND QALCULATE_LIBRARIES) + + # in cache already + set(QALCULATE_FOUND TRUE) + +else(QALCULATE_CFLAGS AND QALCULATE_LIBRARIES) + if(NOT WIN32) + include(UsePkgConfig) + + if(QALCULATE_MIN_VERSION) + exec_program(${PKGCONFIG_EXECUTABLE} ARGS libqalculate --atleast-version=${QALCULATE_MIN_VERSION} RETURN_VALUE _return_VALUE OUTPUT_VARIABLE _pkgconfigDevNull) + else(QALCULATE_MIN_VERSION) + exec_program(${PKGCONFIG_EXECUTABLE} ARGS libqalculate --exists RETURN_VALUE _return_VALUE OUTPUT_VARIABLE _pkgconfigDevNull) + endif(QALCULATE_MIN_VERSION) + + if(_return_VALUE STREQUAL "0") + exec_program(${PKGCONFIG_EXECUTABLE} ARGS libqalculate --libs OUTPUT_VARIABLE QALCULATE_LIBRARIES) + exec_program(${PKGCONFIG_EXECUTABLE} ARGS cln --libs OUTPUT_VARIABLE CLN_LIBRARIES) + exec_program(${PKGCONFIG_EXECUTABLE} ARGS libqalculate --cflags OUTPUT_VARIABLE QALCULATE_CFLAGS) + set(QALCULATE_FOUND TRUE) + endif(_return_VALUE STREQUAL "0") + + else(NOT WIN32) + # XXX: currently no libqalculate on windows + set(QALCULATE_FOUND FALSE) + + endif(NOT WIN32) + + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Qalculate DEFAULT_MSG QALCULATE_LIBRARIES ) + + mark_as_advanced(QALCULATE_CFLAGS QALCULATE_LIBRARIES) + +endif(QALCULATE_CFLAGS AND QALCULATE_LIBRARIES) + diff --git a/cmake/modules/FindRAW1394.cmake b/cmake/modules/FindRAW1394.cmake new file mode 100644 index 00000000..c6ce3568 --- /dev/null +++ b/cmake/modules/FindRAW1394.cmake @@ -0,0 +1,20 @@ +# - Try to find the raw1394 directory library +# Once done this will define +# +# RAW1394_FOUND - system has RAW1394 +# RAW1394_INCLUDE_DIR - the RAW1394 include directory +# RAW1394_LIBRARIES - The libraries needed to use FAM + +if(RAW1394_INCLUDE_DIR AND RAW1394_LIBRARIES) + set(RAW1394_FIND_QUIETLY TRUE) +endif(RAW1394_INCLUDE_DIR AND RAW1394_LIBRARIES) + +FIND_PATH(RAW1394_INCLUDE_DIR libraw1394/raw1394.h) + +FIND_LIBRARY(RAW1394_LIBRARIES NAMES raw1394 ) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(RAW1394 DEFAULT_MSG RAW1394_LIBRARIES RAW1394_INCLUDE_DIR) + +MARK_AS_ADVANCED(RAW1394_INCLUDE_DIR RAW1394_LIBRARIES) + diff --git a/cmake/modules/FindSensors.cmake b/cmake/modules/FindSensors.cmake new file mode 100644 index 00000000..6da908d8 --- /dev/null +++ b/cmake/modules/FindSensors.cmake @@ -0,0 +1,16 @@ +# - Try to find the sensors directory library +# Once done this will define +# +# SENSORS_FOUND - system has SENSORS +# SENSORS_INCLUDE_DIR - the SENSORS include directory +# SENSORS_LIBRARIES - The libraries needed to use SENSORS + +FIND_PATH(SENSORS_INCLUDE_DIR sensors/sensors.h) + +FIND_LIBRARY(SENSORS_LIBRARIES NAMES sensors) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Sensors DEFAULT_MSG SENSORS_INCLUDE_DIR SENSORS_LIBRARIES ) + +MARK_AS_ADVANCED(SENSORS_INCLUDE_DIR SENSORS_LIBRARIES) + diff --git a/cmake/modules/FindUDev.cmake b/cmake/modules/FindUDev.cmake new file mode 100644 index 00000000..4c8390db --- /dev/null +++ b/cmake/modules/FindUDev.cmake @@ -0,0 +1,19 @@ +# - Try to find UDev +# Once done this will define +# +# UDEV_FOUND - system has UDev +# UDEV_INCLUDE_DIR - the libudev include directory +# UDEV_LIBS - The libudev libraries + +# Copyright (c) 2010, Rafael Fernández López, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +find_path(UDEV_INCLUDE_DIR libudev.h) +find_library(UDEV_LIBS udev) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(UDev DEFAULT_MSG UDEV_INCLUDE_DIR UDEV_LIBS) + +mark_as_advanced(UDEV_INCLUDE_DIR UDEV_LIBS) diff --git a/cmake/modules/FindWayland.cmake b/cmake/modules/FindWayland.cmake new file mode 100644 index 00000000..00c17a3c --- /dev/null +++ b/cmake/modules/FindWayland.cmake @@ -0,0 +1,62 @@ +# Try to find Wayland on a Unix system +# +# This will define: +# +# WAYLAND_FOUND - True if Wayland is found +# WAYLAND_LIBRARIES - Link these to use Wayland +# WAYLAND_INCLUDE_DIR - Include directory for Wayland +# WAYLAND_DEFINITIONS - Compiler flags for using Wayland +# +# In addition the following more fine grained variables will be defined: +# +# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES +# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES +# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES +# +# Copyright (c) 2013 Martin Gräßlin +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +IF (NOT WIN32) + IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES) + # In the cache already + SET(WAYLAND_FIND_QUIETLY TRUE) + ENDIF () + + # Use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + FIND_PACKAGE(PkgConfig) + PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl) + + SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS}) + + FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + + FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + + set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR}) + + set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES}) + + list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR) + + MARK_AS_ADVANCED( + WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES + WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES + WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES + WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES + ) + +ENDIF () diff --git a/cmake/modules/FindX11_XCB.cmake b/cmake/modules/FindX11_XCB.cmake new file mode 100644 index 00000000..6b9b8b4c --- /dev/null +++ b/cmake/modules/FindX11_XCB.cmake @@ -0,0 +1,31 @@ +# - Try to find libX11-xcb +# Once done this will define +# +# X11_XCB_FOUND - system has libX11-xcb +# X11_XCB_LIBRARIES - Link these to use libX11-xcb +# X11_XCB_INCLUDE_DIR - the libX11-xcb include dir +# X11_XCB_DEFINITIONS - compiler switches required for using libX11-xcb + +# Copyright (c) 2012 Fredrik Höglund +# Copyright (c) 2008 Helio Chissini de Castro, +# Copyright (c) 2007 Matthias Kretz, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +IF (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + FIND_PACKAGE(PkgConfig) + PKG_CHECK_MODULES(PKG_X11_XCB QUIET x11-xcb) + + SET(X11_XCB_DEFINITIONS ${PKG_X11_XCB_CFLAGS}) + + FIND_PATH(X11_XCB_INCLUDE_DIR NAMES X11/Xlib-xcb.h HINTS ${PKG_X11_XCB_INCLUDE_DIRS}) + FIND_LIBRARY(X11_XCB_LIBRARIES NAMES X11-xcb HINTS ${PKG_X11_XCB_LIBRARY_DIRS}) + + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(X11_XCB DEFAULT_MSG X11_XCB_LIBRARIES X11_XCB_INCLUDE_DIR) + + MARK_AS_ADVANCED(X11_XCB_INCLUDE_DIR X11_XCB_LIBRARIES) +ENDIF (NOT WIN32) diff --git a/cmake/modules/FindXCB.cmake b/cmake/modules/FindXCB.cmake new file mode 100644 index 00000000..a065468f --- /dev/null +++ b/cmake/modules/FindXCB.cmake @@ -0,0 +1,123 @@ +# Try to find XCB on a Unix system +# +# This will define: +# +# XCB_FOUND - True if xcb is available +# XCB_LIBRARIES - Link these to use xcb +# XCB_INCLUDE_DIR - Include directory for xcb +# XCB_DEFINITIONS - Compiler flags for using xcb +# +# In addition the following more fine grained variables will be defined: +# +# XCB_XCB_FOUND XCB_XCB_INCLUDE_DIR XCB_XCB_LIBRARIES +# XCB_COMPOSITE_FOUND XCB_COMPOSITE_INCLUDE_DIR XCB_COMPOSITE_LIBRARIES +# XCB_DAMAGE_FOUND XCB_DAMAGE_INCLUDE_DIR XCB_DAMAGE_LIBRARIES +# XCB_XFIXES_FOUND XCB_XFIXES_INCLUDE_DIR XCB_XFIXES_LIBRARIES +# XCB_RENDER_FOUND XCB_RENDER_INCLUDE_DIR XCB_RENDER_LIBRARIES +# XCB_RANDR_FOUND XCB_RANDR_INCLUDE_DIR XCB_RANDR_LIBRARIES +# XCB_SHAPE_FOUND XCB_SHAPE_INCLUDE_DIR XCB_SHAPE_LIBRARIES +# XCB_SHM_FOUND XCB_SHM_INCLUDE_DIR XCB_SHM_LIBRARIES +# XCB_SYNC_FOUND XCB_SYNC_INCLUDE_DIR XCB_SYNC_LIBRARIES +# XCB_IMAGE_FOUND XCB_IMAGE_INCLUDE_DIR XCB_IMAGE_LIBRARIES +# XCB_RENDERUTIL_FOUND XCB_RENDERUTIL_INCLUDE_DIR XCB_RENDERUTIL_LIBRARIES +# XCB_KEYSYMS_FOUND XCB_KEYSYMS_INCLUDE_DIR XCB_KEYSYMS_LIBRARIES +# XCB_XTEST_FOUND XCB_XTEST_INCLUDE_DIR XCB_XTEST_LIBRARIES +# +# Copyright (c) 2012 Fredrik Höglund +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +IF (NOT WIN32) + IF (XCB_INCLUDE_DIR AND XCB_LIBRARIES) + # In the cache already + SET(XCB_FIND_QUIETLY TRUE) + ENDIF (XCB_INCLUDE_DIR AND XCB_LIBRARIES) + + # Use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + FIND_PACKAGE(PkgConfig) + PKG_CHECK_MODULES(PKG_XCB QUIET xcb xcb-util xcb-composite xcb-xfixes xcb-damage xcb-render xcb-randr + xcb-shape xcb-dri2 xcb-glx xcb-shm xcb-xv xcb-sync + xcb-xtest xcb-icccm xcb-ewmh xcb-image xcb-renderutil xcb-keysyms) + + SET(XCB_DEFINITIONS ${PKG_XCB_CFLAGS}) + + FIND_PATH(XCB_XCB_INCLUDE_DIR NAMES xcb/xcb.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_COMPOSITE_INCLUDE_DIR NAMES xcb/composite.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_XFIXES_INCLUDE_DIR NAMES xcb/xfixes.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_DAMAGE_INCLUDE_DIR NAMES xcb/damage.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_RENDER_INCLUDE_DIR NAMES xcb/render.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_RANDR_INCLUDE_DIR NAMES xcb/randr.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_SHAPE_INCLUDE_DIR NAMES xcb/shape.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_SHM_INCLUDE_DIR NAMES xcb/shm.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_SYNC_INCLUDE_DIR NAMES xcb/sync.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_IMAGE_INCLUDE_DIR NAMES xcb/xcb_image.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_RENDERUTIL_INCLUDE_DIR NAMES xcb/xcb_renderutil.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_KEYSYMS_INCLUDE_DIR NAMES xcb/xcb_keysyms.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + FIND_PATH(XCB_XTEST_INCLUDE_DIR NAMES xcb/xtest.h HINTS ${PKG_XCB_INCLUDE_DIRS}) + + FIND_LIBRARY(XCB_XCB_LIBRARIES NAMES xcb HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_COMPOSITE_LIBRARIES NAMES xcb-composite HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_DAMAGE_LIBRARIES NAMES xcb-damage HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_XFIXES_LIBRARIES NAMES xcb-xfixes HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_RENDER_LIBRARIES NAMES xcb-render HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_RANDR_LIBRARIES NAMES xcb-randr HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_SHAPE_LIBRARIES NAMES xcb-shape HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_SHM_LIBRARIES NAMES xcb-shm HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_SYNC_LIBRARIES NAMES xcb-sync HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_IMAGE_LIBRARIES NAMES xcb-image HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_RENDERUTIL_LIBRARIES NAMES xcb-render-util HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_KEYSYMS_LIBRARIES NAMES xcb-keysyms HINTS ${PKG_XCB_LIBRARY_DIRS}) + FIND_LIBRARY(XCB_XTEST_LIBRARIES NAMES xcb-xtest HINTS ${PKG_XCB_LIBRARY_DIRS}) + + set(XCB_INCLUDE_DIR ${XCB_XCB_INCLUDE_DIR} ${XCB_COMPOSITE_INCLUDE_DIR} ${XCB_XFIXES_INCLUDE_DIR} + ${XCB_DAMAGE_INCLUDE_DIR} ${XCB_RENDER_INCLUDE_DIR} ${XCB_RANDR_INCLUDE_DIR} + ${XCB_SHAPE_INCLUDE_DIR} ${XCB_SHM_INCLUDE_DIR} ${XCB_SYNC_INCLUDE_DIR} + ${XCB_IMAGE_INCLUDE_DIR} ${XCB_RENDERUTIL_INCLUDE_DIR} ${XCB_KEYSYMS_INCLUDE_DIR} + ${XCB_XTEST_INCLUDE_DIR}) + + set(XCB_LIBRARIES ${XCB_XCB_LIBRARIES} ${XCB_COMPOSITE_LIBRARIES} ${XCB_XFIXES_LIBRARIES} + ${XCB_DAMAGE_LIBRARIES} ${XCB_RENDER_LIBRARIES} ${XCB_RANDR_LIBRARIES} + ${XCB_SHAPE_LIBRARIES} ${XCB_SHM_LIBRARIES} ${XCB_SYNC_LIBRARIES} + ${XCB_IMAGE_LIBRARIES} ${XCB_RENDERUTIL_LIBRARIES} ${XCB_KEYSYMS_LIBRARIES} + ${XCB_XTEST_LIBRARIES}) + + list(REMOVE_DUPLICATES XCB_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_XCB DEFAULT_MSG XCB_XCB_LIBRARIES XCB_XCB_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_COMPOSITE DEFAULT_MSG XCB_COMPOSITE_LIBRARIES XCB_COMPOSITE_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_DAMAGE DEFAULT_MSG XCB_DAMAGE_LIBRARIES XCB_DAMAGE_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_XFIXES DEFAULT_MSG XCB_XFIXES_LIBRARIES XCB_XFIXES_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_RENDER DEFAULT_MSG XCB_RENDER_LIBRARIES XCB_RENDER_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_RANDR DEFAULT_MSG XCB_RANDR_LIBRARIES XCB_RANDR_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_SHAPE DEFAULT_MSG XCB_SHAPE_LIBRARIES XCB_SHAPE_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_SHM DEFAULT_MSG XCB_SHM_LIBRARIES XCB_SHM_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_SYNC DEFAULT_MSG XCB_SYNC_LIBRARIES XCB_SYNC_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_IMAGE DEFAULT_MSG XCB_IMAGE_LIBRARIES XCB_IMAGE_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_RENDERUTIL DEFAULT_MSG XCB_RENDERUTIL_LIBRARIES XCB_RENDERUTIL_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_KEYSYMS DEFAULT_MSG XCB_KEYSYMS_LIBRARIES XCB_KEYSYMS_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB_XTEST DEFAULT_MSG XCB_XTEST_LIBRARIES XCB_XTEST_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB DEFAULT_MSG XCB_LIBRARIES XCB_INCLUDE_DIR) + + MARK_AS_ADVANCED( + XCB_INCLUDE_DIR XCB_LIBRARIES + XCB_XCB_INCLUDE_DIR XCB_XCB_LIBRARIES + XCB_COMPOSITE_INCLUDE_DIR XCB_COMPOSITE_LIBRARIES + XCB_DAMAGE_INCLUDE_DIR XCB_DAMAGE_LIBRARIES + XCB_XFIXES_INCLUDE_DIR XCB_XFIXES_LIBRARIES + XCB_RENDER_INCLUDE_DIR XCB_RENDER_LIBRARIES + XCB_RANDR_INCLUDE_DIR XCB_RANDR_LIBRARIES + XCB_SHAPE_INCLUDE_DIR XCB_SHAPE_LIBRARIES + XCB_SHM_INCLUDE_DIR XCB_SHM_LIBRARIES + XCB_SYNC_INCLUDE_DIR XCB_SYNC_LIBRARIES + XCB_IMAGE_INCLUDE_DIR XCB_IMAGE_LIBRARIES + XCB_RENDERUTIL_INCLUDE_DIR XCB_RENDERUTIL_LIBRARIES + XCB_KEYSYMS_INCLUDE_DIR XCB_KEYSYMS_LIBRARIES + XCB_XTEST_INCLUDE_DIR XCB_XTEST_LIBRARIES + ) + +ENDIF (NOT WIN32) diff --git a/cmake/modules/PkgConfigGetVar.cmake b/cmake/modules/PkgConfigGetVar.cmake new file mode 100644 index 00000000..7d03512e --- /dev/null +++ b/cmake/modules/PkgConfigGetVar.cmake @@ -0,0 +1,32 @@ +include(UsePkgConfig) + +MACRO(PKGCONFIG_GETVAR _package _var _output_variable) + SET(${_output_variable}) + + # if pkg-config has been found + IF(PKGCONFIG_EXECUTABLE) + + EXEC_PROGRAM(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --exists RETURN_VALUE _return_VALUE OUTPUT_VARIABLE _pkgconfigDevNull ) + + # and if the package of interest also exists for pkg-config, then get the information + IF(NOT _return_VALUE) + + EXEC_PROGRAM(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --variable ${_var} OUTPUT_VARIABLE ${_output_variable} ) + + ENDIF(NOT _return_VALUE) + + ENDIF(PKGCONFIG_EXECUTABLE) + +ENDMACRO(PKGCONFIG_GETVAR _package _var _output_variable) + +macro(dbus_add_activation_service _sources) + #PKGCONFIG_GETVAR(dbus-1 session_bus_services_dir _install_dir) + foreach (_i ${_sources}) + get_filename_component(_service_file ${_i} ABSOLUTE) + string(REGEX REPLACE "\\.service.*$" ".service" _output_file ${_i}) + set(_target ${CMAKE_CURRENT_BINARY_DIR}/${_output_file}) + configure_file(${_service_file} ${_target}) + install(FILES ${_target} DESTINATION ${DBUS_SERVICES_INSTALL_DIR} ) + #install(FILES ${_target} DESTINATION ${_install_dir}) + endforeach (_i ${ARGN}) +endmacro(dbus_add_activation_service _sources) diff --git a/cmake/modules/UnixAuth.cmake b/cmake/modules/UnixAuth.cmake new file mode 100644 index 00000000..0347251d --- /dev/null +++ b/cmake/modules/UnixAuth.cmake @@ -0,0 +1,55 @@ +macro_optional_find_package(PAM) + +include(CheckFunctionExists) +include(CheckLibraryExists) +include(CheckIncludeFiles) + +set(UNIXAUTH_LIBRARIES) +set(UNIXAUTH_INCLUDE_DIRS) + +set(SHADOW_LIBRARIES) +check_function_exists(getspnam found_getspnam) +if (found_getspnam) + set(HAVE_GETSPNAM 1) +else (found_getspnam) + macro_push_required_vars() + set(CMAKE_REQUIRED_LIBRARIES -lshadow) + check_function_exists(getspnam found_getspnam_shadow) + if (found_getspnam_shadow) + set(HAVE_GETSPNAM 1) + set(SHADOW_LIBRARIES shadow) + check_function_exists(pw_encrypt HAVE_PW_ENCRYPT) # ancient Linux shadow + else (found_getspnam_shadow) + set(CMAKE_REQUIRED_LIBRARIES -lgen) # UnixWare + check_function_exists(getspnam found_getspnam_gen) + if (found_getspnam_gen) + set(HAVE_GETSPNAM 1) + set(SHADOW_LIBRARIES gen) + endif (found_getspnam_gen) + endif (found_getspnam_shadow) + macro_pop_required_vars() +endif (found_getspnam) + +set(CRYPT_LIBRARIES) +check_library_exists(crypt crypt "" HAVE_CRYPT) +if (HAVE_CRYPT) + set(CRYPT_LIBRARIES crypt) + check_include_files(crypt.h HAVE_CRYPT_H) +endif (HAVE_CRYPT) + +if (PAM_FOUND) + + set(HAVE_PAM 1) + set(UNIXAUTH_LIBRARIES ${PAM_LIBRARIES}) + set(UNIXAUTH_INCLUDE_DIRS ${PAM_INCLUDE_DIR}) + +else (PAM_FOUND) + + if (HAVE_GETSPNAM) + set(UNIXAUTH_LIBRARIES ${SHADOW_LIBRARIES}) + endif (HAVE_GETSPNAM) + if (NOT HAVE_PW_ENCRYPT) + set(UNIXAUTH_LIBRARIES ${UNIXAUTH_LIBRARIES} ${CRYPT_LIBRARIES}) + endif (NOT HAVE_PW_ENCRYPT) + +endif (PAM_FOUND) diff --git a/config-X11.h.cmake b/config-X11.h.cmake new file mode 100644 index 00000000..b7975d5e --- /dev/null +++ b/config-X11.h.cmake @@ -0,0 +1,41 @@ +/* Define if you have the XRandR extension */ +#cmakedefine HAVE_XRANDR 1 + +/* Define if you have the XDamage extension */ +#cmakedefine HAVE_XDAMAGE 1 + +/* Define if you have the XKB extension */ +#cmakedefine HAVE_XKB 1 + +/* Define if you have the Xinerama extension */ +#cmakedefine HAVE_XINERAMA 1 + +/* Define if you have the XSHM (MIT SHM) extension */ +#cmakedefine HAVE_XSHM 1 + +/* Define if you have the XComposite extension */ +#cmakedefine HAVE_XCOMPOSITE 1 + +/* Define to 1 if you have Xcursor */ +#cmakedefine HAVE_XCURSOR 1 + +/* Define if you have the xf86misc extension */ +#cmakedefine HAVE_XF86MISC 1 + +/* Define if you have the XFixes extension */ +#cmakedefine HAVE_XFIXES 1 + +/* Define if you have the XTest extension */ +#cmakedefine HAVE_XTEST 1 + +/* Define if your system has XRender support */ +#cmakedefine HAVE_XRENDER 1 + +/* Define if you have OpenGL */ +#cmakedefine HAVE_OPENGL 1 + +/* Define if you have the XSync extension */ +#cmakedefine HAVE_XSYNC 1 + +/* Define if you have XRandR 1.3 */ +#cmakedefine HAS_RANDR_1_3 1 diff --git a/config-unix.h.cmake b/config-unix.h.cmake new file mode 100644 index 00000000..ddb49b68 --- /dev/null +++ b/config-unix.h.cmake @@ -0,0 +1,35 @@ +/* Defines if you have PAM (Pluggable Authentication Modules) */ +#cmakedefine HAVE_PAM 1 + +/* Define if your PAM headers are in pam/ instead of security/ */ +#cmakedefine HAVE_PAM_PAM_APPL_H 1 + +/* Define if your PAM expects a conversation function with const pam_message (Solaris) */ +#cmakedefine PAM_MESSAGE_CONST 1 + +/* The PAM service to be used by kdm */ +#cmakedefine KDM_PAM_SERVICE ${KDM_PAM_SERVICE} + +/* The PAM service to be used by kscreensaver */ +#cmakedefine KSCREENSAVER_PAM_SERVICE ${KSCREENSAVER_PAM_SERVICE} + +/* Defines if your system has the getspnam function */ +#cmakedefine HAVE_GETSPNAM 1 + +/* Defines if your system has the crypt function */ +#cmakedefine HAVE_CRYPT 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_CRYPT_H 1 + +/* Define to 1 if you have the `pw_encrypt' function. */ +#cmakedefine HAVE_PW_ENCRYPT 1 + +/* Define to 1 if you have the `getpassphrase' function. */ +#cmakedefine HAVE_GETPASSPHRASE 1 + +/* Define to 1 if you have the `vsyslog' function. */ +#cmakedefine HAVE_VSYSLOG 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIMITS_H 1 diff --git a/config-workspace.h.cmake b/config-workspace.h.cmake new file mode 100644 index 00000000..90959bf3 --- /dev/null +++ b/config-workspace.h.cmake @@ -0,0 +1,159 @@ +/* config-workspace.h. Generated by cmake from config-workspace.h.cmake */ + +#cmakedefine HAVE_QIMAGEBLITZ + +/* Define if you have DPMS support */ +#cmakedefine HAVE_DPMS 1 + +/* Define if you have the DPMSCapable prototype in */ +#cmakedefine HAVE_DPMSCAPABLE_PROTO 1 + +/* Define if you have the DPMSInfo prototype in */ +#cmakedefine HAVE_DPMSINFO_PROTO 1 + +/* Defines if your system has the libfontconfig library */ +#cmakedefine HAVE_FONTCONFIG 1 + +/* Defines if your system has the freetype library */ +#cmakedefine HAVE_FREETYPE 1 + +/* Define if you have gethostname */ +#cmakedefine HAVE_GETHOSTNAME 1 + +/* Define if you have the gethostname prototype */ +#cmakedefine HAVE_GETHOSTNAME_PROTO 1 + +/* Define to 1 if you have the `getpeereid' function. */ +#cmakedefine HAVE_GETPEEREID 1 + +/* Defines if you have Solaris' libkstat */ +/* #undef HAVE_KSTAT */ + +/* Define if you have long long as datatype */ +#cmakedefine HAVE_LONG_LONG 1 + +/* Define to 1 if you have the `nice' function. */ +#cmakedefine HAVE_NICE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SASL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SASL_SASL_H 1 + +/* Define to 1 if you have the `setpriority' function. */ +#cmakedefine HAVE_SETPRIORITY 1 + +/* Define to 1 if you have the `sigaction' function. */ +#cmakedefine HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigset' function. */ +#cmakedefine HAVE_SIGSET 1 + +/* Define to 1 if you have statvfs */ +#cmakedefine HAVE_STATVFS 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H 1 + +/* Define if you have the struct ucred */ +#cmakedefine HAVE_STRUCT_UCRED 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_LOADAVG_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STATFS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have statfs(). */ +#cmakedefine HAVE_STATFS 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_VFS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MALLOC_H 1 + +/* Define if you have unsetenv */ +#cmakedefine HAVE_UNSETENV 1 + +/* Define if you have the unsetenv prototype */ +#cmakedefine HAVE_UNSETENV_PROTO 1 + +/* Define if you have usleep */ +#cmakedefine HAVE_USLEEP 1 + +/* Define if you have the usleep prototype */ +#cmakedefine HAVE_USLEEP_PROTO 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#cmakedefine HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the Wayland libraries. */ +#cmakedefine WAYLAND_FOUND 1 + +/* KDE's default home directory */ +#cmakedefine KDE_DEFAULT_HOME "${KDE_DEFAULT_HOME}" + +/* KDE's binaries directory */ +#define KDE_BINDIR "${BIN_INSTALL_DIR}" + +/* KDE's configuration directory */ +#define KDE_CONFDIR "${CONFIG_INSTALL_DIR}" + +/* KDE's static data directory */ +#define KDE_DATADIR "${DATA_INSTALL_DIR}" + +/* Define where your java executable is */ +#undef PATH_JAVA + +/* Define to 1 if you can safely include both and . */ +#cmakedefine TIME_WITH_SYS_TIME 1 + +/* X binaries directory */ +#cmakedefine XBINDIR "${XBINDIR}" + +/* X libraries directory */ +#cmakedefine XLIBDIR "${XLIBDIR}" + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +/* type to use in place of socklen_t if not defined */ +#define kde_socklen_t socklen_t + +#define WORKSPACE_VERSION_STRING "${KDE4WORKSPACE_VERSION}" diff --git a/cursors/CMakeLists.txt b/cursors/CMakeLists.txt new file mode 100644 index 00000000..4b0da9dd --- /dev/null +++ b/cursors/CMakeLists.txt @@ -0,0 +1,13 @@ +set(cursors_folders + Oxygen_Black + Oxygen_Blue + Oxygen_White + Oxygen_Yellow + Oxygen_Zion + KDE_Classic + ) + +foreach(theme ${cursors_folders}) + install(DIRECTORY ${theme} DESTINATION ${ICON_INSTALL_DIR}) +endforeach(theme) + diff --git a/cursors/KDE_Classic/cursors/00000000000000020006000e7e9ffc3f b/cursors/KDE_Classic/cursors/00000000000000020006000e7e9ffc3f new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/KDE_Classic/cursors/00000000000000020006000e7e9ffc3f @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/00008160000006810000408080010102 b/cursors/KDE_Classic/cursors/00008160000006810000408080010102 new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/KDE_Classic/cursors/00008160000006810000408080010102 @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/08e8e1c95fe2fc01f976f1e063a24ccd b/cursors/KDE_Classic/cursors/08e8e1c95fe2fc01f976f1e063a24ccd new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/KDE_Classic/cursors/08e8e1c95fe2fc01f976f1e063a24ccd @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/3ecb610c1bf2410f44200f48c40d3599 b/cursors/KDE_Classic/cursors/3ecb610c1bf2410f44200f48c40d3599 new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/KDE_Classic/cursors/3ecb610c1bf2410f44200f48c40d3599 @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/4498f0e0c1937ffe01fd06f973665830 b/cursors/KDE_Classic/cursors/4498f0e0c1937ffe01fd06f973665830 new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/KDE_Classic/cursors/4498f0e0c1937ffe01fd06f973665830 @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 b/cursors/KDE_Classic/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/KDE_Classic/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/9081237383d90e509aa00f00170e968f b/cursors/KDE_Classic/cursors/9081237383d90e509aa00f00170e968f new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/KDE_Classic/cursors/9081237383d90e509aa00f00170e968f @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/9d800788f1b08800ae810202380a0822 b/cursors/KDE_Classic/cursors/9d800788f1b08800ae810202380a0822 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/KDE_Classic/cursors/9d800788f1b08800ae810202380a0822 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/X_cursor b/cursors/KDE_Classic/cursors/X_cursor new file mode 100644 index 00000000..2bd051aa Binary files /dev/null and b/cursors/KDE_Classic/cursors/X_cursor differ diff --git a/cursors/KDE_Classic/cursors/all-scroll b/cursors/KDE_Classic/cursors/all-scroll new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/KDE_Classic/cursors/all-scroll @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/bottom_left_corner b/cursors/KDE_Classic/cursors/bottom_left_corner new file mode 100644 index 00000000..abfe647d Binary files /dev/null and b/cursors/KDE_Classic/cursors/bottom_left_corner differ diff --git a/cursors/KDE_Classic/cursors/bottom_right_corner b/cursors/KDE_Classic/cursors/bottom_right_corner new file mode 100644 index 00000000..87b5e293 Binary files /dev/null and b/cursors/KDE_Classic/cursors/bottom_right_corner differ diff --git a/cursors/KDE_Classic/cursors/bottom_side b/cursors/KDE_Classic/cursors/bottom_side new file mode 100644 index 00000000..ca1cf65e Binary files /dev/null and b/cursors/KDE_Classic/cursors/bottom_side differ diff --git a/cursors/KDE_Classic/cursors/center_ptr b/cursors/KDE_Classic/cursors/center_ptr new file mode 100644 index 00000000..519a6e9e Binary files /dev/null and b/cursors/KDE_Classic/cursors/center_ptr differ diff --git a/cursors/KDE_Classic/cursors/closedhand b/cursors/KDE_Classic/cursors/closedhand new file mode 100644 index 00000000..051aa59d Binary files /dev/null and b/cursors/KDE_Classic/cursors/closedhand differ diff --git a/cursors/KDE_Classic/cursors/col-resize b/cursors/KDE_Classic/cursors/col-resize new file mode 120000 index 00000000..179b52be --- /dev/null +++ b/cursors/KDE_Classic/cursors/col-resize @@ -0,0 +1 @@ +split_v \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/cross b/cursors/KDE_Classic/cursors/cross new file mode 100644 index 00000000..8eeca220 Binary files /dev/null and b/cursors/KDE_Classic/cursors/cross differ diff --git a/cursors/KDE_Classic/cursors/crossed_circle b/cursors/KDE_Classic/cursors/crossed_circle new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/KDE_Classic/cursors/crossed_circle @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/crosshair b/cursors/KDE_Classic/cursors/crosshair new file mode 100644 index 00000000..c00bc799 Binary files /dev/null and b/cursors/KDE_Classic/cursors/crosshair differ diff --git a/cursors/KDE_Classic/cursors/d9ce0ab605698f320427677b458ad60b b/cursors/KDE_Classic/cursors/d9ce0ab605698f320427677b458ad60b new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/KDE_Classic/cursors/d9ce0ab605698f320427677b458ad60b @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/dnd-move b/cursors/KDE_Classic/cursors/dnd-move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/KDE_Classic/cursors/dnd-move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/dnd-no-drop b/cursors/KDE_Classic/cursors/dnd-no-drop new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/KDE_Classic/cursors/dnd-no-drop @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/dnd-none b/cursors/KDE_Classic/cursors/dnd-none new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/KDE_Classic/cursors/dnd-none @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/e-resize b/cursors/KDE_Classic/cursors/e-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/KDE_Classic/cursors/e-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/e29285e634086352946a0e7090d73106 b/cursors/KDE_Classic/cursors/e29285e634086352946a0e7090d73106 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/KDE_Classic/cursors/e29285e634086352946a0e7090d73106 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff b/cursors/KDE_Classic/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/KDE_Classic/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/fleur b/cursors/KDE_Classic/cursors/fleur new file mode 100644 index 00000000..d4332ba8 Binary files /dev/null and b/cursors/KDE_Classic/cursors/fleur differ diff --git a/cursors/KDE_Classic/cursors/forbidden b/cursors/KDE_Classic/cursors/forbidden new file mode 100644 index 00000000..b843aa08 Binary files /dev/null and b/cursors/KDE_Classic/cursors/forbidden differ diff --git a/cursors/KDE_Classic/cursors/half-busy b/cursors/KDE_Classic/cursors/half-busy new file mode 100644 index 00000000..39f1b52e Binary files /dev/null and b/cursors/KDE_Classic/cursors/half-busy differ diff --git a/cursors/KDE_Classic/cursors/hand1 b/cursors/KDE_Classic/cursors/hand1 new file mode 100644 index 00000000..012448a6 Binary files /dev/null and b/cursors/KDE_Classic/cursors/hand1 differ diff --git a/cursors/KDE_Classic/cursors/hand2 b/cursors/KDE_Classic/cursors/hand2 new file mode 100644 index 00000000..1e9cf9c0 Binary files /dev/null and b/cursors/KDE_Classic/cursors/hand2 differ diff --git a/cursors/KDE_Classic/cursors/help b/cursors/KDE_Classic/cursors/help new file mode 100644 index 00000000..5bcc999e Binary files /dev/null and b/cursors/KDE_Classic/cursors/help differ diff --git a/cursors/KDE_Classic/cursors/ibeam b/cursors/KDE_Classic/cursors/ibeam new file mode 100644 index 00000000..90c4dc71 Binary files /dev/null and b/cursors/KDE_Classic/cursors/ibeam differ diff --git a/cursors/KDE_Classic/cursors/left_ptr b/cursors/KDE_Classic/cursors/left_ptr new file mode 100644 index 00000000..5859b2ea Binary files /dev/null and b/cursors/KDE_Classic/cursors/left_ptr differ diff --git a/cursors/KDE_Classic/cursors/left_ptr_watch b/cursors/KDE_Classic/cursors/left_ptr_watch new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/KDE_Classic/cursors/left_ptr_watch @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/left_side b/cursors/KDE_Classic/cursors/left_side new file mode 100644 index 00000000..a17bc1d6 Binary files /dev/null and b/cursors/KDE_Classic/cursors/left_side differ diff --git a/cursors/KDE_Classic/cursors/move b/cursors/KDE_Classic/cursors/move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/KDE_Classic/cursors/move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/n-resize b/cursors/KDE_Classic/cursors/n-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/KDE_Classic/cursors/n-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/not-allowed b/cursors/KDE_Classic/cursors/not-allowed new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/KDE_Classic/cursors/not-allowed @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/openhand b/cursors/KDE_Classic/cursors/openhand new file mode 100644 index 00000000..953b8e7e Binary files /dev/null and b/cursors/KDE_Classic/cursors/openhand differ diff --git a/cursors/KDE_Classic/cursors/pirate b/cursors/KDE_Classic/cursors/pirate new file mode 100644 index 00000000..c13aaa75 Binary files /dev/null and b/cursors/KDE_Classic/cursors/pirate differ diff --git a/cursors/KDE_Classic/cursors/pointer b/cursors/KDE_Classic/cursors/pointer new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/KDE_Classic/cursors/pointer @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/pointing_hand b/cursors/KDE_Classic/cursors/pointing_hand new file mode 100644 index 00000000..1e9cf9c0 Binary files /dev/null and b/cursors/KDE_Classic/cursors/pointing_hand differ diff --git a/cursors/KDE_Classic/cursors/progress b/cursors/KDE_Classic/cursors/progress new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/KDE_Classic/cursors/progress @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/question_arrow b/cursors/KDE_Classic/cursors/question_arrow new file mode 100644 index 00000000..f2ea8ecc Binary files /dev/null and b/cursors/KDE_Classic/cursors/question_arrow differ diff --git a/cursors/KDE_Classic/cursors/right_ptr b/cursors/KDE_Classic/cursors/right_ptr new file mode 100644 index 00000000..368a2a01 Binary files /dev/null and b/cursors/KDE_Classic/cursors/right_ptr differ diff --git a/cursors/KDE_Classic/cursors/right_side b/cursors/KDE_Classic/cursors/right_side new file mode 100644 index 00000000..c9e333ea Binary files /dev/null and b/cursors/KDE_Classic/cursors/right_side differ diff --git a/cursors/KDE_Classic/cursors/row-resize b/cursors/KDE_Classic/cursors/row-resize new file mode 120000 index 00000000..e3aa7487 --- /dev/null +++ b/cursors/KDE_Classic/cursors/row-resize @@ -0,0 +1 @@ +split_h \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/s-resize b/cursors/KDE_Classic/cursors/s-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/KDE_Classic/cursors/s-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/sb_h_double_arrow b/cursors/KDE_Classic/cursors/sb_h_double_arrow new file mode 100644 index 00000000..e9701712 Binary files /dev/null and b/cursors/KDE_Classic/cursors/sb_h_double_arrow differ diff --git a/cursors/KDE_Classic/cursors/sb_v_double_arrow b/cursors/KDE_Classic/cursors/sb_v_double_arrow new file mode 100644 index 00000000..a7a28081 Binary files /dev/null and b/cursors/KDE_Classic/cursors/sb_v_double_arrow differ diff --git a/cursors/KDE_Classic/cursors/size_all b/cursors/KDE_Classic/cursors/size_all new file mode 100644 index 00000000..d4332ba8 Binary files /dev/null and b/cursors/KDE_Classic/cursors/size_all differ diff --git a/cursors/KDE_Classic/cursors/size_bdiag b/cursors/KDE_Classic/cursors/size_bdiag new file mode 100644 index 00000000..403b892f Binary files /dev/null and b/cursors/KDE_Classic/cursors/size_bdiag differ diff --git a/cursors/KDE_Classic/cursors/size_fdiag b/cursors/KDE_Classic/cursors/size_fdiag new file mode 100644 index 00000000..922dd8f4 Binary files /dev/null and b/cursors/KDE_Classic/cursors/size_fdiag differ diff --git a/cursors/KDE_Classic/cursors/size_hor b/cursors/KDE_Classic/cursors/size_hor new file mode 100644 index 00000000..05ef64f7 Binary files /dev/null and b/cursors/KDE_Classic/cursors/size_hor differ diff --git a/cursors/KDE_Classic/cursors/size_ver b/cursors/KDE_Classic/cursors/size_ver new file mode 100644 index 00000000..28c7a446 Binary files /dev/null and b/cursors/KDE_Classic/cursors/size_ver differ diff --git a/cursors/KDE_Classic/cursors/split_h b/cursors/KDE_Classic/cursors/split_h new file mode 100644 index 00000000..2fc7ea9f Binary files /dev/null and b/cursors/KDE_Classic/cursors/split_h differ diff --git a/cursors/KDE_Classic/cursors/split_v b/cursors/KDE_Classic/cursors/split_v new file mode 100644 index 00000000..550990f4 Binary files /dev/null and b/cursors/KDE_Classic/cursors/split_v differ diff --git a/cursors/KDE_Classic/cursors/text b/cursors/KDE_Classic/cursors/text new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/KDE_Classic/cursors/text @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/top_left_corner b/cursors/KDE_Classic/cursors/top_left_corner new file mode 100644 index 00000000..193e1d49 Binary files /dev/null and b/cursors/KDE_Classic/cursors/top_left_corner differ diff --git a/cursors/KDE_Classic/cursors/top_right_corner b/cursors/KDE_Classic/cursors/top_right_corner new file mode 100644 index 00000000..c28d128c Binary files /dev/null and b/cursors/KDE_Classic/cursors/top_right_corner differ diff --git a/cursors/KDE_Classic/cursors/top_side b/cursors/KDE_Classic/cursors/top_side new file mode 100644 index 00000000..30f3435e Binary files /dev/null and b/cursors/KDE_Classic/cursors/top_side differ diff --git a/cursors/KDE_Classic/cursors/up_arrow b/cursors/KDE_Classic/cursors/up_arrow new file mode 100644 index 00000000..519a6e9e Binary files /dev/null and b/cursors/KDE_Classic/cursors/up_arrow differ diff --git a/cursors/KDE_Classic/cursors/v_double_arrow b/cursors/KDE_Classic/cursors/v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/KDE_Classic/cursors/v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/w-resize b/cursors/KDE_Classic/cursors/w-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/KDE_Classic/cursors/w-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/wait b/cursors/KDE_Classic/cursors/wait new file mode 100644 index 00000000..e9cc6b09 Binary files /dev/null and b/cursors/KDE_Classic/cursors/wait differ diff --git a/cursors/KDE_Classic/cursors/watch b/cursors/KDE_Classic/cursors/watch new file mode 100644 index 00000000..e9cc6b09 Binary files /dev/null and b/cursors/KDE_Classic/cursors/watch differ diff --git a/cursors/KDE_Classic/cursors/whats_this b/cursors/KDE_Classic/cursors/whats_this new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/KDE_Classic/cursors/whats_this @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/xcursorconfig b/cursors/KDE_Classic/cursors/xcursorconfig new file mode 100644 index 00000000..0dd949e2 --- /dev/null +++ b/cursors/KDE_Classic/cursors/xcursorconfig @@ -0,0 +1 @@ +24 7 12 pirate.png \ No newline at end of file diff --git a/cursors/KDE_Classic/cursors/xterm b/cursors/KDE_Classic/cursors/xterm new file mode 100644 index 00000000..90c4dc71 Binary files /dev/null and b/cursors/KDE_Classic/cursors/xterm differ diff --git a/cursors/KDE_Classic/index.theme b/cursors/KDE_Classic/index.theme new file mode 100644 index 00000000..b4083cb7 --- /dev/null +++ b/cursors/KDE_Classic/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = KDE Classic +Comment = The default cursor theme in KDE 2 and 3 diff --git a/cursors/LICENSE b/cursors/LICENSE new file mode 100644 index 00000000..fc8a5de7 --- /dev/null +++ b/cursors/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/cursors/Oxygen_Black/cursors/00000000000000020006000e7e9ffc3f b/cursors/Oxygen_Black/cursors/00000000000000020006000e7e9ffc3f new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Black/cursors/00000000000000020006000e7e9ffc3f @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/00008160000006810000408080010102 b/cursors/Oxygen_Black/cursors/00008160000006810000408080010102 new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/00008160000006810000408080010102 @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/03b6e0fcb3499374a867c041f52298f0 b/cursors/Oxygen_Black/cursors/03b6e0fcb3499374a867c041f52298f0 new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_Black/cursors/03b6e0fcb3499374a867c041f52298f0 @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/08e8e1c95fe2fc01f976f1e063a24ccd b/cursors/Oxygen_Black/cursors/08e8e1c95fe2fc01f976f1e063a24ccd new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Black/cursors/08e8e1c95fe2fc01f976f1e063a24ccd @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/1081e37283d90000800003c07f3ef6bf b/cursors/Oxygen_Black/cursors/1081e37283d90000800003c07f3ef6bf new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Black/cursors/1081e37283d90000800003c07f3ef6bf @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/3085a0e285430894940527032f8b26df b/cursors/Oxygen_Black/cursors/3085a0e285430894940527032f8b26df new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/3085a0e285430894940527032f8b26df @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/3ecb610c1bf2410f44200f48c40d3599 b/cursors/Oxygen_Black/cursors/3ecb610c1bf2410f44200f48c40d3599 new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Black/cursors/3ecb610c1bf2410f44200f48c40d3599 @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/4498f0e0c1937ffe01fd06f973665830 b/cursors/Oxygen_Black/cursors/4498f0e0c1937ffe01fd06f973665830 new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/4498f0e0c1937ffe01fd06f973665830 @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 b/cursors/Oxygen_Black/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Black/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/6407b0e94181790501fd1e167b474872 b/cursors/Oxygen_Black/cursors/6407b0e94181790501fd1e167b474872 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Black/cursors/6407b0e94181790501fd1e167b474872 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/640fb0e74195791501fd1ed57b41487f b/cursors/Oxygen_Black/cursors/640fb0e74195791501fd1ed57b41487f new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/640fb0e74195791501fd1ed57b41487f @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/9081237383d90e509aa00f00170e968f b/cursors/Oxygen_Black/cursors/9081237383d90e509aa00f00170e968f new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/9081237383d90e509aa00f00170e968f @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/9d800788f1b08800ae810202380a0822 b/cursors/Oxygen_Black/cursors/9d800788f1b08800ae810202380a0822 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/9d800788f1b08800ae810202380a0822 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/X_cursor b/cursors/Oxygen_Black/cursors/X_cursor new file mode 100644 index 00000000..f6865b59 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/X_cursor differ diff --git a/cursors/Oxygen_Black/cursors/a2a266d0498c3104214a47bd64ab0fc8 b/cursors/Oxygen_Black/cursors/a2a266d0498c3104214a47bd64ab0fc8 new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/a2a266d0498c3104214a47bd64ab0fc8 @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/alias b/cursors/Oxygen_Black/cursors/alias new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/alias @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/all-scroll b/cursors/Oxygen_Black/cursors/all-scroll new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/all-scroll @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/b66166c04f8c3109214a4fbd64a50fc8 b/cursors/Oxygen_Black/cursors/b66166c04f8c3109214a4fbd64a50fc8 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Black/cursors/b66166c04f8c3109214a4fbd64a50fc8 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/circle b/cursors/Oxygen_Black/cursors/circle new file mode 100644 index 00000000..057ce294 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/circle differ diff --git a/cursors/Oxygen_Black/cursors/closedhand b/cursors/Oxygen_Black/cursors/closedhand new file mode 100644 index 00000000..587d8d11 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/closedhand differ diff --git a/cursors/Oxygen_Black/cursors/col-resize b/cursors/Oxygen_Black/cursors/col-resize new file mode 120000 index 00000000..179b52be --- /dev/null +++ b/cursors/Oxygen_Black/cursors/col-resize @@ -0,0 +1 @@ +split_v \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/color-picker b/cursors/Oxygen_Black/cursors/color-picker new file mode 100644 index 00000000..0f36e7ab Binary files /dev/null and b/cursors/Oxygen_Black/cursors/color-picker differ diff --git a/cursors/Oxygen_Black/cursors/copy b/cursors/Oxygen_Black/cursors/copy new file mode 100644 index 00000000..9229c1d8 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/copy differ diff --git a/cursors/Oxygen_Black/cursors/cross b/cursors/Oxygen_Black/cursors/cross new file mode 100644 index 00000000..71c82470 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/cross differ diff --git a/cursors/Oxygen_Black/cursors/crossed_circle b/cursors/Oxygen_Black/cursors/crossed_circle new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_Black/cursors/crossed_circle @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/d9ce0ab605698f320427677b458ad60b b/cursors/Oxygen_Black/cursors/d9ce0ab605698f320427677b458ad60b new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Black/cursors/d9ce0ab605698f320427677b458ad60b @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/dnd-copy b/cursors/Oxygen_Black/cursors/dnd-copy new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Black/cursors/dnd-copy @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/dnd-link b/cursors/Oxygen_Black/cursors/dnd-link new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/dnd-link @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/dnd-move b/cursors/Oxygen_Black/cursors/dnd-move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/dnd-move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/dnd-no-drop b/cursors/Oxygen_Black/cursors/dnd-no-drop new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/dnd-no-drop @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/dnd-none b/cursors/Oxygen_Black/cursors/dnd-none new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/dnd-none @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/e-resize b/cursors/Oxygen_Black/cursors/e-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Black/cursors/e-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/e29285e634086352946a0e7090d73106 b/cursors/Oxygen_Black/cursors/e29285e634086352946a0e7090d73106 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/e29285e634086352946a0e7090d73106 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff b/cursors/Oxygen_Black/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/fleur b/cursors/Oxygen_Black/cursors/fleur new file mode 100644 index 00000000..9e0469ef Binary files /dev/null and b/cursors/Oxygen_Black/cursors/fleur differ diff --git a/cursors/Oxygen_Black/cursors/forbidden b/cursors/Oxygen_Black/cursors/forbidden new file mode 100644 index 00000000..d268ff8c Binary files /dev/null and b/cursors/Oxygen_Black/cursors/forbidden differ diff --git a/cursors/Oxygen_Black/cursors/half-busy b/cursors/Oxygen_Black/cursors/half-busy new file mode 100644 index 00000000..402922cd Binary files /dev/null and b/cursors/Oxygen_Black/cursors/half-busy differ diff --git a/cursors/Oxygen_Black/cursors/hand1 b/cursors/Oxygen_Black/cursors/hand1 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/hand1 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/hand2 b/cursors/Oxygen_Black/cursors/hand2 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/hand2 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/help b/cursors/Oxygen_Black/cursors/help new file mode 100644 index 00000000..286a8eeb Binary files /dev/null and b/cursors/Oxygen_Black/cursors/help differ diff --git a/cursors/Oxygen_Black/cursors/ibeam b/cursors/Oxygen_Black/cursors/ibeam new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/ibeam @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/left_ptr b/cursors/Oxygen_Black/cursors/left_ptr new file mode 100644 index 00000000..23a43e83 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/left_ptr differ diff --git a/cursors/Oxygen_Black/cursors/left_ptr_watch b/cursors/Oxygen_Black/cursors/left_ptr_watch new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Black/cursors/left_ptr_watch @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/link b/cursors/Oxygen_Black/cursors/link new file mode 100644 index 00000000..d156caa1 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/link differ diff --git a/cursors/Oxygen_Black/cursors/move b/cursors/Oxygen_Black/cursors/move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/n-resize b/cursors/Oxygen_Black/cursors/n-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/n-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/not-allowed b/cursors/Oxygen_Black/cursors/not-allowed new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/not-allowed @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/openhand b/cursors/Oxygen_Black/cursors/openhand new file mode 100644 index 00000000..7502f911 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/openhand differ diff --git a/cursors/Oxygen_Black/cursors/pencil b/cursors/Oxygen_Black/cursors/pencil new file mode 100644 index 00000000..43c29d90 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/pencil differ diff --git a/cursors/Oxygen_Black/cursors/pirate b/cursors/Oxygen_Black/cursors/pirate new file mode 100644 index 00000000..a7f82c4c Binary files /dev/null and b/cursors/Oxygen_Black/cursors/pirate differ diff --git a/cursors/Oxygen_Black/cursors/plus b/cursors/Oxygen_Black/cursors/plus new file mode 100644 index 00000000..c56772a7 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/plus differ diff --git a/cursors/Oxygen_Black/cursors/pointer b/cursors/Oxygen_Black/cursors/pointer new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/pointer @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/pointing_hand b/cursors/Oxygen_Black/cursors/pointing_hand new file mode 100644 index 00000000..dc9f77e8 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/pointing_hand differ diff --git a/cursors/Oxygen_Black/cursors/progress b/cursors/Oxygen_Black/cursors/progress new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Black/cursors/progress @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/question_arrow b/cursors/Oxygen_Black/cursors/question_arrow new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Black/cursors/question_arrow @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/row-resize b/cursors/Oxygen_Black/cursors/row-resize new file mode 120000 index 00000000..e3aa7487 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/row-resize @@ -0,0 +1 @@ +split_h \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/s-resize b/cursors/Oxygen_Black/cursors/s-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/s-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/sb_h_double_arrow b/cursors/Oxygen_Black/cursors/sb_h_double_arrow new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Black/cursors/sb_h_double_arrow @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/sb_v_double_arrow b/cursors/Oxygen_Black/cursors/sb_v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/sb_v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/size_all b/cursors/Oxygen_Black/cursors/size_all new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/size_all @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/size_bdiag b/cursors/Oxygen_Black/cursors/size_bdiag new file mode 100644 index 00000000..45d3c703 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/size_bdiag differ diff --git a/cursors/Oxygen_Black/cursors/size_fdiag b/cursors/Oxygen_Black/cursors/size_fdiag new file mode 100644 index 00000000..92d05279 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/size_fdiag differ diff --git a/cursors/Oxygen_Black/cursors/size_hor b/cursors/Oxygen_Black/cursors/size_hor new file mode 100644 index 00000000..0cb5b9a2 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/size_hor differ diff --git a/cursors/Oxygen_Black/cursors/size_ver b/cursors/Oxygen_Black/cursors/size_ver new file mode 100644 index 00000000..ed30b599 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/size_ver differ diff --git a/cursors/Oxygen_Black/cursors/split_h b/cursors/Oxygen_Black/cursors/split_h new file mode 100644 index 00000000..28df4a5b Binary files /dev/null and b/cursors/Oxygen_Black/cursors/split_h differ diff --git a/cursors/Oxygen_Black/cursors/split_v b/cursors/Oxygen_Black/cursors/split_v new file mode 100644 index 00000000..553261d9 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/split_v differ diff --git a/cursors/Oxygen_Black/cursors/text b/cursors/Oxygen_Black/cursors/text new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/text @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/up_arrow b/cursors/Oxygen_Black/cursors/up_arrow new file mode 100644 index 00000000..cb6d683f Binary files /dev/null and b/cursors/Oxygen_Black/cursors/up_arrow differ diff --git a/cursors/Oxygen_Black/cursors/v_double_arrow b/cursors/Oxygen_Black/cursors/v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Black/cursors/v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/w-resize b/cursors/Oxygen_Black/cursors/w-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Black/cursors/w-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/wait b/cursors/Oxygen_Black/cursors/wait new file mode 100644 index 00000000..a5920b57 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/wait differ diff --git a/cursors/Oxygen_Black/cursors/watch b/cursors/Oxygen_Black/cursors/watch new file mode 120000 index 00000000..fd80437a --- /dev/null +++ b/cursors/Oxygen_Black/cursors/watch @@ -0,0 +1 @@ +wait \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/whats_this b/cursors/Oxygen_Black/cursors/whats_this new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Black/cursors/whats_this @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Black/cursors/xterm b/cursors/Oxygen_Black/cursors/xterm new file mode 100644 index 00000000..14bb5da5 Binary files /dev/null and b/cursors/Oxygen_Black/cursors/xterm differ diff --git a/cursors/Oxygen_Black/index.theme b/cursors/Oxygen_Black/index.theme new file mode 100644 index 00000000..a2a6d246 --- /dev/null +++ b/cursors/Oxygen_Black/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Black +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/Oxygen_Blue/cursors/00000000000000020006000e7e9ffc3f b/cursors/Oxygen_Blue/cursors/00000000000000020006000e7e9ffc3f new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/00000000000000020006000e7e9ffc3f @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/00008160000006810000408080010102 b/cursors/Oxygen_Blue/cursors/00008160000006810000408080010102 new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/00008160000006810000408080010102 @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/03b6e0fcb3499374a867c041f52298f0 b/cursors/Oxygen_Blue/cursors/03b6e0fcb3499374a867c041f52298f0 new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/03b6e0fcb3499374a867c041f52298f0 @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/08e8e1c95fe2fc01f976f1e063a24ccd b/cursors/Oxygen_Blue/cursors/08e8e1c95fe2fc01f976f1e063a24ccd new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/08e8e1c95fe2fc01f976f1e063a24ccd @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/1081e37283d90000800003c07f3ef6bf b/cursors/Oxygen_Blue/cursors/1081e37283d90000800003c07f3ef6bf new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/1081e37283d90000800003c07f3ef6bf @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/3085a0e285430894940527032f8b26df b/cursors/Oxygen_Blue/cursors/3085a0e285430894940527032f8b26df new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/3085a0e285430894940527032f8b26df @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/3ecb610c1bf2410f44200f48c40d3599 b/cursors/Oxygen_Blue/cursors/3ecb610c1bf2410f44200f48c40d3599 new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/3ecb610c1bf2410f44200f48c40d3599 @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/4498f0e0c1937ffe01fd06f973665830 b/cursors/Oxygen_Blue/cursors/4498f0e0c1937ffe01fd06f973665830 new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/4498f0e0c1937ffe01fd06f973665830 @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 b/cursors/Oxygen_Blue/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/6407b0e94181790501fd1e167b474872 b/cursors/Oxygen_Blue/cursors/6407b0e94181790501fd1e167b474872 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/6407b0e94181790501fd1e167b474872 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/640fb0e74195791501fd1ed57b41487f b/cursors/Oxygen_Blue/cursors/640fb0e74195791501fd1ed57b41487f new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/640fb0e74195791501fd1ed57b41487f @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/9081237383d90e509aa00f00170e968f b/cursors/Oxygen_Blue/cursors/9081237383d90e509aa00f00170e968f new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/9081237383d90e509aa00f00170e968f @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/9d800788f1b08800ae810202380a0822 b/cursors/Oxygen_Blue/cursors/9d800788f1b08800ae810202380a0822 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/9d800788f1b08800ae810202380a0822 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/X_cursor b/cursors/Oxygen_Blue/cursors/X_cursor new file mode 100644 index 00000000..215d1b2f Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/X_cursor differ diff --git a/cursors/Oxygen_Blue/cursors/a2a266d0498c3104214a47bd64ab0fc8 b/cursors/Oxygen_Blue/cursors/a2a266d0498c3104214a47bd64ab0fc8 new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/a2a266d0498c3104214a47bd64ab0fc8 @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/alias b/cursors/Oxygen_Blue/cursors/alias new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/alias @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/all-scroll b/cursors/Oxygen_Blue/cursors/all-scroll new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/all-scroll @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/b66166c04f8c3109214a4fbd64a50fc8 b/cursors/Oxygen_Blue/cursors/b66166c04f8c3109214a4fbd64a50fc8 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/b66166c04f8c3109214a4fbd64a50fc8 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/circle b/cursors/Oxygen_Blue/cursors/circle new file mode 100644 index 00000000..057ce294 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/circle differ diff --git a/cursors/Oxygen_Blue/cursors/closedhand b/cursors/Oxygen_Blue/cursors/closedhand new file mode 100644 index 00000000..61d924c3 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/closedhand differ diff --git a/cursors/Oxygen_Blue/cursors/col-resize b/cursors/Oxygen_Blue/cursors/col-resize new file mode 120000 index 00000000..179b52be --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/col-resize @@ -0,0 +1 @@ +split_v \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/color-picker b/cursors/Oxygen_Blue/cursors/color-picker new file mode 100644 index 00000000..888cfa64 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/color-picker differ diff --git a/cursors/Oxygen_Blue/cursors/copy b/cursors/Oxygen_Blue/cursors/copy new file mode 100644 index 00000000..62b899b9 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/copy differ diff --git a/cursors/Oxygen_Blue/cursors/cross b/cursors/Oxygen_Blue/cursors/cross new file mode 100644 index 00000000..7657e241 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/cross differ diff --git a/cursors/Oxygen_Blue/cursors/crossed_circle b/cursors/Oxygen_Blue/cursors/crossed_circle new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/crossed_circle @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/d9ce0ab605698f320427677b458ad60b b/cursors/Oxygen_Blue/cursors/d9ce0ab605698f320427677b458ad60b new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/d9ce0ab605698f320427677b458ad60b @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/dnd-copy b/cursors/Oxygen_Blue/cursors/dnd-copy new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/dnd-copy @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/dnd-link b/cursors/Oxygen_Blue/cursors/dnd-link new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/dnd-link @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/dnd-move b/cursors/Oxygen_Blue/cursors/dnd-move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/dnd-move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/dnd-no-drop b/cursors/Oxygen_Blue/cursors/dnd-no-drop new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/dnd-no-drop @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/dnd-none b/cursors/Oxygen_Blue/cursors/dnd-none new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/dnd-none @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/e-resize b/cursors/Oxygen_Blue/cursors/e-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/e-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/e29285e634086352946a0e7090d73106 b/cursors/Oxygen_Blue/cursors/e29285e634086352946a0e7090d73106 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/e29285e634086352946a0e7090d73106 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff b/cursors/Oxygen_Blue/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/fleur b/cursors/Oxygen_Blue/cursors/fleur new file mode 100644 index 00000000..26ce80ee Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/fleur differ diff --git a/cursors/Oxygen_Blue/cursors/forbidden b/cursors/Oxygen_Blue/cursors/forbidden new file mode 100644 index 00000000..f467d7b2 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/forbidden differ diff --git a/cursors/Oxygen_Blue/cursors/half-busy b/cursors/Oxygen_Blue/cursors/half-busy new file mode 100644 index 00000000..d37fe7c3 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/half-busy differ diff --git a/cursors/Oxygen_Blue/cursors/hand1 b/cursors/Oxygen_Blue/cursors/hand1 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/hand1 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/hand2 b/cursors/Oxygen_Blue/cursors/hand2 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/hand2 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/help b/cursors/Oxygen_Blue/cursors/help new file mode 100644 index 00000000..d32c8cfd Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/help differ diff --git a/cursors/Oxygen_Blue/cursors/ibeam b/cursors/Oxygen_Blue/cursors/ibeam new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/ibeam @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/left_ptr b/cursors/Oxygen_Blue/cursors/left_ptr new file mode 100644 index 00000000..033662ef Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/left_ptr differ diff --git a/cursors/Oxygen_Blue/cursors/left_ptr_watch b/cursors/Oxygen_Blue/cursors/left_ptr_watch new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/left_ptr_watch @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/link b/cursors/Oxygen_Blue/cursors/link new file mode 100644 index 00000000..25059582 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/link differ diff --git a/cursors/Oxygen_Blue/cursors/move b/cursors/Oxygen_Blue/cursors/move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/n-resize b/cursors/Oxygen_Blue/cursors/n-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/n-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/not-allowed b/cursors/Oxygen_Blue/cursors/not-allowed new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/not-allowed @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/openhand b/cursors/Oxygen_Blue/cursors/openhand new file mode 100644 index 00000000..7c58f7ca Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/openhand differ diff --git a/cursors/Oxygen_Blue/cursors/pencil b/cursors/Oxygen_Blue/cursors/pencil new file mode 100644 index 00000000..cd6c843a Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/pencil differ diff --git a/cursors/Oxygen_Blue/cursors/pirate b/cursors/Oxygen_Blue/cursors/pirate new file mode 100644 index 00000000..a492ef0f Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/pirate differ diff --git a/cursors/Oxygen_Blue/cursors/plus b/cursors/Oxygen_Blue/cursors/plus new file mode 100644 index 00000000..087c4359 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/plus differ diff --git a/cursors/Oxygen_Blue/cursors/pointer b/cursors/Oxygen_Blue/cursors/pointer new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/pointer @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/pointing_hand b/cursors/Oxygen_Blue/cursors/pointing_hand new file mode 100644 index 00000000..a1c5fbe0 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/pointing_hand differ diff --git a/cursors/Oxygen_Blue/cursors/progress b/cursors/Oxygen_Blue/cursors/progress new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/progress @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/question_arrow b/cursors/Oxygen_Blue/cursors/question_arrow new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/question_arrow @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/row-resize b/cursors/Oxygen_Blue/cursors/row-resize new file mode 120000 index 00000000..e3aa7487 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/row-resize @@ -0,0 +1 @@ +split_h \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/s-resize b/cursors/Oxygen_Blue/cursors/s-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/s-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/sb_h_double_arrow b/cursors/Oxygen_Blue/cursors/sb_h_double_arrow new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/sb_h_double_arrow @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/sb_v_double_arrow b/cursors/Oxygen_Blue/cursors/sb_v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/sb_v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/size_all b/cursors/Oxygen_Blue/cursors/size_all new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/size_all @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/size_bdiag b/cursors/Oxygen_Blue/cursors/size_bdiag new file mode 100644 index 00000000..dd3f89dc Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/size_bdiag differ diff --git a/cursors/Oxygen_Blue/cursors/size_fdiag b/cursors/Oxygen_Blue/cursors/size_fdiag new file mode 100644 index 00000000..ca91aed8 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/size_fdiag differ diff --git a/cursors/Oxygen_Blue/cursors/size_hor b/cursors/Oxygen_Blue/cursors/size_hor new file mode 100644 index 00000000..2279fdf6 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/size_hor differ diff --git a/cursors/Oxygen_Blue/cursors/size_ver b/cursors/Oxygen_Blue/cursors/size_ver new file mode 100644 index 00000000..ce8bc8b3 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/size_ver differ diff --git a/cursors/Oxygen_Blue/cursors/split_h b/cursors/Oxygen_Blue/cursors/split_h new file mode 100644 index 00000000..18480987 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/split_h differ diff --git a/cursors/Oxygen_Blue/cursors/split_v b/cursors/Oxygen_Blue/cursors/split_v new file mode 100644 index 00000000..cc9f078e Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/split_v differ diff --git a/cursors/Oxygen_Blue/cursors/text b/cursors/Oxygen_Blue/cursors/text new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/text @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/up_arrow b/cursors/Oxygen_Blue/cursors/up_arrow new file mode 100644 index 00000000..0efc3e1c Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/up_arrow differ diff --git a/cursors/Oxygen_Blue/cursors/v_double_arrow b/cursors/Oxygen_Blue/cursors/v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/w-resize b/cursors/Oxygen_Blue/cursors/w-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/w-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/wait b/cursors/Oxygen_Blue/cursors/wait new file mode 100644 index 00000000..556453a4 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/wait differ diff --git a/cursors/Oxygen_Blue/cursors/watch b/cursors/Oxygen_Blue/cursors/watch new file mode 120000 index 00000000..fd80437a --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/watch @@ -0,0 +1 @@ +wait \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/whats_this b/cursors/Oxygen_Blue/cursors/whats_this new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Blue/cursors/whats_this @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Blue/cursors/xterm b/cursors/Oxygen_Blue/cursors/xterm new file mode 100644 index 00000000..5db9b7d3 Binary files /dev/null and b/cursors/Oxygen_Blue/cursors/xterm differ diff --git a/cursors/Oxygen_Blue/index.theme b/cursors/Oxygen_Blue/index.theme new file mode 100644 index 00000000..61f96a37 --- /dev/null +++ b/cursors/Oxygen_Blue/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Blue +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/Oxygen_White/cursors/00000000000000020006000e7e9ffc3f b/cursors/Oxygen_White/cursors/00000000000000020006000e7e9ffc3f new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_White/cursors/00000000000000020006000e7e9ffc3f @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/00008160000006810000408080010102 b/cursors/Oxygen_White/cursors/00008160000006810000408080010102 new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/00008160000006810000408080010102 @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/03b6e0fcb3499374a867c041f52298f0 b/cursors/Oxygen_White/cursors/03b6e0fcb3499374a867c041f52298f0 new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_White/cursors/03b6e0fcb3499374a867c041f52298f0 @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/08e8e1c95fe2fc01f976f1e063a24ccd b/cursors/Oxygen_White/cursors/08e8e1c95fe2fc01f976f1e063a24ccd new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_White/cursors/08e8e1c95fe2fc01f976f1e063a24ccd @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/1081e37283d90000800003c07f3ef6bf b/cursors/Oxygen_White/cursors/1081e37283d90000800003c07f3ef6bf new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_White/cursors/1081e37283d90000800003c07f3ef6bf @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/3085a0e285430894940527032f8b26df b/cursors/Oxygen_White/cursors/3085a0e285430894940527032f8b26df new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/3085a0e285430894940527032f8b26df @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/3ecb610c1bf2410f44200f48c40d3599 b/cursors/Oxygen_White/cursors/3ecb610c1bf2410f44200f48c40d3599 new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_White/cursors/3ecb610c1bf2410f44200f48c40d3599 @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/4498f0e0c1937ffe01fd06f973665830 b/cursors/Oxygen_White/cursors/4498f0e0c1937ffe01fd06f973665830 new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_White/cursors/4498f0e0c1937ffe01fd06f973665830 @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 b/cursors/Oxygen_White/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_White/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/6407b0e94181790501fd1e167b474872 b/cursors/Oxygen_White/cursors/6407b0e94181790501fd1e167b474872 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_White/cursors/6407b0e94181790501fd1e167b474872 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/640fb0e74195791501fd1ed57b41487f b/cursors/Oxygen_White/cursors/640fb0e74195791501fd1ed57b41487f new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/640fb0e74195791501fd1ed57b41487f @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/9081237383d90e509aa00f00170e968f b/cursors/Oxygen_White/cursors/9081237383d90e509aa00f00170e968f new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_White/cursors/9081237383d90e509aa00f00170e968f @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/9d800788f1b08800ae810202380a0822 b/cursors/Oxygen_White/cursors/9d800788f1b08800ae810202380a0822 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_White/cursors/9d800788f1b08800ae810202380a0822 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/X_cursor b/cursors/Oxygen_White/cursors/X_cursor new file mode 100644 index 00000000..5f0be9a6 Binary files /dev/null and b/cursors/Oxygen_White/cursors/X_cursor differ diff --git a/cursors/Oxygen_White/cursors/a2a266d0498c3104214a47bd64ab0fc8 b/cursors/Oxygen_White/cursors/a2a266d0498c3104214a47bd64ab0fc8 new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/a2a266d0498c3104214a47bd64ab0fc8 @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/alias b/cursors/Oxygen_White/cursors/alias new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/alias @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/all-scroll b/cursors/Oxygen_White/cursors/all-scroll new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_White/cursors/all-scroll @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/b66166c04f8c3109214a4fbd64a50fc8 b/cursors/Oxygen_White/cursors/b66166c04f8c3109214a4fbd64a50fc8 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_White/cursors/b66166c04f8c3109214a4fbd64a50fc8 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/circle b/cursors/Oxygen_White/cursors/circle new file mode 100644 index 00000000..057ce294 Binary files /dev/null and b/cursors/Oxygen_White/cursors/circle differ diff --git a/cursors/Oxygen_White/cursors/closedhand b/cursors/Oxygen_White/cursors/closedhand new file mode 100644 index 00000000..985c0abb Binary files /dev/null and b/cursors/Oxygen_White/cursors/closedhand differ diff --git a/cursors/Oxygen_White/cursors/col-resize b/cursors/Oxygen_White/cursors/col-resize new file mode 120000 index 00000000..179b52be --- /dev/null +++ b/cursors/Oxygen_White/cursors/col-resize @@ -0,0 +1 @@ +split_v \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/color-picker b/cursors/Oxygen_White/cursors/color-picker new file mode 100644 index 00000000..afd7d42d Binary files /dev/null and b/cursors/Oxygen_White/cursors/color-picker differ diff --git a/cursors/Oxygen_White/cursors/copy b/cursors/Oxygen_White/cursors/copy new file mode 100644 index 00000000..9cebec32 Binary files /dev/null and b/cursors/Oxygen_White/cursors/copy differ diff --git a/cursors/Oxygen_White/cursors/cross b/cursors/Oxygen_White/cursors/cross new file mode 100644 index 00000000..1cb37652 Binary files /dev/null and b/cursors/Oxygen_White/cursors/cross differ diff --git a/cursors/Oxygen_White/cursors/crossed_circle b/cursors/Oxygen_White/cursors/crossed_circle new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_White/cursors/crossed_circle @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/d9ce0ab605698f320427677b458ad60b b/cursors/Oxygen_White/cursors/d9ce0ab605698f320427677b458ad60b new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_White/cursors/d9ce0ab605698f320427677b458ad60b @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/dnd-copy b/cursors/Oxygen_White/cursors/dnd-copy new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_White/cursors/dnd-copy @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/dnd-link b/cursors/Oxygen_White/cursors/dnd-link new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/dnd-link @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/dnd-move b/cursors/Oxygen_White/cursors/dnd-move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_White/cursors/dnd-move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/dnd-no-drop b/cursors/Oxygen_White/cursors/dnd-no-drop new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_White/cursors/dnd-no-drop @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/dnd-none b/cursors/Oxygen_White/cursors/dnd-none new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_White/cursors/dnd-none @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/e-resize b/cursors/Oxygen_White/cursors/e-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_White/cursors/e-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/e29285e634086352946a0e7090d73106 b/cursors/Oxygen_White/cursors/e29285e634086352946a0e7090d73106 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_White/cursors/e29285e634086352946a0e7090d73106 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff b/cursors/Oxygen_White/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_White/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/fleur b/cursors/Oxygen_White/cursors/fleur new file mode 100644 index 00000000..eb7c8f09 Binary files /dev/null and b/cursors/Oxygen_White/cursors/fleur differ diff --git a/cursors/Oxygen_White/cursors/forbidden b/cursors/Oxygen_White/cursors/forbidden new file mode 100644 index 00000000..bc7ca8e9 Binary files /dev/null and b/cursors/Oxygen_White/cursors/forbidden differ diff --git a/cursors/Oxygen_White/cursors/half-busy b/cursors/Oxygen_White/cursors/half-busy new file mode 100644 index 00000000..003eb6e6 Binary files /dev/null and b/cursors/Oxygen_White/cursors/half-busy differ diff --git a/cursors/Oxygen_White/cursors/hand1 b/cursors/Oxygen_White/cursors/hand1 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_White/cursors/hand1 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/hand2 b/cursors/Oxygen_White/cursors/hand2 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_White/cursors/hand2 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/help b/cursors/Oxygen_White/cursors/help new file mode 100644 index 00000000..4d1f8b19 Binary files /dev/null and b/cursors/Oxygen_White/cursors/help differ diff --git a/cursors/Oxygen_White/cursors/ibeam b/cursors/Oxygen_White/cursors/ibeam new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_White/cursors/ibeam @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/left_ptr b/cursors/Oxygen_White/cursors/left_ptr new file mode 100644 index 00000000..24fac724 Binary files /dev/null and b/cursors/Oxygen_White/cursors/left_ptr differ diff --git a/cursors/Oxygen_White/cursors/left_ptr_watch b/cursors/Oxygen_White/cursors/left_ptr_watch new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_White/cursors/left_ptr_watch @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/link b/cursors/Oxygen_White/cursors/link new file mode 100644 index 00000000..13c98bf4 Binary files /dev/null and b/cursors/Oxygen_White/cursors/link differ diff --git a/cursors/Oxygen_White/cursors/move b/cursors/Oxygen_White/cursors/move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_White/cursors/move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/n-resize b/cursors/Oxygen_White/cursors/n-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/n-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/not-allowed b/cursors/Oxygen_White/cursors/not-allowed new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_White/cursors/not-allowed @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/openhand b/cursors/Oxygen_White/cursors/openhand new file mode 100644 index 00000000..e0ab243a Binary files /dev/null and b/cursors/Oxygen_White/cursors/openhand differ diff --git a/cursors/Oxygen_White/cursors/pencil b/cursors/Oxygen_White/cursors/pencil new file mode 100644 index 00000000..69705123 Binary files /dev/null and b/cursors/Oxygen_White/cursors/pencil differ diff --git a/cursors/Oxygen_White/cursors/pirate b/cursors/Oxygen_White/cursors/pirate new file mode 100644 index 00000000..a24d7541 Binary files /dev/null and b/cursors/Oxygen_White/cursors/pirate differ diff --git a/cursors/Oxygen_White/cursors/plus b/cursors/Oxygen_White/cursors/plus new file mode 100644 index 00000000..a60e981f Binary files /dev/null and b/cursors/Oxygen_White/cursors/plus differ diff --git a/cursors/Oxygen_White/cursors/pointer b/cursors/Oxygen_White/cursors/pointer new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_White/cursors/pointer @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/pointing_hand b/cursors/Oxygen_White/cursors/pointing_hand new file mode 100644 index 00000000..dbe5e6c9 Binary files /dev/null and b/cursors/Oxygen_White/cursors/pointing_hand differ diff --git a/cursors/Oxygen_White/cursors/progress b/cursors/Oxygen_White/cursors/progress new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_White/cursors/progress @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/question_arrow b/cursors/Oxygen_White/cursors/question_arrow new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_White/cursors/question_arrow @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/row-resize b/cursors/Oxygen_White/cursors/row-resize new file mode 120000 index 00000000..e3aa7487 --- /dev/null +++ b/cursors/Oxygen_White/cursors/row-resize @@ -0,0 +1 @@ +split_h \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/s-resize b/cursors/Oxygen_White/cursors/s-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/s-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/sb_h_double_arrow b/cursors/Oxygen_White/cursors/sb_h_double_arrow new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_White/cursors/sb_h_double_arrow @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/sb_v_double_arrow b/cursors/Oxygen_White/cursors/sb_v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/sb_v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/size_all b/cursors/Oxygen_White/cursors/size_all new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_White/cursors/size_all @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/size_bdiag b/cursors/Oxygen_White/cursors/size_bdiag new file mode 100644 index 00000000..b3aa9b27 Binary files /dev/null and b/cursors/Oxygen_White/cursors/size_bdiag differ diff --git a/cursors/Oxygen_White/cursors/size_fdiag b/cursors/Oxygen_White/cursors/size_fdiag new file mode 100644 index 00000000..0933e0cb Binary files /dev/null and b/cursors/Oxygen_White/cursors/size_fdiag differ diff --git a/cursors/Oxygen_White/cursors/size_hor b/cursors/Oxygen_White/cursors/size_hor new file mode 100644 index 00000000..87e1d01a Binary files /dev/null and b/cursors/Oxygen_White/cursors/size_hor differ diff --git a/cursors/Oxygen_White/cursors/size_ver b/cursors/Oxygen_White/cursors/size_ver new file mode 100644 index 00000000..93cb3fb0 Binary files /dev/null and b/cursors/Oxygen_White/cursors/size_ver differ diff --git a/cursors/Oxygen_White/cursors/split_h b/cursors/Oxygen_White/cursors/split_h new file mode 100644 index 00000000..69410798 Binary files /dev/null and b/cursors/Oxygen_White/cursors/split_h differ diff --git a/cursors/Oxygen_White/cursors/split_v b/cursors/Oxygen_White/cursors/split_v new file mode 100644 index 00000000..fd0d5419 Binary files /dev/null and b/cursors/Oxygen_White/cursors/split_v differ diff --git a/cursors/Oxygen_White/cursors/text b/cursors/Oxygen_White/cursors/text new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_White/cursors/text @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/up_arrow b/cursors/Oxygen_White/cursors/up_arrow new file mode 100644 index 00000000..e7dc0065 Binary files /dev/null and b/cursors/Oxygen_White/cursors/up_arrow differ diff --git a/cursors/Oxygen_White/cursors/v_double_arrow b/cursors/Oxygen_White/cursors/v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_White/cursors/v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/w-resize b/cursors/Oxygen_White/cursors/w-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_White/cursors/w-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/wait b/cursors/Oxygen_White/cursors/wait new file mode 100644 index 00000000..a9fd0cd0 Binary files /dev/null and b/cursors/Oxygen_White/cursors/wait differ diff --git a/cursors/Oxygen_White/cursors/watch b/cursors/Oxygen_White/cursors/watch new file mode 120000 index 00000000..fd80437a --- /dev/null +++ b/cursors/Oxygen_White/cursors/watch @@ -0,0 +1 @@ +wait \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/whats_this b/cursors/Oxygen_White/cursors/whats_this new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_White/cursors/whats_this @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_White/cursors/xterm b/cursors/Oxygen_White/cursors/xterm new file mode 100644 index 00000000..2e2ce611 Binary files /dev/null and b/cursors/Oxygen_White/cursors/xterm differ diff --git a/cursors/Oxygen_White/index.theme b/cursors/Oxygen_White/index.theme new file mode 100644 index 00000000..6e4470ac --- /dev/null +++ b/cursors/Oxygen_White/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen White +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/Oxygen_Yellow/cursors/00000000000000020006000e7e9ffc3f b/cursors/Oxygen_Yellow/cursors/00000000000000020006000e7e9ffc3f new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/00000000000000020006000e7e9ffc3f @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/00008160000006810000408080010102 b/cursors/Oxygen_Yellow/cursors/00008160000006810000408080010102 new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/00008160000006810000408080010102 @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/03b6e0fcb3499374a867c041f52298f0 b/cursors/Oxygen_Yellow/cursors/03b6e0fcb3499374a867c041f52298f0 new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/03b6e0fcb3499374a867c041f52298f0 @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/08e8e1c95fe2fc01f976f1e063a24ccd b/cursors/Oxygen_Yellow/cursors/08e8e1c95fe2fc01f976f1e063a24ccd new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/08e8e1c95fe2fc01f976f1e063a24ccd @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/1081e37283d90000800003c07f3ef6bf b/cursors/Oxygen_Yellow/cursors/1081e37283d90000800003c07f3ef6bf new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/1081e37283d90000800003c07f3ef6bf @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/3085a0e285430894940527032f8b26df b/cursors/Oxygen_Yellow/cursors/3085a0e285430894940527032f8b26df new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/3085a0e285430894940527032f8b26df @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/3ecb610c1bf2410f44200f48c40d3599 b/cursors/Oxygen_Yellow/cursors/3ecb610c1bf2410f44200f48c40d3599 new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/3ecb610c1bf2410f44200f48c40d3599 @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/4498f0e0c1937ffe01fd06f973665830 b/cursors/Oxygen_Yellow/cursors/4498f0e0c1937ffe01fd06f973665830 new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/4498f0e0c1937ffe01fd06f973665830 @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 b/cursors/Oxygen_Yellow/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/6407b0e94181790501fd1e167b474872 b/cursors/Oxygen_Yellow/cursors/6407b0e94181790501fd1e167b474872 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/6407b0e94181790501fd1e167b474872 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/640fb0e74195791501fd1ed57b41487f b/cursors/Oxygen_Yellow/cursors/640fb0e74195791501fd1ed57b41487f new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/640fb0e74195791501fd1ed57b41487f @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/9081237383d90e509aa00f00170e968f b/cursors/Oxygen_Yellow/cursors/9081237383d90e509aa00f00170e968f new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/9081237383d90e509aa00f00170e968f @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/9d800788f1b08800ae810202380a0822 b/cursors/Oxygen_Yellow/cursors/9d800788f1b08800ae810202380a0822 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/9d800788f1b08800ae810202380a0822 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/X_cursor b/cursors/Oxygen_Yellow/cursors/X_cursor new file mode 100644 index 00000000..80d67f7c Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/X_cursor differ diff --git a/cursors/Oxygen_Yellow/cursors/a2a266d0498c3104214a47bd64ab0fc8 b/cursors/Oxygen_Yellow/cursors/a2a266d0498c3104214a47bd64ab0fc8 new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/a2a266d0498c3104214a47bd64ab0fc8 @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/alias b/cursors/Oxygen_Yellow/cursors/alias new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/alias @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/all-scroll b/cursors/Oxygen_Yellow/cursors/all-scroll new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/all-scroll @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/b66166c04f8c3109214a4fbd64a50fc8 b/cursors/Oxygen_Yellow/cursors/b66166c04f8c3109214a4fbd64a50fc8 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/b66166c04f8c3109214a4fbd64a50fc8 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/circle b/cursors/Oxygen_Yellow/cursors/circle new file mode 100644 index 00000000..057ce294 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/circle differ diff --git a/cursors/Oxygen_Yellow/cursors/closedhand b/cursors/Oxygen_Yellow/cursors/closedhand new file mode 100644 index 00000000..eb99172f Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/closedhand differ diff --git a/cursors/Oxygen_Yellow/cursors/col-resize b/cursors/Oxygen_Yellow/cursors/col-resize new file mode 120000 index 00000000..179b52be --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/col-resize @@ -0,0 +1 @@ +split_v \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/color-picker b/cursors/Oxygen_Yellow/cursors/color-picker new file mode 100644 index 00000000..9546544a Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/color-picker differ diff --git a/cursors/Oxygen_Yellow/cursors/copy b/cursors/Oxygen_Yellow/cursors/copy new file mode 100644 index 00000000..4fd7f17e Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/copy differ diff --git a/cursors/Oxygen_Yellow/cursors/cross b/cursors/Oxygen_Yellow/cursors/cross new file mode 100644 index 00000000..4a27f1c3 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/cross differ diff --git a/cursors/Oxygen_Yellow/cursors/crossed_circle b/cursors/Oxygen_Yellow/cursors/crossed_circle new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/crossed_circle @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/d9ce0ab605698f320427677b458ad60b b/cursors/Oxygen_Yellow/cursors/d9ce0ab605698f320427677b458ad60b new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/d9ce0ab605698f320427677b458ad60b @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/dnd-copy b/cursors/Oxygen_Yellow/cursors/dnd-copy new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/dnd-copy @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/dnd-link b/cursors/Oxygen_Yellow/cursors/dnd-link new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/dnd-link @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/dnd-move b/cursors/Oxygen_Yellow/cursors/dnd-move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/dnd-move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/dnd-no-drop b/cursors/Oxygen_Yellow/cursors/dnd-no-drop new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/dnd-no-drop @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/dnd-none b/cursors/Oxygen_Yellow/cursors/dnd-none new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/dnd-none @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/e-resize b/cursors/Oxygen_Yellow/cursors/e-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/e-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/e29285e634086352946a0e7090d73106 b/cursors/Oxygen_Yellow/cursors/e29285e634086352946a0e7090d73106 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/e29285e634086352946a0e7090d73106 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff b/cursors/Oxygen_Yellow/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/fleur b/cursors/Oxygen_Yellow/cursors/fleur new file mode 100644 index 00000000..71ff1dd6 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/fleur differ diff --git a/cursors/Oxygen_Yellow/cursors/forbidden b/cursors/Oxygen_Yellow/cursors/forbidden new file mode 100644 index 00000000..5c1decd2 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/forbidden differ diff --git a/cursors/Oxygen_Yellow/cursors/half-busy b/cursors/Oxygen_Yellow/cursors/half-busy new file mode 100644 index 00000000..05396742 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/half-busy differ diff --git a/cursors/Oxygen_Yellow/cursors/hand1 b/cursors/Oxygen_Yellow/cursors/hand1 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/hand1 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/hand2 b/cursors/Oxygen_Yellow/cursors/hand2 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/hand2 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/help b/cursors/Oxygen_Yellow/cursors/help new file mode 100644 index 00000000..1bba2fc4 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/help differ diff --git a/cursors/Oxygen_Yellow/cursors/ibeam b/cursors/Oxygen_Yellow/cursors/ibeam new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/ibeam @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/left_ptr b/cursors/Oxygen_Yellow/cursors/left_ptr new file mode 100644 index 00000000..33d6b6f2 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/left_ptr differ diff --git a/cursors/Oxygen_Yellow/cursors/left_ptr_watch b/cursors/Oxygen_Yellow/cursors/left_ptr_watch new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/left_ptr_watch @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/link b/cursors/Oxygen_Yellow/cursors/link new file mode 100644 index 00000000..ad47bcf5 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/link differ diff --git a/cursors/Oxygen_Yellow/cursors/move b/cursors/Oxygen_Yellow/cursors/move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/n-resize b/cursors/Oxygen_Yellow/cursors/n-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/n-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/not-allowed b/cursors/Oxygen_Yellow/cursors/not-allowed new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/not-allowed @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/openhand b/cursors/Oxygen_Yellow/cursors/openhand new file mode 100644 index 00000000..cb8b7412 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/openhand differ diff --git a/cursors/Oxygen_Yellow/cursors/pencil b/cursors/Oxygen_Yellow/cursors/pencil new file mode 100644 index 00000000..1bcdb79e Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/pencil differ diff --git a/cursors/Oxygen_Yellow/cursors/pirate b/cursors/Oxygen_Yellow/cursors/pirate new file mode 100644 index 00000000..20106c34 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/pirate differ diff --git a/cursors/Oxygen_Yellow/cursors/plus b/cursors/Oxygen_Yellow/cursors/plus new file mode 100644 index 00000000..40ea3cc5 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/plus differ diff --git a/cursors/Oxygen_Yellow/cursors/pointer b/cursors/Oxygen_Yellow/cursors/pointer new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/pointer @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/pointing_hand b/cursors/Oxygen_Yellow/cursors/pointing_hand new file mode 100644 index 00000000..3b02fdea Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/pointing_hand differ diff --git a/cursors/Oxygen_Yellow/cursors/progress b/cursors/Oxygen_Yellow/cursors/progress new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/progress @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/question_arrow b/cursors/Oxygen_Yellow/cursors/question_arrow new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/question_arrow @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/row-resize b/cursors/Oxygen_Yellow/cursors/row-resize new file mode 120000 index 00000000..e3aa7487 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/row-resize @@ -0,0 +1 @@ +split_h \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/s-resize b/cursors/Oxygen_Yellow/cursors/s-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/s-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/sb_h_double_arrow b/cursors/Oxygen_Yellow/cursors/sb_h_double_arrow new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/sb_h_double_arrow @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/sb_v_double_arrow b/cursors/Oxygen_Yellow/cursors/sb_v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/sb_v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/size_all b/cursors/Oxygen_Yellow/cursors/size_all new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/size_all @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/size_bdiag b/cursors/Oxygen_Yellow/cursors/size_bdiag new file mode 100644 index 00000000..2abf1eed Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/size_bdiag differ diff --git a/cursors/Oxygen_Yellow/cursors/size_fdiag b/cursors/Oxygen_Yellow/cursors/size_fdiag new file mode 100644 index 00000000..1d2b226c Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/size_fdiag differ diff --git a/cursors/Oxygen_Yellow/cursors/size_hor b/cursors/Oxygen_Yellow/cursors/size_hor new file mode 100644 index 00000000..d66cf3d7 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/size_hor differ diff --git a/cursors/Oxygen_Yellow/cursors/size_ver b/cursors/Oxygen_Yellow/cursors/size_ver new file mode 100644 index 00000000..6fe46785 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/size_ver differ diff --git a/cursors/Oxygen_Yellow/cursors/split_h b/cursors/Oxygen_Yellow/cursors/split_h new file mode 100644 index 00000000..468e56e3 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/split_h differ diff --git a/cursors/Oxygen_Yellow/cursors/split_v b/cursors/Oxygen_Yellow/cursors/split_v new file mode 100644 index 00000000..41927977 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/split_v differ diff --git a/cursors/Oxygen_Yellow/cursors/text b/cursors/Oxygen_Yellow/cursors/text new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/text @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/up_arrow b/cursors/Oxygen_Yellow/cursors/up_arrow new file mode 100644 index 00000000..ec3c3568 Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/up_arrow differ diff --git a/cursors/Oxygen_Yellow/cursors/v_double_arrow b/cursors/Oxygen_Yellow/cursors/v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/w-resize b/cursors/Oxygen_Yellow/cursors/w-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/w-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/wait b/cursors/Oxygen_Yellow/cursors/wait new file mode 100644 index 00000000..1895ed9c Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/wait differ diff --git a/cursors/Oxygen_Yellow/cursors/watch b/cursors/Oxygen_Yellow/cursors/watch new file mode 120000 index 00000000..fd80437a --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/watch @@ -0,0 +1 @@ +wait \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/whats_this b/cursors/Oxygen_Yellow/cursors/whats_this new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Yellow/cursors/whats_this @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Yellow/cursors/xterm b/cursors/Oxygen_Yellow/cursors/xterm new file mode 100644 index 00000000..4797b88d Binary files /dev/null and b/cursors/Oxygen_Yellow/cursors/xterm differ diff --git a/cursors/Oxygen_Yellow/index.theme b/cursors/Oxygen_Yellow/index.theme new file mode 100644 index 00000000..c0a16cd6 --- /dev/null +++ b/cursors/Oxygen_Yellow/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Yellow +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/Oxygen_Zion/cursors/00000000000000020006000e7e9ffc3f b/cursors/Oxygen_Zion/cursors/00000000000000020006000e7e9ffc3f new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/00000000000000020006000e7e9ffc3f @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/00008160000006810000408080010102 b/cursors/Oxygen_Zion/cursors/00008160000006810000408080010102 new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/00008160000006810000408080010102 @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/03b6e0fcb3499374a867c041f52298f0 b/cursors/Oxygen_Zion/cursors/03b6e0fcb3499374a867c041f52298f0 new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/03b6e0fcb3499374a867c041f52298f0 @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/08e8e1c95fe2fc01f976f1e063a24ccd b/cursors/Oxygen_Zion/cursors/08e8e1c95fe2fc01f976f1e063a24ccd new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/08e8e1c95fe2fc01f976f1e063a24ccd @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/1081e37283d90000800003c07f3ef6bf b/cursors/Oxygen_Zion/cursors/1081e37283d90000800003c07f3ef6bf new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/1081e37283d90000800003c07f3ef6bf @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/3085a0e285430894940527032f8b26df b/cursors/Oxygen_Zion/cursors/3085a0e285430894940527032f8b26df new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/3085a0e285430894940527032f8b26df @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/3ecb610c1bf2410f44200f48c40d3599 b/cursors/Oxygen_Zion/cursors/3ecb610c1bf2410f44200f48c40d3599 new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/3ecb610c1bf2410f44200f48c40d3599 @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/4498f0e0c1937ffe01fd06f973665830 b/cursors/Oxygen_Zion/cursors/4498f0e0c1937ffe01fd06f973665830 new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/4498f0e0c1937ffe01fd06f973665830 @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 b/cursors/Oxygen_Zion/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408 @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/6407b0e94181790501fd1e167b474872 b/cursors/Oxygen_Zion/cursors/6407b0e94181790501fd1e167b474872 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/6407b0e94181790501fd1e167b474872 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/640fb0e74195791501fd1ed57b41487f b/cursors/Oxygen_Zion/cursors/640fb0e74195791501fd1ed57b41487f new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/640fb0e74195791501fd1ed57b41487f @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/9081237383d90e509aa00f00170e968f b/cursors/Oxygen_Zion/cursors/9081237383d90e509aa00f00170e968f new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/9081237383d90e509aa00f00170e968f @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/9d800788f1b08800ae810202380a0822 b/cursors/Oxygen_Zion/cursors/9d800788f1b08800ae810202380a0822 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/9d800788f1b08800ae810202380a0822 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/X_cursor b/cursors/Oxygen_Zion/cursors/X_cursor new file mode 100644 index 00000000..ade77fa9 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/X_cursor differ diff --git a/cursors/Oxygen_Zion/cursors/a2a266d0498c3104214a47bd64ab0fc8 b/cursors/Oxygen_Zion/cursors/a2a266d0498c3104214a47bd64ab0fc8 new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/a2a266d0498c3104214a47bd64ab0fc8 @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/alias b/cursors/Oxygen_Zion/cursors/alias new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/alias @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/all-scroll b/cursors/Oxygen_Zion/cursors/all-scroll new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/all-scroll @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/b66166c04f8c3109214a4fbd64a50fc8 b/cursors/Oxygen_Zion/cursors/b66166c04f8c3109214a4fbd64a50fc8 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/b66166c04f8c3109214a4fbd64a50fc8 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/circle b/cursors/Oxygen_Zion/cursors/circle new file mode 100644 index 00000000..057ce294 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/circle differ diff --git a/cursors/Oxygen_Zion/cursors/closedhand b/cursors/Oxygen_Zion/cursors/closedhand new file mode 100644 index 00000000..147feaa3 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/closedhand differ diff --git a/cursors/Oxygen_Zion/cursors/col-resize b/cursors/Oxygen_Zion/cursors/col-resize new file mode 120000 index 00000000..179b52be --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/col-resize @@ -0,0 +1 @@ +split_v \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/color-picker b/cursors/Oxygen_Zion/cursors/color-picker new file mode 100644 index 00000000..5299eece Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/color-picker differ diff --git a/cursors/Oxygen_Zion/cursors/copy b/cursors/Oxygen_Zion/cursors/copy new file mode 100644 index 00000000..2ef4bffb Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/copy differ diff --git a/cursors/Oxygen_Zion/cursors/cross b/cursors/Oxygen_Zion/cursors/cross new file mode 100644 index 00000000..d59a9c3b Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/cross differ diff --git a/cursors/Oxygen_Zion/cursors/crossed_circle b/cursors/Oxygen_Zion/cursors/crossed_circle new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/crossed_circle @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/d9ce0ab605698f320427677b458ad60b b/cursors/Oxygen_Zion/cursors/d9ce0ab605698f320427677b458ad60b new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/d9ce0ab605698f320427677b458ad60b @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/dnd-copy b/cursors/Oxygen_Zion/cursors/dnd-copy new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/dnd-copy @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/dnd-link b/cursors/Oxygen_Zion/cursors/dnd-link new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/dnd-link @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/dnd-move b/cursors/Oxygen_Zion/cursors/dnd-move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/dnd-move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/dnd-no-drop b/cursors/Oxygen_Zion/cursors/dnd-no-drop new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/dnd-no-drop @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/dnd-none b/cursors/Oxygen_Zion/cursors/dnd-none new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/dnd-none @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/e-resize b/cursors/Oxygen_Zion/cursors/e-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/e-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/e29285e634086352946a0e7090d73106 b/cursors/Oxygen_Zion/cursors/e29285e634086352946a0e7090d73106 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/e29285e634086352946a0e7090d73106 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff b/cursors/Oxygen_Zion/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/fcf21c00b30f7e3f83fe0dfd12e71cff @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/fleur b/cursors/Oxygen_Zion/cursors/fleur new file mode 100644 index 00000000..7cec7472 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/fleur differ diff --git a/cursors/Oxygen_Zion/cursors/forbidden b/cursors/Oxygen_Zion/cursors/forbidden new file mode 100644 index 00000000..dceaf88e Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/forbidden differ diff --git a/cursors/Oxygen_Zion/cursors/half-busy b/cursors/Oxygen_Zion/cursors/half-busy new file mode 100644 index 00000000..bac0338a Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/half-busy differ diff --git a/cursors/Oxygen_Zion/cursors/hand1 b/cursors/Oxygen_Zion/cursors/hand1 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/hand1 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/hand2 b/cursors/Oxygen_Zion/cursors/hand2 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/hand2 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/help b/cursors/Oxygen_Zion/cursors/help new file mode 100644 index 00000000..3da67a2a Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/help differ diff --git a/cursors/Oxygen_Zion/cursors/ibeam b/cursors/Oxygen_Zion/cursors/ibeam new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/ibeam @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/left_ptr b/cursors/Oxygen_Zion/cursors/left_ptr new file mode 100644 index 00000000..e546bf79 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/left_ptr differ diff --git a/cursors/Oxygen_Zion/cursors/left_ptr_watch b/cursors/Oxygen_Zion/cursors/left_ptr_watch new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/left_ptr_watch @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/link b/cursors/Oxygen_Zion/cursors/link new file mode 100644 index 00000000..2c02a5a1 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/link differ diff --git a/cursors/Oxygen_Zion/cursors/move b/cursors/Oxygen_Zion/cursors/move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/n-resize b/cursors/Oxygen_Zion/cursors/n-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/n-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/not-allowed b/cursors/Oxygen_Zion/cursors/not-allowed new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/not-allowed @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/openhand b/cursors/Oxygen_Zion/cursors/openhand new file mode 100644 index 00000000..a8dfbeed Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/openhand differ diff --git a/cursors/Oxygen_Zion/cursors/pencil b/cursors/Oxygen_Zion/cursors/pencil new file mode 100644 index 00000000..6d555ab0 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/pencil differ diff --git a/cursors/Oxygen_Zion/cursors/pirate b/cursors/Oxygen_Zion/cursors/pirate new file mode 100644 index 00000000..d5d0c0e0 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/pirate differ diff --git a/cursors/Oxygen_Zion/cursors/plus b/cursors/Oxygen_Zion/cursors/plus new file mode 100644 index 00000000..323873d2 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/plus differ diff --git a/cursors/Oxygen_Zion/cursors/pointer b/cursors/Oxygen_Zion/cursors/pointer new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/pointer @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/pointing_hand b/cursors/Oxygen_Zion/cursors/pointing_hand new file mode 100644 index 00000000..47fb5b32 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/pointing_hand differ diff --git a/cursors/Oxygen_Zion/cursors/progress b/cursors/Oxygen_Zion/cursors/progress new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/progress @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/question_arrow b/cursors/Oxygen_Zion/cursors/question_arrow new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/question_arrow @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/row-resize b/cursors/Oxygen_Zion/cursors/row-resize new file mode 120000 index 00000000..e3aa7487 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/row-resize @@ -0,0 +1 @@ +split_h \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/s-resize b/cursors/Oxygen_Zion/cursors/s-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/s-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/sb_h_double_arrow b/cursors/Oxygen_Zion/cursors/sb_h_double_arrow new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/sb_h_double_arrow @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/sb_v_double_arrow b/cursors/Oxygen_Zion/cursors/sb_v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/sb_v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/size_all b/cursors/Oxygen_Zion/cursors/size_all new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/size_all @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/size_bdiag b/cursors/Oxygen_Zion/cursors/size_bdiag new file mode 100644 index 00000000..1cf8ac75 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/size_bdiag differ diff --git a/cursors/Oxygen_Zion/cursors/size_fdiag b/cursors/Oxygen_Zion/cursors/size_fdiag new file mode 100644 index 00000000..d4732f6d Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/size_fdiag differ diff --git a/cursors/Oxygen_Zion/cursors/size_hor b/cursors/Oxygen_Zion/cursors/size_hor new file mode 100644 index 00000000..388a9acd Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/size_hor differ diff --git a/cursors/Oxygen_Zion/cursors/size_ver b/cursors/Oxygen_Zion/cursors/size_ver new file mode 100644 index 00000000..92efa154 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/size_ver differ diff --git a/cursors/Oxygen_Zion/cursors/split_h b/cursors/Oxygen_Zion/cursors/split_h new file mode 100644 index 00000000..50a9fb7d Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/split_h differ diff --git a/cursors/Oxygen_Zion/cursors/split_v b/cursors/Oxygen_Zion/cursors/split_v new file mode 100644 index 00000000..e38085ce Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/split_v differ diff --git a/cursors/Oxygen_Zion/cursors/text b/cursors/Oxygen_Zion/cursors/text new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/text @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/up_arrow b/cursors/Oxygen_Zion/cursors/up_arrow new file mode 100644 index 00000000..ea3521c9 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/up_arrow differ diff --git a/cursors/Oxygen_Zion/cursors/v_double_arrow b/cursors/Oxygen_Zion/cursors/v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/w-resize b/cursors/Oxygen_Zion/cursors/w-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/w-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/wait b/cursors/Oxygen_Zion/cursors/wait new file mode 100644 index 00000000..6c17265a Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/wait differ diff --git a/cursors/Oxygen_Zion/cursors/watch b/cursors/Oxygen_Zion/cursors/watch new file mode 120000 index 00000000..fd80437a --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/watch @@ -0,0 +1 @@ +wait \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/whats_this b/cursors/Oxygen_Zion/cursors/whats_this new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/Oxygen_Zion/cursors/whats_this @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/Oxygen_Zion/cursors/xterm b/cursors/Oxygen_Zion/cursors/xterm new file mode 100644 index 00000000..739f9733 Binary files /dev/null and b/cursors/Oxygen_Zion/cursors/xterm differ diff --git a/cursors/Oxygen_Zion/index.theme b/cursors/Oxygen_Zion/index.theme new file mode 100644 index 00000000..241e15b1 --- /dev/null +++ b/cursors/Oxygen_Zion/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Zion +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/CMakeLists.txt b/cursors/src/CMakeLists.txt new file mode 100644 index 00000000..f701f985 --- /dev/null +++ b/cursors/src/CMakeLists.txt @@ -0,0 +1,49 @@ +include(cursors.cmake) +include(config.cmake) +include(setup.cmake) + +set(COLORS + black + blue + bluecurve + brown + cherry + chrome + desert + emerald + green + grey + honeycomb + hot_orange + lilac + midnight_meadow + navy + norway + obsidian + obsidian-hc + olympus + olympus-inv + orchid + oxygen + peach + purple + red + red-argentina + sea_blue + steel + terra + terra_green + violet + viorange + white + whitewater + wonton + yellow + zion + ) + +foreach(color ${COLORS}) + add_subdirectory(theme-${color}) + list(APPEND PACKAGES package-${color}) + message(STATUS "Added themes for ${color}") +endforeach(color) diff --git a/cursors/src/COPYING b/cursors/src/COPYING new file mode 100644 index 00000000..0cd37f5b --- /dev/null +++ b/cursors/src/COPYING @@ -0,0 +1,18 @@ +Copyright (C) 2007-2008 by Riccardo Iaconelli +Copyright (C) 2007-2008 by David Miller +Copyright (C) 2007-2008 by Matthew Woehlke + +This cursor theme and the associated scripts are free software: +you can redistribute them and/or modify them under the terms of +the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) +any later version. + +This cursor theme and the associated scripts are distributed in +the hope that they 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, see . diff --git a/cursors/src/LICENSE b/cursors/src/LICENSE new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/cursors/src/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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. But first, please read +. diff --git a/cursors/src/README b/cursors/src/README new file mode 100644 index 00000000..f1638748 --- /dev/null +++ b/cursors/src/README @@ -0,0 +1,17 @@ +How to generate all the pngs and the SVGs and the cursor files: + +mkdir build +cd build +cmake ../src +make [-j ] [theme-|package-] + +Where is the number of jobs to run in parallel (man make), and is the color you want generated if you want just one of them. + +The build system is still young, with rough edges (e.g. doesn't check if inkscape is found). Hopefully it will work, +but there may still be problems. + +All of what you see here is to be considered a work in progress, and therefore must be considered as unreleased. + +Information on the graphics: Riccardo "ruphy" Iaconelli +Information on the build system: Matthew Woehlke and Diego 'Flameeyes' Pettenò. +Preferred place to get help: #oxygen on irc.freenode.net (http://freenode.net/) diff --git a/cursors/src/TODO b/cursors/src/TODO new file mode 100644 index 00000000..3472fe7a --- /dev/null +++ b/cursors/src/TODO @@ -0,0 +1 @@ +* fix hotspot for clock diff --git a/cursors/src/config.cmake b/cursors/src/config.cmake new file mode 100644 index 00000000..dfadfe75 --- /dev/null +++ b/cursors/src/config.cmake @@ -0,0 +1,8 @@ +file(GLOB SVGS svg/*.svg) +file(GLOB CONFIGS config/*.in) +file(GLOB SYMLINKS_PATHS symlinks/*) + +set(SVGDIR ${CMAKE_SOURCE_DIR}/svg) +set(CONFIGDIR ${CMAKE_SOURCE_DIR}/config) +set(MAKE_CONFIG ${CMAKE_SOURCE_DIR}/make_config.cmake) +set(MAKE_SVG ${CMAKE_SOURCE_DIR}/make_svg.cmake) diff --git a/cursors/src/config/Description b/cursors/src/config/Description new file mode 100644 index 00000000..84be4aab --- /dev/null +++ b/cursors/src/config/Description @@ -0,0 +1,5 @@ +== Namespec Description == + +WriteMe! + + diff --git a/cursors/src/config/X_cursor.in b/cursors/src/config/X_cursor.in new file mode 100644 index 00000000..04f86c3d --- /dev/null +++ b/cursors/src/config/X_cursor.in @@ -0,0 +1 @@ +24 12 12 x.png diff --git a/cursors/src/config/circle.in b/cursors/src/config/circle.in new file mode 100644 index 00000000..3d69e87e --- /dev/null +++ b/cursors/src/config/circle.in @@ -0,0 +1 @@ +24 12 12 circle.png diff --git a/cursors/src/config/closedhand.in b/cursors/src/config/closedhand.in new file mode 100644 index 00000000..cf73de12 --- /dev/null +++ b/cursors/src/config/closedhand.in @@ -0,0 +1 @@ +24 12 11 grab.png diff --git a/cursors/src/config/color-picker.in b/cursors/src/config/color-picker.in new file mode 100644 index 00000000..cdfe33b9 --- /dev/null +++ b/cursors/src/config/color-picker.in @@ -0,0 +1 @@ +24 2 20 picker.png diff --git a/cursors/src/config/copy.in b/cursors/src/config/copy.in new file mode 100644 index 00000000..ee8d91a0 --- /dev/null +++ b/cursors/src/config/copy.in @@ -0,0 +1 @@ +24 0 0 copy.png diff --git a/cursors/src/config/cross.in b/cursors/src/config/cross.in new file mode 100644 index 00000000..545353cf --- /dev/null +++ b/cursors/src/config/cross.in @@ -0,0 +1 @@ +24 7 7 cross.png diff --git a/cursors/src/config/fleur.in b/cursors/src/config/fleur.in new file mode 100644 index 00000000..470d84eb --- /dev/null +++ b/cursors/src/config/fleur.in @@ -0,0 +1 @@ +32 16 15 fleur.png diff --git a/cursors/src/config/forbidden.in b/cursors/src/config/forbidden.in new file mode 100644 index 00000000..1e7cf6b5 --- /dev/null +++ b/cursors/src/config/forbidden.in @@ -0,0 +1 @@ +24 0 0 forbidden.png diff --git a/cursors/src/config/half-busy.in b/cursors/src/config/half-busy.in new file mode 100644 index 00000000..97c8476b --- /dev/null +++ b/cursors/src/config/half-busy.in @@ -0,0 +1,18 @@ +32 0 0 half-busy17.png 40 +32 0 0 half-busy16.png 40 +32 0 0 half-busy15.png 40 +32 0 0 half-busy14.png 40 +32 0 0 half-busy13.png 40 +32 0 0 half-busy12.png 40 +32 0 0 half-busy11.png 40 +32 0 0 half-busy10.png 40 +32 0 0 half-busy9.png 40 +32 0 0 half-busy8.png 40 +32 0 0 half-busy7.png 40 +32 0 0 half-busy6.png 40 +32 0 0 half-busy5.png 40 +32 0 0 half-busy4.png 40 +32 0 0 half-busy3.png 40 +32 0 0 half-busy2.png 40 +32 0 0 half-busy1.png 40 +32 0 0 half-busy.png 40 \ No newline at end of file diff --git a/cursors/src/config/help.in b/cursors/src/config/help.in new file mode 100644 index 00000000..50dbbaf6 --- /dev/null +++ b/cursors/src/config/help.in @@ -0,0 +1 @@ +24 0 0 help.png diff --git a/cursors/src/config/left_ptr.in b/cursors/src/config/left_ptr.in new file mode 100644 index 00000000..f38772f2 --- /dev/null +++ b/cursors/src/config/left_ptr.in @@ -0,0 +1 @@ +24 5 0 left_ptr.png diff --git a/cursors/src/config/link.in b/cursors/src/config/link.in new file mode 100644 index 00000000..68d8bebb --- /dev/null +++ b/cursors/src/config/link.in @@ -0,0 +1 @@ +24 0 0 link.png diff --git a/cursors/src/config/openhand.in b/cursors/src/config/openhand.in new file mode 100644 index 00000000..561f8247 --- /dev/null +++ b/cursors/src/config/openhand.in @@ -0,0 +1 @@ +24 12 11 grab_open.png diff --git a/cursors/src/config/pencil.in b/cursors/src/config/pencil.in new file mode 100644 index 00000000..cf73a68b --- /dev/null +++ b/cursors/src/config/pencil.in @@ -0,0 +1 @@ +24 3 20 pencil.png diff --git a/cursors/src/config/pirate.in b/cursors/src/config/pirate.in new file mode 100644 index 00000000..dff24cdd --- /dev/null +++ b/cursors/src/config/pirate.in @@ -0,0 +1 @@ +24 12 12 kill.png diff --git a/cursors/src/config/plus.in b/cursors/src/config/plus.in new file mode 100644 index 00000000..177737af --- /dev/null +++ b/cursors/src/config/plus.in @@ -0,0 +1 @@ +24 12 12 plus.png diff --git a/cursors/src/config/pointing_hand.in b/cursors/src/config/pointing_hand.in new file mode 100644 index 00000000..e9f3bce1 --- /dev/null +++ b/cursors/src/config/pointing_hand.in @@ -0,0 +1 @@ +24 9 1 hand.png diff --git a/cursors/src/config/size_bdiag.in b/cursors/src/config/size_bdiag.in new file mode 100644 index 00000000..0c2de7b1 --- /dev/null +++ b/cursors/src/config/size_bdiag.in @@ -0,0 +1 @@ +24 11 11 size_diag-tr2bl.png diff --git a/cursors/src/config/size_fdiag.in b/cursors/src/config/size_fdiag.in new file mode 100644 index 00000000..70ec1457 --- /dev/null +++ b/cursors/src/config/size_fdiag.in @@ -0,0 +1 @@ +24 11 11 size_diag-tl2br.png diff --git a/cursors/src/config/size_hor.in b/cursors/src/config/size_hor.in new file mode 100644 index 00000000..e3640ac5 --- /dev/null +++ b/cursors/src/config/size_hor.in @@ -0,0 +1 @@ +24 11 11 size_hor.png diff --git a/cursors/src/config/size_ver.in b/cursors/src/config/size_ver.in new file mode 100644 index 00000000..1277ad78 --- /dev/null +++ b/cursors/src/config/size_ver.in @@ -0,0 +1 @@ +24 11 11 size_ver.png diff --git a/cursors/src/config/split_h.in b/cursors/src/config/split_h.in new file mode 100644 index 00000000..b551623b --- /dev/null +++ b/cursors/src/config/split_h.in @@ -0,0 +1 @@ +24 11 11 split_h.png diff --git a/cursors/src/config/split_v.in b/cursors/src/config/split_v.in new file mode 100644 index 00000000..70edff01 --- /dev/null +++ b/cursors/src/config/split_v.in @@ -0,0 +1 @@ +24 11 11 split_v.png diff --git a/cursors/src/config/up_arrow.in b/cursors/src/config/up_arrow.in new file mode 100644 index 00000000..11d4efbb --- /dev/null +++ b/cursors/src/config/up_arrow.in @@ -0,0 +1 @@ +24 12 0 up_arrow.png diff --git a/cursors/src/config/wait.in b/cursors/src/config/wait.in new file mode 100644 index 00000000..bf83b522 --- /dev/null +++ b/cursors/src/config/wait.in @@ -0,0 +1,18 @@ +32 16 16 busy17.png 40 +32 16 16 busy16.png 40 +32 16 16 busy15.png 40 +32 16 16 busy14.png 40 +32 16 16 busy13.png 40 +32 16 16 busy12.png 40 +32 16 16 busy11.png 40 +32 16 16 busy10.png 40 +32 16 16 busy9.png 40 +32 16 16 busy8.png 40 +32 16 16 busy7.png 40 +32 16 16 busy6.png 40 +32 16 16 busy5.png 40 +32 16 16 busy4.png 40 +32 16 16 busy3.png 40 +32 16 16 busy2.png 40 +32 16 16 busy1.png 40 +32 16 16 busy.png 40 \ No newline at end of file diff --git a/cursors/src/config/xterm.in b/cursors/src/config/xterm.in new file mode 100644 index 00000000..c5f341dd --- /dev/null +++ b/cursors/src/config/xterm.in @@ -0,0 +1 @@ +24 4 9 xterm.png diff --git a/cursors/src/cursors.cmake b/cursors/src/cursors.cmake new file mode 100644 index 00000000..19f6bb58 --- /dev/null +++ b/cursors/src/cursors.cmake @@ -0,0 +1,120 @@ +# This macro produces a "themed" version of the SVG, using the spcified colors. +# Than, it renders this themed SVG to PNG files. +# You can specify one or more dpi values when you call this macro. +macro(add_cursor cursor color theme dpi) + # Produce a "themed" SVG + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/oxy-${theme}/svg/${cursor}.svg + DEPENDS ${MAKE_SVG} ${CMAKE_CURRENT_SOURCE_DIR}/colors.in ${SVGDIR}/${cursor}.svg + COMMAND ${CMAKE_COMMAND} -Dconfig=${CMAKE_CURRENT_SOURCE_DIR}/colors.in + -Dinput=${SVGDIR}/${cursor}.svg + -Doutput=${CMAKE_BINARY_DIR}/oxy-${theme}/svg/${cursor}.svg + -P ${MAKE_SVG} + ) + # Prepare a list of resolutions in dpi + set(resolutions ${ARGV}) + list(REMOVE_AT resolutions 0) + list(REMOVE_AT resolutions 0) + list(REMOVE_AT resolutions 0) + # Render the SVG + foreach(resolution ${resolutions}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/oxy-${theme}/png/${resolution}/${cursor}.png + DEPENDS ${CMAKE_BINARY_DIR}/oxy-${theme}/svg/${cursor}.svg + COMMAND ${INKSCAPE} --without-gui --export-dpi=${resolution} + --export-png=${CMAKE_BINARY_DIR}/oxy-${theme}/png/${resolution}/${cursor}.png + ${CMAKE_BINARY_DIR}/oxy-${theme}/svg/${cursor}.svg + ) + endforeach(resolution) +endmacro(add_cursor) + +macro(add_x_cursor theme cursor dpi) + # Prepare a list of resolutions in dpi + set(resolutions ${ARGV}) + list(REMOVE_AT resolutions 0) + list(REMOVE_AT resolutions 0) + # Prepare a list of the png files that are necessary + set(inputs) + foreach(png ${${cursor}_inputs}) + foreach(resolution ${resolutions}) + list(APPEND inputs ${CMAKE_BINARY_DIR}/oxy-${theme}/png/${resolution}/${png}) + endforeach(resolution) + endforeach(png) + # Make a coma-separated list (normal lists can't be passed as argument) + string(REPLACE ";" "," resolutions_coma_separated "${resolutions}") + # Adopt the x cursor config file to the requested resolutions + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/oxy-${theme}/config/${cursor}.in + DEPENDS ${MAKE_CONFIG} ${CONFIGDIR}/${cursor}.in + COMMAND ${CMAKE_COMMAND} -Dconfig=${CONFIGDIR}/${cursor}.in + -Doutput=${CMAKE_BINARY_DIR}/oxy-${theme}/config/${cursor}.in + -Dresolutions=${resolutions_coma_separated} + -P ${MAKE_CONFIG} + ) + # Use the adopted x cursor config file and the png files to produce the cursor file + if(NOT WIN32) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/oxy-${theme}/cursors/${cursor} + DEPENDS ${inputs} ${CMAKE_BINARY_DIR}/oxy-${theme}/config/${cursor}.in + COMMAND ${XCURSORGEN} -p ${CMAKE_BINARY_DIR}/oxy-${theme}/png + ${CMAKE_BINARY_DIR}/oxy-${theme}/config/${cursor}.in + ${CMAKE_BINARY_DIR}/oxy-${theme}/cursors/${cursor} + ) + else(NOT WIN32) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/oxy-${theme}/cursors/${cursor} + DEPENDS ${inputs} ${CMAKE_BINARY_DIR}/oxy-${theme}/config/${cursor}.in + COMMAND "${CMAKE_SOURCE_DIR}/wincursor.py" ${CMAKE_BINARY_DIR}/oxy-${theme}/png + ${CMAKE_BINARY_DIR}/oxy-${theme}/config/${cursor}.in + ${CMAKE_BINARY_DIR}/wincursors/oxy-${theme} + ${CMAKE_BINARY_DIR}/oxy-${theme}/cursors/${cursor} + ) + endif(NOT WIN32) +endmacro(add_x_cursor) + +file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/packages) + +# Macro that adds a theme. You can specify more than one dpi value (overloaded macro). +macro(add_theme color theme dpi) + # Prepare a list of resolutions in dpi + set(resolutions ${ARGV}) + list(REMOVE_AT resolutions 0) + list(REMOVE_AT resolutions 0) + # Make missing directories + foreach (resolution ${resolutions}) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/oxy-${theme}/png/${resolution}) + endforeach(resolution) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/oxy-${theme}/svg) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/oxy-${theme}/config) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/oxy-${theme}/cursors) + if(WIN32) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/wincursors/oxy-${theme}) + endif(WIN32) + set(${theme}_cursors) + # render SVG to PNG files + foreach(svg ${SVGS}) + string(REGEX REPLACE ".*/" "" cursor ${svg}) # use relative paths + string(REGEX REPLACE "[.]svg" "" cursor ${cursor}) # remove ".svg" from the path + add_cursor(${cursor} ${color} ${theme} ${resolutions}) # Render a "themed" version of the SVG to PNG files. + endforeach(svg) + # produce cursor files from the png files + foreach(cursor ${CURSORS}) + add_x_cursor(${theme} ${cursor} ${resolutions}) + list(APPEND ${theme}_cursors ${CMAKE_BINARY_DIR}/oxy-${theme}/cursors/${cursor}) + endforeach(cursor) + # add the symbolic links + foreach(symlink ${SYMLINKS_PATHS}) + file(COPY ${symlink} DESTINATION ${CMAKE_BINARY_DIR}/oxy-${theme}/cursors) + endforeach(symlink) + # packaging + add_custom_target(theme-${theme} ALL DEPENDS ${${theme}_cursors}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/oxy-${theme}/index.theme + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/index.theme + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/index.theme + ${CMAKE_BINARY_DIR}/oxy-${theme}/index.theme + ) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/packages/oxy-${theme}.tar.bz2 + DEPENDS ${${theme}_cursors} ${CMAKE_BINARY_DIR}/oxy-${theme}/index.theme + COMMAND ${TAR} cjf ${CMAKE_BINARY_DIR}/packages/oxy-${theme}.tar.bz2 + oxy-${theme}/cursors + oxy-${theme}/index.theme + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + add_custom_target(package-${theme} ALL DEPENDS ${CMAKE_BINARY_DIR}/packages/oxy-${theme}.tar.bz2) +endmacro(add_theme) diff --git a/cursors/src/make_config.cmake b/cursors/src/make_config.cmake new file mode 100644 index 00000000..b9f6132a --- /dev/null +++ b/cursors/src/make_config.cmake @@ -0,0 +1,33 @@ +macro(adjust in_size in_xhot in_yhot) + #math(EXPR out_size "( ${in_size} * ${resolution} ) / 90") + # The Oxygen cursors have different default sizes at 90 dpi: + # Some have 24x24 px, others have 32x32 px. This causes some + # side-effects when you want to choose your cursor size. + # Instead of the real in_size, we use 24 as convenience value. + # Xcursorlib interpretats this as a _nominal_ size; it is legal + # that the nominal size is different from the real size of the + # png image. + math(EXPR out_size "( 24 * ${resolution} ) / 90") + math(EXPR out_xhot "( ${in_xhot} * ${resolution} ) / 90") + math(EXPR out_yhot "( ${in_yhot} * ${resolution} ) / 90") + set(out_line "${out_size} ${out_xhot} ${out_yhot} ${resolution}/${ARGN}") + string(REPLACE ";" " " out_line "${out_line}") + list(APPEND out_contents "${out_line}") +endmacro(adjust) + +# load config file +file(READ "${config}" in_contents) +set(out_contents) +string(REPLACE "\n" ";" in_contents "${in_contents}") +# convert the coma separated list in a standard list +string(REPLACE "," ";" resolutions ${resolutions}) +# adjust the config file +foreach(resolution ${resolutions}) + foreach(in_line ${in_contents}) + string(REGEX REPLACE "[ \t]+" ";" in_line "${in_line}") + adjust(${in_line}) + endforeach(in_line) +endforeach(resolution) +# save the adjusted config file +string(REPLACE ";" "\n" out_contents "${out_contents}") +file(WRITE "${output}" "${out_contents}\n") diff --git a/cursors/src/make_svg.cmake b/cursors/src/make_svg.cmake new file mode 100644 index 00000000..7aa192c2 --- /dev/null +++ b/cursors/src/make_svg.cmake @@ -0,0 +1,20 @@ +include(${config}) + +if(NOT altLighterColor) + set(altLighterColor ${lighterColor}) +endif(NOT altLighterColor) +if(NOT altMediumColor) + set(altMediumColor ${mediumColor}) +endif(NOT altMediumColor) +if(NOT altDarkerColor) + set(altDarkerColor ${darkerColor}) +endif(NOT altDarkerColor) + +file(READ "${input}" contents) +string(REPLACE "#ff80ff;" "${lighterColor};" contents "${contents}") +string(REPLACE "#804080;" "${mediumColor};" contents "${contents}") +string(REPLACE "#201020;" "${darkerColor};" contents "${contents}") +string(REPLACE "#c080ff;" "${altLighterColor};" contents "${contents}") +string(REPLACE "#604080;" "${altMediumColor};" contents "${contents}") +string(REPLACE "#181020;" "${altDarkerColor};" contents "${contents}") +file(WRITE "${output}" "${contents}") diff --git a/cursors/src/setup.cmake b/cursors/src/setup.cmake new file mode 100644 index 00000000..aedb7772 --- /dev/null +++ b/cursors/src/setup.cmake @@ -0,0 +1,32 @@ +find_program(TAR tar) +# TODO abort if tar not found (or does not understand cjf?) +if(NOT WIN32) +find_program(INKSCAPE inkscape) +# TODO abort if inkscape not found + +find_program(XCURSORGEN xcursorgen) +# TODO abort if xcursorgen not found +else(NOT WIN32) +find_program(INKSCAPE inkscape "$ENV{PROGRAMFILES}/Inkscape" "$ENV{INKSCAPE_DIR}") +endif(NOT WIN32) + +# For a given cursor, this macro defines a variable ${cursor}_inputs that contains +# a list of the necessary png files. +macro(set_dependencies cursor) + file(READ ${CONFIGDIR}/${cursor}.in config_contents) + string(REPLACE "\n" ";" config_contents ${config_contents}) + set(${cursor}_inputs) + foreach(png ${config_contents}) + string(REGEX REPLACE "[0-9]* [0-9]* [0-9]* " "" png ${png}) + string(REGEX REPLACE "[.]png [0-9]*$" ".png" png ${png}) + list(APPEND ${cursor}_inputs ${png}) + endforeach(png) +endmacro(set_dependencies) + +set(CURSORS) +foreach(config ${CONFIGS}) + string(REGEX REPLACE ".*/" "" cursor ${config}) + string(REGEX REPLACE "[.]in" "" cursor ${cursor}) + list(APPEND CURSORS ${cursor}) + set_dependencies(${cursor}) +endforeach(config) \ No newline at end of file diff --git a/cursors/src/svg/busy.svg b/cursors/src/svg/busy.svg new file mode 100644 index 00000000..5348f4fc --- /dev/null +++ b/cursors/src/svg/busy.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy1.svg b/cursors/src/svg/busy1.svg new file mode 100644 index 00000000..a00f18ca --- /dev/null +++ b/cursors/src/svg/busy1.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy10.svg b/cursors/src/svg/busy10.svg new file mode 100644 index 00000000..9b7c2a0b --- /dev/null +++ b/cursors/src/svg/busy10.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy11.svg b/cursors/src/svg/busy11.svg new file mode 100644 index 00000000..42a3c0b9 --- /dev/null +++ b/cursors/src/svg/busy11.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy12.svg b/cursors/src/svg/busy12.svg new file mode 100644 index 00000000..c4b1108f --- /dev/null +++ b/cursors/src/svg/busy12.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy13.svg b/cursors/src/svg/busy13.svg new file mode 100644 index 00000000..2c18a098 --- /dev/null +++ b/cursors/src/svg/busy13.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy14.svg b/cursors/src/svg/busy14.svg new file mode 100644 index 00000000..f0255095 --- /dev/null +++ b/cursors/src/svg/busy14.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy15.svg b/cursors/src/svg/busy15.svg new file mode 100644 index 00000000..e712da9d --- /dev/null +++ b/cursors/src/svg/busy15.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy16.svg b/cursors/src/svg/busy16.svg new file mode 100644 index 00000000..c7465c6d --- /dev/null +++ b/cursors/src/svg/busy16.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy17.svg b/cursors/src/svg/busy17.svg new file mode 100644 index 00000000..045c554a --- /dev/null +++ b/cursors/src/svg/busy17.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy2.svg b/cursors/src/svg/busy2.svg new file mode 100644 index 00000000..5257eb01 --- /dev/null +++ b/cursors/src/svg/busy2.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy3.svg b/cursors/src/svg/busy3.svg new file mode 100644 index 00000000..c4e4ec60 --- /dev/null +++ b/cursors/src/svg/busy3.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy4.svg b/cursors/src/svg/busy4.svg new file mode 100644 index 00000000..76e87c4a --- /dev/null +++ b/cursors/src/svg/busy4.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy5.svg b/cursors/src/svg/busy5.svg new file mode 100644 index 00000000..7fea7b17 --- /dev/null +++ b/cursors/src/svg/busy5.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy6.svg b/cursors/src/svg/busy6.svg new file mode 100644 index 00000000..fbcc072b --- /dev/null +++ b/cursors/src/svg/busy6.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy7.svg b/cursors/src/svg/busy7.svg new file mode 100644 index 00000000..87dcb5b4 --- /dev/null +++ b/cursors/src/svg/busy7.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy8.svg b/cursors/src/svg/busy8.svg new file mode 100644 index 00000000..573acd94 --- /dev/null +++ b/cursors/src/svg/busy8.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/busy9.svg b/cursors/src/svg/busy9.svg new file mode 100644 index 00000000..6e58ac34 --- /dev/null +++ b/cursors/src/svg/busy9.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cursors/src/svg/circle.svg b/cursors/src/svg/circle.svg new file mode 100644 index 00000000..67c0b4d9 --- /dev/null +++ b/cursors/src/svg/circle.svg @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/copy.svg b/cursors/src/svg/copy.svg new file mode 100644 index 00000000..eaf56371 --- /dev/null +++ b/cursors/src/svg/copy.svg @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/cross.svg b/cursors/src/svg/cross.svg new file mode 100644 index 00000000..c927f3ff --- /dev/null +++ b/cursors/src/svg/cross.svg @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/cursors/src/svg/dnd-move.svg b/cursors/src/svg/dnd-move.svg new file mode 100644 index 00000000..916dffd9 --- /dev/null +++ b/cursors/src/svg/dnd-move.svg @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/cursors/src/svg/fleur.svg b/cursors/src/svg/fleur.svg new file mode 100644 index 00000000..3b25aada --- /dev/null +++ b/cursors/src/svg/fleur.svg @@ -0,0 +1,393 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/forbidden.svg b/cursors/src/svg/forbidden.svg new file mode 100644 index 00000000..63fc5a35 --- /dev/null +++ b/cursors/src/svg/forbidden.svg @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/grab.svg b/cursors/src/svg/grab.svg new file mode 100644 index 00000000..1a97be9b --- /dev/null +++ b/cursors/src/svg/grab.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/grab_open.svg b/cursors/src/svg/grab_open.svg new file mode 100644 index 00000000..b8b1cdf0 --- /dev/null +++ b/cursors/src/svg/grab_open.svg @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy.svg b/cursors/src/svg/half-busy.svg new file mode 100644 index 00000000..d27601c2 --- /dev/null +++ b/cursors/src/svg/half-busy.svg @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy1.svg b/cursors/src/svg/half-busy1.svg new file mode 100644 index 00000000..0cc73e8c --- /dev/null +++ b/cursors/src/svg/half-busy1.svg @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy10.svg b/cursors/src/svg/half-busy10.svg new file mode 100644 index 00000000..4140457f --- /dev/null +++ b/cursors/src/svg/half-busy10.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy11.svg b/cursors/src/svg/half-busy11.svg new file mode 100644 index 00000000..f8883fe6 --- /dev/null +++ b/cursors/src/svg/half-busy11.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy12.svg b/cursors/src/svg/half-busy12.svg new file mode 100644 index 00000000..d0c2acf6 --- /dev/null +++ b/cursors/src/svg/half-busy12.svg @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy13.svg b/cursors/src/svg/half-busy13.svg new file mode 100644 index 00000000..b3f5a556 --- /dev/null +++ b/cursors/src/svg/half-busy13.svg @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy14.svg b/cursors/src/svg/half-busy14.svg new file mode 100644 index 00000000..e5530a62 --- /dev/null +++ b/cursors/src/svg/half-busy14.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy15.svg b/cursors/src/svg/half-busy15.svg new file mode 100644 index 00000000..f33a7c9b --- /dev/null +++ b/cursors/src/svg/half-busy15.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy16.svg b/cursors/src/svg/half-busy16.svg new file mode 100644 index 00000000..5266f2a1 --- /dev/null +++ b/cursors/src/svg/half-busy16.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy17.svg b/cursors/src/svg/half-busy17.svg new file mode 100644 index 00000000..42d4f228 --- /dev/null +++ b/cursors/src/svg/half-busy17.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy2.svg b/cursors/src/svg/half-busy2.svg new file mode 100644 index 00000000..a624f925 --- /dev/null +++ b/cursors/src/svg/half-busy2.svg @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy3.svg b/cursors/src/svg/half-busy3.svg new file mode 100644 index 00000000..abb5af86 --- /dev/null +++ b/cursors/src/svg/half-busy3.svg @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy4.svg b/cursors/src/svg/half-busy4.svg new file mode 100644 index 00000000..2f4311a9 --- /dev/null +++ b/cursors/src/svg/half-busy4.svg @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy5.svg b/cursors/src/svg/half-busy5.svg new file mode 100644 index 00000000..2cc12b94 --- /dev/null +++ b/cursors/src/svg/half-busy5.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy6.svg b/cursors/src/svg/half-busy6.svg new file mode 100644 index 00000000..e711c940 --- /dev/null +++ b/cursors/src/svg/half-busy6.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy7.svg b/cursors/src/svg/half-busy7.svg new file mode 100644 index 00000000..fd495239 --- /dev/null +++ b/cursors/src/svg/half-busy7.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy8.svg b/cursors/src/svg/half-busy8.svg new file mode 100644 index 00000000..63b21ac8 --- /dev/null +++ b/cursors/src/svg/half-busy8.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/half-busy9.svg b/cursors/src/svg/half-busy9.svg new file mode 100644 index 00000000..bdd7fbf9 --- /dev/null +++ b/cursors/src/svg/half-busy9.svg @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/hand.svg b/cursors/src/svg/hand.svg new file mode 100644 index 00000000..0ae210dd --- /dev/null +++ b/cursors/src/svg/hand.svg @@ -0,0 +1,516 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/help.svg b/cursors/src/svg/help.svg new file mode 100644 index 00000000..3566f4ef --- /dev/null +++ b/cursors/src/svg/help.svg @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/kill.svg b/cursors/src/svg/kill.svg new file mode 100644 index 00000000..8fcc071c --- /dev/null +++ b/cursors/src/svg/kill.svg @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/left_ptr.svg b/cursors/src/svg/left_ptr.svg new file mode 100644 index 00000000..de8c93bf --- /dev/null +++ b/cursors/src/svg/left_ptr.svg @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/cursors/src/svg/link.svg b/cursors/src/svg/link.svg new file mode 100644 index 00000000..d1fba913 --- /dev/null +++ b/cursors/src/svg/link.svg @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/pencil.svg b/cursors/src/svg/pencil.svg new file mode 100644 index 00000000..d3a152e2 --- /dev/null +++ b/cursors/src/svg/pencil.svg @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/picker.svg b/cursors/src/svg/picker.svg new file mode 100644 index 00000000..898be9b6 --- /dev/null +++ b/cursors/src/svg/picker.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/plus.svg b/cursors/src/svg/plus.svg new file mode 100644 index 00000000..2bdf5384 --- /dev/null +++ b/cursors/src/svg/plus.svg @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/cursors/src/svg/size_diag-tl2br.svg b/cursors/src/svg/size_diag-tl2br.svg new file mode 100644 index 00000000..3be88d69 --- /dev/null +++ b/cursors/src/svg/size_diag-tl2br.svg @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/size_diag-tr2bl.svg b/cursors/src/svg/size_diag-tr2bl.svg new file mode 100644 index 00000000..08a16650 --- /dev/null +++ b/cursors/src/svg/size_diag-tr2bl.svg @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/size_hor.svg b/cursors/src/svg/size_hor.svg new file mode 100644 index 00000000..9ce3e800 --- /dev/null +++ b/cursors/src/svg/size_hor.svg @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/size_ver.svg b/cursors/src/svg/size_ver.svg new file mode 100644 index 00000000..9d4055c0 --- /dev/null +++ b/cursors/src/svg/size_ver.svg @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/split_h.svg b/cursors/src/svg/split_h.svg new file mode 100644 index 00000000..64034bc4 --- /dev/null +++ b/cursors/src/svg/split_h.svg @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/split_v.svg b/cursors/src/svg/split_v.svg new file mode 100644 index 00000000..e33dfd3e --- /dev/null +++ b/cursors/src/svg/split_v.svg @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/up_arrow.svg b/cursors/src/svg/up_arrow.svg new file mode 100644 index 00000000..f1e3946a --- /dev/null +++ b/cursors/src/svg/up_arrow.svg @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/x.svg b/cursors/src/svg/x.svg new file mode 100644 index 00000000..81c1b0c8 --- /dev/null +++ b/cursors/src/svg/x.svg @@ -0,0 +1,1130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cursors/src/svg/xterm.svg b/cursors/src/svg/xterm.svg new file mode 100644 index 00000000..321a94f3 --- /dev/null +++ b/cursors/src/svg/xterm.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/cursors/src/symlinks/.directory b/cursors/src/symlinks/.directory new file mode 100644 index 00000000..9fea84a3 --- /dev/null +++ b/cursors/src/symlinks/.directory @@ -0,0 +1,5 @@ +[Dolphin] +AdditionalInfoV2=Details_Size,Details_Date,CustomizedDetails +Timestamp=2011,9,4,15,13,34 +Version=2 +ViewMode=1 diff --git a/cursors/src/symlinks/00000000000000020006000e7e9ffc3f b/cursors/src/symlinks/00000000000000020006000e7e9ffc3f new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/src/symlinks/00000000000000020006000e7e9ffc3f @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/src/symlinks/00008160000006810000408080010102 b/cursors/src/symlinks/00008160000006810000408080010102 new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/src/symlinks/00008160000006810000408080010102 @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/src/symlinks/03b6e0fcb3499374a867c041f52298f0 b/cursors/src/symlinks/03b6e0fcb3499374a867c041f52298f0 new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/src/symlinks/03b6e0fcb3499374a867c041f52298f0 @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/src/symlinks/08e8e1c95fe2fc01f976f1e063a24ccd b/cursors/src/symlinks/08e8e1c95fe2fc01f976f1e063a24ccd new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/src/symlinks/08e8e1c95fe2fc01f976f1e063a24ccd @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/src/symlinks/1081e37283d90000800003c07f3ef6bf b/cursors/src/symlinks/1081e37283d90000800003c07f3ef6bf new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/src/symlinks/1081e37283d90000800003c07f3ef6bf @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/src/symlinks/3085a0e285430894940527032f8b26df b/cursors/src/symlinks/3085a0e285430894940527032f8b26df new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/src/symlinks/3085a0e285430894940527032f8b26df @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/src/symlinks/3ecb610c1bf2410f44200f48c40d3599 b/cursors/src/symlinks/3ecb610c1bf2410f44200f48c40d3599 new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/src/symlinks/3ecb610c1bf2410f44200f48c40d3599 @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/src/symlinks/4498f0e0c1937ffe01fd06f973665830 b/cursors/src/symlinks/4498f0e0c1937ffe01fd06f973665830 new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/src/symlinks/4498f0e0c1937ffe01fd06f973665830 @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/src/symlinks/5c6cd98b3f3ebcb1f9c7f1c204630408 b/cursors/src/symlinks/5c6cd98b3f3ebcb1f9c7f1c204630408 new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/src/symlinks/5c6cd98b3f3ebcb1f9c7f1c204630408 @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/src/symlinks/6407b0e94181790501fd1e167b474872 b/cursors/src/symlinks/6407b0e94181790501fd1e167b474872 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/src/symlinks/6407b0e94181790501fd1e167b474872 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/src/symlinks/640fb0e74195791501fd1ed57b41487f b/cursors/src/symlinks/640fb0e74195791501fd1ed57b41487f new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/src/symlinks/640fb0e74195791501fd1ed57b41487f @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/src/symlinks/9081237383d90e509aa00f00170e968f b/cursors/src/symlinks/9081237383d90e509aa00f00170e968f new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/src/symlinks/9081237383d90e509aa00f00170e968f @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/src/symlinks/9d800788f1b08800ae810202380a0822 b/cursors/src/symlinks/9d800788f1b08800ae810202380a0822 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/src/symlinks/9d800788f1b08800ae810202380a0822 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/src/symlinks/a2a266d0498c3104214a47bd64ab0fc8 b/cursors/src/symlinks/a2a266d0498c3104214a47bd64ab0fc8 new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/src/symlinks/a2a266d0498c3104214a47bd64ab0fc8 @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/src/symlinks/alias b/cursors/src/symlinks/alias new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/src/symlinks/alias @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/src/symlinks/all-scroll b/cursors/src/symlinks/all-scroll new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/src/symlinks/all-scroll @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/src/symlinks/b66166c04f8c3109214a4fbd64a50fc8 b/cursors/src/symlinks/b66166c04f8c3109214a4fbd64a50fc8 new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/src/symlinks/b66166c04f8c3109214a4fbd64a50fc8 @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/src/symlinks/col-resize b/cursors/src/symlinks/col-resize new file mode 120000 index 00000000..179b52be --- /dev/null +++ b/cursors/src/symlinks/col-resize @@ -0,0 +1 @@ +split_v \ No newline at end of file diff --git a/cursors/src/symlinks/crossed_circle b/cursors/src/symlinks/crossed_circle new file mode 120000 index 00000000..031757cf --- /dev/null +++ b/cursors/src/symlinks/crossed_circle @@ -0,0 +1 @@ +circle \ No newline at end of file diff --git a/cursors/src/symlinks/d9ce0ab605698f320427677b458ad60b b/cursors/src/symlinks/d9ce0ab605698f320427677b458ad60b new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/src/symlinks/d9ce0ab605698f320427677b458ad60b @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/src/symlinks/dnd-copy b/cursors/src/symlinks/dnd-copy new file mode 120000 index 00000000..88740b2c --- /dev/null +++ b/cursors/src/symlinks/dnd-copy @@ -0,0 +1 @@ +copy \ No newline at end of file diff --git a/cursors/src/symlinks/dnd-link b/cursors/src/symlinks/dnd-link new file mode 120000 index 00000000..c150ede2 --- /dev/null +++ b/cursors/src/symlinks/dnd-link @@ -0,0 +1 @@ +link \ No newline at end of file diff --git a/cursors/src/symlinks/dnd-move b/cursors/src/symlinks/dnd-move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/src/symlinks/dnd-move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/src/symlinks/dnd-no-drop b/cursors/src/symlinks/dnd-no-drop new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/src/symlinks/dnd-no-drop @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/src/symlinks/dnd-none b/cursors/src/symlinks/dnd-none new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/src/symlinks/dnd-none @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/src/symlinks/e-resize b/cursors/src/symlinks/e-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/src/symlinks/e-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/src/symlinks/e29285e634086352946a0e7090d73106 b/cursors/src/symlinks/e29285e634086352946a0e7090d73106 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/src/symlinks/e29285e634086352946a0e7090d73106 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/src/symlinks/fcf21c00b30f7e3f83fe0dfd12e71cff b/cursors/src/symlinks/fcf21c00b30f7e3f83fe0dfd12e71cff new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/src/symlinks/fcf21c00b30f7e3f83fe0dfd12e71cff @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/src/symlinks/hand1 b/cursors/src/symlinks/hand1 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/src/symlinks/hand1 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/src/symlinks/hand2 b/cursors/src/symlinks/hand2 new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/src/symlinks/hand2 @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/src/symlinks/ibeam b/cursors/src/symlinks/ibeam new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/src/symlinks/ibeam @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/src/symlinks/left_ptr_watch b/cursors/src/symlinks/left_ptr_watch new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/src/symlinks/left_ptr_watch @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/src/symlinks/move b/cursors/src/symlinks/move new file mode 120000 index 00000000..3e941780 --- /dev/null +++ b/cursors/src/symlinks/move @@ -0,0 +1 @@ +closedhand \ No newline at end of file diff --git a/cursors/src/symlinks/n-resize b/cursors/src/symlinks/n-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/src/symlinks/n-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/src/symlinks/not-allowed b/cursors/src/symlinks/not-allowed new file mode 120000 index 00000000..74313ca4 --- /dev/null +++ b/cursors/src/symlinks/not-allowed @@ -0,0 +1 @@ +forbidden \ No newline at end of file diff --git a/cursors/src/symlinks/pointer b/cursors/src/symlinks/pointer new file mode 120000 index 00000000..76c78220 --- /dev/null +++ b/cursors/src/symlinks/pointer @@ -0,0 +1 @@ +pointing_hand \ No newline at end of file diff --git a/cursors/src/symlinks/progress b/cursors/src/symlinks/progress new file mode 120000 index 00000000..3126613d --- /dev/null +++ b/cursors/src/symlinks/progress @@ -0,0 +1 @@ +half-busy \ No newline at end of file diff --git a/cursors/src/symlinks/question_arrow b/cursors/src/symlinks/question_arrow new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/src/symlinks/question_arrow @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/src/symlinks/row-resize b/cursors/src/symlinks/row-resize new file mode 120000 index 00000000..e3aa7487 --- /dev/null +++ b/cursors/src/symlinks/row-resize @@ -0,0 +1 @@ +split_h \ No newline at end of file diff --git a/cursors/src/symlinks/s-resize b/cursors/src/symlinks/s-resize new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/src/symlinks/s-resize @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/src/symlinks/sb_h_double_arrow b/cursors/src/symlinks/sb_h_double_arrow new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/src/symlinks/sb_h_double_arrow @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/src/symlinks/sb_v_double_arrow b/cursors/src/symlinks/sb_v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/src/symlinks/sb_v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/src/symlinks/size_all b/cursors/src/symlinks/size_all new file mode 120000 index 00000000..147f7449 --- /dev/null +++ b/cursors/src/symlinks/size_all @@ -0,0 +1 @@ +fleur \ No newline at end of file diff --git a/cursors/src/symlinks/text b/cursors/src/symlinks/text new file mode 120000 index 00000000..18632c40 --- /dev/null +++ b/cursors/src/symlinks/text @@ -0,0 +1 @@ +xterm \ No newline at end of file diff --git a/cursors/src/symlinks/v_double_arrow b/cursors/src/symlinks/v_double_arrow new file mode 120000 index 00000000..fb54fee2 --- /dev/null +++ b/cursors/src/symlinks/v_double_arrow @@ -0,0 +1 @@ +size_ver \ No newline at end of file diff --git a/cursors/src/symlinks/w-resize b/cursors/src/symlinks/w-resize new file mode 120000 index 00000000..e0da659c --- /dev/null +++ b/cursors/src/symlinks/w-resize @@ -0,0 +1 @@ +size_hor \ No newline at end of file diff --git a/cursors/src/symlinks/watch b/cursors/src/symlinks/watch new file mode 120000 index 00000000..fd80437a --- /dev/null +++ b/cursors/src/symlinks/watch @@ -0,0 +1 @@ +wait \ No newline at end of file diff --git a/cursors/src/symlinks/whats_this b/cursors/src/symlinks/whats_this new file mode 120000 index 00000000..4cea3acc --- /dev/null +++ b/cursors/src/symlinks/whats_this @@ -0,0 +1 @@ +help \ No newline at end of file diff --git a/cursors/src/theme-black/CMakeLists.txt b/cursors/src/theme-black/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-black/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-black/colors.in b/cursors/src/theme-black/colors.in new file mode 100644 index 00000000..e8a38469 --- /dev/null +++ b/cursors/src/theme-black/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#aaaaaa") +set(mediumColor "#000000") +set(darkerColor "#000000") diff --git a/cursors/src/theme-black/index.theme b/cursors/src/theme-black/index.theme new file mode 100644 index 00000000..a2a6d246 --- /dev/null +++ b/cursors/src/theme-black/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Black +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-blue/CMakeLists.txt b/cursors/src/theme-blue/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-blue/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-blue/colors.in b/cursors/src/theme-blue/colors.in new file mode 100644 index 00000000..e8f807ba --- /dev/null +++ b/cursors/src/theme-blue/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#a4c0e4") +set(mediumColor "#00438a") +set(darkerColor "#00316e") diff --git a/cursors/src/theme-blue/index.theme b/cursors/src/theme-blue/index.theme new file mode 100644 index 00000000..61f96a37 --- /dev/null +++ b/cursors/src/theme-blue/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Blue +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-bluecurve/CMakeLists.txt b/cursors/src/theme-bluecurve/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-bluecurve/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-bluecurve/colors.in b/cursors/src/theme-bluecurve/colors.in new file mode 100644 index 00000000..3758c2e9 --- /dev/null +++ b/cursors/src/theme-bluecurve/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#565D9D") +set(mediumColor "#000000") +set(darkerColor "#FFFFFF") diff --git a/cursors/src/theme-bluecurve/index.theme b/cursors/src/theme-bluecurve/index.theme new file mode 100644 index 00000000..a3e8de52 --- /dev/null +++ b/cursors/src/theme-bluecurve/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Bluecurve (Red Hat) +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-brown/CMakeLists.txt b/cursors/src/theme-brown/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-brown/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-brown/colors.in b/cursors/src/theme-brown/colors.in new file mode 100644 index 00000000..900e9683 --- /dev/null +++ b/cursors/src/theme-brown/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#debc85") +set(mediumColor "#57401e") +set(darkerColor "#382509") diff --git a/cursors/src/theme-brown/index.theme b/cursors/src/theme-brown/index.theme new file mode 100644 index 00000000..9a2e0b4c --- /dev/null +++ b/cursors/src/theme-brown/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Brown +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-cherry/CMakeLists.txt b/cursors/src/theme-cherry/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-cherry/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-cherry/colors.in b/cursors/src/theme-cherry/colors.in new file mode 100644 index 00000000..39df6cda --- /dev/null +++ b/cursors/src/theme-cherry/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#EFE9E8") +set(mediumColor "#D8A6AB") +set(darkerColor "#91454F") +set(altLighterColor "#D9E8C3") +set(altMediumColor "#B3D28F") +set(altDarkerColor "#55803A") diff --git a/cursors/src/theme-cherry/index.theme b/cursors/src/theme-cherry/index.theme new file mode 100644 index 00000000..61ecaa97 --- /dev/null +++ b/cursors/src/theme-cherry/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Cherry Blossom +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-chrome/CMakeLists.txt b/cursors/src/theme-chrome/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-chrome/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-chrome/colors.in b/cursors/src/theme-chrome/colors.in new file mode 100644 index 00000000..7d25b7bf --- /dev/null +++ b/cursors/src/theme-chrome/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#FFFFFF") +set(mediumColor "#AEB7C0") +set(darkerColor "#334050") +set(altLighterColor "#C1CFE0") +set(altMediumColor "#6080A0") +set(altDarkerColor "#263340") diff --git a/cursors/src/theme-chrome/index.theme b/cursors/src/theme-chrome/index.theme new file mode 100644 index 00000000..b1e46776 --- /dev/null +++ b/cursors/src/theme-chrome/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Chrome +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-desert/CMakeLists.txt b/cursors/src/theme-desert/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-desert/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-desert/colors.in b/cursors/src/theme-desert/colors.in new file mode 100644 index 00000000..462144d2 --- /dev/null +++ b/cursors/src/theme-desert/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#F0ECE5") +set(mediumColor "#B0ABA0") +set(darkerColor "#000000") +set(altLighterColor "#CA706D") +set(altMediumColor "#7D0909") +set(altDarkerColor "#000000") diff --git a/cursors/src/theme-desert/index.theme b/cursors/src/theme-desert/index.theme new file mode 100644 index 00000000..67d35bd2 --- /dev/null +++ b/cursors/src/theme-desert/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Desert +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-emerald/CMakeLists.txt b/cursors/src/theme-emerald/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-emerald/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-emerald/colors.in b/cursors/src/theme-emerald/colors.in new file mode 100644 index 00000000..3d6a3797 --- /dev/null +++ b/cursors/src/theme-emerald/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#99dcc6") +set(mediumColor "#00734d") +set(darkerColor "#00583f") diff --git a/cursors/src/theme-emerald/index.theme b/cursors/src/theme-emerald/index.theme new file mode 100644 index 00000000..865e7115 --- /dev/null +++ b/cursors/src/theme-emerald/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Emerald +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-green/CMakeLists.txt b/cursors/src/theme-green/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-green/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-green/colors.in b/cursors/src/theme-green/colors.in new file mode 100644 index 00000000..4d38ee2c --- /dev/null +++ b/cursors/src/theme-green/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#d8e8c2") +set(mediumColor "#00892c") +set(darkerColor "#006e29") diff --git a/cursors/src/theme-green/index.theme b/cursors/src/theme-green/index.theme new file mode 100644 index 00000000..2152cbf0 --- /dev/null +++ b/cursors/src/theme-green/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Green +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-grey/CMakeLists.txt b/cursors/src/theme-grey/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-grey/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-grey/colors.in b/cursors/src/theme-grey/colors.in new file mode 100644 index 00000000..eb2024ee --- /dev/null +++ b/cursors/src/theme-grey/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#eeeeec") +set(mediumColor "#555753") +set(darkerColor "#2e3436") diff --git a/cursors/src/theme-grey/index.theme b/cursors/src/theme-grey/index.theme new file mode 100644 index 00000000..39d45328 --- /dev/null +++ b/cursors/src/theme-grey/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Grey +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-honeycomb/CMakeLists.txt b/cursors/src/theme-honeycomb/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-honeycomb/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-honeycomb/colors.in b/cursors/src/theme-honeycomb/colors.in new file mode 100644 index 00000000..2f795f2f --- /dev/null +++ b/cursors/src/theme-honeycomb/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#E5E8E1") +set(mediumColor "#BABDB7") +set(darkerColor "#2F302E") +set(altLighterColor "#FFF299") +set(altMediumColor "#E3A700") +set(altDarkerColor "#403000") diff --git a/cursors/src/theme-honeycomb/index.theme b/cursors/src/theme-honeycomb/index.theme new file mode 100644 index 00000000..9a6a9308 --- /dev/null +++ b/cursors/src/theme-honeycomb/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Honeycomb +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-hot_orange/CMakeLists.txt b/cursors/src/theme-hot_orange/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-hot_orange/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-hot_orange/colors.in b/cursors/src/theme-hot_orange/colors.in new file mode 100644 index 00000000..5bf06978 --- /dev/null +++ b/cursors/src/theme-hot_orange/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#ffd9b0") +set(mediumColor "#cf4913") +set(darkerColor "#ac4311") diff --git a/cursors/src/theme-hot_orange/index.theme b/cursors/src/theme-hot_orange/index.theme new file mode 100644 index 00000000..6253db2c --- /dev/null +++ b/cursors/src/theme-hot_orange/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Hot Orange +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-lilac/CMakeLists.txt b/cursors/src/theme-lilac/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-lilac/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-lilac/colors.in b/cursors/src/theme-lilac/colors.in new file mode 100644 index 00000000..7e002acd --- /dev/null +++ b/cursors/src/theme-lilac/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#D9D2E7") +set(mediumColor "#625C6E") +set(darkerColor "#393540") +set(altLighterColor "#D2F4E7") +set(altMediumColor "#4F7464") +set(altDarkerColor "#2B4037") diff --git a/cursors/src/theme-lilac/index.theme b/cursors/src/theme-lilac/index.theme new file mode 100644 index 00000000..1e649672 --- /dev/null +++ b/cursors/src/theme-lilac/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Evening Lilac +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-midnight_meadow/CMakeLists.txt b/cursors/src/theme-midnight_meadow/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-midnight_meadow/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-midnight_meadow/colors.in b/cursors/src/theme-midnight_meadow/colors.in new file mode 100644 index 00000000..f5c19a64 --- /dev/null +++ b/cursors/src/theme-midnight_meadow/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#108010") +set(mediumColor "#001C00") +set(darkerColor "#80F080") diff --git a/cursors/src/theme-midnight_meadow/index.theme b/cursors/src/theme-midnight_meadow/index.theme new file mode 100644 index 00000000..9f682973 --- /dev/null +++ b/cursors/src/theme-midnight_meadow/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Midnight Meadow +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-navy/CMakeLists.txt b/cursors/src/theme-navy/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-navy/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-navy/colors.in b/cursors/src/theme-navy/colors.in new file mode 100644 index 00000000..61c8e3d9 --- /dev/null +++ b/cursors/src/theme-navy/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#c3b4da") +set(mediumColor "#34176e") +set(darkerColor "#1d0a55") diff --git a/cursors/src/theme-navy/index.theme b/cursors/src/theme-navy/index.theme new file mode 100644 index 00000000..811868da --- /dev/null +++ b/cursors/src/theme-navy/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Navy +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-norway/CMakeLists.txt b/cursors/src/theme-norway/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-norway/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-norway/colors.in b/cursors/src/theme-norway/colors.in new file mode 100644 index 00000000..571eb1e9 --- /dev/null +++ b/cursors/src/theme-norway/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#F7F3E9") +set(mediumColor "#C5B399") +set(darkerColor "#807060") +set(altLighterColor "#90C1E8") +set(altMediumColor "#176CA5") +set(altDarkerColor "#0F4B70") diff --git a/cursors/src/theme-norway/index.theme b/cursors/src/theme-norway/index.theme new file mode 100644 index 00000000..a676e056 --- /dev/null +++ b/cursors/src/theme-norway/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Norway +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-obsidian-hc/CMakeLists.txt b/cursors/src/theme-obsidian-hc/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-obsidian-hc/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-obsidian-hc/colors.in b/cursors/src/theme-obsidian-hc/colors.in new file mode 100644 index 00000000..4839dd13 --- /dev/null +++ b/cursors/src/theme-obsidian-hc/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#787775") +set(mediumColor "#201F1F") +set(darkerColor "#E8E7E4") +set(altLighterColor "#184880") +set(altMediumColor "#122F50") +set(altDarkerColor "#5177A6") diff --git a/cursors/src/theme-obsidian-hc/index.theme b/cursors/src/theme-obsidian-hc/index.theme new file mode 100644 index 00000000..6ea3c87a --- /dev/null +++ b/cursors/src/theme-obsidian-hc/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Obsidian High Contrast +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-obsidian/CMakeLists.txt b/cursors/src/theme-obsidian/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-obsidian/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-obsidian/colors.in b/cursors/src/theme-obsidian/colors.in new file mode 100644 index 00000000..23688fe1 --- /dev/null +++ b/cursors/src/theme-obsidian/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#787775") +set(mediumColor "#201F1F") +set(darkerColor "#0F0E0E") +set(altLighterColor "#5177A6") +set(altMediumColor "#184880") +set(altDarkerColor "#122F50") diff --git a/cursors/src/theme-obsidian/index.theme b/cursors/src/theme-obsidian/index.theme new file mode 100644 index 00000000..c4808d4d --- /dev/null +++ b/cursors/src/theme-obsidian/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Obsidian +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-olympus-inv/CMakeLists.txt b/cursors/src/theme-olympus-inv/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-olympus-inv/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-olympus-inv/colors.in b/cursors/src/theme-olympus-inv/colors.in new file mode 100644 index 00000000..4ae74b23 --- /dev/null +++ b/cursors/src/theme-olympus-inv/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#0000B0") +set(mediumColor "#000060") +set(darkerColor "#FFEE80") diff --git a/cursors/src/theme-olympus-inv/index.theme b/cursors/src/theme-olympus-inv/index.theme new file mode 100644 index 00000000..50488e88 --- /dev/null +++ b/cursors/src/theme-olympus-inv/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Olympus (Reversed) +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-olympus/CMakeLists.txt b/cursors/src/theme-olympus/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-olympus/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-olympus/colors.in b/cursors/src/theme-olympus/colors.in new file mode 100644 index 00000000..9b67e02c --- /dev/null +++ b/cursors/src/theme-olympus/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#FFEE80") +set(mediumColor "#E0C000") +set(darkerColor "#0000B0") diff --git a/cursors/src/theme-olympus/index.theme b/cursors/src/theme-olympus/index.theme new file mode 100644 index 00000000..e4f25f5c --- /dev/null +++ b/cursors/src/theme-olympus/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Olympus +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-orchid/CMakeLists.txt b/cursors/src/theme-orchid/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-orchid/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-orchid/colors.in b/cursors/src/theme-orchid/colors.in new file mode 100644 index 00000000..b25192ec --- /dev/null +++ b/cursors/src/theme-orchid/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#CACEE2") +set(mediumColor "#A9ADBE") +set(darkerColor "#33166E") +set(altLighterColor "#D2E1F0") +set(altMediumColor "#718BA5") +set(altDarkerColor "#33166E") diff --git a/cursors/src/theme-orchid/index.theme b/cursors/src/theme-orchid/index.theme new file mode 100644 index 00000000..542512e9 --- /dev/null +++ b/cursors/src/theme-orchid/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Stone Orchid +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-oxygen/CMakeLists.txt b/cursors/src/theme-oxygen/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-oxygen/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-oxygen/colors.in b/cursors/src/theme-oxygen/colors.in new file mode 100644 index 00000000..6b53161d --- /dev/null +++ b/cursors/src/theme-oxygen/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#FFFFFF") +set(mediumColor "#B5B4B3") +set(darkerColor "#403F3F") +set(altLighterColor "#7FB9FF") +set(altMediumColor "#2B74C7") +set(altDarkerColor "#132A40") diff --git a/cursors/src/theme-oxygen/index.theme b/cursors/src/theme-oxygen/index.theme new file mode 100644 index 00000000..7ba8379d --- /dev/null +++ b/cursors/src/theme-oxygen/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Default +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-peach/CMakeLists.txt b/cursors/src/theme-peach/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-peach/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-peach/colors.in b/cursors/src/theme-peach/colors.in new file mode 100644 index 00000000..163253eb --- /dev/null +++ b/cursors/src/theme-peach/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#F4E6CF") +set(mediumColor "#EACDA0") +set(darkerColor "#E1646D") +set(altLighterColor "#DAE8C4") +set(altMediumColor "#75B150") +set(altDarkerColor "#5D6E4B") diff --git a/cursors/src/theme-peach/index.theme b/cursors/src/theme-peach/index.theme new file mode 100644 index 00000000..b9715ee7 --- /dev/null +++ b/cursors/src/theme-peach/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen White Peach +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-purple/CMakeLists.txt b/cursors/src/theme-purple/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-purple/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-purple/colors.in b/cursors/src/theme-purple/colors.in new file mode 100644 index 00000000..1fb0b41c --- /dev/null +++ b/cursors/src/theme-purple/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#f9cade") +set(mediumColor "#bf0361") +set(darkerColor "#9c0f56") diff --git a/cursors/src/theme-purple/index.theme b/cursors/src/theme-purple/index.theme new file mode 100644 index 00000000..19bf2d7d --- /dev/null +++ b/cursors/src/theme-purple/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Purple +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-red-argentina/CMakeLists.txt b/cursors/src/theme-red-argentina/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-red-argentina/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-red-argentina/colors.in b/cursors/src/theme-red-argentina/colors.in new file mode 100644 index 00000000..63593b9b --- /dev/null +++ b/cursors/src/theme-red-argentina/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#ff2929") +set(mediumColor "#cc0000") +set(darkerColor "#930000") diff --git a/cursors/src/theme-red-argentina/index.theme b/cursors/src/theme-red-argentina/index.theme new file mode 100644 index 00000000..01fabdde --- /dev/null +++ b/cursors/src/theme-red-argentina/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Red Argentina (Tango) +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-red/CMakeLists.txt b/cursors/src/theme-red/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-red/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-red/colors.in b/cursors/src/theme-red/colors.in new file mode 100644 index 00000000..a875cd87 --- /dev/null +++ b/cursors/src/theme-red/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#f9ccca") +set(mediumColor "#bf0303") +set(darkerColor "#9c0f0f") diff --git a/cursors/src/theme-red/index.theme b/cursors/src/theme-red/index.theme new file mode 100644 index 00000000..c4229357 --- /dev/null +++ b/cursors/src/theme-red/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Red +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-sea_blue/CMakeLists.txt b/cursors/src/theme-sea_blue/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-sea_blue/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-sea_blue/colors.in b/cursors/src/theme-sea_blue/colors.in new file mode 100644 index 00000000..c21456ba --- /dev/null +++ b/cursors/src/theme-sea_blue/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#a8dde0") +set(mediumColor "#006066") +set(darkerColor "#00484d") diff --git a/cursors/src/theme-sea_blue/index.theme b/cursors/src/theme-sea_blue/index.theme new file mode 100644 index 00000000..75ba3cd8 --- /dev/null +++ b/cursors/src/theme-sea_blue/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Sea Blue +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-steel/CMakeLists.txt b/cursors/src/theme-steel/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-steel/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-steel/colors.in b/cursors/src/theme-steel/colors.in new file mode 100644 index 00000000..dfc42eec --- /dev/null +++ b/cursors/src/theme-steel/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#FAF9F2") +set(mediumColor "#AFAEA9") +set(darkerColor "#393837") +set(altLighterColor "#89B2C0") +set(altMediumColor "#597E90") +set(altDarkerColor "#273840") diff --git a/cursors/src/theme-steel/index.theme b/cursors/src/theme-steel/index.theme new file mode 100644 index 00000000..b78f4f3d --- /dev/null +++ b/cursors/src/theme-steel/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Steel +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-terra/CMakeLists.txt b/cursors/src/theme-terra/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-terra/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-terra/colors.in b/cursors/src/theme-terra/colors.in new file mode 100644 index 00000000..5b8dc14d --- /dev/null +++ b/cursors/src/theme-terra/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#CBC2BF") +set(mediumColor "#9A987F") +set(darkerColor "#404642") +set(altLighterColor "#FFFFFF") +set(altMediumColor "#6A8FD2") +set(altDarkerColor "#3E538E") diff --git a/cursors/src/theme-terra/index.theme b/cursors/src/theme-terra/index.theme new file mode 100644 index 00000000..4b3ce6a5 --- /dev/null +++ b/cursors/src/theme-terra/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Terra Sky +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-terra_green/CMakeLists.txt b/cursors/src/theme-terra_green/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-terra_green/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-terra_green/colors.in b/cursors/src/theme-terra_green/colors.in new file mode 100644 index 00000000..aa6721a7 --- /dev/null +++ b/cursors/src/theme-terra_green/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#CBC2BF") +set(mediumColor "#9A987F") +set(darkerColor "#404642") +set(altLighterColor "#008929") +set(altMediumColor "#004D00") +set(altDarkerColor "#0C2607") diff --git a/cursors/src/theme-terra_green/index.theme b/cursors/src/theme-terra_green/index.theme new file mode 100644 index 00000000..9854e38a --- /dev/null +++ b/cursors/src/theme-terra_green/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Terra Earth +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-violet/CMakeLists.txt b/cursors/src/theme-violet/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-violet/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-violet/colors.in b/cursors/src/theme-violet/colors.in new file mode 100644 index 00000000..e37a7937 --- /dev/null +++ b/cursors/src/theme-violet/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#e8b7d7") +set(mediumColor "#85026c") +set(darkerColor "#6a0056") diff --git a/cursors/src/theme-violet/index.theme b/cursors/src/theme-violet/index.theme new file mode 100644 index 00000000..e2a2efa7 --- /dev/null +++ b/cursors/src/theme-violet/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Violet +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-viorange/CMakeLists.txt b/cursors/src/theme-viorange/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-viorange/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-viorange/colors.in b/cursors/src/theme-viorange/colors.in new file mode 100644 index 00000000..032f2ecd --- /dev/null +++ b/cursors/src/theme-viorange/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#fcaf3e") +set(mediumColor "#f57900") +set(darkerColor "#ce5c00") diff --git a/cursors/src/theme-viorange/index.theme b/cursors/src/theme-viorange/index.theme new file mode 100644 index 00000000..87a5d20f --- /dev/null +++ b/cursors/src/theme-viorange/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Vibrant Orange (Tango) +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-white/CMakeLists.txt b/cursors/src/theme-white/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-white/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-white/colors.in b/cursors/src/theme-white/colors.in new file mode 100644 index 00000000..f263f583 --- /dev/null +++ b/cursors/src/theme-white/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#ffffff") +set(mediumColor "#d0d0d0") +set(darkerColor "#000000") diff --git a/cursors/src/theme-white/index.theme b/cursors/src/theme-white/index.theme new file mode 100644 index 00000000..6e4470ac --- /dev/null +++ b/cursors/src/theme-white/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen White +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-whitewater/CMakeLists.txt b/cursors/src/theme-whitewater/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-whitewater/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-whitewater/colors.in b/cursors/src/theme-whitewater/colors.in new file mode 100644 index 00000000..feaab867 --- /dev/null +++ b/cursors/src/theme-whitewater/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#E0DFDC") +set(mediumColor "#787775") +set(darkerColor "#302F2E") +set(altLighterColor "#2966A4") +set(altMediumColor "#153E6D") +set(altDarkerColor "#102C50") diff --git a/cursors/src/theme-whitewater/index.theme b/cursors/src/theme-whitewater/index.theme new file mode 100644 index 00000000..225cab4f --- /dev/null +++ b/cursors/src/theme-whitewater/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Whitewater +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-wonton/CMakeLists.txt b/cursors/src/theme-wonton/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-wonton/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-wonton/colors.in b/cursors/src/theme-wonton/colors.in new file mode 100644 index 00000000..f5bd7341 --- /dev/null +++ b/cursors/src/theme-wonton/colors.in @@ -0,0 +1,6 @@ +set(lighterColor "#494E58") +set(mediumColor "#282C30") +set(darkerColor "#D2DEF0") +set(altLighterColor "#78889C") +set(altMediumColor "#3D4650") +set(altDarkerColor "#D2E2F4") diff --git a/cursors/src/theme-wonton/index.theme b/cursors/src/theme-wonton/index.theme new file mode 100644 index 00000000..da6bd6a5 --- /dev/null +++ b/cursors/src/theme-wonton/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Wonton Soup +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-yellow/CMakeLists.txt b/cursors/src/theme-yellow/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-yellow/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-yellow/colors.in b/cursors/src/theme-yellow/colors.in new file mode 100644 index 00000000..2c3843fc --- /dev/null +++ b/cursors/src/theme-yellow/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#fff6c8") +set(mediumColor "#f3c300") +set(darkerColor "#e3ad00") diff --git a/cursors/src/theme-yellow/index.theme b/cursors/src/theme-yellow/index.theme new file mode 100644 index 00000000..c0a16cd6 --- /dev/null +++ b/cursors/src/theme-yellow/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Yellow +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme-zion/CMakeLists.txt b/cursors/src/theme-zion/CMakeLists.txt new file mode 100644 index 00000000..5e1a072e --- /dev/null +++ b/cursors/src/theme-zion/CMakeLists.txt @@ -0,0 +1 @@ +add_theme(${color} ${color} 90 180 270) diff --git a/cursors/src/theme-zion/colors.in b/cursors/src/theme-zion/colors.in new file mode 100644 index 00000000..32dc4a61 --- /dev/null +++ b/cursors/src/theme-zion/colors.in @@ -0,0 +1,3 @@ +set(lighterColor "#606060") +set(mediumColor "#000000") +set(darkerColor "#ffffff") diff --git a/cursors/src/theme-zion/index.theme b/cursors/src/theme-zion/index.theme new file mode 100644 index 00000000..241e15b1 --- /dev/null +++ b/cursors/src/theme-zion/index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name = Oxygen Zion +Comment = Oxygen mouse theme. Oxygenize your desktop! diff --git a/cursors/src/theme.cmake b/cursors/src/theme.cmake new file mode 100644 index 00000000..b79259ab --- /dev/null +++ b/cursors/src/theme.cmake @@ -0,0 +1,2 @@ +add_theme(${color} ${color} 90) +add_theme(${color} ${color}-big 180) diff --git a/cursors/src/wincursor.py b/cursors/src/wincursor.py new file mode 100644 index 00000000..ddb5e528 --- /dev/null +++ b/cursors/src/wincursor.py @@ -0,0 +1,50 @@ +import sys +import os + +configs = ["left_ptr.in", "help.in", "progress.in", "wait.in", "cross.in", "text.in", "pencil.in", "circle.in", "size_ver.in", "size_hor.in", "size_fdiag.in", "size_bdiag.in", "fleur.in", "up_arrow.in", "pointer.in"] + +if len(sys.argv) < 4: + print "too few arguments for wincursor" + sys.exit(1) + +pngdir = sys.argv[1] +conf = sys.argv[2] +outdir = sys.argv[3] +dummy = sys.argv[4] + +f = open(dummy, "w") +f.close() + +if not configs.count(conf[conf.rfind("/")+1:]): + sys.exit(0) +else: + conffile = conf[conf.rfind("/")+1:] + +f = open(conf) +r = f.read() +f.close() + +ls = r.split("\n") +imglist = [] + +for l in ls: + if l and not l.startswith("#"): + v = l.split(" ") + if len(v) == 4: + imglist += [(v[3], v[1], v[2])] + elif len(v) == 5: + imglist += [(v[3], v[1], v[2], v[4])] + +if len(imglist) > 1: + pngls = [os.path.join(pngdir, i[0]) for i in imglist] + pngstr = "" + for p in pngls: + pngstr += " %s" % p + + img = imglist[0] + jiffie = int((float(img[3]) / 1000) * 60) + + print os.popen4("png2ico %s --hotspotx %s --hotspoty %s --framerate %s %s" % (os.path.join(outdir, conffile.replace(".in", ".ani")), img[1], img[2], jiffie, pngstr))[1].read() +elif len(imglist) == 1: + img = imglist[0] + print os.popen4("png2ico %s --hotspotx %s --hotspoty %s %s" % (os.path.join(outdir, conffile.replace(".in", ".cur")), img[1], img[2], os.path.join(pngdir, img[0])))[1].read() diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 00000000..af00f4cd --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,12 @@ +add_subdirectory(kdm) +add_subdirectory(klipper) +add_subdirectory(kfontview) +add_subdirectory(kmenuedit) +add_subdirectory(ksysguard) +add_subdirectory(plasma-desktop) +add_subdirectory(kcontrol) +add_subdirectory(systemsettings) +add_subdirectory(kinfocenter) +if(POLKITQT_FOUND) + add_subdirectory(PolicyKit-kde) +endif(POLKITQT_FOUND) diff --git a/doc/PolicyKit-kde/CMakeLists.txt b/doc/PolicyKit-kde/CMakeLists.txt new file mode 100644 index 00000000..dd75aec8 --- /dev/null +++ b/doc/PolicyKit-kde/CMakeLists.txt @@ -0,0 +1 @@ +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/PolicyKit-kde/authdialog_1.png b/doc/PolicyKit-kde/authdialog_1.png new file mode 100644 index 00000000..55e4d528 Binary files /dev/null and b/doc/PolicyKit-kde/authdialog_1.png differ diff --git a/doc/PolicyKit-kde/authdialog_2.png b/doc/PolicyKit-kde/authdialog_2.png new file mode 100644 index 00000000..2cdfb0ec Binary files /dev/null and b/doc/PolicyKit-kde/authdialog_2.png differ diff --git a/doc/PolicyKit-kde/authdialog_3.png b/doc/PolicyKit-kde/authdialog_3.png new file mode 100644 index 00000000..55f3efe7 Binary files /dev/null and b/doc/PolicyKit-kde/authdialog_3.png differ diff --git a/doc/PolicyKit-kde/authdialog_4.png b/doc/PolicyKit-kde/authdialog_4.png new file mode 100644 index 00000000..933f4da4 Binary files /dev/null and b/doc/PolicyKit-kde/authdialog_4.png differ diff --git a/doc/PolicyKit-kde/authdialog_5.png b/doc/PolicyKit-kde/authdialog_5.png new file mode 100644 index 00000000..e7b191d3 Binary files /dev/null and b/doc/PolicyKit-kde/authdialog_5.png differ diff --git a/doc/PolicyKit-kde/authdialog_6.png b/doc/PolicyKit-kde/authdialog_6.png new file mode 100644 index 00000000..659e0b0d Binary files /dev/null and b/doc/PolicyKit-kde/authdialog_6.png differ diff --git a/doc/PolicyKit-kde/authorization.docbook b/doc/PolicyKit-kde/authorization.docbook new file mode 100644 index 00000000..5405926e --- /dev/null +++ b/doc/PolicyKit-kde/authorization.docbook @@ -0,0 +1,112 @@ + +Authorization manager + + +Manual + + +The Authorization manager is the application that system administrators can +use to easily change the default behavior of any actions. This page does not +aim to explain how to create new actions or define new .policy +files. + + +The Authorization screen is divided in two parts, at the left we have all the +actions that PolicyKit knows, you are able to search the actions using the search +bar at the top, and at the right we have the selected action. +This screenshot shows the main Authorization screen: + + + + + + +Main window with source device + + + + + +When you select an action it's details will be shown at the right side, +the action might have an icon, a description and the vendor name. Next +in the view we have the Implicit Authorizations and +Explicit Authorizations. + + + +The Implicit Authorizations are authorizations automatically +given to users based on certain criteria such as if they are on the local +console. These authorizations are read from the .policy files +that the given application defined, they are the defaults settings of the action. +These are the valid values + + + +no +auth_self_one_shot +auth_self +auth_self_keep_session +auth_self_keep_always +auth_admin_one_shot +auth_admin +auth_admin_keep_session +auth_admin_keep_always +yes + + + +You can change these defaults values simply by changing it on the combo box, +the not bold value is the default one so if you want to change one value back +you can select it, to make you selection take effect you have to click on the +Modify button. The Revert to defaults can be used +to change all Implicit Authorizations to it's defaults values. +Note that both Modify and Revert to defaults +requires you to issue the PolicyKit org.freedesktop.policykit.modify-defaults +action which might ask a password. + + + +The Explicit Authorizations are authorizations that are either +obtained through authentication process or specifically given to the action +in question. The default behavior is to only show the current user explicit +authorizations; if you want to see others users explicit authorizations +click on the Show authorizations from all users, note that this +requires you to issue the PolicyKit org.freedesktop.policykit.read +action which might ask a password. +Blocked authorizations are marked with a STOP sign. + + + +The Revoke button is used to revoke an explicit authorization. +Note that this requires you to issue the PolicyKit +org.freedesktop.policykit.revoke action which might ask a password. + + + +If you want to specifically grant or block a given user of performing a given action +you can click on the Grant or Block. +The following screenshot you see the Grant/Block dialog: + + + + + + +Grant/Block explicit authorizations dialog + + + + + +To grant/block explicit authorizations you have to select the user that will +receive the authorization. You can also select the Constraints +to limit the authorization such that it only applies under certain circumstances. +Be aware that explicit blocking and authorization might self lock you +of performing the given action so be sure of what you are doing +Note that this requires you to issue the PolicyKit +org.freedesktop.policykit.grant action which might ask a password. + + + + + diff --git a/doc/PolicyKit-kde/authorization_1.png b/doc/PolicyKit-kde/authorization_1.png new file mode 100644 index 00000000..dbd9a864 Binary files /dev/null and b/doc/PolicyKit-kde/authorization_1.png differ diff --git a/doc/PolicyKit-kde/authorization_2.png b/doc/PolicyKit-kde/authorization_2.png new file mode 100644 index 00000000..890c7390 Binary files /dev/null and b/doc/PolicyKit-kde/authorization_2.png differ diff --git a/doc/PolicyKit-kde/authorizationagent.docbook b/doc/PolicyKit-kde/authorizationagent.docbook new file mode 100644 index 00000000..203350c5 --- /dev/null +++ b/doc/PolicyKit-kde/authorizationagent.docbook @@ -0,0 +1,120 @@ + +Authorization Agent + + +Manual + + +The Authorization Agent is the application that is called whenever an user +wants to obtain a given authorization. It's a &DBus; activated daemon which +uses libpolkit-grant that in turn uses PAM for authentication +services (however, other authentication back-ends can be plugged in as required). + + + + +Authorization Agent dialog + + +The appearance of the authentication dialog depends on the result from PolicyKit +and also whether administrator authentication is defined as authenticate as +the root user or authenticate as one of the users from UNIX group +wheel or however the PolicyKit library is configured (see the +PolicyKit.conf(5) manual page for details). Note that some of the screenshots below +were made on a system set up to use the +ThinkFinger +PAM module. The text shown in the authentication dialogs stems from the PolicyKit +.policy XML files residing in /usr/share/PolicyKit/policy and is read by the +authentication daemon when an applications asks to obtain an authorization. +Thus, what the user sees is not under application control +(e.g. it's not passed from the application) which rules out a class of attacks +where applications are trying to fool the user into gaining a privilege. + + +The authentication dialog where the user is asked to authenticate as root +using the password or swiping the finger. +The details shows the application that's requesting the action, the action +itself and the action vendor. If clicking in the action link it will open the +authorization manager pointing to the given action, and the vendor might also +provide a link for the given action that will be fired when clicking on the +Vendor link: + + + + + +The authentication dialog asking for root, swipe finger and showing descriptions + + + + + +Authentication dialog where the user is asked to authenticate as an administrative +user and PolicyKit is configured to use the root password for this: + + + + + +The authentication dialog asking for root + + + + + +Authentication dialog where the user is asked to authenticate as an administrative +user and PolicyKit is configured to use a group for this: + + + + + +The authentication dialog asking for a user of the administrative group + + + + + +Same authentication dialog, showing drop down box where the user can be selected: + + + + + +Same authentication dialog, showing drop down box where the user can be selected + + + + + + +Authentication dialog showing an Action where the privilege can be retained indefinitely: + + + + + +Authentication dialog showing an Action where the privilege can be retained indefinitely + + + + + + +Authentication dialog showing an Action where the privilege can be retained only +for the remainder of the desktop session: + + + + + +Authentication dialog showing an Action where the privilege can be retained only +for the remainder of the desktop session + + + + + + + + diff --git a/doc/PolicyKit-kde/howitworks.docbook b/doc/PolicyKit-kde/howitworks.docbook new file mode 100644 index 00000000..90e4d331 --- /dev/null +++ b/doc/PolicyKit-kde/howitworks.docbook @@ -0,0 +1,53 @@ + +How it works + + +Overview + +PolicyKit has a simple way of working, but it requires some +design changes from the applications that want to use it to request +passwords. + + + +The problem + +In GUI applications the common way to gain root privileges is to start +it as root, but there are several security risks in doing this method and +it does not allow a good actions mapping. There is no way to separate actions +like package-install of system-upgrading. +All the users who want to use it must have the root password. Another common +approach is using sudo but once you start an application with sudo you will +have all the rights the root user will have. +If for example the GUI application has a dialog to select files that dialog +is running as root which means that the user might be able to delete any file +on his machine or even coping others user files. + + + + +The solution + +With PolicyKit this problem is solved. The application in question +just need to separate the privileged code into another application, +often called helper (which will not have a GUI), then maps the desired +actions into a .policy file. PolicyKit then loads this file +and it can now authenticate applications to use those actions. +The use of &DBus; activated applications is the best if not the only, +way of putting an helper application to run with root privileges. + +With this design the GUI application calls an action of the helper +application through &DBus;, which will start the helper with root privileges, +and informing it which action was requested and which application has requested +it. The helper application now calls the PolicyKit agent to see if that application +can do the given task, the helper should report if it could do the requested action. +In case the helper saw that the application didn't have enough rights the GUI +will then need to ask PolicyKit to obtain an authorization. + +When PolicyKit receives the request to obtain an authorization it issues an +available Agent, which might happen to be &policykit-kde; if available. After a successful +authentication the GUI application needs to call the helper repeating the +same operation again. + + + diff --git a/doc/PolicyKit-kde/index.docbook b/doc/PolicyKit-kde/index.docbook new file mode 100644 index 00000000..a1173d32 --- /dev/null +++ b/doc/PolicyKit-kde/index.docbook @@ -0,0 +1,88 @@ + +PolicyKit-kde"> + PolicyKit"> + + + + + + + +]> + + + + +The &policykit-kde; manual + + + +Daniel +Nicoletti + + + + + +2008-2009 +Daniel Nicoletti + + +&FDLNotice; + +2009-01-25 +0.9.0 + + +&policykit-kde; is a &kde; front end to the PolicyKit +system that is used to manages authentication. +&policykit; is a toolkit designed to allow unprivileged processes +to speak to privileged processes. It does that by centralizing information of +actions and authorized applications. + + + +KDE +System +Password +Admin +Authentication +polkit +policykit +policy +policies + + + + +&policykit-kde-introduction; +&policykit-kde-howitworks; +&policykit-kde-authorization; +&policykit-kde-authorizationagent; + + +Credits and License + + +&policykit-kde; + + +Program copyright 2008-2009 Daniel Nicoletti + + +Documentation copyright 2008-2009 Daniel Nicoletti + + + +&underFDL; + + + +&documentation.index; + + + + diff --git a/doc/PolicyKit-kde/introduction.docbook b/doc/PolicyKit-kde/introduction.docbook new file mode 100644 index 00000000..ea94ac13 --- /dev/null +++ b/doc/PolicyKit-kde/introduction.docbook @@ -0,0 +1,28 @@ + +Overview + +&policykit-kde; is a implementation of PolicyKit tool to the look and feel +of KDE. + +PolicyKit allows easy and secure password management, it can be used by +applications to ask their users for a password. Each application defines a set +of actions that can be executed by their program. +The application will call PolicyKit to see if the user can perform a given +action, if not, the application can issue the auth dialog where the user +can enter his/her password, root password, the password of a given group +of users or even swipe the finger. + +&policykit-kde; consists of two applications: +The Authorization agent that receives requests for authentication, and shows +a dialog asking for a password. +The Authorization manager that is used to manage the authorizations, it is +mainly used by system administrators that may want to change the default behavior +of a program policies. + +For Qt/KDE developers there is Qt library to allow easy integration with +you application and PolicyKit. + +For more information of how PolicyKit works, it's design and API visit +PolicyKit Library Reference Manual + + diff --git a/doc/kcontrol/CMakeLists.txt b/doc/kcontrol/CMakeLists.txt new file mode 100644 index 00000000..87f836a3 --- /dev/null +++ b/doc/kcontrol/CMakeLists.txt @@ -0,0 +1,32 @@ +add_subdirectory(clock) +add_subdirectory(colors) +add_subdirectory(desktopthemedetails) +add_subdirectory(joystick) +add_subdirectory(kcmaccess) +add_subdirectory(kcmstyle) +add_subdirectory(solid-actions) +add_subdirectory(splashscreen) +add_subdirectory(powerdevil) +add_subdirectory(kwincompositing) +add_subdirectory(kwinscreenedges) + +if ( Q_WS_X11 ) +add_subdirectory(autostart) +add_subdirectory(bell) +add_subdirectory(cursortheme) +add_subdirectory(fonts) +add_subdirectory(fontinst) +add_subdirectory(keys) +add_subdirectory(keyboard) +add_subdirectory(kwindecoration) +add_subdirectory(desktop) +add_subdirectory(mouse) +add_subdirectory(paths) +add_subdirectory(screensaver) +add_subdirectory(windowspecific) +add_subdirectory(windowbehaviour) +add_subdirectory(kwintabbox) +add_subdirectory(kcmsmserver) +add_subdirectory(workspaceoptions) +add_subdirectory(khotkeys) +endif ( Q_WS_X11 ) diff --git a/doc/kcontrol/autostart/CMakeLists.txt b/doc/kcontrol/autostart/CMakeLists.txt new file mode 100644 index 00000000..635f1ebf --- /dev/null +++ b/doc/kcontrol/autostart/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/autostart) diff --git a/doc/kcontrol/autostart/index.docbook b/doc/kcontrol/autostart/index.docbook new file mode 100644 index 00000000..0f715c25 --- /dev/null +++ b/doc/kcontrol/autostart/index.docbook @@ -0,0 +1,183 @@ + + + +]> +
+ +Autostart + +&Anne-Marie.Mahfouf; + + + +2013-12-05 +&kde; 4.12 + + +KDE +System Settings +autostart +desktop file +script file + + + + +Autostart Manager + +This module is a configuration tool for managing what programs start up with your personal &kde;. It allows you to add programs or scripts so they automatically start during the startup of your &kde; session and to manage them. + +Please note that in this module all changes are immediately applied. + +The program scans ~/.config/autostart/, your KDE Autostart folder ($KDEHOME/Autostart as default), $KDEHOME/env and $KDEHOME/shutdown folders to check what programs and scripts are already there and displays them. It allows you to manage them easily. + + +Note that you can change the location of your Autostart +folder in Account Details Paths +in the Common Appearance and Behaviour category of the &systemsettings; and set a different folder +than $KDEHOME/Autostart. + + +Files display +The main part of the module displays the programs that are loaded when &kde; starts and scripts that are run when &kde; starts, shutdowns or before &kde; starts. + + +Name + + +You cannot amend this column. It states the name of the program or script you want to start with &kde;. The name is extracted from the Desktop file from the Name key for a program and is the filename for a script. + + + + +Command + + +This column lists the commands that are run to start the program. Commands can be modified through the Properties button or by double clicking the program/script row. The command is extracted from the Desktop file from the Exec key. + + +For a script the command is the path to the script. + + + + +Status + + +This setting is only available for programs through Desktop files. You can keep a program in the Autostart folder but disable it from being run at &kde; start. Setting the program to Disabled will not run it on start. + + +Setting a program to Disabled sets the Desktop file Hidden property to true in the Autostart folder. + + + + +Run On + + +Programs (Desktop files) can only be run on startup. Scripts can be run on Startup, Shutdown or Pre-KDE Startup. This column allows you to change when your script is run. Startup is when &kde; starts, shutdown is when you log out of &kde; and pre-KDE startup is before &kde; starts. + + +Scripts and desktop files set to run on Startup are copied or symlinked in $KDEHOME/Autostart and will be run during &kde; startup. + + +Scripts set on to be ran on Shutdown are copied or symlinked in the $KDEHOME/shutdown directory and will be automatically run during &kde; shutdown after the user has logged out. + + +Scripts set to run at Pre-&kde; Startup are copied or symlinked in $KDEHOME/env and are sourced during &kde; startup (the startkde script will look for scripts here). + + +Only scripts with the sh extension can be read by &kde; for Pre-&kde; startup and Shutdown modes. + + + + + + + +Actions + +On the right you have some buttons to change the way Autostart is configure. You can add programs or scripts, remove them or change their properties. + + + +Add Program + + +Clicking this button displays the standard &kde; Choose Application dialog and allows you to choose which program you want to start. After choosing the program, clicking OK brings you the properties for this program. + + +This will copy the program Desktop file in your Autostart folder. + + + + +Add Script + + +This button opens a dialog which asks you for the location of the script you want to add. If you keep Create as symlink checked (default) then the script will be added as a symlink. If you uncheck this option then the script will be copied in the corresponding local folder. + + + +Remove + + +Remove will immediately remove the Desktop file for the program or the script or symbolic link in the Autostart folder. + + + +Properties + + +This button (only enabled for programs &ie; Desktop files) allows you to change the properties of the program or script. You have general properties, permissions properties, a preview when applicable and properties related to the application for programs. + + + +Advanced + + +This button only applies to programs (&ie; Desktop files). A dialog asks you if you only want the program to autostart only in &kde; (and not in other desktop environments you might run). By default, the program will autostart in all desktop environments you might run. Checking Autostart only in KDE will autostart the program only if you start the &kde; desktop environment. + + +This sets the value KDE to the OnlyShowIn key of the program Desktop file. + + + + + + +
+ + + diff --git a/doc/kcontrol/bell/CMakeLists.txt b/doc/kcontrol/bell/CMakeLists.txt new file mode 100644 index 00000000..bb5c3b37 --- /dev/null +++ b/doc/kcontrol/bell/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/bell) diff --git a/doc/kcontrol/bell/index.docbook b/doc/kcontrol/bell/index.docbook new file mode 100644 index 00000000..f904df75 --- /dev/null +++ b/doc/kcontrol/bell/index.docbook @@ -0,0 +1,64 @@ + + + +]> + +
+System Bell + + +PatDowler +MatthiasHoelzer +MikeMcBride + + + +2011-11-28 +&kde; 4.8 + + +The system bell or beep is a feature of the X server, which +attempts to make good use of the available hardware. + +&kde; normally does not use the system bell; instead using its +own system notifications, which could include log entries, message +popups, or its own beep. You can configure these in the +Manage Notifications &systemsettings; module. + +It is not always possible for the X server to actually make +a beep sound with exactly the parameters selected due to hardware +limitations. For example, on most PCs, volume control is not very good +so the X server seems to fake low volume with a reduced duration of +the sound. Thus, if the settings do not seem to do anything, this is +because the X server and/or the hardware do not support anything +better. + + Select Use system bell instead of system notification +then you are able to set the following parameters for the bell: + + + + +Volume (percentage of maximum volume) +Here you can customize the volume of the system bell. + + + +Pitch (in Hz) +Here you can customize the pitch of the system bell. + + + +Duration (in milliseconds) +Here you can customize the duration of the system bell. + + + + +For further customization of the bell, see the Accessibility &systemsettings; module. + +You can use the Test button to hear how +the current settings will sound. + +
diff --git a/doc/kcontrol/clock/CMakeLists.txt b/doc/kcontrol/clock/CMakeLists.txt new file mode 100644 index 00000000..3cc3bc20 --- /dev/null +++ b/doc/kcontrol/clock/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/clock) diff --git a/doc/kcontrol/clock/index.docbook b/doc/kcontrol/clock/index.docbook new file mode 100644 index 00000000..5779367e --- /dev/null +++ b/doc/kcontrol/clock/index.docbook @@ -0,0 +1,90 @@ + + + +]> + +
+ +Date & Time + +&Mike.McBride; &Mike.McBride.mail; + + + +2013-12-05 +4.12 + + +KDE +Systemsettings +clock +date +time +set +configure + + + + + +Date & Time + +You can use this module to alter the system date and time, using a +convenient graphical interface. + +As these settings do not only affect you as a user, +but rather the whole system, you must have system administrator (root) access to change the system date and +time. If you do not have this access level, this module will only show +you the current settings, but your changes will not be saved. + + +Date and Time + +If you check Set date and time automatically you are able +to select a Time server from the drop down box and all other +settings in this dialog are disabled. + + +The applications rdate or ntpdate are used in +this module to fetch date and time from a time server. This happens when you log in to &kde; +while being online or when you later connect to the Internet and access to time +servers is possible. +Both applications are simple NTP clients that set a system's clock +to match the time obtained by communicating with one or more NTP servers. +This is not sufficient, however, for maintaining an accurate clock in the long run. +This is useful for occasionally setting the time on machines that do not have full-time +network access, such as laptops. + + +If you do not use a time server, you are able to set the date manually +using the lower half of the tab. Simply +choose your month and year using the controls at the top of the calendar +and the day of the month by clicking on the day in the +calendar. +Use the controls at the bottom of the calendar +to select the current date, enter the date in the edit box or select the +week of the year from the drop down box. + +You set the time using the spin boxes at the bottom of the analog clock. +You can also directly enter your value. + + + + +Time Zone +To set a new time zone, simply select your area from the list below. +Use the filter box to find the desired Area or Region. + + + + +
diff --git a/doc/kcontrol/colors/CMakeLists.txt b/doc/kcontrol/colors/CMakeLists.txt new file mode 100644 index 00000000..a8b87056 --- /dev/null +++ b/doc/kcontrol/colors/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/colors) diff --git a/doc/kcontrol/colors/index.docbook b/doc/kcontrol/colors/index.docbook new file mode 100644 index 00000000..6b6def0c --- /dev/null +++ b/doc/kcontrol/colors/index.docbook @@ -0,0 +1,399 @@ + + + + +]> + +
+ +Colors + +&Matthew.Woehlke; &Matthew.Woehlke.mail; + + + +2013-11-05 +4.12 + + +KDE +KControl +color +kcm + + + + +Colors + + + Introduction + + The Color Selection module is comprised of several sections: + + + + The Scheme tab, + used to manage schemes. + + + The Options tab, + used to change the options of the current scheme. + + + The Colors tab, + used to change the colors of the current scheme. + + + The state effects tabs + (Inactive, Disabled), used to + change the state effects of the current scheme. + + + + Note: This documentation will sometimes refer to the + "current" scheme, or the "active" scheme. + The "current" scheme is the set of colors and color scheme options + that was most recently applied, &ie; what you would get if you choose + Cancel. The "active" scheme is the set of + colors as has been most recently edited by you, &ie; what you would get if + you choose Apply. + + + + Scheme Management + + The Scheme tab lets you manage the color schemes + on your machine. Only one scheme is active at once, but you may save schemes, + allowing you to quickly change the scheme later. When you have created a + scheme you like, you can save it with Save Scheme.... + You can remove schemes using Remove Scheme. + Note that system schemes cannot be removed; trying to do so will display an + error. + + &kde; ships with several schemes. If you have an Internet connection, + you can also browse and retrieve user-created schemes using Get + New Schemes.... + + + Importing Schemes + + You can also import schemes that you have downloaded or otherwise + obtained, as well as import &kde; 3 schemes. &kde; 4 color schemes are + named like "*.colors", while &kde; 3 schemes are named like + "*.kcsrc". + + Because &kde; 4 has many more color roles than &kde;, importing a + &kde; 3 scheme is different from importing a &kde; 4 scheme. When a + &kde; 4 scheme is imported, it becomes part of your saved scheme + collection. When a &kde; 3 scheme is imported, the colors that exist in + &kde; 3 are overlaid onto the active scheme, and the result is not + automatically saved into your collection. After importing a &kde; 3 scheme, + you will likely need to adjust the colors that are new in &kde; 4, as well + as the state effects. For best results, before importing a &kde; 3 scheme, + select a similar &kde; 4 scheme (you do not need to apply the scheme before + importing). + + + + + Color Scheme Options + + The Options tab allows you to change some + properties that deal with how the color scheme is used, as well as some + options that change the color scheme that are different from actually + assigning colors. + + + Apply inactive window color effects + — If checked, state effects (see below) will be applied to inactive + windows. This can help visually identify active versus inactive windows, + and may have aesthetic value, depending on your taste. However, some + users feel that it causes distracting "flickering" since + windows must be repainted when they become inactive. Unlike desktop + effects, color state effects do not require compositing support and will + work on all systems, however they will only work on &kde; 4 applications. + + Inactive selection changes color + — If checked, the current selection in elements which do not have + input focus will be drawn using a different color. This can assist visual + identification of the element with input focus in some applications, + especially those which simultaneously display several lists. + + Shade sorted column in lists + — If checked, multi-column lists will use a slightly different + color to paint the column whose information is being used to sort the + items in the list. + + Apply colors to non-KDE4 applications + — If checked, &kde; will attempt to export its color scheme so that + non-&kde; 4 applications will use the same colors. Most applications will + honor the exported scheme to varying degrees, though some may have bugs + or otherwise not honor the exported scheme. + + Contrast + — This slider controls the contrast of shaded elements, such as + frame borders and the "3D" effects used by most styles. A lower + value gives less contrast and therefore softer edges, while a higher + value makes such edges "stand out" more. + + + + + + + Colors + + The Colors tab allows you to change the colors in + the active color scheme. + + Creating or changing a scheme is a simple matter of clicking on the + swatch in the color list and selecting a new color. You can check your + changes at any time by pressing Apply. It is suggested + that you save your scheme (via the Scheme tab) when you + are done. + + The Common Colors set, which is displayed + initially, is not actually a "set" in the sense used by &kde; (see + next section), but presents a number of color roles in a way that makes it + easier to edit the scheme as a whole. When creating a new color scheme, you + will usually change these colors first, and use the other sets to tweak + specific colors if needed. + + Note that Common Colors makes available roles from + all sets. For example, "View Background" here is shorthand for the + Normal Background role from the View set. Also, setting colors that do not + refer to a specific set will change that color in all + sets. (As an exception, "Inactive Text" will change the color for + all sets except for Selection; there is a separate + "Selection Inactive Text" for Inactive Text in the Selection set.) + Some roles may not be visible under Common Colors at + all, and can only be changed (if needed) by selecting the appropriate + set. + + + Color Sets + + &kde; 4 breaks the color scheme into several sets based on the type + of user interface element, as follows: + + View — + information presentation elements, such as lists, trees, text input boxes, etc. + + Window — + window elements that are not buttons or views. + + Button — + buttons and similar elements. + + Selection — + selected text and items. + + Tooltip — + tool tips, "What's This" tips, and similar elements. + + Window Manager — + window title bars and related elements. + + + + Each set contains a number of color roles. Except for the Window + Manager colors, each set has the same roles. All colors are associated with + one of the above sets. + + + + Color Roles + + Each color set is made up of a number of roles which are available in + all other sets. (The Window Manager set is an exception; it has its own + unique roles that do not exist in any other set, and does not use the same + roles as the other sets.) In addition to the obvious Normal Text and Normal + Background, these roles are as follows: + + + Alternate Background — + used when there is a need to subtly change the background to aid in + item association. This might be used ⪚ as the background of a + heading, but is mostly used for alternating rows in lists, especially + multi-column lists, to aid in visually tracking rows. + + Link Text — + used for hyperlinks or to otherwise indicate "something which may + be visited", or to show relationships. + + Visited Text — + used for "something (⪚ a hyperlink) that has been + visited", or to indicate something that is "old". + + Active Text — + used to indicate an active element or attract attention, ⪚ alerts, + notifications; also for hovered hyperlinks. + + Inactive Text — + used for text which should be unobtrusive, ⪚ comments, + "subtitles", unimportant information, etc. + + Negative Text — + used for errors, failure notices, notifications that an action may be + dangerous (⪚ unsafe web page or security context), etc. + + Neutral Text — + used to draw attention when another role is not appropriate; ⪚ + warnings, to indicate secure/encrypted content, etc. + + Positive Text — + used for success notices, to indicate trusted content, etc. + + + + As well as the text roles, there are a few additional + "decoration" roles that are used for drawing lines or shading + UI elements (while the above may, in appropriate circumstances, also be + used for this purpose, the following are specifically + not meant for drawing text). These are: + + + Focus Decoration — + used to indicate the item which has active input focus. + + Hover Decoration — + used for mouse-over effects, ⪚ the "illumination" effects for + buttons. + + + + In addition, except for Inactive Text, there is a corresponding + background role for each of the text roles. Currently (except for Normal + and Alternate Background), these colors are not chosen by the user, but are + automatically determined based on Normal Background and the corresponding + Text color. These colors may be previewed by selecting one of the sets + other than "Common Colors". + + The choice of color role is left to the developer; the above are + guidelines intended to represent typical usage. + + + + Window Manager Colors + + As previously stated, the Window Manager set has its own roles, + independent of those in other sets. These are (currently) only accessible + via Common Colors, and are as follows: + + + Active Titlebar — + used to draw the title bar background, borders, and/or decorations for + the active window (that is, the one with input focus). Not all window + decorations will use this in the same way, and some may even use the + Normal Background from the Window set to draw the title bar. + + Active Titlebar Text — + used to draw the title bar text when Active Titlebar is used to draw + the title bar background. May also be used for other foreground + elements which use Active Titlebar as the background. + + + + The Inactive Titlebar [Text] roles are the same as the above, but for + inactive windows, rather than active windows. + + + + + + Color State Effects + + Color state effects are applied to interface elements in the inactive + (windows that do not have focus; only if Apply inactive window + color effects is enabled) or disabled states. By changing the + effects, the appearance of elements in these states can be changed. Usually, + inactive elements will have reduced contrast (text fades slightly into the + background) and may have slightly reduced intensity, while disabled elements + will have strongly reduced contrast and are often notably darker or lighter. + + + Three types of effect may be applied to each state (with the effects + of the two states being independent). These are Intensity, Color and + Contrast. The first two (Intensity, Color) control the overall color, while + the last (Contrast) deals with the foreground colors relative to the + background. + + + Intensity + + Intensity allows the overall color to be lightened or darkened. + Setting the slider to the middle produces no change. The available effects + are: + + + Shade — + makes everything lighter or darker in a controlled manner. Each + "tick" on the slider increases or decreases the overall + intensity (&ie; perceived brightness) by an absolute amount. + + Darken — + changes the intensity to a percentage of the initial value. A slider + setting halfway between middle and maximum results in a color half as + intense as the original. The minimum gives a color twice as intense as + the original. + + Lighten — + conceptually the opposite of darken; lighten can be thought of as + working with "distance from white", where darken works with + "distance from black". The minimum is a color twice as + "far" from white as the original, while halfway between + middle and maximum gives an intensity halfway between the original + color and white. + + + + + + Color + + Color also changes the overall color, but is not limited to + intensity. The available effects are: + + + Desaturate — + changes the relative chroma. The middle setting produces no change; + maximum gives a gray whose perceptual intensity equals that of the + original color. Lower settings increase the chroma, giving a color that + is less gray / more "vibrant" than the original. + + Fade — + smoothly blends the original color into a reference color. The minimum + setting on the slider produces no change; maximum gives the reference + color. + + Tint — + similar to Fade, except that the color (hue and chroma) changes more + quickly while the intensity changes more slowly as the slider value is + increased. + + + + + + Contrast + + The contrast effects are similar to the color effects, except they + apply to the text, using the background color as the reference color, and + desaturate is not available. Fade produces text that "fades out" + more quickly, but keeps its color longer, while Tint produces text that + changes color to match the background more quickly while keeping a greater + intensity contrast for longer (where "longer" means higher + settings on the slider). For Contrast effects, the minimum setting on the + slider produces no change, while maximum causes the text to completely + disappear into the background. + + + + + + +
+ diff --git a/doc/kcontrol/cursortheme/CMakeLists.txt b/doc/kcontrol/cursortheme/CMakeLists.txt new file mode 100644 index 00000000..ad525ad4 --- /dev/null +++ b/doc/kcontrol/cursortheme/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/cursortheme) diff --git a/doc/kcontrol/cursortheme/index.docbook b/doc/kcontrol/cursortheme/index.docbook new file mode 100644 index 00000000..e316df8c --- /dev/null +++ b/doc/kcontrol/cursortheme/index.docbook @@ -0,0 +1,59 @@ + + + +]> + +
+ +Cursor Theme + +&Mike.McBride; &Mike.McBride.mail; +&Brad.Hards; &Brad.Hards.mail; + + + +2013-06-02 +&kde; 4.11 + + +This is the documentation for the &kde; &systemsettings; module to +customize the mouse cursor appearance. + + + + +KDE +Systemsettings +mouse +cursor + + + + +This module allows you to select from a number of installed cursor themes. +A preview of the cursor display is shown above the list box. + + +The features provided by this module may not be available on some systems. +Your system may need to be updated to support cursor themes. + + + +If you have additional cursor themes available, you can install and remove +them using the buttons right to the list box. Note that you cannot remove the default themes. + + +Use the Get New Themes button to launch the Get Hot New Stuff dialog and +download additional themes from the Internet. + +Some themes allow to +choose the cursor size using the combobox below to the label Size. + + + +The size can be set to the resolution dependent or one of the sizes available for your system. + + +
diff --git a/doc/kcontrol/desktop/CMakeLists.txt b/doc/kcontrol/desktop/CMakeLists.txt new file mode 100644 index 00000000..2728822f --- /dev/null +++ b/doc/kcontrol/desktop/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/desktop) diff --git a/doc/kcontrol/desktop/index.docbook b/doc/kcontrol/desktop/index.docbook new file mode 100644 index 00000000..e4a08926 --- /dev/null +++ b/doc/kcontrol/desktop/index.docbook @@ -0,0 +1,141 @@ + + + +]> + +
+Virtual Desktops + + + +&Mike.McBride; &Mike.McBride.mail; +&Jost.Schenck; &Jost.Schenck.mail; + + + +2013-06-02 +4.11 + + +KDE +Systemsettings +desktop + + + + + + +Virtual Desktops + + +<guilabel>Desktops</guilabel> + +&kde; offers you the possibility to have several virtual +desktops. In this tab you can configure the number of desktops, the number of rows in the Pager icon +as well as their names. Just use the input box to adjust the number of +desktops. You can assign names to the desktops by entering text into the +text fields below. + +Enable Different widgets for each desktop +to use independent widgets and wallpapers on each individual desktop. + + + + + +<guilabel>Switching</guilabel> + + + +Desktop navigation wraps around +Enable this option if you want keyboard or active desktop border navigation +beyond the edge of a desktop to take you to the opposite edge of the new desktop. + + + + +Desktop Effect Animation +Select No Animation, Slide, +Desktop Cube Animation or Fade Desktop +from the drop down box. If the selected animation has settings options, click on the +tools icon on the right of the drop down box to launch a configuration dialog. + + + + +Desktop Switch On-Screen Display +Enable this option if you want to have an on-screen display for desktop switching. + + + + +Show desktop layout indicators +Enabling this option will show a small preview of the desktop layout +indicating the selected desktop. + + + + +Shortcuts +This section displays the configured shortcuts for switching the desktops +and allows you to edit them. + + + + + +Scrolling the mouse wheel over an empty space on the +desktop or on the Pager icon in the panel will change to the next +virtual desktop numerically, in the direction you scrolled (either up or down). + + + + +
diff --git a/doc/kcontrol/desktopthemedetails/CMakeLists.txt b/doc/kcontrol/desktopthemedetails/CMakeLists.txt new file mode 100644 index 00000000..0714fb27 --- /dev/null +++ b/doc/kcontrol/desktopthemedetails/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/desktopthemedetails) diff --git a/doc/kcontrol/desktopthemedetails/clicking-apply.png b/doc/kcontrol/desktopthemedetails/clicking-apply.png new file mode 100644 index 00000000..f57723b4 Binary files /dev/null and b/doc/kcontrol/desktopthemedetails/clicking-apply.png differ diff --git a/doc/kcontrol/desktopthemedetails/customizing.png b/doc/kcontrol/desktopthemedetails/customizing.png new file mode 100644 index 00000000..a16743fd Binary files /dev/null and b/doc/kcontrol/desktopthemedetails/customizing.png differ diff --git a/doc/kcontrol/desktopthemedetails/index.docbook b/doc/kcontrol/desktopthemedetails/index.docbook new file mode 100644 index 00000000..adc35ceb --- /dev/null +++ b/doc/kcontrol/desktopthemedetails/index.docbook @@ -0,0 +1,182 @@ + + + +]> +
+ +Desktop Theme + + +Andrew +Lake + + + +2013-06-02 +&kde; 4.11 + + +KDE +System Settings +desktop +theme +plasma + + + + +Theme tab + +A list of available themes is displayed on this tab. Select a theme by clicking on an item in the list. + +Use the Get New Themes button to launch the Get Hot New Stuff dialog and +download additional themes from the Internet. + + + + +Details tab + +A &kde; plasma desktop theme is made up of several components or items, +consisting mostly in svg backgrounds and colors schemes. This module allows you +to customize your desktop Plasma theme and to replace theme items +with items from other themes or from files. + + +Desktop theme items consist in panel theme item, kickoff theme item, +analog clock, ... + + +If you want to change your current theme for a full new theme (for example from +Air to Glassified) then you can do so in the Theme tab. + + + +Quick start +First download one or several themes you want to use to customize your +desktop items by clicking the Get New Themes... +button in the Theme tab. + +All the available themes will be displayed on top, the current one being highlighted. + +In the theme list, select a base theme that will be used for most widgets and start +customizing each item you want to change with a new theme, for example you can +have the panel in Glassified theme, the widget +backgrounds in Air and so on. + +Here Air is the theme for most widgets and we changed the panel background +to Glassified, the Analog clock to Glassified and the Notes to Oxygen. + + + +Customizing your plasma theme + + + + + + Customizing your plasma theme + + + + + + +Clicking the Apply will create a new theme named +(Customized) and will apply it to your desktop. + + + + +Creating a custom theme +When the module is opened, it will show items from the current desktop +theme. If you would like to start customizing with a different theme, select it +from the box above the list of theme items. This theme from the box is the +starting theme, the base for your new customized desktop theme. + + +In the list of items, for each item you would like to replace, select +replacement item from the drop list for that item. You may select the +corresponding item from another theme, or you may select a file. &plasma; +desktop theme items are svg files, except for the color scheme which is a &kde; +color scheme file. + + + +Click Apply when all the changes have been made. This +will create a new theme named (Customized) which you can +select from the Appearance Settings dialog on the desktop. + + + + +Your custom theme + + + + + + Customized + + + + + + +The theme items listed are the most visible components of the plasma +desktop theme. Other theme components are not listed. Your newly created +theme will use these unlisted components from the theme that you selected at +the start of creating the customized theme. + + + + +Naming a custom theme + +To provide a name for your customized theme, click on the +More checkbox and +enter the name of the theme. You may also provide your name (author), a theme +version and a description of your theme. Click Apply +when done. + + + + +Removing a theme + +Select the theme you would like to remove from the box above the list of +theme items. Click on the More check box. Click the +Remove Theme button to +remove the selected theme. + + + + +Exporting a theme to a file + +You can share your newly customized theme with the community by exporting the +theme to a file. Select your customized theme from the box above the list +of theme items. Click on the More check box. Click the +Export Theme to +File.... Enter the name of the zip file to which the theme will be +saved. + + + + +
+ + diff --git a/doc/kcontrol/fontinst/CMakeLists.txt b/doc/kcontrol/fontinst/CMakeLists.txt new file mode 100644 index 00000000..bd208d21 --- /dev/null +++ b/doc/kcontrol/fontinst/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/fontinst) diff --git a/doc/kcontrol/fontinst/index.docbook b/doc/kcontrol/fontinst/index.docbook new file mode 100644 index 00000000..cfeff1c4 --- /dev/null +++ b/doc/kcontrol/fontinst/index.docbook @@ -0,0 +1,109 @@ + + + +]> + +
+Font Management + + +&Craig.Drummond; &Craig.Drummond.Mail; + + + + +2013-06-19 +&kde; 4.11 + + +KDE +Systemsettings +fonts + + + + +Font Management + +This module is responsible for installing, un-installing, previewing and managing your fonts. + + +Font Groups +There are 4 special pre-defined font groups: + + + All Fonts This will display all fonts, both personal and system-wide. + Personal Fonts The fonts shown will be your personal fonts, and will not be available to other users. + System Fonts The fonts shown will be those available to all users. Installing a font system-wide, or removing a system-wide font, will require administrator privileges. + Unclassified This will list all fonts that have not been placed into any user-defined groups. This group will only appear if you have some user-defined groups. + +To add a font to a group, drag it from the list of fonts onto a group. To remove a font from a group, drag the font onto the All Fonts group. +Below this list you find buttons to create a new group, remove a group and enable or disable the fonts in the current group. +In the context menu of this list you have additional menuitems to print font samples and export a font to a zip archive. + + +Enabling and Disabling +Users with many fonts may find it useful to only have certain fonts enabled (or active) at certain times. To facilitate this, this module will allow you to disable individual fonts, or whole groups of fonts. Disabling a font does not remove the font from the system, it simply hides it so that it no longer appears within applications. Re-enabling a font will then allow it to be used. + + + + + +Font List + +The main display is a list of the installed fonts, grouped via the fonts' family name - the number in square brackets represents the number of installed styles for that family. e.g. The Times font may be listed as: + + + Times [4] + + Regular + Italic + Bold + Bold Italic + + + + + +To install a font, press the Add... button, and select the desired fonts from within the file dialog. The selected font group will control where the fonts will be installed. +To un-install fonts, select the appropriate fonts from the list, and press the Delete... button. + +Click with the &RMB; to open a context menu with some additional actions like Enable, Disable, Print, Open in Font Viewer and Reload. + + +Font Filtering +A text field on top of the font preview allows you to filter the list of fonts. You can filter fonts based upon different categories: + + Family. + Style. + Foundry. + FontConfig match. This allows you to enter a family name, and see the family that fontconfig would actually use. + Font file type. + Font file name. + Font file location. + Writing system. + + + + +Get New Fonts +New fonts may be installed from local files, or downloaded from kde-look.org. The Get New Fonts entry in the tool button (located above the group list), allows you to install fonts from kde-look.org. The fonts downloaded in this manner will be installed into your Personal Fonts group. To install system-wide, you will need to move them to the System Fonts group - this may be achieved by dragging the fonts over the System Fonts group entry and will require administrator privileges. + + + + + +Duplicate Fonts +If you have lots of fonts installed on your system it is possible that you may have duplicates. +Click on the tools icon above the group list and select the Scan For Duplicate Fonts... tool, a simple tool that will scan your system looking for fonts that have multiple files associated with them. For example, if you have times.ttf and times.TTF installed in /usr/local/share/fonts the underlying font mechanism (called FontConfig) will only see one of these. So, if you un-installed the font, it would re-appear, as only one of the files would have been removed. Running this tool will produce a dialog listing each font that has multiple files, and the corresponding list of files. To select a file for deletion, click on the column containing the trash can icon. + + + +Preview +This displays a preview text in different font sizes. +Using the context menu enables you to zoom in and out, select a preview type (Standard Preview or All Characters) and change the preview text. + + +
diff --git a/doc/kcontrol/fonts/CMakeLists.txt b/doc/kcontrol/fonts/CMakeLists.txt new file mode 100644 index 00000000..6238f15e --- /dev/null +++ b/doc/kcontrol/fonts/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/fonts) diff --git a/doc/kcontrol/fonts/adjust-all.png b/doc/kcontrol/fonts/adjust-all.png new file mode 100644 index 00000000..506a6179 Binary files /dev/null and b/doc/kcontrol/fonts/adjust-all.png differ diff --git a/doc/kcontrol/fonts/anti-aliasing.png b/doc/kcontrol/fonts/anti-aliasing.png new file mode 100644 index 00000000..d88cacae Binary files /dev/null and b/doc/kcontrol/fonts/anti-aliasing.png differ diff --git a/doc/kcontrol/fonts/index.docbook b/doc/kcontrol/fonts/index.docbook new file mode 100644 index 00000000..1bb5e2e2 --- /dev/null +++ b/doc/kcontrol/fonts/index.docbook @@ -0,0 +1,169 @@ + + + +]> + +
+ +Fonts + +&Mike.McBride; &Mike.McBride.mail; +&Anne-Marie.Mahfouf; &Anne-Marie.Mahfouf.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +KControl +fonts + + + + + +Fonts + +This module is designed to allow you to easily select different +fonts for different parts of the &kde; Desktop. + + + +Here's a screenshot of the fonts settings module + + + + + + The fonts settings module + + + + + +The panel consists of different font groups to give you a lot of +flexibility in configuring your fonts: + + +General: Used everywhere when the other font +groups do not apply + +Fixed width: Anywhere a +non-proportional font is specified + +Small: When small fonts are used + +Toolbar: Font used in &kde; application +toolbars + +Menu: Font used in &kde; application +menus + +Window title: Font used in the window +title + +Taskbar: Font used in the taskbar +panel applet + +Desktop: Font used on the desktop +to label icons + + + +Each font has a corresponding Choose... +button. By clicking on this button, a dialog box appears. You can +use this dialog box to choose a new font, a font style and size. +Then press Ok. + +An example of the font you have chosen will be displayed in the space +between the font group name and the Choose... +button. + +When you are done, simply click OK and +all the necessary components of &kde; will be restarted so your changes +can take affect immediately. + +The Adjust All Fonts... button allows you to +quickly set properties for all the fonts selected +above. A font selection dialog similar to the standard one will +appear, but you will notice checkboxes that allow you to change the +Font, Font style or +Size independently of each other. You can +choose any one, two, or three of these options, and they will be +applied to all the font groups. + + + +Adjusting all fonts + + + + + + The Adjust All Fonts... dialog + + + + + +For example, if you have selected several different font faces +above, and realize they are all a size too big (this often happens +when you change screen resolution, for instance), you can apply a new +font size to all the fonts, without affecting your customized font +faces and styles. + + +Anti-aliasing text + +Default anti-aliasing settings are those used system wide by your distribution and labelled System Settings. You can disable all anti-aliasing by choosing Disabled in the drop down box. + +To use and set up anti-aliasing, simply choose Enabled from the box on the right of Use anti-aliasing:. The Configure... button will then get enabled and clicking on it will bring you a dialog to configure anti-aliasing. + + + +Anti-aliasing properties + + + + + + The anti-aliasing properties dialog + + + + + +Placing a mark in the Exclude range: checkbox will allow you to specify which range of fonts will not be anti-aliased. This range is specified +with the two combo boxes on the same line. + +You can also choose the method that &kde; uses to create an anti-alias +look to your fonts, and how strongly it should be applied. If you are not +familiar with the individual methods, you should leave this option +alone. + + + + +The ability to use anti-aliased fonts and icons requires that you have +support in both X and the &Qt; toolkit, that you have suitable fonts +installed, and that you are using the built-in font serving capabilities +of the X server. If you still are having problems, please contact the +appropriate &kde; mailing list, or check the +FAQ. + + + + +Fonts DPI + +Force fonts DPI: proposes you an alternate DPI other than your system one which is used as default when this setting is on Disabled. You can check what DPI your X server is set to by running xdpyinfo | grep resolution in a terminal window and then change the DPI using the drop down box. This will be applied to newly started applications only. + + + + +
diff --git a/doc/kcontrol/fonts/main.png b/doc/kcontrol/fonts/main.png new file mode 100644 index 00000000..2c0346c4 Binary files /dev/null and b/doc/kcontrol/fonts/main.png differ diff --git a/doc/kcontrol/joystick/CMakeLists.txt b/doc/kcontrol/joystick/CMakeLists.txt new file mode 100644 index 00000000..eb9c4901 --- /dev/null +++ b/doc/kcontrol/joystick/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/joystick) diff --git a/doc/kcontrol/joystick/index.docbook b/doc/kcontrol/joystick/index.docbook new file mode 100644 index 00000000..36a496c5 --- /dev/null +++ b/doc/kcontrol/joystick/index.docbook @@ -0,0 +1,137 @@ + + + +]> +
+ +Joystick + + +Michael +Anderson + +
nosrednaekim@gmail.com
+
+
+ +
+ +2013-12-05 +4.12 + + +KDE +System Settings +joystick +calibrate + +
+ + +Joystick configuration module + +This module provides an interface to calibrate your joystick device as well as +see which functions on your joystick are mapped to which logical button or +axis. + + + +Here's a screenshot of the joystick module + + + + + + The joystick module + + + + + + +Device + + +Here you can see the logical location of the device. If you have more +than one joystick device, you can also select which one to configure. + + + + +Position + + +The plotted location of the X and Y axes of the joystick. Enable Show trace +to plot the path of the joystick from one point to another. + + +If the joystick cannot reach every point on this graph, or if it does not center correctly, you need to calibrate your device. + + + + +Buttons + + +A place to see the pressed state of buttons on your joystick and if the buttons +are mapped correctly. When a joystick button is pressed, PRESSED will appear +next to the logical number (as the computer sees it) of the button which was +pressed. + + + + +Axes + + +This displays the numerical values of the axis positions. 0 is centered and the +maximum and minimum values depend on the joystick and the particular axis. + + + + +Calibrate + + +Clicking on Calibrate will open a dialog to calibrate every axis on your joystick. + + + + +Calibrating your joystick + + + + + + Calibrating your joystick + + + + + + +Each axis will have to be moved to the minimum position, then the center, and finally the +maximum position. A meter in the bottom left corner of the dialog will help +determine which way increases and which way decreases the values. + + + + + +
+ + diff --git a/doc/kcontrol/joystick/joystick-calibration.png b/doc/kcontrol/joystick/joystick-calibration.png new file mode 100644 index 00000000..5ff3bda1 Binary files /dev/null and b/doc/kcontrol/joystick/joystick-calibration.png differ diff --git a/doc/kcontrol/joystick/joystick-main.png b/doc/kcontrol/joystick/joystick-main.png new file mode 100644 index 00000000..f5a8071f Binary files /dev/null and b/doc/kcontrol/joystick/joystick-main.png differ diff --git a/doc/kcontrol/kcmaccess/CMakeLists.txt b/doc/kcontrol/kcmaccess/CMakeLists.txt new file mode 100644 index 00000000..3f3a11cc --- /dev/null +++ b/doc/kcontrol/kcmaccess/CMakeLists.txt @@ -0,0 +1,4 @@ +########### install files ############### +# +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kcmaccess) diff --git a/doc/kcontrol/kcmaccess/index.docbook b/doc/kcontrol/kcmaccess/index.docbook new file mode 100644 index 00000000..99b6b5a9 --- /dev/null +++ b/doc/kcontrol/kcmaccess/index.docbook @@ -0,0 +1,264 @@ + + + +]> + +
+Accessibility + + +&Mike.McBride; &Mike.McBride.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +accessibility +keys +bell + + + + +Accessibility + + +Introduction + +This module is designed to help users who have difficulty hearing +audible cues, or who have difficulty using a keyboard. + + +The module is divided into four tabs: Bell, Modifier keys, Keyboard Filters and Activation Gestures. + + + +<guilabel>Bell</guilabel> + + +This panel is divided into an Audible Bell section +and a Visible Bell section. + + + +The top check box labeled Use System Bell, determines +whether the normal System bell rings. If this option is disabled, the +System bell will be silenced. + + + +The next check box down can be used to play a different sound whenever +the system bell is triggered. To activate, place a mark in the check +box labeled Use customized bell, and enter the +complete pathname to the sound file in the text box labeled +Sound to play. If you want, you can select the +Browse button to navigate through your filesystem +to find the exact file. + + + +For those users who have difficulty hearing the System bell, or those +users who have a silent computer, &kde; offers the visible bell. This +provides a visual signal (inverting the screen or flashing a color +across it) when the system bell would normally sound. + + + +To use the visible bell, first place a mark in the check box labeled +Use visible bell. + + + +You can then select between Invert screen, or +Flash screen. If you select Invert +screen, all colors on the screen will be reversed. If you +choose Flash screen, you can choose the color by +clicking the button to the right of the Flash +screen selection. + + + +The slider bar can be used to adjust the duration of the visible +bell. The default value is 500ms, or half a second. + + + + + +<guilabel>Modifier keys</guilabel> + +There are the two sections Sticky Keys +and Locking Keys to this panel. + + + +Use Sticky Keys + + +If this option is enabled, you can press and release the &Shift;, +&Alt; or &Ctrl; keys, and then press another key to get a key combo +(example: &Ctrl; &Alt; +Del could be done with &Ctrl; then &Alt; +then Del). + + + +Also in this section is a check box labeled Lock Sticky +Keys. If this check box is enabled, the &Alt;, &Ctrl; +and &Shift; keys stay selected until you +de-selected them. + + + +As an example: + + + +With Lock Sticky Keys disabled: + +If you press the &Shift; key then press the +F key, the computer interprets this as &Shift;F. Now if you +type a P, the computer interprets this as the letter p +(no shift). + + + + + +With Lock Sticky Keys enabled: + + +If you press the &Shift; key twice then press the F key, +the computer interprets this as &Shift;F. Now if you +type a P, the computer interprets this as the letter P +(&Shift;P). To +de-select the &Shift; key, press it again. + + + + + + + + + + + + + +<guilabel>Keyboard Filters</guilabel> + +There are two sections to this panel. + + + +Use slow keys + + +If this option is enabled, you must hold the key down for a +specified length of time (adjustable with the slider) before the +keystroke will be accepted. This helps prevent accidental key strokes. + + + + + +Use bounce keys + + +If this option is enabled, you must wait for a specified length of time +(configurable with the slider) before the next key press can be +accepted. This prevents accidental multiple key strokes. + + + + + + + + + + +<guilabel>Activation Gestures</guilabel> + +There are two sections to this panel. + + + +Activation Gestures with these options: + + + +Use gestures for activating sticky keys and slow keys +Here you can activate keyboard gestures that turn on the following features: +Mouse Keys: Press &Shift;+NumLock +Sticky keys: Press &Shift; key 5 consecutive times +Slow keys: Hold down &Shift; for 8 seconds +Turn sticky keys and slow keys off after a certain period of inactivity + + + + + + +Notification with these options: + + + +Use the system bell whenever a gesture is used to turn an accessibility +feature on or off + +Show a confirmation dialog whenever a keyboard accessibility feature is +turned on or off +If this option is checked, &kde; will show a confirmation dialog whenever a +keyboard accessibility feature is turned on or off. +Ensure you know what you are doing if you uncheck it, as the keyboard +accessibility settings will then always be applied without confirmation. + +Use &kde;'s system notification mechanism whenever a keyboard accessibility +feature is turned on or off + + + + + +Click the Configure Notifications button to open a dialog +which allows you to edit the notifications for status changes of all keys. + + + + + + +
diff --git a/doc/kcontrol/kcmsmserver/CMakeLists.txt b/doc/kcontrol/kcmsmserver/CMakeLists.txt new file mode 100644 index 00000000..954e9f31 --- /dev/null +++ b/doc/kcontrol/kcmsmserver/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +#KDE_LANG = en +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kcmsmserver) diff --git a/doc/kcontrol/kcmsmserver/index.docbook b/doc/kcontrol/kcmsmserver/index.docbook new file mode 100644 index 00000000..fe387e04 --- /dev/null +++ b/doc/kcontrol/kcmsmserver/index.docbook @@ -0,0 +1,122 @@ + + + +]> + +
+ +Session Management + +&Jost.Schenck; &Jost.Schenck.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +KControl +session +System Settings + + + + +Session Management + + +Use + +In this &systemsettings; module you can configure &kde;'s session +manager and logout settings. + +Session management refers to &kde;'s ability to save the state +of applications and windows when you log out of &kde; and restore them +when you log back in. + + +General + + +Confirm logout + +If this option is checked, when logging out, &kde; will display a +dialog asking for confirmation. In this dialog you can also choose +whether you want to restore your current session when you login the next +time. + + + +Offer shutdown options + +If this option is checked, &kde; will offer a choice of actions during +logout. These include simply ending the current session (the +action performed if shutdown options are not enabled) turning off the +computer, or restarting the computer. + + + + + + +Default Leave Option +You can configure what should happen by default when you log out of +&kde;. These options are not possible on all operating systems, and some of +them may not appear unless you are using &kdm; as your login manager. + +The options available are self explanatory, if you are in doubt, +leave the default settings. They are: + + +End current session (this is the default) +Turn off computer +Restart computer + + + + +On Login +You may choose one of three options on what should happen when +you log into &kde;: + + + +Restore previous session +If this option is checked, &kde; will save your current +session's state when you logout. &kde; will restore your session on the +next login, so you can continue to work with a desktop just like you +left it. + + + +Restore manually saved session +Instead of restoring &kde; to the state it was when +you logged out last, it will be restored to a specific state that you +have saved manually. +If this option is checked, the start menu offers an additional item +LeaveSave Session. + + + +Start with an empty session + +If you choose this option, &kde; will never restore sessions that it has saved. + + + +Finally, you can enter a colon (:) or comma (,) +separated list of applications that should not be saved in sessions, +and therefore will not be started when restoring a session. For example +xterm:konsole or xterm,konsole. + + + + + + + +
+ diff --git a/doc/kcontrol/kcmstyle/CMakeLists.txt b/doc/kcontrol/kcmstyle/CMakeLists.txt new file mode 100644 index 00000000..6a3947ea --- /dev/null +++ b/doc/kcontrol/kcmstyle/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kcmstyle) diff --git a/doc/kcontrol/kcmstyle/index.docbook b/doc/kcontrol/kcmstyle/index.docbook new file mode 100644 index 00000000..faf1a682 --- /dev/null +++ b/doc/kcontrol/kcmstyle/index.docbook @@ -0,0 +1,238 @@ + + + +]> + +
+ + +Style + +&Mike.McBride; &Mike.McBride.mail; + + + +2013-06-02 +&kde; 4.11 + + +KDE +System Settings +style + + + +Style + + +Introduction + +This module is used to configure how the individual widgets are +drawn by &kde;. + +A Widget is a commonly-used +programmer's term for referring to User Interface elements such as +buttons, menus, and scroll bars. You can think of them as the +fundamental pieces that are assembled to make your +application. + +You can configure how the widgets are drawn with this module, +but to change the color of the widgets, you should refer to the +section entitled Colors. + +This panel is divided into two tabs: Applications +and Fine Tuning. + + +<guilabel>Applications</guilabel> tab + +The top drop down box, labeled Widget Style +contains a list of the pre-defined styles. +Each style has a name, and a brief description. + +To change styles, simply click on the style name, and a preview +of the style will be displayed in the preview box below the style list. + + If a style is configurable, the Configure... button +at the right side of the drop down box is enabled and can be used to open +a dialog to select further settings. + + + + + + +<guilabel>Fine Tuning</guilabel> tab + + + + +Graphical effects + +&kde; applications will run internal animations with the selected display resolution and CPU usage. + + + + +Show icons on buttons + +If this option is selected, action buttons (like OK and +Apply) will have a small icon located within them to act +as a visual reference. If this option is not selected, then only text +will appear on the button. + + + + +Show icons in menus + +If this option is selected, &kde; applications will show small icons alongside +most menu items. If this option is not selected, then only text +will appear in the menus. Changes to the visibility of menu icons will only affect newly started +applications. + + + + +Main toolbar text, Secondary toolbar text + +These drop down boxes lets you determine where on the button in both toolbars the +text name of the button will appear as the default. +If No Text is selected, then there is no text on the toolbar buttons. +If Text Only is selected, then the button's icon is replaced with a text name of +the button. If Text Beside Icons is selected, then the name of the button +will be placed to the right of the icon. +If Text Below Icons is selected, the default will be to have the text +of the button below the icon. + +This option only specifies the default location. +Each application can override the setting used in this panel. + + + + +Menubar style + +In application: The classic menubar at the top of the application window. +Title bar button: The window has an additional menu button top left. +All changes will take effect only for newly started applications. +Top screen menubar: This will turn on a menubar at the top of the screen that +is hidden by default and revealed on mouse over or a menu button on the window decoration. +This menubar will reflect the menu options of the active application. +Only export: for use by plasma runners + applets. +To use this feature you need a KRunner plugin like Appmenu action launcher. +Select an application, press &Alt;F2 +and type the menu action you want to perform. + + + + + + + + + + + +
diff --git a/doc/kcontrol/keyboard/CMakeLists.txt b/doc/kcontrol/keyboard/CMakeLists.txt new file mode 100644 index 00000000..23797c03 --- /dev/null +++ b/doc/kcontrol/keyboard/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/keyboard) diff --git a/doc/kcontrol/keyboard/index.docbook b/doc/kcontrol/keyboard/index.docbook new file mode 100644 index 00000000..31c9dcdc --- /dev/null +++ b/doc/kcontrol/keyboard/index.docbook @@ -0,0 +1,218 @@ + + + +]> + +
+Keyboard + + + +&Mike.McBride; &Mike.McBride.mail; +&Anne-Marie.Mahfouf; &Anne-Marie.Mahfouf.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +System Settings +keyboard + + + +This module allows you to choose how your keyboard works. + +There are three tabs in this module. + + +The Hardware tab +The actual effect of setting these options depends upon the +features provided by your keyboard hardware and the X server on which +&kde; is running. As an example, you may find that changing the key +click volume has no effect because that feature is not available on your +system. + + + +Keyboard model: + + +Here you can set your keyboard model. This setting is independent of your +keyboard layout and refers to the "hardware" model, i.e. the way your +keyboard is manufactured. Modern keyboards that come with your computer usually +have two extra keys and are referred to as "104-key" models, which is +probably what you want if you do not know what kind of keyboard you have. + + + + + +NumLock on KDE Startup + +You can choose to either always Turn on or +Turn off the NumLock when &kde; starts, or you can +choose to have &kde; leave NumLock at whatever it was set to before &kde; +started up. + + + + +Keyboard Repeat + +When this option is turned on, pressing and holding down a key +emits the same character repeatedly until the key is released. Pressing +and holding the key will have the same effect as pressing it multiple +times in succession. + Almost all users will want to have this option enabled, because it +makes navigating through documents with the arrow keys significantly +easier. + + + +Delay + +This option allows you to set the delay after which a pressed +key will start generating keycodes. + + + +Rate + +This option allows you to set the rate at which keycodes are +generated while a key is pressed. + + + +Key click volume + +If supported, this option allows you to hear audible clicks from +your computer's speakers when you press the keys on your keyboard. In +essence, this simulates the click of a mechanical +type-writer. You can change the loudness of the key click feedback by +dragging the slider button. Setting the volume to 0% by moving the slider +to the left turns off the key click. +Type some characters into the Test area text box to +verify the volume you selected. +Many computers won't support this function. +Very few people would choose to enable this option, since it +generally annoys everyone else in the room. However, if your heart +yearns for the pre-soft-key era, this may help you to re-experience the +warm sentimentality of days-gone-by. + + + + + + + + + + + +The Layouts tab +This tab lets you choose what keyboard layouts you want to use, what +indicator you want in the system tray, how you want to switch and which +shortcuts you will use. + + + +Layout Indicator + +You can choose to Show layout indicator +which will show the language iso name in the system tray. You can choose to +show the indicator even if you have a single layout enabled +and you can show the language flag instead of only the ISO code by checking +Show flag. + + + + +Switching Policy + +If you select Application or +Window switching policy, changing the keyboard layout will +only affect the current application or window. Global will +change the keyboard layout globally and Desktop will change +it only for the current virtual desktop. + + + + + +Shortcuts for Switching Layout + +Main shortcuts is a shortcut for switching +layouts which is handled by X.org. 3rd level shortcuts is a +shortcut for switching to a third level of the active layout (if it has one) +which is handled by X.org. It allows modifier-only shortcuts. +Alternative shortcut is a shortcut for switching layouts +which is handled by &kde;. It does not support modifier-only shortcuts and also +may not work in some situations (⪚ if popup is active or from screensaver). + + + + + +Configure layouts + +If you check Configure layouts you will be able to +add and remove keyboard layouts in order to switch between them when you need. + +Clicking on Add will open a dialog where you +will be able to choose the new keyboard layout you want to add as well as its +variant, label and shortcut. + + +The list of layouts right to the Layout label in the +Add Layout dialog can be narrowed down using +Limit selection by language drop-down list. You +can click on Preview button to preview chosen layout +in a separate window. + +You can order the layouts with the up and down buttons, the top one being +the default one. + + + + +Spare layouts + +This option can be enabled only if you have more than two layouts. +Spare layouts allow to toggle between small number of layouts easily +while keeping more layouts handy close by. For example you might use 3 +languages: English, Ukrainian and German but first two are used often +and third one just occasionally. In this case you can configure first +two as main layouts (setting Main layout count: 2) +and German one as spare one - when you toggle with +keyboard and left mouse button the switch will happen between main +layouts only but you can always choose 3rd layout with context menu. +When spare layout is chosen it replaces the last main layout (this is +done for technical reasons, usually global shortcuts work based on the +1st active layout so it's more reliable to preserve the 1st layout when +allowing to activate spare layouts). + +As X.org only allows to have 4 layouts to switch spare layouts feature +also allows to overcome this limitation: user can have up to 4 main +layouts (managed by X.org) but 4 more spare layouts allowed (managed by +layout switcher). Thus user can conveniently work with up to total of 8 +layouts (although the 4 spare layouts limit can be raised in the future). + + + + + + + + +The Advanced tab +In this tab, if you check Configure keyboard options +you will then be able to set a few options regarding some keys settings. You can +expand these options by clicking on the > symbol on the left of the option +then you choose your setting in the expanded list. + +
diff --git a/doc/kcontrol/keys/CMakeLists.txt b/doc/kcontrol/keys/CMakeLists.txt new file mode 100644 index 00000000..2fe4a4ef --- /dev/null +++ b/doc/kcontrol/keys/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/keys) diff --git a/doc/kcontrol/keys/index.docbook b/doc/kcontrol/keys/index.docbook new file mode 100644 index 00000000..f06fff13 --- /dev/null +++ b/doc/kcontrol/keys/index.docbook @@ -0,0 +1,202 @@ + + + +]> + +
+Shortcuts + + +&Mike.McBride; &Mike.McBride.mail; +&Jost.Schenck; &Jost.Schenck.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +KControl +key bindings +bindings +shortcuts + + + + +Shortcuts + + +Introduction + +While most of the functionality offered by &kde; can be accessed +using a simple point and click interface, many people +prefer using the keyboard for some tasks. Pressing something like + &Ctrl;F is often +just faster than moving your hands off the keyboard to the mouse, +opening the Edit menu and selecting +Find. + + As different people have different preferences about keyboard +shortcuts, &kde; offers full customization of key +bindings. A key binding or shortcut is a combination of an +action with a key or a combination of keys. + + + + +Standard Shortcuts and Global Shortcuts + +Standard shortcuts and Global shortcuts work just the same. +Actually, in a certain way standard or application shortcuts are +global as well. The only +difference is: + + +Standard keyboard shortcuts refer to actions +that are often available in applications, such as Save, Print, Copy +&etc; +Global keyboard shortcuts are shortcuts for +actions that make sense even when no application is opened. These +shortcuts usually refer to actions like switching desktops, manipulating +windows &etc; + + +Please note, that the application shortcuts configured here are +only the standard actions often found in +applications. Most applications will define their own actions as well, +for which you have to customize key bindings using the application's +key bindings dialog. + + +Standard Keyboard Shortcuts page +At the top of this dialog you see an input box, where you can +search interactively for shortcut names (⪚ Copy) or combination of keys +(⪚ Ctrl+C) by typing them literally here. +Below the search box you can see a list of key bindings, &ie; associations between actions +(⪚ Copy) shown in the Actions column and keys or combination of keys +(⪚ &Ctrl;C ) shown in the +Shortcut or Alternate column. + + + + + +Global Keyboard Shortcuts page +At the top of this page is a drop down box which allows you +to select a KDE component like KWin, Plasma Desktop &etc; +The defined shortcuts for the selected component are displayed in the +Action and Global column in the list view. +Click the File drop down box at the right to import/export a +Scheme, set all shortcuts to none and remove a component. +This page has the same search box as the Standard Keyboard +Shortcuts tab. + + + + +Configuring Key Bindings + +Configuring key bindings is pretty easy. In the middle of +these &systemsettings; modules you will find a list of available +actions. If there's a key binding configured for that action you will +find it in the columns right to it. Just select the action you want to +configure. + +After you have selected an action in the list you will notice that +this item is highlighted and you see two additional check boxes below +this item in the list view. There you can configure a +combination of keys or maybe no key binding at all for the selected +action. + + + +Default: the selected action +will be associated with &kde;'s default value. This is a good choice +for most actions, as &kde; comes with reasonable key bindings we have +thought about. + +Custom: if this option is +enabled, you can create a key combination for the selected +action. Click on the button labeled either None +or labeled with the previously selected custom shortcut. Now the button label +changes to Input. Then press any modifier key +(&ie; &Shift;, &Ctrl;, or &Alt;) and then normal key or a function key (⪚ F11) +you want to assign to this key combination. +Clicking on the Alternate column of a row in the list +allows to edit the second shortcut for the action. + + + + + + + + +
diff --git a/doc/kcontrol/khotkeys/CMakeLists.txt b/doc/kcontrol/khotkeys/CMakeLists.txt new file mode 100644 index 00000000..cf166228 --- /dev/null +++ b/doc/kcontrol/khotkeys/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/khotkeys) diff --git a/doc/kcontrol/khotkeys/groups-comment.png b/doc/kcontrol/khotkeys/groups-comment.png new file mode 100644 index 00000000..8ef80c3a Binary files /dev/null and b/doc/kcontrol/khotkeys/groups-comment.png differ diff --git a/doc/kcontrol/khotkeys/index.docbook b/doc/kcontrol/khotkeys/index.docbook new file mode 100644 index 00000000..3097c446 --- /dev/null +++ b/doc/kcontrol/khotkeys/index.docbook @@ -0,0 +1,751 @@ + + + +]> +
+Custom Shortcuts + + + +Subhashish Pradhan +&TC.Hollingsworth; &TC.Hollingsworth.mail; + + + + +2011 +Subhashish Pradhan + + +2012 +&TC.Hollingsworth; + +&FDLNotice; + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +shortcuts +hotkeys +Custom Shortcuts +khotkeys + + + + +Introduction + +The Custom Shortcuts &systemsettings; module +allows you to configure custom keyboard shortcuts and mouse gestures. You can +use them to control applications, run specific commands, and more. + + + + + +Managing Shortcuts and Groups + + +Adding Groups + +The module allows to you to sort related shortcuts into Groups. For +instance, if you have some shortcuts that relate to your music player, you +could create a group for them called Music Player. + + +To add a new group, click on the Edit button below +the left pane and select the New Group option. + + + + +Adding Shortcuts + +To add a new shortcut, click on the Edit button +below the left pane and select the New option. + +The first menu that appears allows you to select the type of trigger. The +following options are available: + + + + +Global Shortcut +These are standard keyboard shortcuts that will be recognized +anywhere, as long as a &kde; &plasma; Workspace is running. + + + +Window Action +Window Actions are triggers that occur when something happens +to a particular window, like when it appears, gains focus, or is closed. + + + + +Mouse Gesture Action +A mouse gesture action is triggered when a particular movement +of the mouse (or touchpad or touchscreen) is performed. + + + + +Once you've selected the type of trigger, another submenu appears that allows +you to select an action type. The following types are available: + + + + +Command/&URL; +This action will launch a command or open a &URL; when the +shortcut is triggered. + + + +&DBus; Command +This action will call a &DBus; method in a running application or +system daemon. For more information on &DBus;, see the +&DBus; +Introduction on &kde; TechBase. + + + +Send Keyboard Input +This action will send keyboard input to the currently +running application, just as if you had typed it in yourself. + + + + +Once you've selected the action type, you can then edit the shortcut to +your liking. See for more information. + + + + +Deleting Shortcuts and Groups + +To delete a shortcut or group, select it, then click on the +Edit button below the left pane, and select the +Delete option. + + + + +Exporting Groups + +You can export a group, so you can save the shortcuts contained within and +use them on another computer or maintain a backup. + +To export a group, select the group to be exported, then click on the +Edit button below the left pane and select the +Export Group... option, which opens a new window that +lets you define some options about the exported group. The following options +are available: + + + + +Export Actions +This allows you to select the state the shortcuts will be in +when they are imported later. Select Actual State to +maintain their current state, Enabled to ensure they are +all enabled, or Disabled to ensure they are all disabled. + + + + +Id +Here you may enter text to identify the group. If the group is +included by default, this text may be filled in by default. + + + +Allow Merging +This defines what happens if the group already exists on the +system the exported group is imported to. When enabled, any new actions will +be added to the group on the target system, while actions that have the same +name but a different configuration will updated with the configuration from the +imported file. When disabled, the module will refuse to import the file. + + + + +Filename +Here you may enter the filename you wish to export the +shortcut to. You may also select the Browse button to +the right of the text box to open the File dialog and select a file from there. + + +Exported files use the extension .khotkeys by +default. + + + + + + +Exporting a Group + + +The Export Group dialog. +Exporting a group of shortcuts. + + + + + + +Importing Groups + +To import a group, click the Edit button below the +left pane and select Import.... A file selection dialog +opens that permits you to locate a file previously created using the Export +function. + + + + + + + +Modifying Groups + +In the left section of the window, the default shortcuts are categorized +into groups. These groups can be expanded by clicking the arrow beside them to +reveal the shortcuts. + +When you click on a group, you are presented with two tabs to configure +the group itself. The Comment allows you to store notes +about the group, and are not actually used by the system for anything. The +Conditions tab allows you to restrict which windows a group +of shortcuts works with. + + +The Comment Tab + + +The Comment tab in a group. +Modifying a group's comment. + + + +Conditions are displayed in a tree, the top level of which is +And. All conditions beneath And must +be satisfied for shortcuts in the group to be triggered. + +You may add additional groups of conditions by clicking the +New drop down box to the right of the tree of conditions. Types +of groups include the aforementioned And, +Or, in which only one member of the group must be +satisfied, or Not, in which the inverse of all +members will trigger the shortcuts in the group. + +To add a window definition to the list, press the New +button. You may select Active Window... if you want +the shortcut to be triggered only if the specified window currently has focus, +or you may select Existing Window... if you want the +shortcut to be triggered as long as that window is open , regardless of +whether or not you are using it. Selecting either of these options opens a +window where you can edit the window definitions. + +Click the Edit... button to edit an existing set +of window definitions. A window opens with the window definition editor. For +more information, see . + +To remove a window definition from the conditions list, click the +Delete button. + + + + + +Modifying Shortcuts + +In the left section of the window, the default shortcuts are categorized +into groups. These groups can be expanded by clicking the arrow beside them to +reveal the shortcuts. + +The Preset Actions group, when expanded, reveals a +shortcut configuration named PrintScreen which, when +selected, reveals section on the right side, with three tabs: + + +The Comment Tab + +The Comment tab allows you to describe how to use the +shortcut, what it does, or anything else you might want to include. + + + + +The Trigger Tab +The Trigger tab contains the trigger configuration, +which depends on the type of trigger specified: + + + + +Global (Keyboard) Shortcut + + +To modify a keyboard shortcut, click on the button that contains a wrench, +and then enter the desired keyboard shortcut. To erase the shortcut, click on +the button with the icon to the right of the +change shortcut button. + + +Modifying a Keyboard Trigger + + +The Trigger tab for a keyboard shortcut. +Modifying a trigger for a keyboard shortcut. + + + + + + + +Window Action + + +Window actions contain several options: + + + + +Trigger When + + +This configures the particular window action that must occur for the +shortcut to be triggered. The following options are available: + + + +Window appears - +Triggered when a window is opened. + +Window disappears - +Triggered when a window is closed. + +Window gets focus - +Triggered when you switch to a window. + +Window loses focus - +Triggered when you switch away from a window. + + + + + + + +Window +This is where you define the actual window or windows the trigger applies +to. For more information, see + + + + + + + + +Mouse Gesture + + +A mouse gesture can be changed by clicking the Edit +button below the area that displays the mouse gesture, which will open a window. +Hold down the &LMB; and draw the desired mouse gesture in the area provided. +The gesture will be saved when you release the &LMB;. + + +Modifying a Mouse Gesture Trigger + + +The Trigger tab for a mouse gesture shortcut. +Modifying a trigger for a mouse gesture. + + + + + + + + + + + +The Action Tab + +The Action tab is where you configure the action that +will be performed when the shortcut is triggered. There are several types of +actions that have different configuration options: + + + + +Command/&URL; + + +When using a Command or &URL; is a trigger, a text box is provided where +you may enter the command to run or &URL; to open when the shortcut is triggered. +You may also click the Browse button to the right of the +text box to open a file selection dialog in which you can select a file on your +local or a remote system. + + +Modifying a Command Action + + +The Action tab for a command. +Modifying a command action. + + + + + + + +&DBus; Command + + +The following options are provided that allow you to specify a &DBus; +method to be performed: + + + + +Remote application +The service name of the remote application the method is to +be performed on, for instance org.kde.kate if you wanted +to perform it on the &kate; Advanced Text Editor. + + + +Remote object +The path to the remote object the method is to be performed on, +for instance /Document/1, if you wanted to perform it on +the first document opened in &kate;. + + + +Function +The name of the &DBus; method to be called, for instance +print if you wanted to print the document. + + + + +For more information on &DBus;, see the +&DBus; +Introduction on &kde; TechBase. + + + + + +Send Keyboard Input + + +At the top of the Action tab, there is a large text +entry where you may enter the keystrokes you wish to be sent when the shortcut +is triggered. + +Most keys contain a single character, and to enter them here you just +enter that character. For instance, to type an A, just enter +A. Some keys have longer names, and you can also use +those names. For instance, to press the &Alt; key, simply enter +Alt. + + +Individual keystrokes should be separated by a colon +(:). For instance, to type foo, enter +F:O:O. + +Keys that need to pressed at the same time should be separated by a plus +sign. For instance, to press +&Ctrl;C, enter +Ctrl+C. + + +Remember, you must enter keystrokes here exactly as you would on a keyboard. +To capitalize letters, you must enter the &Shift; key. For instance, to type +Hello, enter Shift+H:E:L:L:O. + +This also applies to special characters. For instance, to type the +at-sign on the U.S. English keyboard layout, enter Shift+2. + + + + +The action that is performed is dependent on the currently selected +keyboard layout. If you change keyboard layouts and trigger a shortcut, it +may have undesired consequences. + + +Beneath the keystroke entry text box, you may select which window the +keystrokes will be directed to. You may choose from the following options: + + + +Active window - +The window that is currently open. + +Specific window - +The window that you describe using the form below. For more information on +describing windows, see . + +Action window - +When using the Window Actions trigger type, enter the keystrokes in the window +that triggered the shortcut. + + + + +Modifying a Keyboard Input Action + + +The Action tab for keyboard input. +Modifying the keyboard input action for a shortcut. + + + + + + + + + + + + + + +Defining Windows + +Several areas of the module allow you to define a list of windows. They +all use the same interface, which contains the following options: + + + + +Comment +This is merely an informational text box you can use to explain +what the trigger applies to or save other useful information. It is not +actually used by the system for anything. + + + +Window List +Beneath the Comment box on the left is the +list of all window definitions currently present in the trigger. Simply click +on one to perform an operation on it. + + + +Edit... + + +Press this button to modify the currently selected window definition. A +new window is opened that allows you to edit it. This window contains the +following options: + + + + +Window Data + + +This is where you describe the window the trigger should apply to. + +At the top, there is a Comment field, which is +informational just like the one in the main Trigger tab. + +Three window characteristics are available: + + + +Window title - +The title that appears at the top of the window. + +Window class - +Usually the name of the application. + +Window role - +Usually the name of the &Qt; class that makes up the window. + + + +Each window characteristic provides a drop-down box, and a text box below +it. Enter the value you wish to test windows for in the text box. From the +drop-down box, select which kind of test you wish to apply. You can use +Is to require an exact match, Contains +to require that the text entered be somewhere inside the full value, or +Matches Regular Expression to use a regular expression to +define the match. You may also perform the inverse of all these operations. +Select Is Not Important if you do not wish for that +particular characteristic to be examined. + +The easiest way to fill in this information is to open the desired window, +then click the Autodetect button at the bottom of this +section, and finally click on the desired trigger window. All three window +characteristics will be populated with the information from that window, and +you can then adjust the settings as necessary. + + + + + +Window Types + + +This lets you restrict the match to a particular type of window. The +following options are available: + + + +Normal - +A regular application window. + +Desktop - +The main desktop is actually a special window all its own. + +Dialog - +A small window that is part of a normal application, such as a message box or +a configuration screen. + +Dock - +A small window that can be attached or detached from a main application window. + + + + + + + + + + + + + +New... +Create a new window definition. This opens the edit dialog +described above. + + + +Duplicate... +This creates a new window definition with the exact same +specifications as the currently selected window definition. It will open the +edit dialog described above so you may make further changes. + + + +Delete +Removes the currently selected window definition. + + + + + + + + +Settings + +When you first enter the module, or when you click the +Settings button below the left pane, there will be +several configuration options in the right pane: + + + + +Start the Input Actions daemon on login +This configures whether or not to activate the background +application that monitors for keyboard shortcuts and triggers configured +actions. It is enabled by default. + + + +Gestures + +Select this check box to enable mouse gestures. + +There are two options specific to mouse gestures: + + + + +Timeout +This specifies the maximum time interval during which the mouse +gesture will be monitored and recognized by the system, in milliseconds. + + + + +Mouse Button +This specifies the mouse button to be used for mouse gestures. +Usually, 1 is the &LMB;, 2 is the +&RMB;, and 3 is the middle or wheel button. If your +mouse has more buttons, you can also use those instead. + + +Button 1 is unavailable, so mouse gestures do not interfere with the +normal operation of your system. + + + + + + + + + + + +Settings + + +The Settings screen. +Editing Custom Shortcuts settings. + + + + + + + +Credits and License + +Special thanks to Google Code-In 2011 participant Subhashish Pradhan for +writing much of this article. + + + +&underFDL; +&underGPL; + + + +
+ + diff --git a/doc/kcontrol/khotkeys/manage-export.png b/doc/kcontrol/khotkeys/manage-export.png new file mode 100644 index 00000000..20a6fd89 Binary files /dev/null and b/doc/kcontrol/khotkeys/manage-export.png differ diff --git a/doc/kcontrol/khotkeys/oxygen-22x22-edit-clear-locationbar-rtl.png b/doc/kcontrol/khotkeys/oxygen-22x22-edit-clear-locationbar-rtl.png new file mode 100644 index 00000000..2bc48d86 Binary files /dev/null and b/doc/kcontrol/khotkeys/oxygen-22x22-edit-clear-locationbar-rtl.png differ diff --git a/doc/kcontrol/khotkeys/settings.png b/doc/kcontrol/khotkeys/settings.png new file mode 100644 index 00000000..95c297d2 Binary files /dev/null and b/doc/kcontrol/khotkeys/settings.png differ diff --git a/doc/kcontrol/khotkeys/shortcuts-action-command.png b/doc/kcontrol/khotkeys/shortcuts-action-command.png new file mode 100644 index 00000000..2ed9b2bb Binary files /dev/null and b/doc/kcontrol/khotkeys/shortcuts-action-command.png differ diff --git a/doc/kcontrol/khotkeys/shortcuts-action-keyboard.png b/doc/kcontrol/khotkeys/shortcuts-action-keyboard.png new file mode 100644 index 00000000..b2a7fca2 Binary files /dev/null and b/doc/kcontrol/khotkeys/shortcuts-action-keyboard.png differ diff --git a/doc/kcontrol/khotkeys/shortcuts-trigger-keyboard.png b/doc/kcontrol/khotkeys/shortcuts-trigger-keyboard.png new file mode 100644 index 00000000..564665c9 Binary files /dev/null and b/doc/kcontrol/khotkeys/shortcuts-trigger-keyboard.png differ diff --git a/doc/kcontrol/khotkeys/shortcuts-trigger-mouse.png b/doc/kcontrol/khotkeys/shortcuts-trigger-mouse.png new file mode 100644 index 00000000..0eedf6f5 Binary files /dev/null and b/doc/kcontrol/khotkeys/shortcuts-trigger-mouse.png differ diff --git a/doc/kcontrol/kwincompositing/CMakeLists.txt b/doc/kcontrol/kwincompositing/CMakeLists.txt new file mode 100644 index 00000000..877a45ce --- /dev/null +++ b/doc/kcontrol/kwincompositing/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kwincompositing) diff --git a/doc/kcontrol/kwincompositing/index.docbook b/doc/kcontrol/kwincompositing/index.docbook new file mode 100644 index 00000000..dce55c39 --- /dev/null +++ b/doc/kcontrol/kwincompositing/index.docbook @@ -0,0 +1,82 @@ + + + +]> + +
+ + +Desktop Effects + +&Mike.McBride; &Mike.McBride.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +KControl +desktop +effects + + + +Desktop Effects + + +Introduction + +This module is used to configure desktop effects +for &kde;. + + +This panel is divided into three tabs: General, +All Effects and Advanced. + + +<guilabel>General</guilabel> tab + +At the top of this tab in the section Activation is a checkbox labeled Enable +desktop effects at startup. If there is no mark in front of this checkbox, then all +visual effects are disabled. +All desktop effects can be turned on and off using the global shortcut +&Alt;&Shift;F12. + +Below that section there are some settings for the simple desktop effects like +improved window management, various animations, effects for desktop switching and +the animation speed. + + + +<guilabel>All Effects</guilabel> tab + +The main part of this page is a list of all available effects grouped +by Accessibility, Appearance, +Candy, Focus, Tools +and Window Management. +Use the incremental search bar above the list window to find items in the list. + +Check an effect in the list to enable it. Display the About +dialog by clicking the info button at the right side of the list item. +Some effects have settings options, in this case there is a tool button +at the left of the info button. Click it to open a configuration dialog. + + + +<guilabel>Advanced</guilabel> tab + +On this tab you can select a Compositing type and the Qt graphics system. +In the next two sections you can configure General Options and OpenGL Options. + + + + + + + + +
diff --git a/doc/kcontrol/kwindecoration/CMakeLists.txt b/doc/kcontrol/kwindecoration/CMakeLists.txt new file mode 100644 index 00000000..ab136bcf --- /dev/null +++ b/doc/kcontrol/kwindecoration/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kwindecoration) diff --git a/doc/kcontrol/kwindecoration/buttons.png b/doc/kcontrol/kwindecoration/buttons.png new file mode 100644 index 00000000..1c4fdf7c Binary files /dev/null and b/doc/kcontrol/kwindecoration/buttons.png differ diff --git a/doc/kcontrol/kwindecoration/decoration.png b/doc/kcontrol/kwindecoration/decoration.png new file mode 100644 index 00000000..9fc84e54 Binary files /dev/null and b/doc/kcontrol/kwindecoration/decoration.png differ diff --git a/doc/kcontrol/kwindecoration/index.docbook b/doc/kcontrol/kwindecoration/index.docbook new file mode 100644 index 00000000..17ea824d --- /dev/null +++ b/doc/kcontrol/kwindecoration/index.docbook @@ -0,0 +1,150 @@ + + + +]> + +
+ +Window Decorations + +&Rik.Hemsley; &Rik.Hemsley.mail; +&Anne-Marie.Mahfouf; &Anne-Marie.Mahfouf.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +Systemsettings +kwin +window +border +theme +style + + + +Window Decoration + +This module allows you to select a style for the buttons and borders around +windows. + + +Window Decorations + + + +Window Decoration Configuration Module + + + + + + Window Decoration Configuration Module + + + + + +Choose a window decoration style from the preview list, using the +search field at the top of the screen. + +The &kde; default window decoration is called "Oxygen". + +Each style has a different look, but also a different +feel. Some have (sometimes invisible) +resize borders all around the edge, which make resizing +easier but moving more difficult. Some have no borders on certain +edges. One (BII) even has a dynamically sized and +positioned title element. + +You are encouraged to experiment with the different styles until +you find one which best suits your pattern of work. + +Below the preview pane you find three buttons to open configuration dialogs +for decoration and buttons of the selected style or to download additional +styles. + + + + +Decorations + +In this dialog you can change the decoration of the window. + +The available options depend on the selected style. + + + +Oxygen Decoration Options + + + + + + Oxygen Decoration Options + + + + + + + +Buttons + +This dialog allows you to customize the buttons location on the titlebar. You can move Close button to the left for example. Check the Use custom titlebar button positions option in order to customize your titlebars. Then use the &kde; titlebar below and the buttons on its left and right to rearrange them as you want them. + + + + +Window Decoration Configuration Module + + + + + + Window Decoration Configuration Module + + + + + + By default, Show window button tooltips is checked and tooltips are shown. + + +This page has instructions directly on it - just drag around the +buttons until you have the order that makes you comfortable. + + +Not all the window decorations are able to comply with your custom +set button order. The ones that cannot are being converted, but at the +time of this release they have not been all been changed. + + +Apart from choosing the window decoration itself, you can choose +here two further options: if there should be a tooltip while you hover +your mouse over a window decoration button, and if the window +decoration should attempt to use a custom set button order. + + +The tooltips can be quite useful if you have set a custom button +order, and then changed to an unfamiliar window decoration. + + + +For accessibility purposes, some window decorations support +extra wide borders. If this is available, you can also choose a +border size here. These large borders are easier to see for low +vision users, and easier to grab for people with limited mobility or +difficulty using a mouse. + + + + + + +
diff --git a/doc/kcontrol/kwindecoration/main.png b/doc/kcontrol/kwindecoration/main.png new file mode 100644 index 00000000..1946aa3e Binary files /dev/null and b/doc/kcontrol/kwindecoration/main.png differ diff --git a/doc/kcontrol/kwinscreenedges/CMakeLists.txt b/doc/kcontrol/kwinscreenedges/CMakeLists.txt new file mode 100644 index 00000000..84580ea8 --- /dev/null +++ b/doc/kcontrol/kwinscreenedges/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kwinscreenedges) diff --git a/doc/kcontrol/kwinscreenedges/index.docbook b/doc/kcontrol/kwinscreenedges/index.docbook new file mode 100644 index 00000000..3a401d4d --- /dev/null +++ b/doc/kcontrol/kwinscreenedges/index.docbook @@ -0,0 +1,69 @@ + + + +]> + +
+ + +Screen Edges + +&Mike.McBride; &Mike.McBride.mail; + + + +2014-03-05 +&kde; 4.11 + + +KDE +Systemsettings +desktop +effects + + + +Active screen edges allow you to activate effects by pushing your mouse +cursor against the edge of the screen. Here you can configure which effect +will get activated on each edge and corner of the screen. + + +Click with any mouse button onto a square and select an effect +in the context menu. Edges with a black square have already an attached effect, +a grey colored square indicates that no effect is selected for this edge. + +The number of accessible items in the context menu depends on the settings in the module + +Desktop Effects in the Workspace Appearance and Behavior +category. Enable desktop effects to activate compositing, select the compositing type, +and then choose your favorite effects on the +All Effects tab from the Windows Management +group. This activates the corresponding items in the context menu. + +If you are looking for the setting to enable switching of +desktops by pushing your mouse cursor against the edge of +the screen choose one of the above mentioned +Window Management effects from the context menu. + +The section Window Management has two additional options when moving windows to screen edges: + +Maximize windows by dragging them to the top of the screen. + +Tile windows by dragging them to the side of the screen. The windows will be tiled to a quarter of the screen if dragged to the upper or lower part of the screen height determined by the value in the spinbox, otherwise to the full height of the screen. + + + + +The Other Settings configure the behavior pushing the mouse cursor to a screen edge. +Switch desktop on edge: Change desktop when the mouse cursor is pushed against the edge of the screen. +If Always Enabled is selected all effects configured for screen edges in the first section of this module will be disabled. + +Activation delay: The amount of time required for the mouse cursor to be pushed against the edge +of the screen before the action is triggered + +Reactivation delay: The amount of time required after triggering an action until the next trigger can occur. + + +
diff --git a/doc/kcontrol/kwintabbox/CMakeLists.txt b/doc/kcontrol/kwintabbox/CMakeLists.txt new file mode 100644 index 00000000..d170cde3 --- /dev/null +++ b/doc/kcontrol/kwintabbox/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/kwintabbox) diff --git a/doc/kcontrol/kwintabbox/index.docbook b/doc/kcontrol/kwintabbox/index.docbook new file mode 100644 index 00000000..9bd26c96 --- /dev/null +++ b/doc/kcontrol/kwintabbox/index.docbook @@ -0,0 +1,101 @@ + + + +]> +
+ +Task Switcher + +&Martin.Graesslin;&Martin.Graesslin.mail; + + + +2014-03-10 +&kde; 4.11 + + +KDE +System Settings +desktop +window +navigation + + + + +Navigating through Windows + +This module offers the possibility to configure the behaviour for Navigating through windows often referred to as &Alt; . There are two independent sets of effects which can have different settings. For each of this sets there is an own tab (Main and Alternative) in this module. + + + +The first set of effects on the Main tab has predefined shortcuts. If you want to use the second set of effects on the Alternative tab, you have to set a shortcut for these effects in the Shortcut Editor manually. + + +For navigating through windows without &Alt; , you can define screen edge actions in the &systemsettings; module Screen Edges. + + +The following documentation of options applies to the general settings and the alternative settings as well. + + +Visualization + +There are several effects which can be used instead of the normal window list when compositing is enabled. By default the Thumbnails effect is used. This effect displays a small thumbnail of each window inside a box and the currently selected window is highlighted. +There are several additional predefined layouts which provide an informative or compact view, small or large icons, a grid and window title only. +Selecting one of these layouts you will have a button to show a preview. +If you enable Show selected window it will be shown as background of the task switcher window. + + +Cover Switch and Flip Switch effect are more fancy effects which require OpenGL. Cover Switch displays the windows in a gallery with a large thumbnail of the currently selected window in the center of the screen while all other windows are rotated on the left and right. Flip Switch displays all windows on a 3D stack. The selected window is on top of the stack and navigating through the windows will move the stack so that the new selected window is on the top. + + +If the effect provides additional settings the configure button will be activated. By clicking this button a configuration dialog will be shown. + + +When compositing is not active or gets suspended the normal window list will be shown. There is no loss in functionality if an effect is selected and compositing is not active. + + + +Shortcuts + +The shortcut editor provides the configuration interface for the keyboard shortcuts for navigating through windows. Each of the two possible sets of effects has two shortcuts: one for the forward direction and one for the reverse direction. Please note that the window list can only be shown if you select a shortcut with a keyboard modifier such as the &Alt; or &Ctrl; key. This modifier has to be hold while switching. Selecting a shortcut without a modifier key can break the behaviour of navigating through windows. + + + + +Content +It is possible to influence the sort order, you can either use a sort order based on the last usage of the windows or the stacking order of the windows. + +If you check Include "Show Desktop" icon an entry for the desktop will be added to list with application windows. Then you can select this entry in the list to minimize all windows. +If Only one window per application is selected then only the last used instance of an application is contained in the list. Switching to other instances is possible only via the panel then. + + + +Filter windows + +You can configure which windows should be shown in the list initiated by pressing &Alt; (predefined for the settings on the Main tab) or the user defined shortcut for the alternative settings. + +So it is possible to only show windows on the current virtual desktop or windows from all other desktops. Additionally you can apply similar rules for windows in activities or on screens for a multimonitor setup. + +The last option allows you to filter on the minimization status of windows. + + + + +
+ + + diff --git a/doc/kcontrol/mouse/CMakeLists.txt b/doc/kcontrol/mouse/CMakeLists.txt new file mode 100644 index 00000000..36a0d843 --- /dev/null +++ b/doc/kcontrol/mouse/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/mouse) diff --git a/doc/kcontrol/mouse/index.docbook b/doc/kcontrol/mouse/index.docbook new file mode 100644 index 00000000..20f8610f --- /dev/null +++ b/doc/kcontrol/mouse/index.docbook @@ -0,0 +1,472 @@ + + + +]> + +
+ +Mouse + +&Mike.McBride; &Mike.McBride.mail; +&Brad.Hards; &Brad.Hards.mail; + + + +2013-12-05 +&kde; 4.12 + + +This is the documentation for the &kde; &systemsettings; module that configures mice and other pointing devices. + + + + +KDE +Systemsettings +mouse + + + + +Mouse + +This module allows you to configure your pointing device. Your +pointing device may be a mouse, a track ball, a touch-pad, or another piece +of hardware that performs a similar function. + +This module is divided into several tabs: +General, +Advanced and +Mouse Navigation. +There may also be one or more additional tabs if you have a Logitech mouse +or trackball, providing access to special features. + + + +General + + + +Button Order + +If you are left-handed, you may +prefer to swap the functions of the left and +right buttons on your pointing device by choosing the +Left handed option. If your pointing device has more than two +buttons, only those that function as the left and +right buttons are affected. For example, if you have +a three-button mouse, the middle button is +unaffected. + + + + +Reverse scroll direction + +With this check box selected, the scroll wheel (if any) will work in the opposite direction (so that if rolling the top of the scroll wheel towards you previously causes a scroll down, then it will now cause a scroll up). This may be useful to handle a unusual setup of the X server. + + + + + +Double-click to open files and folders (select icons on first click) + + If this option is not checked, icons/files will be opened with a +single click of the left mouse-button. This +default behavior is consistent with what you would expect when you click +links in most web browsers. If checked however, icons/files will be +opened with a double click, while a single click will only select the +icon or file. This is the behavior you may know from other desktops or +operating systems. + +This option can be changed in the configuration dialogs of &dolphin; and &konqueror; +on the Navigation tab as well. + + + + + +Single-click to open files and folders + +This is the default setting for &kde;. Clicking once on an icon +will open it. To select you can drag around the icon(s) or &Ctrl;Right click, +or simply click and hold to drag it. You can also enable automatic selection of icons using the Automatically select icons check box, discussed below. + + + + +Change pointer shape over icons + +When this option is checked, the shape of the mouse pointer +changes whenever it is over an icon. + +This option should be checked in most situations. It gives +more visual feedback and says, in essence, if you click here, something +will happen. + + + + + +Automatically select icons + + +As noted above, if you have Single-click to open files and folders selected, you can select icons by dragging around them, or by using &Ctrl;Right click. If you routinely need to select icons, you may want to enable this check box, which will allow icons to be selected automatically by pausing over the icon. The Delay: slider determines how long is required before the automatic selection takes effect. + + + + + + + + +Advanced + + + + +Pointer acceleration + +This option allows you to change the relationship +between the distance that the mouse pointer moves on the +screen and the relative movement of the physical device +itself (which may be a mouse, track-ball, or some other +pointing device.) + +A high value for the acceleration multiplier will lead to large +movements of the mouse pointer on the screen, even when +you only make a small movement with the physical device. + +A multiplier between 1x and +3x will works well for many systems. With a multiplier +over 3x the mouse pointer may become difficult to +control. + + + + +Pointer threshold + +The threshold is the smallest distance that the mouse pointer must +move on the screen before acceleration has any effect. If the movement +is within the threshold, the mouse pointer moves as if the acceleration +were set to 1x. + +Thus, when you make small movements with the physical device (⪚ +mouse), you still have fine control of the mouse pointer on the screen, +whereas larger movements of the physical device will move the mouse +pointer rapidly to different areas on the screen. + +You can set the threshold by entering a value into the edit box or +by clicking the up/down arrows to the right of the box. + +In general, the higher you set the Pointer +acceleration value, the higher you will want to set the +Pointer threshold value. For example, a +Pointer threshold of 4 pixels may +be appropriate for a Pointer Acceleration of +2x, but 10 pixels might be +better for 3x. + + + + +Double click interval + +This is the maximum amount of time between clicks for &kde; to +register a double click. If you click twice, and the time between those +two clicks is less than this number, &kde; recognizes that as a double +click. If the time between these two clicks is greater than this +number, &kde; recognizes those as two separate +single clicks. + + + + +Drag start time and Drag start +distance + + +If you + +click with the mouse +drag within the time specified in Drag start +time, and +move a distance equal to or greater than the number (of +pixels) specified in Drag start distance + + + +&kde; will drag the selected item. + + + + +Mouse wheel scrolls by + +If you have a wheel mouse, use the spin box to determine how many +lines of text one step of the mouse wheel will +scroll. + + + + + + + + +Mouse Navigation + + +This tab allows you to configure the keyboard number pad keys as a mouse-type device. This may be useful when you are working on a device without another pointing device, or where you have no other use for the number pad. + + + + + +Move pointer with keyboard (using the num pad) + + +To enable keyboard mouse mode, you need to select the check box labeled Move pointer with keyboard (using the num pad). When you do this, the other settings will become enabled, and you can customize the keyboard pointer behavior further, if required. + + +The various keys on the number pad move in the direction you would expect. Note that you can move diagonally as well as up, down, left and right. The 5 key emulates a click to a pointer button, typically &LMB;. You change which button is emulated by using the / key (which makes it &LMB;), * key (which makes it &MMB;) and - (which makes it &RMB;). Using the + emulates a double click to the selected pointer button. You can use the 0 key to emulate holding down the selected pointer button (for easy dragging), and then use the . to emulate releasing the selected pointer button. + + + + + +Acceleration delay + + +This is the time (in milliseconds) between the initial key press and the first repeated motion event for mouse key acceleration. + + + + + +Repeat interval + + +This is the time in milliseconds between repeated motion events for mouse key acceleration. + + + + + +Acceleration time + + +This is the time in milliseconds before the pointer reaches a maximum speed for mouse key acceleration. + + + + + +Maximum speed + + +This is the maximum speed in pixels per second the pointer can reach for mouse key acceleration. + + + + + +Acceleration profile + + +This is the slope of the acceleration curve for mouse key acceleration. + + + + + + + + + +Logitech Support + + +Some Logitech USB mice support special features, such as switching to a higher resolution, or +providing cordless status. If &kde; was built with libusb support, then you will get an additional +tab for each supported mouse that is plugged in. + + + +The supported devices are: + + +Wheel Mouse Optical +MouseMan Traveler +MouseMan Dual Optical +MX310 Optical Mouse +MX510 Optical Mouse +MX300 Optical Mouse +MX500 Optical Mouse +iFeel Mouse +Mouse Receiver +Dual Receiver +Cordless Freedom Optical +Cordless Elite Duo +MX700 Optical Mouse +Cordless Optical Trackman +Cordless MX Duo Receiver +MX100 Laser Mouse +Receiver for Cordless Presenter + + + +Not all devices support all capabilities (typically cordless devices do not +provide resolution switching, and of course only cordless devices support +cordless status reporting), so some parts of the tab will not be enabled for +some mouse types. + + + +If the mouse supports resolution switching, the Sensor Resolution +radio button group will be enabled, and you can switch from 400 counts per +inch to 800 counts per inch and back. If you use +800 counts per inch, the same physical movement of the mouse +will cause a greater (roughly double) amount of motion of the cursor. This tends +to be popular amongst gamers. + + + +If the mouse supports cordless reporting, the Battery Level +and RF Channel widgets will be enabled. You can only change +the RF Channel if your mouse has two channel support. + + + + + + +
diff --git a/doc/kcontrol/paths/CMakeLists.txt b/doc/kcontrol/paths/CMakeLists.txt new file mode 100644 index 00000000..a521e4f5 --- /dev/null +++ b/doc/kcontrol/paths/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/paths) diff --git a/doc/kcontrol/paths/index.docbook b/doc/kcontrol/paths/index.docbook new file mode 100644 index 00000000..b4da78ce --- /dev/null +++ b/doc/kcontrol/paths/index.docbook @@ -0,0 +1,91 @@ + + + +]> + +
+Paths + + + + +Michael +Anderson + +
nosrednaekim@gmail.com
+
+
+Anne-Marie +Mahfouf + +
annma@kde.org
+
+ +
+ +2009-11-17 +&kde; 4.4 + + +KDE +KControl +desktop +paths + +
+ +This is a module to configure essential paths for the &kde; desktop. + + + +Configure some &kde; paths + + + + + + Configure some &kde; paths + + + + + + + +Desktop path: +The Desktop folder contains all the files which you see on your desktop. The default path is usually ~/Desktop but you can change here the location of this folder. + + + +Autostart path: + +The Autostart folder contains applications or links to applications or scripts you want to start whenever &kde; starts. You can change the location of this folder if you want to. + + + +Documents path: +This folder will be used by default to load or save documents from or to. + + +Download path: +This folder will be used by default to save your downloaded items. + + +Movies path: +This folder will be used by default to load or save movies from or to. + + +Pictures path: +This folder will be used by default to load or save pictures from or to. + + +Music path: +This folder will be used by default to load or save music from or to. + + +If you change a path and click Apply a dialog appears where you can choose to move the content to the +new folder or use the new folder without moving the files. + +
diff --git a/doc/kcontrol/paths/paths.png b/doc/kcontrol/paths/paths.png new file mode 100644 index 00000000..eff8756d Binary files /dev/null and b/doc/kcontrol/paths/paths.png differ diff --git a/doc/kcontrol/powerdevil/CMakeLists.txt b/doc/kcontrol/powerdevil/CMakeLists.txt new file mode 100644 index 00000000..9b94e716 --- /dev/null +++ b/doc/kcontrol/powerdevil/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/powerdevil) diff --git a/doc/kcontrol/powerdevil/activity.png b/doc/kcontrol/powerdevil/activity.png new file mode 100644 index 00000000..2522903f Binary files /dev/null and b/doc/kcontrol/powerdevil/activity.png differ diff --git a/doc/kcontrol/powerdevil/advanced.png b/doc/kcontrol/powerdevil/advanced.png new file mode 100644 index 00000000..5b928274 Binary files /dev/null and b/doc/kcontrol/powerdevil/advanced.png differ diff --git a/doc/kcontrol/powerdevil/energy.png b/doc/kcontrol/powerdevil/energy.png new file mode 100644 index 00000000..1998a57f Binary files /dev/null and b/doc/kcontrol/powerdevil/energy.png differ diff --git a/doc/kcontrol/powerdevil/index.docbook b/doc/kcontrol/powerdevil/index.docbook new file mode 100644 index 00000000..6ab5f009 --- /dev/null +++ b/doc/kcontrol/powerdevil/index.docbook @@ -0,0 +1,317 @@ + + + +]> +
+ +Power Management + +&Dario.Freddi;&Dario.Freddi.mail; + + + +2013-08-18 +&kde; 4.11 + + +KDE +System Settings +powerdevil +power management +laptop power + + + + +PowerDevil, a Power Management Daemon + +This module is a configuration tool for managing Power Management in &kde;. It is a configurator for the PowerDevil daemon, that you can start or stop from the Service Manager module. + +Through this module, you can define your computer's behavior in various situations, allowing you to save as much energy as possible. + + +Powerdevil works with Solid only and it's integrated in your desktop. You won't even notice it is running, apart from notifications. Moreover, Powerdevil checks your system capabilities first, so you'll see only options available for your system in this module. + + +Note that PowerDevil does not poll your system. This means that it will not waste energy while trying to save it, as some other power managers do. + +Energy Saving Settings + +This page shows the actual energy saving settings. If a battery is detected you have three tabs with different settings for On AC Power, On Battery and On Low Battery profiles. + + + +Energy Saving Settings + + + + + + Energy Saving Settings + + + Energy Saving Settings + + + + + +There are a lot of options you can configure for each profile: + + + +Screen Brightness + +Sets the screen's brightness using a slider. + + + +Dim Screen + +If checked, the display will be progressively dimmed, until reaching +brightness 0, in the amount of time you specify in the spin box. + + + + +Screen Energy Saving + +Here you can define power saving for your monitor. +The check box defines if DPMS support should be enabled or disabled. +If you choose to activate it, set the timeouts in the spin boxes below. + + + + +Suspend Session + +Suspends the session after the selected time to the status +Sleep, Hibernate, +Shutdown or Lock screen. + + + +Button events handling + +Select actions to perform whenever the laptop lid is closed or a button is pressed. + + +Run Script + +Activate this option to run a custom script when a profile is loaded, unloaded +or after a given amount of time. + + + + + + + + +Activity Settings +Here you can configure the Power Management settings per activity. The settings for each activity can be configured on its own tab. + + +Activity Settings + + + + + + Activity Settings + + + Activity Settings + + + + + + +Don't use special settings + + +Use the settings defined on Energy Saving page. + + + + +Act like + + +Here you can choose a predefined profile from the drop-down box: PC running on AC power, PC running on battery power or PC running on low battery. + + + + +Define a special behavior + + +If this option is chosen, a special behavior for activity can be chosen. If this is a presentation activity, you can check the Never shutdown the screen and Never suspend or shutdown the computer boxes. It is also possible to define the time interval for the computer to switch to a suspension mode for the power saving activities. + + + + +Use separate settings (advanced users only) + + +This option allows users to choose the detail power saving settings for a separate activity. The settings are similar to the settings from the Energy Saving page. + + + + + + + +Advanced Settings + + +Advanced Settings + + + + + + Advanced Settings + + + Advanced Settings + + + + + +Battery levels + +These items are only displayed if a battery is detected. + + +Battery is at low level at + + +Here you can set the percentage after which the battery will be considered low. + + + +Battery is at critical level at + + +Here you can set the percentage after which the battery will be considered at critical level. + + + +When battery is at critical level + + +Defines the action that will be done when battery reaches the critical level. + + + + + + +Events + + +Lock screen on resume + + +When this box is checked, every time the PC gets suspended, the screen will be locked when resuming. You will be asked for a password when resuming from sleep state. + + +Never prevent an action on lid close + + +When this option is selected, applications will not be allowed to inhibit sleep when the lid is closed. + + + +Configure Notifications + + +If you want a deeper control over your notifications, you can refine them by clicking this button. + + + + + + + + + + + + +PowerDevil Runner + +PowerDevil can be manually controlled through &krunner; (&Alt;F2). This makes changing profile, brightness, governor and more much easier and faster. The runner has various keywords you can enter to access its functions + + +Runner Keywords + +Here comes a list of keywords you can enter in &krunner; to perform PowerDevil related actions. + + +Power Profile + + +You can manually choose a profile using this keyword. All available profiles will be shown in form of &krunner; matches. + + + + +Screen Brightness + + +You can control screen brightness through this keyword. In this form, some &krunner; matches that let you do some common actions will be shown. If you enter a value after the keyword (⪚: Screen Brightness 50), the brightness will be set to that value. + + + +Suspend + + +You can suspend your pc through this keyword. Available suspend methods will be shown as &krunner; matches. + + + + + + +
+ + + diff --git a/doc/kcontrol/screensaver/CMakeLists.txt b/doc/kcontrol/screensaver/CMakeLists.txt new file mode 100644 index 00000000..57ded656 --- /dev/null +++ b/doc/kcontrol/screensaver/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/screensaver) diff --git a/doc/kcontrol/screensaver/index.docbook b/doc/kcontrol/screensaver/index.docbook new file mode 100644 index 00000000..02395bf1 --- /dev/null +++ b/doc/kcontrol/screensaver/index.docbook @@ -0,0 +1,110 @@ + + + +]> + +
+ +Screen Locker + +&Mike.McBride; &Mike.McBride.mail; + + + +2013-12-05 +&kde; 4.12 + + +KDE +systemsettings +screensaver +screen saver + + + + + +Screen Locker + +Using this module, you can choose your screen saver, determine +how much time must pass before the screen saver is activated, and add +or remove password protection to your screen saver. + + +Setting the time, priority and passwords for screen +savers. + +At the top is a check box to have the screen saver Start automatically after, +and a spin box which determines the period of inactivity before the screen saver should be started. +You can enter any positive number of minutes in this box. + +Below that is a check box labeled Require password +after. If it is checked, when you click a key +or click a mouse button to end the screen saver after the time in the spinbox and return to your +work, you must enter a password. The password used is the same +password you used to login to your machine. If there is no mark in +the check box, no password is required to return to your +desktop. + +Locking the desktop manually causes the password protection to engage immediately. + + + + +Choosing the screen saver, and configuring its options + +Use the Simple locker option for a basic unlock dialog that prompts for a password. + +If you would like to have some interactive widgets like notes or a player +on the locked screen saver, select Desktop Widgets +and click the Configure... button to select your +favorite widgets. + + +To enable the selection of all available screen savers select the Screen +saver option. You can select a screen saver by simply clicking on its name. +Once you have selected a screen saver, you will see a small preview on the +monitor on the right. + +The preview monitor will often show the screen saver +larger than it is when the screen saver is activated. This is done on +purpose, since many of the details of the screen savers would be +unintelligible if actually scaled down to such a small +size. + +Each screen saver has a different set of setup options. By +clicking on Setup..., a dialog box will appear with +all available options. As you adjust the options, the preview box in +the dialog box will show you what effect you will achieve with the +current settings. + +When you are done setting up your screen saver, click +OK. Clicking Cancel +will erase any changes you made in this dialog box, and return you to the +screen saver module. + +For most screen savers a description, Copyright and Author information +is shown directly in the dialog, for others you need to click the +About button to read this information. + +When you think you have all the options set the way you want, +simply click on Test to immediately start the +screen saver exactly as it will appear. + + + + +Using a non-&kde; screen saver + +&kde; does not prevent another screen saver from working. To use a +different screen saver, such as xscreensaver, simply +disable the &kde; Screen Saver, and set up your other screen saver program +normally. + + + + + +
diff --git a/doc/kcontrol/solid-actions/CMakeLists.txt b/doc/kcontrol/solid-actions/CMakeLists.txt new file mode 100644 index 00000000..05eb12aa --- /dev/null +++ b/doc/kcontrol/solid-actions/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/solid-actions) diff --git a/doc/kcontrol/solid-actions/add-action.png b/doc/kcontrol/solid-actions/add-action.png new file mode 100644 index 00000000..67b4ea98 Binary files /dev/null and b/doc/kcontrol/solid-actions/add-action.png differ diff --git a/doc/kcontrol/solid-actions/edit-action.png b/doc/kcontrol/solid-actions/edit-action.png new file mode 100644 index 00000000..aa2731b2 Binary files /dev/null and b/doc/kcontrol/solid-actions/edit-action.png differ diff --git a/doc/kcontrol/solid-actions/index.docbook b/doc/kcontrol/solid-actions/index.docbook new file mode 100644 index 00000000..5cd818b0 --- /dev/null +++ b/doc/kcontrol/solid-actions/index.docbook @@ -0,0 +1,222 @@ + + + +]> +
+ +Device Actions + +BenCooksley +&Anne-Marie.Mahfouf; + + + +2013-12-05 +&kde; 4.12 + + +KDE +System Settings +Solid +actions +devices +hardware + + + + +Actions for new devices + +Introduction + +This module allows you to set up the actions you want to associate when +you plug new devices. + + +Screenshot of the Device Actions Manager + + + + + + Screenshot of the Device Actions Manager + + + + + +You will see listed all of the possible actions that are available when +devices are plugged in. +Please note that they will only be available under certain conditions. + + +Add + This will ask you to supply a name for your new action, then will open that +action for editing. + If you do not supply all the required details in that dialog, then your +action will be deleted. + + +Edit + This will allow you to change the Name, Icon, command to execute + and the conditions the action must match to be shown. + + +Discard / Cannot be deleted / Remove + This will do different actions, depending on if it was supplied with your +system or created by you. + You can only discard changes to system wide actions, if there are no changes +then these actions cannot be deleted. + User created actions are completely removed, including all changes. + + + + + + +Add Action + + +The Add button brings you a dialog to enter the +new action name. + + + +Screenshot of the Add Action dialog + + + + + + Screenshot of the Add Action dialog + + + + + +The action name should correctly describe the action. After entering a name and +clicking OK, the Edit Action dialog will show to allow +you to set up the action properties. + + + + +Edit Action + +This dialog allows you to change the settings of the action you +selected. + + +Screenshot of the Edit Action dialog + + + + + + Screenshot of the Edit Action dialog + + + + + +This includes the icon, the action name, the action command and the various +parameters. +You can change the icon by clicking on it. +The parameters are displayed in a +tree, the top item having to be true in order for the action to be shown. + + +Edit parameter + + +Parameter type + +This controls what can be contained inside it, or +what matching is performed to check if it is true. + + +Property Match + +Compares the specified property of the Device (using +Device type and Value name) and using the evaluator, compares it against the +text provided. + + + +Content Conjunction + +All sub-properties of this must be true for +it to be true itself. + + + +Content Disjunction + +Any sub-property of this may be true for it +to be true itself. + + + +Device interface match + +Checks to see if the Device can be +classed as the selected Device type. + + + + + + + + +Device type + +These are the possible device types supported by &kde; on +your system. +They are used in both Property and Device interface matches. + + + + +Value name + +This is a list of all possible property names for the +selected device type. +It also provides the selection of the value evaluator (which is either +Equals or Contains), and allows +entry of the text to be compared with. + + + +Reset Parameter + +Reverts any unsaved changes you have made to this parameter. + + + +Save Parameter changes + +Saves the changes you have made to the parameter. + + + + + + + +
+ + diff --git a/doc/kcontrol/solid-actions/main.png b/doc/kcontrol/solid-actions/main.png new file mode 100644 index 00000000..19c91c6a Binary files /dev/null and b/doc/kcontrol/solid-actions/main.png differ diff --git a/doc/kcontrol/splashscreen/CMakeLists.txt b/doc/kcontrol/splashscreen/CMakeLists.txt new file mode 100644 index 00000000..72d242cc --- /dev/null +++ b/doc/kcontrol/splashscreen/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/splashscreen) diff --git a/doc/kcontrol/splashscreen/get-new-theme.png b/doc/kcontrol/splashscreen/get-new-theme.png new file mode 100644 index 00000000..dc631ed7 Binary files /dev/null and b/doc/kcontrol/splashscreen/get-new-theme.png differ diff --git a/doc/kcontrol/splashscreen/index.docbook b/doc/kcontrol/splashscreen/index.docbook new file mode 100644 index 00000000..09777dc2 --- /dev/null +++ b/doc/kcontrol/splashscreen/index.docbook @@ -0,0 +1,117 @@ + + + +]> +
+Splash Screen + + + +Anne-Marie +Mahfouf + +
&Anne-Marie.Mahfouf.mail;
+
+
+ +
+ +2010-09-25 +&kde; 4.5 + + +KDE +System Settings +splash screen +theme + +
+ + +This module provides an interface to install and view splash screen themes. + + + +Here's a screenshot of the splash screen manager + + + + + + The splash screen manager module + + + + + +On the left you can see the list of already installed splash screens. The current splash screen name is highlighted. +On the right is displayed a preview of the current splash screen with some information about it below the preview. + + +Get New Themes... + + +You need to be connected to the Internet to use this action. A dialog will display a list of themes from the http://www.kde-look.org website. Clicking the Install button associated with a theme will install this theme locally. + + + +Installing a new theme + + + + + + Installing a new theme + + + + + +This new theme is immediately available after you close the System Settings Add-On Installer dialog and is highlighted. The preview displays the picture. You need to click the Apply biutton to make this theme your current splash-screen theme. + + + + +Install Theme File... + + +Instead of installing a theme directly as above you might have a tarball of a theme locally that you want to install. Clicking on this button will open a file dialog and you choose the tarball of the theme you want to install. The installer then unpacks the theme locally and makes it immediately available in the themes list. + + + + +Remove Theme + + +Removing a theme means removing the theme files from your disk. A message box warns you before doing anything and indicates to you what it will remove. Clicking on Delete in this message box will remove the splash screen theme from your disk. Clicking Cancel will abort the remove action. If you choose Delete, the theme is then no longer available in the list. + + + + +Test Theme + + +This shows you the theme and the associated icons as they will be displayed as splash screen when &kde; starts. Clicking on the splash screen hides it. + + + + + +
+ + diff --git a/doc/kcontrol/splashscreen/splash-main.png b/doc/kcontrol/splashscreen/splash-main.png new file mode 100644 index 00000000..375455e9 Binary files /dev/null and b/doc/kcontrol/splashscreen/splash-main.png differ diff --git a/doc/kcontrol/windowbehaviour/CMakeLists.txt b/doc/kcontrol/windowbehaviour/CMakeLists.txt new file mode 100644 index 00000000..d4349e09 --- /dev/null +++ b/doc/kcontrol/windowbehaviour/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/windowbehaviour) diff --git a/doc/kcontrol/windowbehaviour/index.docbook b/doc/kcontrol/windowbehaviour/index.docbook new file mode 100644 index 00000000..f0bf292d --- /dev/null +++ b/doc/kcontrol/windowbehaviour/index.docbook @@ -0,0 +1,676 @@ + + + +]> + + + +
+ +Window Behavior + +&Mike.McBride; &Mike.McBride.mail; +&Jost.Schenck; &Jost.Schenck.mail; + + + +2013-11-15 +&kde; 4.12 + + +KDE +KControl +system settings +actions +window placement +window size + + + +Window Behavior + + In the upper part of this control module you can see several +tabs: Focus, Titlebar Actions, +Window Actions, Moving and +Advanced. In the +Focus panel you can configure how windows gain or +lose focus, &ie; become active or inactive. Using +Titlebar Actions and Window Actions +you can configure how titlebars and windows react to +mouse clicks. Moving allows you to configure how +windows move and place themselves when started. The +Advanced options cover some specialized options +like window tabbing and window +shading. + + + + +Please note that the configuration in this module will not take effect +if you do not use &kde;'s native window manager, &kwin;. If you do use a +different window manager, please refer to its documentation for how to +customize window behavior. + + + + +Focus + + +The focus of the desktop refers to the window which the +user is currently working on. The window with focus is often referred to +as the active window. + + +Focus does not necessarily mean the window is the one at the +front — this is referred to as raised, and +although this is configured here as well, focus and raising of windows +are configured independently. + + +Focus Policy + + +There are six methods &kde; can use to determine the current focus: + + + + +Click To Focus + + +A window becomes active when you click into it. +This behaviour is common on other operating systems and likely what you want. + + + + +Click To Focus - Mouse Precedence + + +This is mostly the same as Click To Focus. +If an active window has to be chosen by the system +(⪚ because the currently active one was closed) +the window under the mouse is the preferred candidate. +Unusual, but possible variant of Click To Focus. + + + + + +Focus Follows Mouse + + +Moving the mouse pointer actively over a normal window activates it. New +windows such as the mini command line invoked with +&Alt;F2 will receive the focus, +without you having to point the mouse at them explicitly. +⪚ windows randomly appearing under the mouse will not gain the focus. +Focus stealing prevention takes place as usual. +Think as Click To Focus just without having to actually click. + + + +In other window managers, this is sometimes known as Sloppy focus +follows mouse. + + + + + +Focus Follows Mouse - Mouse Precedence + + +This is mostly the same as Focus Follows Mouse. +If an active window has to be chosen by the system +(⪚ because the currently active one was closed) +the window under the mouse is the preferred candidate. +Choose this, if you want a hover controlled focus. + + + + + +Focus Under Mouse + + +The window that happens to be under the mouse pointer becomes active. If +the mouse is not over a window (for instance, it's on the desktop) the last +window that was under the mouse has focus. New windows such as the mini +command line invoked with &Alt;F2 will +not receive the focus, you must move the mouse over them to type. + + + + + +Focus Strictly Under Mouse + +Similar to Focus Under Mouse, but even more +strict with its interpretation. Only the window under the mouse pointer is +active. If the mouse pointer is not over a window, no window has focus. +New windows such as the mini command line invoked with +&Alt;F2 will not receive the focus, +you must move the mouse over them to type. + + + + + + +Note that Focus Under Mouse and +Focus Strictly Under Mouse prevent certain +features, such as Focus stealing prevention and the +&Alt; +walk-through-windows dialog, from working properly. + + + + + +Focus stealing prevention level + +This option specifies how much KWin will try to prevent unwanted focus +stealing caused by unexpected activation of new windows. + + + +None +Prevention is turned off and new windows always become activated. + + +Low +Prevention is enabled; when some window does not have support +for the underlying mechanism and KWin cannot reliably decide whether to activate +the window or not, it will be activated. This setting may have both worse and better +results than the medium level, depending on the applications. + + +Medium +Prevention is enabled. + + + +High +New windows get activated only +if no window is currently active or if they belong to the currently active +application. This setting is probably not really usable when not using mouse +focus policy. + + +Extreme +All windows must be explicitly activated by the user. + + +Windows that are prevented from stealing focus are marked as demanding +attention, which by default means their taskbar entry will be highlighted. +This can be changed in the Notifications control module. + + + +Raising window + +Once you have determined the focus policy, there are the window +raising options. + + + +By placing a mark in front of Raise on hover, delayed by, &kde; can +bring a window to the front if the mouse is over that window for a +specified period of time. You can determine the delay for this option by using the spin box control. + + + + +Setting the delay too short will cause a rapid fire changing of +windows, which can be quite distracting. Most people will like a delay +of 100-300 ms. This is responsive, but it will let you slide over the +corners of a window on your way to your destination without bringing +that window to the front. + + + + +If you do not use auto raise, make sure the +Click raises active window option has a mark in front of it. You +will not be happy with both auto raise and +Click raise active window disabled, the net effect is that +windows are not raised at all. + + + + + + + +Titlebar Actions + + +In this panel you can configure what happens to windows when a mousebutton is +clicked on their titlebars. + + + +Titlebar double-click + + +In this drop down box you can select either +Shade, several variations of +Maximize or Lower. + + + +Selecting Maximize causes &kde; to maximize the +window whenever you doubleclick on the titlebar. You can further +choose to maximize windows only horizontally or only +vertically. + +Shade, on the other hand, causes the window to be +reduced to simply the titlebar. Double clicking on the titlebar again, +restores the window to its normal size. + + + + + + +You can have windows automatically unshade when you simply place the +mouse over their shaded titlebar. Just check the Enable +hover check box in the Advanced tab of +this module. This is a great way to reclaim desktop space when you are +cutting and pasting between a lot of windows, for example. + + + + + + +<guilabel>Titlebar & Frame</guilabel> + + +This section allows you to determine what happens when you single click +on the titlebar or frame of a window. Notice that you can have +different actions associated with the same click depending on whether +the window is active or not. + + + For each combination of mousebuttons, Active and +Inactive, you can select the most appropriate choice. The actions are +as follows: + + + +Activate + + +Make this window active. + + + + + +Lower + + +Will move this window to the bottom of the display. This will get the +window out of the way. + + + + + +Nothing + + +Just like it says. Nothing happens. + + + + + +Operations Menu + + +Will bring up a small submenu, where you can choose window related +commands (&ie; Maximize, Minimize, Close, &etc;). + + + + + +Raise + + +Will bring the window to the top of the display. All other windows +which overlap with this one, will be hidden below it. + + + + + +Toggle Raise & Lower + + +This will raise windows which are not on top, and lower windows which +are already on top. + + + + + + + + +<guilabel>Maximize Button</guilabel> + +This section allows you to determine the behavior of the three mouse buttons +onto the maximize button. You have the choice between vertical only, horizontal +only or both directions. + + + + + + +Window Actions + + +<guilabel>Inactive Inner Window</guilabel> + + +This part of the module, allows you to configure what happens when you +click on an inactive window, with any of the three mouse buttons or use +the mouse wheel. + + + +Your choices are as follows: + + + + +Activate, Raise & Pass Click + + +This makes the clicked window active, raises it to the top of the +display, and passes a mouse click to the application within the window. + + + + + +Activate & Pass Click + + +This makes the clicked window active and passes a mouse click to the +application within the window. + + + + + +Activate + + +This simply makes the clicked window active. The mouse click is not +passed on to the application within the window. + + + + + +Activate & Raise + + +This makes the clicked window active and raises the window to the top of +the display. The mouse click is not passed on to the application within +the window. + + + + + + + + + + +<guilabel>Inner Window, Titlebar & Frame</guilabel> + + +This bottom section, allows you to configure additional actions, when +a modifier key (by default &Alt;) is pressed, and a mouse click is +made on a window. + + +Once again, you can select different actions for +Left, Middle and +Right button clicks and the Mouse +wheel. + + +Your choices are: + + + +Lower + + +Will move this window to the bottom of the display. This will get the +window out of the way. + + + + + +Move + + +Allows you to drag the selected window around the desktop. + + + + + +Nothing + + +Just like it says. Nothing happens. + + + + + +Raise + + +Will bring the window to the top of the display. All other windows +which overlap with this one, will be hidden below it. + + + + + +Resize + + +Allows you to change the size of the selected window. + + + + + +Toggle Raise & Lower + + +This will raise windows which are not on top, and lower windows which +are already on top. + + + + + + + + + + + + +Moving + + +<guilabel>Windows</guilabel> + +The options here determine how windows appear on screen when you +are moving them. + + + +Display window geometry when moving or resizing + +Enable this option if you want a window's geometry to be displayed +while it is being moved or resized. The window position relative to the top-left +corner of the screen is displayed together with its size. + + + + + + + +<guilabel>Snap Zones</guilabel> + +The rest of this page allows you to configure the Snap +Zones. These are like a magnetic field along the side of +the desktop and each window, which will make windows snap alongside +when moved near. + + + +Border snap zone: + + +Here you can set the snap zone for screen borders. Moving a +window within the configured distance will make it snap to the edge of +the desktop. + + + + +Window snap zone: + + +Here you can set the snap zone for windows. As with screen +borders, moving a window near to another will make it snap to the edge +as if the windows were magnetized. + + + + +Center snap zone: + + +Here you can set the snap zone for the screen center, &ie; the +strength of the magnetic field which will make windows snap +to the center of the screen when moved near it. + + + + + +Snap windows only when overlapping + + +If checked, windows will not snap together if they are only near +each other, they must be overlapping, by the configured amount or +less. + + + + + + + + +Advanced + + +In the Advanced panel you can do more advanced fine +tuning to the window behavior. + + + +Shading + + +Enable hover + + +If this option is enabled, a shaded window will un-shade automatically +when the mouse pointer has been over the titlebar for some time. Use +the spinbox to configure the delay un-shading. + + + + + + +Window Tabbing + + +Automatically group similar windows +When turned on attempt to automatically detect when a newly opened window is +related to an existing one and place them in the same window group. + + + +Switch to automatically grouped windows immediately +When turned on immediately switch to any new window tabs that were +automatically added to the current group. + + + +Placement +The placement policy determines where a new window will appear +on the desktop. Smart will try to achieve a minimum +overlap of windows, Cascade will cascade the +windows, and Random will use a random +position. Centered will open all new windows in +the center of the screen, and Zero-Cornered will +open all windows with their top left corner in the top left corner of +the screen. + + + + + +Special Window + +Hide utility windows for inactive applications +When turned on, utility windows (tool windows, torn-off menus,...) of +inactive applications will be hidden and will be shown only when the +application becomes active. Note that applications have to mark the windows +with the proper window type for this feature to work. + + + + + + + + +
diff --git a/doc/kcontrol/windowspecific/CMakeLists.txt b/doc/kcontrol/windowspecific/CMakeLists.txt new file mode 100644 index 00000000..69d7e2e9 --- /dev/null +++ b/doc/kcontrol/windowspecific/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/windowspecific) diff --git a/doc/kcontrol/windowspecific/Face-smile.png b/doc/kcontrol/windowspecific/Face-smile.png new file mode 100644 index 00000000..501cc796 Binary files /dev/null and b/doc/kcontrol/windowspecific/Face-smile.png differ diff --git a/doc/kcontrol/windowspecific/akgregator-info.png b/doc/kcontrol/windowspecific/akgregator-info.png new file mode 100644 index 00000000..c05311f7 Binary files /dev/null and b/doc/kcontrol/windowspecific/akgregator-info.png differ diff --git a/doc/kcontrol/windowspecific/akregator-attributes.png b/doc/kcontrol/windowspecific/akregator-attributes.png new file mode 100644 index 00000000..b22478fe Binary files /dev/null and b/doc/kcontrol/windowspecific/akregator-attributes.png differ diff --git a/doc/kcontrol/windowspecific/akregator-fav.png b/doc/kcontrol/windowspecific/akregator-fav.png new file mode 100644 index 00000000..553fc446 Binary files /dev/null and b/doc/kcontrol/windowspecific/akregator-fav.png differ diff --git a/doc/kcontrol/windowspecific/config-win-behavior.png b/doc/kcontrol/windowspecific/config-win-behavior.png new file mode 100644 index 00000000..afe9ebb4 Binary files /dev/null and b/doc/kcontrol/windowspecific/config-win-behavior.png differ diff --git a/doc/kcontrol/windowspecific/emacs-attribute.png b/doc/kcontrol/windowspecific/emacs-attribute.png new file mode 100644 index 00000000..4a75d35d Binary files /dev/null and b/doc/kcontrol/windowspecific/emacs-attribute.png differ diff --git a/doc/kcontrol/windowspecific/emacs-info.png b/doc/kcontrol/windowspecific/emacs-info.png new file mode 100644 index 00000000..c1a106e5 Binary files /dev/null and b/doc/kcontrol/windowspecific/emacs-info.png differ diff --git a/doc/kcontrol/windowspecific/focus-stealing-pop2top-attribute.png b/doc/kcontrol/windowspecific/focus-stealing-pop2top-attribute.png new file mode 100644 index 00000000..187e713d Binary files /dev/null and b/doc/kcontrol/windowspecific/focus-stealing-pop2top-attribute.png differ diff --git a/doc/kcontrol/windowspecific/index.docbook b/doc/kcontrol/windowspecific/index.docbook new file mode 100644 index 00000000..27df810b --- /dev/null +++ b/doc/kcontrol/windowspecific/index.docbook @@ -0,0 +1,1025 @@ + + + +]> + + +Window Rules + +&Lauri.Watts; &Lauri.Watts.mail; + + + Parts of this documentation was converted from the KDE UserBase KWin Rules page. + + + + + +&FDLNotice; +2012-06-02 + &kde; SC 4.9 + +Here you can customize window settings specifically only for +some windows. + + +KDE +KControl +window settings +window placement +window size + + + +Window Specific Settings: Quick Start + +Here you can customize window settings specifically only for +some windows. + + +Please note that this configuration will not take effect if you +do not use &kwin; as your window manager. If you do use a different +window manager, please refer to its documentation for how to customize +window behavior. + + +Many of the settings you can configure here are those you can +configure on a global basis in the Window Behavior +&systemsettings; module, however some of them are even more detailed. + +They encompass geometry, placement, whether a window should be +kept above or below others, focus stealing prevention, and translucency +settings. + +You can access this module in two ways: from the titlebar of the +application you wish to configure, or from the &systemsettings;. If you +start it from within &systemsettings; you can use the +New... to create a window profile, and the +Detect Window Properties button on the resulting dialog to +partially fill in the required information for the application +you wish to configure. + +You can also at any time Modify... or +Delete any stored settings profile, and +reorder the list. Reordering the list using the Move Up +and Move Down buttons effects on how they are applied. + + + + + +Overview +&kwin; allows the end-user to define rules to alter an application's window attributes. + +For example, when an application is started, it can be forced to always run on Virtual Desktop 2. Or a defect in an application can be worked-around to force the window above others. + +Step-by-step examples are provided along with detailed information on using the &kwin; Rule Editor to specify Window Matching and Window Attributes. + + +Examples and Application Workaround +To see what's possible, detailed examples are provided which can also be used to model your own rules. + +A special page is to dedicated to address Application Workaround. + + +KWin Rule Editor +Invoking the KWin Rule Editor + + + + + + + + + + + + + +There are several ways to invoke the &kwin; Rule Editor. Below are two: + + +Right-click on the title-bar of any window, choose More ActionsWindow Manager Settings... and in the Configure window, select Window Rules or + + +System SettingsWindow BehaviorWindow Rules + +The main window is used to: + + +Affect rules with New..., Modify... and Delete +Share rules with others via Import and Export +Ensure desired rule evaluation using Move Up and Move Down + +Rule Evaluation +When an application starts (or the rules are modified), &kwin; evaluates the rules from the top of the list to the bottom. For all rules which match a window, the collective set of attributes are applied to the window, then the window is displayed. + +Should two or more matching rules enable the same attribute, the setting in the first rule in the list is used. + +You can tailor children windows for the application by placing the more restrictive rules first - see the Kopete and Kopete Chat Window example. + + + +Rule Editor + + + + + + + + + + + + + +The editor is composed of four tabs: + + +Window matching +Size & Position +Arrangement & Access +Appearance & Fixes + +As the name implies, Window matching is used to specify criteria to match one or more windows. The other three tabs are used to alter the attributes of the matching windows. + +Panels can also be affected. + +Window Matching +Each window rule has user specified Window Matching criteria. &kwin; uses the criteria to determine whether the rule is applicable for an application. + + +Window Attributes +Along with Window Matching criteria, each window rule has a set of Window Attributes. The attributes override the corresponding application's settings and are applied before the window is displayed by &kwin;. + + + + + +Window Matching + + + + + + + + + + + + + +The Window Matching tab is used to specify the criteria &kwin; uses to evaluate whether the rule is applicable for a given window. + +Zero (match any window) or more of the following may be specified: + + +Window class (application) - match the class. +Match whole window class - include matching the secondary class. + + +Window role - restrict the match to the function of the window (⪚ a main window, a chat window, &etc;) +Window types - restrict the match to the type of window: Normal Window, Dialog Window, &etc; +Window title - restrict the match to the title of the window. +Machine (hostname) - restrict the match to the host name associated with the window. + +While it's possible to manually enter the above information, the preferred method is to use the Detect Window Properties button. + +For each field, the following operators can be applied against the field value: + + +Unimportant - ignore the field. +Exact Match +Substring Match + +Both Exact Match and Substring Match implement case insensitive matching. For example, AB matches the string AB, ab, Ab and aB. + + +Regular Expression - Qt's regular expressions are implemented - see pattern matching using regular expressions. + +Detect Window Properties + + + + + + + + + + + + + +The Detect Window Properties function simplifies the process of entering the matching-criteria. + + +For the application you'd like to create a rule, start the application. +Next, in the Window matching tab, set the number of seconds of delay before the Detect Window Properties function starts. The default is zero seconds. +Click on Detect Window Properties and +When the mouse-cursor turns to cross-hairs, place it inside the application window (not the title bar) and left-click. +A new window is presented with information about the selected window. Select the desired fields: +Secondary class name - some applications have a secondary class name. This value can be used to restrict windows by this value. +Window role +Window type +Window title + + + +Click the OK button to back-fill the Window Matching criteria. + +By using a combination of the information, a rule can apply to an entire application (by Class) or a to a specific window Type within the Class - say a Toolbar. + + + +Window Attributes + + + + + + + + + + + + + +The attributes which can be set are grouped by function in three tabs: + + +Size & Position +Arrangement & Access +Appearance & Fixes + +Each attribute has a set of parameters which determines its disposition. + +Parameters +Each attribute, minimally, accepts one of the following parameters. Additional, attribute-specific arguments are listed within each attribute definition. + + + Do Not Affect + + Ensure a subsequent rule, which matches the window, does not affect the attribute. + + + Apply Initially + + Start the window with the attribute and allow it to be changed at run-time. + + + Remember + + Use the attribute setting as defined in the rule and if changed at run-time, save and use the new value instead. + + + Force + + The setting cannot be changed at run-time. + + + Apply Now, Force Temporarily + + Apply/Force the setting once and unset the attribute.The difference between the two is at run-time, Apply Now allows the attribute to be changed and Force Temporarily prohibits it to be altered until all affected windows exit. + + + +For Apply Now, if the rule has no other attributes set, the rule is deleted after evaluation whereas Force Temporarily, the rule is deleted after the last affected window terminates. + + +Attributes +The Detect Window Properties button back-fills attribute-specific values - for more information see Window Matching. For example the height and width values of the Size attribute is set to the height and width of the detected window. + +Yes/No arguments are used to toggle on or off attributes. Leniency with grammar helps one understand how a setting will be processed. For example, the attribute Skip taskbar, when set to No means do not skip the taskbar. In other words, show the window in the taskbar. + +Size & Position + + Position + + Position the window's upper left corner at the specified x,y coordinate. + + + +&kwin;'s origin, (0,0), is the upper left of the desktop. + + + Size + + The width and height of the window. + + + Maximized horizontally, Maximized vertically, Fullscreen + + These attributes are used to toggle the maximum horizontal/minimum horizontal/full-screen window attribute. + + + Desktop + + Place the window on the specified (Virtual) Desktop. Use All Desktops to place the window on all Virtual Desktops. + + + Minimized, Shaded + + Toggle the Minimize and Shading window attribute. For example, a window can be started Minimized or if it is started Minimized, it can be forced to not. + + + +Maximized attribute is emulated by using both Maximized horizontally and Maximized vertically or Initial placement with the Maximizing argument. + + + Initial placement + + Override the global window placement strategy with one of the following: + +Default - use the global window placement strategy. +No Placement - top-left corner. +Smart - place where no other window exists. +Maximizing - start the window maximized. +Cascade - staircase-by-title. +Centered - center of the desktop. +Random +Top-Left Corner +Under Mouse +On Main Window - restrict placement of a child window to the boundaries of the parent window. + + + + + Ignore requested geometry + + Toggle whether to accept or ignore the window's requested geometry position. To avoid conflicts between the default placement strategy and the window's request, the placement strategy is ignored when the window's request is accepted. + + + Minimum size, Maximum size + + The minimum and maximum size allowed for the window. + + + Obey geometry restrictions + + Toggle whether to adhere to the window's requested aspect ratio or base increment.In order to understand this attribute, some background is required. Briefly, windows must request from the Window Manager, a base increment: the minimum number of height X width pixels per re-size request. Typically, it's 1x1. Other windows though, for example terminal emulators or editors, use fixed-fonts and request their base-increment according to the size of one character. + + + + +Arrangement & Access + + Keep above, Keep below + + Toggle whether to keep the window above/below all others. + + + Autogroup with identical + + Toggle the grouping (commonly known as tabbing) of windows. + + + Autogroup in foreground + + Toggle whether to make the window active when it is added to the current Autogroup. + + + Autogroup by ID + + Create a group via a user-defined ID. More than one rule can share the same ID to allow for seemingly unrelated windows to be grouped. + + + Tiling + + Override the default window behavior to either Tiled or Floating. + + + Skip taskbar + + Toggle whether to display the window in the taskbar. + + + Skip pager + + Toggle whether to display the window in pager: + + + + + + + + + + + + + + + + + + Skip switcher + + Toggle whether to display the window in the ALT+TAB list. + + + Shortcut + + Assign a shortcut to the window. When Edit... is clicked, additional instructions are presented. + + + + +Appearance & Fixes + + No titlebar and frame + + Toggle whether to display the titlebar and frame around the window. + + + Active/Inactive opacity + + When the window is active/inactive, set its opacity to the percentage specified. + + + +Active/Inactive opacity can only be affected when Desktop Effects are enabled. + + + Moving/resizing + + Deprecated as of >4.8 + + + + Focus stealing prevention + + When a window wants focus, control on a scale (from None to Extreme) whether to honor the request and place above all other windows, or ignore its request (potentially leaving the window behind other windows): + +None - Always grant focus to the window. +Low +Normal +High +Extreme - The window's focus request is denied. Focus is only granted by explicitly requesting via the mousing. + + + + + +See Accept focus to make a window read-only - not accept any keyboard input. + + + Accept focus + + Toggle whether the window accepts keyboard input. Make the window read-only. + + + Ignore global shortcuts + + Toggle whether to ignore global shortcuts (as defined by System SettingsShortcuts and GesturesGlobal Shortcuts or by running kcmshell4 keys in konsole) while the window is active. + + + Closeable + + Toggle whether to display the Close button on the title bar. + + + +A terminal window may still be closed by the end user by ending the shell session however using Accept focus to disable keyboard input will make it more difficult to close the window. + + + Window type + + Change the window to another type and inherit the characteristics of that window: + +Normal Window +Dialog Window +Utility Window +Dock (panel) +Toolbar +Torn-Off Menu +Splash Screen +Desktop +Standalone Menubar + + + + + +Use with care because unwanted results may be introduced. For example, a Splash Screen is a automatically closed by &kwin; when clicked. + + + Block compositing + + Toggle whether to disable compositing while the window exists. If compositing is enabled and the rule specifies to disable compositing, while any matching window exists, compositing will be disabled. Compositing is re-enabled when the last matching window terminates. + + + + + + +Examples +The first example details all the necessary steps to create the rules. In order to keep this page a manageable size, subsequent examples only list steps specific to the example. + +The Pager attribute refers to the Virtual Desktop Manager: + + + + + + + + + + + + +Pin a Window to a Desktop and set other Attributes +Pin &akregator; to Virtual Desktop 2. Additionally, start the application with a preferred size and position. For each attribute, use the Apply Initially parameter so it can be overridden at run-time. + +The &kwin; rule is created as follows: + + +Start &akregator; on desktop two, size and position it to suit: + + + + + + + + + + + +Right-click on the titlebar and select More ActionsWindow Manager Settings...: + + + + + + + + + + + +Select the Window Rules in the left column and click on New...: + + + + + + + + + + + +The Edit Window-Specific Settings window is displayed. Window matching is the default tab: + + + + + + + + + + + +Click Detect Window Properties with 0s delay the cursor immediately turns into cross-hairs. Click (anywhere) inside the &akregator; window (but not the title bar). The window criteria are presented. Match only by primary class name so leave the check boxes unchecked - for additional information see window matching: + + + + + + + + + + + +Clicking OK the previous window back-fills the results in the Window Matching tab. Enter a meaningful text in the Description field (which is displayed in the KWin Rule window): + + + + + + + + + + + +Enable the window attributes: Position, Size and Desktop. The initial values are set by Detect Window Properties and can be overridden: + + + + + + + + + + + +Clicking OK in the previous window returns to the main KWin Rules. The new rule with its description is listed: + + + + + + + + + + + +Click OK to close the window. +Done. + + +Application on all Desktops and Handle One Child Window Uniquely +Except for conversation windows, display &kopete; and its children windows on all desktops and skip the systray and pager. For children conversation windows, treat them as the parent window except show them in systray. + +For each attribute, use the Force parameter so it can not be overridden. + +In order to implement the above, two rules need to be created: + + +A rule for Kopete Chat and +A rule for &kopete; + +The Kopete Chat rule's matching-criteria is more restrictive than the Kopete rule as it needs to match a specific Window Role: the chat window. Due to rule evaluation processing, the Kopete Chat rule must precede the &kopete; rule in the KWin Rule list for Kopete. + +Kopete Chat Rule +Assuming a Kopete Chat window is open: + + +Use Detect Window Properties and select the Kopete Chat window. Check the Window role box to restrict the criteria to chat windows - for additional information see window matching: + + + + + + + + + + + +Clicking OK in the previous window back-fills the results in the Window Matching tab. Enter a meaningful text in the Description box: + + + + + + + + + + + +Enable the following attributes: + + + + + + + + + + + +Click through to complete entry of the rule. + +The Skip taskbar attribute is set to No to display the window in the taskbar which loosely translates to: no do not skip taskbar . + + +Kopete Rule +Assuming &kopete; is open: + + +Use Detect Window Properties and select the &kopete; window. Match only by primary class name so leave the check boxes unchecked - for additional information see window matching: + + + + + + + + + + + +Clicking OK in the previous window back-fills the results in the Window Matching tab. Enter a meaningful text in the Description box: + + + + + + + + + + + +Enable the following attributes: + + + + + + + + + + + +Click through to complete entry of the rule. + + +Kopete KWin Rule List +As mentioned, due to rule evaluation processing, the Kopete Chat rule must precede the &kopete; rule: + + + + + + + + + + + + + + +Suppress a Window from showing on Pager +KNotes currently does not allow for its notes to skip the pager however a rule easily solves this shortcoming. + +Assuming a sticky note' window is available: + + +Use Detect Window Properties and select any sticky note window. Match only by primary class name so leave the check boxes unchecked - for additional information see window matching: + + + + + + + + + + + +Clicking OK in the previous window back-fills the results in the Window Matching tab. Enter a meaningful text in the Description box: + + + + + + + + + + + +Enable the Skip Pager attribute with the Force parameter: + + + + + + + + + + + +Click through to complete entry of the rule. + + +Force a Window to the Top +To pop an active window to the top, set its Focus stealing prevention attribute to None, typically, in conjunction with the Force parameter: + + + + + + + + + + + + + +Multiple Rules per Application +Thunderbird has several different child windows. This example: + + +Pin Thunderbird's main window on Virtual Desktop 1 with a specific size and location on the desktop. +Allow the Thunderbird composer window to reside on any desktop and when activated, force focus and pop it to the top of all windows. +Pop the Thunderbird reminder to the top and do not give it focus so it isn't inadvertently dismissed. + +Each rule's matching criteria is sufficiently restrictive so their order within the main &kwin; window is not important to affect rule evaluation. + +Thunderbird - Main +Assuming the Thunderbird Main window is open, sized and position to suit: + + +Use Detect Window Properties and select the Thunderbird Main window. Check the Window role box to restrict the criteria to the main window - for additional information see window matching: + + + + + + + + + + + +Clicking OK in the previous window back-fills the results in the Window Matching tab. Enter a meaningful text in the Description box: + + + + + + + + + + + +Enable the following attributes: + + + + + + + + + + + +Click through to complete entry of the rule. + + +Thunderbird - Composer +Assuming a Thunderbird Composer window is open: + + +Use Detect Window Properties and select the Thunderbird Compose window. Check the Window role and Window type boxes to restrict the criteria to composition windows - for additional information see window matching: + + + + + + + + + + + +Clicking OK in the previous window back-fills the results in the Window Matching tab. Enter a meaningful text in the Description box: + + + + + + + + + + + +Enable the following attributes: + + + + + + + + + + + +Click through to complete entry of the rule. + + +Thunderbird - Reminder +Assuming a Thunderbird Reminder window is open: + + +Use Detect Window Properties and select the Thunderbird Reminder window. Check the Secondary class name and Window Type boxes to restrict the criteria to reminder windows - for additional information see window matching: + + + + + + + + + + + +Clicking OK in the previous window back-fills the results in the Window Matching tab. Enter a meaningful text in the Description box: + + + + + + + + + + + +Enable the following attributes: + + + + + + + + + + + +Click through to complete entry of the rule. + + + + + +Application Workarounds +Below are Workarounds for misbehaving applications. + +If you are unfamiliar with creating &kwin; Rules, see this detailed example to base your new rule. + +Full-screen Re-size Error +&Emacs; and gVim, when maximized (full-screen mode) and under certain conditions may encounter window re-sizing issues - see Emacs window resizes ... A &kwin; Rule will work-around the issue. + +Assuming an &Emacs; window is open: + + +Use Detect Window Properties and select the &Emacs; window. Match only by primary class name so leave the check boxes unchecked - for additional information see window matching + + + + + + + + + + + +Clicking OK in the previous window back-fills the results in the Window Matching tab. Enter a meaningful text in the Description text box: + + + + + + + + + + + +Ignore &Emacs;'s full-screen request by enabling the Obey geometry restrictions attribute, toggling it to off (No) to ignore and selecting the Force parameter: + + + + + + + + + + + +Click through to complete entry of the rule. + + + + + + +Credits and License + +Documentation Copyright see the UserBase + KWin Rules page history + +&underFDL; + +&documentation.index; + diff --git a/doc/kcontrol/windowspecific/knotes-attribute.png b/doc/kcontrol/windowspecific/knotes-attribute.png new file mode 100644 index 00000000..3f15cc9a Binary files /dev/null and b/doc/kcontrol/windowspecific/knotes-attribute.png differ diff --git a/doc/kcontrol/windowspecific/knotes-info.png b/doc/kcontrol/windowspecific/knotes-info.png new file mode 100644 index 00000000..522b984c Binary files /dev/null and b/doc/kcontrol/windowspecific/knotes-info.png differ diff --git a/doc/kcontrol/windowspecific/kopete-attribute-2.png b/doc/kcontrol/windowspecific/kopete-attribute-2.png new file mode 100644 index 00000000..95dc5b00 Binary files /dev/null and b/doc/kcontrol/windowspecific/kopete-attribute-2.png differ diff --git a/doc/kcontrol/windowspecific/kopete-chat-attribute.png b/doc/kcontrol/windowspecific/kopete-chat-attribute.png new file mode 100644 index 00000000..06e303e4 Binary files /dev/null and b/doc/kcontrol/windowspecific/kopete-chat-attribute.png differ diff --git a/doc/kcontrol/windowspecific/kopete-chat-info.png b/doc/kcontrol/windowspecific/kopete-chat-info.png new file mode 100644 index 00000000..4569419a Binary files /dev/null and b/doc/kcontrol/windowspecific/kopete-chat-info.png differ diff --git a/doc/kcontrol/windowspecific/kopete-info.png b/doc/kcontrol/windowspecific/kopete-info.png new file mode 100644 index 00000000..ca4dfe77 Binary files /dev/null and b/doc/kcontrol/windowspecific/kopete-info.png differ diff --git a/doc/kcontrol/windowspecific/kwin-detect-window.png b/doc/kcontrol/windowspecific/kwin-detect-window.png new file mode 100644 index 00000000..ae31d5eb Binary files /dev/null and b/doc/kcontrol/windowspecific/kwin-detect-window.png differ diff --git a/doc/kcontrol/windowspecific/kwin-kopete-rules.png b/doc/kcontrol/windowspecific/kwin-kopete-rules.png new file mode 100644 index 00000000..48901312 Binary files /dev/null and b/doc/kcontrol/windowspecific/kwin-kopete-rules.png differ diff --git a/doc/kcontrol/windowspecific/kwin-rule-editor.png b/doc/kcontrol/windowspecific/kwin-rule-editor.png new file mode 100644 index 00000000..e42b7b26 Binary files /dev/null and b/doc/kcontrol/windowspecific/kwin-rule-editor.png differ diff --git a/doc/kcontrol/windowspecific/kwin-rules-main-n-akregator.png b/doc/kcontrol/windowspecific/kwin-rules-main-n-akregator.png new file mode 100644 index 00000000..a801fef8 Binary files /dev/null and b/doc/kcontrol/windowspecific/kwin-rules-main-n-akregator.png differ diff --git a/doc/kcontrol/windowspecific/kwin-rules-main.png b/doc/kcontrol/windowspecific/kwin-rules-main.png new file mode 100644 index 00000000..fa290fab Binary files /dev/null and b/doc/kcontrol/windowspecific/kwin-rules-main.png differ diff --git a/doc/kcontrol/windowspecific/kwin-rules-ordering.png b/doc/kcontrol/windowspecific/kwin-rules-ordering.png new file mode 100644 index 00000000..1397150d Binary files /dev/null and b/doc/kcontrol/windowspecific/kwin-rules-ordering.png differ diff --git a/doc/kcontrol/windowspecific/kwin-window-attributes.png b/doc/kcontrol/windowspecific/kwin-window-attributes.png new file mode 100644 index 00000000..b6223522 Binary files /dev/null and b/doc/kcontrol/windowspecific/kwin-window-attributes.png differ diff --git a/doc/kcontrol/windowspecific/kwin-window-matching.png b/doc/kcontrol/windowspecific/kwin-window-matching.png new file mode 100644 index 00000000..50162f98 Binary files /dev/null and b/doc/kcontrol/windowspecific/kwin-window-matching.png differ diff --git a/doc/kcontrol/windowspecific/pager-4-desktops.png b/doc/kcontrol/windowspecific/pager-4-desktops.png new file mode 100644 index 00000000..4f2b2832 Binary files /dev/null and b/doc/kcontrol/windowspecific/pager-4-desktops.png differ diff --git a/doc/kcontrol/windowspecific/tbird-compose-attribute.png b/doc/kcontrol/windowspecific/tbird-compose-attribute.png new file mode 100644 index 00000000..ee0cdf46 Binary files /dev/null and b/doc/kcontrol/windowspecific/tbird-compose-attribute.png differ diff --git a/doc/kcontrol/windowspecific/tbird-compose-info.png b/doc/kcontrol/windowspecific/tbird-compose-info.png new file mode 100644 index 00000000..2bde0f93 Binary files /dev/null and b/doc/kcontrol/windowspecific/tbird-compose-info.png differ diff --git a/doc/kcontrol/windowspecific/tbird-main-attribute.png b/doc/kcontrol/windowspecific/tbird-main-attribute.png new file mode 100644 index 00000000..98e81eeb Binary files /dev/null and b/doc/kcontrol/windowspecific/tbird-main-attribute.png differ diff --git a/doc/kcontrol/windowspecific/tbird-main-info.png b/doc/kcontrol/windowspecific/tbird-main-info.png new file mode 100644 index 00000000..ecaff484 Binary files /dev/null and b/doc/kcontrol/windowspecific/tbird-main-info.png differ diff --git a/doc/kcontrol/windowspecific/tbird-reminder-attribute-2.png b/doc/kcontrol/windowspecific/tbird-reminder-attribute-2.png new file mode 100644 index 00000000..9110bc65 Binary files /dev/null and b/doc/kcontrol/windowspecific/tbird-reminder-attribute-2.png differ diff --git a/doc/kcontrol/windowspecific/tbird-reminder-info.png b/doc/kcontrol/windowspecific/tbird-reminder-info.png new file mode 100644 index 00000000..bcaf2c44 Binary files /dev/null and b/doc/kcontrol/windowspecific/tbird-reminder-info.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-emacs.png b/doc/kcontrol/windowspecific/window-matching-emacs.png new file mode 100644 index 00000000..d0404b1b Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-emacs.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-init.png b/doc/kcontrol/windowspecific/window-matching-init.png new file mode 100644 index 00000000..0bdbcf3f Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-init.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-knotes.png b/doc/kcontrol/windowspecific/window-matching-knotes.png new file mode 100644 index 00000000..2e33a43c Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-knotes.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-kopete-chat.png b/doc/kcontrol/windowspecific/window-matching-kopete-chat.png new file mode 100644 index 00000000..a232d3b9 Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-kopete-chat.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-kopete.png b/doc/kcontrol/windowspecific/window-matching-kopete.png new file mode 100644 index 00000000..dbab3bd3 Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-kopete.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-ready-akregator.png b/doc/kcontrol/windowspecific/window-matching-ready-akregator.png new file mode 100644 index 00000000..f2c0f7c2 Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-ready-akregator.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-tbird-compose.png b/doc/kcontrol/windowspecific/window-matching-tbird-compose.png new file mode 100644 index 00000000..30e8494d Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-tbird-compose.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-tbird-main.png b/doc/kcontrol/windowspecific/window-matching-tbird-main.png new file mode 100644 index 00000000..4dda3601 Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-tbird-main.png differ diff --git a/doc/kcontrol/windowspecific/window-matching-tbird-reminder.png b/doc/kcontrol/windowspecific/window-matching-tbird-reminder.png new file mode 100644 index 00000000..2787ac1f Binary files /dev/null and b/doc/kcontrol/windowspecific/window-matching-tbird-reminder.png differ diff --git a/doc/kcontrol/workspaceoptions/CMakeLists.txt b/doc/kcontrol/workspaceoptions/CMakeLists.txt new file mode 100644 index 00000000..f8c96f80 --- /dev/null +++ b/doc/kcontrol/workspaceoptions/CMakeLists.txt @@ -0,0 +1,2 @@ +########### install files ############### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kcontrol/workspaceoptions) diff --git a/doc/kcontrol/workspaceoptions/index.docbook b/doc/kcontrol/workspaceoptions/index.docbook new file mode 100644 index 00000000..cfad4e1d --- /dev/null +++ b/doc/kcontrol/workspaceoptions/index.docbook @@ -0,0 +1,104 @@ + + + +]> +
+ +Workspace + +&Marco.Martin;&Marco.Martin.mail; + + + +2011-08-24 +&kde; 4.7 + + +KDE +System Settings +desktop +workspace +netbook + + + + +Workspace + +This is a module to configure global options for the Plasma workspace. + + + +Workspace Type +In this section you can configure the type of workspace you will be +using. Right now there are two options: + + + +Desktop + +A workspace optimized for traditional desktops and laptop computers. + + + + +Netbook + +A workspace optimized for netbooks and in general for devices with +a smaller screen resolution. + + + + + + + +Dashboard + +In the dashboard section you can configure the behavior of the Plasma dashboard. +Right now there are two options: + + + + +Show Desktop Widgets + +The dashboard will show the same widgets present on the desktop. + + + + +Show an Independent Widget Set + +The dashboard will present an independent +set of widget that is different from the ones in the desktop. + + + + + + + +Informational Tips + +Show Informational Tips are displayed hovering items in the +Plasma panel or on the desktop. + + +
+ + + diff --git a/doc/kdm/CMakeLists.txt b/doc/kdm/CMakeLists.txt new file mode 100644 index 00000000..312e2ec2 --- /dev/null +++ b/doc/kdm/CMakeLists.txt @@ -0,0 +1,6 @@ +set(confproc ${KDEBASE_WORKSPACE_SOURCE_DIR}/kdm/confproc.pl) +set(confdef ${KDEBASE_WORKSPACE_SOURCE_DIR}/kdm/config.def) +set(confdoc ${CMAKE_CURRENT_SOURCE_DIR}/kdmrc-ref.docbook) +add_custom_target(ref + COMMAND ${PERL_EXECUTABLE} -w ${confproc} --doc ${confdef} ${confdoc}) +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/kdm/index.docbook b/doc/kdm/index.docbook new file mode 100644 index 00000000..e84ee008 --- /dev/null +++ b/doc/kdm/index.docbook @@ -0,0 +1,1786 @@ + + + + kdmrc"> + ksmserver"> + kdesktop"> + XDMCP"> + xdm"> + + + + +]> + + + +The &kdm; Handbook + + + +&Oswald.Buddenhagen; &Oswald.Buddenhagen.mail; + + + + + + + +2000 +&Neal.Crook; + + + +20022007 +&Oswald.Buddenhagen; + + + +2003 +&Lauri.Watts; + + +&FDLNotice; + +2007-12-07 +0.06.00 + + +This document describes &kdm; the &kde; Display Manager. &kdm; +is also known as the Login Manager. + + + +KDE +kdm +xdm +display manager +desktop manager +login manager + + + + + +Introduction + +&kdm; provides a graphical interface that allows you to log in to a +system. It prompts for login (username) and password, authenticates the user +and starts a session. &kdm; is superior to &xdm;, the X +Display Manager, in a number of ways. + + + + + + + +Quick Start Guide + +This is a quick start guide for users who fit the following +pattern: + + + +X is configured and works with the command +startx from the commandline. + + +Each user will generally only use a single window manager or +desktop environment, and does not change this choice very +often, or is comfortable editing a single text file in order to change +their choice. + + + +This scenario will be sufficient for many environments where a single +user or several users normally boot the computer and log into their +preferred environment. + + +Setting up a Default Session + +Create or open the file ~/.xinitrc +If you already have a working ~/.xinitrc, go to +the next step + + +If one does not already exist, add a line to the +~/.xinitrc to start your preferred window manager +or desktop environment. +For &kde; you should enter: +startkde +For other window managers or desktop environments, you should +look in their documentation for the correct command. + +Make a link as follows: +ln ~/.xinitrc ~/.xsession + + + +At this point, typing startx +on the commandline should start X, with a &kde; session. The next task is +to try &kdm;. + +As root, type +kdm at the prompt. + +You should see a login window, which is described more fully in . + +Typing your normal username and password in the fields provided, and +leaving selected as the session type should now +open a &kde; session for your user. + +If you have other users to configure, you should repeat the procedure +above for each of them. + + +This is a quick guide to getting up and running only. You probably +will want to customize &kdm; further, for example, to hide the names of the +system accounts, to allow further sessions, and much more. Please read +through the rest of this manual to find out how to do these things. + + + + + +The Login Window + + The user interface to &kdm; consists of dialog boxes. The main +dialog box contains: + + + +Widgets allowing you to authenticate. When the "classic" authentication +method is chosen, these are: + + + +A Username: field for you to enter your +username. + + + +A Password: field for you to enter your +password. + + + + + + +(Optionally) a list containing entries with the name and graphical +image of each user (for example, a digitized photograph). +Clicking a list entry is equivalent to typing the associated username +into the Username: field. + + + +(Optionally) a region to the right of or above the +authentication area which can be used to display either a static image or an +analog clock. + + + +A Login button that validates the +username/password combination and attempts to start a session of the +selected type. + + + +A Menu button that opens an action menu +with the following items: + + + +(Optionally) A Session Type item +to choose the type of session (desktop environment, window manager) to start. +See to find out +how to configure different session types. + + + +(Optionally) A Authentication Method item +to switch between different authentication methods like the classical +username+password, smartcard, biometry, &etc; The actual authenticators +are combinations of PAM modules and matching frontend +modules (conversation plugins). See +. + + + +(Optionally on local displays) A +Switch User... item to switch between local +sessions running on different virtual terminals of this computer. + + + +(Optionally on local displays) A +Restart X Server item +that terminates the currently running &X-Server;, starts a new one and +displays the login dialog again. You can use this if the display content +seems to be broken somehow. + + + +(Optionally on remote displays) A +Close Connection +item that closes the connection to the &XDMCP; server you are currently +connected to. If you got to this server through a host chooser, this will +bring you back to the chooser, otherwise it will only reset the &X-Server; +and bring up the login dialog again. + + + +(Optionally on local displays) A +Remote Login item that displays a host chooser +dialog with &XDMCP; servers one can log into remotely. + + + +(Optionally on local displays) A Console Mode +item that terminates graphical login and leaves you at the console. See + and +. + + + +(Optionally) A Shutdown... item that displays +the Shutdown dialog box. + + + + + + + +The Shutdown dialog box presents a set of +buttons that allow one of these actions to be executed: + + + +Turn Off Computer + +Shut the system down in a controlled manner, ready for +power-down. + + + +Restart Computer + +Shut the system down and reboot. For systems that use +Lilo or Grub, +an optional drop down box allows you to select a particular operating system +to be used for the reboot. + + + +Schedule... + +If this option is enabled, you may use it to enter a more complex +shutdown dialog. See for details. + + + + +Pressing the Cancel button returns to the +main &kdm; dialog box. + + + + + +Configuring &kdm; + +This chapter assumes that &kdm; is already up and running on your +system, and that you simply want to change its behavior in some way. + +When &kdm; starts up, it reads its configuration from the folder +$KDEDIR/share/config/kdm/ +(this may +be /etc/kde4/kdm/ or something else +on your system). + +The main configuration file is &kdmrc;; all other files are +referenced from there and could be stored under any name anywhere on +the system - but usually that would not make much sense for obvious +reasons (one particular exception is referencing configuration files +of an already installed &xdm; - however when a new &kdm; is installed, +it will import settings from those files if it finds an already installed +&xdm;). + +Since &kdm; must run before any user is logged in, it is not +associated with any particular user. Therefore, it is not possible to have +user-specific configuration files; all users share the common &kdmrc;. It +follows from this that the configuration of &kdm; can only be altered by +those users that have write access to +$KDEDIR/share/config/kdm/kdmrc (normally +restricted to system administrators logged in as root). + +You can view the &kdmrc; file currently in use on your system, and you +can configure &kdm; by editing this file. Alternatively, you can use the +graphical configuration tool provided by the &systemsettings; (the +Login Screen module in the System Administration category). + + +The remainder of this chapter describes configuration of &kdm; +via the &systemsettings; module, and the next +chapter describes the options available in &kdmrc; itself. If +you only need to configure for local users, the &systemsettings; module +should be sufficient for your needs. If you need to configure remote +logins, or have multiple &kdm; sessions running, you will need to read +on. + + + + + +&Thomas.Tanghus; &Thomas.Tanghus.mail; +&Steffen.Hansen; &Steffen.Hansen.mail; +&Mike.McBride; &Mike.McBride.mail; + + + +The Login Manager &systemsettings; Module + +Using this module, you can configure the &kde; graphical login +manager, &kdm;. You can change how the login screen looks, who has +access using the login manager and who can shutdown the +computer. + +All settings will be written to the configuration file +&kdmrc;, which in its original state has many comments to help you +configure &kdm;. Using this &systemsettings; module will strip these +comments from the file. All available options in &kdmrc; are covered +in . + +The options listed in this chapter are cross referenced with +their equivalents in &kdmrc;. All options available in the &systemsettings; +module are also available directly in &kdmrc; but the reverse is not +true. + +In order to organize all of these options, this module is +divided into several sections: General, +Dialog, Background, +Theme, +Shutdown, +Users and +Convenience. + +You can switch between the sections using the tabs at the top of +the window. + +You can only make changes if you run this module with superuser rights. + + +General + +First you have a drop down box to choose the language for +your login box, corresponding to setting in +&kdmrc;. + +In the Appearance section you have an option to use +&kdm; in themed mode. If Use themed greeter is checked, +the settings on the Dialog and Background +pages cannot be configured separately. + +While &kde;'s style depends on the settings of the user logged +in, the style used by &kdm; can be configured using the GUI +style: and Color scheme: options. +These correspond to the keys and in +&kdmrc; respectively. + +From the Fonts section of this page you can change the fonts used in the +login window. Only fonts available to all users are available here, not +fonts you have installed on a per user basis. + +You can select three different font styles in this section +(General:, Failure:, +Greeting:). When you click on the +Choose... button a dialog appears from which you can +select the new characteristics for the font style. + + + +The General: font is used in all other places in the +login window. + + +The Failure: font is used when a login +fails. + + +The Greeting: font is the font used for the title +(Greeting String). + + + +You can also check the box labeled Use anti-aliasing for +fonts if you want smoothed fonts in the login dialog. + + + + +Dialog + +From this page you can change the visual appearance of &kdm;, +&kde;'s graphical login manager in non themed mode. + +The Greeting: is the title of the login + screen. Setting this is especially useful if you have many servers users + may log in to. You may use various placeholders, which are described + along with the corresponding key + + in &kdmrc;. + + +You can then choose to show either the current system time, a logo or +nothing special in the login box. Make your choice in the radio buttons +labeled Logo area:. This corresponds to in &kdmrc; + +If you chose Show logo you can now choose a +logo: + + + +Drop an image file on the image button. + + +Click on the image button and select a new image from the image chooser +dialog. + + + +If you do not specify a logo, the default +$KDEDIR/share/apps/kdm/pics/kdelogo.xpm +will be displayed. + +Normally the login box is centered on the screen. +Drag the anchor to move the center of the dialog to the desired position. +Keyboard control is possible as well: Use the arrow keys or Home to center. +Note that the actual proportions of the dialog are probably different. +These correspond to the key + +in &kdmrc;. + + + + +Background + +Here you can change the desktop background which will be displayed +before a user logs in. Selecting Enable background +allows you to edit the options on this tab. + +This tab is comprised of three areas: + + + +An area for selecting background images + + +The background Preview Monitor + + +An area for determining the background color + + + + + +Preview Monitor + +This is a preview window. It will give you a sense of what to +expect with each change. + + + + +Background + +This section allows you to load a wallpaper on top of the color +gradient chosen in the section below. + +There are three choices available here: + + + +No Picture + +No picture background will be shown. The color and pattern +choices below will still take effect. + + + + +Picture + +A single picture will be used as the background for the selected +desktops. +How this picture is positioned and scaled can be fine tuned +below. + + + + +Slide show + +&kde; allows you to have an automatic slide show of wallpaper +images. To enable this option, press the Setup... +button. In the resulting dialog you may choose any +image or folder of images available on your computer, using the +Add... button to navigate your file system. +Remove will remove the currently selected +entry from the list. + +You may choose the length of time any image is displayed in the +Change picture after: box, and you may choose +Show pictures in random order if you don't want +them displayed in the order they are listed. + +Displaying wallpaper requires that the image be kept in +memory. If you are low on memory, using a small, tiled image or none +at all is recommended. + +Scaling or centering a small image still requires an image the +size of your display to be maintained in memory. + + + + + + + +Options + + + +<guilabel>Position:</guilabel> + +Centered +The image will be centered on the screen without changing the +size of the image. The background colors will be present anywhere the image +does not cover. + + +Tiled +The image will be duplicated until it fills the entire +desktop. The first image will be placed in the upper left corner of the screen, +and duplicated downward and to the right. + + +Center Tiled +The image will be duplicated until it +fills the entire desktop. The first image will be placed in the center of the +screen, and duplicated upward, downward to the right, and to the left. + + +Centered Maxpect +The image will be placed in the center of the screen. It will +be scaled to fit the desktop, but it will not change the aspect ratio of the +original image. This will provide you with an image that is not distorted. + + + +Tiled Maxpect + +The image will be placed in the corner of the screen. It will +be scaled to fit the desktop, but it will not change the aspect ratio +of the original image. This will provide you with an image that is +not distorted. If there is any space over, the image will be +duplicated to fill it. + + + +Scaled +The image will be scaled to fit the desktop. It will be +stretched to fit to all four corners. This may distort the image. + + +Centered Auto fit + +If the picture fits the desktop size, this mode works like the +centered option. If the picture is larger than the desktop then it is +scaled down to fit while keeping the aspect ratio. + + + + +Scale & Crop + +Magnify the picture without distorting it until it fills both the +width and height of the desktop (cropping the picture if necessary), and +then center it on the desktop. + + + + + + +Colors: + +The first drop down box allows you to choose the type of color, +gradient, or pattern to display under (or in place of) wallpaper. +If you are going to be using a picture as a wallpaper, you +can skip this section of the dialog box. +However, if your chosen wallpaper does not cover the entire +desktop, the chosen colors will still show in the remaining +space. + + + +Single Color +By choosing this mode, you select one color using the +first color bar, and the entire background is covered with this one +color. + + +Horizontal Gradient +By choosing this mode, you select two colors (using both color +buttons). &kde; will then start with the primary color selected with the left +button on the left edge of the screen, and slowly transform into the blend color +selected with the right button by the time it gets to the +right edge of the screen. + + +Vertical Gradient +By choosing this mode, you select two colors (using both color +buttons). &kde; will then start with the primary color selected with the left +button on the top edge of the screen, and slowly transform into the blend color +selected with the right button as it moves to the bottom of +the screen. + + +Pyramid Gradient +By choosing this mode, you select two colors (using both color +buttons). &kde; will then start with the primary color selected with the left +button in each corner of the screen, and slowly transform into the blend color +selected with the right button as it moves to the center of the +screen. + + +Pipecross Gradient +By choosing this mode, you select two colors (using both color +buttons). &kde; will then start with the primary color selected with the left +button in each corner of the screen, and slowly transform into the blend color +selected with the right button as it moves to the center of the screen. +The shape of this gradient is different than the pyramid gradient. + + +Elliptic Gradient +By choosing this mode, you select two colors (using both color +buttons). &kde; will then start with the blend color selected with the right +button in the center of the screen, and slowly +transform into the primary color selected by the left button +as it moves to the edges, in an elliptical pattern. + + + +Pattern + +The rest of the list are the names of various patterns +or textures you can choose. +For more on patterns, see +the section Adding, Removing and +Modifying Patterns. + +Select the primary color with the first color bar. If you have +chosen a pattern that requires two colors to be set the secondary +color can be set by pressing the appropriate button. + + + + + + + + + + +Blending: + +The drop down box labeled Blending: contains the +options to make a smooth transition (blend) from the wallpaper as it +changes to the background. + + +A drop down box allows you to select the blending mode. +Many of the modes are similar to blending modes for background colors. Select +your mode from the list, and the preview window shows you what it will look +like. +The Balance slider adjusts the +blending. The results can be seen immediately in the preview +window. +The Reverse roles can reverse the +role of the picture and the background for some types of +blending. + + + + + + + + + + +Advanced options +Located below the preview monitor is a button labeled +Advanced Options. + +To use an external program to determine and change the +background of &kde;, simply select Use the following program +for drawing the background. Available &kde; programs are +listed, select one to enable it. + + + + + +Adding, Removing and Modifying Wallpapers and Patterns + +There is a button under the preview monitor labeled Get +New Wallpapers that helps you fetch new wallpaper images from a +selection of popular images from the KDE-Look website. You can of course +select any image you have available to use as wallpaper, and it may be +stored in any location on your hard drive. To have a wallpaper show up in +the list automatically for all users, you should save it to the $KDEDIR/share/wallpapers +folder. + +A pattern is a picture file which &kde; uses as a template to +draw your background. The picture file provides the shapes, but &kde; +provides the colors. &kde; is packaged with several patterns, and you also +can add new patterns. + +To add a new pattern that is available to every user on your +computer, simply place the file in $KDEDIR/share/apps/kdm/patterns/. + +Copy a .desktop file from +this folder, and name it the same as your new pattern image file. +Modify the contents to suit your new pattern. + +To add a new pattern for a single user, add the files to +$KDEHOME/share/apps/kdm/patterns/. + +For best results, the pattern should be a grayscale PNG file. + + + + + + +Theme +This page consists of three sections: + +A list of installed themes, where you can select the one to be used. + +A screenshot with a preview of the selected theme and additional +information like Copyright and Description. + +Three buttons to install or remove a theme and a button to launch +the Get Hot New Stuff dialog where you can download new themes. + +The settings on this page are only available in themed mode. + + + + +Shutdown + +Allow Shutdown +Use this drop down box to choose who is allowed to shut down: + + +Nobody: No one can shutdown the computer using +&kdm;. You must be logged in, and execute a command. + + +Everybody: Everyone can shutdown the computer using +&kdm;. + +Only Root: &kdm; requires that the +root password be entered before shutting down the +computer. + + +You can independently configure who is allowed to issue a +shutdown command for the Local: and +Remote: users. + +Commands Use these text fields to +define the exact shutdown command. The +Halt: command defaults to +/sbin/halt. The Reboot: command +defaults to +/sbin/reboot. + +When Boot manager is set to Grub +or Lilo, &kdm; +will on reboot offer you options for these boot managers. Note that this +option is not available on all operating systems. + + + + +Users + +From here you can change the way users are represented in the +login window. + +Independently of the users you specify by name, you can use the +System UIDs to specify a range of valid +UIDs that are shown in the list. By default user +id's under 1000, which are often system or daemon users, and user id's +over 30000, are not shown. + +You may disable the user list in &kdm; entirely in the +Users section. You can choose from: + + + +Show list + +Only show users you have specifically not excluded in the list +alongside +If you do not check this box, no list will be shown. This is the most secure setting, since an +attacker would then have to guess a valid login name as well as a +password. It is also the preferred option if you have more than a +handful of users to list, or the list itself would become +unwieldy. + + + +Autocompletion + +If this option is checked, &kdm; will automatically complete user names while +they are typed in the line edit. + + + +Inverse selection + +Allows you to instead select a list of users that should +be shown, and all other users will not be +listed. + + + + +You can also enable the Sort users +checkbox, to have the user list sorted alphabetically. If this is +disabled, users will appear in the order they are listed in the +password file. &kdm; will also autocomplete user names if you enable the +Autocompletion option. + +If you choose to show users, then the login window will show +images (which you select), of a list of users. When someone is ready +to login, they may select their user name/image, enter their password, +and they are granted access. + +If you permit a user image, then you can configure the +User Image Source: + +Here you can specify where &kdm; will obtain the images that represent users. +System represents the global folder; these are the pictures you can set +below. User means that &kdm; should read the user's +$HOME/.face.icon file. +The two selections in the middle define the order of preference if both +sources are available. + + +If you choose not to show users, then the login window will be +more traditional. Users will need to type their username and password +to gain entrance. This is the preferred way if you have many users on +this terminal. + + + + +Convenience + +In the Convenience tab you can configure +some options that make life easier for lazy people, like automatic +login or disabling passwords. + +Please think more than twice before using these +options. Every option in the Convenience tab is +well-suited to seriously compromise your system security. Practically, +these options are only to be used in a completely non-critical +environment, ⪚ a private computer at home. + + +Automatic Login + +Automatic login will give anyone access to a certain account on +your system without doing any authentication. You can enable it using +the option Enable Auto-Login. + +You can choose the account to be used for automatic login from +the list labeled User:. + +With Lock session the automatically started session +will be locked immediately (provided it is a &kde; session). This can be used +to obtain a super-fast login restricted to one user. + + +Automatic login can be suppressed by pressing the &Shift; key immediately +after the &X-Server; switches to graphics mode and releasing it when &kdm;'s +hourglass cursor appears. + + + +<guilabel>Preselected User</guilabel> + +You can also choose which user is preselected +when &kdm; starts. The default is None, but you +can choose Previous to have &kdm; default to the +last successfully logged in user, or you can +Specify a particular user to always be selected +from the list. You can also have &kdm; set the focus to the password +field, so that when you reach the &kdm; login screen, you can type the +password immediately. + + + + +<guilabel>Password-Less Login</guilabel> + +Using this feature, you can allow certain users to login without +having to provide their password. Enable this feature using the +Enable Password-Less Logins option. + +Below this option you'll see a list of users on the system. +Enable password-less login for specific users by checking the checkbox +next to the login names. By default, this feature is disabled for +all users. + +Again, this option should only be used in a safe +environment. If you enable it on a rather public system you should +take care that only users with heavy access restrictions are granted +password-less login, ⪚ +guest. + +The Automatically login after X server crash +option allows you to skip the authentication procedure when your X +server accidentally crashed. + + + + + + + + + +&kdmrc-ref; + +&theme-ref; + + + +Configuring your system to use &kdm; + +This chapter assumes that your system is already configured to +run the &X-Window;, and that you only need to reconfigure it to +allow graphical login. + + +Setting up &kdm; + +The fundamental thing that controls whether your computer boots to a +terminal prompt (console mode) or a graphical login prompt is the default +runlevel. The runlevel is set by the program /sbin/init under the control of the +configuration file /etc/inittab. The default runlevels +used by different &UNIX; systems (and different &Linux; distributions) vary, +but if you look at /etc/inittab the start of it should +be something like this: + +# Default runlevel. The runlevels used by RHS are: +# 0 - halt (Do NOT set initdefault to this) +# 1 - Single user mode +# 2 - Multiuser, without NFS +# 3 - Full multiuser mode +# 4 - unused +# 5 - X11 +# 6 - reboot (Do NOT set initdefault to this) + +id:3:initdefault: + + +All but the last line of this extract are comments. The comments +show that runlevel 5 is used for X11 and that runlevel 3 is used for +multi-user mode without X11 (console mode). The final line specifies +that the default runlevel of the system is 3 (console mode). If your +system currently uses graphical login (for example, using &xdm;) its +default runlevel will match the runlevel specified for X11. + +The runlevel with graphical login (&xdm;) for some common &Linux; +distributions is: + + +5 for &RedHat; 3.x and later, and for &Mandrake; +4 for Slackware +3 for &SuSE;. 4.x and 5.x + + +The first step in configuring your system is to ensure that you +can start &kdm; from the command line. Once this is working, you can +change your system configuration so that &kdm; starts automatically +each time you reboot your system. + +To test &kdm;, you must first bring your system to a runlevel +that does not run &xdm;. To do so, issue a command like this: + +/sbin/init + +Instead of the number you should specify the +appropriate runlevel for console mode on your system. + +If your system uses Pluggable Authentication Modules +(PAM), which is normal with recent &Linux; and &Solaris; +systems, you should check that your PAM configuration permits +login through the service named kde. If you previously used +&xdm; successfully, you should not need to make any +changes to your PAM configuration in order to use +&kdm;. /etc/pam.conf or +/etc/pam.d/kde. Information on configuring +PAM is beyond the scope of this handbook, but +PAM comes with comprehensive documentation (try looking in +/usr/share/doc/*pam*/html/). + +Now it's time for you to test &kdm; by issuing the following +command: + +kdm + + +If you get a &kdm; login dialog and you are able to log in, +things are going well. The main thing that can go wrong here is that +the run-time linker might not find the shared &Qt; or &kde; libraries. +If you have a binary distribution of the &kde; libraries, make sure +&kdm; is installed where the libraries believe &kde; is installed and +try setting some environment variables to point to your &kde; and &Qt; +libraries. + +For example: + +export + +export + +export + +export + + + +If you are still unsuccessful, try starting &xdm; instead, to +make sure that you are not suffering from a more serious X +configuration problem. + +When you are able to start &kdm; successfully, you can start to +replace &xdm; by &kdm;. Again, this is distribution-dependent. + + + +For &RedHat;, edit /etc/inittab, look for this + line: +x:5:respawn:/usr/X11/bin/xdm -nodaemon +and replace with: +x:5:respawn:/opt/kde/bin/kdm +This tells init(8) to respawn &kdm; when the +system is in run level 5. Note that &kdm; does not need the + option. + + +For &Mandrake;, the X11 runlevel in +/etc/inittab invokes the shell script +/etc/X11/prefdm, which is set up to select from +amongst several display managers, including &kdm;. Make sure that all +the paths are correct for your installation. + + +For &SuSE;, edit /sbin/init.d/xdm to add a +first line: + +. /etc/rc.config +DISPLAYMANAGER=kdm +export DISPLAYMANAGER + +For FreeBSD, edit /etc/ttys and find +the line like this: +ttyv8 "/usr/X11R6/bin/xdm -nodaemon" xterm off secure +and edit it to this: +ttyv8 "/opt/kde/bin/kdm" xterm on secure + + +Most other distributions are a variation of one of +these. + + +At this stage, you can test &kdm; again by bringing your system +to the runlevel that should now run &kdm;. To do so, issue a command +like this: + +/sbin/init + + +Instead of the number you should specify the +appropriate runlevel for running X11 on your system. + +The final step is to edit the initdefault +entry in /etc/inittab to specify the appropriate +runlevel for X11. + +Before you make this change, ensure that you have a way +to reboot your system if a problem occurs. This might be a +rescue floppy-disk provided by your operating system +distribution or a specially-designed rescue +floppy-disk, such as tomsrtbt. Ignore this advice +at your peril. + +This usually involves changing the line: +id:3:initdefault: +to +id:5:initdefault: + +When you reboot your system, you should end up with the +graphical &kdm; login dialog. + +If this step is unsuccessful the most likely problem is that the +environment used at boot time differs from the environment that you used for +testing at the command line. If you are trying to get two versions of &kde; +to co-exist, be particularly careful that the settings you use for your +PATH and LD_LIBRARY_PATH environment variables +are consistent, and that the startup scripts are not over-riding them in +some way. + + + + + + +Supporting multiple window managers + +&kdm; detects most available window managers and desktop environments when +it is run. Installing a new one should make it automatically available in +the &kdm; main dialog's Session Type submenu. + +If you have a very new window manager, or something that &kdm; does +not support, the first thing you should check is that the executable to be +run is in the PATH and has not been renamed by the distributor +into something unexpected. + +If the case is that the session type is not supported by &kdm; yet +(maybe because it is too new), you can quite easily add it. + +The session types are defined by .desktop files +located in the directories listed in . The +last named directory contains the system-provided default session types +and is $KDEDIR/share/apps/kdm/sessions +in an installation from source. Software upgrades will typically overwrite +anything in here, so it is unwise to use it for configuration purposes. +Instead, a separate configuration directory should be listed first. It is +set to $KDEDIR/share/config/kdm/sessions +in an installation from source, but distributors often change it to something +like /etc/kde4/kdm/sessions. +You can simply add an appropriately named .desktop files here. The fields are: + +[Desktop Entry] +Encoding=UTF-8 This is fixed to and +may be omitted +Type=XSession This is fixed to and +may be omitted +Exec=executable name Passed to +eval exec in a Bourne shell +TryExec=executable name Supported +but not required +Name=name to show in the &kdm; session list + +There are also three magic types: + + + +default + + +The default session for &kdm; is normally &kde; but can be configured by the +system administrator. + + + + +custom + + +The Custom session will run the user's ~/.xsession if it exists, falling +back to the default session otherwise. + + + + +failsafe + + +Failsafe will run a very plain session, and is useful only for debugging +purposes. + + + + + +To override a session type, copy the .desktop file from the data dir +to the config dir and edit it at will. Removing the shipped session types +can be accomplished by shadowing them with .desktop files +containing Hidden=true. For the magic session types no .desktop files exist +by default, but &kdm; pretends they would, so you can override them like any +other type. + + + + +Using &kdm; for Remote Logins (&XDMCP;) + +&XDMCP; is the Open Group standard, the X Display Manager +Control Protocol. This is used to set up connections between +remote systems over the network. + +&XDMCP; is useful in multiuser situations where there are users +with workstations and a more powerful server that can provide the +resources to run multiple X sessions. For example, &XDMCP; is a good +way to reuse old computers - a Pentium or even 486 computer with 16 Mb +RAM is sufficient to run X itself, and using &XDMCP; such a computer can +run a full modern &kde; session from a server. For the server part, +once a single &kde; (or other environment) session is running, running +another one requires very few extra resources. + +However, allowing another method of login to your machine +obviously has security implications. You should run this service only +if you need to allow remote X Servers to start login sessions on your +system. Users with a single &UNIX; computer should not need to run +this. + + + + +Advanced Topics + + +Command Sockets + +This is a feature you can use to remote-control &kdm;. It's mostly +intended for use by &ksmserver; and &kdesktop; from a running session, but +other applications are possible as well. + +The sockets are &UNIX; domain sockets which live in subdirectories of the +directory specified by =. The subdir is the key to +addressing and security; the sockets all have the file name +socket and file permissions +rw-rw-rw- (0666). This is because some systems don't care +for the file permission of the socket files. + +There are two types of sockets: the global one (dmctl) and the +per-display ones (dmctl-<display>). + +The global one's subdir is owned by root, the subdirs of the per-display +ones' are owned by the user currently owning the session (root or the +logged in user). Group ownership of the subdirs can be set via FifoGroup=, +otherwise it's root. The file permissions of the subdirs are rwxr-x--- +(0750). + +The fields of a command are separated by tabs (\t), the +fields of a list are separated by spaces, literal spaces in list fields are +denoted by \s. + +The command is terminated by a newline (\n). + +The same applies to replies. The reply on success is +ok, possibly followed by the requested +information. The reply on error is an errno-style word (⪚ +perm, noent, &etc;) +followed by a longer explanation. + + +Global commands: + + +login +(now | schedule) user password +[session_arguments] + +login user at specified display. if now is +specified, a possibly running session is killed, otherwise the login is done +after the session exits. session_arguments are printf-like escaped contents +for .dmrc. Unlisted keys will default to previously saved values. + + + + +resume + +Force return from console mode, even if TTY logins are still +active. + + + + +manage display +[display_class +[auth_name auth_data]] + +Start managing the named foreign display. +display_class, if specified and non-empty, +will be used for configuration matching; see . + +auth_name and auth_data +need to be passed if the display requires X authorization. The format is +the same as the 2nd and 3rd column of the xauth list +output. + + + + +unmanage display + +Stop managing the named foreign display. + + + + + + +Per-display commands: + +lock + +The display is marked as locked. If the &X-Server; crashes in this +state, no auto-relogin will be performed even if the option is on. + + + +unlock + +Reverse the effect of lock, and re-enable +auto-relogin. + + + +suicide + +The currently running session is forcibly terminated. No auto-relogin +is attempted, but a scheduled "login" command will be executed. + + + + + +Commands for all sockets + + +caps + +Returns a list of this socket's capabilities: + + + +kdm + +identifies &kdm;, in case some other DM implements this protocol, +too + + + +list, lock, +suicide, login, +resume, manage + + +The respective command is supported + + + +bootoptions + +The listbootoptions command and the + to shutdown are supported + + + +shutdown <list> + +shutdown is supported and allowed for the listed +users (a comma separated list.) * means all +authenticated users. + + + +nuke <list> + +Forced shutdown may be performed by the listed users. + + + +nuke + +Forced shutdown may be performed by everybody + + + +reserve <number> + +Reserve displays are configured, and number +are available at this time + + + + + + + + +list [all | +alllocal] + +Return a list of running sessions. By default all active sessions are +listed (this is useful for a shutdown warning). If all +is specified, passive sessions are listed as well. +If alllocal is specified, passive +sessions are listed as well, but all incoming remote sessions are +skipped (this is useful for a fast user switching agent). +Each session entry is a comma separated tuple of: + +Display or TTY name +VT name for local sessions, remote host name prefixed by +@ for remote TTY sessions, otherwise empty +Logged in user's name, empty for passive sessions and +outgoing remote sessions (local chooser mode) +Session type for active local sessions, remote hostname for +outgoing remote sessions, empty for passive sessions. +A Flag field: +* for the display belonging +to the requesting socket. +! for sessions that cannot be killed by the +requesting socket. +t for TTY sessions. + + + +New fields may be added in the future. + + + + +reserve + +Start a reserve login screen. If nobody logs in within some +time, the display is removed again. When the session on the display +exits, the display is removed, too. +Permitted only on sockets of local displays and the global +socket. + + + + +activate +(vt|display) + +Switch to a particular VT (virtual terminal). The VT may be specified +either directly (⪚ vt3) or by a display using it +(eg; :2). +Permitted only on sockets of local displays and the global +socket. + + + + +listbootoptions + +List available boot options. +The return value contains these tokens: + + +A list of boot options (as shown in &kdm; itself). + + +The default boot option. + + +The current boot option. + + +The default and current option are zero-based indices into the list +of boot options. If either one is unset or not determinable, it is -1. + + + + +shutdown (reboot | +halt) +[=bootchoice] +(ask|trynow|forcenow|schedule|start +(-1|end +(force|forcemy|cancel)))) + +Request a system shutdown, either a reboot or a halt/poweroff. +An OS choice for the next boot may be specified from the list returned +by listbootoptions +Shutdowns requested from per-display sockets are executed when the +current session on that display exits. Such a request may pop up a dialog +asking for confirmation and/or authentication +start is the time for which the shutdown is +scheduled. If it starts with a plus-sign, the current time is added. Zero +means immediately. +end is the latest time at which the shutdown +should be performed if active sessions are still running. If it starts with +a plus-sign, the start time is added. -1 means wait infinitely. If end is +through and active sessions are still running, &kdm; can do one of the +following: + +cancel - give up the +shutdown +force - shut down +nonetheless +forcemy - shut down nonetheless if +all active sessions belong to the requesting user. +Only for per-display sockets. + +start and end are +specified in seconds since the &UNIX; epoch. +trynow is a synonym for 0 0 +cancel, forcenow for 0 0 +force and schedule for 0 +-1. +ask attempts an immediate shutdown and +interacts with the user if active sessions are still running. Only for +per-display sockets. + + + + +shutdown cancel +[local|global} + +Cancel a scheduled shutdown. The global socket always cancels the +currently pending shutdown, while per-display sockets default to cancelling +their queued request. + + + + +shutdown status + +Return a list with information about shutdowns. +The entries are a comma-separated tuples of: + + +(global|local) - +pending vs. queued shutdown. A local entry can be returned only by a +per-display socket. + +(halt|reboot) +start +end +("ask"|"force"|"forcemy"|"cancel") +Numeric user ID of the requesting user, -1 for the global +socket. +The next boot OS choice or "-" for none. + +New fields might be added later + + + + + +There are two ways of using the sockets: + + +Connecting them directly. FifoDir is exported as +$DM_CONTROL; the name of per-display sockets can be derived +from $DISPLAY. + + +By using the kdmctl command (⪚ from within a +shell script). Try kdmctl to find out +more. + + + +Here is an example bash script reboot into FreeBSD: + +if kdmctl | grep -q shutdown; then + IFS=$'\t' + set -- `kdmctl listbootoptions` + if [ "$1" = ok ]; then + fbsd=$(echo "$2" | tr ' ' '\n' | sed -ne 's,\\s, ,g;/freebsd/I{p;q}') + if [ -n "$fbsd" ]; then + kdmctl shutdown reboot "=$fbsd" ask > /dev/null + else + echo "FreeBSD boot unavailable." + fi + else + echo "Boot options unavailable." + fi +else + echo "Cannot reboot system." +fi + + + + + +Other sources of information + +Since &kdm; is descended from &xdm;, the xdm man page may provide useful background +information. For X-related problems try the man pages X and startx. If you have +questions about &kdm; that are not answered by this handbook, take advantage of +the fact the &kdm; is provided under the terms of the &GNU; +General Public License: look at the source code. + + + + + +Credits and License + +&kdm; is derived from, and includes code from, +&xdm; © Keith Packard, MIT X Consortium. + +&kdm; 0.1 was written by &Matthias.Ettrich;. Later versions till &kde; +2.0.x were written by &Steffen.Hansen;. Some new features for &kde; 2.1.x and +a major rewrite for &kde; 2.2.x made by &Oswald.Buddenhagen;. + +Other parts of the &kdm; code are copyright by the authors, and +licensed under the terms of the &GNU; +GPL. Anyone is allowed to change &kdm; and redistribute the result +as long as the names of the authors are mentioned. + +&kdm; requires the &Qt; library, which is copyright Troll Tech AS. + +Documentation contributors: + + +Documentation written by &Steffen.Hansen; +&Steffen.Hansen.mail; + +Documentation extended by Gregor +Zumsteinzumstein@ssd.ethz.ch. Last update August 9, +1998 + +Documentation revised for &kde; 2 by &Neal.Crook; +&Neal.Crook.mail;. Last update August 6, +2000 + +Documentation extended and revised for &kde; 2.2 and 4.0 by +&Oswald.Buddenhagen; &Oswald.Buddenhagen.mail;. Last update December 7, +2007 + + + +Documentation copyright &Steffen.Hansen;, Gregor Zumstein, &Neal.Crook; +and &Oswald.Buddenhagen;. +This document also includes large parts of the &xdm; man page, +which is © Keith Packard. +The theme format documentation is heavily based on the GDM manual, +which is © Martin K. Petersen, George Lebl, &RedHat;, Inc. and +Sun Microsystems, Inc. + + + +&underFDL; + + + + +Glossary + + +greeter +The greeter is the login dialog, &ie; the part of &kdm; +which the user sees. + + + + +entropy +The entropy of a system is the measure of its +unpredictability. This is used during the generation of random numbers. + + + + + + + diff --git a/doc/kdm/kdmrc-ref.docbook b/doc/kdm/kdmrc-ref.docbook new file mode 100644 index 00000000..e83f8743 --- /dev/null +++ b/doc/kdm/kdmrc-ref.docbook @@ -0,0 +1,2402 @@ + + + +The Files &kdm; Uses for Configuration + +This chapter documents the files that control &kdm;'s behavior. +Some of this can be also controlled from the &systemsettings; module, but +not all. + + +&kdmrc; - The &kdm; master configuration file + +The basic format of the file is INI-like. +Options are key/value pairs, placed in sections. +Everything in the file is case sensitive. +Syntactic errors and unrecognized key/section identifiers cause &kdm; to +issue non-fatal error messages. + +Lines beginning with # are comments; empty lines +are ignored as well. + +Sections are denoted by +[Name of Section]. + + +You can configure every X-display individually. +Every display has a display name, which consists of a host name +(which is empty for local displays specified in +or ), a colon, and a display number. +Additionally, a display belongs to a +display class (which can be ignored in most cases). + +Sections with display-specific settings have the formal syntax +[X- host [ : number [ _ class ] ] - sub-section ] + +All sections with the same sub-section +make up a section class. + +You can use the wildcard * (match any) for +host, number, +and class. You may omit trailing components; +they are assumed to be * then. The host part may be a +domain specification like .inf.tu-dresden.de +or the wildcard + (match non-empty). + +From which section a setting is actually taken is determined by +these rules: + + + +An exact match takes precedence over a partial match (for the +host part), which in turn takes precedence over a wildcard +(+ taking precendence over *). + + + +Precedence decreases from left to right for equally exact matches. + + + + + +Example: display name myhost.foo:0, class dpy + + + +[X-myhost.foo:0_dpy] precedes + + +[X-myhost.foo:0_*] (same as [X-myhost.foo:0]) precedes + + +[X-myhost.foo:*_dpy] precedes + + +[X-myhost.foo:*_*] (same as [X-myhost.foo]) precedes + + +[X-.foo:*_*] (same as [X-.foo]) precedes + + +[X-+:0_dpy] precedes + + +[X-*:0_dpy] precedes + + +[X-*:0_*] (same as [X-*:0]) precedes + + +[X-*:*_*] (same as [X-*]). + + +These sections do not match this display: +[X-hishost], [X-myhost.foo:0_dec], [X-*:1], [X-:*] + + + + + + + +Common sections are [X-*] (all displays), [X-:*] (all local displays) +and [X-:0] (the first local display). + +The format for all keys is + = value. +Keys are only valid in the section class they are defined for. +Some keys do not apply to particular displays, in which case they are ignored. + + +If a setting is not found in any matching section, the default +is used. + +Special characters need to be backslash-escaped (leading and trailing +spaces (\s), tab (\t), linefeed +(\n), carriage return (\r) and the +backslash itself (\\)). +In lists, fields are separated with commas without whitespace in between. + +Some command strings are subject to simplified sh-style word splitting: +single quotes (') and double quotes (") +have the usual meaning; the backslash quotes everything (not only special +characters). Note that the backslashes need to be doubled because of the +two levels of quoting. + +A pristine &kdmrc; is very thoroughly commented. +All comments will be lost if you change this file with the +&systemsettings; frontend. + + + +The [General] section of &kdmrc; + + +This section contains global options that do not fit into any specific section. + + + + + + + + +This option exists solely for the purpose of clean automatic upgrades. +Do not change it, you may interfere with future +upgrades and this could result in &kdm; failing to run. + + + + + + + + +List of displays (&X-Server;s) permanently managed by &kdm;. Displays with a +hostname are foreign displays which are expected to be already running, +the others are local displays for which &kdm; starts an own &X-Server;; +see . Each display may belong to a display class; +append it to the display name separated by an underscore. +See for the details. + +The default is :0. + + + + + + + +List of on-demand displays. See for syntax. + +Empty by default. + + + + + + + +List of Virtual Terminals to allocate to &X-Server;s. For negative numbers the +absolute value is used, and the VT will be allocated only +if the kernel says it is free. If &kdm; exhausts this list, it will allocate +free VTs greater than the absolute value of the last entry +in this list. +Currently Linux only. + +Empty by default. + + + + + + + +This option is for operating systems (OSs) with support +for virtual terminals (VTs), by both &kdm; and the +OSs itself. +Currently this applies only to Linux. + +When &kdm; switches to console mode, it starts monitoring all +TTY lines listed here (without the leading +/dev/). +If none of them is active for some time, &kdm; switches back to the X login. + +Empty by default. + + + + + + + +The filename specified will be created to contain an ASCII representation +of the process ID of the main &kdm; process; the PID will not be stored +if the filename is empty. + +Empty by default. + + + + + + + +This option controls whether &kdm; uses file locking to keep multiple +display managers from running onto each other. + +The default is true. + + + + + + + +This names a directory under which &kdm; stores &X-Server; authorization +files while initializing the session. &kdm; expects the system to clean up +this directory from stale files on reboot. + +The authorization file to be used for a particular display can be +specified with the option in [X-*-Core]. + +The default is /var/run/xauth. + + + + + + + +This boolean controls whether &kdm; automatically re-reads its +configuration files if it finds them to have changed. + +The default is true. + + + + + + + +Additional environment variables &kdm; should pass on to all programs it runs. +LD_LIBRARY_PATH and XCURSOR_THEME are good candidates; +otherwise, it should not be necessary very often. + +Empty by default. + + + + + + + +If the system has no native entropy source like /dev/urandom (see +) and no entropy daemon like EGD (see + and ) is running, +&kdm; will fall back to its own pseudo-random number generator +that will, among other things, successively checksum parts of this file +(which, obviously, should change frequently). + +This option does not exist on Linux and various BSDs. + +The default is /dev/mem. + + + + + + + +If the system has no native entropy source like /dev/urandom (see +), read random data from a Pseudo-Random +Number Generator Daemon, +like EGD (http://egd.sourceforge.net) via this UNIX domain socket. + +This option does not exist on Linux and various BSDs. + +Empty by default. + + + + + + + +Same as , only use a TCP socket on localhost. + + + + + + + + +The path to a character device which &kdm; should read random data from. +Empty means to use the system's preferred entropy device if there is one. + +This option does not exist on OpenBSD, as it uses the arc4_random +function instead. + +Empty by default. + + + + + + + +The directory in which the command sockets should +be created; make it empty to disable them. + +The default is /var/run/xdmctl. + + + + + + + +The group to which the global command socket should belong; +can be either a name or a numerical ID. + + + + + + + + +The user the greeter should run as. Empty results in root. +Consider the impact on when setting it. + +Empty by default. + + + + + + + +The directory in which &kdm; should store persistent working data; such data +is, for example, the previous user that logged in on a particular display. + +The default is /var/lib/kdm. + + + + + + + +The directory in which &kdm; should store users' .dmrc files. This is only +needed if the home directories are not readable before actually logging in +(like with AFS). + +Empty by default. + + + + + + + + +The [Xdmcp] section of &kdmrc; + + +This section contains options that control &kdm;'s handling of +&XDMCP; requests. + + + + + + + + +Whether &kdm; should listen to incoming &XDMCP; requests. + +The default is true. + + + + + + + +This indicates the UDP port number which &kdm; uses to listen for incoming +&XDMCP; requests. Unless you need to debug the system, leave this with its +default value. + +The default is 177. + + + + + + + +XDM-AUTHENTICATION-1 style &XDMCP; authentication requires a private +key to be shared between &kdm; and the terminal. This option specifies +the file containing those values. Each entry in the file consists of a +display name and the shared key. + +Empty by default. + + + + + + + +To prevent unauthorized &XDMCP; service and to allow forwarding of &XDMCP; +IndirectQuery requests, this file contains a database of hostnames which +are either allowed direct access to this machine, or have a list of hosts +to which queries should be forwarded to. The format of this file is +described in . + +The default is ${kde_confdir}/kdm/Xaccess. + + + + + + + +Number of seconds to wait for the display to respond after the user has +selected a host from the chooser. If the display sends an &XDMCP; +IndirectQuery within this time, the request is forwarded to the chosen +host; otherwise, it is assumed to be from a new session and the chooser +is offered again. + +The default is 15. + + + + + + + +When computing the display name for &XDMCP; clients, the name resolver will +typically create a fully qualified host name for the terminal. As this is +sometimes confusing, &kdm; will remove the domain name portion of the host +name if it is the same as the domain name of the local host when this option +is enabled. + +The default is true. + + + + + + + +Use the numeric IP address of the incoming connection on multihomed hosts +instead of the host name. This is to avoid trying to connect on the wrong +interface which might be down at this time. + +The default is false. + + + + + + + +This specifies a program which is run (as +root) when an &XDMCP; +DirectQuery or BroadcastQuery is received and this host is configured +to offer &XDMCP; display management. The output of this program may be +displayed in a chooser window. If no program is specified, the string +Willing to manage is sent. + +Empty by default. + + + + + + + + +The [Shutdown] section of &kdmrc; + + +This section contains global options concerning system shutdown. + + + + + + + + +The command (subject to word splitting) to run to halt/poweroff the system. + +The default is something reasonable for the system on which &kdm; was built, like +/sbin/shutdown  now. + + + + + + + + +The command (subject to word splitting) to run to reboot the system. + +The default is something reasonable for the system &kdm; on which was built, like +/sbin/shutdown  now. + + + + + + + + +Whether it is allowed to shut down the system via the global command socket. + +The default is false. + + + + + + + +Whether it is allowed to abort active sessions when shutting down the +system via the global command socket. + +This will have no effect unless is enabled. + +The default is true. + + + + + + + +The boot manager &kdm; should use for offering boot options in the +shutdown dialog. + + + +None +no boot manager + + +Grub +Grub boot manager + + +Grub2 +Grub2 boot manager + + +Lilo +Lilo boot manager (Linux on i386 & x86-64 only) + + +The default is None. + + + + + + + + +The [X-*-Core] section class of &kdmrc; + + +This section class contains options concerning the configuration +of the &kdm; backend (core). + + + + + + + + +See . + +The default is 15. + + + + + + + +See . + +The default is 120. + + + + + + + +These options control the behavior of &kdm; when attempting to open a +connection to an &X-Server;. is the length +of the pause (in seconds) between successive attempts, + is the number of attempts to make and + is the amount of time to spend on a +connection attempt. After attempts have been +made, or if seconds elapse in any particular +connection attempt, the start attempt is considered failed. + +The default is 5. + + + + + + + +How many times &kdm; should attempt to start a foreign +display listed in before giving up +and disabling it. +Local displays are attempted only once, and &XDMCP; displays are retried +indefinitely by the client (unless the option +was given to the &X-Server;). + +The default is 4. + + + + + + + +How many times &kdm; should attempt to start up a local &X-Server;. +Starting up includes executing it and waiting for it to come up. + +The default is 1. + + + + + + + +How many seconds &kdm; should wait for a local &X-Server; to come up. + +The default is 30. + + + + + + + +The command line to start the &X-Server;, without display number and VT spec. +Note that with some &X-Server;s (in particular, OpenSolaris') it is necessary +to put most additional arguments into and + even if they are the same for both. +This string is subject to word splitting. + +The default is something reasonable for the system on which &kdm; was built, +like /usr/X11R6/bin/X. + + + + + + + + +Additional arguments for the &X-Server;s for local sessions. +This string is subject to word splitting. + +Empty by default. + + + + + + + +Additional arguments for the &X-Server;s for remote sessions. +This string is subject to word splitting. + +Empty by default. + + + + + + + +The VT the &X-Server; should run on. + should be used instead of this option. +Leave it zero to let &kdm; assign a VT automatically. +Set it to -1 to avoid assigning a VT +alltogether - this is required for setups with multiple physical consoles. +Currently Linux only. + + + + + + + + +This option is for OSs without support for +VTs, either by &kdm; or the OS itself. +Currently this applies to all OSs but Linux. + +When &kdm; switches to console mode, it starts monitoring this +TTY line (specified without the leading +/dev/) for activity. If the line is not used for some time, +&kdm; switches back to the X login. + +Empty by default. + + + + + + + +The user the &X-Server; should run as. Empty results in root. + +Empty by default. + + + + + + + +See . + +The default is 5. + + + + + + + +To discover when remote displays disappear, &kdm; +regularly pings them. + specifies the time (in minutes) between the +pings and specifies the maximum amount of +time (in minutes) to wait for the terminal to respond to the request. If +the terminal does not respond, the session is declared dead and terminated. + +If you frequently use X terminals which can become isolated from +the managing host, you may wish to increase the timeout. The only worry +is that sessions will continue to exist after the terminal has been +accidentally disabled. + +The default is 5. + + + + + + + +Whether &kdm; should restart the local &X-Server; after session exit instead +of resetting it. Use this if the &X-Server; leaks memory or crashes the system +on reset attempts. + +The default is false. + + + + + + + +Controls whether &kdm; generates and uses authorization for +local &X-Server; connections. +For &XDMCP; displays the authorization requested by the display is used; +foreign non-&XDMCP; displays do not support authorization at all. + +The default is true. + + + + + + + +If is true, use the authorization mechanisms +listed herein. The MIT-MAGIC-COOKIE-1 authorization is always available; +XDM-AUTHORIZATION-1, SUN-DES-1 and MIT-KERBEROS-5 might be available as well, +depending on the build configuration. + +The default is DEF_AUTH_NAME. + + + + + + + +Some old &X-Server;s re-read the authorization file +at &X-Server; reset time, instead of when checking the initial connection. +As &kdm; generates the authorization information just before connecting to +the display, an old &X-Server; would not get up-to-date authorization +information. This option causes &kdm; to send SIGHUP to the &X-Server; +after setting up the file, causing an additional &X-Server; reset to occur, +during which time the new authorization information will be read. + +The default is false. + + + + + + + +This file is used to communicate the authorization data from &kdm; to +the &X-Server;, using the &X-Server; command line +option. It should be kept in a directory which is not world-writable +as it could easily be removed, disabling the authorization mechanism in +the &X-Server;. If not specified, a random name is generated from + and the name of the display. + +Empty by default. + + + + + + + +This option specifies the name of the file to be loaded by +xrdb as the resource database onto the root window +of screen 0 of the display. KDE programs generally do not use +X-resources, so this option is only needed if the +program needs some X-resources. + +Empty by default. + + + + + + + +The xrdb program to use to read the X-resources file +specified in . +The command is subject to word splitting. + +The default is ${x_bindir}/xrdb. + + + + + + + +This string is subject to word splitting. +It specifies a program which is run (as +root) before offering the +greeter window. This may be used to change the appearance of the screen +around the greeter window or to put up other windows (e.g., you may want +to run xconsole here). +Usually, a script named Xsetup is used here. +See . + +Empty by default. + + + + + + + +This string is subject to word splitting. +It specifies a program which is run (as +root) after the user +authentication process succeeds. +Usually, a script named Xstartup is used here. +See . + +Empty by default. + + + + + + + +This string is subject to word splitting. +It specifies a program which is run (as +root) after the session +terminates. +Usually, a script named Xreset is used here. +See . + +Empty by default. + + + + + + + +This string is subject to word splitting. +It specifies the session program to be executed (as the user owning +the session). +Usually, a script named Xsession is used here. +See . + +The default is ${x_bindir}/xterm -ls -T. + + + + + + + +If the program fails to execute, &kdm; will +fall back to this program. This program is executed with no arguments, +but executes using the same environment variables as the session would +have had (see ). + +The default is ${x_bindir}/xterm. + + + + + + + +The PATH environment variable for +non-root s. + +The default depends on the system &kdm; was built on. + + + + + + + + +The PATH environment variable for all programs but +non-root +s. Note that it is good practice not to include +. (the current directory) into this entry. + +The default depends on the system &kdm; was built on. + + + + + + + + +The SHELL environment variable for all programs but the +. + +The default is /bin/sh. + + + + + + + +When &kdm; is unable to write to the usual user authorization file +($HOME/.Xauthority), it creates a unique file name in this +directory and points the environment variable XAUTHORITY +at the created file. + +The default is /tmp. + + + + + + + +If true, will be used unconditionally. + +The default is false. + + + + + + + +If enabled, &kdm; will automatically restart a session after an &X-Server; +crash (or if it is killed by Alt-Ctrl-BackSpace). Note that enabling this +feature opens a security hole: a secured display lock can be circumvented +(unless &kde;'s built-in screen locker is used). + +The default is false. + + + + + + + +If disabled, do not allow root +(and any other user with UID = 0) to log in directly. + +The default is true. + + + + + + + +If disabled, only users that have passwords assigned can log in. + +The default is true. + + + + + + + +Who is allowed to shut down the system. This applies both to the +greeter and to the command sockets. + + + +None +no Shutdown... menu entry is shown at all + + +Root +the root password must be entered to shut down + + +All +everybody can shut down the machine + + +The default is All. + + + + + + + +Who is allowed to abort active sessions when shutting down. + + + +None +no forced shutdown is allowed at all + + +Root +the root password must be entered to shut down forcibly + + +All +everybody can shut down the machine forcibly + + +The default is All. + + + + + + + +The default choice for the shutdown condition/timing. + + + +Schedule +shut down after all active sessions exit (possibly at once) + + +TryNow +shut down, if no active sessions are open; otherwise, do nothing + + +ForceNow +shut down unconditionally + + +The default is Schedule. + + + + + + + +How to offer shutdown scheduling options: + + + +Never +not at all + + +Optional +as a button in the simple shutdown dialogs + + +Always +instead of the simple shutdown dialogs + + +The default is Never. + + + + + + + +Enable password-less logins on this display. Use with extreme care! + +The default is false. + + + + + + + +The users that do not need to provide a password to log in. +Items which are prefixed with @ represent all users in the +user group named by that item. +* means all users but +root +(and any other user with UID = 0). +Never list root. + +Empty by default. + + + + + + + +Enable automatic login. Use with extreme care! + +The default is false. + + + + + + + +If true, auto-login after logout. If false, auto-login is performed only +when a display session starts up. + +The default is false. + + + + + + + +The delay in seconds before automatic login kicks in. This is also known as +Timed Login. + + + + + + + + +The user to log in automatically. Never specify root! + +Empty by default. + + + + + + + +The password for the user to log in automatically. This is not required +unless the user is logged into a NIS or Kerberos domain. If you use this +option, you should chmod  kdmrc for obvious reasons. + +Empty by default. + + + + + + + +Immediately lock the automatically started session. This works only with +KDE sessions. + +The default is false. + + + + + + + +A list of directories containing session type definitions. +Ordered by falling priority. + +The default is ${kde_datadir}/kdm/sessions. + + + + + + + +The file (relative to the user's home directory) to redirect the session +output to. + +The following character pairs are replaced by their value: + + +%d +name of the current display + + +%u +login name of the current user + + +%r +empty at first. See below. + + +%% +a single % + + +When the constructed filename cannot be used safely and the specification +contains +%stuffr, +other names will be tried - this time expanding +%stuffr +to stuff followed by a random number. + +The default is .xsession-errors. + + + + + + + +Fallback when cannot be used. The same expansions are +supported. Do not use relative paths here. + +The default is /tmp/xerr-%u-%d%-r. + + + + + + + +Specify whether &kdm;'s built-in utmp/wtmp/lastlog registration should +be used. If it is not, the tool sessreg should be used +in the and scripts, or, +alternatively, the pam_lastlog module should be used on +PAM-enabled systems. + +The default is true. + + + + + + + + +The [X-*-Greeter] section class of &kdmrc; + + +This section class contains options concerning the configuration +of the &kdm; frontend (greeter). + + + + + + + + +Specify the widget style for the greeter. Empty means to use the +built-in default which currently is Oxygen-air. + +Empty by default. + + + + + + + +Specify the widget color scheme for the greeter. Empty means to use the +built-in default which currently is Oxygen-air. + +Empty by default. + + + + + + + +What should be shown in the greeter righthand of the input lines (if + is disabled) or above them (if + is enabled): + + + +None +nothing + + +Logo +the image specified by + + +Clock +a neat analog clock + + +The default is Clock. + + + + + + + +The image to show in the greeter if is +Logo. + +Empty by default. + + + + + + + +The relative coordinates (percentages of the screen size; X,Y) at which +the center of the greeter is put. &kdm; aligns the greeter to the edges +of the screen it would cross otherwise. + +The default is 50,50. + + + + + + + +The screen the greeter should be displayed on in multi-headed and Xinerama +setups. The numbering starts with 0. For Xinerama, it corresponds to the +listing order in the active ServerLayout section of XF86Config; -1 means +to use the upper-left screen, -2 means to use the upper-right screen. + + + + + + + + +The headline in the greeter. An empty greeting means none at all. + +The following character pairs are replaced by their value: + + +%d +name of the current display + + +%h +local host name, possibly with the + domain name + + +%n +local node name, most probably the host name without the + domain name + + +%s +operating system + + +%r +operating system version + + +%m +machine (hardware) type + + +%% +a single % + + + +The default is Welcome to %s at %n. + + + + + + + +Whether the fonts used in the greeter should be antialiased. + +The default is false. + + + + + + + +The font for the greeter headline. The value is encoded. + +The default is Serif 20pt bold. + + + + + + + +The normal font used in the greeter. The value is encoded. + +The default is Sans Serif 10pt. + + + + + + + +The font used for the Login Failed message. The value is encoded. + +The default is Sans Serif 10pt bold. + + + + + + + +What to do with the Num Lock modifier for the time the greeter is running: + + + +Off +turn off + + +On +turn on + + +Keep +do not change the state + + +The default is Keep. + + + + + + + +Language and locale to use in the greeter, encoded like $LANGUAGE. +If empty, the settings from the environment are used. + +Empty by default. + + + + + + + +Enable autocompletion in the username line edit. + +The default is false. + + + + + + + +Show a user list with unix login names, real names, and images in the greeter. + +The default is true. + + + + + + + +This option controls which users will be shown in the user view +() and/or offered for autocompletion +(). +If it is Selected, contains +the final list of users. +If it is NotHidden, the initial user list contains all +users found on the system. Users contained in are +removed from the list, just like all users with a UID greater than specified +in and users with a non-zero UID less than +specified in . +Items in and +which are prefixed with @ represent all users in the +user group named by that item. +Finally, the user list will be sorted alphabetically, if + is enabled. + +The default is NotHidden. + + + + + + + +See . + +Empty by default. + + + + + + + +See . + +Empty by default. + + + + + + + +See . + + + + + + + + +See . + +The default is 65535. + + + + + + + +See . + +The default is true. + + + + + + + +If is enabled, this specifies where &kdm; gets the +images from: + + + +AdminOnly +from <>/$USER.face[.icon] + + +PreferAdmin +prefer <>, fallback on $HOME + + +PreferUser +... and the other way round + + +UserOnly +from the user's $HOME/.face[.icon] + + + + +The images can be in any format Qt recognizes, but the filename +must match &kdm;'s expectations: .face.icon should be a +48x48 icon, while .face should be a 300x300 image. +Currently the big image is used only as a fallback and is scaled down, +but in the future it might be displayed full-size in the logo area or a +tooltip. +To be accessible to &kdm;, the images must be world readable and their +parent directories must be world executable. + +The default is AdminOnly. + + + + + + + +See . + +The default is ${kde_datadir}/kdm/faces. + + + + + + + +Specify, if/which user should be preselected for log in: + + + +None +do not preselect any user + + +Previous +the user which successfully logged in last time + + +Default +the user specified in the option + + + + +If is enabled and a user was preselected, +the cursor is placed in the password input field automatically. + +Enabling user preselection can be considered a security hole, +as it presents a valid login name to a potential attacker, so he +only needs to guess the password. On the other hand, +one could set to a fake login name. + + +The default is None. + + + + + + + +See . + +Empty by default. + + + + + + + +See . + +The default is false. + + + + + + + +If this is true, the entered password is echoed as bullets. Otherwise, +no feedback is given at all. + +The default is true. + + + + + + + +If enabled, &kdm; will automatically start the krootimage +program to set up the background; otherwise, the +program is responsible for the background. + +The default is true. + + + + + + + +The configuration file to be used by krootimage. +It contains a section named [Desktop0] like +kdesktoprc does. Its options are not described +herein; guess their meanings or use the control center. + +The default is ${kde_confdir}/kdm/backgroundrc. + + + + + + + +To improve security, the greeter may grab mouse and keyboard input so +no other X clients can eavesdrop it. However, the X authorization +mechanism will usually prevent malicious X clients from connecting +in the first place. Consequently, enabling grabs for local displays +is pointless and only marginally improves security for remote displays. + +The mouse grab will make on-screen keyboards unusable. + + + + + +Never +never grab + + +IfNoAuth +grab if the display requires no X authorization + + +Always +always grab + + +The default is IfNoAuth. + + + + + + + +To improve security, the greeter grabs the &X-Server; and then the input +when it starts up. This option specifies if the &X-Server; grab should be held +for the duration of the name/password reading. When disabled, the &X-Server; +is ungrabbed after the input grabs succeed; otherwise, the &X-Server; is +grabbed until just before the session begins. + +Enabling this option disables and +. + + +The default is false. + + + + + + + +This option specifies the maximum time &kdm; will wait for the grabs to +succeed. A grab may fail if some other X-client has the &X-Server; or the +keyboard grabbed, or possibly if the network latencies are very high. You +should be cautious when raising the timeout, as a user can be spoofed by +a look-alike window on the display. If a grab fails, &kdm; kills and +restarts the &X-Server; (if possible) and the session. + +The default is 3. + + + + + + + +Warn, if a display has no X-authorization. This will be the case if + + + the authorization file for a local &X-Server; could not be created, + + + a remote display from &XDMCP; did not request any authorization or + + + the display is a foreign display specified in + . + + + +The default is true. + + + + + + + +Specify whether the greeter of local displays should start up in host chooser +(remote) or login (local) mode and whether it is allowed to switch to the +other mode. + + + +LocalOnly +only local login possible + + +DefaultLocal +start up in local mode, but allow switching to remote mode + + +DefaultRemote +... and the other way round + + +RemoteOnly +only choice of remote host possible + + +The default is LocalOnly. + + + + + + + +A list of hosts to be automatically added to the remote login menu. +The special name * means broadcast. +Has no effect if is LocalOnly. + +The default is *. + + + + + + + +Use this number as a random seed when forging saved session types, etc. of +unknown users. This is used to avoid telling an attacker about existing users +by reverse conclusion. This value should be random but constant across the +login domain. + + + + + + + + +Enable &kdm;'s built-in xconsole. +Note that this can be enabled for only one display at a time. +This option is available only if &kdm; was configured +with . + +The default is false. + + + + + + + +The data source for &kdm;'s built-in xconsole. +If empty, a console log redirection is requested from +/dev/console. +Has no effect if is disabled. + +Empty by default. + + + + + + + +Specify conversation plugins for the login dialog; the first in the list +is selected initially. +Each plugin can be specified as a base name (which expands to +$kde_modulesdir/kgreet_base) +or as a full pathname. + +Conversation plugins are modules for the greeter which obtain authentication +data from the user. Currently only the classic plugin is +shipped with &kde;; it presents the well-known username and password form. + +The default is classic. + + + + + + + +Same as , but for the shutdown dialog. + +The default is classic. + + + + + + + +A list of options of the form +Key=Value. +The conversation plugins can query these settings; it is up to them what +possible keys are. + +Empty by default. + + + + + + + +Show the Console Login action in the greeter (if / +is configured). + +The default is true. + + + + + + + +Show the Restart X Server/Close Connection action in the greeter. + +The default is true. + + + + + + + +A program to run while the greeter is visible. It is supposed to preload +as much as possible of the session that is going to be started (most +probably). + +Empty by default. + + + + + + + +Whether the greeter should be themed. +Note that the themed greeter is challenged accessibility-wise, and themes +may lack support for features like a user list or alternative +authentication methods. + +The default is false. + + + + + + + +The theme to use for the greeter. Can point to either a directory or an XML +file. + +Empty by default. + + + + + + + +Enable the Alt-Ctrl-D shortcut to toggle greeter theme debugging. + +The default is false. + + + + + + + + + + + +Specifying permanent &X-Server;s + +Each entry in the list indicates a +display which should constantly be +managed and which is not using &XDMCP;. This method is typically used only for +local &X-Server;s that are started by &kdm;, but &kdm; can manage externally +started (foreign) &X-Server;s as well, may they run on the +local machine or rather remotely. + +The formal syntax of a specification is + +display name [_display class] + +for all &X-Server;s. Foreign displays differ in having +a host name in the display name, may it be localhost. + +The display name must be something that can +be passed in the option to an X program. This string +is used to generate the display-specific section names, so be careful to match +the names. +The display name of &XDMCP; displays is derived from the display's address by +reverse host name resolution. For configuration purposes, the +localhost prefix from locally running &XDMCP; displays is +not stripped to make them distinguishable from local +&X-Server;s started by &kdm;. + +The display class portion is also used in the +display-specific sections. This is useful if you have a large collection of +similar displays (such as a corral of X terminals) and would like to set +options for groups of them. +When using &XDMCP;, the display is required to specify the display class, +so the manual for your particular X terminal should document the display +class string for your device. If it does not, you can run &kdm; in debug +mode and grep the log for class. + +The displays specified in will not be +started when &kdm; starts up, but when it is explicitly requested via +the command socket. +If reserve displays are specified, the &kde; menu will have a +Start New Session item near the bottom; use that to +activate a reserve display with a new login session. The monitor will switch +to the new display, and you will have a minute to login. If there are no more +reserve displays available, the menu item will be disabled. + +When &kdm; starts a session, it sets up authorization data for the +&X-Server;. For local servers, &kdm; passes + filename +on the &X-Server;'s command line to point it at its authorization data. +For &XDMCP; displays, &kdm; passes the authorization data to the &X-Server; +via the Accept &XDMCP; message. + + + + +&XDMCP; access control + +The file specified by the option provides +information which &kdm; uses to control access from displays requesting service +via &XDMCP;. +The file contains four types of entries: entries which control the response +to Direct and Broadcast queries, entries which +control the response to Indirect queries, macro definitions, +and entries which control on which network interfaces &kdm; listens for &XDMCP; +queries. +Blank lines are ignored, # is treated as a comment +delimiter causing the rest of that line to be ignored, and \ +causes an immediately following newline to be ignored, allowing host lists +to span multiple lines. + + +The format of the Direct entries is simple, either a +host name or a pattern, which is compared against the host name of the display +device. Alternatively, a macro may be used to make the entry match everything +the macro expands to. +Patterns are distinguished from host names by the inclusion of one or more +meta characters; * matches any sequence of 0 or more +characters, and ? matches any single character. +If the entry is a host name, all comparisons are done using network addresses, +so any name which converts to the correct network address may be used. Note +that only the first network address returned for a host name is used. +For patterns, only canonical host names are used in the comparison, so ensure +that you do not attempt to match aliases. +Host names from &XDMCP; queries always contain the local domain name +even if the reverse lookup returns a short name, so you can use +patterns for the local domain. +Preceding the entry with a ! character causes hosts which +match that entry to be excluded. Preceding it with an = has +no effect but is required when specifying a macro to distinguish the entry +from a macro definition. +To only respond to Direct queries for a host or pattern, +it can be followed by the optional NOBROADCAST keyword. +This can be used to prevent a &kdm; server from appearing on menus based on +Broadcast queries. + +An Indirect entry also contains a host name, pattern or +macro, but follows it with a list of host names or macros to which the queries +should be forwarded. Indirect entries can be excluding as well, +in which case a (valid) dummy host name must be supplied to make the entry +distinguishable from a Direct entry. +If compiled with IPv6 support, multicast address groups may also be included +in the list of addresses the queries are forwarded to. + +If the indirect host list contains the keyword CHOOSER, +Indirect queries are not forwarded, but instead a host chooser +dialog is displayed by &kdm;. The chooser will send a Direct +query to each of the remaining host names in the list and offer a menu of +all the hosts that respond. The host list may contain the keyword +BROADCAST, to make the chooser send a +Broadcast query as well; note that on some operating systems, +UDP packets cannot be broadcast, so this feature will not work. + + +When checking access for a particular display host, each entry is scanned +in turn and the first matching entry determines the response. +Direct and Broadcast entries are ignored when +scanning for an Indirect entry and vice-versa. + +A macro definition contains a macro name and a list of host names and +other macros that the macro expands to. To distinguish macros from hostnames, +macro names start with a % character. + +The last entry type is the LISTEN directive. +The formal syntax is + + LISTEN [interface [multicast list]] + +If one or more LISTEN lines are specified, &kdm; listens +for &XDMCP; requests only on the specified interfaces. +interface may be a hostname or IP address +representing a network interface on this machine, or the wildcard +* to represent all available network interfaces. +If multicast group addresses are listed on a LISTEN line, +&kdm; joins the multicast groups on the given interface. For IPv6 multicasts, +the IANA has assigned ff0X:0:0:0:0:0:0:12b as the +permanently assigned range of multicast addresses for &XDMCP;. The +X in the prefix may be replaced by any valid scope +identifier, such as 1 for Node-Local, 2 for Link-Local, 5 for Site-Local, and +so on (see IETF RFC 2373 or its replacement for further details and scope +definitions). &kdm; defaults to listening on the Link-Local scope address +ff02:0:0:0:0:0:0:12b to most closely match the IPv4 subnet broadcast behavior. +If no LISTEN lines are given, &kdm; listens on all +interfaces and joins the default &XDMCP; IPv6 multicast group (when +compiled with IPv6 support). +To disable listening for &XDMCP; requests altogether, a +LISTEN line with no addresses may be specified, but using +the [Xdmcp] option is preferred. + + + + + +Supplementary programs + + +The following programs are run by &kdm; at various stages of a session. +They typically are shell scripts. + + + +The Setup, Startup and Reset programs are run as +root, so they should be careful +about security. +Their first argument is auto if the session results +from an automatic login; otherwise, no arguments are passed to them. + + + +Setup program + + +The Xsetup program is run after the &X-Server; is +started or reset, but before the greeter is offered. +This is the place to change the root background (if + is disabled) or bring up other windows that +should appear on the screen along with the greeter. Resources for this +program can be put into the file named by . + + + +In addition to any specified by , +the following environment variables are passed: + + + DISPLAY + the associated display name + + + PATH + the value of + + + SHELL + the value of + + + XAUTHORITY + may be set to an authority file + + + DM_CONTROL + the value of + + + + can make &kdm; grab the +keyboard and mouse, making any other windows unable to receive input. +If is set, Xsetup +will not be able to connect to the display at all. + + + + +Startup program + +The Xstartup program is run as +root when the user logs in. +This is the place to put commands which add entries to +utmp (the sessreg program +may be useful here), mount users' home directories from file servers, +or abort the session if some requirements are not met (but note that on +modern systems, many of these tasks are already taken care of by +PAM modules). + +In addition to any specified by , +the following environment variables are passed: + + + DISPLAY + the associated display name + + + HOME + the initial working directory of the user + + + LOGNAME + the username + + + USER + the username + + + PATH + the value of + + + SHELL + the value of + + + XAUTHORITY + may be set to an authority file + + + DM_CONTROL + the value of + + + +&kdm; waits until this program exits before starting the user session. +If the exit value of this program is non-zero, &kdm; discontinues the session +and starts another authentication cycle. + + + + +Session program + +The Xsession program is the command which is run +as the user's session. It is run with the permissions of the authorized user. +One of the keywords failsafe, default +or custom, or a string to eval by a +Bourne-compatible shell is passed as the first argument. + +In addition to any specified by , +the following environment variables are passed: + + + DISPLAY + the associated display name + + + HOME + the initial working directory of the user + + + LOGNAME + the username + + + USER + the username + + + PATH + the value of + (or for + root user sessions) + + + + SHELL + the user's default shell + + + XAUTHORITY + may be set to a non-standard authority file + + + KRBTKFILE + may be set to a Kerberos4 credentials cache name + + + + KRB5CCNAME + may be set to a Kerberos5 credentials cache name + + + + DM_CONTROL + the value of + + + XDM_MANAGED + will contain a comma-separated list of parameters the + session might find interesting, like which conversation + plugin was used for the login + + + + DESKTOP_SESSION + the name of the session the user has chosen to run + + + + + + + +Reset program + +Symmetrical with Xstartup, the +Xreset program is run after the user session has +terminated. Run as root, it should +contain commands that undo the effects of commands in +Xstartup, removing entries from utmp +or unmounting directories from file servers. + +The environment variables that were passed to +Xstartup are also passed to Xreset. + + + + + + + diff --git a/doc/kdm/theme-ref.docbook b/doc/kdm/theme-ref.docbook new file mode 100644 index 00000000..931483c0 --- /dev/null +++ b/doc/kdm/theme-ref.docbook @@ -0,0 +1,1348 @@ + + Creating themes for the &kdm; greeter + + + This section describes the creation of themes for the themed + greeter. For examples including screenshots, see the installed + standard themes and the themes from + + the theme website. + + + + Theme Overview + + + &kdm; themes can be created by creating an XML file that follows the + specification in + $KDEDIR/share/apps/doc/kdm/greeter.dtd. + Theme files are stored in the directory + $KDEDIR/share/apps/kdm/themes/theme_name. + The theme directory should contain a file called + KdmGreeterTheme.desktop which has similar format + to other .desktop files and looks + like: + + +[KdmGreeterTheme] +Greeter=circles.xml +Name=Circles +Description=Theme with blue circles +Author=Bond, James Bond +Copyright=(c) 2002 Bond, James Bond +Screenshot=screenshot.png + + + + + The Name, Description, + Author and Copyright fields can + be translated just like in other + .desktop files. All the files + that are mentioned should be in the theme directory itself. The + Screenshot field points to a file which should be a + 200x150 screenshot of the theme in action (it is OK not to have one, + but it makes it nicer for the user). The Greeter + entry points to an XML file that contains the description of the theme. + + + + + + Once a theme has been fully tested, make a tarball that contains + the directory as it would be installed to the + $KDEDIR/share/apps/kdm/themes + directory. This is the standard format for distributing &kdm; themes. + + + + + Detailed Description of Theme XML format + + + Toplevel Node + + + &kdm; themes are XML files with the <greeter> tag at their root. + The toplevel node is an item node + of type rect with an implicit + fixed layout. + + + + + +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE greeter SYSTEM "greeter.dtd"> +<greeter> +[...] +</greeter> + + + + Contained within the greeter tag can be the nodes described + in the next sections of this document. Some of these nodes are + containers (layout nodes, item nodes) which can contain other + nodes again. + + + + + Item Nodes + + + A &kdm; theme is created by specifying a hierarchy of item and layout + nodes. Item nodes can have the following value for the + type attribute: + + + + + + button + + + A button field. This field uses a Qt button. + + + It is also possible to make any other item act like a button + by setting its button attribute to + true. However, it is better to use + Qt buttons in &kdm; themes since these are accessible to + users with disabilities. + + + + + + entry + + An input widget like a line edit or combo box. + Note that this is merely a placeholder for Qt widgets. + + + + + label + + + A text label. Must contain either a + text node + or a + stock node + to specify the text. + + + + + + list + + A face browser widget. + + + + + pixmap + + A raster image in a format that Qt supports, ⪚ + PNG, JPEG, Tiff, etc. + + + + + rect + + A plain rectangle. + + + + + svg + + A vector image in SVG format. + + + + + + For example: + +<item type="label"> + + + An item that acts as a button: + + <item type="rect" id="disconnect_button" button="true">. + + + + + By default, the &kdm; login screen will disappear after authentication. + This can result in flicker between the login screen and the session. + The background attribute allows users to specify + what elements of the theme are the background image. When used, this + will cause &kdm; to remove all non-background items from the display + and render the remaining background items to the root + window. This can be used to create a smooth transition between the + login screen and the session: + + +<item type="rect" background="true"> + <normal file="background.svg"/> + <pos x="0" y="0" width="100%" height="-75"/> +</item> + + + To use a different background for login transition than the one + used for login, the theme should specify two item nodes (which + could contain pixmaps or svg images, for example). The item + which corresponds to the greeter background should not have the + background property while the item which corresponds + to the transition background should have the + background property. For instance : + + +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE greeter SYSTEM "greeter.dtd"> +<greeter> + <item type="rect" background="true"> + <normal file="background_for_login.svg" element="background"/> + <pos x="0" y="0" width="100%" height="100%"/> + </item> + <item type="rect"> + <normal file="background_for_greeter.svg"/> + <pos x="0" y="0" width="100%" height="100%"/> + </item> + [...] +</greeter> + + + + + + In multi-screen setups, themes may also specify the look of other + screens than the one the greeter is on - but typically only background + items will appear there. To specify which screen(s) an item should + appear on, the screen attribute can be used with the + value being one of greeter, other + or all, meaning the screen the greeter is on, all + screens the greeter is not on and all screens, resp. + + + + + Each item can be given a name via the id + attribute. Certain ids are recognized by &kdm; to give those + items a special function: + + + + + + button items and items with the + button="true" attribute. + + + + Buttons typically trigger certain actions. + Addionally, &kdm; will hide buttons whose actions are + not available for some reason. + + + + + IdAction + + + chooser_button + Runs the XDMCP chooser. + + + + + + disconnect_button + Disconnect from remote session. + + + + + + + + session_button + Open the session type selection menu. + + + + system_button + Open a catch-all menu with various options and actions, + depending on the configuration. + + + + + + + label items + + + + &kdm; will show/hide these labels and set their text depending + on the state of the login dialog. + + + + + IdFunction + + + + + pam-error + This displays the Login failed. + message. + + + + + + + + Widget embedding items + + + + &kdm; will embed particular Qt widgets into these items. + + + + + IdFunction + + + user-entry + Entry field for username entry. + + + + pw-entry + Entry field for password entry. + + + + domain-entry + Some conversation plugins use this field + to query a domain name. If this field is present, the related + enclosing items should have + show nodes with the type + plugin-domain-entry. + + + + talker + This item should be of type rect. + It represents the hot area of the + greeter: it contains the label and + entry items which concern the + authentication process. If a given + conversation plugin cannot match the + existing items with its needs, it tries to embed a complex + widget with an own layout into this item, thus completely + overriding the theme's talker. + Strictily speaking, &kdm; themes do not need to provide + own talker designs at all, as all &kdm; + authentication plugins are able make use of the + talker item. + + + + + userlist + This item must be of type list. + If the user list feature is enabled, &kdm; will embed + the user list widget here. Otherwise, this item is + hidden. + + + + xconsole + This item should be of type rect. + If the built-in xconsole feature is + compiled in and enabled, &kdm; will embed + the console log widget here. Otherwise, this item is + hidden. + + + + + + + + Other items + + + + &kdm; will show/hide these items depending on the configuration + and the current state of the greeter. &kdm; does not impose + type requirements on them, but they usually lend themselves + to a particular type. + + + + + IdShown only when ... + + + timed-label + ... timed login is in progress. + + + + caps-lock-warning + ... Caps Lock is active. + + + + xauth-warning + ... the &X-Server; requires no X authorization to + connect. + + + + + + userlist-rect + ... the user list is enabled. By nesting the + userlist item into this one, it is possible + to create something like a frame around the list and have + it shown only when the user list itself if shown. + + + + xconsole-rect + ... the built-in xconsole is enabled. + Analogous to userlist-rect. + + + + + + + + + + + + Layout Container Nodes + + + Layout nodes appear inside item nodes and contain item nodes again. + The type of the layout node determines the arrangement of its + child nodes. An item node can contain one layout node of each type. + + + + Box Nodes + + + Box nodes automatically arrange their children in a row. + They are specified as follows: + +<box orientation="alignment" min-width="num" min-height="num" + xpadding="num" ypadding="num" spacing="num" + homogeneous="bool"> + + Where num means number of pixels and + bool means either true + or false. + The alignment value can be either + horizontal or vertical. + If you leave any attribute off, it will default to zero for numbers, + false for bools and vertical + for the orientation. + + + + The spacing is the distance between neighboring child items. + The padding is the box' outer margin. + If the box is homogeneous, the same amount of space is allocated + to each child item. + + + + + Fixed Nodes + + + Fixed is a container that has its children + laid out at precise coordinates. The size of this container + is the smallest rectangle that contains all the children. Fixed + has no extra attributes and so you just use: + +<fixed> + + Then you put other items with proper position nodes inside it. + + + + + + + Position Nodes + + + Each item can specify its position and size via the pos + node. For example: + +<pos x="0" y="4" width="100%" height="100%"/> + + + + + If the size is not specified, it will be the item's + natural size, called the size hint. + Note that not all items have a useful size hint. + + + + Both position and size can be given in percent and will be calculated + relative to the size of the enclosing container in this case. + For toplevel items it is the percentage of the whole screen. + By appending circumflexes (^) to the size + specification it is possible to modify it to be relative to the + size of the enclosing item's enclosing item and so on. + + + + If the item contains a box, width and + height can be specified to be + box to mean that they are supposed to be the width + and height of the box, that is the items in the box plus the padding. + + + + One of width and height can + be specified to be scale + to mean that it should be scaled according to the other dimension's + scale relative to its size hint. Use this to preserve the aspect + ratio of scaled images automatically. + + + + If the expand attribute is specified and + true, this item will be expanded in the + enclosing box as much as possible (that is it will be given + more space if available). + + + + If width or height is a + plain number, a negative value represents + an offset from the enclosing container's size. Note that it is + possible to specify a positive offset by writing two minus signs. + + + + In either case it is possible to constrain the final size with the + min-width, min-height, + max-width and max-height + attributes which can be specified in the same ways as + width and height. + + + + If x or y is a plain number, + a negative value represents an offset from the right resp. bottom edge, + unlike the default which is the left resp. top edge. + + + + It is also possible to specify which point within the item the + position refers to. This is called the anchor and can be + either c for center or one of + n, ne, e, + se, s, sw, + w and nw + which stand for the different edges/corners corresponding the + directions on a topographical map. + The default is nw, which is the upper left corner. + For example: + +<pos x="10%" y="50%" anchor="w" width="80%" height="95"/> + + + + + + + Show Nodes + + + + + You can specify the type attribute to indicate that + certain items should only be displayed if the type is set. + Prefixing the type with an exclamation mark (!) + reverses the condition. + Valid values include the following: + + + + TypeDisplay if ... + + + chooser + switching to remote login is permitted. + + + + + + halt and reboot + system shutdown is permitted. + + + + + + system + no condition (always set in &kdm;). + + + + + + plugin-entry-name + the conversation plugin provides a + corresponding input field. + + + + + + + For example: + +<show type="chooser"/> + + + + + Alternatively, you can specify a min-screen-width or + min-screen-height value to indicate that certain + items should be displayed only if the screen resolution is the + at least the specified size. + For example: + +<show min-screen-height="768"/> + + + + + + + Normal/Active/Prelight Nodes + + + The look of most item types can be parametrized via the following + tags: + + + + + normal + + Normal state. + + + + prelight + + When the mouse is hovering over the item. + + + + active + + When a mouse button is clicked on the item. + + + + + + + + The exact set of available attributes depends on the item type: + + + + rect + + + +<normal color="#000000" alpha="0.0"/> + + Either of the attributes may be omitted, in which case the + default is used (the example represents the defaults). + alpha is a floating point number between + zero (transparent) and one (opaque). + color is a hashmark followed by a six-digit + hex number; the format is + #rrggbb. + Alternatively, color may be specified as an + eight-digit hex number, in which case the first two digits are + the alpha value. + + + + + + label + + + +<normal color="#ffffff" alpha="1.0" font="Sans 14"/> + + alpha and color are + specified like in rect items. + + + font follows the format + family-list style-options size. + Each part is optional. + + + family-list is a comma-separated + list of font families like helvetica, + monospace, etc. + + + style-options is a space-delimited + list of keywords from the categories style, weight and stretch; + from each category at most one. + The style can be normal, + italic or oblique. + Weight can be ultra-light, + light, medium, + semi-bold, bold, + ultra-bold or heavy. + Allowable stretches comprise ultra-condensed, + extra-condensed, condensed, + semi-condensed, normal, + semi-expanded, expanded, + extra-expanded and ultra-expanded. + + + size is either a floating point + number representing the size in points (1/72 inch) or an + integer followed by px representing the + size in pixels. Point sizes are preferable, as they are + independent from the display resolution. + + + If either attribute is left out, the values from the + style node are used. + If this yields no window-text color specification, white + is used. The default font is the one configured in &kdmrc;. + + + + + + pixmap + svg + + + +<normal file="picture.png" tint="#dddddd" alpha="1.0"/> + + + + + file specifies the file containing the image. + Relative pathnames are relative to the theme's directory. + + + + wallpaper can be used instead of + file to have &kdm; look for images in the + usual locations for &kde; wallpapers. Plasma wallpaper packages + are supported. + + + + element specifies the element id of a SVG file. + If empty, the whole SVG image will be rendered. + + + + For pixmap nodes, it is possible to provide + multiple images, so the best-quality image for a given resolution + can be used. Size-tagged file names have the format + basename-widthxheight.extension. + If the not size-tagged file exists and it is no Plasma + wallpaper package, &kdm; will accept only a perfect match + for a given size and otherwise fall back to the original file. + Otherwise it will try to find an image whose dimensions come + closest to the required size if no perfect match is found. + + + + + + scalemode specifies how to adjust the size of + images which do not match the element's size. + free (the default) means to simply scale the + image to the right size, possibly distorting its aspect ratio. + The other two modes maintain the image's aspect ratio: + fit means to zoom the image to the maximal size + which fits into the element's geometry. The image will be centered. + The remaining area will not be painted by this element, so it should + be placed on top of a solid-filled rect. + crop means to zoom the image to the minimal size + which completely fills the element's geometry. The image will be + clipped symmetrically. + + + + tint and alpha form a + color specification like in rect items. + Each pixel of the image is multiplied with this color + component-wise. + + + + + + + + + + Widget Style Nodes + + + This tag makes it possible to change the appearance of labels and + Qt widgets embedded into the theme, e.g., line edits, buttons or + the user list. + The style settings are inherited by child items, but can be + overridden individually. The defaults are taken from &kdmrc;. + + + + The font attribute defines the font for all widgets. + For widgets with an input function it can be overridden with the + edit-font attribute. + Fonts are specified the same way as in + normal/active/prelight nodes. + + + + Usually, the theming engine tries hard to remove any frames from + Qt widgets, so they melt into the theme seamlessly. In cases + where this is not desired, the frame attribute can + be set to true. + + + + The guistyle attribute can be used to override the + Qt GUI style for embedded widgets. The default is given by + in &kdmrc; + + + + It is possible to specify almost the entire palette for the widgets + as documented at + Trolltech's site. + Attribute names are composed from a scope, a color role and a suffix. + + Possible scopes are - in order of increasing precedence - + all- for all color groups, + no scope for the active and inactive color groups and + active-, inactive- and + disabled- for the respective color group. + + Supported color roles are + window, window-text, + base, alternate-base, + text, bright-text, + highlight, highlighted-text, + button and button-text. + + The suffix can be -color or + -alpha with the respective meaning as in + normal/active/prelight nodes. + + + + As an alternative to specifying the palette inline, the + colorscheme attribute can be used to load + a complete &kde; color scheme. The default is given by + in &kdmrc;. + Individual color specifications will override + the colors from the scheme. + + + + Example: + +<style edit-font="Comic 16" text-color="#dddddd" frame="true"/> + + + + + + Face Browser Color Nodes + + + Color nodes permit overriding the background color of the items + in the face browser. labelcolor and + altlabelcolor are essentially equivalent to + all-base-color resp. + all-alternate-base-color in + style nodes. + If only labelcolor is specified, alternating + item backgrounds are disabled. + + + + +<color labelcolor="#80ffffff" altlabelcolor="#80f0f0f0"/> + + + + + + Text Nodes + + + Text tags are used by labels. They can be used to display + localized text as follows (if the xml:lang + attribute is omitted, the POSIX locale is assumed): + +<text xml:lang="fr">Option</text> + + + + + + + Text nodes can contain the following special character sequences + which will be translated as follows: + + + + + SequenceExpansion + + + %% + A literal % character + + + + %c + Wall clock time and date + + + + %d + Display name (DISPLAY environment variable) + + + + %h + Hostname (gethostname output) + + + + %m + Machine name (machine part of + uname output) + + + + %n + Node name (nodename part of + uname output) + + + + %o + Domain name (getdomainname output) + + + + %r + Release name (release part of + uname output) + + + + %s + System name (sysname part of + uname output) + + + + %t + Remaining number of seconds until timed login is performed, + plus the appropriate i18n plural form of second + + + + %u + Username for timed login + + + + + + _ + Causes the following character to be an accelerator + + + + + + %t and %u are intended to be + used only internally to display the timed-label + message, which is automatically updated every second. + + + + + Stock Nodes + + + Certain common localized labels can be specified via the stock + tags. The text tag is ignored if the + stock tag is used. You really should use the + stock labels rather than just putting all the translations into + the themes. This yields faster load times and likely better + translations. The following values are valid: + + + + + TypeExpansion + + + + caps-lock-warning + Caps Lock is enabled + + + chooser + XDMCP Choose_r + + + quit + _Quit + + + disconnect + Disconn_ect + + + halt + Power o_ff + + + language + Lan_guage + + + login + _Login + + + session + Session _Type + + + reboot + Re_boot + + + + system + _Menu + + + timed-label + User %u will login in %t + + + domain-label + _Domain: + + + username-label + _Username: + + + password-label + _Password: + + + welcome-label + Welcome to %h + + + + + + For example: + +<stock type="welcome-label"/> + + + + + + Buddy Nodes + + + Items which do not directly cause an action can be assigned a buddy. + The buddy is given input focus when the item is activated (clicked + or a label's accelerator pressed). + + + + The buddy is referenced by id with the idref + attribute. Obviously, it must be given an id. Example: + +<item type="label"> + <stock type="username-label"/> + <buddy idref="user-entry"/> + [...] +</item> +[...] +<item type="entry" id="user-entry"> + [...] +</item> + + + + + + + diff --git a/doc/kfontview/CMakeLists.txt b/doc/kfontview/CMakeLists.txt new file mode 100644 index 00000000..dd75aec8 --- /dev/null +++ b/doc/kfontview/CMakeLists.txt @@ -0,0 +1 @@ +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/kfontview/index.docbook b/doc/kfontview/index.docbook new file mode 100644 index 00000000..77dae585 --- /dev/null +++ b/doc/kfontview/index.docbook @@ -0,0 +1,124 @@ + +KFontview"> + + + + +]> + +
+ + +Font Viewer + +&Burkhard.Lueck; &Burkhard.Lueck.mail; + + + + +2013-06-19 +1.1 (&kde; 4.11) + + +KDE +fontview +fonts + + + + +&kfontview; is an application to view and install different types of fonts: + +TrueType (.ttf) +OpenType (otf, .ttf) +Postscript type 1 (file extension on &Windows; & OS/2 .pfb/.pfm; on &UNIX;/&Linux; .pfa/.afm) +BDF (Bitmap Distribution Format, file extension .bdf) +PCF (Portable Compiled Format, file extension .pcf) + + +You can use it as standalone program to preview and install a font +downloaded from the Internet. In the preview you can check that the font +has all characters you need. + + +Additionally &kfontview; can be launched from +the &systemsettings; module +Font Installer to use the extended preview capabilities +of &kfontview;. +To use &kfontview; in &konqueror; select Services in +the sidebar and go to the folders Fonts/Personal + or Fonts/System. +Then open the context menu with a &RMB; click on a font and start &kfontview; +by selecting it from the context menu. + + + + +&kfontview; application + + + + + + &kfontview; application + + + + + + +&kfontview;'s Standard Preview displays your font in several +different sizes using a pangram (a sentence using every letter of the alphabet at least once). +So you can get a good idea of what it will look like. +From the drop down box in the toolbar you can choose additional preview types: + +All Characters displays all characters +provided by the font in one size. +Unicode Block: The Unicode standard arranges groups of characters +together in blocks +Unicode Script: In Unicode, a script is a collection of letters +and other written signs used to represent textual information in one or more +writing systems +Change Text: Using this button opens the Preview +String dialog where you can insert a user defined text. +This feature enables you to check that a font supports the characters you need. + + +You can use the zoom buttons or the mousewheel to change the font size in all preview types. +In Unicode Block and Unicode Script +preview mode additional tooltip info's are displayed hovering a character with the +mouse pointer: +The character's Unicode Category and the value in +UCS-4, UTF-16, UTF-8 and +as XML Decimal Entity. + + +To install a font you downloaded from the Internet, click the +Install button in the lower-right corner. + + +You can install the font for personal us only available to you or system-wide available +for all users, the latter will require administrator privileges. + +Fonts are often provided in an archive format like zip. +Open these archives with &ark; which provides a simple previewer for fonts. +To make use of the extended capabilities of &kfontview; extract the fonts and open them in +&kfontview;. + +Applications need to be restarted to use of the newly installed fonts. +
+ + diff --git a/doc/kfontview/kfontview.png b/doc/kfontview/kfontview.png new file mode 100644 index 00000000..fa205993 Binary files /dev/null and b/doc/kfontview/kfontview.png differ diff --git a/doc/kinfocenter/CMakeLists.txt b/doc/kinfocenter/CMakeLists.txt new file mode 100644 index 00000000..dd75aec8 --- /dev/null +++ b/doc/kinfocenter/CMakeLists.txt @@ -0,0 +1 @@ +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/kinfocenter/index.docbook b/doc/kinfocenter/index.docbook new file mode 100644 index 00000000..62a8b333 --- /dev/null +++ b/doc/kinfocenter/index.docbook @@ -0,0 +1,931 @@ + + + + +]> + + + +The &infocenter; + + + +Michael +McBride +
&Mike.McBride.mail;
+
+ +
+ +&FDLNotice; +2013-06-22 +&kde; SC 4.11 + + +This documentation describes &kde;’s information center. + + + +KDE +kinfocenter +system +information +module + + +
+ + +The &infocenter; + + +The &infocenter; provides you with a centralized and convenient +overview of your system and desktop environment. + + + +The information center is made up of multiple modules. Each module is a +separate application, but the information center organizes all of these +programs into a convenient location. + + + +This next section details the use of the information center itself. For +information on individual modules, please see Default KInfo +Center Modules. + + + +Starting the &infocenter; + + +The &infocenter; can be started in three ways: + + + + + +By selecting Applications +SystemInfo +Center from the application launcher in the panel. + + + + + +By pressing &Alt;F2. +This will bring up &krunner;. Type +kinfocenter, and press &Enter;. + + + + + +You can type kinfocenter & at any command prompt. + + + + + +All three of these methods are equivalent, and produce the same result. + + + + + +The &infocenter; Screen + + +When you start the information center, you are presented with a window, +which can be divided into three functional parts. + + + + The &infocenter; Screen. + + + + + + The &infocenter; Screen + + + + + +Across the top is a toolbar. The toolbar will provide you with quick +access to most of &infocenter;’s features like export, get help on the current +module and a help menu. + + + +Along the left hand side, is a column with a filter field at the top. +This is a where you choose which module to investigate. To navigate through the various KCM modules, left click on +the module in the tree view. You can also use the arrow keys to scroll though the KCM's and pressing &Enter; will select the module. The module will +now appear of the main panel of the &infocenter; window. Some items within the tree view are categories, you can left click or again press &Enter; to expand and collapsed these items. This +will show the modules under the category. +You can right click on the module listing to show the following options: + + Collapse All Categories: Collapses the tree to show only top level modules and categories. + Expand All Categories: Expands the tree to show modules. + Clear Search: This will clear any filter you have applied on the module listing via the search box + + + + +The main panel shows you the system information about the selected module. + + + + + + + + + + +The &infocenter; Toolbar + +This next section gives you a brief description of what each toolbar item does. + + + + +Module Help button + + +This button opens khelpcenter with the current help page for the information module. + + + + +Help Menu button + +&kinfocenter; has the common &kde; Help +menu items, for more information read the section about the Help Menu +of the &kde; Fundamentals. + + + + + + +Exiting The &kde; Information Center + +You can exit the info center one of two ways: + + + +Type &Ctrl;Q on the keyboard. + + + + +Click on the Close button on the frame surrounding the info center. + + + + + + + + +The Default &infocenter; Modules + + + + +Summary Information Module + + +The summary information KCM provides a quick way to display important information. +The module has three categories; OS Information, CPU Information and Hard Drive Information. + +You may have more than one of these information boxes per category. + + +<acronym>OS</acronym> Information Box + + +Screenshot of OS Information box + + + + + + OS Information Box + + + + +The OS information box has the following information: + + +OS Version: This is the version information of the Operating System KInfoCenter is present on. +KDE SC Version: This is the version of the KDE Software Collection KInfoCenter was compiled on. +Hostname: This is the hostname of the computer KInfoCenter is present on. + + + + + +<acronym>CPU</acronym> Information Box + + +Screenshot of CPU Information box + + + + + + CPU Information Box + + + + +The CPU information box has the following information: + + +Processor: This is the vendors name for your CPU +Processor Number: This is the ID number of your CPU, starting from zero. +Processor Max Speed: This is the processors maximum speed. + + + + + +Hard Drive Information Box + + +Screenshot of Hard Drive Information box + + + + + + Hard Drive Information Box + + + + +The Hard Drive information box has the following information: + + +Drive Title: This is the vendors name for the hard drive. +Storage Size: This is the current size of your hard drive. +Bus: This is the bus your hard drive uses. + + + + + + + +Memory Information Module + +This module displays the current memory usage. It is updated +constantly, and can be very useful for pinpointing bottlenecks when certain +applications are executed. + + +Memory Types + +The first thing you must understand, is there are two types of +memory, available to the operating system and the programs +that run within it. + +The first type, is called physical memory. This is the memory located +within the memory chips, within your computer. This is the +RAM (for Random Access Memory) you bought when you +purchased your computer. + +The second type of memory, is called virtual or swap memory. This +block of memory, is actually space on the hard drive. The operating +system reserves a space on the hard drive for swap space. +The operating system can use this virtual memory (or swap space), if it +runs out of physical memory. The reason this is called +swap memory, is the operating system takes some data that +it doesn't think you will want for a while, and saves that to disk in +this reserved space. The operating system then loads the new data you +need right now. It has swapped the not needed data, for +the data you need right now. Virtual or swap memory is not as fast as +physical memory, so operating systems try to keep data (especially often +used data), in the physical memory. + +The total memory, is the combined total of physical memory and +virtual memory. + + + + +Memory Information Module + +This window is divided into a top and bottom section + +The top section shows you the total physical memory, total free + physical memory, shared memory, and buffered memory. + +All four values are represented as the total number of bytes, and + as the number of megabytes (1 megabyte = slightly more than 1,000,000 + bytes) + +The bottom section shows you three graphs: + + +Total Memory (this is the combination of physical and virtual memory). +Physical Memory +Virtual memory, or Swap Space. + + +The grey areas are free, and the blue and green areas are used. +The exact values of each type of memory are not critical, and + they change regularly. When you evaluate this page, look at + trends. + +Does your computer have plenty of free space (grey areas)? If + not, you can increase the swap size or increase the physical + memory. + +Also, if your computer seems sluggish: is your physical memory + full, and does the hard drive always seem to be running? This suggests + that you do not have enough physical memory, and your computer is + relying on the slower virtual memory for commonly used data. Increasing + your physical memory will improve the responsiveness of your + computer. + + + + + + + +Device Information Module + +Device Information is a device viewer module. It shows all relevant devices that are present within your PC. It has three sections, +a device viewer, a information panel and a UDI listing for the currently selected device. + +Device Listing +The device viewer displays all the current devices detected on your PC in a tree. The main topics at the beginning of the tree +are the device categories, left click on a collapsed category to expand it and vice versa to collapse it. +To display information about a device, left click on the device in the viewer, the information will display on the right side information panel. +You can right click on the device viewer to show the following options: + +Collapse All: Collapses the tree to show only the main categories. +Expand All: Expands the tree to show all the children devices. +Show All Devices: Show all the categories no matter if devices are present in those categories +Show Relevant Devices: Only show categories that have devices present. + +The default display is to collapse all while showing only relevant devices. Please note that the devices shown +in the device listing are not all devices within your PC, they are just devices that have been detected via the Solid. + The device viewer can show the following devices: + +Processors: These are your computers CPUs ( Central Processing Units ). +Storage Drives: Devices that are used to store your PCs files and data. +Network Interfaces: Devices that allow you to connect to a network or to another PC. +Audio Interfaces: Devices that allow your PC to play Sound. They are split into 2 categories, ALSA and OSS sound architectures. +Video Devices: Devices that allow you to stream live video. +Serial Devices: Devices that are connected to your serial port in your PC. +Smart Card Devices: Devices that are smart card readers. +Digital Video Broadcasting Devices: Devices that use the open standards for digital television. +Device Buttons: These are buttons that are present on your PC or external devices. +Batteries: These are battery devices that are plugged into your laptop. +AC Adapters: These devices will be present when you plug in your AC Adapter. +Multimedia Players: Devices that play media files, like a music player. +Camera Devices: These are digital camera that are connected to your PC. + + +Video devices do not include your video card adapter + + + +Information Panel +The information panel is where device information is shown when you select a device. The first two information topics are always: + +Product: The name of the device. +Vendor: The vendors name of the device. + +The following information topics are dependent on the device chosen. They are labeled with easy to understand names. +The information labels have the ability to be selected and copied from. + +Processor Max Speed and Supported Instruction sets topics are usual not set by solid. + + +Top categories in the device listing do not show any information. + + + +<acronym>UDI</acronym> Information +The bottom information panel shows the current selected devices UDI. This is the unique device identifier. +The label has the ability to be selected and copied from. + + + + + + +Interrupt Request (<abbrev>IRQ</abbrev>) Information Module + +This page displays information about the Interrupt Request +Lines in use, and the devices that use them. + +An IRQ is a hardware line used in a +PC by (ISA bus) devices like +keyboards, modems, sound cards, &etc;, to send interrupt signals to the +processor to tell it that the device is ready to send or accept data. +Unfortunately, there are only sixteen IRQ's (0-15) +available in the i386 (PC) architecture for sharing among +the various ISA devices. + +Many hardware problems are the result of IRQ +conflicts, when two devices try to use the same IRQ, or +software is misconfigured to use a different IRQ from the +one a device is actually configured for. + +The exact information displayed is system-dependent. On some +systems, IRQ information cannot be displayed + yet. + +On &Linux;, this information is read from +/proc/interrupts, which is only +available if the /proc +pseudo-filesystem is compiled into the kernel. + +The first column, is the IRQ number. The second +column, is the number of interrupts that have been received since the last +reboot. The third column shows the type of interrupt. The fourth, +identifies the device assigned to that interrupt. + +The user cannot modify any settings on this page. + + + + + +<acronym>DMA</acronym> Channel Information Module + + This page displays information about the DMA +(Direct Memory Access) Channels. A DMA channel is a +direct connection that allows devices to transfer data to and from +memory without going through the processor. Typically, i386-architecture +systems (PC's) have eight DMA +channels (0-7). + + The exact information displayed is system-dependent. On +some systems, DMA Channel information cannot be +displayed yet. + + On &Linux;, this information is read from /proc/dma, which is only available if the +/proc pseudo-filesystem is +compiled into the kernel. + + A list of all currently-registered (ISA bus) +DMA channels that are in use is shown. The first +column shows the DMA channel, and the second column +shows the device which uses that channel. + + +Unused DMA channels are not listed. + + + +The user cannot modify any settings on this page. + + + + + + +IEEE 1394 Device Information Module + +The IEEE 1394 interface, also known as FireWire, +is a serial bus interface standard for high-speed +communications and isochronous real-time data transfer. + +The list in this module displays all devices attached to IEEE 1394 bus and +allows you to reset the bus by clicking the Generate 1394 Bus Reset +button. + +The meaning of the columns in this list: + +Name: port or node name, the number can change with each bus reset +GUID: the 64 bit GUID of the node +Local: checked if the node is an IEEE 1394 port of your computer +IRM: checked if the node is isochronous resource manager capable +CRM: checked if the node is cycle master capable +ISO: checked if the node supports isochronous transfers +BM: checked if the node is bus manager capable +PM: checked if the node is power management capable +Acc: the cycle clock accuracy of the node, valid from 0 to 100 +Speed: the speed of the node +Vendor: the vendor of the device + + + + + + +<acronym>PCI</acronym>-bus/Installed <acronym>PCI</acronym> Cards Information Module + +This page displays information about the +PCI-bus and installed PCI cards, +and other devices that use the Peripheral Component Interconnect +(PCI) bus. + +The exact information displayed is system-dependent. On some +systems, PCI-information can not yet be +displayed. + +On &Linux;, this information is read from /proc/pci which is only available if the +/proc pseudo-filesystem is +compiled into the kernel. A listing of all PCI +devices found during kernel initialization, and their configuration, is +shown. + +Each entry begins with a bus, device and function number. +The user cannot modify any settings on this page. + + + + + +Input/Output Port Information Module + +This page displays information about the I/O ports. + +I/O Ports are memory addresses used by the processor for direct +communication with a device that has sent an +interrupt signal to the processor. + +The exchange of commands or data between the processor and the device +takes place through the I/O port address of the device, which is a + hexadecimal +number. No two devices can share the same I/O port. Many devices use + multiple +I/O port addresses, which are expressed as a range of hexadecimal +numbers. + +The exact information displayed is system-dependent. On some +systems, I/O port information can not yet be displayed. + +On &Linux;, this information is read from /proc/ioports which is only available if +the /proc pseudo-filesystem is +compiled into the kernel. A list of all currently-registered I/O port +regions that are in use is shown. + +The first column is the I/O port (or the range of I/O ports), the +second column identifies the device that uses these I/O ports. + +The user cannot modify any settings on this page. + + + + + +<acronym>SCSI</acronym> Interface Information Module + +This page displays information about Small Computer Systems +Interface (SCSI) Interfaces and the attached +SCSI devices. + +The exact information displayed is system-dependent. On +some systems SCSI information cannot be displayed +yet. + +On &Linux;, this information is read from /proc/scsi/scsi, which is only available +if the /proc pseudo-filesystem is +compiled into the kernel. A listing of all SCSI +devices known to the kernel is shown. + +The devices are sorted numerically by their host, channel, and +ID numbers. + +The user cannot modify any settings on this page. + + + + + +<acronym>USB</acronym> Controller/<acronym>USB</acronym> Devices Information Module + +This module allows you to see the devices attached to your +USB bus(es). + +This module is for information only, you cannot edit any +information you see here. + + + + + +Samba Status Information Module + +The Samba and NFS Status Monitor is a front end +to the programs smbstatus and +showmount. Smbstatus reports on current Samba +connections, and is part of the suite of Samba tools, which implements +the SMB (Session Message Block) protocol, also called +the NetBIOS or LanManager protocol. + +This protocol can be used to provide printer sharing or drive +sharing services on a network including machines running the various +flavors of &Microsoft; &Windows;. + +showmount is part of the NFS +software package. NFS stands for Network File System +and is the traditional &UNIX; way to share folders over the +network. In this case the output of showmount + is parsed. On some systems showmount is in +/usr/sbin, check if you have +showmount in your PATH. + + +Exports + +On this page you can see a big list which shows the currently +active connections to Samba shares and NFS exports of +your machine. The first column shows you whether the resource is a Samba +(SMB) share or a NFS export. The +second column contains the name of the share, the third the name of the +remote host, which accesses this share. The remaining columns have only +a meaning for Samba-shares. + +The fourth column contains the User ID of the +user, who accesses this share. Note that this does not have to be equal +to the &UNIX; user ID of this user. The same applies +for the next column, which displays the group ID of the +user. + +Each connection to one of your shares is handled by a single +process (smbd), the next column shows the process +ID (pid) of this +smbd. If you kill this process the connected user +will be disconnected. If the remote user works from &Windows;, as soon +as this process is killed a new one will be created, so he will almost +not notice it. + +The last column shows how many files this user has currently open. +Here you see only, how many files he has open just +now, you don't see how many he copied or formerly opened &etc; + + + + +Imports + + Here you see which Samba- and NFS-shares from +other hosts are mounted on your local system. The first column shows +whether it is a Samba- or NFS-share, the second column +displays the name of the share, and the third shows where it is +mounted. + +The mounted NFS-shares you should see on +&Linux; (this has been tested), and it should also work on &Solaris; +(this has not been tested). + + + + +Log + +This page presents the contents of your local samba log file in a +nice way. If you open this page, the list will be empty. You have to +press the Update button, then the samba log file +will be read and the results displayed. Check whether the samba log file +on your system is really at the location as specified in the input +line. If it is somewhere else or if it has another name, correct +it. After changing the file name you have to press +Update again. + +Samba logs its actions according to the log level (see +smb.conf). If loglevel = 1, samba logs only when +somebody connects to your machine and when this connection is closed +again. If log level = 2, it logs also if somebody opens a file and if he +closes the file again. If the log level is higher than 2, yet more +stuff is logged. + +If you are interested in who accesses your machine, and which +files are accessed, you should set the log level to 2 and regularly +create a new samba log file (⪚ set up a cron task +which once a week moves your current samba log file into another +folder or something like that). Otherwise your samba log file may +become very big. + +With the four checkboxes below the big list you can decide, which +events are displayed in the list. You have to press +Update to see the results. If the log level of +your samba is too low, you won't see everything. + +By clicking on the header of one column you can sort the list by +this column. + + + +Statistics + +On this page you can filter the contents of the third page for +certain contents. + +Let's say the Event field (not the one in the +list) is set to Connection, +Service/File is set to *, +Host/User is set to *, +Show expanded service info is disabled and +Show expanded host info is disabled. + +If you press Update now, you will see how +often a connection was opened to share * (&ie; to any +share) from host * (&ie; from any host). Now enable +Show expanded host info and press +Update again. Now you will see for every host +which matches the wildcard *, how many connections +were opened by him. + +Now press clear. + +Now set the Event field to File Access and +enable Show expanded service info and press +Update again. + +Now you will see how often every single file was accessed. If you +enable Show expanded host info too, you will see +how often every single user opened each file. + +In the input lines Service/File and +Host/User you can use the wildcards +* and ? in the same way you use +them at the command line. Regular expressions are not +recognized. + +By clicking on the header of a column you can sort the list by +this column. This way you can check out which file was opened most +often, or which user opened the most files or whatever. + + + + + +Section Author + +Module copyright 2000: Michael Glauche and &Alexander.Neundorf; &Alexander.Neundorf.mail; + +Originally written by: Michael Glauche + +Currently maintained by: &Alexander.Neundorf; &Alexander.Neundorf.mail; + + +Contributors +Conversion to kcontrol applet: +&Matthias.Hoelzer-Kluepfel; &Matthias.Hoelzer-Kluepfel.mail; +Use of K3Process instead of popen, and more error checking: +&David.Faure; &David.Faure.mail; +Conversion to kcmodule, added tab pages 2,3,4, bug +fixed: +&Alexander.Neundorf; &Alexander.Neundorf.mail; + + +Documentation copyright 2000 &Alexander.Neundorf; &Alexander.Neundorf.mail; + +Documentation translated to docbook by &Mike.McBride; &Mike.McBride.mail; + + + + + + + + + +Network Interfaces Information Module + + +This page displays information about the network interfaces +installed in your computer. + + +The exact information displayed is system-dependent. On +some systems, this information can not yet be displayed. + +The user cannot modify any settings on this page. + + + + + +OpenGL Information Module + +This page displays information about installed OpenGL implementation. +OpenGL (for "Open Graphics Library") is a cross-platform, +hardware independent interface for 3D graphics. + +GLX is the binding for OpenGL to X Window system. + + DRI (Direct Rendering Infrastucture) provides hardware acceleration for OpenGL. +You must have a videocard with 3D accelerator and properly installed driver for this. + + +Read more at the official OpenGL site http://www.opengl.org + + + + + +X Server Information Module + +This screen is useful for getting specific information about your +X server and the current session of X. + +When you open this module, you are presented with some +information. The left hand side of the window is organized into a +tree. Some of the elements have a plus sign in front of the label. +Clicking this sign opens a submenu related to the +label. Clicking on a minus sign in front of a label hides the +submenu. + +The right hand side of the window contains the individual +values for each of the parameters on the left. + +The information presented will vary depending on your +setup. + +Some setups may not be able to determine some or all of the +parameters. + +You can not change any values from this menu. It is for +information only. + + + + + + + +Credits and License + +&infocenter; +Program copyright 1997-2001 The &infocenter; Developers +Contributors: + + +Matthias Hoelzer-Kluepfel +&Matthias.Hoelzer-Kluepfel.mail; +&Matthias.Elter; &Matthias.Elter.mail; + + +Documentation copyright 2000 Michael +McBride &Mike.McBride.mail; + +Contributors: + + +&Paul.Campbell; &Paul.Campbell.mail; +&Helge.Deller; &Helge.Deller.mail; +&Mark.Donohoe; +&Patrick.Dowler; +&Duncan.Haldane; duncan@kde.org +&Steffen.Hansen; stefh@mip.ou.dk. +Matthias Hoelzer-Kluepfel &Matthias.Hoelzer-Kluepfel.mail; +Martin Jones &Martin.R.Jones.mail; +&Jost.Schenck; &Jost.Schenck.mail; +&Jonathan.Singer; &Jonathan.Singer.mail; +&Thomas.Tanghus; &Thomas.Tanghus.mail; +&Krishna.Tateneni; &Krishna.Tateneni.mail; +Ellis Whitehead ewhitehe@uni-freiburg.de + + + + + +&underFDL; +&underGPL; + + +
+ diff --git a/doc/kinfocenter/kinfocenter.png b/doc/kinfocenter/kinfocenter.png new file mode 100644 index 00000000..29176c92 Binary files /dev/null and b/doc/kinfocenter/kinfocenter.png differ diff --git a/doc/kinfocenter/os_block.png b/doc/kinfocenter/os_block.png new file mode 100644 index 00000000..1fa1fce0 Binary files /dev/null and b/doc/kinfocenter/os_block.png differ diff --git a/doc/kinfocenter/pro_block.png b/doc/kinfocenter/pro_block.png new file mode 100644 index 00000000..551fbd1c Binary files /dev/null and b/doc/kinfocenter/pro_block.png differ diff --git a/doc/kinfocenter/sto_block.png b/doc/kinfocenter/sto_block.png new file mode 100644 index 00000000..079f460d Binary files /dev/null and b/doc/kinfocenter/sto_block.png differ diff --git a/doc/klipper/CMakeLists.txt b/doc/klipper/CMakeLists.txt new file mode 100644 index 00000000..0df9c9ad --- /dev/null +++ b/doc/klipper/CMakeLists.txt @@ -0,0 +1,4 @@ +########### install files ############### +# +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/klipper/index.docbook b/doc/klipper/index.docbook new file mode 100644 index 00000000..c119f6d6 --- /dev/null +++ b/doc/klipper/index.docbook @@ -0,0 +1,532 @@ + + + + + +]> + + + +The &klipper; Handbook + + +&Philip.Rodrigues; &Philip.Rodrigues.mail; + + +&Carsten.Pfeiffer; &Carsten.Pfeiffer.mail; + + + + + + + + +2000-2003 +&Philip.Rodrigues; + + +&FDLNotice; + +2013-06-02 +0.9.7 (&kde; 4.11) + + +&klipper; is the &kde; clipboard cut & paste utility. + + + +KDE +Klipper +kdebase +clipboard + + + + +Introduction +&klipper; is the &kde; clipboard utility. It stores clipboard +history, and allows you to link clipboard contents to application +actions. Please report any problems or feature requests to KDEs bugzilla or use the Report Bug +item in the Help menu. + + + + +Using &klipper; + + +Basic Usage + +The &klipper; icon. + + + + + +The &klipper; icon + + + + +To display the clipboard history, click on the &klipper; icon in + the &kde; panel, or press &Ctrl;&Alt;V . Previous + clipboard entries are shown at the top of the popup menu which + appears. Selecting one of these copies it to the clipboard, from + where it can be pasted into any &kde; or X application as + usual. + +The shortcut for this action has to be configured in the +System Tray Settings on the Entries +page. + +You can search through the clipboard history by opening it +(click on &klipper;) and typing your query. The results are updated as +you type. In case you're wondering how to use the accelerator keys in +the &klipper; menu, just press &Alt; and the accelerator you want. For +example, to clear the clipboard history when the &klipper; menu is +open, press &Alt; and the underlined letter in Clear Clipboard History +. + +Select Show Barcode from the &klipper; popup menu to open a +dialog with a QRCode and a +DataMatrix barcode. +Use &ksnapshot; to capture the barcodes and save them. + + +To disable &klipper;, click on its icon and +from the menu that appears, select +Quit. + + + + +Actions + +&klipper; can perform actions on the contents of the clipboard, +based on whether they match a particular regular expression. For +example, any clipboard contents starting with http:// can +be passed to Firefox or &konqueror; as &URL;s to open. In addition, if the +contents matches a path, similar actions can be performed according to the file's +type. E.g, if the path to a PDF file is copied to the clipboard, the file can be +viewed in &okular;. + +To use this feature, just select a &URL; or path. +If there is a matching regular expression in &klipper;'s +list, a menu will appear showing you the programs for your selection. +Use the mouse or cursor keys to select a program, and &klipper; will run +this program, opening the address pointed to by the +selection. + +If you do not want to perform any actions on the clipboard +contents, select Disable This Popup on the pop-up menu +to return to what you were doing before. If you leave the menu, it will +disappear, leaving you to continue your work. You can change the time +that the menu remains for in the Configure Klipper... +dialog, with the option Timeout for action popups +under the General page. You can separately disable the +file path part using the option Enable MIME-based actions under +the Actions page. + +Actions can be disabled completely by clicking on &klipper; and +deselecting Enable Clipboard Actions, or by pressing +&Ctrl;&Alt;X. + +Clipboard contents which match a regular expression can also be +edited before performing an action on them. Select Edit +contents... on the &klipper; pop-up menu, and you can +change the clipboard contents in the dialog which appears, before +clicking the OK button to run the appropriate +action. + +Pressing &Ctrl;&Alt;R shows the pop-up +menu to repeat the last action which &klipper; performed. + + + + +Clipboard/Selection Behavior + + +General + +&klipper; can be used to set the behavior of the clipboard and selection in +&kde;. + + +The &X-Window; uses two separate clipboard buffers: the +selection and the clipboard. Text is +placed in the selection buffer by simply selecting it, and can be +pasted with the middle mouse button. To place text in +the clipboard buffer, select it and press +&Ctrl;X or +&Ctrl;C . Text from the +clipboard buffer is pasted using &Ctrl;V + or by selecting +EditPaste +. + + + + + + +Changing Clipboard/Selection Behavior + +In order to change clipboard/selection behavior, select +Configure &klipper;... from the &klipper; pop-up menu, +and in the dialog box that appears, select the +General page. Unchecking Synchronize contents of the clipboard and the +selection makes the clipboard and selection function as completely +separate buffers as described above. With this option set, the option +Ignore selection will prevent &klipper; from +including the contents of the selection in its clipboard history and from +performing actions on the contents of the selection. Selecting +Synchronize contents of the clipboard and the selection +causes the clipboard and selection buffers to always be the same, meaning that +text in the selection can be pasted with either the +middle mouse button or the key combination &Ctrl;V +, and similarly for text in the clipboard buffer. + + + + + + + + + + + + +Configuring &klipper; + + + +Viewing the Configuration Dialog + +To view or change &klipper;'s settings, open the &klipper; +pop-up menu, and select Configure Klipper.... The &klipper; +configuration dialog will appear. Its contents are described +below. + + + + +General Options + + + + +Save clipboard contents on +exit If this option is on, the clipboard +history will be saved when &klipper; exits, allowing you to use it next time +&klipper; starts. + + + + +Prevent empty clipboard +If selected, the clipboard will never be empty: &klipper; will +insert the most recent item from the clipboard history into the clipboard +instead of allowing it to be empty. + + + +Ignore images +When an area of the screen is selected with mouse or keyboard, +this is called the selection. If this option is selected, only text +selections are stored in the history, while images and other selections are not. + + + + + +Ignore selection +Sets the clipboard mode. This option will prevent &klipper; from +including the contents of the selection in its clipboard history and from +performing actions on the contents of the selection. See . + + + + + +Text selection only +When an area of the screen is selected with mouse or keyboard, this is +called the selection. If this option is selected, only text selections +are stored in the history, while images and other selections are not. +See . + + + + + +Synchronize contents of the clipboard and the +selection +Sets the clipboard mode. +When an area of the screen is selected with mouse or keyboard, this is +called the selection. If this option is selected, the selection and the +clipboard is kept the same, so that anything in the selection is immediately +available for pasting elsewhere using any method, including the traditional +middle mouse button. Otherwise, the selection is recorded in the clipboard +history, but the selection can only be pasted using the middle mouse button. +Also see the Ignore selection option. +See . + + + + + +Timeout for Action pop-ups +Set the time that a popup menu will remain for if you do +nothing with it. + + +Clipboard history +size +Sets the number of items that are stored +in the clipboard history. + + + + + + + +Actions Options + + + +Replay actions on an item selected from +history +If this is switched on, selecting an item from the history +causes &klipper; to display the actions pop-up on that item, if +appropriate. + + + + +Remove white space when executing actions +If selected, any white space (spaces, tabs, &etc;) at the +beginning and end of the clipboard contents will be removed before passing the +clipboard contents to an application. This is useful, for example, if the +clipboard contains a &URL; with spaces which, if opened by a web browser, would +cause an error. + + + + +Enable MIME-based actions +If selected, in addition to the actions you defined +a list of applications for the detected MIME type will appear in the popup menu. + + + + +Editing Expressions/Actions +On the Actions page, double-click +the regular expression or action that you want to edit or select it and +press the Edit Action button. A dialog will appear in which the +expression text can be edited as you wish. + + + +Adding Expressions/Actions +Click the Add Action button +to add a regular expression for &klipper; to match. &klipper; uses +&Qt;'s QRegExp, which understands most regular +expressions as you would use in grep or +egrep for instance. +You can add a description of the regular expression type (⪚ +HTTP URL) by left clicking in the +Description column. + +You can find detailed information about the use of +QRegExp regular expressions at http://qt-project.org/doc/qt-4.8/qregexp.html#details. +Note that &klipper; does not support the wildcard mode mentioned on this +page. + +Edit the regular expression as described above. To add a command +to execute, click Add Command and edit the command +in an in-place text editing box. Double-clicking on a command allows you to edit it. + +Note that %s in the command line is replaced with +the clipboard contents, ⪚ if your command definition is +kwrite %s and +your clipboard contents are /home/phil/textfile, +the command kwrite +/home/phil/textfile will be run. To +include %s in the command line, escape it with a +backslash, as so: \%s. + + +Advanced +Brings up the Disable Actions for windows of type +WM_CLASS dialog. +Some programs, such as &konqueror;, +use the clipboard internally. If you get unwanted &klipper; pop-ups all the time +when using a certain application, do the following: + + +Open the application. +From a terminal, run xprop +| grep WM_CLASS +and then click on the window of the application you are +running. +The first string after the equals sign is the one to +enter. + + +Once the WM_CLASS is added, no more actions will be generated for +windows of that application. + + + + + + + +Shortcuts Options + +The shortcuts page allows you to change the keyboard shortcuts +which are used to access &klipper; functions. You can change the +shortcut to one of three things: + + + +None +The selected action cannot be accessed directly from the +keyboard + + +Default +The selected action uses &klipper;'s default key. These are the +shortcuts referred to in this manual. + + +Custom +The selected action is assigned to the keys you choose. +To choose a custom key for the action you have selected, click on +Custom and then None. +Now type the desired key combination on your keyboard, as in any &kde; application. + + + + +If you define a shortcut for Open Klipper at Mouse Position +pressing this shortcut will open the &klipper; popup menu at the position of +the mouse cursor, instead of their default position (in the &kde; Panel). +Useful if you use the mouse more than the keyboard. + + + + + +Credits and License + + +&klipper; + + +Program copyright 1998 &Andrew.Stanley-Jones; asj@cban.com + + +Program copyright 1998-2000 &Carsten.Pfeiffer; &Carsten.Pfeiffer.mail; + +Currently maintained by Esben Mose Hansen. See http://mosehansen.dk/about +for contact details. + + + +Documentation copyright 2000-2003, 2005 &Philip.Rodrigues; +&Philip.Rodrigues.mail; + + +&underFDL; +&underGPL; + + + + +Installation + + +How to obtain &klipper; + +&install.intro.documentation; + + + + +Compilation and Installation +&install.compile.documentation; + + + + + + +&documentation.index; + + + + + + + + + + + + + diff --git a/doc/klipper/screenshot.png b/doc/klipper/screenshot.png new file mode 100644 index 00000000..6c660576 Binary files /dev/null and b/doc/klipper/screenshot.png differ diff --git a/doc/kmenuedit/CMakeLists.txt b/doc/kmenuedit/CMakeLists.txt new file mode 100644 index 00000000..cad13c8f --- /dev/null +++ b/doc/kmenuedit/CMakeLists.txt @@ -0,0 +1,3 @@ +########### install files ############### +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/kmenuedit/done.png b/doc/kmenuedit/done.png new file mode 100644 index 00000000..e9caa39e Binary files /dev/null and b/doc/kmenuedit/done.png differ diff --git a/doc/kmenuedit/index.docbook b/doc/kmenuedit/index.docbook new file mode 100644 index 00000000..b02f6851 --- /dev/null +++ b/doc/kmenuedit/index.docbook @@ -0,0 +1,645 @@ + + + + Firefox"> + + +]> + + + + + +The &kde; Menu Editor Handbook + + +&Milos.Prudek; &Milos.Prudek.mail; +&Anne-Marie.Mahfouf; &Anne-Marie.Mahfouf.mail; + +&Lauri.Watts; &Lauri.Watts.mail; + + + + + + +2000 +&Milos.Prudek; + + +2008 +&Anne-Marie.Mahfouf; + + +&FDLNotice; + +2013-09-07 +0.9 (&kde; 4.11) + +&kmenuedit; allows editing one of the &kde; application launchers: &kickoff;, the classic &kmenu; or Lancelot Launcher. + + + +KDE +KDE Menu Editor +kmenuedit +application +program +menu +kickoff +Lancelot + + + + +Introduction + +&kmenuedit; allows editing the menu of &kde; application launchers: &kickoff;, classic &kmenu; or Lancelot Launcher. + +&kmenuedit; can be started either by &RMB; clicking the application launcher +button on the panel and choosing Edit +Applications..., or +by typing kmenuedit in the &krunner; line. + +&kmenuedit; allows you to: + + +View and edit the menu used by the current application launcher (&kickoff;, classic menu or Lancelot Launcher) +Cut, Copy +and Paste submenus and items +Create and delete submenus and items +Change the order of submenus and items +Hide items and add new submenus and items + + +By default all applications installed on the computer appear in the application launchers menu of all users. +Applications may appear more than once in several different menus. +Empty submenu categories defined in the desktop menu specification will show up as well, +but are not visible in application launchers unless you install applications belonging to these categories. + + +The tree view has three different entry types: + +Submenu: Only Name, Comment and +Description fields and the button to select an icon +are enabled, the Advanced tab is disabled. +Any submenu can hold additional submenus and/or items. + +Items: Use this entry to enter the data for the application you want to add. +For detailed information see Using &kmenuedit;. + +Separator: A visual entry to structure the menu. It cannot be modified +and all editing actions are disabled. + + + +&kmenuedit; has two tree view modes - normal and with hidden entries. To see the latter check the option +Show hidden entries in the configuration dialog on the General options page. + +Many additional entries appear in hidden view mode in the tree. Several hidden entries seem to be just duplicates +but have different command options. Usually you should never change these hidden entries or you risk to break some +functionality of the system. + +In hidden mode you will have a special submenu .hidden [Hidden] as top level +item in the tree. This special submenu is not editable. In this submenu all deleted items will be shown at the next +start of &kmenuedit;. +It is not possible to delete entries using the &GUI; in this special submenu. They will reappear at the +next start of &kmenuedit;. + + + +Use Cases + + +Adapt the Menu for a User + + +Reorder Items + +This should be done in hidden view mode where only the submenus and items visible in the application +launcher menu are displayed. + +By default the menu is sorted alphabetically using the English names or descriptions. Using another language +than English some submenus and items therefore will appear in an unsorted order. + +Use the options in EditSort +to sort either by name or description. If you use the classic application launcher you have to select the +corresponding Format option in the settings dialog. In the &kickoff; launcher check +Show applications by name if you sort them by name here. + +Grouping your frequently used submenus or items together ⪚ at the top of the menu makes selecting them easier. +To change the order of particular items or submenus in the tree use the Move Up or +Move Down button in the toolbar or these actions in the menu. + +All application launchers will use the order of submenus defined in &kmenuedit;. + + + + +Remove Items from the Menu View + +Having shown all applications installed on a computer may be confusing for some users so you may +want to hide some less frequently used items or submenus. There are two different ways to do that: + + +Switch to normal view mode without hidden entries. If you delete items they are moved to the +.hidden [Hidden] submenu. You can move them back into the tree to have them in the menu again. + +If you delete a submenu it will be really deleted with all its submenus and items. +To recreate them you can use EditRestore to System +Menu, but this will remove all your custom submenus and items +and the corresponding .desktop files are deleted too. This action cannot be reverted. + + +The preferred way to remove submenus and items in the menu of an application launcher is to check Hidden +entry on the General tab and switch to the hidden view mode. +In this mode it is easy to revert changes without destroying the menu structure. +The only drawback is that you have to hide all entries in a submenu manually to +hide the whole submenu from the view. + + + + + + +Adding Custom Items + +To add custom items (submenu, item or separator) use the actions in the menu or toolbar. +Items need a Name and a Command, without a command entry an item will not be saved and your addition gets lost. + +If you add an entry it is inserted as sub entry at the actual highlighted position in the tree. +Move an entry by dragging it with the mouse or using the Move Down button +to the bottom of the tree to make it a top level entry. + + + + + +Transfer application launcher settings + +There is no way to transfer menu settings using the &GUI;, you have to do that manually +and copy the following files to the target user: +&kmenuedit; stores the menu hierarchy in +$HOME/.config/menus/applications-kmenuedit.menu +and $HOME/.local/share/desktop-directories +contains desktop files for submenus you created. +In $HOME/.local/share/applications/ you +find the desktop files for the custom items you created. + +The shortcuts for each application are stored in ~/.kde/share/config/kglobalshortcutsrc, +but export/import does not work because the UUIDs of the shortcuts do not match up between systems, even though the +.desktop files are the same. You have to assign all shortcuts manually again. + + + + + + + + + + +&Virgil.J.Nisly; &Virgil.J.Nisly.mail; + + +Adding a Menu Entry + + In this example, we will add &firefox; to the Internet submenu. + To start off, we need to open &kmenuedit;, so &RMB; on the application +launcher menu, click Edit Applications... to start +&kmenuedit;. After &kmenuedit; has started, select Internet as shown in picture below. + +Select Internet + + + + + +Select Internet + + + + + Once you have selected Internet, click on FileNew Item..., opening the New Item dialog, as shown below. Type the name of the program you want to add, in this case, type firefox. + +New Item dialog + + + + + +The New Item dialog. + + + + + +Press return, and you should see something like the picture below in the main window. + +New Item + + + + + +The new item created. + + + + + +Now lets fill in the Description:, in this case type Web Browser. +The appearance how description and name will be displayed depends on the settings in the application +launcher ⪚ Web Browser (Firefox) or Firefox (Web Browser). +We will need to fill in the executable name in the Command: field, in this instance we will type firefox. +The command has to be in your PATH variable or you have to specify the full path to the executable. +If you do not know the executable name of an application use the locate +command to search for the desktop file and enter the string from the Exec line as command here. + +Following the command, you can have several place holders which will be replaced with actual values when the program is run: + +%f - a single file name +%F - a list of files; use for applications that can open several local files at once +%u - a single &URL; +%U - a list of &URL;s +%d - the folder of a file to open +%D - a list of folders +%i - the icon +%m - the mini icon +%c - the caption + +For example: if you want to firefox to start your web browsing at www.kde.org - instead of firefox you would type firefox %u www.kde.org. +Most applications accept additional options ⪚ the name of a defined profile like &konqueror; or &konsole;. +To see all options for an application launch applicationname in &konsole;. +We would like to have a more creative icon, so we will click the generic icon sitting beside Name: (note, the default icon may be blank, in which case click in the area to the right of the name entry box.) It will bring the Select Icon dialog which will let us choose the new icon, as shown below. + +Select Icon dialog + + + + + +The Select Icon dialog. + + + + + We choose the firefox icon from the list, and press &Enter;. Your finished screen should probably look something like the screenshot below. + +Done screenshot + + + + + +This is what the completed menu item should looks like. + + + + +The place of the new menu item can now be changed using Move Up and Move Down buttons on the &kmenuedit; toolbar or by dragging with the mouse. + The submenu items can be sorted using Sort button on the &kmenuedit; toolbar or EditSort submenu items. + +Click FileSave, wait for the Updating System Configuration dialog to get finished, you should find &firefox; in the application launcher Internet submenu. + + + + +Using &kmenuedit; + +The left application panel shows the application launcher structure. When +you browse items in the left panel, the right panel shows detailed +information for the highlighted menu item. + + +General tab + + + +Name: +This is the name of your program as it appears in the +application launcher menu. It can be different from the real executable +name. For instance the name of mc executable is +"Midnight Commander". + + +Description: +The description will be displayed together with the name in the application launcher. This is entirely optional. + + +Comment: +Describe the program in greater detail in this field. This is +entirely optional. + + +Command: +This is the name of the executable program. Make sure that you +have permission to run the program. + + +Enable launch feedback +If this box is checked, this will display feedback when an application is started. + + + +Place in system tray +When checked, the application's icon will show up in the panel system tray. +You will then be able to hide or show the application by clicking on the system +tray icon. Clicking on it using the &RMB; will allow also you to undock, or quit the +application. + + + +Only show in &kde; +When checked, the application entry will only be visible in all &kde; application launchers but not in other desktops environments. + + + +Hidden entry +Remove an entry from the menu view in the application launcher. + + + + + +Advanced tab + + + +Work path: +Specify the work path of the program. This will be the current +path when the program launches. It does not need to be the same as the +executable location. + + +Run in terminal +You must check this if your program requires terminal emulator +in order to run. This mainly applies to console +applications. + + +Terminal options: +Put all terminal options in this field. + + +Run as a different user +If you want to run this program as a different user (not you), +check this checkbox, and provide the username in the +Username: field. + + + +Current shortcut key: +You can assign a special keyboard shortcut to launch your program. + +Click the None button to the right of the Current +shortcut key: checkbox. + +The button text will change to Input... +and you can press the key combination on your keyboard that you want to be assigned to your program. + +You can reset the shortcut to None by using this button: . + + +Don't forget to save your setting by clicking the toolbar Save icon or using the +FileSave + menu item. + + + + + + + + + +Menu Reference + +Most actions in the menubar are also available in the context menu opened with a &RMB; +click on an item in the tree view. + + + + +&Ctrl;N +File New Item... + Adds new menu +item. + + + + +File +New Submenu... + +Adds new submenu. + + + +FileNew +Separator + +Adds a new separator to the menu. + + + + + +&Ctrl;S +FileSave + + +Saves the menu + + + + + + +&Ctrl;Q + +File +Quit + +Quits &kmenuedit;. + + + + +Edit +Move Up + +Moves the selected item up in its submenu. + + + + +Edit +Move Down + +Moves the selected item down in its submenu. + + + + + + +&Ctrl;X + + +Edit Cut + +Cuts the current menu item to the clipboard. If +you want to move menu item, you should first cut it to the clipboard, move to +the destination place using the left panel, and use the +Paste function to paste the menu item from the +clipboard. + + + + + +&Ctrl;C + + +Edit Copy + +Copies the current menu item to the +clipboard. You can later use the Paste +function to paste the copied menu item from the clipboard to its destination. You +can paste the same item many times. + + + + + +&Ctrl;V + +Edit +Paste +Paste menu item from the clipboard to currently +selected place in the main menu. You must first use +Cut or Copy before you can +Paste. + + + + +Del +Edit Delete + +Deletes currently selected menu +item. + + + + +Edit +Sort + +Opens submenu to sort selected submenu or all menu tree. There are two sorting methods implemented, namely, by the name and by the description. + + + + +Edit Restore to System Menu + +This will restore the application launcher as it was as default and remove all your custom settings. A message box will ask you if you really want to do that. + + + + + +&kmenuedit; has the common &kde; Settings and Help +menu items, for more information read the sections about the Settings Menu and Help Menu +of the &kde; Fundamentals. + + + + + + +Credits and License + + +&kmenuedit; + +Program copyright © 2002, &Raffaele.Sandrini; + +Contributors: + +&Matthias.Elter; &Matthias.Elter.mail; - Original +Author + +&Matthias.Ettrich; &Matthias.Ettrich.mail; + +&Daniel.M.Duley; &Daniel.M.Duley.mail; + +&Preston.Brown; &Preston.Brown.mail; + + + +Documentation copyright © 2000 &Milos.Prudek; +Documentation copyright © 2008 &Anne-Marie.Mahfouf; +Updated for &kde; 3.0 by &Lauri.Watts; &Lauri.Watts.mail; +2002 + + + +&underFDL; +&underGPL; + + + + +Glossary + + +Console Application + + +Application originally written for non-graphic, text oriented +environment. Such applications run fine in &kde;. They must run within +console emulator, like &konsole;. They are not warned automatically +when you shut down your &kde; session. You therefore must not forget +to save documents open in these applications before you log out from +the &kde;. + +Console applications support copying and pasting from +&kde;-compliant applications.Simply mark the text in the console +application with your mouse, switch to the &kde;-compliant application +and press &Ctrl; +V to paste the text. If you want to copy +from &kde; application to a console application, first mark the text +with your mouse, press &Ctrl; +C, switch to the console application and +press the middle button on your mouseIf your mouse +does not have a middle button, you must press +left and right +button at the same time. This is called middle button +emulation and it must be supported by your operating system to +work.. + + + + + + +&documentation.index; + + + + diff --git a/doc/kmenuedit/itemname.png b/doc/kmenuedit/itemname.png new file mode 100644 index 00000000..5d0abffa Binary files /dev/null and b/doc/kmenuedit/itemname.png differ diff --git a/doc/kmenuedit/new.png b/doc/kmenuedit/new.png new file mode 100644 index 00000000..6ebf25cd Binary files /dev/null and b/doc/kmenuedit/new.png differ diff --git a/doc/kmenuedit/reset.png b/doc/kmenuedit/reset.png new file mode 100644 index 00000000..02a20bd0 Binary files /dev/null and b/doc/kmenuedit/reset.png differ diff --git a/doc/kmenuedit/selecticon.png b/doc/kmenuedit/selecticon.png new file mode 100644 index 00000000..518f16e8 Binary files /dev/null and b/doc/kmenuedit/selecticon.png differ diff --git a/doc/kmenuedit/selectinternet.png b/doc/kmenuedit/selectinternet.png new file mode 100644 index 00000000..45ce5fdf Binary files /dev/null and b/doc/kmenuedit/selectinternet.png differ diff --git a/doc/ksysguard/CMakeLists.txt b/doc/ksysguard/CMakeLists.txt new file mode 100644 index 00000000..0df9c9ad --- /dev/null +++ b/doc/ksysguard/CMakeLists.txt @@ -0,0 +1,4 @@ +########### install files ############### +# +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) diff --git a/doc/ksysguard/index.docbook b/doc/ksysguard/index.docbook new file mode 100644 index 00000000..1f30bc67 --- /dev/null +++ b/doc/ksysguard/index.docbook @@ -0,0 +1,533 @@ + + + + + +]> + + + +The &ksysguard; Handbook + + + +&Chris.Schlaeger;&Chris.Schlaeger.mail; + + + +&John.Tapsell; &John.Tapsell.mail; + + + + +&Chris.Schlaeger;&Chris.Schlaeger.mail; + + + + +&Tobias.Koenig;&Tobias.Koenig.mail; + + + + + + + +2000 +&Chris.Schlaeger; + + +&FDLNotice; + +2010-10-24 +&kde; 4.5 + +&ksysguard; is a network enabled task and system monitor +application. + + +KDE +KSysGuard +process monitor +performance monitor +system monitor +top +ps + + + + +Introduction + +&ksysguard; is the &kde; Task and Performance Monitor. + + +It features +a client/server architecture that allows monitoring of local as well as remote +hosts. The graphical front end uses so-called sensors to retrieve the +information it displays. A sensor can return simple values or more complex +information like tables. For each type of information, one or more displays are +provided. Displays are organized in worksheets that can be saved and loaded +independently from each other. So, &ksysguard; is not only a simple task manager +but also a very powerful tool to control large server farms. + + + + +Using &ksysguard; + + +Getting started + +&ksysguard; can be started from the application launcher menu, using the entry +System Monitor in the +ApplicationsSystem menu. Alternatively, you +can start it by typing ksysguard in a terminal. + +The &ksysguard; main window consists of a menu bar, an optional tool bar +and status bar, and the work space. Custom worksheets will also show the sensor +browser. + + + +By default &ksysguard; shows two worksheets: Process Table +and System Load. The Process Table +lists the running processes and lets the user control them. +Multiple processes can be selected and controlled at once. +The System Load worksheet shows graphs of system utilization: +CPU History, Memory and Swap History, +and the Network History. + + +This default setup is sufficient enough for an inexperienced user to do +some system management. An experienced user or even a system administrator of a +large computer lab has different needs. To address a wide range of users, +&ksysguard; +is highly flexible. + + + +Process Table + +The Process Table gives you a list of processes on your +system. The list can be sorted by each column. Just press the left +mouse button at the head of the column. + +Use the What's This help for the columns titles +to get additional information about the value displayed here. + +In the context menu of a process in the list view you find additional actions +like changing the priority, sending signals to the process, switching to the +application window, showing detailed memory information and killing the process. + +The list shows the following information about each process. Please note +that not all properties are available on every operating system. + + +Default Columns in the Process Table + + + +Name +The name of the executable that started the process + + +Username +The user who owns this process + + +CPU % +The current total CPU usage of the process, divided by the number of +processor cores in the machine + + +Memory +This is the amount of real physical memory that this process is using by +itself, and approximates the Private memory usage of the process. +It does not include any swapped out memory, nor the code size of its shared +libraries. +This is often the most useful figure to judge the memory use +of a program. + + +Shared Mem +This is approximately the amount of real physical memory that this +process's shared libraries are using. This memory is shared among all +processes that use this library + + + +
+ + +Additional Columns in the Process Table + + + +PID +The unique Process ID that identifies this process + + +TTY +The controlling terminal on which this process is running + + +Niceness +The priority with which this process is being run. For the normal scheduler, +this ranges from 19 (very nice, least priority) to -19 (top priority) + + +CPU Time +The total user and system time that this process has been running for, +displayed as minutes:seconds + + +IO Read +The number of bytes read. The Display Units +and the Displayed Information can be changed using +the context menu of this column header + + +IO Write +The number of bytes written. The Display Units +and the Displayed Information can be changed using +the context menu of this column header + + +Virtual Size +This is the amount of virtual memory space that the process is using, +included shared libraries, graphics memory, files on disk, and so on. This +number is almost meaningless. Use the context menu to select the +Display Units + + +Command +The command with which this process was launched + + + +
+ +At the top of the table you find three controls which will be described now +from left to right. + + +End Processes + +If you have selected one or more processes you can press the End +Process button to kill them. A so called SIGKILL +is sent to the processes which causes them to terminate immediately. +If these applications still have unsaved data this data +will be lost. So use this button with care. + + + +Filter Bar + +Filter which processes are shown by the text given here. The text can be a +partial string match of the Name, Command +or Window Title of the process. +It can also be a Username or a Process ID number. + + + + +Process Filter + +The Process Filter can be used to reduce the number of processes displayed +in the table. You can filter out processes you are not interested in. Currently +you can display All Processes in a flat or tree view, System +Processes only, User Processes only, your +Own Processes only or Programs Only. + +The tree view has been designed to show the relationships between the +running processes. A process that is started by another process is called the +child of that process. A tree is an elegant way to show this parent-child +relationship. The init process is the ancestor of all +processes. + +If you are not interested in the children of a particular process you can +click on the little box to the left of the parent and the subtree will +collapse. Another click on that box will unfold the subtree again. + +You can launch the Process Table from &krunner; +using the Show System Activities button or using +the global shortcut &Ctrl;&Esc; at any time. +The process table is displayed in a window titled System Activities. + + + +
+ + +Work Space + +The work space is organized as worksheets. Select +New Tab... from the File menu to create a +new worksheet. A dialog will appear where you can set the name, the +dimension and the update interval of the worksheet. To remove a worksheet +again, select +Close Tab from the File menu. Any +modifications will be saved to the worksheet file. If a worksheet has +never been saved, you will be asked for a file name. Worksheets consist of +cells +organized as a grid. + +Each cell can be filled with a display for one or more sensors. You can +fill a cell by dragging a sensor from the sensor browser and dropping it over +the cell. If there is more than one type of display available for that type +of sensor, a popup menu will appear. You can then select which display you +prefer to use. Certain types of displays can display more than one sensor. Add more +sensors to a display by dragging them over from the sensor browser and dropping +them over the already existing display. + +Worksheets can be configured by clicking Tab Properties +at the View menu. In the appearing dialog +you can set the dimension and the update interval. + + +Displays can be configured by clicking with the right mouse button on +them. A popup menu appear where you can select whether you want to change the +properties of that display or remove it from the worksheet. + + +Sensor Browser +The sensor browser exposes &ksysguard;'s advanced functionality. To +use it, you must first go to the File menu and create a new worksheet. +It is shown whenever a custom worksheet is selected. +The sensor browser displays the registered hosts and their sensors in a +tree form. Click on the tree handles to open or close a branch. Each sensor +monitors a certain system value. +After you have configured your custom worksheet use the splitter and move +it to the right edge of the window to hide the sensor browser. +If the sensor browser does not appear on a custom worksheet, it is +probably hidden. To unhide it, select the right edge of the window and +drag it to the left. + + + +Line Graph + +The line graph prints samples of one or more sensors over time. If, +several sensors are displayed, the values are piled in different colors. If +the display is large enough a grid will be displayed to show the range of the +plotted samples. By default, the automatic range mode is active so the minimum +and maximum values will be set automatically. Sometimes you want fixed +minimum and maximum values. In that case, you can deactivate automatic range +mode and set the values in the properties dialog. + + + +Digital Display + +The multimeter displays the sensor values as a digital meter. In the +properties dialog you can specify a lower and upper limit. If the range +is exceeded, the display is colored in the alarm color. + + + +Bar Graph + +The bar graph displays the sensor values as dancing bars. In the +properties dialog you can specify minimum and maximum values of range and +a lower and upper limit. If the range is exceeded, the display is +colored in the alarm color. + + + +Log to a File + +The sensor logger does not display any values, but logs them in +a file with additional date and time information. For each sensor +you can specify a lower and upper limit in the properties dialog. +If the range is exceeded, the entry of the sensor table is colored in +the alarm color. + + + +Partition Table + +The Partition Usage has a special table +sensor showing information about all mounted partitions + + + +Connecting to other hosts + +To connect to a new host use Monitor Remote Machine... +from the File menu. A dialog box will appear and allows you +to enter the name of the host you want to connect to. Below the name you can choose +the connection method. The default is ssh, the secure +shell. Alternatively the rsh, the remote shell, +the daemon mode or a custom command can be used. Click OK to +establish the connection. Shortly afterwards the new host will appear in the +sensor browser and you can browse the list of sensors. + + + +To establish a connection, a program called +ksysguardd, that can be started in the following +two modes, must be installed on the new host. + + + +daemon mode + +You can start ksysguardd at boot time in +Daemon mode by adding -d as the +argument. In this case, you have to select daemon mode at the connection +dialog of ksysguard. +A disadvantage of this connection type is that you won't be able to kill or +renice a process in the Process Table and +the data exchange over network won't be encrypted. As a result, daemon +mode is not recommended. + + + +shell mode + +In this mode ksysguardd is started at +connecting time by ksysguard. To make that possible, +its location needs to be included in your PATH. +Unfortunately the ssh does not source your .profile file, +so your regular PATH setting will not be available. +Instead it uses a default PATH like +/bin:/usr/bin. +Since it is very likely that &kde; is not installed in these folders you need +to create or update a file in your home folder. The file is called +environment and needs to be in a hidden folder called +.ssh. See the manual page for +ssh for more details. The file needs to contain a +line similar to: + + +PATH=/bin:/usr/bin:/opt/kde/bin + + +assuming that ksysguardd can be found under +/opt/kde/bin/ksysguardd. + +When using ssh you should make sure that +you have your identity.pub installed on the remote machine +and the host key of the remote machine is already registered on your machine. +If you don't set up identity.pub correctly, you will be asked +for your password every time you start ksysguard. +The easiest way to make sure that everything is working is to run ssh in a shell. If you are greeted by +ksysguardd, then everything is working correctly +and you can type quit to exit ksysguardd. + + + + +For experts: ksysguardd is a +very small program that is only linked against the libc. So it can +also be used on machines that do not have a full blown &kde; +installed, such as servers. Many major distributions provide a separate +ksysguardd package for your convenience. +If you choose the custom command option in +the host connector you need to specify the complete command to start +ksysguardd. + + + + + + +
+ + +Configuring <application>ksysguardd</application> + +The graphical front-end is available on any platform that &kde; runs +on. The back-end is at the moment available on the following flavors of +&UNIX;: + + + +&Linux; 2.x + For ksysguardd to work it +is necessary to compile the &Linux; Kernel +with the /proc File system enabled. This is the default +setting and most &Linux; Distributions have it already. + + +FreeBSD +The ksysguardd program +needs to be owned by the kmem group and needs to have the setgid +bit set. + + +&Solaris; +To be written + + + +Support for other platforms is in progress. Your help is greatly +appreciated. + + + +Credits and License + +&ksysguard; is currently developed and maintained by &John.Tapsell; +&John.Tapsell.mail;. &ksysguard; is a rewrite of +KTop, the &kde; 1.x task manager. Several other people +have worked on KTop: + + + A. Sanda alex@darkstar.ping.at + Ralf Mueller ralf@bj-ig.de + &Bernd.Johannes.Wuebben; +wuebben@math.cornell.edu + Nicolas Leclercq +nicknet@planete.net + + +The porting to other platforms than &Linux; was done by: + + + FreeBSD: Hans Petter Bieker +zerium@traad.lavvu.no + + + +&underFDL; +&underGPL; + + + +
+ + diff --git a/doc/plasma-desktop/CMakeLists.txt b/doc/plasma-desktop/CMakeLists.txt new file mode 100644 index 00000000..1d646fe0 --- /dev/null +++ b/doc/plasma-desktop/CMakeLists.txt @@ -0,0 +1,5 @@ +########### install files ############### +# +# +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) + diff --git a/doc/plasma-desktop/add-widgets.png b/doc/plasma-desktop/add-widgets.png new file mode 100644 index 00000000..7c062760 Binary files /dev/null and b/doc/plasma-desktop/add-widgets.png differ diff --git a/doc/plasma-desktop/desktop-settings.png b/doc/plasma-desktop/desktop-settings.png new file mode 100644 index 00000000..03732de5 Binary files /dev/null and b/doc/plasma-desktop/desktop-settings.png differ diff --git a/doc/plasma-desktop/device_notifier_widget.png b/doc/plasma-desktop/device_notifier_widget.png new file mode 100644 index 00000000..34d916da Binary files /dev/null and b/doc/plasma-desktop/device_notifier_widget.png differ diff --git a/doc/plasma-desktop/device_notifier_widget_actions.png b/doc/plasma-desktop/device_notifier_widget_actions.png new file mode 100644 index 00000000..d00a7a2e Binary files /dev/null and b/doc/plasma-desktop/device_notifier_widget_actions.png differ diff --git a/doc/plasma-desktop/index.docbook b/doc/plasma-desktop/index.docbook new file mode 100644 index 00000000..786dda27 --- /dev/null +++ b/doc/plasma-desktop/index.docbook @@ -0,0 +1,642 @@ + + + + + +]> + + + +The &plasma; Handbook + + + + +Sebastian +Kügler + +sebas@kde.org + +Claus Christensen + + + + +2008–2010 +Sebastian Kügler + + +&FDLNotice; + +2013-06-19 +&kde; 4.11 + + + +&plasma;, the most visible pillar of &kde;, is the core interface to the desktop. + + + + +KDE +Plasma +Plasmoid +Widget +Containments +Desktop +Runner +Kicker + + + + + +Introduction + + +&plasma; is one of the key technologies of &kde; Software Compilation 4 (also known as the +“Pillars of &kde;”), and one of the most visible to users. As &plasma; +treats the user interface differently than a traditional desktop, there may be +confusion on what &plasma; is, what it does, and how to perform common tasks. + + + +This document attempts to address these problems by providing answers to the +most common questions. + + + + +Using &plasma; + + +&plasma; Components + + +&plasma; Widgets and Containments + + +The essence of &plasma; revolves around two basic concepts: + + + + +&plasma; Widgets + + +Applets, or small applications that live on the desktop. + + + + +Containments + + +Applets that act as the container for the &plasma; widgets + + + + + + +On a default desktop, there are two main elements: the Panel and the Desktop +itself. Both are containments in the &plasma; sense. + + + + + +Default &plasma; Desktop + +The &plasma; Desktop can be configured in countless ways. The screenshot seen below shows a fairly standard desktop. Some distributions apply extensive customizations, so your desktop may look different. + +Similarly, the graphical appearance of the interface elements can be styled. These screenshots uses the &kde; default style, Oxygen. + + + +A fairly standard &plasma; Desktop + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The program starter. Usually this will be &kickoff;. +A couple of icons giving easy access to often used applications +The Pager widget +The Task Manager, which shows the titles of windows belonging to the applications currently running. No application had opened a window, when the screenshot was taken +The System Tray +The Digital Clock widget +The Panel Toolbox +The Desktop Toolbox (previously known as a Cashew) +A Folder View widget, showing the content of the Desktop folder + + + + + + +The Panel + + +The default panel holds a few &plasma; widgets: starting from the left, there is the +&kickoff; application launcher. You can use it to start applications, open recently +opened files and the usual logout/shutdown options. There is also a structure +that allows you to browse through your applications. The layout has been +optimized for the use case that is most common: starting an application. The +default tab is the Favorites tab that holds the most-used +entries. In the beginning, you'll probably find yourself using the +Applications tab more often. +Once you have found out what your most frequently started applications are, +right click on the items and select the +Add to Favorites to add them to your +Favorites (or directly into the panel or on the desktop. +Note that you need to unlock &plasma; by means of right +clicking on the desktop for any kind of modification). If you prefer the +traditional menu-style application launcher, change it by +right clicking on the menu button and selecting +Switch to Classic Menu Style. + + + +The taskbar is another widget on the panel. It shows an area for all open windows on +all desktops by default. You can make it show all open windows on the current +desktop only by checking Only show tasks from the +current desktop when you right click on the task manager, between +two windows. The size of the text on the taskbar items can be set +in &systemsettings; under the +Application AppearanceFonts +Taskbar. Right-clicking on the taskbar +brings the Settings dialog where you can choose several options to customize +your taskbar. + +Here is a screenshot of the taskbar settings dialog + + + + + + Taskbar settings dialog + + + + + + +Another default panel item is the System Tray, which +is used by traditional applications and widgets as a dock. Right clicking on the +System Tray allows you to open the settings dialog, +where you can set entries to display and their visibility. + + +System Tray settings dialog + + + + + + System Tray settings dialog + + + + +An icon located usually in the system tray is the Device Notifier. +Plug in a USB disk and a dialog will open that allows you to +open the device in &dolphin; or another associated application. + + + + + + + + + + + + + + +The Device Notifier is used for handling pluggable devices such as USB pendrives (also called flash drives or thumb drives), digital cameras, external USB hard drives, &etc; It also comes into play when a medium such as a &CD; or DVD is loaded into an optical drive. + +When you plug in an external device, or load a new medium into a drive, the Notifier window pops up (you can also open it explicitly by clicking on its Panel icon.) It stays open while the cursor is over it, otherwise it hides itself after a few seconds. + +The Notifier window shows a list of all the devices it currently knows about. Moving the mouse cursor over a device will highlight how many possible actions are associated with that device. + + + + + + + + + + + + + + +Clicking anywhere in the shaded box around the device name (but not on the eject/unmount icon if present) expands the entry to show the list of possible actions for that device. The set of actions depends on the device; it is configurable from the Device Notifier's context menu or from the &systemsettings; modules Device Actions and Removable Devices. Simply select one with the mouse or keyboard to launch that action. + +There is also a small icon to the right of each entry showing whether that device is currently accessible (or mounted) or not. Only when a device is not mounted is it safe to physically disconnect it from the computer. Clicking on the icon causes the device to be unmounted and/or the medium to be ejected if it is currently mounted, and will mount it if it is not. Note that unmounting/ejecting might fail if the device still has open files on it, ⪚ if a large file copy hasn't finished. In most cases you can just wait a while and try again. When an unmounting has succeeded, a success icon will be shown on the Device Notifier's icon. + + +The System Tray normally holds some more entries like +&klipper;, &kmix; &etc; + +Some of the default entries in the System Tray are hidden +to save space in the bar. To display these entries click on the small white triangle + +, then use +the &LMB; to launch a widget or the &RMB; to open its settings dialog. + + +The right-most &plasma; widget in the default panel holds the Digital +Clock. +This clock can display the time in different timezones as well as have its size +changed. The clock will adjust its font size to the area it is given by the +surrounding containment (that is the panel in this case). If you choose to +display the date, this date will be rendered using the Small +font option from the &systemsettings; Font +dialog. The time will take the rest of the space. So in the end, you'll choose +yourself the amount of information displayed, and if that fits. If you want to +display more information, make the panel larger or put the clock on the desktop +where it can grow freely. + + + +An optional item on your panel is the Pager. +It allows you to switch between your virtual desktops. +If you change the layout of the Pager +through the Number of rows option, +which will also affect the layout and animations that are shown in &kwin;’s +Desktop Grid effect. +For larger pagers, selecting Display windows icons +typically makes sense. + + + + + + + + + + +The Panel Toolboxes + +If your desktop is unlocked (you can do that by +right clicking on the desktop, or when no +application has the focus, with &Alt;D, L), a small &plasma; +logo will appear in the bottom right corner in the panel (it is commonly named the +“cashew”). Click on this cashew, and the panel controller opens. + + +Panel Settings + + + + + + Panel Settings + + + + +The panel controller allows you to reposition, resize and realign the panel. The +&plasma; widgets living in this panel will adjust their size automatically. +&plasma; widgets have basic knowledge about sizing, provided by the containment. They +are programmed to take advantage of that size, and inform the applet about how +much space they possibly need. In the end, the containment gives a possible size +to the applets, the applets obey. + + + + +Adding Applets + + +Unlock the desktop and you'll be able to add and remove &plasma; widgets from panel +or desktop. You add &plasma; widgets by simply dragging them where you want them. +Right click on an widget to remove it. + + +Add Widgets + + + + + + Add Widgets + + + + +The Get New Widgets button allows you to add widgets +you've previously downloaded and download new &plasma; widgets. +Currently it supports native &plasmagik; packages +and some &Mac; OS X dashboard widgets. Widgets you install this way can then be +accessed just like regular, preinstalled widgets. + + + + +The Desktop + + +The desktop is in fact another containment. One that does not put size +constraints on the applets. Applets can be moved and sized freely. On the +unlocked desktop, &plasma; widgets will show a frame when you move the mouse over +them. This applet handle allows you to move, resize, relocate and realign the +panel. It also allows you to drag &plasma; widgets on the desktop. The buttons in the +corner are used to resize, rotate configure and remove the applet. When +rotated, a &plasma; widget will act magnetic towards 12 o'clock, so it is easy to get +them back into sensible position. By default, most applets keep their aspect +ratio when they are being resized. If you want to freely resize an applet, +hold the &Ctrl; key pressed while resizing. + + + +Right clicking on the desktop also offers you to configure aspects such as the +wallpaper and the layout used, and the mouse actions. It offers to download new +wallpapers through &knewstuff;. + + + +Desktop Settings + + + + + + Desktop Settings + + + + +To change the &plasma; theme or download a new one through &knewstuff; +open the Workspace Appearance Desktop +Theme page in the &systemsettings;. + + +With open applications, it quickly gets hard to see the &plasma; widgets on your +desktop. The Dashboard gets those &plasma; widgets +in front of you, much like the Show desktop functionality +you are used to from traditional desktops. + + + + + +&krunner; + + +&krunner; is a versatile mini command-line. You can use it to start applications, +open web pages, access bookmarks, search through your desktop data, calculate +short equations, and many more.Pressing &Alt;F2 opens the &krunner; dialog. +You just start typing and &krunner; will start searching matches as soon as +you've entered more than two characters. You can open the settings dialog to +learn about &krunner;’s functionality, provided by plugins. You can +navigate through the matches using the tab and arrow keys. + + + +If you want to know what is going on on your system, there is the Show +System Activity button, giving you quick access to a list of windows +and processes, with options to monitor their output and kill processes. + + + + + +Activities + + +The desktop toolbox, accessed via the upper right corner has a button for +displaying your activities, of which &plasma; allows you to have more than one. +Basically, that is multiple desktop containments hosting multiple sets of &plasma; widgets. +Display the Activities bar, select one of the predefined activities +or choose Create Activity +to create a new containment, select your new containment and customize suiting your taste. +&plasma;’s activities and &kwin;’s desktop grid are similar in that respect, but there +is a fundamental difference. While virtual desktop are used to group and organize windows, +&plasma;’s activities are used to group and organize &plasma; widgets. This way, you can +switch between activities and have relevant &plasma; widgets supporting the task you are +currently trying to accomplish. You can create a Free time activity, with +comic strips, a puzzle and other &plasma; widgets, and a Work activity, +with relevant RSS feeds, calculator and calendar, for example. + + + +To delete an activity, press the Stop Activity button on +Activities bar (press &Alt;D then &Alt;A to open this bar) then click +the red 'X' (or press &Alt;D +then &Alt;R) and confirm the +deletion. + + + + + + +Shortcuts + + +Most of &plasma;’s functionality is also accessible through keyboard +shortcuts. The various combinations should be pressed in sequence, that +is for example &Alt;D, A +means: Press &Alt; and D, release and press A. + +Currently, the following default shortcuts can be used: + + + + +&Alt;D, A +Add Widgets + + + +&Alt;D, R +Remove Widget + + + +&Alt;D, L +Lock/Unlock Widgets + + + + +&Alt;D, N +Next Widget + + + +&Alt;D, P +Previous Widget + + + +&Alt;D, S +Widget settings + + + +&Alt;D, &Alt;A +Activities + + + +&Alt;D, &Alt;R +Remove this Activity + + + +&Alt;D, &Alt;S +Activities Settings + + + +Meta +Next Activity + + + +Meta&Shift; +Previous Activity + + + +&Ctrl;F12 +Show Dashboard + + + +&Alt;D, T +Run the Associated Application + + + + + +To change shortcuts, click with the &LMB; on the desktop Toolbox +(the cashew usually at the top right of the desktop) and select Shortcut Settings. + + + + + + +Credits and License + + +&plasma; + + +Program copyright 2008 &Aaron.J.Seigo; &Aaron.J.Seigo.mail; + + + +Documentation Copyright © 2008–2010 Sebastian Kügler sebas@kde.org + + + + +&underFDL; + + + +&documentation.index; + + + diff --git a/doc/plasma-desktop/panel-settings.png b/doc/plasma-desktop/panel-settings.png new file mode 100644 index 00000000..49fe1dc4 Binary files /dev/null and b/doc/plasma-desktop/panel-settings.png differ diff --git a/doc/plasma-desktop/plasma-desktop-annotated.png b/doc/plasma-desktop/plasma-desktop-annotated.png new file mode 100644 index 00000000..8ab73438 Binary files /dev/null and b/doc/plasma-desktop/plasma-desktop-annotated.png differ diff --git a/doc/plasma-desktop/system-tray-settings.png b/doc/plasma-desktop/system-tray-settings.png new file mode 100644 index 00000000..e3ff1c3a Binary files /dev/null and b/doc/plasma-desktop/system-tray-settings.png differ diff --git a/doc/plasma-desktop/system-tray-up-arrow.png b/doc/plasma-desktop/system-tray-up-arrow.png new file mode 100644 index 00000000..6de1abb9 Binary files /dev/null and b/doc/plasma-desktop/system-tray-up-arrow.png differ diff --git a/doc/plasma-desktop/taskbar-settings.png b/doc/plasma-desktop/taskbar-settings.png new file mode 100644 index 00000000..47c61e97 Binary files /dev/null and b/doc/plasma-desktop/taskbar-settings.png differ diff --git a/doc/systemsettings/CMakeLists.txt b/doc/systemsettings/CMakeLists.txt new file mode 100644 index 00000000..2757f627 --- /dev/null +++ b/doc/systemsettings/CMakeLists.txt @@ -0,0 +1,4 @@ +##### Install Systems Settings Documentation ##### +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en) + +##### Install System Settings Modules Documentation ##### diff --git a/doc/systemsettings/index.docbook b/doc/systemsettings/index.docbook new file mode 100644 index 00000000..5feb5d2b --- /dev/null +++ b/doc/systemsettings/index.docbook @@ -0,0 +1,473 @@ + + + + + +]> + + + +The &systemsettings; Handbook + + + +&Richard.Johnson; +&Richard.Johnson.mail; + + + + + +2007 +&Richard.Johnson; + +&FDLNotice; + +2013-12-05 +4.12 (&kde; 4.12) + + + +This documentation describes &kde;'s system configuration and administration center. + + + + +KDE +System +Settings +configuration +administration +config +admin + + + + + +Introduction + + +The &kde; &systemsettings; provides the user with a centralized and convenient way to configure all of the &kde; settings. + + + +&systemsettings; is made up of multiple modules. Each module is a separate application, however the &kde; &systemsettings; organizes all of these applications into a single location. + + + + +Each &systemsettings; module can be executed individually + + +See section entitled Running +individual &systemsettings; modules for more information. + + + + +&systemsettings; groups all of the configuration modules into several categories: + +Common Appearance and Behavior +Workspace Appearance and Behavior +Network and Connectivity +Hardware +System Administration + + + + +The modules that make up &systemsettings; fall under one of the above categories, making it easier to locate the correct configuration module. + + + + + +Using &systemsettings; + + +This section details the use of &systemsettings; itself. For information on each individual module, please see &systemsettings; Modules. + + + +Starting &systemsettings; + + +The &kde; &systemsettings; can be started in one of three ways: + + + + + +By selecting K ButtonApplicationsSystem Settings. + + + + + By pressing &Alt;F2. This will bring up the &krunner; dialog. Type systemsettings, and press &Enter;. + + + + +Type systemsettings & at any command prompt. + + + + + +All three of these methods are equivalent, and produce the same result. + + + + +The &kde; &systemsettings; Screen + + +When you start &systemsettings;, you are presented with a window, which is divided into three functional parts. + + + +Across the top is a toolbar. The toolbar provides the user with the ability to go back into the main view from within a module using the Overview. +You can also find a Help menu as well as a Configure button which provides you a dialog with alternate view settings. + +To search for something within all of the modules, start to type keywords into the search field at the right of the toolbar in the Overview. When you start typing, a list of matching topics will popup. Select one and only the groups with settings for this keyword are enabled, the other are greyed out. +When the icon window has the focus, you can type the first letter of +any module or module group name to select it. Typing this letter again the +selection moves to the next match. + + +Underneath the toolbar is an icon view of the individual modules or module groups that +make up &systemsettings; grouped by different categories. By default, +if your mouse stays a few seconds over an icon, a detailed tooltip +appears, explaining the purpose of the module or the modules in this group. + + + + +&systemsettings; Categories and Modules +A brief overview of all categories and their modules: + + + +Common Appearance and Behavior + + + +Account Details (Password & User Account, Paths, KDE Wallet, Social Desktop, Web Shortcuts) + + +Application Appearance (Style, Colors, Icons, Fonts, Emoticons) + + +Application and System Notifications (Manage Notifications, System Bell, Launch Feedback) + + +File Associations + + +Locale (Country/Region & Language, Spell Checker) + + +Personal Information (Akonadi Resources Configuration) + + +Shortcuts and Gestures (Custom Shortcuts, Standard Keyboard Shortcuts, Global Keyboard Shortcuts) + + + + + + + +Workspace Appearance and Behavior + + + +Desktop Effects + + +Workspace Appearance (Window Decorations, Cursor Theme, Desktop Theme, Splash Screen) + + +Accessibility (Accessibility, Text-to-Speech) + + +Default Applications + + +Desktop Search + + +Window Behavior (Task Switcher, Window Behavior, KWin Scripts, Window Rules) + + +Workspace Behavior (Activities, Virtual Desktops, Screen Edges, Workspace) + + + + + + + +Network and Connectivity + + + +Network Settings (Proxy, Connection Preferences, Service Discovery) + + +Sharing (Windows Shares) + + +SSL Preferences + + + + + + + +Hardware + + + +Device Actions + + +Digital Camera + + +Display and Monitor (Size & Orientation, Screen Locker, Gamma) + + +Input Devices (Keyboard, Mouse, Joystick, Remote Controls) + + +Power Management (Energy Savings Settings, Activity Settings, Advanced Settings) + + +Printers + + +Removable Devices + + +Multimedia (Audio CDs, Audio and Video Settings, CDDB Retrieval) + + + + + + + +System Administration + + + +Date & Time + + +Font Management + + +Login Screen + + +Startup and Shutdown (Autostart, Service Manager, Session Management) + + +Task Scheduler + + + + + + + + +Use the search field in Overview to find all matching modules for a given keyword. + + +Exiting the &kde; &systemsettings; + + +&systemsettings; can be exited in one of two ways: + + + + + +Press &Ctrl;Q on the keyboard. + + + + +Click on the Close button located in the toolbar. + + + + + + +Configuring &systemsettings; + + +The Configure icon in the toolbar allows you to change some &systemsettings; parameters. +You can change from Icon View (default view) to Classic Tree View. + + + +You can also turn off the detailed tooltips by unchecking Show detailed tooltips. +You will then get only normal tooltips and not the content of a module group. + + + + +Running Individual &systemsettings; Modules + + +Individual modules can be run without running &systemsettings; using the command kcmshell4 from the command line. Type kcmshell4 --list to see a list of the available &kde; &systemsettings; modules. + + + + + + +The &kde; &systemsettings; Modules + + +In order to make it as easy as possible, the &kde; &systemsettings; has organized options into five categories. Under each category, there are icons grouped together under subcategories. Each icon is called a module. When you double click on a module icon, you will be presented with the options of the module in the main window. + + + +Each module will have some or all of the following buttons: + + + + +Help + + +This button will provide help specific to the current module. Clicking the button will open &khelpcenter; in a new window providing detailed information on the module. + + + + + +Defaults + + +Clicking this button will restore this module to its default values. You must click Apply to save the options. + + + + + +Reset + + +This button will "Reset" the module to the previous settings. + + + + + +Apply + + +Clicking this button will save all changes to &kde;. If you have changed anything, clicking Apply will cause the changes to take effect. + + + + + + + +You must either "Reset" or "Apply" the changes before changing to another module. + + +If you try to change without saving or resetting your options, you will be asked if you want to save your changes, or discard them. + + + + + + + +Credits and License + + +&systemsettings; + + +Program copyright 2007 Benjamin C. Meyer. + + +Program copyright 2009 Ben Cooksley. + + +Contributors: + + + +Will Stephenson wstepheson@kde.org + + + +Michael D. Stemle, Jr. manchicken@notsosoft.net + + + + +Matthias Kretz kretz@kde.org + + + + +&Daniel.Molkentin; &Daniel.Molkentin.mail; + + + + +&Matthias.Elter; &Matthias.Elter.mail; + + + + +Frans Englich englich@kde.org + + + + +Michael Jansen kde@michael-jansen.biz + + + + + + +Documentation Copyright © 2008 &Richard.Johnson; &Richard.Johnson.mail; + + + + +&underFDL; +&underGPL; + + +&documentation.index; + + + diff --git a/freespacenotifier/CMakeLists.txt b/freespacenotifier/CMakeLists.txt new file mode 100644 index 00000000..2ce73eb8 --- /dev/null +++ b/freespacenotifier/CMakeLists.txt @@ -0,0 +1,28 @@ +project (freespacenotifier) + +find_package(KDE4 REQUIRED) +include (KDE4Defaults) + +add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) +include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) + +########### next target ############### + +set(kded_freespacenotifier_SRCS freespacenotifier.cpp module.cpp) + +kde4_add_ui_files(kded_freespacenotifier_SRCS freespacenotifier_prefs_base.ui) + +kde4_add_kcfg_files(kded_freespacenotifier_SRCS settings.kcfgc) + +kde4_add_plugin(kded_freespacenotifier ${kded_freespacenotifier_SRCS}) + +target_link_libraries(kded_freespacenotifier ${KDE4_KIO_LIBS} ) + +install(TARGETS kded_freespacenotifier DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES freespacenotifier.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded ) +install( FILES freespacenotifier.notifyrc DESTINATION ${DATA_INSTALL_DIR}/freespacenotifier ) +install( FILES freespacenotifier.kcfg DESTINATION ${KCFG_INSTALL_DIR} ) diff --git a/freespacenotifier/COPYING b/freespacenotifier/COPYING new file mode 100644 index 00000000..5185fd3f --- /dev/null +++ b/freespacenotifier/COPYING @@ -0,0 +1,346 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + 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 Library 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. + + + Copyright (C) 19yy + + 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) 19yy 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. + + , 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 Library General +Public License instead of this License. diff --git a/freespacenotifier/Messages.sh b/freespacenotifier/Messages.sh new file mode 100644 index 00000000..858cfc3b --- /dev/null +++ b/freespacenotifier/Messages.sh @@ -0,0 +1,3 @@ +#! /bin/sh +$EXTRACTRC *.ui *.kcfg >> rc.cpp +$XGETTEXT *.cpp -o $podir/freespacenotifier.pot diff --git a/freespacenotifier/README b/freespacenotifier/README new file mode 100644 index 00000000..208f817d --- /dev/null +++ b/freespacenotifier/README @@ -0,0 +1,3 @@ +This is a small KDED module that monitors free disk space on the home dir +partition and shows a warning dialog when it runs too low, +with a configurable limit and the possibility to postpone. diff --git a/freespacenotifier/freespacenotifier.cpp b/freespacenotifier/freespacenotifier.cpp new file mode 100644 index 00000000..a977d0c3 --- /dev/null +++ b/freespacenotifier/freespacenotifier.cpp @@ -0,0 +1,182 @@ +/* This file is part of the KDE Project + Copyright (c) 2006 Lukas Tinkl + Copyright (c) 2008 Lubos Lunak + Copyright (c) 2009 Ivo Anjo + + 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, see . +*/ + +#include "freespacenotifier.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "settings.h" +#include "ui_freespacenotifier_prefs_base.h" + +FreeSpaceNotifier::FreeSpaceNotifier( QObject* parent ) + : QObject( parent ) + , lastAvailTimer( NULL ) + , notification( NULL ) + , lastAvail( -1 ) +{ + // If we are running, notifications are enabled + FreeSpaceNotifierSettings::setEnableNotification( true ); + + connect( &timer, SIGNAL(timeout()), SLOT(checkFreeDiskSpace()) ); + timer.start( 1000 * 60 /* 1 minute */ ); +} + +FreeSpaceNotifier::~FreeSpaceNotifier() +{ + // The notification is automatically destroyed when it goes away, so we only need to do this if + // it is still being shown + if ( notification ) notification->deref(); +} + +void FreeSpaceNotifier::checkFreeDiskSpace() +{ + if ( notification || !FreeSpaceNotifierSettings::enableNotification() ) + return; + KDiskFreeSpaceInfo fsInfo = KDiskFreeSpaceInfo::freeSpaceInfo( QDir::homePath() ); + if ( fsInfo.isValid() ) + { + int limit = FreeSpaceNotifierSettings::minimumSpace(); // MiB + int availpct = int( 100 * fsInfo.available() / fsInfo.size() ); + qint64 avail = fsInfo.available() / ( 1024 * 1024 ); // to MiB + bool warn = false; + if( avail < limit ) // avail disk space dropped under a limit + { + if( lastAvail < 0 ) // always warn the first time + { + lastAvail = avail; + warn = true; + } + else if( avail > lastAvail ) // the user freed some space + lastAvail = avail; // so warn if it goes low again + else if( avail < lastAvail / 2 ) // available dropped to a half of previous one, warn again + { + warn = true; + lastAvail = avail; + } + // do not change lastAvail otherwise, to handle free space slowly going down + } + if ( warn ) + { + notification = new KNotification( "freespacenotif", 0, KNotification::Persistent ); + + notification->setText( i18nc( "Warns the user that the system is running low on space on his home folder, indicating the percentage and absolute MiB size remaining, and asks if the user wants to do something about it", "You are running low on disk space on your home folder (currently %2%, %1 MiB free).\nWould you like to run a file manager to free some disk space?", avail, availpct ) ); + notification->setActions( QStringList() << i18nc( "Opens a file manager like dolphin", "Open File Manager" ) << i18nc( "Closes the notification", "Do Nothing" ) << i18nc( "Allows the user to configure the warning notification being shown", "Configure Warning" ) ); + //notification->setPixmap( ... ); // TODO: Maybe add a picture here? + + connect( notification, SIGNAL(action1Activated()), SLOT(openFileManager()) ); + connect( notification, SIGNAL(action2Activated()), SLOT(cleanupNotification()) ); + connect( notification, SIGNAL(action3Activated()), SLOT(showConfiguration()) ); + connect( notification, SIGNAL(closed()), SLOT(cleanupNotification()) ); + + notification->setComponentData( KComponentData( "freespacenotifier" ) ); + notification->sendEvent(); + } + } +} + +void FreeSpaceNotifier::openFileManager() +{ + cleanupNotification(); + new KRun( KUrl( QDir::homePath() ), 0 ); +} + +void FreeSpaceNotifier::showConfiguration() +{ + cleanupNotification(); + + if ( KConfigDialog::showDialog( "settings" ) ) { + return; + } + + KConfigDialog *dialog = new KConfigDialog( 0, "settings", FreeSpaceNotifierSettings::self() ); + QWidget *generalSettingsDlg = new QWidget(); + + Ui::freespacenotifier_prefs_base preferences; + preferences.setupUi( generalSettingsDlg ); + + dialog->addPage( generalSettingsDlg, i18nc( "The settings dialog main page name, as in 'general settings'", "General" ), "system-run" ); + connect( dialog, SIGNAL(finished()), this, SLOT(configDialogClosed()) ); + dialog->setAttribute( Qt::WA_DeleteOnClose ); + dialog->show(); +} + +void FreeSpaceNotifier::cleanupNotification() +{ + notification = NULL; + + // warn again if constantly below limit for too long + if( lastAvailTimer == NULL ) + { + lastAvailTimer = new QTimer( this ); + connect( lastAvailTimer, SIGNAL(timeout()), SLOT(resetLastAvailable()) ); + } + lastAvailTimer->start( 1000 * 60 * 60 /* 1 hour*/ ); +} + +void FreeSpaceNotifier::resetLastAvailable() +{ + lastAvail = -1; + lastAvailTimer->deleteLater(); + lastAvailTimer = NULL; +} + +void FreeSpaceNotifier::configDialogClosed() +{ + if ( !FreeSpaceNotifierSettings::enableNotification() ) + disableFSNotifier(); +} + +/* The idea here is to disable ourselves by telling kded to stop autostarting us, and + * to kill the current running instance. + */ +void FreeSpaceNotifier::disableFSNotifier() +{ + QDBusInterface iface( "org.kde.kded", "/kded", "org.kde.kded" ); + if ( dbusError( iface ) ) return; + + // Disable current module autoload + iface.call( "setModuleAutoloading", "freespacenotifier", false ); + if ( dbusError( iface ) ) return; + + // Unload current module + iface.call( "unloadModule", "freespacenotifier" ); + if ( dbusError( iface ) ) return; +} + +bool FreeSpaceNotifier::dbusError( QDBusInterface &iface ) +{ + QDBusError err = iface.lastError(); + if ( err.isValid() ) + { + kError() << "Failed to perform operation on kded [" << err.name() << "]:" << err.message(); + return true; + } + return false; +} diff --git a/freespacenotifier/freespacenotifier.desktop b/freespacenotifier/freespacenotifier.desktop new file mode 100644 index 00000000..37167833 --- /dev/null +++ b/freespacenotifier/freespacenotifier.desktop @@ -0,0 +1,131 @@ +[Desktop Entry] +Name=Free Space Notifier +Name[ar]=منبه المساحة الحرة +Name[ast]=Notificador d'espaciu llibre +Name[bg]=Уведомяване за свободно пространство +Name[bs]=Izvještač o slobodnom prostoru +Name[ca]=Notificador d'espai lliure +Name[ca@valencia]=Notificador d'espai lliure +Name[cs]=Oznamování volného místa +Name[da]=Bekendtgørelse om ledig plads +Name[de]=Speicherplatzbenachrichtigung +Name[el]=Ειδοποίηση ελεύθερου χώρου +Name[en_GB]=Free Space Notifier +Name[es]=Notificador de espacio libre +Name[et]=Vaba ruumi teavitaja +Name[eu]=Leku askearen jakinarazlea +Name[fi]=Vapaan tilan ilmoitin +Name[fr]=Notification d'espace libre +Name[ga]=Fógróir Spáis Shaoir +Name[gl]=Notificador de espazo libre +Name[he]=Free Space Notifier +Name[hi]=खाली स्थान सूचक +Name[hr]=Glasnik slobodnog prostora +Name[hu]=Szabad hely értesítő +Name[ia]=Notificator de spatio libere +Name[id]=Notifikasi Ruang Kosong +Name[is]=Tilkynningar um laust pláss +Name[it]=Notificatore dello spazio libero +Name[ja]=空き領域の通知 +Name[kk]=KDE-нің бос орын туралы құлақтандыруы +Name[km]=កម្មវិធី​ជូនដំណឹង​​ទំហំ​ទំនេរ +Name[kn]=ಖಾಲಿ ಜಾಗ ಸೂಚಕ +Name[ko]=남은 공간 알림이 +Name[lt]=Laisvos vietos pranešėjas +Name[lv]=Brīvās vietas ziņotājs +Name[ml]=ലഭ്യമായ സ്ഥലം അറിയിക്കുന്നതിനുള്ള സംവിധാനം +Name[mr]=मोकळी जागा निदर्शक +Name[nb]=Ledig plass-varsler +Name[nds]=Freeruumbescheden +Name[nl]=Vrije ruimte-melder +Name[nn]=Varsel om lite ledig plass +Name[pa]=ਖਾਲੀ ਥਾਂ ਨੋਟੀਫਾਇਰ +Name[pl]=Powiadomienie o wolnym miejscu +Name[pt]=Notificação de Espaço Livre +Name[pt_BR]=Notificação de espaço livre +Name[ro]=Notificare spațiu liber +Name[ru]=Слежение за свободным местом на диске +Name[si]=හිස් ඉඩ දැනුම් දෙන්නා +Name[sk]=Monitor voľného miesta +Name[sl]=Obvestilnik o neporabljenem prostoru +Name[sr]=Извештавач о слободном простору +Name[sr@ijekavian]=Извјештавач о слободном простору +Name[sr@ijekavianlatin]=Izvještavač o slobodnom prostoru +Name[sr@latin]=Izveštavač o slobodnom prostoru +Name[sv]=Information om ledigt utrymme +Name[th]=ตัวแจ้งพื้นที่ว่าง +Name[tr]=Boş Alan Bildirici +Name[ug]=بىكار بوشلۇق خەۋەرچىسى +Name[uk]=Сповіщення про вільне місце +Name[vi]=Trình thông báo không gian trống +Name[wa]=Notifieu del plaece di libe +Name[x-test]=xxFree Space Notifierxx +Name[zh_CN]=空闲空间通知器 +Name[zh_TW]=剩餘空間通知 +Comment=Warns when running out of space on your home folder +Comment[ar]=يحذر عندما توشك مساحة مجلد المنزل على النفاد +Comment[ast]=Avisa cuando te quedes ensin espaciu na carpeta personal +Comment[bg]=Предупреждение при твърде малко пространство в домашната директория +Comment[bn]=ব্যক্তিগত ফোল্ডারে জায়গা কমে গেলে সতর্ক করে +Comment[bs]=Upozorava kada vam ponestaje prostora u ličnom direktoriju +Comment[ca]=Avisa quan s'exhaureix l'espai de la carpeta personal +Comment[ca@valencia]=Avisa quan s'exhaureix l'espai de la carpeta personal +Comment[cs]=Varování při blížícím se nedostatku místa v domácí složce +Comment[da]=Advarer når du er ved at løbe tør for plads i din hjemmemappe +Comment[de]=Gibt eine Warnung aus, wenn der freie Speicherplatz in Ihrem Persönlichen Ordner knapp wird +Comment[el]=Προειδοποιεί όταν τελειώνει ο ελεύθερος χώρος στον 'Προσωπικό φάκελό' σας +Comment[en_GB]=Warns when running out of space on your home folder +Comment[es]=Le avisa cuando se está quedando sin espacio en su carpeta personal +Comment[et]=Hoiatus, kui kodukataloogis hakkab ruumi nappima +Comment[eu]=Abisua ematen du etxeko karpetan lekurik gabe gelditzen ari zarenean +Comment[fi]=Varoittaa kun kotikansiosta on tila loppumassa +Comment[fr]=Avertit lorsque l'espace vient à manquer dans votre dossier utilisateur +Comment[ga]=Tugann sé rabhadh duit nuair atá d'fhillteán baile ag éirí lán +Comment[gl]=Avisa cando se está a quedar sen espazo no cartafol persoal +Comment[he]=משמש לאזהרה כאשר המקום הפנוי בתיקיית הבית מועט +Comment[hr]=Upozori kada nestaje prostora u mojoj korisničkoj mapi +Comment[hu]=Figyelmeztet, ha kezd elfogyni a szabad lemezterület a saját könyvtárában +Comment[ia]=Il avisa quando il termina le spatio sur tu dossier domo +Comment[id]=Memperingatkan jika kehabisan ruang kosong di folder rumah anda +Comment[is]=Varar við þegar lítið pláss er eftir í heimamöppunni þinni +Comment[it]=Avvisa quando si sta finendo lo spazio nella tua cartella Home +Comment[ja]=ホームフォルダの空き領域が少なくなったとき警告します +Comment[kk]=Мекен қапшығыңызда орын тапшылығы туралы ескерту +Comment[km]=ព្រមាន នៅពេល​ដំណើរការ​អស់ទំហំ​នៅ​លើ​ក្នុង​​ផ្ទះ​របស់​អ្នក +Comment[kn]=ನೆಲೆ ಕೋಶದಲ್ಲಿ ಖಾಲಿ ಸ್ಥಳವು ಇದಕ್ಕಿಂತ ಕಡಿಮೆಯಾದರೆ ಎಚ್ಚರಿಸುತ್ತದೆ +Comment[ko]=홈 폴더에 공간이 없을 때 알려 줍니다 +Comment[lt]=Įspėja, kai namų aplanke baigiasi laisva vieta +Comment[lv]=Brīdina, kad mājas mapē beidzas brīvā vieta +Comment[mr]=तुमच्या मुख्य संचयीकेतील जागा संपत आल्याची सूचना देतो +Comment[nb]=Varsler når det er lite plass igjen i hjemmemappa +Comment[nds]=Wohrschoen bi to minn free Ruum binnen Dien Tohuusorner +Comment[nl]=Geeft een waarschuwing bij een lage stand van de vrije ruimte voor uw persoonlijke map +Comment[nn]=Varslar når det er lite plass i heimemappa +Comment[pa]=ਚੇਤਾਵਨੀ ਦਿਉ, ਜਦੋਂ ਤੁਹਾਡੇ ਘਰ ਫੋਲਡਰ ਉੱਤੇ ਥਾਂ ਖਤਮ ਹੋ ਰਹੀ ਹੋਵੇ +Comment[pl]=Ostrzega, kiedy zaczyna brakować miejsca w katalogu domowym +Comment[pt]=Avisa de estiver com falta de espaço na sua pasta pessoal +Comment[pt_BR]=Avisa quando ficar sem espaço na sua pasta pessoal +Comment[ro]=Atenționează cînd spațiul de stocare din dosarul acasă este pe cale să se termine +Comment[ru]=Предупреждает о нехватке дискового пространства в домашней папке +Comment[si]=ඔබගේ නිවාස බහාලුමේ ඉඩ අඩුවෙන් ධාවනය වෙන විට ඇනතුරු අඟවයි +Comment[sk]=Upozorňuje, keď dochádza voľné miesto v domovskom priečinku +Comment[sl]=Opozori, ko v domači mapi primanjkuje prostora +Comment[sr]=Упозорава када вам понестаје простора у домаћој фасцикли +Comment[sr@ijekavian]=Упозорава када вам понестаје простора у домаћој фасцикли +Comment[sr@ijekavianlatin]=Upozorava kada vam ponestaje prostora u domaćoj fascikli +Comment[sr@latin]=Upozorava kada vam ponestaje prostora u domaćoj fascikli +Comment[sv]=Varnar när utrymmet i hemkatalogen håller på att ta slut +Comment[th]=เตือนเมื่อพื้นที่ในโฟลเดอร์บ้านเหลือน้อย +Comment[tr]=Ev dizininizde boş alan azaldığı zaman uyarır +Comment[ug]=ماكان قىسقۇچىڭىزدىكى دىسكا بوشلۇقى ئاز قالغاندا ئەسكەرتىدۇ +Comment[uk]=Попереджає, якщо у домашній теці залишається мало місця +Comment[vi]=Cảnh báo khi sắp hết không gian cho thư mục chính của bạn +Comment[wa]=Advierti cwand i gn a cåzu pupont d' plaece dins vosse ridant måjhon +Comment[x-test]=xxWarns when running out of space on your home folderxx +Comment[zh_CN]=在您主目录磁盘空间过低时发出警告 +Comment[zh_TW]=當您的家目錄剩餘空間快不足時警告您 +Type=Service +X-KDE-ServiceTypes=KDEDModule +X-KDE-Library=freespacenotifier +X-KDE-DBus-ModuleName=freespacenotifier +X-KDE-Kded-autoload=true diff --git a/freespacenotifier/freespacenotifier.h b/freespacenotifier/freespacenotifier.h new file mode 100644 index 00000000..7e9bed53 --- /dev/null +++ b/freespacenotifier/freespacenotifier.h @@ -0,0 +1,52 @@ +/* This file is part of the KDE Project + Copyright (c) 2006 Lukas Tinkl + Copyright (c) 2008 Lubos Lunak + Copyright (c) 2009 Ivo Anjo + + 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, see . +*/ + +#ifndef _FREESPACENOTIFIER_H_ +#define _FREESPACENOTIFIER_H_ + +#include +#include + +#include + +class FreeSpaceNotifier +: public QObject +{ + Q_OBJECT + public: + FreeSpaceNotifier( QObject* parent = NULL ); + virtual ~FreeSpaceNotifier(); + private slots: + void checkFreeDiskSpace(); + void resetLastAvailable(); + void openFileManager(); + void showConfiguration(); + void cleanupNotification(); + void configDialogClosed(); + private: + QTimer timer; + QTimer* lastAvailTimer; + KNotification *notification; + qint64 lastAvail; // used to suppress repeated warnings when available space hasn't changed + + void disableFSNotifier(); + bool dbusError( QDBusInterface &iface ); +}; + +#endif diff --git a/freespacenotifier/freespacenotifier.kcfg b/freespacenotifier/freespacenotifier.kcfg new file mode 100644 index 00000000..51e02b3d --- /dev/null +++ b/freespacenotifier/freespacenotifier.kcfg @@ -0,0 +1,19 @@ + + + + + + + 200 + 1 + 100000 + + + + 1 + + + diff --git a/freespacenotifier/freespacenotifier.notifyrc b/freespacenotifier/freespacenotifier.notifyrc new file mode 100644 index 00000000..0b86e25c --- /dev/null +++ b/freespacenotifier/freespacenotifier.notifyrc @@ -0,0 +1,423 @@ +[Global] +IconName=drive-harddisk +Comment=KDE Free Space Notifier Daemon +Comment[ar]=مراقب كدي لمنبه المساحة الحرّة +Comment[ast]=Degorriu de notificaciones d'espaciu llibre de KDE +Comment[bg]=Демон на KDE за свободно пространство +Comment[bn]=কে.ডি.ই. ফ্রী স্পেস বিজ্ঞপ্তি ডিমন +Comment[bs]=KDE‑ov demon izveštavača o slobodnom prostoru +Comment[ca]=Dimoni de notificacions d'espai lliure del KDE +Comment[ca@valencia]=Dimoni de notificacions d'espai lliure del KDE +Comment[cs]=Upozorňovací démon volného místa KDE +Comment[da]=KDE dæmon til bekendtgørelse om ledig plads +Comment[de]=KDE-Dienst für Speicherplatzbenachrichtigung +Comment[el]=Δαίμονας ειδοποιήσεων ελευθέρου χώρου του KDE +Comment[en_GB]=KDE Free Space Notifier Dæmon +Comment[es]=Demonio de notificaciones de espacio libre de KDE +Comment[et]=KDE vaba ruumi teavitamise deemon +Comment[eu]=KDEren leku askea jakinarazteko daimona +Comment[fi]=KDE:n vapaan tilan ilmoitustaustaprosessi +Comment[fr]=Démon de notification d'espace libre de KDE +Comment[ga]=Fógróir Spáis Shaoir KDE +Comment[gl]=Daemon notificador do espazo libre de KDE +Comment[he]=KDE Free Space Notifier Daemon +Comment[hi]=केडीई खाली स्थान सूचना डेमन +Comment[hr]=KDE-ov servis za obavještavanje o slobodnom prostoru +Comment[hu]=KDE szabad hely értesítő szolgáltatás +Comment[ia]=Demone de notification de spatio libere de KDE +Comment[id]=Jurik Notifikasi RUang Kosong KDE +Comment[is]=KDE tilkynningaþjónn fyrir laust pláss +Comment[it]=Demone di notifica dello spazio libero di KDE +Comment[ja]=KDE 空き領域デーモン +Comment[kk]=KDE-нің бос орын туралы құлақтандыру қызметі +Comment[km]=ដេមិន​​ជូន​ដំណឹង​​ទំហំ​ទំនេរ​របស់ KDE +Comment[kn]=ಕೆಡಿಇ ಖಾಲಿ ಜಾಗ ಸೂಚನಾ ನೇಪಥಿಕ (ಡೀಮನ್) +Comment[ko]=KDE 남은 공간 알림 데몬 +Comment[lt]=KDE laisvos vietos pranešimų tarnyba +Comment[lv]=KDE brīvās vietas paziņošanas dēmons +Comment[ml]=കെഡിഇയിലെ ലഭ്യമായ സ്ഥലം അറിയിയ്ക്കുന്നതിനുള്ള നിരന്തര പ്രവൃത്തി +Comment[mr]=केडीई मोकळी जागा निदर्शक डीमन +Comment[nb]=KDEs varslingsdaemon for ledig plass +Comment[nds]=KDE-Dämoon för Freeruumbescheden +Comment[nl]=KDE-daemon voor het melden van vrije ruimte +Comment[nn]=KDE-varsel om lite plass +Comment[pa]=KDE ਖਾਲੀ ਥਾਂ ਨੋਟੀਫਿਕੇਸ਼ਨ ਡੈਮਨ +Comment[pl]=Demon powiadomień o wolnym miejscu KDE +Comment[pt]=Servidor de Notificação de Espaço Livre do KDE +Comment[pt_BR]=Serviço de notificação de espaço livre do KDE +Comment[ro]=Demon de notificare KDE a spațiului liber +Comment[ru]=Служба уведомлений о свободном месте на диске +Comment[si]=KDE හිස් ඉඩ දැනුම්දීමේ ඩීමනය +Comment[sk]=Monitor voľného miesta KDE +Comment[sl]=KDE-jev obvestilnik o neporabljenem prostoru +Comment[sr]=КДЕ‑ов демон извештавача о слободном простору +Comment[sr@ijekavian]=КДЕ‑ов демон извјештавача о слободном простору +Comment[sr@ijekavianlatin]=KDE‑ov demon izvještavača o slobodnom prostoru +Comment[sr@latin]=KDE‑ov demon izveštavača o slobodnom prostoru +Comment[sv]=KDE:s demon för information om ledigt utrymme +Comment[th]=ดีมอนการแจ้งพื้นที่ว่างของ KDE +Comment[tr]=KDE Boş Alan Bildirme Servisi +Comment[ug]=KDE بىكار بوشلۇق خەۋەرچى نازارەتچىسى +Comment[uk]=Фонова служба сповіщення про переповнення диска KDE +Comment[vi]=Trình nền thông báo không gian trống KDE +Comment[wa]=Démon KDE notifieu del plaece di libe +Comment[x-test]=xxKDE Free Space Notifier Daemonxx +Comment[zh_CN]=KDE 空闲空间通知守护程序 +Comment[zh_TW]=KDE 剩餘空間通知伺服程式 +Name=Low Disk Space +Name[ar]=مساحة القرص منخفضة +Name[ast]=Pocu espaciu en discu +Name[bg]=Дисковото пространство е твърде малко +Name[bn]=ডিস্ক-এ জায়গা কম +Name[bs]=Malo prostora na disku +Name[ca]=Espai escàs al disc +Name[ca@valencia]=Espai escàs al disc +Name[cs]=Málo místa na disku +Name[da]=Lav diskplads +Name[de]=Wenig Speicherplatz +Name[el]=Χαμηλή χωρητικότητα δίσκου +Name[en_GB]=Low Disk Space +Name[es]=Poco espacio en disco +Name[et]=Kettaruumi napib +Name[eu]=Leku gutxi diskoan +Name[fi]=Vähäinen levytila +Name[fr]=Espace disque faible +Name[ga]=Easpa Spáis ar an Diosca +Name[gl]=Pouco espazo no disco +Name[he]=שטח מועט פנוי בדיסק +Name[hi]=डिस्क जगह कम +Name[hr]=Malo prostora na disku +Name[hu]=Kevés a lemezterület +Name[ia]=Spatio de disco basse +Name[id]=Ruang Kosong Tinggal Sedikit +Name[is]=Lítið diskpláss +Name[it]=Poco spazio su disco +Name[ja]=ディスクの空き領域が少ないです +Name[kk]=Дискіде орын тапшылығы +Name[km]=ទំហំ​ថាស​ទាប +Name[kn]=ಕಡಿಮೆ ಡಿಸ್ಕ್‌ ಜಾಗ +Name[ko]=디스크 공간 부족 +Name[lt]=Mažai vietos diske +Name[lv]=Maz diska vietas +Name[mai]=कम डिस्क स्थान +Name[ml]=ഡിസ്കില്‍ സഥലം കുറവാണു് +Name[mr]=डिस्कवर कमी जागा शिल्लक आहे +Name[nb]=Lite diskplass +Name[nds]=To minn free Ruum op de Fastplaat +Name[nl]=Schijf bijna vol +Name[nn]=Lite diskplass +Name[pa]=ਘੱਟ ਡਿਸਕ ਥਾਂ +Name[pl]=Mało miejsca na dysku +Name[pt]=Pouco Espaço em Disco +Name[pt_BR]=Pouco espaço em disco +Name[ro]=Spațiu pe disc scăzut +Name[ru]=Недостаточно места на диске +Name[si]=පහත් තැටි ඉඩ +Name[sk]=Nedostatok miesta na disku +Name[sl]=Prostora na disku je malo +Name[sr]=Мало простора на диску +Name[sr@ijekavian]=Мало простора на диску +Name[sr@ijekavianlatin]=Malo prostora na disku +Name[sr@latin]=Malo prostora na disku +Name[sv]=Ont om diskutrymme +Name[th]=พื้นที่ดิสก์เหลือน้อย +Name[tr]=Düşük Disk Alanı +Name[ug]=دىسكىدىكى بوشلۇق ئاز +Name[uk]=Замало місця на диску +Name[vi]=Dung lượng đĩa trống thấp +Name[wa]=Pus bråmint d' plaece sol plake +Name[x-test]=xxLow Disk Spacexx +Name[zh_CN]=低磁盘空间 +Name[zh_TW]=磁碟空間過低 + +[Context/warningnot] +Name=Warning +Name[af]=Waarskuwing +Name[ar]=إنذار +Name[as]=সতৰ্কবাণী +Name[ast]=Avisu +Name[be]=Папярэджанне +Name[be@latin]=Uvaha +Name[bg]=Предупреждение +Name[bn]=সতর্কবার্তা +Name[bn_IN]=সতর্কবার্তা +Name[bs]=Upozorenje +Name[ca]=Avís +Name[ca@valencia]=Avís +Name[cs]=Varování +Name[csb]=Bôczënk +Name[da]=Advarsel +Name[de]=Warnung +Name[el]=Προειδοποίηση +Name[en_GB]=Warning +Name[eo]=Averto +Name[es]=Aviso +Name[et]=Hoiatus +Name[eu]=Abisua +Name[fi]=Varoitus +Name[fr]=Avertissement +Name[fy]=Warskôging +Name[ga]=Rabhadh +Name[gl]=Aviso +Name[gu]=ચેતવણી +Name[he]=אזהרה +Name[hi]=चेतावनी +Name[hne]=चेतावनी +Name[hr]=Upozorenje +Name[hsb]=Kedźbu +Name[hu]=Figyelmeztetés +Name[ia]=Aviso +Name[id]=Peringatan +Name[is]=Aðvörun +Name[it]=Avviso +Name[ja]=警告 +Name[kk]=Ескерту +Name[km]=ការ​ព្រមាន +Name[kn]=ಎಚ್ಚರಿಕೆ +Name[ko]=경고 +Name[ku]=Hişyarî +Name[lt]=Dėmesio +Name[lv]=Brīdinājums +Name[mai]=चेतावनी +Name[mk]=Предупредување +Name[ml]=മുന്നറിയിപ്പു് +Name[mr]=इशारा +Name[nb]=Advarsel +Name[nds]=Wohrschoen +Name[ne]=चेतावनी +Name[nl]=Waarschuwing +Name[nn]=Åtvaring +Name[oc]=Alèrta +Name[or]=ଚେତାବନୀ +Name[pa]=ਚੇਤਾਵਨੀ +Name[pl]=Ostrzeżenie +Name[pt]=Aviso +Name[pt_BR]=Aviso +Name[ro]=Atenționare +Name[ru]=Предупреждение +Name[se]=Várrehus +Name[si]=අවවාදය +Name[sk]=Varovanie +Name[sl]=Opozorilo +Name[sr]=Упозорење +Name[sr@ijekavian]=Упозорење +Name[sr@ijekavianlatin]=Upozorenje +Name[sr@latin]=Upozorenje +Name[sv]=Varning +Name[ta]=எச்சரிக்கை +Name[te]=హెచ్చరిక +Name[tg]=Огоҳинома +Name[th]=คำเตือน +Name[tr]=Uyarı +Name[ug]=ئاگاھلاندۇرۇش +Name[uk]=Попередження +Name[uz]=Ogohnoma +Name[uz@cyrillic]=Огоҳнома +Name[vi]=Cảnh báo +Name[wa]=Adviertixhmint +Name[x-test]=xxWarningxx +Name[zh_CN]=警告 +Name[zh_TW]=警告 +Comment=Used for warning notifications +Comment[ar]=يُستخدم للتنبيهات التحذيرية +Comment[ast]=Usáu pa notificaciones d'avisu +Comment[be@latin]=Dla aścierahalnych paviedamleńniaŭ +Comment[bg]=Използва се за предупреждения +Comment[bn]=সতর্কীকরণ বিজ্ঞপ্তির জন্য ব্যবহৃত হয় +Comment[bs]=Koristi se za obavještenja o upozorenjima +Comment[ca]=S'usa per a les notificacions d'avís +Comment[ca@valencia]=S'usa per a les notificacions d'avís +Comment[cs]=Použito pro varování a upozornění +Comment[da]=Bruges til advarselsbekendtgørelser +Comment[de]=Verwendet für Warnmeldungen +Comment[el]=Χρησιμοποιείται για τις προειδοποιήσεις +Comment[en_GB]=Used for warning notifications +Comment[eo]=Uzita por avertmesaĝoj +Comment[es]=Usado para notificaciones de advertencia +Comment[et]=Hoiatuste jaoks +Comment[eu]=Abisu-jakinarazpenetarako erabiltzen da +Comment[fi]=Käytetään varoitusilmoituksiin +Comment[fr]=Utilisé pour les notifications d'avertissements +Comment[fy]=Brûkt faor warskôging notifikaasjes +Comment[ga]=Úsáidte do rabhaidh +Comment[gl]=Emprégase para as notificacións de aviso +Comment[gu]=ચેતવણી નોંધણીઓ આપવા માટે વપરાય છે +Comment[he]=משמש להתרעות אזהרה +Comment[hi]=चेतावनियाँ देने के लिए उपयोग में लिया जाता है +Comment[hne]=चेतावनी सूचना बर उपयोग होथे +Comment[hr]=Korišten za upozoravajuće obavijesti +Comment[hu]=Kezelőprogram figyelmeztető üzenetekhez +Comment[ia]=Usate pro notificationes de avisos +Comment[id]=Digunakan untuk notifikasi peringatan +Comment[is]=Notað fyrir aðvaranir +Comment[it]=Usato per notifiche di avviso +Comment[ja]=警告の通知に使用 +Comment[kk]=Ескерту хабарларға қолданылады +Comment[km]=បានប្រើ​សម្រាប់​ការ​ជូន​ព្រមាន +Comment[kn]=ಎಚ್ಚರಿಕೆ ಸೂಚನೆಗಳಿಗೆ ಬಳಸಲಾಗುತ್ತದೆ +Comment[ko]=경고 알림에 사용됨 +Comment[lt]=Naudojama perspėjimams +Comment[lv]=Izmanto brīdinājumu paziņojumiem +Comment[ml]=താക്കീത് അറിയിപ്പുകള്‍ക്കായി ഉപയോഗിക്കുന്നു +Comment[mr]=इशारा सूचना करिता वापरले जाते +Comment[nb]=Brukt til varselsmeldinger +Comment[nds]=Bi Wohrschoen bruukt +Comment[nl]=Wordt gebruikt voor waarschuwingsmeldingen +Comment[nn]=Er brukt til åtvaringsvarsel +Comment[or]=ଚେତାବନୀ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପାଇଁ ବ୍ୟବହୃତ ହୋଇଥାଏ +Comment[pa]=ਚੇਤਾਵਨੀ ਨੋਟੀਫਿਕੇਸ਼ਨ ਲਈ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ +Comment[pl]=Używane do ostrzeżeń +Comment[pt]=Usado para as notificações de aviso +Comment[pt_BR]=Usado para as notificações de aviso +Comment[ro]=Utilizat pentru notificări de avertizare +Comment[ru]=Используется для системных уведомлений +Comment[si]=අවවාද පණිවුඩ සඳහා යොදාගනී +Comment[sk]=Používa sa pre varovné upozornenia +Comment[sl]=Uporabljeno za obvestila z opozorili +Comment[sr]=Користи се за позорна обавештења +Comment[sr@ijekavian]=Користи се за позорна обавјештења +Comment[sr@ijekavianlatin]=Koristi se za pozorna obavještenja +Comment[sr@latin]=Koristi se za pozorna obaveštenja +Comment[sv]=Används för varningsmeddelanden +Comment[ta]=Used for warning notifications +Comment[te]=హెచ్చరిక నోటీసుల కొరకు వుపయోగించబడింది +Comment[tg]=Используется для надписей под значками на рабочем столе. +Comment[th]=ใช้สำหรับการแจ้งเตือนให้ทราบ +Comment[tr]=Uyarı bildirimleri için kullanılır +Comment[ug]=ئاگاھلاندۇرۇش ئۇقتۇرۇشلىرى ئۈچۈن ئىشلىتىلىدۇ. +Comment[uk]=Використовується для попереджень +Comment[vi]=Sử dụng cho thông tin cảnh báo +Comment[wa]=Eployî po des notifiaedjes d' adviertixhmint +Comment[x-test]=xxUsed for warning notificationsxx +Comment[zh_CN]=用于发出警告通知 +Comment[zh_TW]=用於警告通知 + +[Event/freespacenotif] +Name=Running low on disk space +Name[ar]=قارب القرص على الامتلاء +Name[ast]=Queda poco espaciu en discu +Name[bg]=Дисковото пространство е твърде малко +Name[bn]=ডিস্ক-এ বেশী জায়গা বাকি নেই +Name[bs]=Ponestaje prostora na disku +Name[ca]=S'està exhaurint l'espai del disc +Name[ca@valencia]=S'està exhaurint l'espai del disc +Name[cs]=Dochází místo na disku +Name[da]=Ved at løbe tør for diskplads +Name[de]=Speicherplatz wird knapp +Name[el]=Τρέχον χωρητικότητα δίσκου χαμηλή +Name[en_GB]=Running low on disk space +Name[es]=Queda poco espacio en disco +Name[et]=Kettaruumi napib +Name[eu]=Leku gutxi gelditzen da diskoan +Name[fi]=Levytila alkaa olla lopussa +Name[fr]=L'espace disque commence à manquer +Name[ga]=Tá an diosca ag éirí lán +Name[gl]=Esgotando o espazo no disco +Name[he]=השטח הפנוי בדיסק מועט +Name[hi]=डिस्क में जगह कम हो गया है +Name[hr]=Ponestajanje diskovnog prostora +Name[hu]=Kezd fogyni a lemezterület +Name[ia]=Exhauriente le spatio de disco +Name[id]=Berjalan pada ruang kosong yang tinggal sedikit +Name[is]=Lítið pláss eftir á diski +Name[it]=Lo spazio su disco si sta esaurendo +Name[ja]=ディスクの空き領域が少ないです +Name[kk]=Диск орын тапшылығы +Name[km]=ដំណើរការ​ទាប​លើ​ទំហំ​ថាស +Name[kn]=ಮುದ್ರಿಕೆಯಲ್ಲಿ (ಡಿಸ್ಕ್) ಜಾಗ ಕಮ್ಮಿಯಾಗುತ್ತಿದೆ. +Name[ko]=디스크 공간 거의 없음 +Name[lt]=Diske liko mažai vietos +Name[lv]=Ir palicis maz brīvas vietas +Name[mr]=डिस्कवर कमी जागा शिल्लक आहे +Name[nb]=Det er nå lite diskplass +Name[nds]=De free Ruum op de Fastplaat geiht op de Neeg. +Name[nl]=Bijna geen vrije schijfruimte meer +Name[nn]=Det er lite diskplass att +Name[pa]=ਡਿਸਕ ਥਾਂ ਖਤਮ ਹੋ ਰਹੀ ਹੈ +Name[pl]=Zaczyna brakować miejsca na dysku +Name[pt]=Pouco espaço livre em disco +Name[pt_BR]=Pouco espaço livre em disco +Name[ro]=Spațiu pe disc este scăzut +Name[ru]=Недостаточно места на диске +Name[si]=පහත් තැටි ඉඩෙන් ධාවනය කරමි +Name[sk]=Dochádza voľné miesto na disku +Name[sl]=Razpoložljivega prostora na disku je malo +Name[sr]=Понестаје простора на диску +Name[sr@ijekavian]=Понестаје простора на диску +Name[sr@ijekavianlatin]=Ponestaje prostora na disku +Name[sr@latin]=Ponestaje prostora na disku +Name[sv]=Diskutrymmet håller på att ta slut +Name[th]=พื้นที่ดิสก์กำลังเหลือน้อย +Name[tr]=Düşük disk alanı üzerinde çalışıyor +Name[ug]=دىسكىدىكى بوشلۇق ئاز ھالەتتە ئىجرا قىلىۋاتىدۇ +Name[uk]=Замало місця на диску +Name[vi]=Không gian đĩa trống sắp hết +Name[wa]=Gn a pus bråmint d' plaece sol plake +Name[x-test]=xxRunning low on disk spacexx +Name[zh_CN]=磁盘空间过低 +Name[zh_TW]=磁碟空間快用完了 +Comment=You are running low on disk space +Comment[ar]=إن مساحة التخزين المتوفرة على القرص توشك على النفاذ +Comment[ast]=Tas quedando ensin espaciu en discu +Comment[bg]=Дисковото Ви пространство е твърде малко +Comment[bn]=আপনার ডিস্ক-এ বেশী জায়গা বাকি নেই +Comment[bs]=Ponestaje vam prostora na disku +Comment[ca]=L'espai del disc s'està exhaurint +Comment[ca@valencia]=L'espai del disc s'està exhaurint +Comment[cs]=Dochází vám místo na disku +Comment[da]=Du er ved at løbe tør for diskplads +Comment[de]=Ihr freier Speicherplatz wird knapp +Comment[el]=Η τρέχουσα χωρητικότητα του δίσκου σας είναι χαμηλή +Comment[en_GB]=You are running low on disk space +Comment[es]=Se está quedando sin espacio en disco +Comment[et]=Kettaruumi on vähe järele jäänud +Comment[eu]=Diskoan lekurik gabe gelditzen ari zara +Comment[fi]=Levytilasi alkaa loppua +Comment[fr]=Vous manquez d'espace disque +Comment[ga]=Tá an diosca ag éirí lán +Comment[gl]=Está a quedar sen espazo no disco +Comment[he]=השטח הפנוי בדיסק מועט +Comment[hi]=आप कम डिस्क जगह पर चल रहे हैं +Comment[hr]=Ponestaje vam diskovnog prostora +Comment[hu]=A lemezterület kezd elfogyni +Comment[ia]=Tu es exhauriente le spatio de disco +Comment[id]=Anda berjalan pada ruang kosong yang tinggal sedikit +Comment[is]=Þú ert að verða uppiskroppa með diskpláss +Comment[it]=Stai esaurendo lo spazio su disco +Comment[ja]=ディスクの空き領域が少なくなりました +Comment[kk]=Диск орын тапшылықтасыз +Comment[km]=អ្នក​កំពុង​ដំណើរការ​ទាប​​លើ​ទំហំ​ថាស +Comment[kn]=ನಿಮ್ಮಲ್ಲಿ ಕಡಿಮೆ ಡಿಸ್ಕ್‍ ಸ್ಥಳವಿದೆ +Comment[ko]=디스크 공간이 거의 없습니다 +Comment[lt]=Jūsų diske liko mažai vietos +Comment[lv]=Uz diska ir maz brīvas vietas +Comment[mr]=तुमच्या डिस्कवर कमी जागा शिल्लक आहे +Comment[nb]=Du har lite diskplass igjen +Comment[nds]=De free Ruum op Dien Fastplaat geiht op de Neeg. +Comment[nl]=U hebt bijna geen vrije schijfruimte meer +Comment[nn]=Du har lite diskplass att +Comment[pa]=ਤੁਹਾਡੇ ਕੋਲ ਡਿਸਕ ਖਾਲੀ ਥਾਂ ਘੱਟ ਰਹੀ ਹੈ +Comment[pl]=Zaczyna brakować miejsca na dysku +Comment[pt]=Está a ficar com pouco espaço livre em disco +Comment[pt_BR]=Você tem pouco espaço livre em disco +Comment[ro]=Spațiul dumneavoastră de stocare este pe cale să se termine +Comment[ru]=На диске осталось мало свободного места +Comment[si]=ඔබගේ තැටි ඉඩ අඩු වෙමින් පවතී +Comment[sk]=Dochádza vám voľné miesto na disku +Comment[sl]=Na disku imate malo razpoložljivega prostora +Comment[sr]=Понестаје вам простора на диску +Comment[sr@ijekavian]=Понестаје вам простора на диску +Comment[sr@ijekavianlatin]=Ponestaje vam prostora na disku +Comment[sr@latin]=Ponestaje vam prostora na disku +Comment[sv]=Diskutrymmet håller på att ta slut +Comment[th]=คุณกำลังทำงานด้วยพื้นที่ดิสก์ที่เหลือน้อย +Comment[tr]=Düşük disk alanı üzerinde çalışıyorsunuz +Comment[ug]=دىسكىدىكى بوشلۇق ئاز ھالەتتە ئىجرا قىلىۋاتىسىز +Comment[uk]=На вашому диску залишилося замало місця +Comment[vi]=Bạn đang dùng sắp hết không gian đĩa +Comment[wa]=Vos estoz k' n' a pus bråmint d' plaece sol plake +Comment[x-test]=xxYou are running low on disk spacexx +Comment[zh_CN]=您现在的磁盘空间过低 +Comment[zh_TW]=您的磁碟空間快用完了 +Contexts=warningnot +Action=Popup diff --git a/freespacenotifier/freespacenotifier_prefs_base.ui b/freespacenotifier/freespacenotifier_prefs_base.ui new file mode 100644 index 00000000..7f93d49c --- /dev/null +++ b/freespacenotifier/freespacenotifier_prefs_base.ui @@ -0,0 +1,91 @@ + + + freespacenotifier_prefs_base + + + + 0 + 0 + 320 + 217 + + + + + + + Enable low disk space warning + + + true + + + + + + + Warn when free space is below: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + MiB + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + kcfg_enableNotification + toggled(bool) + kcfg_minimumSpace + setEnabled(bool) + + + 114 + 15 + + + 272 + 44 + + + + + kcfg_enableNotification + toggled(bool) + label_minimumSpace + setEnabled(bool) + + + 114 + 15 + + + 114 + 44 + + + + + diff --git a/freespacenotifier/module.cpp b/freespacenotifier/module.cpp new file mode 100644 index 00000000..abbc3f11 --- /dev/null +++ b/freespacenotifier/module.cpp @@ -0,0 +1,36 @@ +/* This file is part of the KDE Project + Copyright (c) 2006 Lukas Tinkl + Copyright (c) 2008 Lubos Lunak + Copyright (c) 2009 Ivo Anjo + + 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, see . +*/ + +#include "module.h" + +#include +#include + +K_PLUGIN_FACTORY(FreeSpaceNotifierModuleFactory, + registerPlugin(); + ) +K_EXPORT_PLUGIN(FreeSpaceNotifierModuleFactory("freespacenotifier")) + + +FreeSpaceNotifierModule::FreeSpaceNotifierModule(QObject* parent, const QList&) + : KDEDModule(parent) +{ +} + +#include "module.moc" diff --git a/freespacenotifier/module.h b/freespacenotifier/module.h new file mode 100644 index 00000000..37592c9e --- /dev/null +++ b/freespacenotifier/module.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE Project + Copyright (c) 2006 Lukas Tinkl + Copyright (c) 2008 Lubos Lunak + Copyright (c) 2009 Ivo Anjo + + 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, see . +*/ + +#ifndef MODULE_H +#define MODULE_H + +#include +#include +#include + +#include "freespacenotifier.h" + +class FreeSpaceNotifierModule + : public KDEDModule + { + Q_OBJECT + public: + FreeSpaceNotifierModule(QObject* parent, const QList&); + private: + FreeSpaceNotifier notifier; + }; + +#endif diff --git a/freespacenotifier/settings.kcfgc b/freespacenotifier/settings.kcfgc new file mode 100644 index 00000000..3997ce98 --- /dev/null +++ b/freespacenotifier/settings.kcfgc @@ -0,0 +1,6 @@ +# Code generation options for kconfig_compiler +File=freespacenotifier.kcfg +ClassName=FreeSpaceNotifierSettings +Singleton=true +Mutators=minimumSpace,enableNotification +# will create the necessary code for setting those variables diff --git a/kcheckpass/CMakeLists.txt b/kcheckpass/CMakeLists.txt new file mode 100644 index 00000000..375e4f8e --- /dev/null +++ b/kcheckpass/CMakeLists.txt @@ -0,0 +1,31 @@ + +include_directories( ${UNIXAUTH_INCLUDE_DIRS} ) +check_include_files(paths.h HAVE_PATHS_H) +configure_file (config-kcheckpass.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kcheckpass.h ) + +set(kcheckpass_SRCS + kcheckpass.h + kcheckpass.c + checkpass_etcpasswd.c + checkpass_pam.c + checkpass_shadow.c + checkpass_osfc2passwd.c + checkpass_aix.c +) + +kde4_add_executable(kcheckpass NOGUI ${kcheckpass_SRCS}) + +if (KDE4_ENABLE_FPIE) + macro_add_compile_flags(kcheckpass ${KDE4_CXX_FPIE_FLAGS}) + macro_add_link_flags(kcheckpass ${KDE4_PIE_LDFLAGS}) +endif (KDE4_ENABLE_FPIE) + +macro_add_compile_flags(kcheckpass -U_REENTRANT) +target_link_libraries(kcheckpass ${KDE4_KDEFAKES_LIBS} ${UNIXAUTH_LIBRARIES} ${SOCKET_LIBRARIES}) +install(TARGETS kcheckpass DESTINATION ${LIBEXEC_INSTALL_DIR}) +install(CODE " + set(KCP_PATH \"\$ENV{DESTDIR}${LIBEXEC_INSTALL_DIR}/kcheckpass\") + EXECUTE_PROCESS(COMMAND sh -c \"chown root '\${KCP_PATH}' && chmod +s '\${KCP_PATH}'\") +") + +#EXTRA_DIST = README diff --git a/kcheckpass/README b/kcheckpass/README new file mode 100644 index 00000000..ba7cb471 --- /dev/null +++ b/kcheckpass/README @@ -0,0 +1,50 @@ +The KCheckPass authentication software: +----------------------------------------- + +KCheckPass is KDE's authentication program. It is meant to be +used by any software in need of user authentication, most +notably screensavers. + +It enhances security be the following means: + +- It's only a small program, which is hopefully simple enough to + allow it to be SUID root. Setting it to SUID root is necessary + on Shadow Password systems. +- No other program in need of user authentication, must be + SUID root. +- It provides a single implementation to check passwords. So one + only must take a closer look at KCheckPass to ensure password + security. It's much easier for programs using KCheckPass to + preserve security. + + +Technique: +---------- +KCheckPass is a simple password checker. Just invoke and +send it the password on stdin. + +If the password was accepted, the program exits with 0; +if it was rejected, it exits with 1. Any other exit +code signals an error. + + + +Compilation hints: +------------------ +Compile with -DHAVE_VSYSLOG if you have vsyslog(). +Compile with -DHAVE_PAM if you have a PAM system, and link with -lpam -ldl + (If libdl is present). +Compile with -DHAVE_SHADOW if you have a shadow password system. + +Copyright, Author and License notice: +------------------------------------- +Copyright (C) 1998, Caldera, Inc. +Released under the GNU General Public License + +Olaf Kirch General Framework and PAM support +Christian Esken Shadow and /etc/passwd support + +Some parts were taken from kscreensaver's passwd.cpp + +Currently this Software is maintained by Oswald Buddenhagen . +Please send new authentication modules (checkpass_*.cpp) to me. diff --git a/kcheckpass/checkpass_aix.c b/kcheckpass/checkpass_aix.c new file mode 100644 index 00000000..8f06cfe6 --- /dev/null +++ b/kcheckpass/checkpass_aix.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2001 Reza Arbab + * Copyright (c) 2003 Oswald Buddenhagen + * + * 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 "kcheckpass.h" + +#ifdef HAVE_AIX_AUTH +#include +#include +#include +#include + +/* + * The AIX builtin authenticate() uses whichever method the system + * has been configured for. (/etc/passwd, DCE, etc.) + */ +int authenticate(const char *, const char *, int *, char **); + +AuthReturn Authenticate(const char *method, + const char *login, char *(*conv) (ConvRequest, const char *)) +{ + int result; + int reenter; /* Tells if authenticate is done processing or not. */ + char *passwd; + char *msg; /* Contains a prompt message or failure reason. */ + + if (!strcmp(method, "classic")) { + + if (!(passwd = conv(ConvGetHidden, 0))) + return AuthAbort; + + if ((result = authenticate(login, passwd, &reenter, &msg))) { + if (msg) { + conv(ConvPutError, msg); + free(msg); + } + dispose(passwd); + return AuthBad; + } + if (reenter) { + char buf[256]; + snprintf(buf, sizeof(buf), "More authentication data requested: %s\n", msg); + conv(ConvPutError, buf); + free(msg); + dispose(passwd); + return result == ENOENT || result == ESAD ? AuthBad : AuthError; + } + dispose(passwd); + return AuthOk; + + } else if (!strcmp(method, "generic")) { + + for (passwd = 0;;) { + if ((result = authenticate(login, passwd, &reenter, &msg))) { + if (msg) { + conv(ConvPutError, msg); + free(msg); + } + if (passwd) + dispose(passwd); + return result == ENOENT || result == ESAD ? AuthBad : AuthError; + } + if (passwd) + dispose(passwd); + if (!reenter) + break; + passwd = conv(ConvGetHidden, msg); + free(msg); + if (!passwd) + return AuthAbort; + } + return AuthOk; + + } else + return AuthError; + +} + +#endif diff --git a/kcheckpass/checkpass_etcpasswd.c b/kcheckpass/checkpass_etcpasswd.c new file mode 100644 index 00000000..e261b7c4 --- /dev/null +++ b/kcheckpass/checkpass_etcpasswd.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1998 Christian Esken + * Copyright (c) 2003 Oswald Buddenhagen + * + * 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. + * + * Copyright (C) 1998, Christian Esken + */ + +#include "kcheckpass.h" + +#ifdef HAVE_ETCPASSWD + +/******************************************************************* + * This is the authentication code for /etc/passwd passwords + *******************************************************************/ + +#include +#include + +AuthReturn Authenticate(const char *method, + const char *login, char *(*conv) (ConvRequest, const char *)) +{ + struct passwd *pw; + char *passwd; + char *crpt_passwd; + + if (strcmp(method, "classic")) + return AuthError; + + /* Get the password entry for the user we want */ + if (!(pw = getpwnam(login))) + return AuthBad; + + if (!*pw->pw_passwd) + return AuthOk; + + if (!(passwd = conv(ConvGetHidden, 0))) + return AuthAbort; + + if ((crpt_passwd = crypt(passwd, pw->pw_passwd)) && !strcmp(pw->pw_passwd, crpt_passwd)) { + dispose(passwd); + return AuthOk; /* Success */ + } + dispose(passwd); + return AuthBad; /* Password wrong or account locked */ +} + +#endif diff --git a/kcheckpass/checkpass_osfc2passwd.c b/kcheckpass/checkpass_osfc2passwd.c new file mode 100644 index 00000000..d1812336 --- /dev/null +++ b/kcheckpass/checkpass_osfc2passwd.c @@ -0,0 +1,204 @@ +/* + * + * Copyright (C) 1999 Mark Davies + * Copyright (C) 2003 Oswald Buddenhagen + * + * 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 "kcheckpass.h" + +#ifdef HAVE_OSF_C2_PASSWD + +static char *osf1c2crypt(const char *pw, char *salt); +static int osf1c2_getprpwent(char *p, char *n, int len); + +/******************************************************************* + * This is the authentication code for OSF C2 security passwords + *******************************************************************/ + +#include +#include +#include + +AuthReturn Authenticate(const char *method, + const char *login, char *(*conv) (ConvRequest, const char *)) +{ + char *passwd; + char *crpt_passwd; + char c2passwd[256]; + + if (strcmp(method, "classic")) + return AuthError; + + if (!osf1c2_getprpwent(c2passwd, login, sizeof(c2passwd))) + return AuthBad; + + if (!*c2passwd) + return AuthOk; + + if (!(passwd = conv(ConvGetHidden, 0))) + return AuthAbort; + + if ((crpt_passwd = osf1c2crypt(passwd, c2passwd)) && !strcmp(c2passwd, crpt_passwd)) { + dispose(passwd); + return AuthOk; /* Success */ + } + dispose(passwd); + return AuthBad; /* Password wrong or account locked */ +} + + +/* +The following code was lifted from the file osfc2.c from the ssh 1.2.26 +distribution. Parts of the code that were not needed by kcheckpass +(notably the osf1c2_check_account_and_terminal() function and the code +to set the external variable days_before_password_expires have been +removed). The original copyright from the osfc2.c file is included +below. +*/ + +/* + +osfc2.c + +Author: Christophe Wolfhugel + +Copyright (c) 1995 Christophe Wolfhugel + +Free use of this file is permitted for any purpose as long as +this copyright is preserved in the header. + +This program implements the use of the OSF/1 C2 security extensions +within ssh. See the file COPYING for full licensing information. + +*/ + +#include +#include +#include + +static int c2security = -1; +static int crypt_algo; + +static void +initialize_osf_security(int ac, char **av) +{ + FILE *f; + char buf[256]; + char siad[] = "siad_ses_init="; + + if (access(SIAIGOODFILE, F_OK) == -1) + { + /* Broken OSF/1 system, better don't run on it. */ + fprintf(stderr, SIAIGOODFILE); + fprintf(stderr, " does not exist. Your OSF/1 system is probably broken\n"); + exit(1); + } + if ((f = fopen(MATRIX_CONF, "r")) == NULL) + { + /* Another way OSF/1 is probably broken. */ + fprintf(stderr, "%s unreadable. Your OSF/1 system is probably broken.\n" + + MATRIX_CONF); + exit(1); + } + + /* Read matrix.conf to check if we run C2 or not */ + while (fgets(buf, sizeof(buf), f) != NULL) + { + if (strncmp(buf, siad, sizeof(siad) - 1) == 0) + { + if (strstr(buf, "OSFC2") != NULL) + c2security = 1; + else if (strstr(buf, "BSD") != NULL) + c2security = 0; + break; + } + } + fclose(f); + if (c2security == -1) + { + fprintf(stderr, "C2 security initialization failed : could not determine security level.\n"); + exit(1); + } + if (c2security == 1) + set_auth_parameters(ac, av); +} + + +static int +osf1c2_getprpwent(char *p, char *n, int len) +{ + time_t pschg, tnow; + + if (c2security == 1) + { + struct es_passwd *es; + struct pr_passwd *pr = getprpwnam(n); + if (pr) + { + strlcpy(p, pr->ufld.fd_encrypt, len); + crypt_algo = pr->ufld.fd_oldcrypt; + + tnow = time(NULL); + if (pr->uflg.fg_schange == 1) + pschg = pr->ufld.fd_schange; + else + pschg = 0; + if (pr->uflg.fg_template == 0) + { + /** default template, system values **/ + if (pr->sflg.fg_lifetime == 1) + if (pr->sfld.fd_lifetime > 0 && + pschg + pr->sfld.fd_lifetime < tnow) + return 1; + } + else /** user template, specific values **/ + { + es = getespwnam(pr->ufld.fd_template); + if (es) + { + if (es->uflg->fg_expire == 1) + if (es->ufld->fd_expire > 0 && + pschg + es->ufld->fd_expire < tnow) + return 1; + } + } + } + } + else + { + struct passwd *pw = getpwnam(n); + if (pw) + { + strlcpy(p, pw->pw_passwd, len); + return 1; + } + } + return 0; +} + +static char * +osf1c2crypt(const char *pw, char *salt) +{ + if (c2security == 1) { + return(dispcrypt(pw, salt, crypt_algo)); + } else + return(crypt(pw, salt)); +} + +#endif diff --git a/kcheckpass/checkpass_pam.c b/kcheckpass/checkpass_pam.c new file mode 100644 index 00000000..e2ccaf24 --- /dev/null +++ b/kcheckpass/checkpass_pam.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 1998 Caldera, Inc. + * Copyright (C) 2003 Oswald Buddenhagen + * + * 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 "kcheckpass.h" + +#ifdef HAVE_PAM + +#include +#include +#include +#include + +#ifdef HAVE_PAM_PAM_APPL_H +#include +#else +#include +#endif + +struct pam_data { + char *(*conv) (ConvRequest, const char *); + int abort:1; + int classic:1; +}; + +#ifdef PAM_MESSAGE_CONST +typedef const struct pam_message pam_message_type; +typedef const void *pam_gi_type; +#else +typedef struct pam_message pam_message_type; +typedef void *pam_gi_type; +#endif + +static int +PAM_conv (int num_msg, pam_message_type **msg, + struct pam_response **resp, + void *appdata_ptr) +{ + int count; + struct pam_response *repl; + struct pam_data *pd = (struct pam_data *)appdata_ptr; + + if (!(repl = calloc(num_msg, sizeof(struct pam_response)))) + return PAM_CONV_ERR; + + for (count = 0; count < num_msg; count++) + switch (msg[count]->msg_style) { + case PAM_TEXT_INFO: + pd->conv(ConvPutInfo, msg[count]->msg); + break; + case PAM_ERROR_MSG: + pd->conv(ConvPutError, msg[count]->msg); + break; + default: + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: + repl[count].resp = pd->conv(ConvGetNormal, msg[count]->msg); + break; + case PAM_PROMPT_ECHO_OFF: + repl[count].resp = + pd->conv(ConvGetHidden, pd->classic ? 0 : msg[count]->msg); + break; +#ifdef PAM_BINARY_PROMPT + case PAM_BINARY_PROMPT: + repl[count].resp = pd->conv(ConvGetBinary, msg[count]->msg); + break; +#endif + default: + /* Must be an error of some sort... */ + goto conv_err; + } + if (!repl[count].resp) { + pd->abort = 1; + goto conv_err; + } + repl[count].resp_retcode = PAM_SUCCESS; + break; + } + *resp = repl; + return PAM_SUCCESS; + + conv_err: + for (; count >= 0; count--) + if (repl[count].resp) + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + dispose(repl[count].resp); + break; +#ifdef PAM_BINARY_PROMPT + case PAM_BINARY_PROMPT: /* handle differently? */ +#endif + case PAM_PROMPT_ECHO_ON: + free(repl[count].resp); + break; + } + free(repl); + return PAM_CONV_ERR; +} + +static struct pam_data PAM_data; + +static struct pam_conv PAM_conversation = { + &PAM_conv, + &PAM_data +}; + +#ifdef PAM_FAIL_DELAY +static void +fail_delay(int retval ATTR_UNUSED, unsigned usec_delay ATTR_UNUSED, + void *appdata_ptr ATTR_UNUSED) +{} +#endif + + +AuthReturn Authenticate(const char *caller, const char *method, + const char *user, char *(*conv) (ConvRequest, const char *)) +{ + const char *tty; + pam_handle_t *pamh; + pam_gi_type pam_item; + const char *pam_service; + char pservb[64]; + int pam_error; + + openlog("kcheckpass", LOG_PID, LOG_AUTH); + + PAM_data.conv = conv; + if (strcmp(method, "classic")) { + sprintf(pservb, "%.31s-%.31s", caller, method); + pam_service = pservb; + } else { + /* PAM_data.classic = 1; */ + pam_service = caller; + } + pam_error = pam_start(pam_service, user, &PAM_conversation, &pamh); + if (pam_error != PAM_SUCCESS) + return AuthError; + + tty = ttyname(0); + if (!tty) + tty = getenv ("DISPLAY"); + + pam_error = pam_set_item (pamh, PAM_TTY, tty); + if (pam_error != PAM_SUCCESS) { + pam_end(pamh, pam_error); + return AuthError; + } + +# ifdef PAM_FAIL_DELAY + pam_set_item (pamh, PAM_FAIL_DELAY, (void *)fail_delay); +# endif + + pam_error = pam_authenticate(pamh, 0); + if (pam_error != PAM_SUCCESS) { + if (PAM_data.abort) { + pam_end(pamh, PAM_SUCCESS); + return AuthAbort; + } + pam_end(pamh, pam_error); + switch (pam_error) { + case PAM_USER_UNKNOWN: + case PAM_AUTH_ERR: + case PAM_MAXTRIES: /* should handle this better ... */ + case PAM_AUTHINFO_UNAVAIL: /* returned for unknown users ... bogus */ + return AuthBad; + default: + return AuthError; + } + } + + /* just in case some module is stupid enough to ignore a preset PAM_USER */ + pam_error = pam_get_item (pamh, PAM_USER, &pam_item); + if (pam_error != PAM_SUCCESS) { + pam_end(pamh, pam_error); + return AuthError; + } + if (strcmp((const char *)pam_item, user)) { + pam_end(pamh, PAM_SUCCESS); /* maybe use PAM_AUTH_ERR? */ + return AuthBad; + } + + pam_error = pam_setcred(pamh, PAM_REFRESH_CRED); + /* ignore errors on refresh credentials. If this did not work we use the old ones. */ + + pam_end(pamh, PAM_SUCCESS); + return AuthOk; +} + +#endif diff --git a/kcheckpass/checkpass_shadow.c b/kcheckpass/checkpass_shadow.c new file mode 100644 index 00000000..c0f6913f --- /dev/null +++ b/kcheckpass/checkpass_shadow.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 1998 Christian Esken + * Copyright (C) 2003 Oswald Buddenhagen + * + * This is a modified version of checkpass_shadow.cpp + * + * Modifications made by Thorsten Kukuk + * Mathias Kettner + * + * ------------------------------------------------------------ + * + * 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 "kcheckpass.h" + +/******************************************************************* + * This is the authentication code for Shadow-Passwords + *******************************************************************/ + +#ifdef HAVE_SHADOW +#include +#include +#include + +#ifndef __hpux +#include +#endif + +AuthReturn Authenticate(const char *method, + const char *login, char *(*conv) (ConvRequest, const char *)) +{ + char *typed_in_password; + char *crpt_passwd; + char *password; + struct passwd *pw; + struct spwd *spw; + + if (strcmp(method, "classic")) + return AuthError; + + if (!(pw = getpwnam(login))) + return AuthAbort; + + spw = getspnam(login); + password = spw ? spw->sp_pwdp : pw->pw_passwd; + + if (!*password) + return AuthOk; + + if (!(typed_in_password = conv(ConvGetHidden, 0))) + return AuthAbort; + +#if defined( __linux__ ) && defined( HAVE_PW_ENCRYPT ) + crpt_passwd = pw_encrypt(typed_in_password, password); /* (1) */ +#else + crpt_passwd = crypt(typed_in_password, password); +#endif + + if (crpt_passwd && !strcmp(password, crpt_passwd )) { + dispose(typed_in_password); + return AuthOk; /* Success */ + } + dispose(typed_in_password); + return AuthBad; /* Password wrong or account locked */ +} + +/* + (1) Deprecated - long passwords have known weaknesses. Also, + pw_encrypt is non-standard (requires libshadow.a) while + everything else you need to support shadow passwords is in + the standard (ELF) libc. + */ +#endif diff --git a/kcheckpass/config-kcheckpass.h.cmake b/kcheckpass/config-kcheckpass.h.cmake new file mode 100644 index 00000000..a8a4ee50 --- /dev/null +++ b/kcheckpass/config-kcheckpass.h.cmake @@ -0,0 +1,3 @@ +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PATHS_H 1 + diff --git a/kcheckpass/kcheckpass-enums.h b/kcheckpass/kcheckpass-enums.h new file mode 100644 index 00000000..58387ff6 --- /dev/null +++ b/kcheckpass/kcheckpass-enums.h @@ -0,0 +1,70 @@ +/***************************************************************** + * + *· kcheckpass + * + *· Simple password checker. Just invoke and send it + *· the password on stdin. + * + *· If the password was accepted, the program exits with 0; + *· if it was rejected, it exits with 1. Any other exit + *· code signals an error. + * + * + * 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. + * + *· Copyright (C) 1998, Caldera, Inc. + *· Released under the GNU General Public License + * + *· Olaf Kirch General Framework and PAM support + *· Christian Esken Shadow and /etc/passwd support + *· Oswald Buddenhagen Binary server mode + * + * Other parts were taken from kscreensaver's passwd.cpp + *****************************************************************/ + +#ifndef KCHECKPASS_ENUMS_H +#define KCHECKPASS_ENUMS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* these must match kcheckpass' exit codes */ +typedef enum { + AuthOk = 0, + AuthBad = 1, + AuthError = 2, + AuthAbort = 3 +} AuthReturn; + +typedef enum { + ConvGetBinary, + ConvGetNormal, + ConvGetHidden, + ConvPutInfo, + ConvPutError +} ConvRequest; + +/* these must match the defs in kgreeterplugin.h */ +typedef enum { + IsUser = 1, /* unused in kcheckpass */ + IsPassword = 2 +} DataTag; + +#ifdef __cplusplus +} +#endif + +#endif /* KCHECKPASS_ENUMS_H */ diff --git a/kcheckpass/kcheckpass.c b/kcheckpass/kcheckpass.c new file mode 100644 index 00000000..fd2d2215 --- /dev/null +++ b/kcheckpass/kcheckpass.c @@ -0,0 +1,458 @@ +/***************************************************************** + * + * kcheckpass - Simple password checker + * + * 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. + * + * + * kcheckpass is a simple password checker. Just invoke and + * send it the password on stdin. + * + * If the password was accepted, the program exits with 0; + * if it was rejected, it exits with 1. Any other exit + * code signals an error. + * + * It's hopefully simple enough to allow it to be setuid + * root. + * + * Compile with -DHAVE_VSYSLOG if you have vsyslog(). + * Compile with -DHAVE_PAM if you have a PAM system, + * and link with -lpam -ldl. + * Compile with -DHAVE_SHADOW if you have a shadow + * password system. + * + * Copyright (C) 1998, Caldera, Inc. + * Released under the GNU General Public License + * + * Olaf Kirch General Framework and PAM support + * Christian Esken Shadow and /etc/passwd support + * Roberto Teixeira other user (-U) support + * Oswald Buddenhagen Binary server mode + * + * Other parts were taken from kscreensaver's passwd.cpp. + * + *****************************************************************/ + +#include "kcheckpass.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Compatibility: accept some options from environment variables */ +#define ACCEPT_ENV + +#define THROTTLE 3 + +static int havetty, sfd = -1, nullpass; + +static char * +conv_legacy (ConvRequest what, const char *prompt) +{ + char *p, *p2; + int len; + char buf[1024]; + + switch (what) { + case ConvGetBinary: + break; + case ConvGetNormal: + /* there is no prompt == 0 case */ + if (!havetty) + break; + /* i guess we should use /dev/tty ... */ + fputs(prompt, stdout); + fflush(stdout); + if (!fgets(buf, sizeof(buf), stdin)) + return 0; + len = strlen(buf); + if (len && buf[len - 1] == '\n') + buf[--len] = 0; + return strdup(buf); + case ConvGetHidden: + if (havetty) { +#ifdef HAVE_GETPASSPHRASE + p = getpassphrase(prompt ? prompt : "Password: "); +#else + p = getpass(prompt ? prompt : "Password: "); +#endif + p2 = strdup(p); + memset(p, 0, strlen(p)); + return p2; + } else { + if (prompt) + break; + if ((len = read(0, buf, sizeof(buf) - 1)) < 0) { + message("Cannot read password\n"); + return 0; + } else { + if (len && buf[len - 1] == '\n') + --len; + buf[len] = 0; + p2 = strdup(buf); + memset(buf, 0, len); + return p2; + } + } + case ConvPutInfo: + message("Information: %s\n", prompt); + return 0; + case ConvPutError: + message("Error: %s\n", prompt); + return 0; + } + message("Authentication backend requested data type which cannot be handled.\n"); + return 0; +} + + +static int +Reader (void *buf, int count) +{ + int ret, rlen; + + for (rlen = 0; rlen < count; ) { + dord: + ret = read (sfd, (void *)((char *)buf + rlen), count - rlen); + if (ret < 0) { + if (errno == EINTR) + goto dord; + if (errno == EAGAIN) + break; + return -1; + } + if (!ret) + break; + rlen += ret; + } + return rlen; +} + +static void +GRead (void *buf, int count) +{ + if (Reader (buf, count) != count) { + message ("Communication breakdown on read\n"); + exit(15); + } +} + +static void +GWrite (const void *buf, int count) +{ + if (write (sfd, buf, count) != count) { + message ("Communication breakdown on write\n"); + exit(15); + } +} + +static void +GSendInt (int val) +{ + GWrite (&val, sizeof(val)); +} + +static void +GSendStr (const char *buf) +{ + unsigned len = buf ? strlen (buf) + 1 : 0; + GWrite (&len, sizeof(len)); + GWrite (buf, len); +} + +static void +GSendArr (int len, const char *buf) +{ + GWrite (&len, sizeof(len)); + GWrite (buf, len); +} + +static int +GRecvInt (void) +{ + int val; + + GRead (&val, sizeof(val)); + return val; +} + +static char * +GRecvStr (void) +{ + unsigned len; + char *buf; + + if (!(len = GRecvInt())) + return (char *)0; + if (len > 0x1000 || !(buf = malloc (len))) { + message ("No memory for read buffer\n"); + exit(15); + } + GRead (buf, len); + buf[len - 1] = 0; /* we're setuid ... don't trust "them" */ + return buf; +} + +static char * +GRecvArr (void) +{ + unsigned len; + char *arr; + unsigned const char *up; + + if (!(len = (unsigned) GRecvInt())) + return (char *)0; + if (len < 4) { + message ("Too short binary authentication data block\n"); + exit(15); + } + if (len > 0x10000 || !(arr = malloc (len))) { + message ("No memory for read buffer\n"); + exit(15); + } + GRead (arr, len); + up = (unsigned const char *)arr; + if (len != (unsigned)(up[3] | (up[2] << 8) | (up[1] << 16) | (up[0] << 24))) { + message ("Mismatched binary authentication data block size\n"); + exit(15); + } + return arr; +} + + +static char * +conv_server (ConvRequest what, const char *prompt) +{ + GSendInt (what); + switch (what) { + case ConvGetBinary: + { + unsigned const char *up = (unsigned const char *)prompt; + int len = up[3] | (up[2] << 8) | (up[1] << 16) | (up[0] << 24); + GSendArr (len, prompt); + return GRecvArr (); + } + case ConvGetNormal: + case ConvGetHidden: + { + char *msg; + GSendStr (prompt); + msg = GRecvStr (); + if (msg && (GRecvInt() & IsPassword) && !*msg) + nullpass = 1; + return msg; + } + case ConvPutInfo: + case ConvPutError: + default: + GSendStr (prompt); + return 0; + } +} + +void +message(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +#endif + +static void ATTR_NORETURN +usage(int exitval) +{ + message( + "usage: kcheckpass {-h|[-c caller] [-m method] [-U username|-S handle]}\n" + " options:\n" + " -h this help message\n" + " -U username authenticate the specified user instead of current user\n" + " -S handle operate in binary server mode on file descriptor handle\n" + " -c caller the calling application, effectively the PAM service basename\n" + " -m method use the specified authentication method (default: \"classic\")\n" + " exit codes:\n" + " 0 success\n" + " 1 invalid password\n" + " 2 cannot read password database\n" + " Anything else tells you something's badly hosed.\n" + ); + exit(exitval); +} + +int +main(int argc, char **argv) +{ +#ifdef HAVE_PAM + const char *caller = KSCREENSAVER_PAM_SERVICE; +#endif + const char *method = "classic"; + const char *username = 0; +#ifdef ACCEPT_ENV + char *p; +#endif + struct passwd *pw; + int c, nfd, lfd; + uid_t uid; + time_t nexttime; + AuthReturn ret; + struct flock lk; + char fname[64], fcont[64]; + +#ifdef HAVE_OSF_C2_PASSWD + initialize_osf_security(argc, argv); +#endif + + /* Make sure stdout/stderr are open */ + for (c = 1; c <= 2; c++) { + if (fcntl(c, F_GETFL) == -1) { + if ((nfd = open("/dev/null", O_WRONLY)) < 0) { + message("cannot open /dev/null: %s\n", strerror(errno)); + exit(10); + } + if (c != nfd) { + dup2(nfd, c); + close(nfd); + } + } + } + + havetty = isatty(0); + + while ((c = getopt(argc, argv, "hc:m:U:S:")) != -1) { + switch (c) { + case 'h': + usage(0); + break; + case 'c': +#ifdef HAVE_PAM + caller = optarg; +#endif + break; + case 'm': + method = optarg; + break; + case 'U': + username = optarg; + break; + case 'S': + sfd = atoi(optarg); + break; + default: + message("Command line option parsing error\n"); + usage(10); + } + } + +#ifdef ACCEPT_ENV +# ifdef HAVE_PAM + if ((p = getenv("KDE_PAM_ACTION"))) + caller = p; +# endif + if ((p = getenv("KCHECKPASS_USER"))) + username = p; +#endif + + uid = getuid(); + if (!username) { + if (!(p = getenv("LOGNAME")) || !(pw = getpwnam(p)) || pw->pw_uid != uid) + if (!(p = getenv("USER")) || !(pw = getpwnam(p)) || pw->pw_uid != uid) + if (!(pw = getpwuid(uid))) { + message("Cannot determinate current user\n"); + return AuthError; + } + if (!(username = strdup(pw->pw_name))) { + message("Out of memory\n"); + return AuthError; + } + } + + /* + * Throttle kcheckpass invocations to avoid abusing it for bruteforcing + * the password. This delay belongs to the *previous* invocation, where + * we can't enforce it reliably (without risking giving away the result + * before it is due). We don't differentiate between success and failure - + * it's not expected to have a noticeable adverse effect. + */ + if ( uid != geteuid() ) { + sprintf(fname, "/var/run/kcheckpass.%d", uid); + if ((lfd = open(fname, O_RDWR | O_CREAT | O_NOFOLLOW, 0600)) < 0) { + message("Cannot open lockfile\n"); + return AuthError; + } + + lk.l_type = F_WRLCK; + lk.l_whence = SEEK_SET; + lk.l_start = lk.l_len = 0; + if (fcntl(lfd, F_SETLKW, &lk)) { + message("Cannot obtain lock\n"); + return AuthError; + } + + if ((c = read(lfd, fcont, sizeof(fcont)-1)) > 0 && + (fcont[c] = '\0', sscanf(fcont, "%ld", &nexttime) == 1)) + { + time_t ct = time(0); + if (nexttime > ct && nexttime < ct + THROTTLE) + sleep(nexttime - ct); + } + + lseek(lfd, 0, SEEK_SET); + write(lfd, fcont, sprintf(fcont, "%lu\n", time(0) + THROTTLE)); + + close(lfd); + } + + /* Now do the fandango */ + ret = Authenticate( +#ifdef HAVE_PAM + caller, +#endif + method, + username, + sfd < 0 ? conv_legacy : conv_server); + + if (ret == AuthBad) { + message("Authentication failure\n"); + if (!nullpass) { + openlog("kcheckpass", LOG_PID, LOG_AUTH); + syslog(LOG_NOTICE, "Authentication failure for %s (invoked by uid %d)", username, uid); + } + } + + return ret; +} + +void +dispose(char *str) +{ + memset(str, 0, strlen(str)); + free(str); +} + +/***************************************************************** + The real authentication methods are in separate source files. + Look in checkpass_*.c +*****************************************************************/ diff --git a/kcheckpass/kcheckpass.h b/kcheckpass/kcheckpass.h new file mode 100644 index 00000000..d75341c8 --- /dev/null +++ b/kcheckpass/kcheckpass.h @@ -0,0 +1,123 @@ +/***************************************************************** + * + * kcheckpass + * + * Simple password checker. Just invoke and send it + * the password on stdin. + * + * If the password was accepted, the program exits with 0; + * if it was rejected, it exits with 1. Any other exit + * code signals an error. + * + * + * 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. + * + * Copyright (C) 1998, Caldera, Inc. + * Released under the GNU General Public License + * + * Olaf Kirch General Framework and PAM support + * Christian Esken Shadow and /etc/passwd support + * Oswald Buddenhagen Binary server mode + * + * Other parts were taken from kscreensaver's passwd.cpp + *****************************************************************/ + +#ifndef KCHECKPASS_H_ +#define KCHECKPASS_H_ + +#include +#include +#include + +#ifdef HAVE_CRYPT_H +#include +#endif + +#ifdef HAVE_PATHS_H +#include +#endif + +#include +#include + +#ifndef _PATH_TMP +#define _PATH_TMP "/tmp/" +#endif + + +#ifdef ultrix +#include +#endif + +#include + +#ifdef OSF1_ENH_SEC +#include +#include +#endif + +/* Make sure there is only one! */ +#if defined(HAVE_PAM) +# undef HAVE_OSF_C2_PASSWD +#elif defined(HAVE_OSF_C2_PASSWD) +#elif defined(_AIX) +# define HAVE_AIX_AUTH +#elif defined(HAVE_GETSPNAM) +# define HAVE_SHADOW +#else +# define HAVE_ETCPASSWD +#endif + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +# define ATTR_UNUSED __attribute__((unused)) +# define ATTR_NORETURN __attribute__((noreturn)) +# define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) +#else +# define ATTR_UNUSED +# define ATTR_NORETURN +# define ATTR_PRINTFLIKE(fmt,var) +#endif + +#include "kcheckpass-enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************** + * Authenticates user + *****************************************************************/ +AuthReturn Authenticate( +#ifdef HAVE_PAM + const char *caller, +#endif + const char *method, + const char *user, + char *(*conv) (ConvRequest, const char *)); + +/***************************************************************** + * Output a message to stderr + *****************************************************************/ +void message(const char *, ...) ATTR_PRINTFLIKE(1, 2); + +/***************************************************************** + * Overwrite and free the passed string + *****************************************************************/ +void dispose(char *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/kcminit/CMakeLists.txt b/kcminit/CMakeLists.txt new file mode 100644 index 00000000..029990c1 --- /dev/null +++ b/kcminit/CMakeLists.txt @@ -0,0 +1,26 @@ +########### next target ############### + +set(kcminit_KDEINIT_SRCS main.cpp) + + +kde4_add_kdeinit_executable( kcminit ${kcminit_KDEINIT_SRCS}) + +target_link_libraries(kdeinit_kcminit ${KDE4_KCMUTILS_LIBS} ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES}) + +install(TARGETS kdeinit_kcminit ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install(TARGETS kcminit ${INSTALL_TARGETS_DEFAULT_ARGS} ) + +########### next target ############### + +# TODO might be simpler to make _startup to be a symlink to + +set(kcminit_startup_KDEINIT_SRCS main.cpp) + + +kde4_add_kdeinit_executable( kcminit_startup ${kcminit_startup_KDEINIT_SRCS}) + +target_link_libraries(kdeinit_kcminit_startup ${KDE4_KCMUTILS_LIBS} ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES}) + +install(TARGETS kdeinit_kcminit_startup ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install(TARGETS kcminit_startup ${INSTALL_TARGETS_DEFAULT_ARGS} ) + diff --git a/kcminit/Messages.sh b/kcminit/Messages.sh new file mode 100755 index 00000000..59f7b2dd --- /dev/null +++ b/kcminit/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kcminit.pot diff --git a/kcminit/main.cpp b/kcminit/main.cpp new file mode 100644 index 00000000..856d8b74 --- /dev/null +++ b/kcminit/main.cpp @@ -0,0 +1,270 @@ +/* + Copyright (c) 1999 Matthias Hoelzer-Kluepfel + + 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 "main.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef Q_WS_X11 +#include +#include +#endif + +#include +#include + +static int ready[ 2 ]; +static bool startup = false; + +static void sendReady() +{ + if( ready[ 1 ] == -1 ) + return; + char c = 0; + write( ready[ 1 ], &c, 1 ); + close( ready[ 1 ] ); + ready[ 1 ] = -1; +} + +static void waitForReady() +{ + char c = 1; + close( ready[ 1 ] ); + read( ready[ 0 ], &c, 1 ); + close( ready[ 0 ] ); +} + +bool KCMInit::runModule(const QString &libName, KService::Ptr service) +{ + KLibrary lib(libName); + if (lib.load()) { + QVariant tmp = service->property("X-KDE-Init-Symbol", QVariant::String); + QString kcminit; + if( tmp.isValid() ) + { + kcminit = tmp.toString(); + if( !kcminit.startsWith( QLatin1String( "kcminit_" ) ) ) + kcminit = "kcminit_" + kcminit; + } + else + kcminit = "kcminit_" + libName; + + // get the kcminit_ function + KLibrary::void_function_ptr init = lib.resolveFunction(kcminit.toUtf8()); + if (init) { + // initialize the module + kDebug(1208) << "Initializing " << libName << ": " << kcminit; + + void (*func)() = (void(*)())init; + func(); + return true; + } else { + kDebug(1208) << "Module" << libName << "does not actually have a kcminit function"; + } + } + return false; +} + +void KCMInit::runModules( int phase ) +{ + for(KService::List::Iterator it = list.begin(); + it != list.end(); + ++it) { + KService::Ptr service = (*it); + + QVariant tmp = service->property("X-KDE-Init-Library", QVariant::String); + QString library; + if( tmp.isValid() ) + { + library = tmp.toString(); + if( !library.startsWith( QLatin1String( "kcminit_" ) ) ) + library = QLatin1String( "kcminit_" ) + library; + } + else + { + library = service->library(); + } + + if (library.isEmpty()) + continue; // Skip + + // see ksmserver's README for the description of the phases + QVariant vphase = service->property("X-KDE-Init-Phase", QVariant::Int ); + int libphase = 1; + if( vphase.isValid() ) + libphase = vphase.toInt(); + + if( phase != -1 && libphase != phase ) + continue; + + // try to load the library + if (!alreadyInitialized.contains(library)) { + runModule(library, service); + alreadyInitialized.append(library); + } + } +} + +KCMInit::KCMInit( KCmdLineArgs* args ) +{ + QDBusConnection::sessionBus().registerObject("/kcminit", this, + QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportScriptableSignals); + QString arg; + if (args->count() == 1) { + arg = args->arg(0); + } + + if (args->isSet("list")) + { + list = KServiceTypeTrader::self()->query( "KCModuleInit" ); + + for(KService::List::Iterator it = list.begin(); + it != list.end(); + ++it) + { + KService::Ptr service = (*it); + if (service->library().isEmpty()) + continue; // Skip + printf("%s\n", QFile::encodeName(service->desktopEntryName()).data()); + } + return; + } + + if (!arg.isEmpty()) { + + QString module = arg; + if (!module.endsWith(".desktop")) + module += ".desktop"; + + KService::Ptr serv = KService::serviceByStorageId( module ); + if ( !serv || serv->library().isEmpty() ) { + kError(1208) << i18n("Module %1 not found", module) << endl; + return; + } else + list.append(serv); + + } else { + + // locate the desktop files + list = KServiceTypeTrader::self()->query( "KCModuleInit" ); + + } + // This key has no GUI apparently + KConfig _config( "kcmdisplayrc" ); + KConfigGroup config(&_config, "X11"); +#ifdef Q_WS_X11 + bool multihead = !config.readEntry( "disableMultihead", false) && + (ScreenCount(QX11Info::display()) > 1); +#else + bool multihead = false; +#endif + // Pass env. var to kdeinit. + QString name = "KDE_MULTIHEAD"; + QString value = multihead ? "true" : "false"; + KToolInvocation::klauncher()->setLaunchEnv(name, value); + setenv( name.toLatin1().constData(), value.toLatin1().constData(), 1 ); // apply effect also to itself + + if( startup ) + { + runModules( 0 ); + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.message_type = XInternAtom( QX11Info::display(), "_KDE_SPLASH_PROGRESS", False ); + e.xclient.display = QX11Info::display(); + e.xclient.window = QX11Info::appRootWindow(); + e.xclient.format = 8; + strcpy( e.xclient.data.b, "kcminit" ); + XSendEvent( QX11Info::display(), QX11Info::appRootWindow(), False, SubstructureNotifyMask, &e ); + sendReady(); + QTimer::singleShot( 300 * 1000, qApp, SLOT(quit())); // just in case + qApp->exec(); // wait for runPhase1() and runPhase2() + } + else + runModules( -1 ); // all phases +} + +KCMInit::~KCMInit() +{ + sendReady(); +} + +void KCMInit::runPhase1() +{ + runModules( 1 ); + emit phase1Done(); +} + +void KCMInit::runPhase2() +{ + runModules( 2 ); + emit phase2Done(); + qApp->exit( 0 ); +} + +extern "C" KDE_EXPORT int kdemain(int argc, char *argv[]) +{ + // kdeinit waits for kcminit to finish, but during KDE startup + // only important kcm's are started very early in the login process, + // the rest is delayed, so fork and make parent return after the initial phase + pipe( ready ); + if( fork() != 0 ) + { + waitForReady(); + return 0; + } + close( ready[ 0 ] ); + + startup = ( strcmp( argv[ 0 ], "kcminit_startup" ) == 0 ); // started from startkde? + KAboutData aboutData( "kcminit", "kcminit", ki18n("KCMInit"), + "", + ki18n("KCMInit - runs startup initialization for Control Modules.")); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("list", ki18n("List modules that are run at startup")); + options.add("+module", ki18n("Configuration module to run")); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + KApplication app; + QDBusConnection::sessionBus().interface()->registerService( "org.kde.kcminit", + QDBusConnectionInterface::DontQueueService ); + KLocale::setMainCatalog(0); + KCMInit kcminit( KCmdLineArgs::parsedArgs()); + return 0; +} + +#include "main.moc" diff --git a/kcminit/main.h b/kcminit/main.h new file mode 100644 index 00000000..51358bb4 --- /dev/null +++ b/kcminit/main.h @@ -0,0 +1,47 @@ +/* + Copyright (c) 1999 Matthias Hoelzer-Kluepfel + + 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 + +#include + +class KCmdLineArgs; + +class KCMInit : public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.KCMInit") + public Q_SLOTS: //dbus + Q_SCRIPTABLE void runPhase1(); + Q_SCRIPTABLE void runPhase2(); + Q_SIGNALS: //dbus signal + Q_SCRIPTABLE void phase1Done(); + Q_SCRIPTABLE void phase2Done(); + public: + KCMInit( KCmdLineArgs* args ); + virtual ~KCMInit(); + private: + bool runModule(const QString &libName, KService::Ptr service); + void runModules( int phase ); + KService::List list; + QStringList alreadyInitialized; +}; + +#endif // MAIN_H diff --git a/kcontrol/CMakeLists.txt b/kcontrol/CMakeLists.txt new file mode 100644 index 00000000..fc666b11 --- /dev/null +++ b/kcontrol/CMakeLists.txt @@ -0,0 +1,52 @@ + +macro_optional_find_package(Freetype) +set_package_properties(Freetype PROPERTIES DESCRIPTION "A font rendering engine" + URL "http://www.freetype.org" + TYPE OPTIONAL + PURPOSE "Needed to build kfontinst, a simple font installer." + ) + + +set(libkxftconfig_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/fonts/kxftconfig.cpp ) + + +if( X11_Xrandr_FOUND ) + add_subdirectory( randr ) +endif(X11_Xrandr_FOUND ) + +if(X11_Xkb_FOUND) + add_subdirectory( keyboard ) +endif(X11_Xkb_FOUND) + +if(NOT WIN32) +add_subdirectory( bell ) +add_subdirectory( input ) +add_subdirectory( access ) +add_subdirectory( screensaver ) +add_subdirectory( dateandtime ) +add_subdirectory( autostart ) +endif(NOT WIN32) + +add_subdirectory( launch ) +add_subdirectory( colors ) +add_subdirectory( krdb ) +add_subdirectory( style ) +add_subdirectory( desktoptheme ) +add_subdirectory( standard_actions ) +add_subdirectory( keys ) +add_subdirectory( workspaceoptions ) + +# TODO needs porting +#add_subdirectory( smartcard ) + +add_subdirectory( hardware ) +add_subdirectory( desktoppaths ) + +if( FREETYPE_FOUND ) + if( WIN32 OR FONTCONFIG_FOUND ) + add_subdirectory( fonts ) + endif( WIN32 OR FONTCONFIG_FOUND ) +endif( FREETYPE_FOUND ) +if(FONTCONFIG_FOUND AND FREETYPE_FOUND AND NOT WIN32) + add_subdirectory( kfontinst ) +endif(FONTCONFIG_FOUND AND FREETYPE_FOUND AND NOT WIN32) diff --git a/kcontrol/PURPOSE b/kcontrol/PURPOSE new file mode 100644 index 00000000..ef03e579 --- /dev/null +++ b/kcontrol/PURPOSE @@ -0,0 +1,10 @@ +System Settings is: +-Desktop Configuration +-User System Configuration + +System Settings is not: +-Application Configuration +-System Administration/Configuration +-Tools/Utilities + +On other environments the already provided equivalent should be used. In KDE the other environment equivalents should not be needed. diff --git a/kcontrol/access/CMakeLists.txt b/kcontrol/access/CMakeLists.txt new file mode 100644 index 00000000..1fbcd78a --- /dev/null +++ b/kcontrol/access/CMakeLists.txt @@ -0,0 +1,33 @@ + + + +########### next target ############### + +set(kcm_access_PART_SRCS kcmaccess.cpp ) + + +kde4_add_plugin(kcm_access ${kcm_access_PART_SRCS}) + + +target_link_libraries(kcm_access ${KDE4_KIO_LIBS} ${KDE4_PHONON_LIBS} ${KDE4_KNOTIFYCONFIG_LIBS} ${X11_LIBRARIES}) + +install(TARGETS kcm_access DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### next target ############### + +set(kaccess_KDEINIT_SRCS kaccess.cpp main.cpp ) + + +kde4_add_kdeinit_executable( kaccess ${kaccess_KDEINIT_SRCS}) + +target_link_libraries(kdeinit_kaccess ${KDE4_KDEUI_LIBS} ${KDE4_PHONON_LIBS} ${X11_LIBRARIES}) + +install(TARGETS kdeinit_kaccess ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install(TARGETS kaccess ${INSTALL_TARGETS_DEFAULT_ARGS} ) + +########### install files ############### + +install( FILES kcmaccess.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES kaccess.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES kaccess.notifyrc DESTINATION ${DATA_INSTALL_DIR}/kaccess/ ) diff --git a/kcontrol/access/Messages.sh b/kcontrol/access/Messages.sh new file mode 100644 index 00000000..3834cc09 --- /dev/null +++ b/kcontrol/access/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +### TODO: why do we need 2 POT files for a single directory? +$XGETTEXT kaccess.cpp main.cpp rc.cpp -o $podir/kaccess.pot +$XGETTEXT kcmaccess.cpp rc.cpp -o $podir/kcmaccess.pot diff --git a/kcontrol/access/kaccess.cpp b/kcontrol/access/kaccess.cpp new file mode 100644 index 00000000..24beed3d --- /dev/null +++ b/kcontrol/access/kaccess.cpp @@ -0,0 +1,918 @@ +#include + + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#define XK_MISCELLANY +#define XK_XKB_KEYS +#include + + +#include "kaccess.moc" +#include +#include + +struct ModifierKey { + const unsigned int mask; + const KeySym keysym; + const char *name; + const char *lockedText; + const char *latchedText; + const char *unlatchedText; +}; + +static ModifierKey modifierKeys[] = { + { ShiftMask, 0, "Shift", + I18N_NOOP("The Shift key has been locked and is now active for all of the following keypresses."), + I18N_NOOP("The Shift key is now active."), + I18N_NOOP("The Shift key is now inactive.") }, + { ControlMask, 0, "Control", + I18N_NOOP("The Control key has been locked and is now active for all of the following keypresses."), + I18N_NOOP("The Control key is now active."), + I18N_NOOP("The Control key is now inactive.") }, + { 0, XK_Alt_L, "Alt", + I18N_NOOP("The Alt key has been locked and is now active for all of the following keypresses."), + I18N_NOOP("The Alt key is now active."), + I18N_NOOP("The Alt key is now inactive.") }, + { 0, 0, "Win", + I18N_NOOP("The Win key has been locked and is now active for all of the following keypresses."), + I18N_NOOP("The Win key is now active."), + I18N_NOOP("The Win key is now inactive.") }, + { 0, XK_Meta_L, "Meta", + I18N_NOOP("The Meta key has been locked and is now active for all of the following keypresses."), + I18N_NOOP("The Meta key is now active."), + I18N_NOOP("The Meta key is now inactive.") }, + { 0, XK_Super_L, "Super", + I18N_NOOP("The Super key has been locked and is now active for all of the following keypresses."), + I18N_NOOP("The Super key is now active."), + I18N_NOOP("The Super key is now inactive.") }, + { 0, XK_Hyper_L, "Hyper", + I18N_NOOP("The Hyper key has been locked and is now active for all of the following keypresses."), + I18N_NOOP("The Hyper key is now active."), + I18N_NOOP("The Hyper key is now inactive.") }, + { 0, 0, "Alt Graph", + I18N_NOOP("The Alt Graph key has been locked and is now active for all of the following keypresses."), + I18N_NOOP("The Alt Graph key is now active."), + I18N_NOOP("The Alt Graph key is now inactive.") }, + { 0, XK_Num_Lock, "Num Lock", + I18N_NOOP("The Num Lock key has been activated."), + "", + I18N_NOOP("The Num Lock key is now inactive.") }, + { LockMask, 0, "Caps Lock", + I18N_NOOP("The Caps Lock key has been activated."), + "", + I18N_NOOP("The Caps Lock key is now inactive.") }, + { 0, XK_Scroll_Lock, "Scroll Lock", + I18N_NOOP("The Scroll Lock key has been activated."), + "", + I18N_NOOP("The Scroll Lock key is now inactive.") }, + { 0, 0, "", "", "", "" } +}; + + +/********************************************************************/ + + +KAccessApp::KAccessApp(bool allowStyles, bool GUIenabled) + : KUniqueApplication(allowStyles, GUIenabled), + overlay(0), _player(0) +{ + _activeWindow = KWindowSystem::activeWindow(); + connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(activeWindowChanged(WId))); + + features = 0; + requestedFeatures = 0; + dialog = 0; + + initMasks(); + XkbStateRec state_return; + XkbGetState (QX11Info::display(), XkbUseCoreKbd, &state_return); + unsigned char latched = XkbStateMods (&state_return); + unsigned char locked = XkbModLocks (&state_return); + state = ((int)locked)<<8 | latched; +} + +int KAccessApp::newInstance() +{ + KGlobal::config()->reparseConfiguration(); + readSettings(); + return 0; +} + +void KAccessApp::readSettings() +{ + KSharedConfig::Ptr _config = KGlobal::config(); + KConfigGroup cg(_config, "Bell"); + + // bell --------------------------------------------------------------- + _systemBell = cg.readEntry("SystemBell", true); + _artsBell = cg.readEntry("ArtsBell", false); + _currentPlayerSource = cg.readPathEntry("ArtsBellFile", QString()); + _visibleBell = cg.readEntry("VisibleBell", false); + _visibleBellInvert = cg.readEntry("VisibleBellInvert", false); + _visibleBellColor = cg.readEntry("VisibleBellColor", QColor(Qt::red)); + _visibleBellPause = cg.readEntry("VisibleBellPause", 500); + + // select bell events if we need them + int state = (_artsBell || _visibleBell) ? XkbBellNotifyMask : 0; + XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd, XkbBellNotifyMask, state); + + // deactivate system bell if not needed + if (!_systemBell) + XkbChangeEnabledControls(QX11Info::display(), XkbUseCoreKbd, XkbAudibleBellMask, 0); + else + XkbChangeEnabledControls(QX11Info::display(), XkbUseCoreKbd, XkbAudibleBellMask, XkbAudibleBellMask); + + // keyboard ------------------------------------------------------------- + KConfigGroup keyboardGroup(_config,"Keyboard"); + + // get keyboard state + XkbDescPtr xkb = XkbGetMap(QX11Info::display(), 0, XkbUseCoreKbd); + if (!xkb) + return; + if (XkbGetControls(QX11Info::display(), XkbAllControlsMask, xkb) != Success) + return; + + // sticky keys + if (keyboardGroup.readEntry("StickyKeys", false)) + { + if (keyboardGroup.readEntry("StickyKeysLatch", true)) + xkb->ctrls->ax_options |= XkbAX_LatchToLockMask; + else + xkb->ctrls->ax_options &= ~XkbAX_LatchToLockMask; + if (keyboardGroup.readEntry("StickyKeysAutoOff", false)) + xkb->ctrls->ax_options |= XkbAX_TwoKeysMask; + else + xkb->ctrls->ax_options &= ~XkbAX_TwoKeysMask; + if (keyboardGroup.readEntry("StickyKeysBeep", false)) + xkb->ctrls->ax_options |= XkbAX_StickyKeysFBMask; + else + xkb->ctrls->ax_options &= ~XkbAX_StickyKeysFBMask; + xkb->ctrls->enabled_ctrls |= XkbStickyKeysMask; + } + else + xkb->ctrls->enabled_ctrls &= ~XkbStickyKeysMask; + + // toggle keys + if (keyboardGroup.readEntry("ToggleKeysBeep", false)) + xkb->ctrls->ax_options |= XkbAX_IndicatorFBMask; + else + xkb->ctrls->ax_options &= ~XkbAX_IndicatorFBMask; + + // slow keys + if (keyboardGroup.readEntry("SlowKeys", false)) { + if (keyboardGroup.readEntry("SlowKeysPressBeep", false)) + xkb->ctrls->ax_options |= XkbAX_SKPressFBMask; + else + xkb->ctrls->ax_options &= ~XkbAX_SKPressFBMask; + if (keyboardGroup.readEntry("SlowKeysAcceptBeep", false)) + xkb->ctrls->ax_options |= XkbAX_SKAcceptFBMask; + else + xkb->ctrls->ax_options &= ~XkbAX_SKAcceptFBMask; + if (keyboardGroup.readEntry("SlowKeysRejectBeep", false)) + xkb->ctrls->ax_options |= XkbAX_SKRejectFBMask; + else + xkb->ctrls->ax_options &= ~XkbAX_SKRejectFBMask; + xkb->ctrls->enabled_ctrls |= XkbSlowKeysMask; + } + else + xkb->ctrls->enabled_ctrls &= ~XkbSlowKeysMask; + xkb->ctrls->slow_keys_delay = keyboardGroup.readEntry("SlowKeysDelay", 500); + + // bounce keys + if (keyboardGroup.readEntry("BounceKeys", false)) { + if (keyboardGroup.readEntry("BounceKeysRejectBeep", false)) + xkb->ctrls->ax_options |= XkbAX_BKRejectFBMask; + else + xkb->ctrls->ax_options &= ~XkbAX_BKRejectFBMask; + xkb->ctrls->enabled_ctrls |= XkbBounceKeysMask; + } + else + xkb->ctrls->enabled_ctrls &= ~XkbBounceKeysMask; + xkb->ctrls->debounce_delay = keyboardGroup.readEntry("BounceKeysDelay", 500); + + // gestures for enabling the other features + _gestures = keyboardGroup.readEntry("Gestures", false); + if (_gestures) + xkb->ctrls->enabled_ctrls |= XkbAccessXKeysMask; + else + xkb->ctrls->enabled_ctrls &= ~XkbAccessXKeysMask; + + // timeout + if (keyboardGroup.readEntry("AccessXTimeout", false)) + { + xkb->ctrls->ax_timeout = keyboardGroup.readEntry("AccessXTimeoutDelay", 30)*60; + xkb->ctrls->axt_opts_mask = 0; + xkb->ctrls->axt_opts_values = 0; + xkb->ctrls->axt_ctrls_mask = XkbStickyKeysMask | XkbSlowKeysMask; + xkb->ctrls->axt_ctrls_values = 0; + xkb->ctrls->enabled_ctrls |= XkbAccessXTimeoutMask; + } + else + xkb->ctrls->enabled_ctrls &= ~XkbAccessXTimeoutMask; + + // gestures for enabling the other features + if (keyboardGroup.readEntry("AccessXBeep", true)) + xkb->ctrls->ax_options |= XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask; + else + xkb->ctrls->ax_options &= ~(XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask); + + _gestureConfirmation = keyboardGroup.readEntry("GestureConfirmation", false); + + _kNotifyModifiers = keyboardGroup.readEntry("kNotifyModifiers", false); + _kNotifyAccessX = keyboardGroup.readEntry("kNotifyAccessX", false); + + // mouse-by-keyboard ---------------------------------------------- + + KConfigGroup mouseGroup(_config,"Mouse"); + + if (mouseGroup.readEntry("MouseKeys", false)) + { + xkb->ctrls->mk_delay = mouseGroup.readEntry("MKDelay", 160); + + // Default for initial velocity: 200 pixels/sec + int interval = mouseGroup.readEntry("MKInterval", 5); + xkb->ctrls->mk_interval = interval; + + // Default time to reach maximum speed: 5000 msec + xkb->ctrls->mk_time_to_max = mouseGroup.readEntry("MKTimeToMax", + (5000+interval/2)/interval); + + // Default maximum speed: 1000 pixels/sec + // (The old default maximum speed from KDE <= 3.4 + // (100000 pixels/sec) was way too fast) + xkb->ctrls->mk_max_speed = mouseGroup.readEntry("MKMaxSpeed", interval); + + xkb->ctrls->mk_curve = mouseGroup.readEntry("MKCurve", 0); + xkb->ctrls->mk_dflt_btn = mouseGroup.readEntry("MKDefaultButton", 0); + + xkb->ctrls->enabled_ctrls |= XkbMouseKeysMask; + } + else + xkb->ctrls->enabled_ctrls &= ~XkbMouseKeysMask; + + features = xkb->ctrls->enabled_ctrls & (XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask); + if (dialog == 0) + requestedFeatures = features; + // set state + XkbSetControls(QX11Info::display(), XkbControlsEnabledMask | XkbMouseKeysAccelMask | XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbAccessXKeysMask | XkbAccessXTimeoutMask, xkb); + + // select AccessX events + XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask); + + // do we need to stay running to perform notifications? + if (!_artsBell && !_visibleBell && !(_gestures && _gestureConfirmation) + && !_kNotifyModifiers && !_kNotifyAccessX) { + + // We will exit, but the features need to stay configured + uint ctrls = XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbMouseKeysMask | XkbAudibleBellMask | XkbControlsNotifyMask; + uint values = xkb->ctrls->enabled_ctrls & ctrls; + XkbSetAutoResetControls(QX11Info::display(), ctrls, &ctrls, &values); + exit(0); + } else { + // reset them after program exit + uint ctrls = XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbMouseKeysMask | XkbAudibleBellMask | XkbControlsNotifyMask; + uint values = XkbAudibleBellMask; + XkbSetAutoResetControls(QX11Info::display(), ctrls, &ctrls, &values); + } + + delete overlay; + overlay = 0; +} + +static int maskToBit (int mask) { + for (int i = 0; i < 8; i++) + if (mask & (1 << i)) + return i; + return -1; +} + +void KAccessApp::initMasks() { + for (int i = 0; i < 8; i++) + keys [i] = -1; + state = 0; + + for (int i = 0; strcmp (modifierKeys[i].name, "") != 0; i++) { + int mask = modifierKeys[i].mask; + if (mask == 0) { + if (modifierKeys[i].keysym != 0) { + mask = XkbKeysymToModifiers (QX11Info::display(), modifierKeys[i].keysym); + } else { + if (!strcmp(modifierKeys[i].name, "Win")) { + mask = KKeyServer::modXMeta(); + } else { + mask = XkbKeysymToModifiers (QX11Info::display(), XK_Mode_switch) + | XkbKeysymToModifiers (QX11Info::display(), XK_ISO_Level3_Shift) + | XkbKeysymToModifiers (QX11Info::display(), XK_ISO_Level3_Latch) + | XkbKeysymToModifiers (QX11Info::display(), XK_ISO_Level3_Lock); + } + } + } + + + int bit = maskToBit (mask); + if (bit != -1 && keys[bit] == -1) + keys[bit] = i; + } +} + + +bool KAccessApp::x11EventFilter(XEvent *event) +{ + // handle XKB events + if (event->type == xkb_opcode) + { + XkbAnyEvent *ev = (XkbAnyEvent*) event; + + switch (ev->xkb_type) { + case XkbStateNotify: + xkbStateNotify(); + break; + case XkbBellNotify: + xkbBellNotify((XkbBellNotifyEvent*)event); + break; + case XkbControlsNotify: + xkbControlsNotify((XkbControlsNotifyEvent*)event); + break; + } + return true; + } + + // process other events as usual + return KApplication::x11EventFilter(event); +} + + +void VisualBell::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); + QTimer::singleShot(_pause, this, SLOT(hide())); +} + + +void KAccessApp::activeWindowChanged(WId wid) +{ + _activeWindow = wid; +} + + +void KAccessApp::xkbStateNotify () { + XkbStateRec state_return; + XkbGetState (QX11Info::display(), XkbUseCoreKbd, &state_return); + unsigned char latched = XkbStateMods (&state_return); + unsigned char locked = XkbModLocks (&state_return); + int mods = ((int)locked)<<8 | latched; + + if (state != mods) { + if (_kNotifyModifiers) + for (int i = 0; i < 8; i++) { + if (keys[i] != -1) { + if ( !strcmp(modifierKeys[keys[i]].latchedText, "") + && ( (((mods >> i) & 0x101) != 0) != (((state >> i) & 0x101) != 0) )) + { + if ((mods >> i) & 1) { + KNotification::event ("lockkey-locked", i18n(modifierKeys[keys[i]].lockedText)); + } + else { + KNotification::event ("lockkey-unlocked", i18n(modifierKeys[keys[i]].unlatchedText)); + } + } + else if (strcmp(modifierKeys[keys[i]].latchedText, "") + && ( ((mods >> i) & 0x101) != ((state >> i) & 0x101) )) + { + if ((mods >> i) & 0x100) { + KNotification::event ("modifierkey-locked", i18n(modifierKeys[keys[i]].lockedText)); + } + else if ((mods >> i) & 1) { + KNotification::event ( "modifierkey-latched", i18n(modifierKeys[keys[i]].latchedText)); + } + else { + KNotification::event ("modifierkey-unlatched", i18n(modifierKeys[keys[i]].unlatchedText)); + } + } + } + } + state = mods; + } +} + +void KAccessApp::xkbBellNotify(XkbBellNotifyEvent *event) +{ + // bail out if we should not really ring + if (event->event_only) + return; + + // flash the visible bell + if (_visibleBell) + { + // create overlay widget + if (!overlay) + overlay = new VisualBell(_visibleBellPause); + + WId id = _activeWindow; + + NETRect frame, window; + NETWinInfo net(QX11Info::display(), id, desktop()->winId(), 0); + + net.kdeGeometry(frame, window); + + overlay->setGeometry(window.pos.x, window.pos.y, window.size.width, window.size.height); + + if (_visibleBellInvert) + { + QPixmap screen = QPixmap::grabWindow(id, 0, 0, window.size.width, window.size.height); +#ifdef __GNUC__ +#warning is this the best way to invert a pixmap? +#endif +// QPixmap invert(window.size.width, window.size.height); + QImage i = screen.toImage(); + i.invertPixels(); + QPalette pal = overlay->palette(); + pal.setBrush(overlay->backgroundRole(), QBrush(QPixmap::fromImage(i))); + overlay->setPalette(pal); +/* + QPainter p(&invert); + p.setRasterOp(QPainter::NotCopyROP); + p.drawPixmap(0, 0, screen); + overlay->setBackgroundPixmap(invert); +*/ + } + else + { + QPalette pal = overlay->palette(); + pal.setColor(overlay->backgroundRole(), _visibleBellColor); + overlay->setPalette(pal); + } + + // flash the overlay widget + overlay->raise(); + overlay->show(); + flush(); + } + + // ask Phonon to ring a nice bell + if (_artsBell) { + if (!_player) { // as creating the player is expensive, delay the creation + _player = Phonon::createPlayer(Phonon::AccessibilityCategory); + _player->setParent(this); + _player->setCurrentSource(_currentPlayerSource); + } + _player->play(); + } +} + +QString mouseKeysShortcut (Display *display) { + // Calculate the keycode + KeySym sym = XK_MouseKeys_Enable; + KeyCode code = XKeysymToKeycode(display, sym); + if (code == 0) { + sym = XK_Pointer_EnableKeys; + code = XKeysymToKeycode(display, sym); + if (code == 0) + return ""; // No shortcut available? + } + + // Calculate the modifiers by searching the keysym in the X keyboard mapping + XkbDescPtr xkbdesc = XkbGetMap(display, XkbKeyTypesMask | XkbKeySymsMask, XkbUseCoreKbd); + + if (!xkbdesc) + return ""; // Failed to obtain the mapping from server + + bool found = false; + unsigned char modifiers = 0; + int groups = XkbKeyNumGroups(xkbdesc, code); + for (int grp = 0; grp < groups && !found; grp++) + { + int levels = XkbKeyGroupWidth(xkbdesc, code, grp); + for (int level = 0; level < levels && !found; level++) + { + if (sym == XkbKeySymEntry(xkbdesc, code, level, grp)) + { + // keysym found => determine modifiers + int typeIdx = xkbdesc->map->key_sym_map[code].kt_index[grp]; + XkbKeyTypePtr type = &(xkbdesc->map->types[typeIdx]); + for (int i = 0; i < type->map_count && !found; i++) + { + if (type->map[i].active && (type->map[i].level == level)) + { + modifiers = type->map[i].mods.mask; + found = true; + } + } + } + } + } + XkbFreeClientMap (xkbdesc, 0, true); + + if (!found) + return ""; // Somehow the keycode -> keysym mapping is flawed + + XEvent ev; + ev.type = KeyPress; + ev.xkey.display = display; + ev.xkey.keycode = code; + ev.xkey.state = 0; + int key; + KKeyServer::xEventToQt(&ev, &key); + QString keyname = QKeySequence(key).toString(); + + unsigned int AltMask = KKeyServer::modXAlt(); + unsigned int WinMask = KKeyServer::modXMeta(); + unsigned int NumMask = KKeyServer::modXNumLock(); + unsigned int ScrollMask= KKeyServer::modXScrollLock(); + + unsigned int MetaMask = XkbKeysymToModifiers (display, XK_Meta_L); + unsigned int SuperMask = XkbKeysymToModifiers (display, XK_Super_L); + unsigned int HyperMask = XkbKeysymToModifiers (display, XK_Hyper_L); + unsigned int AltGrMask = XkbKeysymToModifiers (display, XK_Mode_switch) + | XkbKeysymToModifiers (display, XK_ISO_Level3_Shift) + | XkbKeysymToModifiers (display, XK_ISO_Level3_Latch) + | XkbKeysymToModifiers (display, XK_ISO_Level3_Lock); + + unsigned int mods = ShiftMask | ControlMask | AltMask | WinMask + | LockMask | NumMask | ScrollMask; + + AltGrMask &= ~mods; + MetaMask &= ~(mods | AltGrMask); + SuperMask &= ~(mods | AltGrMask | MetaMask); + HyperMask &= ~(mods | AltGrMask | MetaMask | SuperMask); + + if ((modifiers & AltGrMask) != 0) + keyname = i18n("AltGraph") + '+' + keyname; + if ((modifiers & HyperMask) != 0) + keyname = i18n("Hyper") + '+' + keyname; + if ((modifiers & SuperMask) != 0) + keyname = i18n("Super") + '+' + keyname; + if ((modifiers & WinMask) != 0) + keyname = i18n("Meta") + '+' + keyname; + if ((modifiers & WinMask) != 0) + keyname = QKeySequence(Qt::META).toString() + '+' + keyname; + if ((modifiers & AltMask) != 0) + keyname = QKeySequence(Qt::ALT).toString() + '+' + keyname; + if ((modifiers & ControlMask) != 0) + keyname = QKeySequence(Qt::CTRL).toString() + '+' + keyname; + if ((modifiers & ShiftMask) != 0) + keyname = QKeySequence(Qt::SHIFT).toString() + '+' + keyname; + + return keyname; +} + +void KAccessApp::createDialogContents() { + if (dialog == 0) { + dialog = new KDialog( 0 ); + dialog->setCaption( i18n("Warning") ); + dialog->setButtons( KDialog::Yes | KDialog::No ); + dialog->setButtonGuiItem( KDialog::Yes, KStandardGuiItem::yes() ); + dialog->setButtonGuiItem( KDialog::No, KStandardGuiItem::no() ); + dialog->setDefaultButton( KDialog::No ); + dialog->setEscapeButton( KDialog::Close ); + dialog->setObjectName( "AccessXWarning" ); + dialog->setModal( true ); + + KVBox *topcontents = new KVBox (dialog); + topcontents->setSpacing(KDialog::spacingHint()*2); +#ifdef __GNUC__ +#warning "kde4 fixme" +#endif + //topcontents->setMargin(KDialog::marginHint()); + + QWidget *contents = new QWidget(topcontents); + QHBoxLayout * lay = new QHBoxLayout(contents); + lay->setSpacing(KDialog::spacingHint()); + + QLabel *label1 = new QLabel( contents); + QPixmap pixmap = KIconLoader::global()->loadIcon("dialog-warning", KIconLoader::NoGroup, KIconLoader::SizeMedium, KIconLoader::DefaultState, QStringList(), 0, true); + if (pixmap.isNull()) + pixmap = QMessageBox::standardIcon(QMessageBox::Warning); + label1->setPixmap(pixmap); + + lay->addWidget( label1, 0, Qt::AlignCenter ); + lay->addSpacing(KDialog::spacingHint()); + + QVBoxLayout * vlay = new QVBoxLayout(); + lay->addItem( vlay ); + + featuresLabel = new QLabel( "", contents ); + featuresLabel->setAlignment( Qt::AlignVCenter ); + featuresLabel->setWordWrap( true ); + vlay->addWidget( featuresLabel ); + vlay->addStretch(); + + QHBoxLayout * hlay = new QHBoxLayout(); + vlay->addItem(hlay); + + QLabel *showModeLabel = new QLabel( i18n("&When a gesture was used:"), contents ); + hlay->addWidget( showModeLabel ); + + showModeCombobox = new KComboBox (contents); + hlay->addWidget( showModeCombobox ); + showModeLabel->setBuddy(showModeCombobox); + showModeCombobox->insertItem ( 0, i18n("Change Settings Without Asking")); + showModeCombobox->insertItem ( 1, i18n("Show This Confirmation Dialog")); + showModeCombobox->insertItem ( 2, i18n("Deactivate All AccessX Features & Gestures")); + showModeCombobox->setCurrentIndex (1); + + dialog->setMainWidget(topcontents); + + connect (dialog, SIGNAL(yesClicked()), this, SLOT(yesClicked())); + connect (dialog, SIGNAL(noClicked()), this, SLOT(noClicked())); + connect (dialog, SIGNAL(closeClicked()), this, SLOT(dialogClosed())); + } +} + +void KAccessApp::xkbControlsNotify(XkbControlsNotifyEvent *event) +{ + unsigned int newFeatures = event->enabled_ctrls & (XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask); + + if (newFeatures != features) { + unsigned int enabled = newFeatures & ~features; + unsigned int disabled = features & ~newFeatures; + + if (!_gestureConfirmation) { + requestedFeatures = enabled | (requestedFeatures & ~disabled); + notifyChanges(); + features = newFeatures; + } + else { + // set the AccessX features back to what they were. We will + // apply the changes later if the user allows us to do that. + readSettings(); + + requestedFeatures = enabled | (requestedFeatures & ~disabled); + + enabled = requestedFeatures & ~features; + disabled = features & ~requestedFeatures; + + QStringList enabledFeatures; + QStringList disabledFeatures; + + if (enabled & XkbStickyKeysMask) + enabledFeatures << i18n("Sticky keys"); + else if (disabled & XkbStickyKeysMask) + disabledFeatures << i18n("Sticky keys"); + + if (enabled & XkbSlowKeysMask) + enabledFeatures << i18n("Slow keys"); + else if (disabled & XkbSlowKeysMask) + disabledFeatures << i18n("Slow keys"); + + if (enabled & XkbBounceKeysMask) + enabledFeatures << i18n("Bounce keys"); + else if (disabled & XkbBounceKeysMask) + disabledFeatures << i18n("Bounce keys"); + + if (enabled & XkbMouseKeysMask) + enabledFeatures << i18n("Mouse keys"); + else if (disabled & XkbMouseKeysMask) + disabledFeatures << i18n("Mouse keys"); + + QString question; + switch (enabledFeatures.count()) { + case 0: switch (disabledFeatures.count()) { + case 1: question = i18n("Do you really want to deactivate \"%1\"?", + disabledFeatures[0]); + break; + case 2: question = i18n("Do you really want to deactivate \"%1\" and \"%2\"?", + disabledFeatures[0], disabledFeatures[1]); + break; + case 3: question = i18n("Do you really want to deactivate \"%1\", \"%2\" and \"%3\"?", + disabledFeatures[0], disabledFeatures[1], + disabledFeatures[2]); + break; + case 4: question = i18n("Do you really want to deactivate \"%1\", \"%2\", \"%3\" and \"%4\"?", + disabledFeatures[0], disabledFeatures[1], + disabledFeatures[2], disabledFeatures[3]); + break; + } + break; + case 1: switch (disabledFeatures.count()) { + case 0: question = i18n("Do you really want to activate \"%1\"?", + enabledFeatures[0]); + break; + case 1: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\"?", + enabledFeatures[0], disabledFeatures[0]); + break; + case 2: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\" and \"%3\"?", + enabledFeatures[0], disabledFeatures[0], + disabledFeatures[1]); + break; + case 3: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\", \"%3\" and \"%4\"?", + enabledFeatures[0], disabledFeatures[0], + disabledFeatures[1], disabledFeatures[2]); + break; + } + break; + case 2: switch (disabledFeatures.count()) { + case 0: question = i18n("Do you really want to activate \"%1\" and \"%2\"?", + enabledFeatures[0], enabledFeatures[1]); + break; + case 1: question = i18n("Do you really want to activate \"%1\" and \"%2\" and to deactivate \"%3\"?", + enabledFeatures[0], enabledFeatures[1], + disabledFeatures[0]); + break; + case 2: question = i18n("Do you really want to activate \"%1\", and \"%2\" and to deactivate \"%3\" and \"%4\"?", + enabledFeatures[0], enabledFeatures[1], + enabledFeatures[0], disabledFeatures[1]); + break; + } + break; + case 3: switch (disabledFeatures.count()) { + case 0: question = i18n("Do you really want to activate \"%1\", \"%2\" and \"%3\"?", + enabledFeatures[0], enabledFeatures[1], + enabledFeatures[2]); + break; + case 1: question = i18n("Do you really want to activate \"%1\", \"%2\" and \"%3\" and to deactivate \"%4\"?", + enabledFeatures[0], enabledFeatures[1], + enabledFeatures[2], disabledFeatures[0]); + break; + } + break; + case 4: question = i18n("Do you really want to activate \"%1\", \"%2\", \"%3\" and \"%4\"?", + enabledFeatures[0], enabledFeatures[1], + enabledFeatures[2], enabledFeatures[3]); + break; + } + QString explanation; + if (enabledFeatures.count()+disabledFeatures.count() == 1) { + explanation = i18n("An application has requested to change this setting."); + + if (_gestures) { + if ((enabled | disabled) == XkbSlowKeysMask) + explanation = i18n("You held down the Shift key for 8 seconds or an application has requested to change this setting."); + else if ((enabled | disabled) == XkbStickyKeysMask) + explanation = i18n("You pressed the Shift key 5 consecutive times or an application has requested to change this setting."); + else if ((enabled | disabled) == XkbMouseKeysMask) { + QString shortcut = mouseKeysShortcut(QX11Info::display()); + if (!shortcut.isEmpty() && !shortcut.isNull()) + explanation = i18n("You pressed %1 or an application has requested to change this setting.", shortcut); + } + } + } + else { + if (_gestures) + explanation = i18n("An application has requested to change these settings, or you used a combination of several keyboard gestures."); + else + explanation = i18n("An application has requested to change these settings."); + } + + createDialogContents(); + featuresLabel->setText ( question+"\n\n"+explanation + +" "+i18n("These AccessX settings are needed for some users with motion impairments and can be configured in the KDE System Settings. You can also turn them on and off with standardized keyboard gestures.\n\nIf you do not need them, you can select \"Deactivate all AccessX features and gestures\".") ); + + KWindowSystem::setState( dialog->winId(), NET::KeepAbove ); + kapp->updateUserTimestamp(); + dialog->show(); + } + } +} + +void KAccessApp::notifyChanges() { + if (!_kNotifyAccessX) + return; + + unsigned int enabled = requestedFeatures & ~features; + unsigned int disabled = features & ~requestedFeatures; + + if (enabled & XkbSlowKeysMask) + KNotification::event ("slowkeys", i18n("Slow keys has been enabled. From now on, you need to press each key for a certain length of time before it gets accepted.")); + else if (disabled & XkbSlowKeysMask) + KNotification::event ("slowkeys", i18n("Slow keys has been disabled.")); + + if (enabled & XkbBounceKeysMask) + KNotification::event ("bouncekeys", i18n("Bounce keys has been enabled. From now on, each key will be blocked for a certain length of time after it was used.")); + else if (disabled & XkbBounceKeysMask) + KNotification::event ("bouncekeys", i18n("Bounce keys has been disabled.")); + + if (enabled & XkbStickyKeysMask) + KNotification::event ("stickykeys", i18n("Sticky keys has been enabled. From now on, modifier keys will stay latched after you have released them.")); + else if (disabled & XkbStickyKeysMask) + KNotification::event ("stickykeys", i18n("Sticky keys has been disabled.")); + + if (enabled & XkbMouseKeysMask) + KNotification::event ("mousekeys", i18n("Mouse keys has been enabled. From now on, you can use the number pad of your keyboard in order to control the mouse.")); + else if (disabled & XkbMouseKeysMask) + KNotification::event ("mousekeys", i18n("Mouse keys has been disabled.")); +} + +void KAccessApp::applyChanges() { + notifyChanges(); + unsigned int enabled = requestedFeatures & ~features; + unsigned int disabled = features & ~requestedFeatures; + + KConfigGroup config(KGlobal::config(), "Keyboard"); + + if (enabled & XkbSlowKeysMask) + config.writeEntry("SlowKeys", true); + else if (disabled & XkbSlowKeysMask) + config.writeEntry("SlowKeys", false); + + if (enabled & XkbBounceKeysMask) + config.writeEntry("BounceKeys", true); + else if (disabled & XkbBounceKeysMask) + config.writeEntry("BounceKeys", false); + + if (enabled & XkbStickyKeysMask) + config.writeEntry("StickyKeys", true); + else if (disabled & XkbStickyKeysMask) + config.writeEntry("StickyKeys", false); + + KConfigGroup mousegrp(KGlobal::config(),"Mouse"); + + if (enabled & XkbMouseKeysMask) + mousegrp.writeEntry("MouseKeys", true); + else if (disabled & XkbMouseKeysMask) + mousegrp.writeEntry("MouseKeys", false); + mousegrp.sync(); + config.sync(); +} + +void KAccessApp::yesClicked() { + if (dialog != 0) + dialog->deleteLater(); + dialog = 0; + + KConfigGroup config(KGlobal::config(), "Keyboard"); + switch (showModeCombobox->currentIndex()) { + case 0: + config.writeEntry("Gestures", true); + config.writeEntry("GestureConfirmation", false); + break; + default: + config.writeEntry("Gestures", true); + config.writeEntry("GestureConfirmation", true); + break; + case 2: + requestedFeatures = 0; + config.writeEntry("Gestures", false); + config.writeEntry("GestureConfirmation", true); + } + config.sync(); + + if (features != requestedFeatures) { + notifyChanges(); + applyChanges(); + } + readSettings(); +} + +void KAccessApp::noClicked() { + if (dialog != 0) + dialog->deleteLater(); + dialog = 0; + requestedFeatures = features; + + KConfigGroup config(KGlobal::config(), "Keyboard"); + switch (showModeCombobox->currentIndex()) { + case 0: + config.writeEntry("Gestures", true); + config.writeEntry("GestureConfirmation", false); + break; + default: + config.writeEntry("Gestures", true); + config.writeEntry("GestureConfirmation", true); + break; + case 2: + requestedFeatures = 0; + config.writeEntry("Gestures", false); + config.writeEntry("GestureConfirmation", true); + } + config.sync(); + + if (features != requestedFeatures) + applyChanges(); + readSettings(); +} + +void KAccessApp::dialogClosed() { + if (dialog != 0) + dialog->deleteLater(); + dialog = 0; + + requestedFeatures = features; +} + +void KAccessApp::setXkbOpcode(int opcode) { + xkb_opcode = opcode; +} diff --git a/kcontrol/access/kaccess.desktop b/kcontrol/access/kaccess.desktop new file mode 100644 index 00000000..3e0262ea --- /dev/null +++ b/kcontrol/access/kaccess.desktop @@ -0,0 +1,97 @@ +[Desktop Entry] +Type=Service +Name=KDE Accessibility Tool +Name[af]=KDE toeganklikheid program +Name[ar]=أداة كدي للإتاحة +Name[ast]=Ferramienta d'accesibilidad de KDE +Name[be]=Інструмент даступнасці KDE +Name[be@latin]=Pryłada dastupnaści KDE +Name[bg]=Равностоен достъп +Name[bn]=কে.ডি.ই. সহায়ক প্রযুক্তি টুল +Name[br]=Ostilh haezadusted KDE +Name[bs]=KDE alat za pristupačnost +Name[ca]=Eina d'accessibilitat KDE +Name[ca@valencia]=Eina d'accessibilitat KDE +Name[cs]=Nástroj pro zpřístupnění prostředí KDE +Name[csb]=Pòmòce przëstãpù KDE +Name[cy]=Erfyn Hygyrchedd KDE +Name[da]=KDE Tilgængelighedsværktøj +Name[de]=KDE-Zugangshilfen +Name[el]=Εργαλείο προσιτότητας του KDE +Name[en_GB]=KDE Accessibility Tool +Name[eo]=KDE-ilo por alirebleco +Name[es]=Herramienta de accesibilidad de KDE +Name[et]=KDE hõlbustustööriist +Name[eu]=KDEren erabilerraztasun-tresna +Name[fa]=ابزار دستیابی‌پذیری KDE +Name[fi]=KDE:n esteettömyystyökalu +Name[fr]=Outil d'accessibilité de KDE +Name[fy]=KDE Tagonklikens +Name[ga]=Uirlis Inrochtaineachta KDE +Name[gl]=Utilidade de accesibilidade de KDE +Name[gu]=KDE ઉપયોગિતા સાધન +Name[he]=כלי הנגישות של KDE +Name[hi]=केडीई पहुँच औज़ार +Name[hne]=केडीई पहुंच औजार +Name[hr]=KDE pristupačnost +Name[hsb]=KDE pomocnik za přistupnosć +Name[hu]=KDE kezelési segédeszköz +Name[ia]=Instrumento de Accessibilitate de KDE +Name[id]=Alat Aksesibilitas KDE +Name[is]=KDE aðgengistól +Name[it]=Strumento per l'accessibilità di KDE +Name[ja]=KDE アクセシビリティ支援ツール +Name[ka]=KDE-ს სპეცეციალური შესაძლებლობების ხელსაწყოები +Name[kk]=KDE арнайы мүмкіндіктер құралы +Name[km]=ឧបករណ៍​មធ្យោបាយ​ងាយស្រួល​របស់ KDE +Name[kn]=ಕೆಡಿಇ ನಿಲುಕಣೆ (ಅಕ್ಸೆಸಿಬಲಿಟಿ) ಸಲಕರಣೆ +Name[ko]=KDE 접근성 도구 +Name[ku]=KDE Amûra Xwegihandinê +Name[lt]=KDE pritaikymo neįgaliesiems įrankis +Name[lv]=KDE pieejamības rīks +Name[mai]=केडीई पहुँच अओजार +Name[mk]=Алатка за пристапливост во KDE +Name[ml]=കെഡിഇ സാമീപ്യതാ ഉപകരണം +Name[mr]=केडीई सुलभता साधन +Name[ms]=Alat Keaksesan KDE +Name[nb]=Tilgjengelighetsverktøy for KDE +Name[nds]=KDE-Togangwarktüüch +Name[ne]=केडीई पहुँचयोग्य उपकरण +Name[nl]=KDE Toegankelijkheid +Name[nn]=Tilgjengeverktøy for KDE +Name[oc]=Esplech d'accessibilitat de KDE +Name[or]=KDE ଅଭିଗମ୍ୟତା ଉପକରଣ +Name[pa]=KDE ਸਹਾਇਕ ਟੂਲ +Name[pl]=Narzędzie ułatwień dostępu KDE +Name[pt]=Ferramenta de Acessibilidade do KDE +Name[pt_BR]=Ferramenta de Acessibilidade do KDE +Name[ro]=Utilitar de accesibilitate pentru KDE +Name[ru]=Специальные возможности +Name[se]=KDE reaidu álkkibut geavaheami várás +Name[si]=KDE ප්‍රවේශන මෙවලම +Name[sk]=Nástroj na sprístupnenie KDE +Name[sl]=Orodje za dostopnost KDE +Name[sr]=КДЕ‑ова алатка за приступачност +Name[sr@ijekavian]=КДЕ‑ова алатка за приступачност +Name[sr@ijekavianlatin]=KDE‑ova alatka za pristupačnost +Name[sr@latin]=KDE‑ova alatka za pristupačnost +Name[sv]=Handikappverktyg för KDE +Name[ta]=KDE அணுகும் கருவி +Name[te]=KDE అందుబాటు సాధనం +Name[tg]=Имкониятҳои KDE +Name[th]=เครื่องมือปรับการช่วยการใช้งานของ KDE +Name[tr]=KDE Erişilebilirlik Aracı +Name[ug]=ك د ئې(KDE) ياردەمچى ئىقتىدار قوراللىرى +Name[uk]=Утиліта керування доступності KDE +Name[uz]=KDE qulaylik vositasi +Name[uz@cyrillic]=KDE қулайлик воситаси +Name[vi]=Công cụ hỗ trợ truy cập của KDE +Name[wa]=Usteye d' accessibilité di KDE +Name[x-test]=xxKDE Accessibility Toolxx +Name[zh_CN]=KDE 辅助工具 +Name[zh_TW]=KDE 無障礙工具 +Exec=kaccess +X-DBUS-StartupType=None +X-KDE-Library=kcm_access +X-KDE-ParentApp=kcontrol +X-DocPath=kcontrol/kcmaccess/index.html diff --git a/kcontrol/access/kaccess.h b/kcontrol/access/kaccess.h new file mode 100644 index 00000000..c364b251 --- /dev/null +++ b/kcontrol/access/kaccess.h @@ -0,0 +1,115 @@ +#ifndef __K_ACCESS_H__ +#define __K_ACCESS_H__ + + +#include +#include +//Added by qt3to4: +#include +#include + + +#include +#include + +#include + +#include +#define explicit int_explicit // avoid compiler name clash in XKBlib.h +#include +#undef explicit + +class KDialog; +class QLabel; +class KComboBox; + +class KAccessApp : public KUniqueApplication +{ + Q_OBJECT + +public: + + explicit KAccessApp(bool allowStyles=true, bool GUIenabled=true); + + bool x11EventFilter(XEvent *event); + + int newInstance(); + + void setXkbOpcode(int opcode); + +protected: + + void readSettings(); + + void xkbStateNotify(); + void xkbBellNotify(XkbBellNotifyEvent *event); + void xkbControlsNotify(XkbControlsNotifyEvent *event); + + +private Q_SLOTS: + + void activeWindowChanged(WId wid); + void notifyChanges(); + void applyChanges(); + void yesClicked(); + void noClicked(); + void dialogClosed(); + + +private: + void createDialogContents(); + void initMasks(); + + int xkb_opcode; + unsigned int features; + unsigned int requestedFeatures; + + bool _systemBell, _artsBell, _visibleBell, _visibleBellInvert; + QColor _visibleBellColor; + int _visibleBellPause; + + bool _gestures, _gestureConfirmation; + bool _kNotifyModifiers, _kNotifyAccessX; + + QWidget *overlay; + + Phonon::MediaObject *_player; + QString _currentPlayerSource; + + WId _activeWindow; + + KDialog *dialog; + QLabel *featuresLabel; + KComboBox *showModeCombobox; + + int keys[8]; + int state; +}; + + +class VisualBell : public QWidget +{ + Q_OBJECT + +public: + + VisualBell(int pause) + : QWidget(( QWidget* )0, Qt::X11BypassWindowManagerHint), _pause(pause) + {} + + +protected: + + void paintEvent(QPaintEvent *); + + +private: + + int _pause; + +}; + + + + +#endif diff --git a/kcontrol/access/kaccess.notifyrc b/kcontrol/access/kaccess.notifyrc new file mode 100644 index 00000000..06c80cdf --- /dev/null +++ b/kcontrol/access/kaccess.notifyrc @@ -0,0 +1,1532 @@ +[Global] +IconName=preferences-desktop-accessibility +Comment=Accessibility +Comment[af]=Toeganklikheid +Comment[ar]=الإتاحة +Comment[as]=অভিগম্যতা +Comment[ast]=Accesibilidá +Comment[be]=Даступнасць +Comment[be@latin]=Dastupnaść +Comment[bg]=Равностоен достъп +Comment[bn]=সহায়ক প্রযুক্তি +Comment[bn_IN]=বিশেষ ব্যবহারের সহায়তা +Comment[br]=Haezadusted +Comment[bs]=Pristupačnost +Comment[ca]=Accessibilitat +Comment[ca@valencia]=Accessibilitat +Comment[cs]=Zpřístupnění +Comment[csb]=Pòmòce przëstãpù +Comment[cy]=Hygyrchedd +Comment[da]=Tilgængelighed +Comment[de]=Zugangshilfen +Comment[el]=Προσβασιμότητα +Comment[en_GB]=Accessibility +Comment[eo]=Alirebleco +Comment[es]=Accesibilidad +Comment[et]=Hõlbustus +Comment[eu]=Erabilerraztasuna +Comment[fa]=دستیابی‌پذیری +Comment[fi]=Esteettömyys +Comment[fr]=Accessibilité +Comment[fy]=Tagonklikens +Comment[ga]=Inrochtaineacht +Comment[gl]=Accesibilidade +Comment[gu]=ઉપયોગિતા +Comment[he]=נגישות +Comment[hi]=पहुँच +Comment[hne]=पहुंच +Comment[hr]=Pristupačnost +Comment[hsb]=Přistupnosć +Comment[hu]=Kezelési segítség +Comment[ia]=Accessibilitate +Comment[id]=Aksesibilitas +Comment[is]=Auðveldað aðgengi +Comment[it]=Accessibilità +Comment[ja]=アクセシビリティ +Comment[kk]=Арнайы мүмкіндіктер +Comment[km]=មធ្យោបាយ​ងាយស្រួល +Comment[kn]=ನಿಲುಕಣೆ (ಆಕ್ಸೆಸಿಬಿಲಿಟಿ) +Comment[ko]=내게 필요한 설정 +Comment[ku]=Gihîştin +Comment[lt]=Pritaikymas neįgaliesiems +Comment[lv]=Pieejamība +Comment[mai]=अभिगम्यता +Comment[mk]=Пристапливост +Comment[ml]=സാമീപ്യത +Comment[mr]=सुलभता +Comment[ms]=Kebolehcapaian +Comment[nb]=Tilgjengelighet +Comment[nds]=Toganghülp +Comment[ne]=पहुँचता +Comment[nl]=Toegankelijkheid +Comment[nn]=Tilgjenge +Comment[oc]=Accessibilitat +Comment[or]=ଅଭିଗମ୍ୟତା +Comment[pa]=ਸਹੂਲਤਾਂ +Comment[pl]=Ułatwienia dostępu +Comment[pt]=Acessibilidade +Comment[pt_BR]=Acessibilidade +Comment[ro]=Accesibilitate +Comment[ru]=Специальные возможности +Comment[se]=Álkkibut geavaheapmi +Comment[si]=ප්‍රවේශණය +Comment[sk]=Prístupnosť +Comment[sl]=Dostopnost +Comment[sr]=Приступачност +Comment[sr@ijekavian]=Приступачност +Comment[sr@ijekavianlatin]=Pristupačnost +Comment[sr@latin]=Pristupačnost +Comment[sv]=Handikappstöd +Comment[ta]=அணுகுத்தன்மை +Comment[te]=అందుబాటు +Comment[tg]=Имкониятҳо +Comment[th]=ช่วยการใช้งานให้ง่ายขึ้น +Comment[tr]=Erişilebilirlik +Comment[ug]=قوشۇمچە ئىقتىدار +Comment[uk]=Доступність +Comment[uz]=Qulayliklar +Comment[uz@cyrillic]=Қулайликлар +Comment[vi]=Hỗ trợ truy cập +Comment[wa]=Accessibilité +Comment[x-test]=xxAccessibilityxx +Comment[zh_CN]=辅助 +Comment[zh_TW]=無障礙輔助 + +[Event/modifierkey-latched] +Name=A modifier key has become active +Name[af]='n Verandering sleutel was geaktiveer +Name[ar]=تم تفعيل مفتاح مغيِّر +Name[ast]=Activosé una tecla modificadora +Name[be@latin]=Klavišny madyfikatar prycisnuty +Name[bg]=Включен е клавиш-модификатор +Name[bn]=একটি মডিফায়ার কী সক্রিয় হয়েছে +Name[bs]=Modifikatorski taster je aktiviran +Name[ca]=Alguna tecla modificadora ha esdevingut activa +Name[ca@valencia]=Alguna tecla modificadora ha esdevingut activa +Name[cs]=Modifikátor klávesnice je aktivní +Name[csb]=Klawisza zjinaczi òsta aktiwòwónô +Name[da]=En ændringstast er blevet aktiv +Name[de]=Eine Modifikator-Taste ist aktiviert worden +Name[el]=Ένα πλήκτρο τροποποιητή έγινε ενεργό +Name[en_GB]=A modifier key has become active +Name[eo]=Modifigita klavo aktiviĝis +Name[es]=Se ha activado una tecla modificadora +Name[et]=Muuteklahv muutus aktiivseks +Name[eu]=Tekla aldatzaile bat aktibatu da +Name[fi]=Muunnosnäppäin on aktivoitunut +Name[fr]=Une touche de modification est devenue active +Name[fy]=In modifkaasjetoets wurdt aktyf +Name[ga]=Tá eochair mhionathraithe gníomhach anois +Name[gl]=Activouse unha tecla modificadora +Name[gu]=બદલવાની કળ સક્રિય બની છે +Name[he]=מקש משנה מצב הפך לפעיל +Name[hi]=कोई मॉडिफ़ायर कुंजी सक्रिय हो गया है +Name[hne]=कोई माडिफायर कुंजी सक्रिय हो गे हे +Name[hr]=Tipka modifikatora je aktivirana +Name[hsb]=Modifikowaca tasta je so aktiwizowała. +Name[hu]=Egy módosító billentyű aktívvá vált +Name[ia]=Un clave de modificator ha devenite active +Name[id]=Sebuah tombol pengubah telah menjadi aktif +Name[is]=Breytilykill er nú virkur +Name[it]=Un tasto modificatore è stato attivato +Name[ja]=修飾キーがアクティブになりました +Name[kk]=Түрлендіргіш перне белсендірілді +Name[km]=គ្រាប់​ចុច​កែប្រែ​ក្លាយ​ជា​សកម្ម +Name[kn]=ಒಂದು ಪರಿವರ್ತಕ (ಮಾಡಿಫಯರ್) ಕೀಲಿ ಸಕ್ರಿಯಗೊಂಡಿದೆ +Name[ko]=수정자 키가 활성화됨 +Name[ku]=Bişkojkeke Guherker hat çalakirin +Name[lt]=Modifikavimo klavišas tapo aktyvus +Name[lv]=Modifikatora taustiņš tika aktivizēts +Name[mk]=Некое копче за модификација стана активно +Name[ml]=ഒരു മോഡിഫയര്‍ കീ സജീവമായിരിക്കുന്നു +Name[mr]=परिवर्तक कि सक्रिय झाली आहे +Name[nb]=En valgtast er slått på +Name[nds]=En Sünnertast is nu aktiev +Name[ne]=परिमार्जक कुञ्जी सक्रिय भएको छ +Name[nl]=Een modificatietoets is geactiveerd +Name[nn]=Ein valtast er no aktiv +Name[or]=ଗୋଟିଏ ପରିବର୍ତ୍ତକ କି ସକ୍ରିୟ ହୋଇଯାଇଛି +Name[pa]=ਮੋਡੀਫਾਇਰ ਸਵਿੱਚ ਐਕਟਿਵ ਕੀਤੀ ਗਈ +Name[pl]=Klawisz modyfikujący został włączony +Name[pt]=Ficou activa uma tecla modificadora +Name[pt_BR]=Uma tecla modificadora se tornou ativa +Name[ro]=Un modificator de taste a devenit activ +Name[ru]=Нажата клавиша-модификатор +Name[se]=Válljenboallu lea šaddan aktiiva +Name[si]=වෙනස්කිරීම් යතුර සක්‍රීයයි +Name[sk]=Modifikačný kláves je aktívny +Name[sl]=Spremenilna tipka se je omogočila +Name[sr]=Модификаторски тастер је активиран +Name[sr@ijekavian]=Модификаторски тастер је активиран +Name[sr@ijekavianlatin]=Modifikatorski taster je aktiviran +Name[sr@latin]=Modifikatorski taster je aktiviran +Name[sv]=En väljartangent har aktiverats +Name[ta]=A modifier key has become active +Name[te]=సవరింపు కీ క్రియాశీలం కాబోతోంది +Name[tg]=Нажата клавиша модификатора +Name[th]=ปุ่มพิมพ์ประกอบถูกเปิดการทำงาน +Name[tr]=Bir değiştirici tuş etkinleştirildi +Name[ug]=بىر ئۆزگەرتكۈچى كۇنۇپكا ئاكتىپلاندى +Name[uk]=Клавіша модифікатора стала активною +Name[wa]=Ene modifieuse tape a divnou active +Name[x-test]=xxA modifier key has become activexx +Name[zh_CN]=修饰键已经激活 +Name[zh_TW]=組合鍵已啟動 +Comment=A modifier key (e.g. Shift or Ctrl) has changed its state and is now active +Comment[af]='n Veranderingsleutel (bv. Shift of Control) se toestand het verander en is nou aktief +Comment[ar]=مفتاح مغيِّر (شفت او كنترول) غيّر حالته وأصبح مفعلاً +Comment[ast]=Una tecla modificadora (Mayús o Ctrl) camudó l'estáu y ta activa +Comment[be@latin]=Klavišny madyfikatar (naprykład, „Shift” ci „Ctrl”) źmianiŭ svajo stanovišča j ciapier prycisnuty. +Comment[bg]=Клавиш-модификатор (напр. Shift или Ctrl) промени състоянието си и е активен +Comment[bn]=একটি মডিফায়ার কী (e.g. Shift বা Ctrl) অবস্থা পরিবর্তন করে এখন সক্রিয় হয়েছে +Comment[bs]=Modifikatorski taster (npr. Shift ili Ctrl) promijenio je stanje i sada je aktivan +Comment[ca]=Ha canviat l'estat d'una tecla modificadora (p.ex. Majúscules o Control) i ara està activa +Comment[ca@valencia]=Ha canviat l'estat d'una tecla modificadora (p.ex. Majúscules o Control) i ara està activa +Comment[cs]=Modifikátor klávesnice (Shift nebo Ctrl) změnil stav a je právě aktivní +Comment[csb]=Klawisza zjinaczi (Shift abò Control) zmienia swój sztatus ë je aktiwòwónô +Comment[da]=En ændringstast (f.eks. Skift eller Ctrl) har ændret sin tilstand og er nu aktiv +Comment[de]=Eine Modifikator-Taste (Umschalt oder Strg) hat ihren Status verändert und ist nun aktiv +Comment[el]=Ένα πλήκτρο τροποποιητή (π.χ., Shift ή Ctrl) άλλαξε την κατάστασή του και είναι τώρα ενεργό +Comment[en_GB]=A modifier key (e.g. Shift or Ctrl) has changed its state and is now active +Comment[eo]=Modifa klavo (ekz. majuskliga klavo aŭ stirklavo) ŝanĝis sian staton kaj nun estas aktiva +Comment[es]=Una tecla modificadora (Mayús o Ctrl) ha cambiado su estado y está activa +Comment[et]=Muuteklahv (nt. Shift või Ctrl) muutis oma olekut ning on nüüd aktiivne +Comment[eu]=Tekla aldatzaile bat (adibidez, Maius edo Ktrl) egoeraz aldatu da, eta orain aktibo dago +Comment[fi]=Muunnosnäppäin (esim. Shift tai Ctrl) on vaihtanut tilaa ja on nyt aktiivinen +Comment[fr]=Une touche de modification (ex : « Maj. » ou « Ctrl. ») a changé d'état et est maintenant active +Comment[fy]=De tastân fan in modifikaasjetoets (lykas Shift of Control) is feroare en is no aktyf +Comment[ga]=Athraíodh staid eochrach mionathraithe (m.sh. Shift nó Ctrl) agus tá sí gníomhach anois +Comment[gl]=Unha tecla modificadora (por ex. Maiúsc ou Control) mudou de estado e agora está activa +Comment[gu]=બદલવાની કળે (દા.ત., શીફ્ટ અથવા કંટ્રોલ) હવે તેની સ્થિતિ બદલી છે અને હવે સક્રિય છે +Comment[he]=מקש משנה מצב (למשל Shift או Ctrl) שינה את מצבו וכרגע פעיל +Comment[hne]=कोई माडिफायर कुंजी (जइसन कि शिफ्ट या कंट्रोल) हर अपन स्थिति ल बदल दे हे अउ अब वो हर सक्रिय हो गे हे +Comment[hr]=Tipka modifikatora (npr. SHIFT ili CTRL) promijenila je svoje stanje i aktivna je +Comment[hsb]=Modifikowaca tasta (na př. Wulkopis abo Strg) je status změniła a je nětko aktiwna. +Comment[hu]=Egy módosító billentyű (pl. a Shift vagy a Ctrl) aktívvá vált +Comment[ia]=Un clave modificator (p.ex. Shift o Ctrl) ha cambiate su stato e ora es active +Comment[id]=Sebuah tombol pengubah (misalnya Shift atau Ctrl) telah diubah keadaannya dan sekarang aktif +Comment[is]=Breytilykill (t.d. Shift eða Ctrl) hefur breytt um stöðu og er nú virkur +Comment[it]=Un tasto modificatore (come Shift o Ctrl) ha cambiato stato ed è ora attivo +Comment[ja]=修飾キー (Shift や Ctrl) の状態が変更され、アクティブになりました +Comment[kk]=Түрлендіргіш перне (мыс. Shift не Ctrl) күйін ауыстырып енді белсенді +Comment[km]=គ្រាប់ចុច​កែប្រែ (ឧ. ប្ដូរ (Shift) ឬ​ជំនួស (Control)) បាន​ផ្លាស់ប្ដូរ​សភាព​របស់​វា ឥឡូវ​នេះ​សកម្ម +Comment[kn]=ಒಂದು ಪರಿವರ್ತಕ (ಮಾಡಿಫಯರ್) ಕೀಲಿ (ಉ.ದಾ Shift ಅಥವಾ Ctrl) ನ ಸ್ಥಿತಿಯು ಬದಲಾಗಿದ್ದು ಈಗ ಸಕ್ರಿಯಗೊಂಡಿದೆ +Comment[ko]=Shift나 Control 키 같은 수정자 키의 상태가 바뀌었고 현재 사용 가능함 +Comment[ku]=Bişkojkeke Guherker (mînak Shift an jî Ctrl) ciyê xwe guherand û niha çalak e +Comment[lt]=Klavišo – modifikatoriaus (pvz., Lyg2(Shift) arba Vald(Ctrl)) būsena pakito ir jis dabar – aktyvus +Comment[lv]=Modifikatora taustiņš (piem. Shift vai Control) ir mainījis stāvokli un tagad ir aktīvs +Comment[mk]=Некое копче за модификација (пр. Shift или Ctrl) си ја смени состојбата и сега е активно +Comment[ml]=ഒരു മോഡിഫയര്‍ കീ (ഉദാ. ഷിഫ്ട് അല്ലെങ്കില്‍ കണ്ട്രോള്‍) അവസ്ഥ മാറി സജീവമായിരിക്കുന്നു +Comment[mr]=परिवर्तक कि (उ.दा. Shift किंवा Ctrl) याने स्तर बदलविले आहे व आता सक्रिय आहे +Comment[nb]=En valgtast (f.eks. Shift eller Ctrl) har endret status og er nå slått på +Comment[nds]=En Sünnertast (Ümschalt oder Stüern (Strg) a.B.) hett sien Tostand ännert un is nu aktiev +Comment[nl]=Een modificatietoets (bijv. Shift of Ctrl) is nu actief +Comment[nn]=Ein valtast (som «Shift» eller «Ctrl») har endra status, og er no aktiv +Comment[or]=ଗୋଟିଏ ପରିବର୍ତ୍ତକ କି (ଯେପରିକି Shift କିମ୍ବା Ctrl) ସେମାନଙ୍କର ସ୍ଥିତି ପରିବର୍ତ୍ତନ କରିଅଛି ଏବଂ ବର୍ତ୍ତମାନ ସକ୍ରିୟ ଅଛି +Comment[pl]=Klawisz modyfikujący (np. Shift lub Ctrl) zmienił stan i jest teraz włączony +Comment[pt]=Uma tecla modificadora (p.ex., o Shift ou o Control) mudou o seu estado e ficou agora activa +Comment[pt_BR]=Uma tecla modificadora (p.ex. Shift ou Ctrl) teve seu estado alterado e agora está ativa +Comment[ro]=Un modificator de taste (cum ar fi Shift sau Ctrl) și-a schimbat starea și este acum activ +Comment[ru]=Клавиша-модификатор (например, Shift или Ctrl) изменила состояние и сейчас активна +Comment[si]=වෙනස් කරීමේ යතුරේ (උදා. Shift හෝ Ctrl) තත්වය වෙනස් වී ඇති අතර එය දැන් සක්‍රීයයි +Comment[sk]=Modifikačný kláves (napr. Shift alebo Ctrl) zmenil svoj stav a je teraz aktívny. +Comment[sl]=Spremenilna tipka (npr. Shift ali Ctrl) je spremenila stanje in je sedaj dejavna +Comment[sr]=Модификаторски тастер (нпр. Shift или Ctrl) променио је стање и сада је активан +Comment[sr@ijekavian]=Модификаторски тастер (нпр. Shift или Ctrl) промијенио је стање и сада је активан +Comment[sr@ijekavianlatin]=Modifikatorski taster (npr. Shift ili Ctrl) promijenio je stanje i sada je aktivan +Comment[sr@latin]=Modifikatorski taster (npr. Shift ili Ctrl) promenio je stanje i sada je aktivan +Comment[sv]=En väljartangent (t.ex. Skift eller Ctrl) har ändrat tillstånd och är nu aktiv +Comment[ta]=A modifier key (e.g. Shift or Ctrl) has changed its state and is now active +Comment[te]=సవరింపు కీ (ఉ.దా. Shift లేదా Ctrl) దానియొక్క స్థితి మార్చుకుంది మరియు ఇప్పుడు క్రియాశీలంగా ఉంది +Comment[tg]=Клавиша модификатора (например, Shift или Ctrl) изменила состояние и сейчас активна +Comment[th]=ปุ่มพิมพ์ประกอบ (เช่น Shift หรือ Ctrl) มีการเปลี่ยนสถานะของตัวมัน และตอนนี้กำลังทำงานอยู่ +Comment[tr]=Bir değiştirici tuşun (Shift veya Ctrl gibi) durumu değiştirildi ve etkinleştirildi +Comment[ug]=بىر ئۆزگەرتكۈچى كۇنۇپكا (مەسىلەن، Shift ياكى Ctrl) ئۇنىڭ ھالىتىنى ئۆزگەرتىپ ھازىر ئاكتىپلاشتۇرۇلدى +Comment[uk]=Клавіша модифікатора (наприклад Shift або Ctrl) змінила свій стан і тепер активна +Comment[wa]=Ene modifieuse tape (metans MAJ oudonbén CTRL) a candjî si estat eyet est asteure active +Comment[x-test]=xxA modifier key (e.g. Shift or Ctrl) has changed its state and is now activexx +Comment[zh_CN]=修饰键(如 Shift 或 Ctrl)更改了其状态,现已激活 +Comment[zh_TW]=一個組合鍵(如 Shift 或 Ctrl 等)已改變了它的狀態成為啟動 +Sound=KDE-Sys-Special.ogg + +nopresentation=236 + +[Event/modifierkey-unlatched] +Name=A modifier key has become inactive +Name[af]='n Verandering sleutel was gedeaktiveer +Name[ar]=تم إلغاء مفتاح مغيِّر +Name[ast]=Desactivóse una tecla modificadora +Name[be@latin]=Klavišny madyfikatar adcisnuty +Name[bg]=Изключен е клавиш-модификатор +Name[bn]=একটি মডিফায়ার কী নিষ্ক্রীয় হয়েছে +Name[bs]=Modifikatorski taster je deaktiviran +Name[ca]=Alguna tecla modificadora ha esdevingut inactiva +Name[ca@valencia]=Alguna tecla modificadora ha esdevingut inactiva +Name[cs]=Modifikátor klávesnice je neaktivní +Name[csb]=Klawisza zjiaczi òsta deaktiwòwónô +Name[da]=En ændringstast er blevet deaktiveret +Name[de]=Eine Modifikator-Taste ist deaktiviert worden +Name[el]=Ένα πλήκτρο τροποποιητή έγινε ανενεργό +Name[en_GB]=A modifier key has become inactive +Name[eo]=Modifigita klavo malaktiviĝis +Name[es]=Se ha desactivado una tecla modificadora +Name[et]=Muuteklahv muutus mitteaktiivseks +Name[eu]=Tekla aldatzaile bat inaktibatu da +Name[fi]=Muunnosnäppäin ei ole enää aktiivinen +Name[fr]=Une touche de modification est devenue inactive +Name[fy]=In modifikaasjetoets wurdt ynaktief +Name[ga]=Tá eochair mhionathraithe neamhghníomhach anois +Name[gl]=Desactivouse unha tecla modificadora +Name[gu]=બદલવાની કળ નિષ્ક્રિય બની છે +Name[he]=מקש משנה מצב הפך ללא פעיל +Name[hi]=कोई मॉडिफ़ायर कुंजी अक्रिय हो गया है +Name[hne]=कोई माडिफायर कुंजी हर अक्रिय हो गे हे +Name[hr]=Tipka modifikatora je deaktivirana +Name[hsb]=Modifikowaca tasta je so stała njeaktiwna +Name[hu]=Egy módosító billentyű inaktívvá vált +Name[ia]=Un clave modificator ha devenite inactive +Name[id]=Sebuah tombol pengubah telah menjadi tidak aktif +Name[is]=Breytilykill er nú óvirkur +Name[it]=Un tasto modificatore è stato disattivato +Name[ja]=修飾キーが非アクティブになりました +Name[kk]=Түрлендіргіш перне белсенсіздірілді +Name[km]=គ្រាប់​ចុច​កែប្រែ​បាន​ក្លាយ​ជា​អសកម្ម +Name[kn]=ಒಂದು ಪರಿವರ್ತಕ (ಮಾಡಿಫಯರ್) ಕೀಲಿ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ +Name[ko]=수정자 키가 비활성화됨 +Name[ku]=Bişkojkeke Guherker hat neçalakirin +Name[lt]=Klavišas – modifikatorius tapo neaktyvus +Name[lv]=Modifikatora taustiņš tika deaktivizēts +Name[mk]=Некое копче за модификација стана неактивно +Name[ml]=ഒരു മോഡിഫയര്‍ കീ നിര്‍ജീവമായിരിക്കുന്നു +Name[mr]=परिवर्तक कि निष्क्रिय झाली आहे +Name[nb]=En valgtast er slått av +Name[nds]=En Sünnertast is nich mehr aktiev +Name[ne]=परिमार्जक कुञ्जी निष्क्रिय भएको छ +Name[nl]=Een modificatietoets is inactief geworden +Name[nn]=Ein valtast er no inaktiv +Name[or]=ଗୋଟିଏ ପରିବର୍ତ୍ତକ କି ନିଷ୍କ୍ରିୟ ହୋଇଯାଇଛି +Name[pa]=ਮੋਡੀਫਾਇਰ ਸਵਿੱਚ ਇਨ-ਐਕਟਿਵ ਕੀਤੀ ਗਈ +Name[pl]=Klawisz modyfikujący został wyłączony +Name[pt]=Ficou inactiva uma tecla modificadora +Name[pt_BR]=Uma tecla modificadora se tornou inativa +Name[ro]=Un modificator de taste a devenit inactiv +Name[ru]=Клавиша модификатора отпущена +Name[se]=Válljenboallu ii leat šat aktiiva +Name[si]=වෙනස්කිරීම් යතුර අක්‍රීයයි +Name[sk]=Modifikačný kláves je neaktívny +Name[sl]=Spremenilna tipka se je onemogočila +Name[sr]=Модификаторски тастер је деактивиран +Name[sr@ijekavian]=Модификаторски тастер је деактивиран +Name[sr@ijekavianlatin]=Modifikatorski taster je deaktiviran +Name[sr@latin]=Modifikatorski taster je deaktiviran +Name[sv]=En väljartangent har inaktiverats +Name[ta]=A modifier key has become inactive +Name[te]=సవరింపు కీ క్రియాహీనం కాబోతోంది +Name[tg]=Клавиша модификатора не активна +Name[th]=ปุ่มพิมพ์ประกอบถูกปิดการทำงาน +Name[tr]=Bir değiştirici tuş pasifleştirildi +Name[ug]=بىر ئۆزگەرتكۈچى كۇنۇپكا پاسسىپلاشتۇرۇلدى +Name[uk]=Клавіша модифікатора стала неактивною +Name[wa]=Ene modifieuse tape a divnou nén active +Name[x-test]=xxA modifier key has become inactivexx +Name[zh_CN]=修饰键现已停用 +Name[zh_TW]=組合鍵已放開 +Comment=A modifier key (e.g. Shift or Ctrl) has changed its state and is now inactive +Comment[af]='n Veranderingsleutel (bv. Shift of Contorl) se toestand het verander en is nou onaktief +Comment[ar]=مفتاح مغيِّر (شفت او كنترول) غيّر حالته وأصبح ملغى +Comment[ast]=Una tecla modificadora (Shift o Ctrl) camudó l'estáu y nun ta activa +Comment[be@latin]=Klavišny madyfikatar (naprykład, „Shift” ci „Ctrl”) źmianiŭ svajo stanovišča j ciapier adcisnuty. +Comment[bg]=Клавиш-модификатор (напр. Shift или Ctrl) промени състоянието си и е изключен +Comment[bn]=একটি মডিফায়ার কী (e.g. Shift বা Ctrl) অবস্থা পরিবর্তন করে এখন নিষ্ক্রীয় হয়েছে +Comment[bs]=Modifikatorski taster (npr. Shift ili Ctrl) je promijenio stanje i nije više aktivan +Comment[ca]=Ha canviat l'estat d'una tecla modificadora (p.ex. Majúscules o Control) i ara està inactiva +Comment[ca@valencia]=Ha canviat l'estat d'una tecla modificadora (p.ex. Majúscules o Control) i ara està inactiva +Comment[cs]=Modifikátor klávesnice (Shift nebo Ctrl) změnil stav a je právě neaktivní +Comment[csb]=Klawisza zjinaczi (Shift abò Control) zmienia swój sztatus ë nie je ju aktiwnô +Comment[da]=En ændringstast (f.eks. Skift eller Ctrl) har ændret sin tilstand og er nu inaktiv +Comment[de]=Eine Modifikator-Taste (Umschalt oder Strg) hat ihren Status verändert und ist nun inaktiv +Comment[el]=Ένα πλήκτρο τροποποιητή (π.χ., Shift ή Ctrl) άλλαξε την κατάστασή του και είναι τώρα ανενεργό +Comment[en_GB]=A modifier key (e.g. Shift or Ctrl) has changed its state and is now inactive +Comment[eo]=Modifa klavo (ekz. majuskliga klavo aŭ stirklavo) ŝanĝis sian staton kaj nun estas malaktiva +Comment[es]=Una tecla modificadora (Mayus o Ctrl) ha cambiado su estado y no está activa +Comment[et]=Muuteklahv (nt. Shift või Ctrl) muutis oma olekut ning on nüüd mitteaktiivne +Comment[eu]=Tekla aldatzaile bat (adibidez, Maius edo Ktrl) egoeraz aldatu da, eta orain inaktibo dago +Comment[fi]=Muunnosnäppäin (esim. Shift tai Ctrl) on vaihtanut tilaa eikä ole enää aktiivinen +Comment[fr]=Une touche de modification (ex : « Maj. » ou « Ctrl. ») a changé d'état et est maintenant inactive +Comment[fy]=De tastân fan in modifikaasjetoets (lykas Shift of Control) is feroare en is no ynaktyf +Comment[ga]=Athraíodh staid eochrach mionathraithe (m.sh. Shift nó Ctrl) agus tá sí neamhghníomhach anois +Comment[gl]=Unha tecla modificadora (por ex. Maiúsc ou Control) mudou de estado e agora está inactiva +Comment[gu]=બદલવાની કળે (દા.ત., શીફ્ટ અથવા કંટ્રોલ) હવે તેની સ્થિતિ બદલી છે અને હવે નિષ્ક્રિય છે +Comment[he]=מקש משנה מצב (למשל Shift או Ctrl) שינה את מצבו וכרגע לא פעיל +Comment[hne]=कोई माडिफायर कुंजी (जइसन कि शिफ्ट या कंट्रोल) हर अपन स्थिति ल बदल दे हे अउ अब वो हर अक्रिय हो गे हे +Comment[hr]=Tipka modifikatora (npr. SHIFT ili CTRL) promijenila je svoje stanje i više nije aktivna +Comment[hsb]=Modifikowaca tasta (na př. Wulkopis abo Strg) je swój status změniła a je nětko njeaktiwna +Comment[hu]=Egy módosító billentyű (pl. a Shift vagy a Ctrl) inaktívvá vált +Comment[ia]=Un clave modificator (p.ex.Shift o Ctrl) ha cambiate su stato e ora es inactive +Comment[id]=Sebuah tombol pengubah (misalnya Shift atau Ctrl) tekah diubah keadaannya dan sekarang tidak aktif +Comment[is]=Breytilykill (t.d. Shift eða Ctrl) hefur breytt um stöðu og er nú óvirkur +Comment[it]=Un tasto modificatore (come Shift o Ctrl) ha cambiato stato ed è ora inattivo +Comment[ja]=修飾キー (Shift や Ctrl) の状態が変更され、非アクティブになりました +Comment[kk]=Түрлендіргіш перне (мыс. Shift не Ctrl) күйін ауыстырып енді белсенді емес +Comment[km]=គ្រាប់​ចុច​កែប្រែ (ឧ. ប្ដូរ (Shift) ឬ បញ្ជា (Control)) បាន​ផ្លាស់ប្ដូរ​សភាព​របស់​វា ហើយ​ឥឡូវ​នេះ​អសកម្ម +Comment[kn]=ಒಂದು ಪರಿವರ್ತಕ (ಮಾಡಿಫಯರ್) ಕೀಲಿ (ಉ.ದಾ Shift ಅಥವಾ Ctrl) ನ ಸ್ಥಿತಿಯು ಬದಲಾಗಿದ್ದು ಈಗ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ +Comment[ko]=Shift나 Control 키 같은 수정자 키의 상태가 바뀌었고 현재 사용 불가능함 +Comment[ku]=Bişkojkeke Guherker (mînak Shift an jî Ctrl) ciyê xwe guherand û niha neçalak e +Comment[lt]=Klavišo – modifikatoriaus (pvz., Lyg2(Shift) arba Vald(Ctrl)) būsena pakito ir jis dabar – neaktyvus +Comment[lv]=Modifikatora taustiņš (piem. Shift vai Control) ir mainījis stāvokli un tagad ir neaktīvs +Comment[mk]=Некое копче за модификација (пр. Shift или Ctrl) си ја смени состојбата и сега е неактивно +Comment[ml]=ഒരു മോഡിഫയര്‍ കീ (ഉദാ. ഷിഫ്ട് അല്ലെങ്കില്‍ കണ്ട്രോള്‍) അവസ്ഥ മാറി നിര്‍ജീവമായിരിക്കുന്നു +Comment[mr]=परिवर्तक कि (उ.दा. Shift किंवा Ctrl) याने स्तर बदलविले आहे व आता निष्क्रिय आहे +Comment[nb]=En valgtast (f.eks. Shift eller Ctrl) har endret status og er nå slått av +Comment[nds]=En Sünnertast (Ümschalt oder Stüern (Strg) a.B.) hett sien Tostand ännert un is nu nich mehr aktiev +Comment[nl]=Een modificatietoets (bijv. Shift of Ctrl) is nu inactief +Comment[nn]=Ein valtast (som «Shift» eller «Ctrl») har endra status, og er no inaktiv +Comment[or]=ଗୋଟିଏ ପରିବର୍ତ୍ତକ କି (ଯେପରିକି Shift କିମ୍ବା Ctrl) ସେମାନଙ୍କର ସ୍ଥିତି ପରିବର୍ତ୍ତନ କରିଛନ୍ତି ଏବଂ ବର୍ତ୍ତମାନ ନିଷ୍କ୍ରିୟ ହୋଇଯାଇଛନ୍ତି +Comment[pl]=Klawisz modyfikujący (np. Shift lub Ctrl) zmienił stan i jest teraz wyłączony +Comment[pt]=Uma tecla modificadora (p.ex., o Shift ou o Control) mudou o seu estado e ficou agora inactiva +Comment[pt_BR]=Uma tecla modificadora (p.ex. Shift ou Ctrl) teve seu estado alterado e agora está inativa +Comment[ro]=Un modificator de taste (cum ar fi Shift sau Ctrl) și-a schimbat starea și este acum inactiv +Comment[ru]=Клавиша-модификатор (например, Shift или Ctrl) изменила своё состояние и сейчас неактивна +Comment[si]=වෙනස් කරීමේ යතුරේ (උදා. Shift හෝ Ctrl) තත්වය වෙනස් වී ඇති අතර එය දැන් අක්‍රීයයි +Comment[sk]=Modifikačný kláves (napr. Shift alebo Ctrl) zmenil svoj stav a je teraz neaktívny. +Comment[sl]=Spremenilna tipka (npr. Shift ali Ctrl) je spremenila stanje in je sedaj nedejavna +Comment[sr]=Модификаторски тастер (нпр. Shift или Ctrl) је променио стање и није више активан +Comment[sr@ijekavian]=Модификаторски тастер (нпр. Shift или Ctrl) је промијенио стање и није више активан +Comment[sr@ijekavianlatin]=Modifikatorski taster (npr. Shift ili Ctrl) je promijenio stanje i nije više aktivan +Comment[sr@latin]=Modifikatorski taster (npr. Shift ili Ctrl) je promenio stanje i nije više aktivan +Comment[sv]=En väljartangent (t.ex. Skift eller Ctrl) har ändrat tillstånd och är nu inaktiv +Comment[ta]=A modifier key (e.g. Shift or Ctrl) has changed its state and is now inactive +Comment[te]=సవరింపు కీ (ఉ.దా. Shift లేదా Ctrl) దాని స్థితి మార్చుకుంది మరియు ఇప్పుడు క్రియాహీనంగా ఉంది +Comment[tg]=Клавиша модификатора (например, Shift или Ctrl) изменила своё состояние и сейчас не активна +Comment[th]=ปุ่มพิมพ์ประกอบ (เช่น Shift หรือ Ctrl) มีการเปลี่ยนสถานะของตัวมัน และตอนนี้ได้ปิดการทำงาน +Comment[tr]=Bir değiştirici tuşun (Shift veya Ctrl gibi) durumu değiştirildi ve pasifleştirildi +Comment[ug]=بىر ئۆزگەرتكۈچى كۇنۇپكا (مەسىلەن، Shift ياكى Ctrl) ئۇنىڭ ھالىتىنى ئۆزگەرتىپ ھازىر پاسسىپلاشتۇرۇلدى +Comment[uk]=Клавіша модифікатора (наприклад Shift або Ctrl) змінила свій стан і тепер неактивна +Comment[wa]=Ene modifieuse tape (metans MAJ oudonbén CTRL) a candjî si estat eyet n' est asteure pus active +Comment[x-test]=xxA modifier key (e.g. Shift or Ctrl) has changed its state and is now inactivexx +Comment[zh_CN]=修饰键(如 Shift 或 Ctrl)更改了其状态,现已停用 +Comment[zh_TW]=一個組合鍵(如 Shift 或 Ctrl 等)已改變了它的狀態成為放開 +Sound=KDE-Sys-Special.ogg + +nopresentation=236 + +[Event/modifierkey-locked] +Name=A modifier key has been locked +Name[af]='n Verandering sleutel was gesluit +Name[ar]=تم قفل مفتاح مغيِّر +Name[ast]=Bloquióse una tecla modificadora +Name[be@latin]=Klavišny madyfikatar zamacavany +Name[bg]=Клавиш-модификатор е заключен +Name[bn]=একটি মডিফায়ার কী লক করা হয়েছে +Name[bs]=Modifikatorski taster je zaključan +Name[ca]=S'ha fixat alguna tecla modificadora +Name[ca@valencia]=S'ha fixat alguna tecla modificadora +Name[cs]=Modifikátor klávesnice je zamčený +Name[csb]=Klawisza zjinaczi òsta zablokòwónô +Name[da]=En ændringstast er blevet låst +Name[de]=Eine Modifikator-Taste ist gesperrt worden +Name[el]=Ένα πλήκτρο τροποποιητή κλειδώθηκε +Name[en_GB]=A modifier key has been locked +Name[eo]=Modifigita klavo ŝlosiĝis +Name[es]=Se ha bloqueado una tecla modificadora +Name[et]=Muuteklahv on lukustatud +Name[eu]=Tekla aldatzaile bat blokeatu da +Name[fi]=Muunnosnäppäin on lukittu +Name[fr]=Une touche de modification a été verrouillée +Name[fy]=In modifikaasjetoets is beskoattele +Name[ga]=Tá eochair mhionathraithe faoi ghlas anois +Name[gl]=Trancouse unha tecla modificadora +Name[gu]=બદલવાની કળને તાળું મારવામાં આવ્યું છે +Name[he]=מקש משנה מצב ננעל +Name[hi]=कोई मॉडिफ़ायर कुंजी तालाबंद हो गया है +Name[hne]=कोई माडिफायर कुंजी हर तालाबंद हो गे हे +Name[hr]=Tipka modifikatora je zaključana +Name[hsb]=Modifikowaca tasta bu stajnje zaswěćena +Name[hu]=Egy módosító billentyű zárolódott +Name[ia]=Un clave modificator ha essite blocate +Name[id]=Sebuah tombol pengubah telah dikunci +Name[is]=Breytilykli hefur verið læst +Name[it]=Un tasto modificatore è stato bloccato +Name[ja]=修飾キーがロックされました +Name[kk]=Түрлендіргіш перне басылды +Name[km]=គ្រាប់​ចុច​កែប្រែ​បាន​ត្រូវ​ចាក់​សោ +Name[kn]=ಒಂದು ಪರಿವರ್ತಕ (ಮಾಡಿಫಯರ್) ಕೀಲಿಯನ್ನು ಬಂಧಿಸಲಾಗಿದೆ (ಲಾಕ್) +Name[ko]=수정자 키가 잠김 +Name[ku]=Bişkojkeke Guherker hat kilîtkirin +Name[lt]=Klavišas – modifikatorius buvo užrakintas +Name[lv]=Modifikatora taustiņš tika fiskēts +Name[mk]=Некое копче за модификација е заклучено +Name[ml]=ഒരു മോഡിഫയര്‍ കീ പൂട്ടിയിരിക്കുന്നു +Name[mr]=परिवर्तक कि कुलूपबंद केली गेली आहे +Name[nb]=En valgtast er blitt låst +Name[nds]=En Sünnertast wöör fastsett +Name[ne]=परिमार्जक कुञ्जी ताल्चा लगाइएको छ +Name[nl]=Een modificatietoets is vergrendeld +Name[nn]=Ein valtast er no låst +Name[or]=ଗୋଟିଏ ପରିବର୍ତ୍ତକ କି ଅପରିବର୍ତ୍ତିତ ହୋଇଯାଇଛି +Name[pa]=ਮੋਡੀਫਾਇਰ ਸਵਿੱਚ ਲਾਕ ਕੀਤੀ ਗਈ +Name[pl]=Klawisz modyfikujący został zablokowany +Name[pt]=Uma tecla modificadora ficou bloqueada +Name[pt_BR]=Uma tecla modificadora foi bloqueada +Name[ro]=Un modificator de taste a fost blocat +Name[ru]=Клавиша-модификатор зафиксирована +Name[se]=Válljenboallu lea dál lohkkaduvvon +Name[si]=වෙනස්කිරීම් යතුර අගුළු දමා ඇත +Name[sk]=Modifikačný kláves je zamknutý +Name[sl]=Spremenilna tipka se je zaklenila +Name[sr]=Модификаторски тастер је закључан +Name[sr@ijekavian]=Модификаторски тастер је закључан +Name[sr@ijekavianlatin]=Modifikatorski taster je zaključan +Name[sr@latin]=Modifikatorski taster je zaključan +Name[sv]=En väljartangent har låsts +Name[ta]=A modifier key has been locked +Name[te]=సవరింపు కీ అప్రవేశంగా ఉంది +Name[tg]=Клавиша модификатора зафиксирована +Name[th]=ปุ่มพิมพ์ประกอบถูกล็อคอยู่ +Name[tr]=Bir değiştirici tuş kilitlendi +Name[ug]=بىر ئۆزگەرتكۈچى كۇنۇپكا قۇلۇپلاندى +Name[uk]=Клавішу модифікатора було заблоковано +Name[wa]=Ene modifieuse tape a stî eclawêye +Name[x-test]=xxA modifier key has been lockedxx +Name[zh_CN]=修饰键现已锁定 +Name[zh_TW]=組合鍵已鎖定 +Comment=A modifier key (e.g. Shift or Ctrl) has been locked and is now active for all of the following keypresses +Comment[af]='n Veranderingsleutel (bv. Shift of Control) is gesluit en is nou aktief vir al die volgende sleuteldrukke +Comment[ar]=تم قفل مفتاح مغيِّر (شفت أو كنترول) وأصبح مفعّلاً لكل الكتابات التالية +Comment[ast]=Bloquióse una tecla modificadora (Mayús o Ctrl) y afectará a toles tecles calcaes +Comment[be@latin]=Klavišny madyfikatar (naprykład, „Shift” ci „Ctrl”) zamacavaŭsia j ciapier prycisnuty dla ŭsich nastupnych klavišaŭ. +Comment[bg]=Клавиш-модификатор (напр. Shift или Ctrl) е заключен и е активен за всички последващи натискания на клавиши +Comment[bn]=একটি মডিফায়ার কী (e.g. Shift বা Ctrl) লক করা হয়েছে এবং পরবর্তী সবকটি কী-র (key) জন্য সক্রিয় থাকবে +Comment[bs]=Modifikatorski taster (npr. Shift ili Ctrl) upravo je zaključan i od sada aktivan za sve pritiske na tastere +Comment[ca]=S'ha fixat alguna tecla modificadora (p.ex. Majúscules o Control) i ara està activa per a totes les tecles que es premin a continuació +Comment[ca@valencia]=S'ha fixat alguna tecla modificadora (p.ex. Majúscules o Control) i ara està activa per a totes les tecles que es premen a continuació +Comment[cs]=Modifikátor klávesnice (např. Shift nebo Ctrl) je zamčený a je nyní aktivní pro všechny následující stisknuté klávesy +Comment[csb]=Klawisza zjinaczi (Shift abò Control) òsta zablokòwónô ë je terô dlô pòsobnegò wcësniącô klawiszów aktiwnô +Comment[da]=En ændringstast (f.eks. Skift eller Ctrl) er blevet låst og er nu aktiv for alle følgende tastetryk +Comment[de]=Eine Modifikator-Taste (Umschalt oder Strg) ist festgesetzt worden und ist nun für alle folgenden Tastendrücke aktiv +Comment[el]=Ένα πλήκτρο τροποποιητή (π.χ., Shift ή Ctrl) κλειδώθηκε και τώρα είναι ενεργό για όλα τα ακόλουθα πατήματα πλήκτρων +Comment[en_GB]=A modifier key (e.g. Shift or Ctrl) has been locked and is now active for all of the following keypresses +Comment[eo]=Modifa klavo (ekz. majuskliga klavo aŭ stirklavo) ŝlosiĝis kaj nun estas aktiva por la sekvaj klavpremoj +Comment[es]=Se ha bloqueado una tecla modificadora (Mayús o Ctrl) y afectará a todas las teclas que se pulsen +Comment[et]=Muuteklahv (nt. Shift või Ctrl) on lukustatud ja on nüüd aktiivne kõikide järgnevate klahvivajutuste jaoks +Comment[eu]=Tekla aldatzaile bat (adibidez, Maius edo Ktrl) blokeatu da, eta orain aktibo dago sakatzen diren tekla guztietarako +Comment[fi]=Muunnosnäppäin (esim. Shift tai Ctrl) on lukittu ja on nyt aktiivinen kaikille seuraaville näppäinpainalluksille +Comment[fr]=Une touche de modification (ex : « Maj. » ou « Ctrl. ») a été verrouillée et est maintenant active pour tous les appuis suivants de touches +Comment[fy]=In modifikaasjetoets (lykas Shift of Control) is beskoattele en is no aktyf foar de neikommende toetsoanslaggen +Comment[ga]=Cuireadh eochair mhionathraithe (m.sh., Shift nó Ctrl) faoi ghlas tá sí gníomhach anois le haghaidh na n-eochairbhrúnna seo a leanas +Comment[gl]=Unha tecla modificadora (por ex. Maiúsc ou Control) foi trancada e agora está activa +Comment[gu]=બદલવાની કળને (દા.ત., શીફ્ટ અથવા કંટ્રોલ) હવે તાળું મારવામાં આવ્યું છે અને હવે તે નીચેની કળ દબાવવા માટે સક્રિય છે +Comment[he]=מקש משנה מצב (למשל Shift או Ctrl) ננעל וכרגע פעיל עבור לחיצות המקשים הבאות +Comment[hne]=कोई माडिफायर कुंजी (जइसन कि शिफ्ट या कंट्रोल) हर तालाबंद हो गे हे अउ अब वो हर नीचे के सब्बो कुंजीदबाव मं सक्रिय रहिही +Comment[hr]=Tipka modifikatora (npr. SHIFT ili CTRL) zaključana je i aktivna je tijekom svih sljedećih pritisaka tipki +Comment[hsb]=Modifikowaca tasta (na př. Wulkopis abo Strg) bu stajnje zaswěćena a je nětko za wšě přichodne tasty aktiwna +Comment[hu]=Egy módosító billentyű (pl. a Shift vagy a Ctrl) zárolódott, és ezután minden billentyűlenyomásnál aktív lesz +Comment[ia]=Un clave modificator (p.ex.Shift o CTRL) ha essite blocate e ora es active pro tote le sequente keypresses +Comment[id]=Sebuah tombol pengubah (misalnya Shift atau Ctrl) telah dikunci dan sekarang aktif untuk semua penekanan tombol berikut +Comment[is]=Breytilykli (t.d. Shift eða Ctrl) hefur verið læst og er nú virkur fyrir eftirfarandi lyklaborðsaðgerðir +Comment[it]=Un tasto modificatore (come Shift o Ctrl) è stato bloccato ed è ora attivo per tutte le battute successive +Comment[ja]=修飾キー (Shift や Ctrl) がロックされ、続くキー押下のすべてに対してアクティブになりました +Comment[kk]=Түрлендіргіш перне (мыс. Shift не Ctrl) басылып енді барлық басылмақ пернелер үшін белсенді +Comment[km]=គ្រាប់​ចុច​កែប្រែ (ឧ. ប្ដូរ (Shift) ឬ​បញ្ជា (Control)) ត្រូវ​បាន​ចាក់​សោ ហើយ​ឥឡូវ​នេះ​សកម្ម​សម្រាប់​ការ​ចុច​គ្រាប់​ចុច​ខាង​ក្រោម +Comment[kn]=ಒಂದು ಪರಿವರ್ತಕ (ಮಾಡಿಫಯರ್) ಕೀಲಿಯನ್ನು (ಉ.ದಾ Shift ಅಥವಾ Ctrl) ಬಂಧಿಸಲಾಗಿದ್ದು (ಲಾಕ್), ಮುಂದಿನ ಎಲ್ಲಾ ಕೀಲಿಮಣೆ ಒತ್ತುಗಳಿಗೆ ಈಗ ಸಕ್ರಿಯವಾಗಿದೆ +Comment[ko]=Shift나 Control 키 같은 수정자 키의 상태가 바뀌었고 현재 모든 키 입력에 대해서 활성화됨 +Comment[ku]=Bişkojka guhêrker (wekî Shift an jî Ctrl) hate qufl kirin û niha ji bo çalak kirina hemû bişkojkên jêr çalak e +Comment[lt]=Klavišas – modifikatorius (pvz., Lyg2(Shift) arba Vald(Ctrl)) buvo užrakintas ir dabar visiems būsimiems klavišų paspaudimams yra aktyvus +Comment[lv]=Modifikatora taustiņš (piem. Shift vai Control) tika fiksēts un ir aktīvs visiem nākamajiem taustiņu nospiedieniem +Comment[mk]=Некое копче за модификација (пр. Shift или Ctrl) беше заклучено и сега е активно за сите наредни притиснати копчиња +Comment[ml]=ഒരു മോഡിഫയര്‍ കീ (ഉദാ. ഷിഫ്ട് അല്ലെങ്കില്‍ കണ്ട്രോള്‍) പൂട്ടിയിരിക്കുന്നു. നിലവില്‍ താഴെ പറയുന്ന കീപ്രെസ്സുകള്‍ക്കു് ഇതു് സജീവമാണു് +Comment[mr]=परिवर्तक कि (उ.दा. Shift किंवा Ctrl) कुलूपबंद झाली आहे व खालील किप्रेस् करिता सक्रिय झाली आहे +Comment[nb]=En valgtast (f.eks. Shift eller Ctrl) har blitt låst og er nå skrudd på for alle etterfølgende tastetrykk +Comment[nds]=En Sünnertast (Ümschalt oder Stüern (Strg) a.B.) wöör fastsett un is nu för all nakamen Tasten aktiev +Comment[nl]=Een modificatietoets (bijv. Shift of Ctrl) is vergrendeld en nu actief voor alle volgende toetsaanslagen +Comment[nn]=Ein valtast (som «Shift» eller «Ctrl») er vorten låst, og er no aktiv for alle etterfølgjande tastetrykk +Comment[or]=ଗୋଟିଏ ପରିବର୍ତ୍ତକ କି (ଯେପରିକି Shift କିମ୍ବା Ctrl) ଅପରିବର୍ତ୍ତିତ ହୋଇଯାଇଛି ଏବଂ ବର୍ତ୍ତମାନ ନିମ୍ନଲିଖିତ ସମସ୍ତ କି ଚାପ ପାଇଁ ସକ୍ରିୟ ହୋଇଛି +Comment[pl]=Klawisz modyfikujący (np. Shift lub Ctrl) został zablokowany i będzie włączony przy następnych naciśnięciach klawiszy +Comment[pt]=Uma tecla modificadora (p.ex., o Shift ou o Control) foi bloqueada e ficou agora activa para todas as combinações de teclas seguintes +Comment[pt_BR]=Uma tecla modificadora (p.ex. Shift ou Ctrl) foi bloqueada e agora está ativa, para todos os pressionamentos de tecla seguintes +Comment[ro]=Un modificator de taste (cum ar fi Shift sau Ctrl) a fost blocat și este acum activ pentru următoarele apăsări de taste +Comment[ru]=Клавиша-модификатор (например, Shift или Ctrl) зафиксирована и активна при нажатии любых других клавиш +Comment[si]=වෙනස් කිරීමේ යතුර (උදා. Shift හෝ Ctrl) අගුළු දමා ඇති අතර පහත සියළුම යතුරු එබීම් සඳහා එය සක්‍රීයයි +Comment[sk]=Modifikačný kláves (napr. Shift alebo Ctrl) je zamknutý a je teraz aktívny pre všetky nasledujúce stlačenia kláves +Comment[sl]=Spremenilna tipka (npr. Shift ali Ctrl) se je zaklenila in je sedaj dejavna za vse prihodnje pritiske tipk +Comment[sr]=Модификаторски тастер (нпр. Shift или Ctrl) управо је закључан и од сада активан за све притиске на тастере +Comment[sr@ijekavian]=Модификаторски тастер (нпр. Shift или Ctrl) управо је закључан и од сада активан за све притиске на тастере +Comment[sr@ijekavianlatin]=Modifikatorski taster (npr. Shift ili Ctrl) upravo je zaključan i od sada aktivan za sve pritiske na tastere +Comment[sr@latin]=Modifikatorski taster (npr. Shift ili Ctrl) upravo je zaključan i od sada aktivan za sve pritiske na tastere +Comment[sv]=En väljartangent (t.ex. Skift eller Ctrl) har låsts och är nu aktiv för alla följande tangentnertryckningar +Comment[ta]=A modifier key (e.g. Shift or Ctrl) has been locked and is now active for all of the following keypresses +Comment[te]=సవరింపు కీ (ఉ.దా. Shift లేదా Ctrl) అప్రవేశం చేయబడింది మరియు ఇప్పుడు క్రింది అన్ని కీవత్తులకు క్రియాశీలంగా ఉంది +Comment[tg]=Клавиша модификатора (например, Shift или Ctrl) зафиксирована и активна при нажатии любых других клавиш +Comment[th]=ปุ่มพิมพ์ประกอบ (เช่น Shift หรือ Cntrl) ถูกล็อคอยู่ และขณะนี้อยู่ในสถานะทำงาน สำหรับใช้ร่วมกับการกดแป้นต่อจากนี้ +Comment[tr]=Bir değiştirici tuş (Shift ya da Ctrl gibi) kilitlendi ve bundan sonraki tüm tuş basma eylemleri için etkinleştirildi +Comment[ug]=بىر ئۆزگەرتكۈچى كۇنۇپكا (مەسىلەن، Shift ياكى Ctrl) قۇلۇپلاندى، بۇندىن كېيىنكى كۇنۇپكا بېسىشقا ئىشلىتىلىدۇ +Comment[uk]=Клавішу модифікатора (наприклад Shift або Ctrl) було зафіксовано і тепер вона активна для всіх наступних натискань клавіш +Comment[wa]=Ene modifieuse tape (metans MAJ oudonbén CTRL) a stî eclawêye eyet est asteure active po tos les tapes tchôkeyes ki shuront +Comment[x-test]=xxA modifier key (e.g. Shift or Ctrl) has been locked and is now active for all of the following keypressesxx +Comment[zh_CN]=修饰键(如 Shift 或 Ctrl)已被锁定,现在将适用于后续按键 +Comment[zh_TW]=一個組合鍵(如 Shift 或 Ctrl 等)已被鎖定,現在再按任何鍵都視為快捷鍵組合 +Sound=KDE-Sys-Special.ogg + +nopresentation=236 + +[Event/lockkey-locked] +Name=A lock key has been activated +Name[af]='n Sluitsleutel is geaktiveer +Name[ar]=تم تفعيل مفتاح قفل +Name[ast]=Activóse una tecla de bloquéu +Name[be@latin]=Klaviša macavańnia prycisnutaja +Name[bg]=Включен е клавиш за превключване на режим +Name[bn]=একটি লক কী (lock key) সক্রিয় হয়েছে +Name[bs]=Zaključavajući taster je aktiviran +Name[ca]=S'ha activat alguna tecla de fixació +Name[ca@valencia]=S'ha activat alguna tecla de fixació +Name[cs]=Klávesa pro přepnutí stavu byla aktivována +Name[csb]=Klawisza blokadë òsta aktiwòwónô +Name[da]=En låsetast er blevet aktiveret +Name[de]=Eine Sperrtaste ist aktiviert worden +Name[el]=Ένα πλήκτρο κλειδώματος έχει ενεργοποιηθεί +Name[en_GB]=A lock key has been activated +Name[eo]=Baskula klavo aktiviĝis +Name[es]=Se ha activado una tecla de bloqueo +Name[et]=Lukustusklahv on aktiveeritud +Name[eu]=Blokeo-tekla bat aktibatu da +Name[fi]=Lukitusnäppäin on aktivoitu +Name[fr]=Une touche de verrouillage a été activée +Name[fy]=In beskoatteltoets is aktivearre +Name[ga]=Tá eochair ghlasála gníomhach anois +Name[gl]=Activouse unha tecla de bloqueo +Name[gu]=તાળાં કળ સક્રિય કરવામાં આવી છે +Name[he]=מקש נועל הפך לפעיל +Name[hi]=कोई तालाबंद कुंजी सक्रिय किया जा चुका है +Name[hne]=कोई ताला कुंजी सक्रिय हो गे हे +Name[hr]=Tipka zaključavanja je aktivirana +Name[hsb]=Tasta za stajne zaswěćene je nětko aktiwna +Name[hu]=Egy zároló billentyű aktívvá vált +Name[ia]=Un clave de bloco ha essite activate +Name[id]=Sebuah tombol pengunci telah diaktifkan +Name[is]=Læsilykill hefur verið virkjaður +Name[it]=Un tasto di blocco è stato attivato +Name[ja]=ロックキーがアクティブになりました +Name[ka]=დაბლოკვის ღილაკი გააქტივებულია +Name[kk]=Қосқыш перне белсендірілді +Name[km]=គ្រាប់​ចុច​ចាក់​សោ​បាន​ត្រូវ​ធ្វើ​ឲ្យ​សកម្ម +Name[kn]=ಒಂದು ಭಂಧನ ಕೀಲಿಯನ್ನು (ಲಾಕ್) ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Name[ko]=잠금 키가 활성화됨 +Name[ku]=Bişkojkeke Mifteyê hat çalakirin +Name[lt]=Užrakto klavišas buvo aktyvuotas +Name[lv]=Slēga taustiņš tika aktivizēts +Name[mk]=Некое копче за заклучување беше активирано +Name[ml]=ഒരു ലോക്ക് കീ സജീവമാക്കിയിരിക്കുന്നു +Name[mr]=कुलूपबंद कि सक्रिय केली गेली +Name[nb]=En låsetast er blitt slått på +Name[nds]=En Tastrast is nu inleggt +Name[ne]=एउटा ताल्चा कुञ्जी सक्रिय बनाइएको छ +Name[nl]=Een vergrendeltoets is geactiveerd +Name[nn]=Ein låstetast er no aktiv +Name[or]=ଗୋଟିଏ ଅପରିବର୍ତ୍ତନୀୟ କିକୁ ସକ୍ରିୟ କରାଯାଇଛି +Name[pa]=ਇੱਕ ਲਾਕ ਸਵਿੱਚ ਐਕਟਿਵੇਟ ਕੀਤੀ ਗਈ +Name[pl]=Klawisz blokujący został włączony +Name[pt]=Uma tecla de bloqueio foi activada +Name[pt_BR]=Uma tecla de bloqueio foi ativada +Name[ro]=O tastă de blocare a fost activată +Name[ru]=Активирована клавиша переключения режимов +Name[se]=Lohkkadanboallu lea aktiivalaš +Name[si]=අගුළු යතුර සක්‍රීයයි +Name[sk]=Zamykací kláves je aktívny +Name[sl]=Zaklepna tipka je bila omogočena +Name[sr]=Закључавајући тастер је активиран +Name[sr@ijekavian]=Закључавајући тастер је активиран +Name[sr@ijekavianlatin]=Zaključavajući taster je aktiviran +Name[sr@latin]=Zaključavajući taster je aktiviran +Name[sv]=En låstangent har aktiverats +Name[ta]=A lock key has been activated +Name[te]=అప్రవేశపు కీ క్రియాశీలం చేయబడింది +Name[tg]=Активирована клавиша переключения режимов +Name[th]=ปุ่มล็อคถูกเปิดการทำงาน +Name[tr]=Bir kilitleme tuşu etkinleştirildi +Name[ug]=بىر قۇلۇپلاش كۇنۇپكىسى ئاكتىپلاندى +Name[uk]=Було активовано клавішу фіксації +Name[wa]=Ene eclawåve tape a stî metowe en alaedje +Name[x-test]=xxA lock key has been activatedxx +Name[zh_CN]=锁定键现已激活 +Name[zh_TW]=已啟動鎖定鍵 +Comment=A lock key (e.g. Caps Lock or Num Lock) has changed its state and is now active +Comment[af]='n Sluitsleutel (bv. Caps Lock of Num Lock) se toestand het verander en is nou aktief +Comment[ar]=تغيرت حالة مفتاح قفل (Caps Lock أو Num Lock) وأصبح مفعلاً +Comment[ast]=Una tecla de bloquéu (como Bloq Mayús o Bloq Num) camudó l'estáu y ta activa +Comment[be@latin]=Klaviša macavańnia (naprykład, „Caps Lock” ci „Num Lock”) źmianiła svajo stanovišča j ciapier prycisnutaja. +Comment[bg]=Клавиш за превключване на режим (напр. Caps Lock или Num Lock) промени състоянието си и е активен +Comment[bn]=একটি লক কী (e.g. Caps Lock বা Num Lock) অবস্থা পরিবর্তন করে এখন সক্রিয় হয়েছে +Comment[bs]=Zaključavajući taster (npr. CapsLock ili NumLock) promijenio je stanje i sada je aktivan +Comment[ca]=Alguna tecla de fixació (p.ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està activa +Comment[ca@valencia]=Alguna tecla de fixació (p.ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està activa +Comment[cs]=Klávesa pro přepnutí stavu (např. CapsLock nebo NumLock) byla stisknuta a je nyní aktivní +Comment[csb]=Klawisza blokadë (Caps Lock abò Num Lock) zmienia swój sztatus ë je terô aktiwnô +Comment[da]=En låsetast (f.eks. Caps Lock eller Num Lock) har ændret sin tilstand og er nu aktiv +Comment[de]=Eine Sperrtaste (Feststelltaste oder Nummernblocksperre) hat ihren Status geändert und ist nun aktiv +Comment[el]=Ένα πλήκτρο κλειδώματος (π.χ., Caps Lock ή Num Lock) άλλαξε την κατάστασή του και είναι τώρα ενεργό +Comment[en_GB]=A lock key (e.g. Caps Lock or Num Lock) has changed its state and is now active +Comment[eo]=Baskula klavo (ekz. majuskla baskulo aŭ nombra baskulo) ŝanĝis sian staton kaj nun estas aktiva +Comment[es]=Una tecla de bloqueo (como Bloq Mayús o Bloq Num) ha cambiado su estado y está activa +Comment[et]=Lukustusklahv (nt. Caps Lock või Num Lock) muutis oma seisundit ning on nüüd aktiivne +Comment[eu]=Blokeo-tekla bat (adibidez, Blok Maius edo Blok Zenb) egoeraz aldatu da, eta orain aktibo dago +Comment[fi]=Lukitusnäppäin (esim. CapsLock tai NumLock) on vaihtanut tilaansa ja on nyt aktiivinen +Comment[fr]=Une touche de verrouillage (ex : « Verr. Maj. » ou « Verr. Num. ») a changé d'état et est maintenant active +Comment[fy]=De tastân fan in beskoatteltoets (lykas kaptaalskoattel of Nûm skoattel) is feroare en is no aktyf +Comment[ga]=Athraíodh staid eochrach glasála (m.sh. Caps Lock nó Num Lock) agus tá sí gníomhach anois +Comment[gl]=Unha tecla de bloqueo (por ex., Bloq Maiúsc ou Bloq Num) mudou de estado e agora está activa +Comment[gu]=તાળાં કળે (દા.ત., કેપ્સ લોક અથવા નમ લોક) હવે તેની સ્થિતિ બદલી છે અને હવે સક્રિય છે +Comment[he]=מקש נועל (למשל Caps Lock או Num Lock) שינה את מצבו וכרגע פעיל +Comment[hne]=कोई ताला कुंजी (जइसन कि कैप्स लाक या न्यूम लाक) हर अपन स्थिति ल बदल दे हे अउ अब वो हर सक्रिय हो गे हे +Comment[hr]=Tipka zaključavanja (npr. CapsLock ili NumLock) promijenila je svoje stanje i aktivna je +Comment[hsb]=Tasta za stajne zaswěćene (na př. Stajny Wulkopis) je status změniła a je nětko aktiwna +Comment[hu]=Egy zároló billentyű (pl. a Caps Lock vagy a Num Lock) aktívvá vált +Comment[ia]=Un clave de bloco (p.ex. Caps Lock o Num Lock) ha cambiate su stato e ora es active +Comment[id]=Sebuah tombol kunci (misalnya Caps Lock atau Num Lock) telah diubah keadaannya dan sekarang aktif +Comment[is]=Læsilykill (t.d. Caps Lock eða Num Lock) hefur breytt um stöðu og er nú virkur +Comment[it]=Un tasto di blocco (ad es. Bloc Maiusc o Bloc Num) ha cambiato stato ed è ora attivo +Comment[ja]=ロックキー (Caps Lock や Num Lock) の状態が変更され、非アクティブになりました +Comment[kk]=Қосқыш перне (мыс. Caps Lock не Num Lock) күйін ауыстырып енді белсенді +Comment[km]=គ្រាប់ចុច​ចាក់សោ (ឧ. ប្ដូរ​ជាប់(Caps Lock) ឬ​គ្រាប់ចុច​លេខ) បាន​ផ្លាស់ប្ដូរ​ស្ថានភាព​របស់វា ហើយ​តឡូវ​សកម្ម +Comment[kn]=ಒಂದು ಭಂಧನ (ಲಾಕ್) ಕೀಲಿ (ಉ.ದಾ Shift ಅಥವಾ Ctrl) ನ ಸ್ಥಿತಿಯು ಬದಲಾಗಿದ್ದು ಈಗ ಸಕ್ರಿಯಗೊಂಡಿದೆ +Comment[ko]=Caps Lock이나 Num Lock 키 같은 잠금 키의 상태가 바뀌었고 현재 활성화됨 +Comment[ku]=Rewşa Bişkojkeke Mifteyê (wekî Caps Lock an jî Num Lock) hate guhertin û niha çalak e +Comment[lt]=Užrakto klavišo (pvz., Didž(Caps Lock) arba Sk(Num Lock)) būsena pakito ir jis dabar – aktyvus +Comment[lv]=Slēga taustiņš (piem. Caps Lock vai Num Lock) ir mainījis stāvokli un tagad ir aktīvs +Comment[mk]=Некое копче за заклучување (пр. Caps Lock или Num Lock) си ја смени состојбата и сега е активно +Comment[ml]=ഒരു ലോക്ക് കീ (ഉദാ. കാപ്സ് ലോക്ക് അല്ലെങ്കില്‍ നം ലോക്ക്) അവസ്ഥ മാറി സജീവമാക്കിയിരിക്കുന്നു +Comment[mr]=कुलूपबंद कि (उ.दा. Caps Lock किंवा Num Lock) ने स्तर बदलविले आहे व आता सक्रिय आहे +Comment[nb]=En låsetast (f.eks. Caps Lock eller Num Lock) har endret status og er nå slått på +Comment[nds]=En Tastrast (Tallen- oder Grootschriev-Rast a.B.) hett sien Tostand ännert un is nu inleggt +Comment[nl]=Een vergrendeltoets (bijv. Caps Lock of Num Lock ) is nu actief +Comment[nn]=Ein låsetast (som «Caps Lock» eller «Num Lock») har endra status, og er no aktiv +Comment[or]=ଗୋଟିଏ ଅପରିବର୍ତ୍ତନୀୟ କି (ଯେପରିକି Caps Lock କିମ୍ବା Num Lock) ସେମାନଙ୍କର ସ୍ଥିତି ପରିବର୍ତ୍ତନ କରିଛନ୍ତି ଏବଂ ବର୍ତ୍ତମାନ ସକ୍ରିୟ ଅଛନ୍ତି +Comment[pl]=Klawisz blokujący (np. Caps Lock lub Num Lock) zmienił stan i jest teraz włączony +Comment[pt]=Uma tecla de bloqueio (p.ex., a Caps Lock ou a Num Lock) alterou o seu estado e ficou agora activa +Comment[pt_BR]=Uma tecla de bloqueio (p.ex. Caps Lock ou Num Lock) teve seu estado alterado e agora está ativa +Comment[ro]=O tastă de blocare (cum ar fi Caps Lock sau Num Lock) și-a schimbat starea și este acum activă +Comment[ru]=Клавиша переключения режимов (например, Caps Lock или Num Lock) изменила своё состояние и сейчас активна +Comment[si]=අගුළු යතුරේ (උදා. Caps Lock හෝ Num Lock) තත්වය වෙනස් වී ඇති අතර එය දැන් සක්‍රීයයි +Comment[sk]=Zamykací kláves (napr. Caps Lock alebo Num Lock) zmenil svoj stav a je teraz aktívny +Comment[sl]=Zaklepna tipka (npr. Caps Lock ali Num Lock) je spremenila stanje in je sedaj dejavna +Comment[sr]=Закључавајући тастер (нпр. CapsLock или NumLock) променио је стање и сада је активан +Comment[sr@ijekavian]=Закључавајући тастер (нпр. CapsLock или NumLock) промијенио је стање и сада је активан +Comment[sr@ijekavianlatin]=Zaključavajući taster (npr. CapsLock ili NumLock) promijenio je stanje i sada je aktivan +Comment[sr@latin]=Zaključavajući taster (npr. CapsLock ili NumLock) promenio je stanje i sada je aktivan +Comment[sv]=En låstangent (t.ex. Caps Lock eller Num Lock) har ändrat tillstånd och är nu aktiv +Comment[ta]=A lock key (e.g. Caps Lock or Num Lock) has changed its state and is now active +Comment[te]=అప్రవేశపు కీ (ఉ.దా. Caps Lock లేదా Num Lock) దాని స్థితి మార్చుకుంది మరియు ఇప్పుడు క్రియాశీలంగా ఉంది +Comment[tg]=Клавиша переключения режимов (например, Caps Lock или Num Lock) изменила своё состояние и сейчас активна +Comment[th]=ปุ่มล็อค (เช่น Caps Lock หรือ Num Lock) ได้มีการเปลี่ยนสถานะของมันและขณะนี้กำลังทำงานอยู่ +Comment[tr]=Bir kilitleme tuşunun (Caps Lock ya da Num Lock gibi.) durumu değiştirildi ve etkinleştirildi +Comment[ug]=بىر قۇلۇپلاش كۇنۇپكىسى (مەسىلەن، Caps Lock ياكى Num Lock) ئۇنىڭ ھالىتىنى ئۆزگەرتتى، ھازىر ئاكتىپلاندى +Comment[uk]=Клавіша фіксації (наприклад Caps Lock або Num Lock) змінила свій стан і тепер активна +Comment[wa]=Ene eclawåve tape ki sere (metans CAPS LOCK oudonbén NUM LOCK) a candjî si estat eyet est asteure ovrante +Comment[x-test]=xxA lock key (e.g. Caps Lock or Num Lock) has changed its state and is now activexx +Comment[zh_CN]=锁定键(如 Caps Lock 或 Num Lock)更改了其状态,现已激活 +Comment[zh_TW]=一個鎖定鍵(如 CapsLock 或 NumLock)已改變它的狀態為啟用 +Sound=KDE-Sys-Special.ogg + +nopresentation=236 + +[Event/lockkey-unlocked] +Name=A lock key has been deactivated +Name[af]='n Sluit sleutel was gedeaktiveer +Name[ar]=تم إلغاء تفعيل مفتاح قفل +Name[ast]=Desactivóse una tecla de bloquéu +Name[be@latin]=Klaviša macavańnia adcisnutaja +Name[bg]=Изключен е клавиш за превключване на режим +Name[bn]=একটি লক কী (lock key) নিষ্ক্রীয় হয়েছে +Name[bs]=Zaključavajući taster je deaktiviran +Name[ca]=S'ha desactivat alguna tecla de fixació +Name[ca@valencia]=S'ha desactivat alguna tecla de fixació +Name[cs]=Klávesa pro přepnutí stavu byla deaktivována +Name[csb]=Klawisza blokadë òsta deaktiwòwónô +Name[da]=En låsetast er blevet deaktiveret +Name[de]=Eine Sperrtaste ist deaktiviert worden +Name[el]=Ένα πλήκτρο κλειδώματος απενεργοποιήθηκε +Name[en_GB]=A lock key has been deactivated +Name[eo]=Baskula klavo malaktiviĝis +Name[es]=Se ha desactivado una tecla de bloqueo +Name[et]=Lukustusklahv on nüüd mitteaktiivne +Name[eu]=Blokeo-tekla bat desaktibatu da +Name[fi]=Lukitusnäppäin on nyt deaktivoitu +Name[fr]=Une touche de verrouillage a été désactivée +Name[fy]=In beskoatteltoets is ûntaktivearre +Name[ga]=Tá eochair ghlasála neamhghníomhach anois +Name[gl]=Desactivouse unha tecla de bloqueo +Name[gu]=તાળાં કળ નિષ્ક્રિય કરવામાં આવી છે +Name[he]=מקש נועל הפך ללא פעיל +Name[hi]=कोई तालाबंद कुंजी अक्रिय किया जा चुका है +Name[hne]=कोई ताला कुंजी हर अक्रिय हो गे हे +Name[hr]=Tipka zaključavanja je deaktivirana +Name[hsb]=Tasta za stajne zaswěćene je nětko njeaktiwna +Name[hu]=Egy zároló billentyű inaktívvá vált +Name[ia]=Un clave de bloco ha essite deactivate +Name[id]=Sebuah tombol kunci telah dinonaktifkan +Name[is]=Læsilykill hefur verið aftengdur +Name[it]=Un tasto di blocco è stato disattivato +Name[ja]=ロックキーが非アクティブになりました +Name[ka]=დაბლოკვის ღილაკი ამორთულია +Name[kk]=Қосқыш перне белсенсіздірілді +Name[km]=គ្រាប់​ចុច​ចាក់​សោ​ត្រូវ​បាន​​​ធ្វើ​ឲ្យ​អសកម្ម +Name[kn]=ಒಂದು ಭಂಧನ ಕೀಲಿಯನ್ನು (ಲಾಕ್) ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Name[ko]=잠금 키가 비활성화됨 +Name[ku]=Bişkojkeke Mifteyê hate neçalakirin +Name[lt]=Užrakto klavišas buvo išjungtas +Name[lv]=Slēga taustiņš tika deaktivizēts +Name[mk]=Некое копче за заклучување беше активирано +Name[ml]=ഒരു ലോക്ക് കീ നിര്‍ജ്ജീവമാക്കിയിരിക്കുന്നു +Name[mr]=कुलूपबंद कि निष्क्रिय केली गेली +Name[nb]=En låsetast er blitt slått av +Name[nds]=En Tastrast is nich mehr inleggt +Name[ne]=लक कुञ्जी निष्क्रिय भएको छ +Name[nl]=Een vergrendeltoets is gedeactiveerd +Name[nn]=Ein låsetast er no inaktiv +Name[or]=ଗୋଟିଏ ଅପରିବର୍ତ୍ତନୀୟ କିକୁ ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Name[pa]=ਇੱਕ ਲਾਕ ਸਵਿੱਚ ਡਿਐਕਟਿਵੇਟ ਕੀਤੀ ਗਈ +Name[pl]=Klawisz blokujący został wyłączony +Name[pt]=Uma tecla de bloqueio foi desactivada +Name[pt_BR]=Uma tecla de bloqueio foi desativada +Name[ro]=O tastă de blocare a fost dezactivată +Name[ru]=Деактивирована клавиша переключения режимов +Name[se]=Lohkkadanboallu ii leat šat aktiivalaš +Name[si]=අගුළු යතුර අක්‍රීයයි +Name[sk]=Zamykací kláves je neaktívny +Name[sl]=Zaklepna tipka je bila onemogočena +Name[sr]=Закључавајући тастер је деактивиран +Name[sr@ijekavian]=Закључавајући тастер је деактивиран +Name[sr@ijekavianlatin]=Zaključavajući taster je deaktiviran +Name[sr@latin]=Zaključavajući taster je deaktiviran +Name[sv]=En låstangent har inaktiverats +Name[ta]=A lock key has been deactivated +Name[te]=అప్రవేశపు కీ క్రియాహీనం చేయబడింది +Name[tg]=Деактивирована клавиша переключения режимов +Name[th]=ปุ่มล็อคถูกปิดการทำงาน +Name[tr]=Bir kilitleme tuşu pasifleştirildi +Name[ug]=بىر قۇلۇپلاش كۇنۇپكىسى پاسسىپلاشتۇرۇلدى +Name[uk]=Було деактивовано клавішу фіксації +Name[wa]=Ene eclawåve tape a stî dismetowe +Name[x-test]=xxA lock key has been deactivatedxx +Name[zh_CN]=锁定键现已停用 +Name[zh_TW]=已解除鎖定鍵 +Comment=A lock key (e.g. Caps Lock or Num Lock) has changed its state and is now inactive +Comment[af]='n Sluitsleutel (bv. Caps Lock of Num Lock) se toestand het verander en is nou onaktief +Comment[ar]=تغيرت حالة مفتاح قفل (Caps Lock أو Num Lock) وألغي تفعيله +Comment[ast]=Una tecla de bloquéu (como Bloq Mayús o Bloq Num) camudó l'estáu y non ta activada +Comment[be@latin]=Klaviša macavańnia (naprykład, „Caps Lock” ci „Num Lock”) źmianiła svajo stanovišča j ciapier adcisnutaja. +Comment[bg]=Клавиш за превключване на режим (напр. Caps Lock или Num Lock) промени състоянието си и е неактивен +Comment[bn]=একটি লক কী (e.g. Caps Lock বা Num Lock) অবস্থা পরিবর্তন করে এখন নিষ্ক্রীয় হয়েছে +Comment[bs]=Zaključavajući taster (npr. CapsLock ili NumLock) promijenio je stanje i više nije aktivan +Comment[ca]=Alguna tecla de fixació (p.ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està inactiva +Comment[ca@valencia]=Alguna tecla de fixació (p.ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està inactiva +Comment[cs]=Klávesa pro přepnutí stavu (např. CapsLock nebo NumLock) byla stisknuta a je nyní neaktivní +Comment[csb]=Klawisza blokadë (Caps Lock abò Num Lock) zmienia swój sztatus ë nie je ju aktiwnô +Comment[da]=En låsetast (f.eks. Caps Lock eller Num Lock) har ændret sin tilstand og er nu inaktiv +Comment[de]=Eine Sperrtaste (Feststelltaste oder Nummernblocksperre) hat ihren Status geändert und ist nun inaktiv +Comment[el]=Ένα πλήκτρο κλειδώματος (π.χ. Caps Lock ή Num Lock) άλλαξε την κατάστασή του και είναι τώρα ανενεργό +Comment[en_GB]=A lock key (e.g. Caps Lock or Num Lock) has changed its state and is now inactive +Comment[eo]=Baskula klavo (ekz. majuskla baskulo aŭ nombra baskulo) ŝanĝis sian staton kaj nun estas malaktiva +Comment[es]=Una tecla de bloqueo (como Bloq Mayús o Bloq Num) ha cambiado su estado y no está activa +Comment[et]=Lukustusklahv (nt. Caps Lock või Num Lock) muutis oma seisundit ning on nüüd mitteaktiivne +Comment[eu]=Blokeo-tekla bat (adibidez, Blok Maius edo Blok Zenb) egoeraz aldatu da, eta orain inaktibo dago +Comment[fi]=Lukitusnäppäin (esim. CapsLock tai NumLock) on vaihtanut tilaansa ja ei ole enää aktiivinen +Comment[fr]=Une touche de verrouillage (ex : « Verr. Maj. » ou « Verr. Num. ») a changé d'état et est maintenant inactive +Comment[fy]=De tastân fan in beskoatteltoets (lykas kaptaalskoattel of Nûm skoattel) is feroare en is no ynaktyf +Comment[ga]=Athraíodh staid eochrach glasála (m.sh. Caps Lock nó Num Lock) agus tá sí neamhghníomhach anois +Comment[gl]=Unha tecla de bloqueo (por ex., Bloq Maiúsc ou Bloq Num) mudou de estado e agora está inactiva +Comment[gu]=તાળાં કળે (દા.ત., કેપ્સ લોક અથવા નમ લોક) હવે તેની સ્થિતિ બદલી છે અને હવે તે નિષ્ક્રિય છે +Comment[he]=מקש נועל (למשל Caps Lock או Num Lock) שינה את מצבו וכרגע לא פעיל +Comment[hne]=कोई ताला कुंजी (जइसन कि कैप्स लाक या न्यूम लाक) हर अपन स्थिति ल बदल दे हे अउ अब वो हर अक्रिय हो गे हे +Comment[hr]=Tipka zaključavanja (npr. CapsLock ili NumLock) promijenila je svoje stanje i više nije aktivna +Comment[hsb]=Tasta za stajne zaswěćene (na př. Stajny Wulkopis) je status změniła a je nětko njeaktiwna +Comment[hu]=Egy zároló billentyű (pl. a Caps Lock vagy a Num Lock) inaktívvá vált +Comment[ia]=Un clave de bloco (p.ex. Caps Lock o Num Lock) ha cambiate su stato e ora es inactive +Comment[id]=Sebuah tombol kunci (misalnya Caps Lock atau Num Lock) telah diubah keadaannya dan sekarang tidak aktif +Comment[is]=Læsilykill (t.d. Caps Lock eða Num Lock) hefur breytt um stöðu og er nú óvirkur +Comment[it]=Un tasto di blocco (ad es. Bloc Maiusc o Bloc Num) ha cambiato stato ed è ora disattivo +Comment[ja]=ロックキー (Caps Lock や Num Lock) の状態が変更され、非アクティブになりました +Comment[kk]=Қосқыш перне (мыс. Caps Lock не Num Lock) күйін ауыстырып енді белсенді емес +Comment[km]=គ្រាប់​ចុច​ចាក់​សោ (ឧ. ប្ដូរ​ជាប់ (Caps Lock) ឬ​គ្រាប់ចុច​លេខ (Num Lock)) បាន​ត្រូវ​ផ្លាស់ប្ដូរ​ស្ថានភាព​​របស់​​វា ហើយ​ឥឡូវ​នេះ​អសកម្ម +Comment[kn]=ಒಂದು ಭಂಧನ (ಲಾಕ್) ಕೀಲಿ (ಉ.ದಾ Shift ಅಥವಾ Ctrl) ನ ಸ್ಥಿತಿಯು ಬದಲಾಗಿದ್ದು ಈಗ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ +Comment[ko]=Caps Lock이나 Num Lock 키 같은 잠금 키의 상태가 바뀌었고 현재 비활성화됨 +Comment[ku]=Rewşa bişkojkeke mifteyê (wekî Caps Lock an jî Num Lock) hate guhertin û niha neçalak e +Comment[lt]=Užrakto klavišo (pvz., Didž(Caps Lock) arba Sk(Num Lock)) būsena pakito ir jis dabar – neaktyvus +Comment[lv]=Slēga taustiņš (piem. Caps Lock vai Num Lock) ir mainījis stāvokli un tagad ir neaktīvs +Comment[mk]=Некое копче за заклучување (пр. Caps Lock или Num Lock) си ја смени состојбата и сега е неактивно +Comment[ml]=ഒരു ലോക്ക് കീ (ഉദാ. കാപ്സ് ലോക്ക് അല്ലെങ്കില്‍ നം ലോക്ക്) അവസ്ഥ മാറി നിര്‍ജീവമായിരിക്കുന്നു +Comment[mr]=कुलूपबंद कि (उ.दा. Caps Lock किंवा Num Lock) ने स्तर बदलविले आहे व आता निष्क्रिय आहे +Comment[nb]=En låsetast (f.eks. Caps Lock eller Num Lock) har endret status og er nå slått av +Comment[nds]=En Tastrast (Tallen- oder Grootschriev-Rast a.B.) hett sien Tostand ännert un is nu nich mehr inleggt +Comment[nl]=Een vergrendeltoets (bijv. Caps Lock of Num Lock ) is nu inactief +Comment[nn]=Ein låsetast (som «Caps Lock» eller «Num Lock») har endra status, og er no inaktiv +Comment[or]=ଗୋଟିଏ ଅପରିବର୍ତ୍ତନୀୟ କି (ଯେପରିକି Caps Lock କିମ୍ବା Num Lock) ସେମାନଙ୍କର ସ୍ଥିତି ପରିବର୍ତ୍ତନ କରିଛନ୍ତି ଏବଂ ବର୍ତ୍ତମାନ ନିଷ୍କ୍ରିୟ ଅଛି +Comment[pl]=Klawisz blokujący (np. Caps Lock lub Num Lock) zmienił stan i jest teraz wyłączony +Comment[pt]=Uma tecla de bloqueio (p.ex., a Caps Lock ou a Num Lock) alterou o seu estado e ficou agora inactiva +Comment[pt_BR]=Uma tecla de bloqueio (p.ex. Caps Lock ou Num Lock) teve seu estado alterado e agora está inativa +Comment[ro]=O tastă de blocare (cum ar fi Caps Lock sau Num Lock) și-a schimbat starea și este acum inactivă +Comment[ru]=Клавиша переключения режимов (например, Caps Lock или Num Lock) изменила своё состояние и сейчас не активна +Comment[si]=අගුළු යතුරේ (උදා. Caps Lock හෝ Num Lock) තත්වය වෙනස් වී ඇති අතර එය දැන් අක්‍රීයයි +Comment[sk]=Zamykací kláves (napr. Caps Lock alebo Num Lock) zmenil svoj stav a je teraz neaktívny +Comment[sl]=Zaklepna tipka (npr. Caps Lock ali Num Lock) je spremenila stanje in je sedaj nedejavna +Comment[sr]=Закључавајући тастер (нпр. CapsLock или NumLock) променио је стање и више није активан +Comment[sr@ijekavian]=Закључавајући тастер (нпр. CapsLock или NumLock) промијенио је стање и више није активан +Comment[sr@ijekavianlatin]=Zaključavajući taster (npr. CapsLock ili NumLock) promijenio je stanje i više nije aktivan +Comment[sr@latin]=Zaključavajući taster (npr. CapsLock ili NumLock) promenio je stanje i više nije aktivan +Comment[sv]=En låstangent (t.ex. Caps Lock eller Num Lock) har ändrat tillstånd och är nu inaktiv +Comment[ta]=A lock key (e.g. Caps Lock or Num Lock) has changed its state and is now inactive +Comment[te]=అప్రవేశపు కీ (ఉ.దా. Caps Lock లేదా Num Lock) దాని స్థితిని మార్చుకుంది మరియు ఇప్పుడు క్రియాహీనంగా ఉంది +Comment[tg]=Клавиша переключения режимов (например, Caps Lock или Num Lock) изменила своё состояние и сейчас не активна +Comment[th]=ปุ่มล็อค (เช่น Caps Lock หรือ Num Lock) ได้มีการเปลี่ยนสถานะของมันและขณะนี้ได้ปิดการทำงาน +Comment[tr]=Bir kilitleme tuşunun (Caps Lock ya da Num Lock gibi.) durumu değiştirildi ve pasifleştirildi +Comment[ug]=بىر قۇلۇپلاش كۇنۇپكىسى (مەسىلەن، Caps Lock ياكى Num Lock) ئۇنىڭ ھالىتىنى ئۆزگەرتتى، ھازىر پاسسىپلاشتۇرۇلدى +Comment[uk]=Клавіша фіксації (наприклад Caps Lock або Num Lock) змінила свій стан і тепер неактивна +Comment[wa]=Ene eclawåve tape (metans CAPS LOCK oudonbén NUM LOCK) a candjî si estat eyet n' est asteure pus ovrante +Comment[x-test]=xxA lock key (e.g. Caps Lock or Num Lock) has changed its state and is now inactivexx +Comment[zh_CN]=锁定键(如 Caps Lock 或 Num Lock)更改了其状态,现已停用 +Comment[zh_TW]=一個鎖定鍵(如 CapsLock 或 NumLock)已改變它的狀態成為未啟用 +Sound=KDE-Sys-Special.ogg + +nopresentation=236 + +[Event/stickykeys] +Name=Sticky keys has been enabled or disabled +Name[af]=Sticky sleutels was geaktiveer of gedeaktiveer +Name[ar]=تم تفعيل أو إلغاء تفعيل المفاتيح المثبتة +Name[ast]=Les tecles pegañoses activáronse o desactiváronse +Name[be@latin]=Lipučyja klavišy źmianili svajo stanovišča +Name[bg]="Лепкави" клавиши са включени или изключени +Name[bs]=Ljepljivi tasteri su uključeni ili isključeni +Name[ca]=Les tecles apegaloses s'han activat o desactivat +Name[ca@valencia]=Les tecles apegaloses s'han activat o desactivat +Name[cs]=Lepivé klávesy byly povoleny nebo zakázány +Name[csb]=Klawisze przëlepieniô òstałë aktiwòwòné abò deaktiwòwóné +Name[da]=Klæbende taster er aktiveret eller deaktiveret +Name[de]=Klebende Tasten sind aktiviert oder deaktiviert worden +Name[el]=Τα κολλημένα πλήκτρα ενεργοποιήθηκαν ή απενεργοποιήθηκαν +Name[en_GB]=Sticky keys has been enabled or disabled +Name[eo]=Fiksaj klavoj validiĝis aŭ malvalidiĝis +Name[es]=Las teclas pegajosas se han activado o desactivado +Name[et]=Kleepuvad klahvid on keelatud või lubatud +Name[eu]=Tekla itsaskorrak gaitu edo desgaitu dira +Name[fi]=Tahmeat näppäimet on otettu käyttöön tai poistettu käytöstä +Name[fr]=L'auto-maintien des touches a été activé ou désactivé +Name[fy]=Plakkende toetsen binne aktivearre of deaktivearre +Name[ga]=Cumasaíodh nó díchumasaíodh eochracha greamaitheacha +Name[gl]=As teclas pegañentas activáronse ou desactiváronse +Name[gu]=સ્થિત કળો સક્રિય અથવા નિષ્ક્રિય કરવામાં આવી છે +Name[he]=מקשים דביקים הופעלו או בוטלו +Name[hi]=चिपकती कुंजियों को सक्षम या अक्षम किया गया है +Name[hne]=स्टिकी कुंजी सक्रिय या अक्रिय हो गे हे +Name[hr]=Ljepljive tipke su omogućene ili onemogućene +Name[hsb]=Lěpjate tasty zaswěćene abo hasnjene +Name[hu]=Ragadós billentyűk átkapcsolva +Name[ia]=Le claves collate ha essite habilitate o dishabilitate +Name[id]=Tombol lekat telah diaktifkan atau dinonaktifkan +Name[is]=Slökkt eða kveikt hefur verið á klístruðum lyklum +Name[it]=I tasti permanenti sono stati attivati o disattivati +Name[ja]=スティッキーキーが有効または無効になりました +Name[kk]=Жабысқақ пернелер рұқсат етілді/етілмеді +Name[km]=គ្រាប់​ចុច​ស្អិត​​ត្រូវ​បាន​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត +Name[kn]=ಅಂಟು (ಸ್ಟಿಕಿ) ಕೀಲಿಯನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Name[ko]=끈적이 키가 활성화되거나 비활성화됨 +Name[ku]=Bişkojkên Mezeloqî hatin çalakirin an jî neçalakirin +Name[lt]=Lipnūs klavišai buvo įgalinti arba išjungti +Name[lv]=Lipīgie taustiņi tika ieslēgti vai izslēgti +Name[mk]=„Лепливи копчиња“ е овозможено или оневозможено +Name[ml]=സ്റ്റിക്കി കീ പ്രവര്‍ത്തന സജ്ജം അല്ലെങ്കില്‍ പ്രവര്‍ത്തന രഹിതം ആക്കിയിരിക്കുന്നു +Name[mr]=स्टिकी कि कार्यन्वीत किंवा अकार्यान्वित केली गेली आहे +Name[nb]=Faste valgtaster er blitt slått på eller av +Name[nds]="Backig Tasten" wöör an- oder utmaakt +Name[ne]=स्टिकी कुञ्जीहरू सक्षम वा अक्षम बनाइएको छ +Name[nl]=Plakkende toetsen is geactiveerd of gedeactiveerd +Name[nn]=Faste valtastar er no slått på eller av +Name[or]=Sticky କିଗୁଡ଼ିକୁ ସକ୍ରିୟ ଅଥବା ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Name[pa]=ਸਟਿੱਕੀ ਸਵਿੱਚਾਂ ਯੋਗ ਜਾਂ ਆਯੋਗ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ +Name[pl]=Lepkie klawisze zostały włączone lub wyłączone +Name[pt]=As teclas fixas foram activadas ou desactivadas +Name[pt_BR]=Teclas de aderência foram habilitadas ou desabilitadas +Name[ro]=Taste lipicioase au fost activate sau dezactivate +Name[ru]=Включены или отключены «залипающие» клавиши +Name[se]=Giddes válljenboallu lea rievdadan stáhtusa +Name[si]=ඇළෙන යතුරු සක්‍රීය හෝ අක්‍රීය කර ඇත +Name[sk]=Lepkavé klávesy zmenili svoj stav +Name[sl]=Lepljive tipke so bile omogočene ali onemogočene +Name[sr]=Лепљиви тастери су укључени или искључени +Name[sr@ijekavian]=Љепљиви тастери су укључени или искључени +Name[sr@ijekavianlatin]=Ljepljivi tasteri su uključeni ili isključeni +Name[sr@latin]=Lepljivi tasteri su uključeni ili isključeni +Name[sv]=Klistriga tangenter har aktiverats eller inaktiverats +Name[ta]=Sticky keys has been enabled or disabled +Name[te]=స్టికీ కీలు చేతనంకాబడినవి లేదా అచేతనంకాబడినవి +Name[tg]=Тугмаҳои часпанда фаъол ё ғайрифаъол шудаанд +Name[th]=การกดปุ่มพิมพ์ค้างได้ถูกเปิดหรือปิดการทำงาน +Name[tr]=Yapışkan tuşlar etkinleştirildi ya da pasifleştirildi +Name[ug]=چاپلىشاڭغۇ(Sticky) كۇنۇپكىلار ئىناۋەتلىك ياكى چەكلەنگەن +Name[uk]=Було активовано або деактивовано липкі клавіші +Name[wa]=Les aclapantès tapes on stî metowes oudonbén dismetowes +Name[x-test]=xxSticky keys has been enabled or disabledxx +Name[zh_CN]=启用或禁用了粘滞键 +Name[zh_TW]=相黏鍵已改變狀態 +Comment=Sticky keys has been enabled or disabled +Comment[af]=Sticky sleutels was geaktiveer of gedeaktiveer +Comment[ar]=تم تفعيل أو إلغاء تفعيل المفاتيح المثبتة +Comment[ast]=Les tecles pegañoses activáronse o desactiváronse +Comment[be@latin]=Lipučyja klavišy źmianili svajo stanovišča. +Comment[bg]="Лепкави" клавиши са включени или изключени +Comment[bs]=Ljepljivi tasteri su uključeni ili isključeni +Comment[ca]=Les tecles apegaloses s'han activat o desactivat +Comment[ca@valencia]=Les tecles apegaloses s'han activat o desactivat +Comment[cs]=Lepivé klávesy byly povoleny nebo zakázány +Comment[csb]=Klawisze przëlepieniô òstałë aktiwòwòné abò deaktiwòwóné +Comment[da]=Klæbende taster er aktiveret eller deaktiveret +Comment[de]=Die Funktion „Klebende Tasten“ ist aktiviert oder deaktiviert worden +Comment[el]=Τα κολλημένα πλήκτρα ενεργοποιήθηκαν ή απενεργοποιήθηκαν +Comment[en_GB]=Sticky keys has been enabled or disabled +Comment[eo]=Fiksaj klavoj validiĝis aŭ malvalidiĝis +Comment[es]=Las teclas pegajosas se han activado o desactivado +Comment[et]=Kleepuvad klahvid on keelatud või lubatud +Comment[eu]=Tekla itsaskorrak gaitu edo desgaitu dira +Comment[fi]=Tahmeat näppäimet on otettu käyttöön tai poistettu käytöstä +Comment[fr]=L'auto-maintien des touches a été activé ou désactivé +Comment[fy]=Plakkende toetsen binne aktivearre of deaktivearre +Comment[ga]=Cumasaíodh nó díchumasaíodh eochracha greamaitheacha +Comment[gl]=As teclas pegañentas foron ou activadas ou desactivadas +Comment[gu]=સ્થિત કળો સક્રિય અથવા નિષ્ક્રિય કરવામાં આવી છે +Comment[he]=מקשים דביקים הופעלו או בוטלו +Comment[hi]=चिपकती कुंजियों को सक्षम या अक्षम किया गया है +Comment[hne]=स्टिकी कुंजी सक्रिय या अक्रिय हो गे हे +Comment[hr]=Ljepljive tipke su omogućene ili onemogućene +Comment[hsb]=Lěpjate tasty zaswěćene abo hasnjene +Comment[hu]=A ragadós billentyűk használatát ki- vagy bekapcsolták +Comment[ia]=Le claves collate ha essite habilitate o dishabilitate +Comment[id]=Tombol lekat telah diaktifkan atau dinonaktifkan +Comment[is]=Slökkt eða kveikt hefur verið á klístruðum lyklum +Comment[it]=I tasti permanenti sono stati attivati o disattivati +Comment[ja]=スティッキーキーが有効または無効になりました +Comment[kk]=Жабысқақ пернелер рұқсат етілді/етілмеді +Comment[km]=គ្រាប់​ចុច​ស្អិត​​ត្រូវ​បាន​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត +Comment[kn]=ಅಂಟು (ಸ್ಟಿಕಿ) ಕೀಲಿಯನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Comment[ko]=끈적이 키가 활성화되거나 비활성화됨 +Comment[ku]=Bişkojkên Mezeloqî hatin çalakirin an jî neçalakirin +Comment[lt]=Lipnūs klavišai buvo įjungti arba išjungti +Comment[lv]=Lipīgie taustiņi tika ieslēgti vai izslēgti +Comment[mk]=„Лепливи копчиња“ е овозможено или оневозможено +Comment[ml]=സ്റ്റിക്കി കീ പ്രവര്‍ത്തന സജ്ജം അല്ലെങ്കില്‍ പ്രവര്‍ത്തന രഹിതം ആക്കിയിരിക്കുന്നു +Comment[mr]=स्टिकी कि कार्यन्वीत किंवा अकार्यान्वित केली गेली आहे +Comment[nb]=Faste valgtaster er blitt slått på eller av +Comment[nds]="Backig Tasten" wöör an- oder utmaakt +Comment[ne]=स्टिकी कुञ्जीहरू सक्षम वा अक्षम बनाइएको छ +Comment[nl]=Plakkende toetsen is geactiveerd of gedeactiveerd +Comment[nn]=Faste valtastar er no slått på eller av +Comment[or]=Sticky କିଗୁଡ଼ିକୁ ସକ୍ରିୟ ଅଥବା ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Comment[pa]=ਸਟਿੱਕੀ ਸਵਿੱਚਾਂ ਯੋਗ ਜਾਂ ਆਯੋਗ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ +Comment[pl]=Lepkie klawisze zostały włączone lub wyłączone +Comment[pt]=As teclas fixas foram activadas ou desactivadas +Comment[pt_BR]=Teclas de aderência foram habilitadas ou desabilitadas +Comment[ro]=Taste lipicioase au fost activate sau dezactivate +Comment[ru]=Включены или отключены «залипающие» клавиши +Comment[se]=Giddes válljenboallu lea rievdadan stáhtusa +Comment[si]=ඇළෙන යතුරු සක්‍රීය හෝ අක්‍රීය කර ඇත +Comment[sk]=Lepkavé klávesy zmenili svoj stav +Comment[sl]=Lepljive tipke so bile omogočene ali onemogočene +Comment[sr]=Лепљиви тастери су укључени или искључени +Comment[sr@ijekavian]=Љепљиви тастери су укључени или искључени +Comment[sr@ijekavianlatin]=Ljepljivi tasteri su uključeni ili isključeni +Comment[sr@latin]=Lepljivi tasteri su uključeni ili isključeni +Comment[sv]=Klistriga tangenter har aktiverats eller inaktiverats +Comment[ta]=Sticky keys has been enabled or disabled +Comment[te]=స్టికీ కీలు చేతనంకాబడినవి లేదా అచేతనంకాబడినవి +Comment[tg]=Тугмаҳои часпанда фаъол ё ғайрифаъол шудаанд +Comment[th]=การกดปุ่มพิมพ์ค้างได้ถูกเปิดหรือปิดการทำงาน +Comment[tr]=Yapışkan tuşlar etkinleştirildi ya da pasifleştirildi +Comment[ug]=چاپلىشاڭغۇ(Sticky) كۇنۇپكىلار ئىناۋەتلىك ياكى چەكلەنگەن +Comment[uk]=Було активовано або деактивовано липкі клавіші +Comment[wa]=Les aclapantès tapes on stî metowes oudonbén dismetowes +Comment[x-test]=xxSticky keys has been enabled or disabledxx +Comment[zh_CN]=启用或禁用了粘滞键 +Comment[zh_TW]=相黏鍵已啟動或關閉。 +Sound=KDE-Sys-Special.ogg +Action=Popup +nopresentation=236 + +[Event/slowkeys] +Name=Slow keys has been enabled or disabled +Name[af]=Stadige sleutels was geaktiveer of gedeaktiveer +Name[ar]=تم تفعيل أو إلغاء تفعيل المفاتيح البطيئة +Name[ast]=Les tecles lentes activáronse o desactiváronse +Name[be@latin]=Pavolnyja klavišy źmianili svajo stanovišča +Name[bg]="Бавни" клавиши са включени или изключени +Name[bs]=Spori tasteri su uključeni ili isključeni +Name[ca]=Les tecles lentes s'han activat o desactivat +Name[ca@valencia]=Les tecles lentes s'han activat o desactivat +Name[cs]=Pomalé klávesy byly povoleny nebo zakázány +Name[csb]=Pòwòlné klawisze òstałë aktiwòwòné abò deaktiwòwóné +Name[da]=Langsomme taster er aktiveret eller deaktiveret +Name[de]=Langsame Tasten sind aktiviert oder deaktiviert worden +Name[el]=Τα αργά πλήκτρα ενεργοποιήθηκαν ή απενεργοποιήθηκαν +Name[en_GB]=Slow keys has been enabled or disabled +Name[eo]=Malrapidklavoj validiĝis aŭ malvalidiĝis +Name[es]=Las teclas lentas se han activado o desactivado +Name[et]=Aeglased klahvid on keelatud või lubatud +Name[eu]=Tekla motelak gaitu edo desgaitu dira +Name[fi]=Hitaat näppäimet on otettu käyttöön tai poistettu käytöstä +Name[fr]=Les touches lentes ont été activées ou désactivées +Name[fy]=Trage toetsen binne aktivearre of ûntaktivearre +Name[ga]=Cumasaíodh nó díchumasaíodh eochracha malla +Name[gl]=As teclas lentas activáronse ou desactiváronse +Name[gu]=ધીમી કળો સક્રિય અથવા નિષ્ક્રિય કરવામાં આવી છે +Name[he]=תגובה איטית של המקשים הופעלה או הופסקה +Name[hi]=धीमी कुंजियों को सक्षम या अक्षम किया गया है +Name[hne]=धीमा कुंजी सक्रिय या अक्रिय हो गे हे +Name[hr]=Spore tipke su omogućene ili onemogućene +Name[hsb]=Pomałe tasty zaswěćene abo hasnjene +Name[hu]=A lassú billentyűk használata átkapcsolva +Name[ia]=Le claves lente ha essite activate o disactivate +Name[id]=Tombol pelan telah diaktifkan atau dinonaktifkan +Name[is]=Slökkt eða kveikt hefur verið á hægum lyklum +Name[it]=Il rallentamento dei tasti è stato attivato o disattivato +Name[ja]=スローキーが有効または無効になりました +Name[kk]=Баяу пернелер рұқсат етілді/етілмеді +Name[km]=គ្រាប់​ចុច​យឺត​​ត្រូវ​បាន​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត +Name[kn]=ನಿಧಾನ (ಸ್ಲೋ) ಕೀಲಿಯನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Name[ko]=느린 키가 활성화되거나 비활성화됨 +Name[ku]=Bişkojkên Hêdî hatin çalakirin an jî neçalakirin +Name[lt]=Lėti klavišai buvo įgalinti arba išjungti +Name[lv]=Lēnie taustiņi tika ieslēgti vai izslēgti +Name[mk]=„Спори копчиња“ е овозможено или оневозможено +Name[ml]=സ്ലോ കീ പ്രവര്‍ത്തന സജ്ജമലെങ്കില്‍ പ്രവര്‍ത്തന രഹിതമാക്കിയിരിക്കുന്നു +Name[mr]=हळु कार्यरत कि आता कार्यान्वित किंवा अकार्यान्वित केली गेली आहे +Name[nb]=Trege taster er blitt slått på eller av +Name[nds]="Langsam Tasten" wöör an- oder utmaakt +Name[ne]=शो कुञ्जीहरू सक्षम वा अक्षम बनाइएको छ +Name[nl]=Langzame toetsen is geactiveerd of gedeactiveerd +Name[nn]=Trege tastar er no slått på eller av +Name[or]=Slow କିଗୁଡ଼ିକୁ ସକ୍ରିୟ ଅଥବା ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Name[pa]=ਸਲੋਅ ਸਵਿੱਚਾਂ ਯੋਗ ਜਾਂ ਆਯੋਗ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ +Name[pl]=Powolne klawisze zostały włączone lub wyłączone +Name[pt]=As teclas lentas foram activadas ou desactivadas +Name[pt_BR]=Teclas lentas foram habilitadas ou desabilitadas +Name[ro]=Taste lente (Slow keys) au fost activate sau dezactivate +Name[ru]=Включены или отключены замедленные клавиши +Name[si]=වේගය අඩු යතුරු සක්‍රීය හෝ අක්‍රීය කර ඇත +Name[sk]=Pomalé klávesy zmenili svoj stav +Name[sl]=Počasne tipke so bile omogočene ali onemogočene +Name[sr]=Спори тастери су укључени или искључени +Name[sr@ijekavian]=Спори тастери су укључени или искључени +Name[sr@ijekavianlatin]=Spori tasteri su uključeni ili isključeni +Name[sr@latin]=Spori tasteri su uključeni ili isključeni +Name[sv]=Långsamma tangenter har aktiverats eller inaktiverats +Name[ta]=Slow keys has been enabled or disabled +Name[te]=స్లో కీలు చేతనంకాబడినవి లేదా అచేతనంకాబడినవి +Name[tg]=Тугмаҳои суст фаъол ё ғайрифаъол шудаанд +Name[th]=การกดปุ่มพิมพ์ช้าได้ถูกเปิดหรือปิดการทำงาน +Name[tr]=Yavaş tuşlar etkinleştirildi ya da pasifleştirildi +Name[ug]=ئاستا(Slow) كۇنۇپكىلار ئىناۋەتلىك ياكى چەكلەنگەن +Name[uk]=Було активовано або деактивовано повільні клавіші +Name[wa]=Des londjinnès tapes ont stî metowe en alaedje oudonbén dismetowes +Name[x-test]=xxSlow keys has been enabled or disabledxx +Name[zh_CN]=启用或禁用了筛选键 +Name[zh_TW]=慢速鍵已改變狀態 +Comment=Slow keys has been enabled or disabled +Comment[af]=Stadige sleutels was geaktiveer of gedeaktiveer +Comment[ar]=تم تفعيل أو إلغاء تفعيل المفاتيح البطيئة +Comment[ast]=Les tecles lentes activáronse o desactiváronse +Comment[be@latin]=Pavolnyja klavišy źmianili svajo stanovišča. +Comment[bg]="Бавни" клавиши са включени или изключени +Comment[bs]=Spori tasteri su uključeni ili isključeni +Comment[ca]=Les tecles lentes s'han activat o desactivat +Comment[ca@valencia]=Les tecles lentes s'han activat o desactivat +Comment[cs]=Pomalé klávesy byly povoleny nebo zakázány +Comment[csb]=Pòwòlné klawisze òstałë aktiwòwòné abò deaktiwòwóné +Comment[da]=Langsomme taster er aktiveret eller deaktiveret +Comment[de]=Die Funktion „Langsame Tasten“ ist aktiviert oder deaktiviert worden +Comment[el]=Τα αργά πλήκτρα ενεργοποιήθηκαν ή απενεργοποιήθηκαν +Comment[en_GB]=Slow keys has been enabled or disabled +Comment[eo]=Malrapidklavoj validiĝis aŭ malvalidiĝis +Comment[es]=Las teclas lentas se han activado o desactivado +Comment[et]=Aeglased klahvid on keelatud või lubatud +Comment[eu]=Tekla motelak gaitu edo desgaitu dira +Comment[fi]=Hitaat näppäimet on otettu käyttöön tai poistettu käytöstä +Comment[fr]=Les touches lentes ont été activées ou désactivées +Comment[fy]=Trage toetsen binne aktivearre of ûntaktivearre +Comment[ga]=Cumasaíodh nó díchumasaíodh eochracha malla +Comment[gl]=As teclas lentas foron ou activadas ou desactivadas +Comment[gu]=ધીમી કળો સક્રિય અથવા નિષ્ક્રિય કરવામાં આવી છે +Comment[he]=תגובה איטית של המקשים הופעלה או הופסקה +Comment[hi]=धीमी कुंजियों को सक्षम या अक्षम किया गया है +Comment[hne]=धीमा कुंजी सक्छम या अक्छम हो गे हे +Comment[hr]=Spore tipke su omogućene ili onemogućene +Comment[hsb]=Pomałe tasty zaswěćene abo hasnjene +Comment[hu]=A lassú billentyűk használatát ki- vagy bekapcsolták +Comment[ia]=Le claves lente ha essite activate o disactivate +Comment[id]=Tombol pelan telah diaktifkan atau dinonaktifkan +Comment[is]=Slökkt eða kveikt hefur verið á hægum lyklum +Comment[it]=Il rallentamento dei tasti è stato attivato o disattivato +Comment[ja]=スローキーが有効または無効になりました +Comment[kk]=Баяу пернелер рұқсат етілді/етілмеді +Comment[km]=គ្រាប់​ចុច​យឺត​ត្រូវ​បាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត +Comment[kn]=ನಿಧಾನ (ಸ್ಲೋ) ಕೀಲಿಯನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Comment[ko]=느린 키가 활성화되거나 비활성화됨 +Comment[ku]=Bişkojkên Hêdî hatin çalakirin an jî neçalakirin +Comment[lt]=Lėti klavišai buvo įgalinti arba išjungti +Comment[lv]=Lēnie taustiņi tika ieslēgti vai izslēgti +Comment[mk]=„Спори копчиња“ е овозможено или оневозможено +Comment[ml]=സ്ലോ കീ പ്രവര്‍ത്തന സജ്ജമലെങ്കില്‍ പ്രവര്‍ത്തന രഹിതമാക്കിയിരിക്കുന്നു +Comment[mr]=हळु कार्यरत कि आता कार्यान्वित किंवा अकार्यान्वित केली गेली आहे +Comment[nb]=Trege taster er blitt slått på eller av +Comment[nds]="Langsam Tasten" wöör an- oder utmaakt +Comment[ne]=शो कुञ्जीहरू सक्षम वा अक्षम बनाइएको छ +Comment[nl]=Langzame toetsen is geactiveerd of gedeactiveerd +Comment[nn]=Trege tastar er no slått på eller av +Comment[or]=Slow କିଗୁଡ଼ିକୁ ସକ୍ରିୟ ଅଥବା ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Comment[pa]=ਸਲੋਅ ਸਵਿੱਚਾਂ ਯੋਗ ਜਾਂ ਆਯੋਗ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ +Comment[pl]=Powolne klawisze zostały włączone lub wyłączone +Comment[pt]=As teclas lentas foram activadas ou desactivadas +Comment[pt_BR]=Teclas lentas foram habilitadas ou desabilitadas +Comment[ro]=Taste lente (Slow keys) au fost activate sau dezactivate +Comment[ru]=Включены или отключены замедленные клавиши +Comment[si]=වේගය අඩු යතුරු සක්‍රීය හෝ අක්‍රීය කර ඇත +Comment[sk]=Pomalé klávesy zmenili svoj stav +Comment[sl]=Počasne tipke so bile omogočene ali onemogočene +Comment[sr]=Спори тастери су укључени или искључени +Comment[sr@ijekavian]=Спори тастери су укључени или искључени +Comment[sr@ijekavianlatin]=Spori tasteri su uključeni ili isključeni +Comment[sr@latin]=Spori tasteri su uključeni ili isključeni +Comment[sv]=Långsamma tangenter har aktiverats eller inaktiverats +Comment[ta]=Slow keys has been enabled or disabled +Comment[te]=స్లో కీలు చేతనంకాబడినవి లేదా అచేతనంకాబడినవి +Comment[tg]=Тугмаҳои суст фаъол ё ғайрифаъол шудаанд +Comment[th]=การกดปุ่มพิมพ์ช้าได้ถูกเปิดหรือปิดการทำงาน +Comment[tr]=Yavaş tuşlar etkinleştirildi ya da pasifleştirildi +Comment[ug]=ئاستا(Slow) كۇنۇپكىلار ئىناۋەتلىك ياكى چەكلەنگەن +Comment[uk]=Було активовано або деактивовано повільні клавіші +Comment[wa]=Des londjinnès tapes ont stî metowe en alaedje oudonbén dismetowes +Comment[x-test]=xxSlow keys has been enabled or disabledxx +Comment[zh_CN]=启用或禁用了筛选键 +Comment[zh_TW]=慢速鍵已啟動或關閉。 +Sound=KDE-Sys-Special.ogg +Action=Popup +nopresentation=236 + +[Event/bouncekeys] +Name=Bounce keys has been enabled or disabled +Name[af]=Hopsleutels is geaktiveer of gedeaktiveer +Name[ar]=تم تفعيل أو إلغاء تفعيل المفاتيح المكررة +Name[ast]=Les tecles de rebote activáronse o desactiváronse +Name[bg]="Подскачащи" клавиши са включени или изключени +Name[bs]=Odskačući tasteri su uključeni ili isključeni +Name[ca]=Les tecles de repetició s'han activat o desactivat +Name[ca@valencia]=Les tecles de repetició s'han activat o desactivat +Name[cs]=Zdvojené klávesy byly povoleny nebo zakázány +Name[csb]=Òdbijającé klawisze òstałë aktiwòwòné abò deaktiwòwóné +Name[da]=Elastiske taster er aktiveret eller deaktiveret +Name[de]=Zurückschnellende Tasten sind aktiviert oder deaktiviert worden +Name[el]=Τα πλήκτρα αναπήδησης ενεργοποιήθηκαν ή απενεργοποιήθηκαν +Name[en_GB]=Bounce keys has been enabled or disabled +Name[eo]=Prokrastaj klavoj validiĝis aŭ malvalidiĝis +Name[es]=Se ha activado o desactivado el rebote de teclas +Name[et]=Põrkavad klahvid on keelatud või lubatud +Name[eu]=Errebote-teklak gaitu edo desgaitu dira +Name[fi]=Kimpoavat näppäimet on otettu käyttöön tai poistettu käytöstä +Name[fr]=Les touches non répétées ont été activées ou désactivées +Name[fy]=Stuiterjende toetsen binne aktivearre of ûntaktivearre +Name[ga]=Cumasaíodh nó díchumasaíodh eochracha preabtha +Name[gl]=A anulación temporal de teclas activouse ou desactivouse +Name[gu]=ઉછાળ કળો સક્રિય અથવા નિષ્ક્રિય કરવામાં આવી છે +Name[he]=מניעת לחיצה על מספר מקשים בו־זמנית הופעלה או הופסקה +Name[hi]=बाउंस कुंजियों को सक्षम या अक्षम किया गया है +Name[hne]=बाउन्स कुंजी सक्छम या अक्छम हो गे हे +Name[hr]=Obijanje tipki je omogućeno ili onemogućeno +Name[hsb]=Zamkane tasty zaswěćene abo hasnjene +Name[hu]=A visszaugró billentyűk átkapcsolva +Name[ia]=Le claves elastic ha essite activate o disactivate +Name[id]=Tombol pantul telah diaktifkan atau dinonaktifkan +Name[is]=Slökkt eða kveikt hefur verið á skoppandi lyklum +Name[it]=I tasti ravvicinati sono stati abilitati o disattivati +Name[ja]=バウンスキーが有効または無効になりました +Name[kk]=Қалшылға қарсы пернелер рұқсат етілді/етілмеді +Name[km]=គ្រាប់​ចុច​លោត​​ត្រូវ​បាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត +Name[kn]=ಪುಟಿಯುವ (ಬೌನ್ಸ್) ಕೀಲಿಯನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Name[ko]=튕김 키가 활성화되거나 비활성화됨 +Name[ku]=Bişkojkên Zindî hatin çalakirin an jî neçalakirin +Name[lt]=Tamprūs klavišai buvo įgalinti arba išjungti +Name[lv]=Atlecošie taustiņi tika ieslēgti vai izslēgti +Name[mk]=„Скокачки копчиња“ е овозможено или оневозможено +Name[ml]=ബൌണ്‍സ് കീ പ്രവര്‍ത്തന സജ്ജം അല്ലെങ്കില്‍ പ്രവര്‍ത്തന രഹിതം ആക്കിയിരിക്കുന്നു +Name[mr]=बाउन्स् कि कार्यान्वित किंवा अकार्यान्वित केली गेली आहे +Name[nb]=Filtertaster er blitt slått på eller av +Name[nds]="Jumpen Tasten" wöör an- oder utmaakt +Name[ne]=बाउन्स कुञ्जीहरू सक्षम वा अक्षम बनाइएको छ +Name[nl]=Stuiterende toetsen is geactiveerd of gedeactiveerd +Name[nn]=Filtertastar er no slått på eller av +Name[or]=Bounce କିଗୁଡ଼ିକୁ ସକ୍ରିୟ ଅଥବା ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Name[pa]=ਬਾਊਂਸ ਸਵਿੱਚਾਂ ਯੋਗ ਜਾਂ ਆਯੋਗ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ +Name[pl]=Odbijające klawisze zostały włączone lub wyłączone +Name[pt]=As teclas sonoras foram activadas ou desactivadas +Name[pt_BR]=As teclas de repercussão foram ativadas ou desativadas +Name[ro]=Taste săltărețe (Bounce keys) au fost activate sau dezactivate +Name[ru]=Включены или отключены «прыгающие» клавиши +Name[se]=Sillenboallu lea rievdadan stáhtusa +Name[si]=පොළාපැනුම් යතුරු සක්‍රීය හෝ අක්‍රීය කර ඇත +Name[sk]=Bounce klávesy zmenili svoj stav +Name[sl]=Odbijajoče tipke so bile omogočene ali onemogočene +Name[sr]=Одскачући тастери су укључени или искључени +Name[sr@ijekavian]=Одскачући тастери су укључени или искључени +Name[sr@ijekavianlatin]=Odskačući tasteri su uključeni ili isključeni +Name[sr@latin]=Odskačući tasteri su uključeni ili isključeni +Name[sv]=Studsande tangenter har aktiverats eller inaktiverats +Name[ta]=Bounce keys has been enabled or disabled +Name[te]=బౌన్‍స్ కీలు చేతనంకాబడినవి లేదా అచేతనంకాబడినవి +Name[tg]=Тугмаҳои ҷаҳиш фаъол ё ғайрифаъол шудаанд +Name[th]=การกดปุ่มพิมพ์รัวได้ถูกเปิดหรือปิดการทำงาน +Name[tr]=Sıçrama tuşları etkinleştirildi ya da pasifleştirildi +Name[ug]=سەكرىمە(Bounce) كۇنۇپكىلار ئىناۋەتلىك ياكى چەكلەنگەن +Name[uk]=Було активовано або деактивовано пружні клавіші +Name[vi]=Phím nảy đã được bật hoặc tắt +Name[wa]=Des dimey-eclawåvès tapes ont stî metowe en alaedje oudonbén dismetowes +Name[x-test]=xxBounce keys has been enabled or disabledxx +Name[zh_CN]=启用或禁用了撞击键 +Name[zh_TW]=彈回鍵已改變狀態 +Comment=Bounce keys has been enabled or disabled +Comment[af]=Hop sleutels was geaktiveer of gedeaktiveer +Comment[ar]=تم تفعيل أو إلغاء تفعيل المفاتيح المكررة +Comment[ast]=Les tecles de rebote activáronse o desactiváronse +Comment[bg]="Подскачащи" клавиши са включени или изключени +Comment[bs]=Odskačući tasteri su uključeni ili isključeni +Comment[ca]=Les tecles de repetició s'han activat o desactivat +Comment[ca@valencia]=Les tecles de repetició s'han activat o desactivat +Comment[cs]=Zdvojené klávesy byly povoleny nebo zakázány +Comment[csb]=Òdbijającé klawisze òstałë aktiwòwòné abò deaktiwòwóné +Comment[da]=Elastiske taster er aktiveret eller deaktiveret +Comment[de]=Die Funktion „Zurückschnellende Tasten“ ist aktiviert oder deaktiviert worden +Comment[el]=Τα πλήκτρα αναπήδησης ενεργοποιήθηκαν ή απενεργοποιήθηκαν +Comment[en_GB]=Bounce keys has been enabled or disabled +Comment[eo]=Prokrastaj klavoj validiĝis aŭ malvalidiĝis +Comment[es]=Se ha activado o desactivado el rebote de teclas +Comment[et]=Põrkavad klahvid on keelatud või lubatud +Comment[eu]=Errebote-teklak gaitu edo desgaitu dira +Comment[fi]=Kimpoavat näppäimet on otettu käyttöön tai poistettu käytöstä +Comment[fr]=Les touches non répétées ont été activées ou désactivées +Comment[fy]=Stuiterjende toetsen binne aktivearre of ûntaktivearre +Comment[ga]=Cumasaíodh nó díchumasaíodh eochracha preabtha +Comment[gl]=A anulación temporal de teclas foi ou activada ou desactivada +Comment[gu]=ઉછાળ કળો સક્રિય અથવા નિષ્ક્રિય કરવામાં આવી છે +Comment[he]=מניעת לחיצה על מספר מקשים בו־זמנית הופעלה או הופסקה +Comment[hi]=बाउंस कुंजियों को सक्षम या अक्षम किया गया है +Comment[hne]=बाउन्स कुंजी सक्छम या अक्छम हो गे हे +Comment[hr]=Obijanje tipki je omogućeno ili onemogućeno +Comment[hsb]=Zamkane tasty zaswěćene abo hasnjene +Comment[hu]=A visszaugró billentyűk használatát ki- vagy bekapcsolták +Comment[ia]=Le claves elastic ha essite activate o disactivate +Comment[id]=Tombol pantul telah diaktifkan atau dinonaktifkan +Comment[is]=Slökkt eða kveikt hefur verið á skoppandi lyklum +Comment[it]=I tasti ravvicinati sono stati abilitati o disattivati +Comment[ja]=バウンスキーが有効または無効になりました +Comment[kk]=Қалшылға қарсы пернелер рұқсат етілді/етілмеді +Comment[km]=គ្រាប់​ចុច​លោត​​ត្រូវបាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត +Comment[kn]=ಪುಟಿಯುವ (ಬೌನ್ಸ್) ಕೀಲಿಯನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Comment[ko]=튕김 키가 활성화되거나 비활성화됨 +Comment[ku]=Bişkojkên Zindî hatin çalakirin an jî neçalakirin +Comment[lt]=Tamprūs klavišai buvo įgalinti arba išjungti +Comment[lv]=Atlecošie taustiņi tika ieslēgti vai izslēgti +Comment[mk]=„Скокачки копчиња“ е овозможено или оневозможено +Comment[ml]=ബൌണ്‍സ് കീ പ്രവര്‍ത്തന സജ്ജം അല്ലെങ്കില്‍ പ്രവര്‍ത്തന രഹിതം ആക്കിയിരിക്കുന്നു +Comment[mr]=बाउन्स् कि कार्यान्वित किंवा अकार्यान्वित केली गेली आहे +Comment[nb]=Filtertaster er blitt slått på eller av +Comment[nds]="Jumpen Tasten" wöör an- oder utmaakt +Comment[ne]=बाउन्स कुञ्जीहरू सक्षम वा अक्षम बनाइएको छ +Comment[nl]=Stuiterende toetsen is geactiveerd of gedeactiveerd +Comment[nn]=Filtertastar er no slått på eller av +Comment[or]=Bounce କିଗୁଡ଼ିକୁ ସକ୍ରିୟ ଅଥବା ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Comment[pa]=ਬਾਊਂਸ ਸਵਿੱਚਾਂ ਯੋਗ ਜਾਂ ਆਯੋਗ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ +Comment[pl]=Powolne klawisze zostały włączone lub wyłączone +Comment[pt]=As teclas sonoras foram activadas ou desactivadas +Comment[pt_BR]=As teclas de repercussão foram ativadas ou desativadas +Comment[ro]=Taste săltărețe (Bounce keys) au fost activate sau dezactivate +Comment[ru]=Включены или отключены «прыгающие» клавиши +Comment[se]=Sillenboallu lea rievdadan stáhtusa +Comment[si]=පොළාපැනුම් යතුරු සක්‍රීය හෝ අක්‍රීය කර ඇත +Comment[sk]=Bounce klávesy zmenili svoj stav +Comment[sl]=Odbijajoče tipke so bile omogočene ali onemogočene +Comment[sr]=Одскачући тастери су укључени или искључени +Comment[sr@ijekavian]=Одскачући тастери су укључени или искључени +Comment[sr@ijekavianlatin]=Odskačući tasteri su uključeni ili isključeni +Comment[sr@latin]=Odskačući tasteri su uključeni ili isključeni +Comment[sv]=Studsande tangenter har aktiverats eller inaktiverats +Comment[ta]=Bounce keys has been enabled or disabled +Comment[te]=బౌన్‍స్ కీలు చేతనంకాబడినవి లేదా అచేతనంకాబడినవి +Comment[tg]=Тугмаҳои ҷаҳиш фаъол ё ғайрифаъол шудаанд +Comment[th]=การกดปุ่มพิมพ์รัวได้ถูกเปิดหรือปิดการทำงาน +Comment[tr]=Sıçrama tuşları etkinleştirildi ya da pasifleştirildi +Comment[ug]=سەكرىمە(Bounce) كۇنۇپكىلار ئىناۋەتلىك ياكى چەكلەنگەن +Comment[uk]=Було активовано або деактивовано пружні клавіші +Comment[vi]=Phím nảy đã được bật hoặc tắt +Comment[wa]=Des dimey-eclawåvès tapes ont stî metowes en alaejde oudonbén essoctêyes +Comment[x-test]=xxBounce keys has been enabled or disabledxx +Comment[zh_CN]=启用或禁用了撞击键 +Comment[zh_TW]=彈回鍵已啟動或關閉。 +Sound=KDE-Sys-Special.ogg +Action=PassivePopup +nopresentation=236 + +[Event/mousekeys] +Name=Mouse keys has been enabled or disabled +Name[af]=Muis sleutels was geaktiveer of gedeaktiveer +Name[ar]=تم تفعيل أو إلغاء تفعيل فأرة لوحة المفاتيح +Name[ast]=Tecles de mur activáronse o desactiváronse +Name[be@latin]=Klavišy kiravańnia kursoram źmianili svajo stanovišča +Name[bg]=Клавишите за управление на курсора са включени или изключени +Name[bs]=Miš‑tasteri su uključeni ili isključeni +Name[ca]=Les tecles del ratolí s'han activat o desactivat +Name[ca@valencia]=Les tecles del ratolí s'han activat o desactivat +Name[cs]=Klávesy myší byly povoleny nebo zakázány +Name[csb]=Knąpë mëszë òstałë aktiwòwòné abò deaktiwòwóné +Name[da]=Musetaster er aktiveret eller deaktiveret +Name[de]=Maustasten sind aktiviert oder deaktiviert worden +Name[el]=Τα πλήκτρα ποντικιού ενεργοποιήθηκαν ή απενεργοποιήθηκαν +Name[en_GB]=Mouse keys has been enabled or disabled +Name[eo]=Musklavoj validiĝis aŭ malvalidiĝis +Name[es]=Se han activado o desactivado los botones del ratón +Name[et]=Hiire klahvid on keelatud või lubatud +Name[eu]=Saguaren botoiak gaitu edo desgaitu dira +Name[fi]=Hiirinäppäimet on otettu käyttöön tai poistettu käytöstä +Name[fr]=Les touches gérant la souris ont été activées ou désactivées +Name[fy]=Mûstoetsen binne aktivearre of ûntaktivearre +Name[ga]=Cumasaíodh nó díchumasaíodh eochracha luiche +Name[gl]=O control do rato co teclado activouse ou desactivouse +Name[gu]=માઉસ કળો સક્રિય અથવા નિષ્ક્રિય કરવામાં આવી છે +Name[he]=חיקוי כפתורי העכבר הופעל או הופסק +Name[hi]=माउस कुंजियों को सक्षम या अक्षम किया गया है +Name[hne]=मुसुवा कुंजी सच्छम या अच्छम हो गिस +Name[hr]=Mišolike tipke su omogućene ili onemogućene +Name[hsb]=Myšace tasty zaswěćene abo hasnjene +Name[hu]=Az egérmozgató billentyűk átkapcsolva +Name[ia]=Le claves de mus ha essite activate o disactivate +Name[id]=Tombol tetikus telah diaktifkan atau dinonaktifkan +Name[is]=Slökkt eða kveikt hefur verið á músarlyklum +Name[it]=Il mouse da tastiera è stato attivato o disattivato +Name[ja]=マウスキーが有効または無効になりました +Name[kk]=Тышқан пернелер рұқсат етілді/етілмеді +Name[km]=គ្រាប់​ចុច​កណ្ដុរ​ត្រូវ​បាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត +Name[kn]=ಮೂಷಕ (ಮೌಸ್) ಕೀಲಿಯನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Name[ko]=마우스 키가 활성화되거나 비활성화됨 +Name[ku]=Bişkojkên Mişkî hatin çalakirin an jî neçalakirin +Name[lt]=Pelės klavišai buvo įgalinti arba išjungti +Name[lv]=Peles taustiņi tika ieslēgti vai izslēgti +Name[mk]=„Копчиња на глушецот“ е овозможено или оневозможено +Name[ml]=മൌസ് കീ പ്രവര്‍ത്തന സജ്ജം അല്ലെങ്കില്‍ പ്രവര്‍ത്തന രഹിതം ആക്കിയിരിക്കുന്നു +Name[mr]=माऊस कि कार्यान्वित किंवा अकार्यान्वित केली गेली आहे +Name[nb]=Musetaster er blitt slått på eller av +Name[nds]="Muustasten" wöör an- oder utmaakt +Name[ne]=माउस कुञ्जी सक्षम वा अक्षम बानइएको छ +Name[nl]=Muistoetsen is geactiveerd of gedeactiveerd +Name[nn]=Musetastar er no slått på eller av +Name[or]=ମାଉସ କିଗୁଡ଼ିକୁ ସକ୍ରିୟ ଅଥବା ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Name[pa]=ਮਾਊਸ ਸਵਿੱਚਾਂ ਯੋਗ ਜਾਂ ਆਯੋਗ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ +Name[pl]=Klawisze myszy zostały włączone lub wyłączone +Name[pt]=As teclas do rato foram activadas ou desactivadas +Name[pt_BR]=Teclas de mouse foram habilitadas ou desabilitadas +Name[ro]=Taste de maus au fost activate sau dezactivate +Name[ru]=Нажаты или отжаты клавиши мыши +Name[se]=Sáhppánboalut leat rievdadan stáhtusa +Name[si]=මවුස යතුරු සක්‍රීය හෝ අක්‍රීය කර ඇත +Name[sk]=Klávesy myši zmenili svoj stav +Name[sl]=Miškine tipke so bile omogočene ali onemogočene +Name[sr]=Миш‑тастери су укључени или искључени +Name[sr@ijekavian]=Миш‑тастери су укључени или искључени +Name[sr@ijekavianlatin]=Miš‑tasteri su uključeni ili isključeni +Name[sr@latin]=Miš‑tasteri su uključeni ili isključeni +Name[sv]=Mustangenter har aktiverats eller inaktiverats +Name[ta]=Mouse keys has been enabled or disabled +Name[te]=మౌస్ కీలు చేతనంకాబడినవి లేదా అచేతనంకాబడినవి +Name[tg]=Тугмаҳои муш фаъол ё ғайрифаъол шудаанд +Name[th]=การจำลองเมาส์ด้วยแป้นพิมพ์ได้ถูกเปิดหรือปิดการทำงาน +Name[tr]=Fare tuşları etkinleştirildi ya da pasifleştirildi +Name[ug]=چاشقىنەك كۇنۇپكىلىرى ئىناۋەتلىك ياكى چەكلەنگەن +Name[uk]=Було активовано або деактивовано клавіші мишки +Name[wa]=Des tapes di soris ont stî metowe en alaedje oudonbén essoctêyes +Name[x-test]=xxMouse keys has been enabled or disabledxx +Name[zh_CN]=启用或禁用了鼠标键 +Name[zh_TW]=滑鼠鍵已改變狀態 +Comment=Mouse keys has been enabled or disabled +Comment[af]=Muis sleutels was geaktiveer of gedeaktiveer +Comment[ar]=تم تفعيل أو إلغاء تفعيل فأرة لوحة المفاتيح +Comment[ast]=Tecles de mur activáronse o desactiváronse +Comment[be@latin]=Klavišy kiravańnia kursoram źmianili svajo stanovišča +Comment[bg]=Клавишите за управление на курсора са включени или изключени +Comment[bs]=Miš‑tasteri su uključeni ili isključeni +Comment[ca]=Les tecles del ratolí s'han activat o desactivat +Comment[ca@valencia]=Les tecles del ratolí s'han activat o desactivat +Comment[cs]=Klávesy myší byly povoleny nebo zakázány +Comment[csb]=Knąpë mëszë òstałë aktiwòwòné abò deaktiwòwóné +Comment[da]=Musetaster er aktiveret eller deaktiveret +Comment[de]=Die Funktion „Maustasten“ ist aktiviert oder deaktiviert worden +Comment[el]=Τα πλήκτρα ποντικιού ενεργοποιήθηκαν ή απενεργοποιήθηκαν +Comment[en_GB]=Mouse keys has been enabled or disabled +Comment[eo]=Musklavoj validiĝis aŭ malvalidiĝis +Comment[es]=Se han activado o desactivado los botones del ratón +Comment[et]=Hiire klahvid on keelatud või lubatud +Comment[eu]=Saguaren botoiak gaitu edo desgaitu dira +Comment[fi]=Hiirinäppäimet on otettu käyttöön tai poistettu käytöstä +Comment[fr]=Les touches gérant la souris ont été activées ou désactivées +Comment[fy]=Mûstoetsen binne aktivearre of ûntaktivearre +Comment[ga]=Cumasaíodh nó díchumasaíodh eochracha luiche +Comment[gl]=O control do rato co teclado foi ou activado ou desactivado +Comment[gu]=માઉસ કળો સક્રિય અથવા નિષ્ક્રિય કરવામાં આવી છે +Comment[he]=חיקוי כפתורי העכבר הופעל או הופסק +Comment[hi]=माउस कुंजियों को सक्षम या अक्षम किया गया है +Comment[hne]=मुसुवा कुंजी सच्छम या अच्छम हो गिस +Comment[hr]=Mišolike tipke su omogućene ili onemogućene +Comment[hsb]=Myšace tasty zaswěćene abo hasnjene +Comment[hu]=Az egérmozgató billentyűk használatát ki- vagy bekapcsolták +Comment[ia]=Le claves de mus ha essite activate o disactivate +Comment[id]=Tombol tetikus telah diaktifkan atau dinonaktifkan +Comment[is]=Slökkt eða kveikt hefur verið á músarlyklum +Comment[it]=Il mouse da tastiera è stato attivato o disattivato +Comment[ja]=マウスキーが有効または無効になりました +Comment[kk]=Тышқан пернелер рұқсат етілді/етілмеді +Comment[km]=គ្រាប់​ចុច​កណ្ដុរ​ត្រូវ​បាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត +Comment[kn]=ಮೂಷಕ (ಮೌಸ್) ಕೀಲಿಯನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ +Comment[ko]=마우스 키가 활성화되거나 비활성화됨 +Comment[ku]=Bişkojkên Mişkî hatin çalakirin an jî neçalakirin +Comment[lt]=Pelės mygtukai buvo įgalinti arba išjungti +Comment[lv]=Peles taustiņi tika ieslēgti vai izslēgti +Comment[mk]=„Копчиња на глушецот“ е овозможено или оневозможено +Comment[ml]=മൌസ് കീ പ്രവര്‍ത്തന സജ്ജം അല്ല്ലെങ്കില്‍ പ്രവര്‍ത്തനരഹിതം ആക്കിയിരിക്കുന്നു +Comment[mr]=माऊस कि कार्यान्वित किंवा अकार्यान्वित केली गेली आहे +Comment[nb]=Musetaster er blitt slått på eller av +Comment[nds]="Muustasten" wöör an- oder utmaakt +Comment[ne]=माउस कुञ्जी सक्षम वा अक्षम बनाइएको छ +Comment[nl]=Muistoetsen is geactiveerd of gedeactiveerd +Comment[nn]=Musetastar er no slått på eller av +Comment[or]=ମାଉସ କିଗୁଡ଼ିକୁ ସକ୍ରିୟ ଅଥବା ନିଷ୍କ୍ରିୟ କରାଯାଇଛି +Comment[pa]=ਮਾਊਸ ਸਵਿੱਚਾਂ ਯੋਗ ਜਾਂ ਆਯੋਗ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ +Comment[pl]=Klawisze myszy zostały włączone lub wyłączone +Comment[pt]=As teclas do rato foram activadas ou desactivadas +Comment[pt_BR]=Teclas de mouse foram habilitadas ou desabilitadas +Comment[ro]=Taste de maus au fost activate sau dezactivate +Comment[ru]=Нажаты или отжаты клавиши мыши +Comment[se]=Sáhppánboalut leat rievdadan stáhtusa +Comment[si]=මවුස යතුරු සක්‍රීය හෝ අක්‍රීය කර ඇත +Comment[sk]=Klávesy myši zmenili svoj stav +Comment[sl]=Miškine tipke so bile omogočene ali onemogočene +Comment[sr]=Миш‑тастери су укључени или искључени +Comment[sr@ijekavian]=Миш‑тастери су укључени или искључени +Comment[sr@ijekavianlatin]=Miš‑tasteri su uključeni ili isključeni +Comment[sr@latin]=Miš‑tasteri su uključeni ili isključeni +Comment[sv]=Mustangenter har aktiverats eller inaktiverats +Comment[ta]=Mouse keys has been enabled or disabled +Comment[te]=మౌస్ కీలు చేతనంకాబడినవి లేదా అచేతనంకాబడినవి +Comment[tg]=Тугмаҳои муш фаъол ё ғайрифаъол шудаанд +Comment[th]=การจำลองเมาส์ด้วยแป้นพิมพ์ได้ถูกเปิดหรือปิดการทำงาน +Comment[tr]=Fare tuşları etkinleştirildi ya da pasifleştirildi +Comment[ug]=چاشقىنەك كۇنۇپكىلىرى ئىناۋەتلىك ياكى چەكلەنگەن +Comment[uk]=Було активовано або деактивовано клавіші мишки +Comment[wa]=Des tapes di soris ont stî metowe en alaedje oudonbén essoctêyes +Comment[x-test]=xxMouse keys has been enabled or disabledxx +Comment[zh_CN]=启用或禁用了鼠标键 +Comment[zh_TW]=滑鼠鍵已啟動或關閉。 +Sound=KDE-Sys-Special.ogg +Action=PassivePopup +nopresentation=236 diff --git a/kcontrol/access/kcmaccess.cpp b/kcontrol/access/kcmaccess.cpp new file mode 100644 index 00000000..45e9d604 --- /dev/null +++ b/kcontrol/access/kcmaccess.cpp @@ -0,0 +1,783 @@ +/** + * kcmaccess.cpp + * + * Copyright (c) 2000 Matthias H�zer-Klpfel + * + */ + + +#include +#include + + +#include +#include +#include +#include +#include +#include +#include + +//Added by qt3to4: +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#define XK_MISCELLANY +#define XK_XKB_KEYS +#include +#include + +#include "kcmaccess.moc" + +K_PLUGIN_FACTORY(KAccessConfigFactory, registerPlugin();) +K_EXPORT_PLUGIN(KAccessConfigFactory("kcmaccess")) + +QString mouseKeysShortcut (Display *display) { + // Calculate the keycode + KeySym sym = XK_MouseKeys_Enable; + KeyCode code = XKeysymToKeycode(display, sym); + if (code == 0) { + sym = XK_Pointer_EnableKeys; + code = XKeysymToKeycode(display, sym); + if (code == 0) + return ""; // No shortcut available? + } + + // Calculate the modifiers by searching the keysym in the X keyboard mapping + XkbDescPtr xkbdesc = XkbGetMap(display, XkbKeyTypesMask | XkbKeySymsMask, XkbUseCoreKbd); + if (!xkbdesc) + return ""; // Failed to obtain the mapping from server + + bool found = false; + unsigned char modifiers = 0; + int groups = XkbKeyNumGroups(xkbdesc, code); + for (int grp = 0; grp < groups && !found; grp++) + { + int levels = XkbKeyGroupWidth(xkbdesc, code, grp); + for (int level = 0; level < levels && !found; level++) + { + if (sym == XkbKeySymEntry(xkbdesc, code, level, grp)) + { + // keysym found => determine modifiers + int typeIdx = xkbdesc->map->key_sym_map[code].kt_index[grp]; + XkbKeyTypePtr type = &(xkbdesc->map->types[typeIdx]); + for (int i = 0; i < type->map_count && !found; i++) + { + if (type->map[i].active && (type->map[i].level == level)) + { + modifiers = type->map[i].mods.mask; + found = true; + } + } + } + } + } + XkbFreeClientMap (xkbdesc, 0, true); + + if (!found) + return ""; // Somehow the keycode -> keysym mapping is flawed + + XEvent ev; + ev.type = KeyPress; + ev.xkey.display = display; + ev.xkey.keycode = code; + ev.xkey.state = 0; + int key; + KKeyServer::xEventToQt(&ev, &key); + QString keyname = QKeySequence(key).toString(); + + unsigned int AltMask = KKeyServer::modXAlt(); + unsigned int WinMask = KKeyServer::modXMeta(); + unsigned int NumMask = KKeyServer::modXNumLock(); + unsigned int ScrollMask= KKeyServer::modXScrollLock(); + + unsigned int MetaMask = XkbKeysymToModifiers (display, XK_Meta_L); + unsigned int SuperMask = XkbKeysymToModifiers (display, XK_Super_L); + unsigned int HyperMask = XkbKeysymToModifiers (display, XK_Hyper_L); + unsigned int AltGrMask = XkbKeysymToModifiers (display, XK_Mode_switch) + | XkbKeysymToModifiers (display, XK_ISO_Level3_Shift) + | XkbKeysymToModifiers (display, XK_ISO_Level3_Latch) + | XkbKeysymToModifiers (display, XK_ISO_Level3_Lock); + + unsigned int mods = ShiftMask | ControlMask | AltMask | WinMask + | LockMask | NumMask | ScrollMask; + + AltGrMask &= ~mods; + MetaMask &= ~(mods | AltGrMask); + SuperMask &= ~(mods | AltGrMask | MetaMask); + HyperMask &= ~(mods | AltGrMask | MetaMask | SuperMask); + + if ((modifiers & AltGrMask) != 0) + keyname = i18n("AltGraph") + '+' + keyname; + if ((modifiers & HyperMask) != 0) + keyname = i18n("Hyper") + '+' + keyname; + if ((modifiers & SuperMask) != 0) + keyname = i18n("Super") + '+' + keyname; + if ((modifiers & WinMask) != 0) + keyname = QKeySequence(Qt::META).toString() + '+' + keyname; + if ((modifiers & AltMask) != 0) + keyname = QKeySequence(Qt::ALT).toString() + '+' + keyname; + if ((modifiers & ControlMask) != 0) + keyname = QKeySequence(Qt::CTRL).toString() + '+' + keyname; + if ((modifiers & ShiftMask) != 0) + keyname = QKeySequence(Qt::SHIFT).toString() + '+' + keyname; + + QString result; + if ((modifiers & ScrollMask) != 0) + if ((modifiers & LockMask) != 0) + if ((modifiers & NumMask) != 0) + result = i18n("Press %1 while NumLock, CapsLock and ScrollLock are active", keyname); + else + result = i18n("Press %1 while CapsLock and ScrollLock are active", keyname); + else if ((modifiers & NumMask) != 0) + result = i18n("Press %1 while NumLock and ScrollLock are active", keyname); + else + result = i18n("Press %1 while ScrollLock is active", keyname); + else if ((modifiers & LockMask) != 0) + if ((modifiers & NumMask) != 0) + result = i18n("Press %1 while NumLock and CapsLock are active", keyname); + else + result = i18n("Press %1 while CapsLock is active", keyname); + else if ((modifiers & NumMask) != 0) + result = i18n("Press %1 while NumLock is active", keyname); + else + result = i18n("Press %1", keyname); + + return result; +} + +KAccessConfig::KAccessConfig(QWidget *parent, const QVariantList& args) + : KCModule(KAccessConfigFactory::componentData(), parent, args) +{ + + KAboutData *about = + new KAboutData(I18N_NOOP("kaccess"), 0, ki18n("KDE Accessibility Tool"), + 0, KLocalizedString(), KAboutData::License_GPL, + ki18n("(c) 2000, Matthias Hoelzer-Kluepfel")); + + about->addAuthor(ki18n("Matthias Hoelzer-Kluepfel"), ki18n("Author") , "hoelzer@kde.org"); + + setAboutData( about ); + + QVBoxLayout *main = new QVBoxLayout(this); + main->setMargin(0); + QTabWidget *tab = new QTabWidget(this); + main->addWidget(tab); + + // bell settings --------------------------------------- + QWidget *bell = new QWidget(this); + + QVBoxLayout *vbox = new QVBoxLayout(bell); + + QGroupBox *grp = new QGroupBox(i18n("Audible Bell"), bell); + QHBoxLayout *layout = new QHBoxLayout; + grp->setLayout(layout); + vbox->addWidget(grp); + + QVBoxLayout *vvbox = new QVBoxLayout(); + layout->addLayout( vvbox ); + + systemBell = new QCheckBox(i18n("Use &system bell"), grp); + vvbox->addWidget(systemBell); + customBell = new QCheckBox(i18n("Us&e customized bell"), grp); + vvbox->addWidget(customBell); + systemBell->setWhatsThis( i18n("If this option is checked, the default system bell will be used. See the" + " \"System Bell\" control module for how to customize the system bell." + " Normally, this is just a \"beep\".") ); + customBell->setWhatsThis( i18n("

Check this option if you want to use a customized bell, playing" + " a sound file. If you do this, you will probably want to turn off the system bell.

Please note" + " that on slow machines this may cause a \"lag\" between the event causing the bell and the sound being played.

") ); + + QHBoxLayout *hbox = new QHBoxLayout(); + vvbox->addLayout( hbox ); + hbox->addSpacing(24); + soundEdit = new QLineEdit(grp); + soundLabel = new QLabel(i18n("Sound &to play:"), grp); + soundLabel->setBuddy(soundEdit); + hbox->addWidget(soundLabel); + hbox->addWidget(soundEdit); + soundButton = new QPushButton(i18n("Browse..."), grp); + hbox->addWidget(soundButton); + QString wtstr = i18n("If the option \"Use customized bell\" is enabled, you can choose a sound file here." + " Click \"Browse...\" to choose a sound file using the file dialog."); + soundEdit->setWhatsThis( wtstr ); + soundLabel->setWhatsThis( wtstr ); + soundButton->setWhatsThis( wtstr ); + + connect(soundButton, SIGNAL(clicked()), this, SLOT(selectSound())); + + connect(customBell, SIGNAL(clicked()), this, SLOT(checkAccess())); + + connect(systemBell, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(customBell, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(soundEdit, SIGNAL(textChanged(QString)), this, SLOT(configChanged())); + + // ----------------------------------------------------- + + // visible bell ---------------------------------------- + grp = new QGroupBox(i18n("Visible Bell"), bell); + layout = new QHBoxLayout; + grp->setLayout(layout); + vbox->addWidget(grp); + + vvbox = new QVBoxLayout(); + layout->addLayout( vvbox ); + + visibleBell = new QCheckBox(i18n("&Use visible bell"), grp); + vvbox->addWidget(visibleBell); + visibleBell->setWhatsThis( i18n("This option will turn on the \"visible bell\", i.e. a visible" + " notification shown every time that normally just a bell would occur. This is especially useful" + " for deaf people.") ); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + invertScreen = new QRadioButton(i18n("I&nvert screen"), grp); + hbox->addWidget(invertScreen); + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + invertScreen->setWhatsThis( i18n("All screen colors will be inverted for the amount of time specified below.") ); + hbox->addSpacing(24); + flashScreen = new QRadioButton(i18n("F&lash screen"), grp); + hbox->addWidget(flashScreen); + flashScreen->setWhatsThis( i18n("The screen will turn to a custom color for the amount of time specified below.") ); + hbox->addSpacing(12); + colorButton = new KColorButton(grp); + colorButton->setFixedWidth(colorButton->sizeHint().height()*2); + hbox->addWidget(colorButton); + hbox->addStretch(); + colorButton->setWhatsThis( i18n("Click here to choose the color used for the \"flash screen\" visible bell.") ); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + + durationSlider = new KDoubleNumInput(grp); + durationSlider->setRange(100, 2000, 100); + durationSlider->setExponentRatio(2); + durationSlider->setDecimals(0); + durationSlider->setLabel(i18n("Duration:")); + durationSlider->setSuffix(i18n(" msec")); + hbox->addWidget(durationSlider); + durationSlider->setWhatsThis( i18n("Here you can customize the duration of the \"visible bell\" effect being shown.") ); + + connect(invertScreen, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(flashScreen, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(visibleBell, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(visibleBell, SIGNAL(clicked()), this, SLOT(checkAccess())); + connect(colorButton, SIGNAL(clicked()), this, SLOT(changeFlashScreenColor())); + + connect(invertScreen, SIGNAL(clicked()), this, SLOT(invertClicked())); + connect(flashScreen, SIGNAL(clicked()), this, SLOT(flashClicked())); + + connect(durationSlider, SIGNAL(valueChanged(double)), this, SLOT(configChanged())); + + vbox->addStretch(); + + // ----------------------------------------------------- + + tab->addTab(bell, i18n("&Bell")); + + + // modifier key settings ------------------------------- + QWidget *modifiers = new QWidget(this); + + vbox = new QVBoxLayout(modifiers); + + grp = new QGroupBox(i18n("S&ticky Keys"), modifiers); + layout = new QHBoxLayout; + grp->setLayout(layout); + vbox->addWidget(grp); + + vvbox = new QVBoxLayout(); + layout->addLayout(vvbox); + + stickyKeys = new QCheckBox(i18n("Use &sticky keys"), grp); + vvbox->addWidget(stickyKeys); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + stickyKeysLock = new QCheckBox(i18n("&Lock sticky keys"), grp); + hbox->addWidget(stickyKeysLock); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + stickyKeysAutoOff = new QCheckBox(i18n("Turn sticky keys off when two keys are pressed simultaneously"), grp); + hbox->addWidget(stickyKeysAutoOff); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + stickyKeysBeep = new QCheckBox(i18n("Use system bell whenever a modifier gets latched, locked or unlocked"), grp); + hbox->addWidget(stickyKeysBeep); + + grp = new QGroupBox(i18n("Locking Keys"), modifiers); + layout = new QHBoxLayout; + grp->setLayout(layout); + vbox->addWidget(grp); + + vvbox = new QVBoxLayout(); + layout->addLayout(vvbox); + + toggleKeysBeep = new QCheckBox(i18n("Use system bell whenever a locking key gets activated or deactivated"), grp); + vvbox->addWidget(toggleKeysBeep); + + kNotifyModifiers = new QCheckBox(i18n("Use KDE's system notification mechanism whenever a modifier or locking key changes its state"), grp); + vvbox->addWidget(kNotifyModifiers); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addStretch(1); + kNotifyModifiersButton = new QPushButton(i18n("Configure &Notifications..."), grp); + kNotifyModifiersButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + hbox->addWidget(kNotifyModifiersButton); + + connect(stickyKeys, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(stickyKeysLock, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(stickyKeysAutoOff, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(stickyKeys, SIGNAL(clicked()), this, SLOT(checkAccess())); + + connect(stickyKeysBeep, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(toggleKeysBeep, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(kNotifyModifiers, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(kNotifyModifiers, SIGNAL(clicked()), this, SLOT(checkAccess())); + connect(kNotifyModifiersButton, SIGNAL(clicked()), this, SLOT(configureKNotify())); + + vbox->addStretch(); + + tab->addTab(modifiers, i18n("&Modifier Keys")); + + // key filter settings --------------------------------- + QWidget *filters = new QWidget(this); + + vbox = new QVBoxLayout(filters); + grp = new QGroupBox(i18n("Slo&w Keys"), filters); + layout = new QHBoxLayout; + grp->setLayout(layout); + vbox->addWidget(grp); + + vvbox = new QVBoxLayout(); + layout->addLayout(vvbox); + + slowKeys = new QCheckBox(i18n("&Use slow keys"), grp); + vvbox->addWidget(slowKeys); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + slowKeysDelay = new KDoubleNumInput(grp); + slowKeysDelay->setRange(50, 10000, 100); + slowKeysDelay->setExponentRatio(2); + slowKeysDelay->setDecimals(0); + slowKeysDelay->setSuffix(i18n(" msec")); + slowKeysDelay->setLabel(i18n("Acceptance dela&y:"), Qt::AlignVCenter|Qt::AlignLeft); + hbox->addWidget(slowKeysDelay); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + slowKeysPressBeep = new QCheckBox(i18n("&Use system bell whenever a key is pressed"), grp); + hbox->addWidget(slowKeysPressBeep); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + slowKeysAcceptBeep = new QCheckBox(i18n("&Use system bell whenever a key is accepted"), grp); + hbox->addWidget(slowKeysAcceptBeep); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + slowKeysRejectBeep = new QCheckBox(i18n("&Use system bell whenever a key is rejected"), grp); + hbox->addWidget(slowKeysRejectBeep); + + grp = new QGroupBox(i18n("Bounce Keys"), filters); + layout= new QHBoxLayout; + grp->setLayout(layout); + vbox->addWidget(grp); + + vvbox = new QVBoxLayout(); + layout->addLayout( vvbox ); + + bounceKeys = new QCheckBox(i18n("Use bou&nce keys"), grp); + vvbox->addWidget(bounceKeys); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + bounceKeysDelay = new KDoubleNumInput(grp); + bounceKeysDelay->setRange(100, 5000, 100); + bounceKeysDelay->setExponentRatio(2); + bounceKeysDelay->setDecimals(0); + bounceKeysDelay->setSuffix(i18n(" msec")); + bounceKeysDelay->setLabel(i18n("D&ebounce time:"), Qt::AlignVCenter|Qt::AlignLeft);; + hbox->addWidget(bounceKeysDelay); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + bounceKeysRejectBeep = new QCheckBox(i18n("Use the system bell whenever a key is rejected"), grp); + hbox->addWidget(bounceKeysRejectBeep); + + connect(slowKeysDelay, SIGNAL(valueChanged(double)), this, SLOT(configChanged())); + connect(slowKeys, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(slowKeys, SIGNAL(clicked()), this, SLOT(checkAccess())); + + connect(slowKeysPressBeep, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(slowKeysAcceptBeep, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(slowKeysRejectBeep, SIGNAL(clicked()), this, SLOT(configChanged())); + + connect(bounceKeysDelay, SIGNAL(valueChanged(double)), this, SLOT(configChanged())); + connect(bounceKeys, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(bounceKeysRejectBeep, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(bounceKeys, SIGNAL(clicked()), this, SLOT(checkAccess())); + + vbox->addStretch(); + + tab->addTab(filters, i18n("&Keyboard Filters")); + + // gestures -------------------------------------------- + QWidget *features = new QWidget(this); + + vbox = new QVBoxLayout(features); + + grp = new QGroupBox(i18n("Activation Gestures"), features); + layout = new QHBoxLayout; + grp->setLayout(layout); + vbox->addWidget(grp); + + vvbox = new QVBoxLayout(); + layout->addLayout( vvbox ); + + gestures = new QCheckBox(i18n("Use gestures for activating sticky keys and slow keys"), grp); + vvbox->addWidget(gestures); + QString shortcut = mouseKeysShortcut(x11Info().display()); + if (shortcut.isEmpty()) + gestures->setWhatsThis( i18n("Here you can activate keyboard gestures that turn on the following features: \n" + "Sticky keys: Press Shift key 5 consecutive times\n" + "Slow keys: Hold down Shift for 8 seconds")); + else + gestures->setWhatsThis( i18n("Here you can activate keyboard gestures that turn on the following features: \n" + "Mouse Keys: %1\n" + "Sticky keys: Press Shift key 5 consecutive times\n" + "Slow keys: Hold down Shift for 8 seconds", shortcut)); + + timeout = new QCheckBox(i18n("Turn sticky keys and slow keys off after a certain period of inactivity."), grp); + vvbox->addWidget(timeout); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addSpacing(24); + timeoutDelay = new KIntNumInput(grp); + timeoutDelay->setSuffix(i18n(" min")); + timeoutDelay->setRange(1, 30, 4); + timeoutDelay->setLabel(i18n("Timeout:"), Qt::AlignVCenter|Qt::AlignLeft);; + hbox->addWidget(timeoutDelay); + + grp = new QGroupBox(i18n("Notification"), features); + layout = new QHBoxLayout; + grp->setLayout(layout); + vbox->addWidget(grp); + + vvbox = new QVBoxLayout(); + layout->addLayout(vvbox); + + accessxBeep = new QCheckBox(i18n("Use the system bell whenever a gesture is used to turn an accessibility feature on or off"), grp); + vvbox->addWidget(accessxBeep); + + gestureConfirmation = new QCheckBox(i18n("Show a confirmation dialog whenever a keyboard accessibility feature is turned on or off"), grp); + vvbox->addWidget(gestureConfirmation); + gestureConfirmation->setWhatsThis( i18n("If this option is checked, KDE will show a confirmation dialog whenever a keyboard accessibility feature is turned on or off.\nEnsure you know what you are doing if you uncheck it, as the keyboard accessibility settings will then always be applied without confirmation.") ); + + kNotifyAccessX = new QCheckBox(i18n("Use KDE's system notification mechanism whenever a keyboard accessibility feature is turned on or off"), grp); + vvbox->addWidget(kNotifyAccessX); + + hbox = new QHBoxLayout(); + vvbox->addLayout(hbox); + hbox->addStretch(1); + kNotifyAccessXButton = new QPushButton(i18n("Configure &Notifications..."), grp); + kNotifyAccessXButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + hbox->addWidget(kNotifyAccessXButton); + + connect(gestures, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(timeout, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(timeout, SIGNAL(clicked()), this, SLOT(checkAccess())); + connect(timeoutDelay, SIGNAL(valueChanged(int)), this, SLOT(configChanged())); + connect(accessxBeep, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(gestureConfirmation, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(kNotifyAccessX, SIGNAL(clicked()), this, SLOT(configChanged())); + connect(kNotifyAccessX, SIGNAL(clicked()), this, SLOT(checkAccess())); + connect(kNotifyAccessXButton, SIGNAL(clicked()), this, SLOT(configureKNotify())); + + vbox->addStretch(); + + tab->addTab(features, i18n("Activation Gestures")); +} + + +KAccessConfig::~KAccessConfig() +{ +} + +void KAccessConfig::configureKNotify() +{ + KNotifyConfigWidget::configure (this, "kaccess"); +} + +void KAccessConfig::changeFlashScreenColor() +{ + invertScreen->setChecked(false); + flashScreen->setChecked(true); + configChanged(); +} + +void KAccessConfig::selectSound() +{ + QStringList list = KGlobal::dirs()->findDirs("sound", ""); + QString start; + if (list.count()>0) + start = list[0]; + // TODO: Why only wav's? How can I find out what artsd supports? + QString fname = KFileDialog::getOpenFileName(start, i18n("*.wav|WAV Files")); + if (!fname.isEmpty()) + soundEdit->setText(fname); +} + + +void KAccessConfig::configChanged() +{ + emit changed(true); +} + + +void KAccessConfig::load() +{ + KConfigGroup cg(KSharedConfig::openConfig("kaccessrc"), "Bell"); + + systemBell->setChecked(cg.readEntry("SystemBell", true)); + customBell->setChecked(cg.readEntry("ArtsBell", false)); + soundEdit->setText(cg.readPathEntry("ArtsBellFile", QString())); + + visibleBell->setChecked(cg.readEntry("VisibleBell", false)); + invertScreen->setChecked(cg.readEntry("VisibleBellInvert", true)); + flashScreen->setChecked(!invertScreen->isChecked()); + colorButton->setColor(cg.readEntry("VisibleBellColor", QColor(Qt::red))); + + durationSlider->setValue(cg.readEntry("VisibleBellPause", 500)); + + KConfigGroup keyboardGroup(KSharedConfig::openConfig("kaccessrc"),"Keyboard"); + + stickyKeys->setChecked(keyboardGroup.readEntry("StickyKeys", false)); + stickyKeysLock->setChecked(keyboardGroup.readEntry("StickyKeysLatch", true)); + stickyKeysAutoOff->setChecked(keyboardGroup.readEntry("StickyKeysAutoOff", false)); + stickyKeysBeep->setChecked(keyboardGroup.readEntry("StickyKeysBeep", true)); + toggleKeysBeep->setChecked(keyboardGroup.readEntry("ToggleKeysBeep", false)); + kNotifyModifiers->setChecked(keyboardGroup.readEntry("kNotifyModifiers", false)); + + slowKeys->setChecked(keyboardGroup.readEntry("SlowKeys", false)); + slowKeysDelay->setValue(keyboardGroup.readEntry("SlowKeysDelay", 500)); + slowKeysPressBeep->setChecked(keyboardGroup.readEntry("SlowKeysPressBeep", true)); + slowKeysAcceptBeep->setChecked(keyboardGroup.readEntry("SlowKeysAcceptBeep", true)); + slowKeysRejectBeep->setChecked(keyboardGroup.readEntry("SlowKeysRejectBeep", true)); + + bounceKeys->setChecked(keyboardGroup.readEntry("BounceKeys", false)); + bounceKeysDelay->setValue(keyboardGroup.readEntry("BounceKeysDelay", 500)); + bounceKeysRejectBeep->setChecked(keyboardGroup.readEntry("BounceKeysRejectBeep", true)); + + gestures->setChecked(keyboardGroup.readEntry("Gestures", false)); + timeout->setChecked(keyboardGroup.readEntry("AccessXTimeout", false)); + timeoutDelay->setValue(keyboardGroup.readEntry("AccessXTimeoutDelay", 30)); + + accessxBeep->setChecked(keyboardGroup.readEntry("AccessXBeep", true)); + gestureConfirmation->setChecked(keyboardGroup.readEntry("GestureConfirmation", false)); + kNotifyAccessX->setChecked(keyboardGroup.readEntry("kNotifyAccessX", false)); + + checkAccess(); + + emit changed(false); +} + + +void KAccessConfig::save() +{ + KConfigGroup cg(KSharedConfig::openConfig("kaccessrc"), "Bell"); + + cg.writeEntry("SystemBell", systemBell->isChecked()); + cg.writeEntry("ArtsBell", customBell->isChecked()); + cg.writePathEntry("ArtsBellFile", soundEdit->text()); + + cg.writeEntry("VisibleBell", visibleBell->isChecked()); + cg.writeEntry("VisibleBellInvert", invertScreen->isChecked()); + cg.writeEntry("VisibleBellColor", colorButton->color()); + + cg.writeEntry("VisibleBellPause", durationSlider->value()); + + KConfigGroup keyboardGroup(KSharedConfig::openConfig("kaccessrc"),"Keyboard"); + + keyboardGroup.writeEntry("StickyKeys", stickyKeys->isChecked()); + keyboardGroup.writeEntry("StickyKeysLatch", stickyKeysLock->isChecked()); + keyboardGroup.writeEntry("StickyKeysAutoOff", stickyKeysAutoOff->isChecked()); + keyboardGroup.writeEntry("StickyKeysBeep", stickyKeysBeep->isChecked()); + keyboardGroup.writeEntry("ToggleKeysBeep", toggleKeysBeep->isChecked()); + keyboardGroup.writeEntry("kNotifyModifiers", kNotifyModifiers->isChecked()); + + keyboardGroup.writeEntry("SlowKeys", slowKeys->isChecked()); + keyboardGroup.writeEntry("SlowKeysDelay", slowKeysDelay->value()); + keyboardGroup.writeEntry("SlowKeysPressBeep", slowKeysPressBeep->isChecked()); + keyboardGroup.writeEntry("SlowKeysAcceptBeep", slowKeysAcceptBeep->isChecked()); + keyboardGroup.writeEntry("SlowKeysRejectBeep", slowKeysRejectBeep->isChecked()); + + + keyboardGroup.writeEntry("BounceKeys", bounceKeys->isChecked()); + keyboardGroup.writeEntry("BounceKeysDelay", bounceKeysDelay->value()); + keyboardGroup.writeEntry("BounceKeysRejectBeep", bounceKeysRejectBeep->isChecked()); + + keyboardGroup.writeEntry("Gestures", gestures->isChecked()); + keyboardGroup.writeEntry("AccessXTimeout", timeout->isChecked()); + keyboardGroup.writeEntry("AccessXTimeoutDelay", timeoutDelay->value()); + + keyboardGroup.writeEntry("AccessXBeep", accessxBeep->isChecked()); + keyboardGroup.writeEntry("GestureConfirmation", gestureConfirmation->isChecked()); + keyboardGroup.writeEntry("kNotifyAccessX", kNotifyAccessX->isChecked()); + + + cg.sync(); + keyboardGroup.sync(); + + if (systemBell->isChecked() || + customBell->isChecked() || + visibleBell->isChecked()) + { + KConfig _cfg("kdeglobals", KConfig::NoGlobals); + KConfigGroup cfg(&_cfg, "General"); + cfg.writeEntry("UseSystemBell", true); + cfg.sync(); + } + + // make kaccess reread the configuration + // turning a11y features off needs to be done by kaccess + // so run it to clear any enabled features and it will exit if it should + KToolInvocation::startServiceByDesktopName("kaccess"); + + emit changed(false); +} + + +void KAccessConfig::defaults() +{ + systemBell->setChecked(true); + customBell->setChecked(false); + soundEdit->setText(""); + + visibleBell->setChecked(false); + invertScreen->setChecked(true); + flashScreen->setChecked(false); + colorButton->setColor(QColor(Qt::red)); + + durationSlider->setValue(500); + + slowKeys->setChecked(false); + slowKeysDelay->setValue(500); + slowKeysPressBeep->setChecked(true); + slowKeysAcceptBeep->setChecked(true); + slowKeysRejectBeep->setChecked(true); + + bounceKeys->setChecked(false); + bounceKeysDelay->setValue(500); + bounceKeysRejectBeep->setChecked(true); + + stickyKeys->setChecked(false); + stickyKeysLock->setChecked(true); + stickyKeysAutoOff->setChecked(false); + stickyKeysBeep->setChecked(true); + toggleKeysBeep->setChecked(false); + kNotifyModifiers->setChecked(false); + + gestures->setChecked(false); + timeout->setChecked(false); + timeoutDelay->setValue(30); + + accessxBeep->setChecked(true); + gestureConfirmation->setChecked(true); + kNotifyAccessX->setChecked(false); + + checkAccess(); + + emit changed(true); +} + + +void KAccessConfig::invertClicked() +{ + flashScreen->setChecked(false); +} + + +void KAccessConfig::flashClicked() +{ + invertScreen->setChecked(false); +} + + +void KAccessConfig::checkAccess() +{ + bool custom = customBell->isChecked(); + soundEdit->setEnabled(custom); + soundButton->setEnabled(custom); + soundLabel->setEnabled(custom); + + bool visible = visibleBell->isChecked(); + invertScreen->setEnabled(visible); + flashScreen->setEnabled(visible); + colorButton->setEnabled(visible); + durationSlider->setEnabled(visible); + + bool sticky = stickyKeys->isChecked(); + stickyKeysLock->setEnabled(sticky); + stickyKeysAutoOff->setEnabled(sticky); + stickyKeysBeep->setEnabled(sticky); + + bool slow = slowKeys->isChecked(); + slowKeysDelay->setEnabled(slow); + slowKeysPressBeep->setEnabled(slow); + slowKeysAcceptBeep->setEnabled(slow); + slowKeysRejectBeep->setEnabled(slow); + + bool bounce = bounceKeys->isChecked(); + bounceKeysDelay->setEnabled(bounce); + bounceKeysRejectBeep->setEnabled(bounce); + + bool useTimeout = timeout->isChecked(); + timeoutDelay->setEnabled(useTimeout); +} + +extern "C" +{ + /* This one gets called by kcminit + + */ + KDE_EXPORT void kcminit_access() + { + KConfig config("kaccessrc", KConfig::NoGlobals); + KToolInvocation::startServiceByDesktopName("kaccess"); + } +} + + diff --git a/kcontrol/access/kcmaccess.desktop b/kcontrol/access/kcmaccess.desktop new file mode 100644 index 00000000..936d3e2a --- /dev/null +++ b/kcontrol/access/kcmaccess.desktop @@ -0,0 +1,237 @@ +[Desktop Entry] +Exec=kcmshell4 kcmaccess +Icon=preferences-desktop-accessibility +Type=Service +X-KDE-ServiceTypes=KCModule,KCModuleInit +X-DocPath=kcontrol/kcmaccess/index.html + +X-KDE-Library=kcm_access +X-KDE-Init-Symbol=kcminit_access +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=accessibility + +Name=Accessibility +Name[af]=Toeganklikheid +Name[ar]=الإتاحة +Name[as]=অভিগম্যতা +Name[ast]=Accesibilidá +Name[be]=Даступнасць +Name[be@latin]=Dastupnaść +Name[bg]=Равностоен достъп +Name[bn]=সহায়ক প্রযুক্তি +Name[bn_IN]=বিশেষ ব্যবহারের সহায়তা +Name[br]=Haezadusted +Name[bs]=Pristupačnost +Name[ca]=Accessibilitat +Name[ca@valencia]=Accessibilitat +Name[cs]=Zpřístupnění +Name[csb]=Pòmòce przëstãpù +Name[cy]=Hygyrchedd +Name[da]=Tilgængelighed +Name[de]=Zugangshilfen +Name[el]=Προσιτότητα +Name[en_GB]=Accessibility +Name[eo]=Alirebleco +Name[es]=Accesibilidad +Name[et]=Hõlbustus +Name[eu]=Erabilerraztasuna +Name[fa]=دستیابی‌پذیری +Name[fi]=Esteettömyys +Name[fr]=Accessibilité +Name[fy]=Tagonklikens +Name[ga]=Inrochtaineacht +Name[gl]=Accesibilidade +Name[gu]=ઉપયોગિતા +Name[he]=נגישות +Name[hi]=पहुँच +Name[hne]=पहुंच +Name[hr]=Pristupačnost +Name[hsb]=Přistupnosć +Name[hu]=Kezelési segítség +Name[ia]=Accessibilitate +Name[id]=Aksesibilitas +Name[is]=Aðgengi +Name[it]=Accessibilità +Name[ja]=アクセシビリティ +Name[ka]=სპეციალური შესაძლბლობები +Name[kk]=Арнайы мүмкіндіктер +Name[km]=មធ្យោបាយ​ងាយស្រួល +Name[kn]=ನಿಲುಕಣೆ (ಆಕ್ಸೆಸಿಬಿಲಿಟಿ) +Name[ko]=내게 필요한 설정 +Name[ku]=Gihîştin +Name[lt]=Pritaikymas neįgaliesiems +Name[lv]=Pieejamība +Name[mai]=अभिगम्यता +Name[mk]=Пристапливост +Name[ml]=സാമീപ്യത +Name[mr]=सुलभता +Name[ms]=Kebolehcapaian +Name[nb]=Tilgjengelighet +Name[nds]=Toganghülp +Name[ne]=पहुँचता +Name[nl]=Toegankelijkheid +Name[nn]=Tilgjenge +Name[oc]=Accessibilitat +Name[or]=ଅଭିଗମ୍ୟତା +Name[pa]=ਸਹੂਲਤਾਂ +Name[pl]=Ułatwienia dostępu +Name[pt]=Acessibilidade +Name[pt_BR]=Acessibilidade +Name[ro]=Accesibilitate +Name[ru]=Специальные возможности +Name[se]=Álkkibut geavaheapmi +Name[si]=ප්‍රවේශණය +Name[sk]=Prístupnosť +Name[sl]=Dostopnost +Name[sr]=Приступачност +Name[sr@ijekavian]=Приступачност +Name[sr@ijekavianlatin]=Pristupačnost +Name[sr@latin]=Pristupačnost +Name[sv]=Handikappstöd +Name[ta]=அணுகல் +Name[te]=అందుబాటు +Name[tg]=Имкониятҳо +Name[th]=ช่วยการใช้งาน +Name[tr]=Erişilebilirlik +Name[ug]=قوشۇمچە ئىقتىدار +Name[uk]=Доступність +Name[uz]=Qulayliklar +Name[uz@cyrillic]=Қулайликлар +Name[vi]=Hỗ trợ truy cập +Name[wa]=Accessibilité +Name[xh]=Unikezelo +Name[x-test]=xxAccessibilityxx +Name[zh_CN]=辅助 +Name[zh_TW]=無障礙輔助 + +Comment=Improve accessibility for disabled persons +Comment[af]=Verbeter toeganklikheid vir gestremde persone +Comment[ar]=تحسين إمكانية الوصول للمعوقين +Comment[ast]=Ameyorar accesibilidá pa discapacitaos +Comment[be]=Павялічвае даступнасць для людзей з фізічнымі адхіленнямі +Comment[be@latin]=Palapšeńnie dastupnaści prahramaŭ dla invalidaŭ +Comment[bg]=Настройки на достъпа за хора с увреждания +Comment[bn]=অসমর্থ ব্যবহারকারীদের সহায়তা করার প্রযুক্তি +Comment[bs]=Poboljšava pristupačnost hendikepiranim osobama +Comment[ca]=Accessibilitat millorada per a persones discapacitades +Comment[ca@valencia]=Accessibilitat millorada per a persones discapacitades +Comment[cs]=Zlepšení přístupnosti pro osoby s postižením +Comment[csb]=Pòprôwionô przëstãpnosc dlô niefùlsprôwnëch lëdzi +Comment[cy]=Gwella hygyrchedd i bobl anabl +Comment[da]=Forbedr tilgængelighed for handicappede personer +Comment[de]=Verbesserte Benutzbarkeit für Menschen mit Behinderung +Comment[el]=Βελτίωση της προσιτότητας για άτομα με ειδικές ανάγκες +Comment[en_GB]=Improve accessibility for disabled persons +Comment[eo]=Plibonigita alirebleco por handikapitoj +Comment[es]=Mejorar accesibilidad para discapacitados +Comment[et]=Puuetega inimestele mõeldud seaded +Comment[eu]=Ezinduentzako erabilerraztasuna handitzen du +Comment[fa]=بهبود دستیابی‌پذیری برای اشخاص ناتوان +Comment[fi]=Esteettömyysasetukset +Comment[fy]=Ferbeterde tagonklikens foar brûkers mei in handikap +Comment[ga]=Feabhsaigh an inrochtaineacht do dhaoine míchumasaithe +Comment[gl]=Accesibilidade mellorada para persoas con discapacidades +Comment[gu]=અસક્ષમ વ્યક્તિઓ માટે ઉપયોગિતામાં સુધારો કરો +Comment[he]=שיפור הנגישות עבור אנשים עם מוגבלויות +Comment[hi]=विकलांग व्यक्तियों के लिए पहुँच बेहतर बनाए +Comment[hne]=विकलांग मनखे बर पहुंच बेहतर बनाए +Comment[hr]=Unaprijedite pristupačnost osobama s invaliditetom +Comment[hsb]=Přistupnosć za zbrašenych zlěpšić +Comment[hu]=A számítógép kezelését segítő eszközök fogyatékosoknak +Comment[ia]=Il meliora le accessibilitate pro personas invalide +Comment[id]=Tingkatkan aksesibilitas bagi orang cacat +Comment[is]=Endurbætt aðgengi fyrir þá sem þurfa +Comment[ka]=ფიზიკური ნაკლოვანებბის მქონი ხალხისთვის სპეციალური შესაძლბლობები +Comment[kk]=Мүмкіншіліктері шектеулі адамдарға көмек +Comment[km]=បង្កើន​មធ្យោបាយ​ងាយស្រួល​សម្រាប់​មនុស្ស​ពិការ +Comment[kn]=ದುರ್ಬಲೀನರಾದ ವ್ಯಕ್ತಿಗಳಿಗೆ ನಿಲುಕಣೆಯನ್ನು (ಅಕ್ಸೆಸಿಬಲಿಟಿ) ಸುಧಾರಿಸಿ +Comment[ko]=장애인들을 위하여 접근성을 향상시킵니다 +Comment[ku]=Ji bo kesên neçalak gihîştinê biguherîne +Comment[lt]=Pagerintas prieinamumas neįgaliems asmenims +Comment[lv]=Uzlabo pieejamību cilvēkiem ar īpašām vajadzībām +Comment[mai]=विकलांग लोकनिसभक लेल पहुँच बेहतर बनाएल जाए +Comment[mk]=Ја подобрува пристапливоста за хендикепирани лица +Comment[ml]=അംഗവൈകല്യമുള്ളവര്‍ക്കുള്ള സാമീപ്യത നന്നാക്കുക +Comment[mr]=विकलांग व्यक्तिं करिता सुधारित सुलभता +Comment[ms]=Tingkatkan keaksesan bagi orang kurang upaya +Comment[nb]=Forbedre tilgjengelighet for funksjonshemmede +Comment[nds]=Verbetert den Togang för behinnert Lüüd +Comment[ne]=अक्षम व्यक्तिका लागि पहुँच क्षमता सुधार गर्नुहोस् +Comment[nl]=Verbeterde toegankelijkheid voor gebruikers met een handicap +Comment[nn]=Forbetra tilgjenge for funksjonshemma personar +Comment[or]=ନିଷ୍କ୍ରିୟ ବ୍ୟକ୍ତିମାନଙ୍କ ପାଇଁ ଅଭିଗମ୍ୟତା ଉନ୍ନତ କରନ୍ତୁ +Comment[pa]=ਅਪੰਗ ਵਿਅਕਤੀ ਲਈ ਸੁਧਾਰੀਆਂ ਸਹੂਲਤਾਂ +Comment[pl]=Poprawiona dostępność dla osób niepełnosprawnych +Comment[pt]=Acessibilidade melhorada para pessoas com necessidades especiais +Comment[pt_BR]=Melhora a acessibilidade para pessoas com deficiência +Comment[ro]=Îmbunătățește accesibilitate KDE pentru persoanele cu handicap +Comment[ru]=Специальные возможности для людей с физическими ограничениями +Comment[se]=Álkkibut geavaheapmi doaimmahehttejuvvon olbmuide +Comment[si]=අබාධිත අයෙකුට පහසුවෙන් පිවිසීමට ඉඩදෙයි +Comment[sk]=Zlepšenie prístupnosti pre postihnutých užívateľov +Comment[sl]=Izboljšana dostopnost za prizadete osebe +Comment[sr]=Побољшава приступачност хендикепираним особама +Comment[sr@ijekavian]=Побољшава приступачност хендикепираним особама +Comment[sr@ijekavianlatin]=Poboljšava pristupačnost hendikepiranim osobama +Comment[sr@latin]=Poboljšava pristupačnost hendikepiranim osobama +Comment[sv]=Förbättrad tillgänglighet för handikappade personer +Comment[ta]=பார்க்க முடியாதவர்களுக்கு அணுகலை அதிகப்படுத்தவும் +Comment[te]=వికలాంగులైన వ్యక్తులకు అందుబాటును మెరుగుపరుచుము +Comment[tg]=Специальные возможности для людей с физическими недостатками +Comment[th]=ช่วยให้ผู้พิการหรือผู้บกพร่องทางร่างกายด้านอื่นๆ สามารถใช้งานได้สะดวกสบายมากขึ้น +Comment[tr]=Görme sorunu olanlar için erişilebilirlik seçenekleri +Comment[ug]=مېيىپلەر ئۈچۈن ئىشلىتىلىدىغان ياردەمچى ئىقتىدارلار +Comment[uk]=Підвищення зручності для інвалідів +Comment[uz]=Nogiron kishilar uchun qulayliklar +Comment[uz@cyrillic]=Ногирон кишилар учун қулайликлар +Comment[vi]=Cải thiện khả năng truy cập cho người khuyết tật +Comment[wa]=Rind pus åjhey l' accessibilité po les sakîs k' ont des andicapes +Comment[xh]=Phucula unikekezeleko lwabantu abakhubazekileyo +Comment[x-test]=xxImprove accessibility for disabled personsxx +Comment[zh_CN]=方便残疾人使用的辅助功能 +Comment[zh_TW]=方便傷殘人士使用 + +X-KDE-Keywords=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys +X-KDE-Keywords[bs]=pristup,pristupačnost,gluh,oštećen,sluh,gubitak sluha,zvono,zvučno zvono,vidljivo zvono,tastatura,tipke,ljepljive tipke,odskočne tipke,usporene tipke,navigacija uz pomoć miša,numerički dio, +X-KDE-Keywords[ca]=accés,accessibilitat,sord,discapacitat,oïda,pèrdua d'oïda,campana,campana audible,campana visible,Teclat,tecles apegaloses,repetició de tecles,tecles lentes,navegació de ratolí,teclat numèric,activació de gestos,gestors,apegalós,tecles modificadores,modificador,tecles bloquejadores +X-KDE-Keywords[ca@valencia]=accés,accessibilitat,sord,discapacitat,oïda,pèrdua d'oïda,campana,campana audible,campana visible,Teclat,tecles apegaloses,repetició de tecles,tecles lentes,navegació de ratolí,teclat numèric,activació de gestos,gestors,apegalós,tecles modificadores,modificador,tecles bloquejadores +X-KDE-Keywords[da]=tilgang,tilgængelighed,døv,hæmmet,handicappet,hørelse,hørehæmmet,klokke,hørbar klokke,synlig klokke,tastatur,taster,sticky keys,elastiske taster,bounce,langsomme taster,musenavigation,numerisk tastatur,aktiveringsgestusser,gestusser,klæbende,ændringstaster,låsetaster +X-KDE-Keywords[de]=Behinderung,Maussteuerung,Signale,Tastatur,Tasten,Klebende Tasten,Taubheit,Verlangsamte Tasten,Zahlenblock,Zugang,Zugangshilfen,Zahlentasten,Gesten aktivieren,Sondertasten,Sperrtasten +X-KDE-Keywords[el]=πρόσβαση,προσβασιμότητα,βαρήκοος,πρόβλημα,ακοής,απώλεια ακοής,κουδούνι,ηχητικό κουδούνι,οπτικό κουδούνι,πληκτρολόγιο,πλήκτρα,κολλημένα πλήκτρα,πλήκτρα αναπήδησης,αργά πλήκτρα,πλοήγηση με ποντίκι,αριθμητικό πληκτρολόγιο,numpad,νεύματα ενεργοποίησης,νεύματα,κολλημένο,πλήκτρα τροποποιητή,τροποποιητής,πλήκτρα κλειδώματος +X-KDE-Keywords[en_GB]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys +X-KDE-Keywords[es]=acceso,accesibilidad,sordera,descapacitado,oído,pérdida de oído,campana,campana audible,campana visible,teclado,teclas,teclas pegajosas,repetición de teclas,teclas lentas,navegación con ratón,teclado numérico,gestos de activación,gestos,pegajoso,teclas modificadoras,modificador,teclas de bloqueo +X-KDE-Keywords[et]=hõlbustus,kasutusmugavus,kurdid,tummad,kuulmine,kuulmiskaotus,puuetega,kell,kuuldav kell,nähtav kell,klaviatuur,klahvid,kleepuvad klahvid,põrkuvad klahvid,aeglased klahvid,hiirega liikumine,numbriklahvistik,aktiveerimisžestid,žestid,muuteklahvid,lukustusklahvid +X-KDE-Keywords[eu]=sarbide,erabilerraztasun,gor,baliaezintasun,entzumen,entzumena galdu,kanpai,kanpai entzungarri,kanpai ikusgarri,teklatu,tekla,tekla itsaskor,errebote-teklak,tekla motel,sagu bidezko nabigazio,zenbakizko teklatu,zk teklatu,aktibazio-keinu,keinu,itsaskor,tekla aldatzaile,aldatzaile,blokeo-tekla +X-KDE-Keywords[fi]=esteettömyys,kuuro,heikentynyt,heikko,kuulo,varoitus,äänimerkki,visuaalinen äänimerkki,näppäimistö,näppäimet,alas jäävät näppäimet,tahmeat näppäimet,ponnahdusnäppäimet,hitaat näppäimet,hiirinäppäimet,numeronäppäimistö +X-KDE-Keywords[fr]=accès, accessibilité, sourd, affaiblis, audition, perte d'audition, cloche, cloche audible, cloche visuelle, clavier, touches, touches collantes, touche rebondissante, touches lentes, navigation de la souris, pavé numérique, gestes d'activation, gestes, collant, touches modifiantes, modificateur, touche de verrouillage +X-KDE-Keywords[ga]=rochtain,inrochtaineacht,bodhar,lagaithe,cloigín,cloigín inchloiste,clog infheicthe,Méarchlár,eochracha,eochracha greamaitheacha,eochracha preabtha,eochracha go mall,nascleanúint luiche,eochaircheap uimhriúil,gothaí,greamaitheach,mionthraitheoir,eochracha glasála +X-KDE-Keywords[gl]=acceso, accesibilidade, xordo, discapacitado, minusválido, audición, auditiva, campá audíbel, campá visíbel, teclado, tecla pegañentas, teclas lentas, navegación co rato, teclado numérico, acenos, teclas modificadoras +X-KDE-Keywords[hu]=kezelés,akadálymentesítés,süket,károsodott,hallás,halláskárosodás,csengő,hallható csengő,látható csengő,Billentyűzet,billentyűk,ragadós billentyűk,pattogó billentyűk,lassú billentyűk,egérnavigáció,numerikus billentyűzet +X-KDE-Keywords[ia]=accesso,accessibilitate,surde,debilitate,audito, perdita de audito,campana,campana audibile,campana visibile,Claviero,claves,claves collose,claves saltante,claves lente,navigation de mus,pad numeric, gestos de activation,gestos,collose, claves modificator, modificator, claves blocante +X-KDE-Keywords[it]=accesso,accessibilità,sordo,handicap,udito,sordità,campanella,campanella udibile,campanella visiva,tastiera,tasti,permanenza dei tasti,pressione ravvicinata dei tasti,rallentamento dei tasti,navigazione col mouse,tastierino numerico,attivazione gesti,gesti,tasti modificatori,modificatore,tasti di blocco +X-KDE-Keywords[kk]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys +X-KDE-Keywords[km]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys +X-KDE-Keywords[ko]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,접근,접근성,청각장애,청각 장애,시각장애,시각 장애,키보드,키,고정키,튕김키,느린키,마우스키,숫자패드 +X-KDE-Keywords[mr]=एक्सेस, एक्सेसिबिलिटी, कर्णबधीर, विकलांग, ऐकणे, कमी ऐकू येणे, घंटा, घंटानाद , दृश्यघंटा, कि-बोर्ड, कीज, स्टिकी किज, बाउन्स किज, स्लो किज, माऊस दिशानिर्देश, न्यूम पॅड, एक्टिव्हेशन गेस्चर्स, गेस्चर्स, स्टिकी, मॉडीफायर कीज, मॉडीफायर, लॉकिंग किज, +X-KDE-Keywords[nb]=tilgang,tilgjengelighet,døv,hemmet,hørsel, hørselstap,bjelle,hørbar bjelle,synlig bjelle,Tastatur,låsetaster,faste taster,trege taster,musnavigering, talltastatur,tallboks,aktiveringsbevegelser,bevegelser,valgtaster +X-KDE-Keywords[nds]=Togang,Toganghülp,doof,kiekbehinnert,Hören,Pingel,Ogenpingel,Tastatuur,Tasten,backige Tasten,jumpen Tasten,langsame Tasten,Muusstüern,Tallenblock,Tekens,Anmaaktekens,backig,Sünnertasten,Wesseltekens,Fastsetttasten +X-KDE-Keywords[nl]=toegang,toegankelijkheid,doof,gehandicapt,gehoor,gehoorverlies,bel,hoorbare bel,zichtbare bel,toetsenbord,toetsen,dode toetsen,herhaaltoetsen,langzame toetsen,muisnavigatie,numeriek toetsenbord,activeringsgebaren,gebaren,plakkerig,modificatietoetsen,modificator,vergrendeltoets +X-KDE-Keywords[pl]=dostęp,dostępność,głuchota,upośledzenie,dzwonek,słyszalny dzwonek,widoczny dzwonek,Klawiatura,klawisze,lepkie klawisze,odbijające klawisze,powolne klawisze, ruchy myszą,klawiatura numeryczna +X-KDE-Keywords[pt]=acesso,acessibilidade,surdo,deficiente,campainha,campainha audível,campainha visível,teclado,teclas,teclas fixas,teclas lentas,teclas sonoras,navegação do rato,teclado numérico,numérico,gestos de activação,gestos,fixo,teclas modificadoras,modificadora,teclas de bloqueio +X-KDE-Keywords[pt_BR]=acesso,acessibilidade,surdo,deficiente,audição,campainha,campainha audível,campainha visível,Teclado,teclas,teclas de aderência,teclas lentas,teclas de repercussão,navegação do mouse,teclado numérico numérico,gestos de ativação,gestos,fixo,teclas modificadoras,modificadora,teclas de bloqueio +X-KDE-Keywords[ru]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,доступ,доступность,глухота,слух,ослабленный,слабый,потеря слуха,звонок,сигнал,звуковой сигнал,визуальный сигнал,видимый сигнал,клавиатура,кнопки,клавиши,залипание,залипающие клавиши,липкие клавиши,прыгающие клавиши,«прыгающие» клавиши,замедленные клавиши,навигация с помощью мыши,управление мышью,цифровая клавиатура,жесты активации,жесты,клавиши-модификаторы,модификаторы,модификатор,клавиши индикаторов +X-KDE-Keywords[sk]=prístup,prístupnosť,hluchý,opitý,sluch,strata sluchu,zvonček,hlasný zvonček,viditeľný zvonček,Klávesnica,klávesy,lepkavé klávesy,skákajúce klávesy,pomalé klávesy,navigácia myšou,numerická klávesnica,numpad,aktivačné gestá,lepkavé,modifikačné klávesy,modifikátor,zamykacie klávesy +X-KDE-Keywords[sl]=dostop,dostopnost,gluh,oviran,sluh,slušno,izguba sluha,zvonec,slišen zvonec,viden zvonec,tipkovnica,tipke,lepljive tipke,odbijajoče tipke,počasne tipke,krmarjenje z miško,številčnica,številske tipke,kretnje za vklop,kretnje,lepljivo,spremenilne tipke,zaklepne tipke +X-KDE-Keywords[sr]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,приступ,приступачност,глув,оштећен,слух,губитак,звоно,чујно,видно,тастатура,тастери,лепљиви,одскачући,спори,нумеричка,активација,гестови,лепљив,модификаторски,тастери,закључавање +X-KDE-Keywords[sr@ijekavian]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,приступ,приступачност,глув,оштећен,слух,губитак,звоно,чујно,видно,тастатура,тастери,лепљиви,одскачући,спори,нумеричка,активација,гестови,лепљив,модификаторски,тастери,закључавање +X-KDE-Keywords[sr@ijekavianlatin]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,pristup,pristupačnost,gluv,oštećen,sluh,gubitak,zvono,čujno,vidno,tastatura,tasteri,lepljivi,odskačući,spori,numerička,aktivacija,gestovi,lepljiv,modifikatorski,tasteri,zaključavanje +X-KDE-Keywords[sr@latin]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,pristup,pristupačnost,gluv,oštećen,sluh,gubitak,zvono,čujno,vidno,tastatura,tasteri,lepljivi,odskačući,spori,numerička,aktivacija,gestovi,lepljiv,modifikatorski,tasteri,zaključavanje +X-KDE-Keywords[sv]=åtkomst,handikappstöd,döva,funktionshindrade,hörsel,hörselförlust,summer,hörbar summer,synlig summer,Tangentbord,tangenter,klistriga tangenter,studsande tangenter,långsamma tangenter,musnavigering,numeriskt tangentbord,aktiveringsgester,gester,klistrig,väljartangenter,väljare,låstangenter +X-KDE-Keywords[tr]=erişim,erişebilirlik,sağır,bozukluk,işitme,kayıp,zil,işitilebilir zil,görünen zil,Klayve,tuşlar,yapışkan tuşlar,sıçrama tuşları,yavaş tuşlar,fare gezinmesi,rakamlar klavyesi,jestler,yapışkan,hızlandırma tuşları,hızlandırıcı,kilitleme tuşları +X-KDE-Keywords[uk]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,доступ,доступність,спеціальні можливості,глухий,слух,враження,вади,звук,сповіщення,видиме сповіщення,візуальне сповіщення,клавіатура,клавіші,клавіша,липкі клавіші,утримування,повільні клавіші,миша,навігація,цифри,цифровий блок,слух,втрата слуху,жести активування,жести,липка,липкі клавіші,клавіші-модифікатори,модифікатори,клавіші фіксування,фіксування,блокування +X-KDE-Keywords[x-test]=xxaccess,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keysxx +X-KDE-Keywords[zh_CN]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,访问,可访问性,耳聋,聋,听力,听力丧失,铃声,可视铃声,按键,残疾人,残疾,聋哑,键盘,粘滞键,鼠标,小键盘,撞击键,鼠标导航,数字键盘,激活手势,手势,粘滞,修饰键,锁定键 +X-KDE-Keywords[zh_TW]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys + +Categories=Qt;KDE;X-KDE-settings-accessibility; diff --git a/kcontrol/access/kcmaccess.h b/kcontrol/access/kcmaccess.h new file mode 100644 index 00000000..d3cb40f3 --- /dev/null +++ b/kcontrol/access/kcmaccess.h @@ -0,0 +1,76 @@ +/** + * kcmaccess.h + * + * Copyright (c) 2000 Matthias H�zer-Klpfel + * + */ + +#ifndef __kcmaccess_h__ +#define __kcmaccess_h__ + + +#define KDE3_SUPPORT +#include +#undef KDE3_SUPPORT +#include + + +class QCheckBox; +class QLabel; +class QLineEdit; +class QPushButton; +class QRadioButton; +class KColorButton; +class QSlider; + +class KAccessConfig : public KCModule +{ + Q_OBJECT + +public: + + KAccessConfig( QWidget *parent, const QVariantList& ); + virtual ~KAccessConfig(); + + void load(); + void save(); + void defaults(); + +protected Q_SLOTS: + + void configChanged(); + void checkAccess(); + void invertClicked(); + void flashClicked(); + void selectSound(); + void changeFlashScreenColor(); + void configureKNotify(); + +private: + + QCheckBox *systemBell, *customBell, *visibleBell; + QRadioButton *invertScreen, *flashScreen; + QLabel *soundLabel, *colorLabel; + QLineEdit *soundEdit; + QPushButton *soundButton; + KColorButton *colorButton; + KDoubleNumInput *durationSlider; + + QCheckBox *stickyKeys, *stickyKeysLock, *stickyKeysAutoOff; + QCheckBox *stickyKeysBeep, *toggleKeysBeep, *kNotifyModifiers; + QPushButton *kNotifyModifiersButton; + + QCheckBox *slowKeys, *bounceKeys; + KDoubleNumInput *slowKeysDelay, *bounceKeysDelay; + QCheckBox *slowKeysPressBeep, *slowKeysAcceptBeep; + QCheckBox *slowKeysRejectBeep, *bounceKeysRejectBeep; + + QCheckBox *gestures, *gestureConfirmation; + QCheckBox *timeout; + KIntNumInput *timeoutDelay; + QCheckBox *accessxBeep, *kNotifyAccessX; + QPushButton *kNotifyAccessXButton; +}; + + +#endif diff --git a/kcontrol/access/main.cpp b/kcontrol/access/main.cpp new file mode 100644 index 00000000..9dc1ae59 --- /dev/null +++ b/kcontrol/access/main.cpp @@ -0,0 +1,52 @@ + +#include "kaccess.h" +#include +#include +#include +#include +extern "C" KDE_EXPORT int kdemain(int argc, char * argv[] ) +{ + KAboutData about(I18N_NOOP("kaccess"), 0, ki18n("KDE Accessibility Tool"), + 0, KLocalizedString(), KAboutData::License_GPL, + ki18n("(c) 2000, Matthias Hoelzer-Kluepfel")); + + about.addAuthor(ki18n("Matthias Hoelzer-Kluepfel"), ki18n("Author") , "hoelzer@kde.org"); + + KCmdLineArgs::init( argc, argv, &about ); + + if (!KAccessApp::start()) + return 0; + + // verify the Xlib has matching XKB extension + int major = XkbMajorVersion; + int minor = XkbMinorVersion; + if (!XkbLibraryVersion(&major, &minor)) + { + kError() << "Xlib XKB extension does not match" << endl; + return 1; + } + kDebug() << "Xlib XKB extension major=" << major << " minor=" << minor; + + // we need an application object for QX11Info + KAccessApp app; + + // verify the X server has matching XKB extension + // if yes, the XKB extension is initialized + int opcode_rtrn; + int error_rtrn; + int xkb_opcode; + if (!XkbQueryExtension(QX11Info::display(), &opcode_rtrn, &xkb_opcode, &error_rtrn, + &major, &minor)) + { + kError() << "X server has not matching XKB extension" << endl; + return 1; + } + kDebug() << "X server XKB extension major=" << major << " minor=" << minor; + + //Without that, the application dies when the dialog is closed only once. + app.setQuitOnLastWindowClosed(false); + + app.setXkbOpcode(xkb_opcode); + app.disableSessionManagement(); + return app.exec(); +} diff --git a/kcontrol/autostart/AUTHORS b/kcontrol/autostart/AUTHORS new file mode 100644 index 00000000..ab559c90 --- /dev/null +++ b/kcontrol/autostart/AUTHORS @@ -0,0 +1,2 @@ +Stephen Leaf +Montel Laurent diff --git a/kcontrol/autostart/CMakeLists.txt b/kcontrol/autostart/CMakeLists.txt new file mode 100644 index 00000000..e05ac65c --- /dev/null +++ b/kcontrol/autostart/CMakeLists.txt @@ -0,0 +1,25 @@ +PROJECT (autostart) + +INCLUDE (KDE4Defaults) + +ADD_DEFINITIONS (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) +INCLUDE_DIRECTORIES (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) + +########### next target ############### + +SET(kcm_autostart_PART_SRCS + autostartitem.cpp + addscriptdialog.cpp + advanceddialog.cpp + autostart.cpp ) + +KDE4_ADD_UI_FILES(kcm_autostart_PART_SRCS autostartconfig.ui ) + +KDE4_ADD_PLUGIN(kcm_autostart ${kcm_autostart_PART_SRCS}) + +TARGET_LINK_LIBRARIES(kcm_autostart ${KDE4_KIO_LIBS} ) + +########### install files ############### + +INSTALL(TARGETS kcm_autostart DESTINATION ${PLUGIN_INSTALL_DIR} ) +INSTALL( FILES autostart.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/kcontrol/autostart/Messages.sh b/kcontrol/autostart/Messages.sh new file mode 100644 index 00000000..8f32b9b7 --- /dev/null +++ b/kcontrol/autostart/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/kcm_autostart.pot +rm -f rc.cpp diff --git a/kcontrol/autostart/addscriptdialog.cpp b/kcontrol/autostart/addscriptdialog.cpp new file mode 100644 index 00000000..8a4ef796 --- /dev/null +++ b/kcontrol/autostart/addscriptdialog.cpp @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2007 by Stephen Leaf * + * smileaf@gmail.com * + * Copyright (C) 2008 by Montel Laurent * + * * + * 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 "addscriptdialog.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +AddScriptDialog::AddScriptDialog (QWidget* parent) + : KDialog( parent ) { + QWidget *w = new QWidget( this ); + setButtons( Cancel|Ok ); + QVBoxLayout *lay= new QVBoxLayout; + w->setLayout( lay ); + QLabel *lab = new QLabel( i18n( "Shell script path:" ), w ); + lay->addWidget( lab ); + m_url = new KUrlRequester( w ); + lay->addWidget( m_url ); + m_symlink = new QCheckBox( i18n( "Create as symlink" ), w ); //TODO fix text + m_symlink->setChecked( true ); + lay->addWidget( m_symlink ); + connect( m_url->lineEdit(), SIGNAL(textChanged(QString)), SLOT(textChanged(QString)) ); + m_url->lineEdit()->setFocus(); + enableButtonOk(false); + + setMainWidget( w ); +} + +AddScriptDialog::~AddScriptDialog() +{ +} + +void AddScriptDialog::textChanged(const QString &text) +{ + enableButtonOk(!text.isEmpty()); +} + +void AddScriptDialog::accept() +{ + if ( doBasicSanityCheck() ) + KDialog::accept(); +} + +bool AddScriptDialog::doBasicSanityCheck() +{ + const QString& path = KShell::tildeExpand(m_url->text()); + + QFileInfo file(path); + + if ( ! file.isAbsolute() ) { + KMessageBox::sorry( 0, i18n("\"%1\" is not an absolute path.", path) ); + return false; + } else if ( ! file.exists() ) { + KMessageBox::sorry( 0, i18n("\"%1\" does not exist.", path) ); + return false; + } else if ( !file.isFile() ) { + KMessageBox::sorry( 0, i18n("\"%1\" is not a file.", path) ); + return false; + } else if ( ! file.isReadable() ) { + KMessageBox::sorry( 0, i18n("\"%1\" is not readable.", path) ); + return false; + } + + return true; +} + +KUrl AddScriptDialog::importUrl() const +{ + return m_url->lineEdit()->text(); +} + +bool AddScriptDialog::symLink() const +{ + return m_symlink->isChecked(); +} + +#include "addscriptdialog.moc" diff --git a/kcontrol/autostart/addscriptdialog.h b/kcontrol/autostart/addscriptdialog.h new file mode 100644 index 00000000..4064bf10 --- /dev/null +++ b/kcontrol/autostart/addscriptdialog.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2007 by Stephen Leaf * + * smileaf@gmail.com * + * Copyright (C) 2008 by Montel Laurent * + * * + * 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 ADDSCRIPTDIALOG_H +#define ADDSCRIPTDIALOG_H + +#include + +class KUrlRequester; +class QCheckBox; + +class AddScriptDialog : public KDialog +{ + Q_OBJECT + +public: + explicit AddScriptDialog(QWidget* parent=0); + ~AddScriptDialog(); + // Returns the Url of the script to be imported + KUrl importUrl() const; + bool symLink() const; + +public slots: + // reimplemented + virtual void accept(); + +protected: + virtual bool doBasicSanityCheck(); + +private slots: + void textChanged(const QString &text); + +private: + KUrlRequester *m_url; + QCheckBox* m_symlink; +}; + +#endif diff --git a/kcontrol/autostart/advanceddialog.cpp b/kcontrol/autostart/advanceddialog.cpp new file mode 100644 index 00000000..2fb11c5d --- /dev/null +++ b/kcontrol/autostart/advanceddialog.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2008 by Montel Laurent * + * * + * 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 "advanceddialog.h" + +#include +#include + +#include + +AdvancedDialog::AdvancedDialog( QWidget *parent, bool status ) + :KDialog( parent ) +{ + QWidget *w = new QWidget( this ); + setButtons( Cancel|Ok ); + QVBoxLayout *lay= new QVBoxLayout; + w->setLayout( lay ); + m_onlyInKde = new QCheckBox( i18n( "Autostart only in KDE" ), w ); + m_onlyInKde->setChecked( status ); + lay->addWidget( m_onlyInKde ); + setMainWidget( w ); +} + +AdvancedDialog::~AdvancedDialog() +{ +} + +bool AdvancedDialog::onlyInKde() const +{ + return m_onlyInKde->isChecked(); +} + + +#include "advanceddialog.moc" + diff --git a/kcontrol/autostart/advanceddialog.h b/kcontrol/autostart/advanceddialog.h new file mode 100644 index 00000000..28631a75 --- /dev/null +++ b/kcontrol/autostart/advanceddialog.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2008 by Montel Laurent * + * * + * 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 ADVANCEDDIALOG_H +#define ADVANCEDDIALOG_H + +#include +class QCheckBox; + +class AdvancedDialog : public KDialog +{ + Q_OBJECT + +public: + AdvancedDialog(QWidget* parent, bool status); + ~AdvancedDialog(); + + bool onlyInKde() const; + +private: + QCheckBox *m_onlyInKde; +}; + +#endif diff --git a/kcontrol/autostart/autostart.cpp b/kcontrol/autostart/autostart.cpp new file mode 100644 index 00000000..4ed67648 --- /dev/null +++ b/kcontrol/autostart/autostart.cpp @@ -0,0 +1,440 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Stephen Leaf * + * smileaf@gmail.com * + * Copyright (C) 2008 by Montel Laurent * + * * + * 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 "autostart.h" +#include "autostartitem.h" +#include "addscriptdialog.h" +#include "advanceddialog.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +K_PLUGIN_FACTORY(AutostartFactory, registerPlugin();) + K_EXPORT_PLUGIN(AutostartFactory( "kcmautostart", "kcm_autostart" )) + + Autostart::Autostart( QWidget* parent, const QVariantList& ) + : KCModule( AutostartFactory::componentData(), parent ) +{ + widget = new Ui_AutostartConfig(); + widget->setupUi(this); + + QStringList lstHeader; + lstHeader << i18n( "Name" ) + << i18n( "Command" ) + << i18n( "Status" ) + << i18nc("@title:column The name of the column that decides if the program is run on kde startup, on kde shutdown, etc", "Run On" ); + widget->listCMD->setHeaderLabels(lstHeader); + widget->listCMD->setFocus(); + + setButtons(Help); + + connect( widget->btnAddScript, SIGNAL(clicked()), SLOT(slotAddScript()) ); + connect( widget->btnAddProgram, SIGNAL(clicked()), SLOT(slotAddProgram()) ); + connect( widget->btnRemove, SIGNAL(clicked()), SLOT(slotRemoveCMD()) ); + connect( widget->btnAdvanced, SIGNAL(clicked()), SLOT(slotAdvanced()) ); + connect( widget->listCMD, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), SLOT(slotEditCMD(QTreeWidgetItem*)) ); + connect( widget->listCMD, SIGNAL(itemClicked(QTreeWidgetItem*,int)),this,SLOT(slotItemClicked(QTreeWidgetItem*,int)) ); + connect( widget->btnProperties, SIGNAL(clicked()), SLOT(slotEditCMD()) ); + connect( widget->listCMD, SIGNAL(itemSelectionChanged()), SLOT(slotSelectionChanged()) ); + + + KAboutData* about = new KAboutData("Autostart", 0, ki18n("KDE Autostart Manager"), "1.0", + ki18n("KDE Autostart Manager Control Panel Module"), + KAboutData::License_GPL, + ki18n("Copyright © 2006–2010 Autostart Manager team")); + about->addAuthor(ki18n("Stephen Leaf"), KLocalizedString(), "smileaf@gmail.com"); + about->addAuthor(ki18n("Montel Laurent"), ki18n( "Maintainer" ), "montel@kde.org"); + setAboutData( about ); + +} + +Autostart::~Autostart() +{ + delete widget; +} + + +void Autostart::slotItemClicked( QTreeWidgetItem *item, int col) +{ + if ( item && col == COL_STATUS ) { + DesktopStartItem *entry = dynamic_cast( item ); + if ( entry ) { + bool disable = ( item->checkState( col ) == Qt::Unchecked ); + KDesktopFile kc(entry->fileName().path()); + KConfigGroup grp = kc.desktopGroup(); + if ( grp.hasKey( "Hidden" ) && !disable) { + grp.deleteEntry( "Hidden" ); + } + else + grp.writeEntry("Hidden", disable); + + kc.sync(); + if ( disable ) + item->setText( COL_STATUS, i18nc( "The program won't be run", "Disabled" ) ); + else + item->setText( COL_STATUS, i18nc( "The program will be run", "Enabled" ) ); + } + } +} + +void Autostart::addItem( DesktopStartItem* item, const QString& name, const QString& run, const QString& command, bool disabled ) +{ + Q_ASSERT( item ); + item->setText( COL_NAME, name ); + item->setText( COL_RUN, run ); + item->setText( COL_COMMAND, command ); + item->setCheckState( COL_STATUS, disabled ? Qt::Unchecked : Qt::Checked ); + item->setText( COL_STATUS, disabled ? i18nc( "The program won't be run", "Disabled" ) : i18nc( "The program will be run", "Enabled" )); +} + +void Autostart::addItem(ScriptStartItem* item, const QString& name, const QString& command, ScriptStartItem::ENV type ) +{ + Q_ASSERT( item ); + item->setText( COL_NAME, name ); + item->setText( COL_COMMAND, command ); + item->changeStartup( type ); +} + + +void Autostart::load() +{ + // share/autostart may *only* contain .desktop files + // shutdown and env may *only* contain scripts, links or binaries + // autostart on the otherhand may contain all of the above. + // share/autostart is special as it overrides entries found in $KDEDIR/share/autostart + m_paths << KGlobalSettings::autostartPath() // All new entries should go here + << componentData().dirs()->localkdedir() + "shutdown/" + << componentData().dirs()->localkdedir() + "env/" + << componentData().dirs()->localkdedir() + "share/autostart/" // For Importing purposes + << componentData().dirs()->localxdgconfdir() + "autostart/" ; //xdg-config autostart dir + + // share/autostart shouldn't be an option as this should be reserved for global autostart entries + m_pathName << i18n("Startup") + << i18n("Shutdown") + << i18n("Pre-KDE startup") + ; + widget->listCMD->clear(); + + m_programItem = new QTreeWidgetItem( widget->listCMD ); + m_programItem->setText( 0, i18n( "Desktop File" )); + m_programItem->setFlags(m_programItem->flags()^Qt::ItemIsSelectable ); + + QFont boldFont = m_programItem->font(0); + boldFont.setBold( true ); + m_programItem->setData ( 0, Qt::FontRole, boldFont ); + + m_scriptItem = new QTreeWidgetItem( widget->listCMD ); + m_scriptItem->setText( 0, i18n( "Script File" )); + m_scriptItem->setFlags(m_scriptItem->flags()^Qt::ItemIsSelectable); + m_scriptItem->setData ( 0, Qt::FontRole, boldFont); + + widget->listCMD->expandItem( m_programItem ); + widget->listCMD->expandItem( m_scriptItem ); + + foreach (const QString& path, m_paths) { + if (! KStandardDirs::exists(path)) + KStandardDirs::makeDir(path); + + QDir autostartdir( path ); + autostartdir.setFilter( QDir::Files ); + const QFileInfoList list = autostartdir.entryInfoList(); + for (int i = 0; i < list.size(); ++i) { + QFileInfo fi = list.at(i); + QString filename = fi.fileName(); + bool desktopFile = filename.endsWith(".desktop"); + if ( desktopFile ) + { + KDesktopFile config(fi.absoluteFilePath()); + //kDebug() << fi.absoluteFilePath() << "trying" << config.desktopGroup().readEntry("Exec"); + QStringList commandLine = KShell::splitArgs(config.desktopGroup().readEntry("Exec")); + if (commandLine.isEmpty()) { + continue; + } + + const QString exe = commandLine.first(); + if (exe.isEmpty() || KStandardDirs::findExe(exe).isEmpty()) { + continue; + } + + DesktopStartItem *item = new DesktopStartItem( fi.absoluteFilePath(), m_programItem, this ); + + const KConfigGroup grp = config.desktopGroup(); + const bool hidden = grp.readEntry("Hidden", false); + const QStringList notShowList = grp.readXdgListEntry("NotShowIn"); + const QStringList onlyShowList = grp.readXdgListEntry("OnlyShowIn"); + + const bool disabled = hidden || + notShowList.contains("KDE") || + (!onlyShowList.isEmpty() && !onlyShowList.contains("KDE")); + + int indexPath = m_paths.indexOf((item->fileName().directory()+'/' ) ); + if ( indexPath > 2 ) + indexPath = 0; //.kde/share/autostart and .config/autostart load destkop at startup + addItem(item, config.readName(), m_pathName.value(indexPath), grp.readEntry("Exec"), disabled ); + } + else + { + ScriptStartItem *item = new ScriptStartItem( fi.absoluteFilePath(), m_scriptItem,this ); + int typeOfStartup = m_paths.indexOf((item->fileName().directory()+'/') ); + ScriptStartItem::ENV type = ScriptStartItem::START; + switch( typeOfStartup ) + { + case 0: + type =ScriptStartItem::START; + break; + case 1: + type = ScriptStartItem::SHUTDOWN; + break; + case 2: + type = ScriptStartItem::PRE_START; + break; + default: + kDebug()<<" type is not defined :"<listCMD->resizeColumnToContents(COL_NAME); + //widget->listCMD->resizeColumnToContents(COL_COMMAND); + widget->listCMD->resizeColumnToContents(COL_STATUS); + widget->listCMD->resizeColumnToContents(COL_RUN); +} + +void Autostart::slotAddProgram() +{ + KOpenWithDialog owdlg( this ); + if (owdlg.exec() != QDialog::Accepted) + return; + + KService::Ptr service = owdlg.service(); + + Q_ASSERT(service); + if (!service) { + return; // Don't crash if KOpenWith wasn't able to create service. + } + + // It is important to ensure that we make an exact copy of an existing + // desktop file (if selected) to enable users to override global autostarts. + // Also see + // https://bugs.launchpad.net/ubuntu/+source/kde-workspace/+bug/923360 + QString desktopPath; + KUrl desktopTemplate; + if ( service->desktopEntryName().isEmpty() ) { + // Build custom desktop file (e.g. when the user entered an executable + // name in the OpenWithDialog). + desktopPath = m_paths[4] + service->name() + ".desktop"; + desktopTemplate = KUrl( desktopPath ); + KConfig kc(desktopTemplate.path(), KConfig::SimpleConfig); + KConfigGroup kcg = kc.group("Desktop Entry"); + kcg.writeEntry("Exec",service->exec()); + kcg.writeEntry("Icon","system-run"); + kcg.writeEntry("Path",""); + kcg.writeEntry("Terminal",false); + kcg.writeEntry("Type","Application"); + kc.sync(); + + KPropertiesDialog dlg( desktopTemplate, this ); + if ( dlg.exec() != QDialog::Accepted ) + { + return; + } + } + else + { + // Use existing desktop file and use same file name to enable overrides. + desktopPath = m_paths[4] + service->desktopEntryName() + ".desktop"; + desktopTemplate = KUrl( KStandardDirs::locate("apps", service->entryPath()) ); + + KPropertiesDialog dlg( desktopTemplate, KUrl(m_paths[4]), service->desktopEntryName() + ".desktop", this ); + if ( dlg.exec() != QDialog::Accepted ) + return; + } + DesktopStartItem * item = new DesktopStartItem( desktopPath, m_programItem,this ); + addItem( item, service->name(), m_pathName[0], service->exec() , false); +} + +void Autostart::slotAddScript() +{ + AddScriptDialog * addDialog = new AddScriptDialog(this); + int result = addDialog->exec(); + if (result == QDialog::Accepted) { + if (addDialog->symLink()) + KIO::link(addDialog->importUrl(), m_paths[0]); + else + KIO::copy(addDialog->importUrl(), m_paths[0]); + + ScriptStartItem * item = new ScriptStartItem( m_paths[0] + addDialog->importUrl().fileName(), m_scriptItem,this ); + addItem( item, addDialog->importUrl().fileName(), addDialog->importUrl().fileName(),ScriptStartItem::START ); + } + delete addDialog; +} + +void Autostart::slotRemoveCMD() +{ + QTreeWidgetItem* item = widget->listCMD->currentItem(); + if (!item) + return; + DesktopStartItem *startItem = dynamic_cast( item ); + if ( startItem ) + { + m_programItem->takeChild( m_programItem->indexOfChild( startItem ) ); + KIO::del(startItem->fileName().path() ); + delete item; + } + else + { + ScriptStartItem * scriptItem = dynamic_cast( item ); + if ( scriptItem ) + { + m_scriptItem->takeChild( m_scriptItem->indexOfChild( scriptItem ) ); + KIO::del(scriptItem->fileName().path() ); + delete item; + } + } +} + +void Autostart::slotEditCMD(QTreeWidgetItem* ent) +{ + if (!ent) return; + AutoStartItem *entry = dynamic_cast( ent ); + if ( entry ) + { + const KFileItem kfi = KFileItem( KFileItem::Unknown, KFileItem::Unknown, KUrl( entry->fileName() ), true ); + if (! slotEditCMD( kfi )) + return; + DesktopStartItem *desktopEntry = dynamic_cast( entry ); + if (desktopEntry) { + KService service(desktopEntry->fileName().path()); + addItem( desktopEntry, service.name(), m_pathName.value(m_paths.indexOf((desktopEntry->fileName().directory()+'/') )), service.exec(),false ); + } + } +} + +bool Autostart::slotEditCMD( const KFileItem &item) +{ + KPropertiesDialog dlg( item, this ); + bool c = ( dlg.exec() == QDialog::Accepted ); + return c; +} + +void Autostart::slotEditCMD() +{ + if ( widget->listCMD->currentItem() == 0 ) + return; + slotEditCMD( (AutoStartItem*)widget->listCMD->currentItem() ); +} + +void Autostart::slotAdvanced() +{ + if ( widget->listCMD->currentItem() == 0 ) + return; + + DesktopStartItem *entry = static_cast( widget->listCMD->currentItem() ); + KDesktopFile kc(entry->fileName().path()); + KConfigGroup grp = kc.desktopGroup(); + bool status = false; + QStringList lstEntry; + if (grp.hasKey("OnlyShowIn")) + { + lstEntry = grp.readXdgListEntry("OnlyShowIn"); + status = lstEntry.contains("KDE"); + } + + AdvancedDialog *dlg = new AdvancedDialog( this,status ); + if ( dlg->exec() ) + { + status = dlg->onlyInKde(); + if ( lstEntry.contains( "KDE" ) && !status ) + { + lstEntry.removeAll( "KDE" ); + grp.writeXdgListEntry( "OnlyShowIn", lstEntry ); + } + else if ( !lstEntry.contains( "KDE" ) && status ) + { + lstEntry.append( "KDE" ); + grp.writeXdgListEntry( "OnlyShowIn", lstEntry ); + } + } + delete dlg; +} + +void Autostart::slotChangeStartup( ScriptStartItem* item, int index ) +{ + Q_ASSERT(item); + + if ( item ) + { + item->setPath(m_paths.value(index)); + widget->listCMD->setCurrentItem( item ); + if ( ( index == 2 ) && !item->fileName().path().endsWith( ".sh" )) + KMessageBox::information( this, i18n( "Only files with “.sh” extensions are allowed for setting up the environment." ) ); + + } +} + +void Autostart::slotSelectionChanged() +{ + const bool hasItems = ( dynamic_cast( widget->listCMD->currentItem() )!=0 ) ; + widget->btnRemove->setEnabled(hasItems); + + const bool isDesktopItem = (dynamic_cast(widget->listCMD->currentItem() ) != 0) ; + widget->btnProperties->setEnabled(isDesktopItem); + widget->btnAdvanced->setEnabled(isDesktopItem) ; +} + +void Autostart::defaults() +{ +} + +void Autostart::save() +{ +} + +#include "autostart.moc" diff --git a/kcontrol/autostart/autostart.desktop b/kcontrol/autostart/autostart.desktop new file mode 100644 index 00000000..0c7a0536 --- /dev/null +++ b/kcontrol/autostart/autostart.desktop @@ -0,0 +1,190 @@ +[Desktop Entry] +Exec=kcmshell4 autostart +Icon=system-run +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/autostart/index.html + +X-KDE-Library=kcm_autostart +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=startup-and-shutdown + +Name=Autostart +Name[af]=Outomatiese begin +Name[ar]=البدء التلقائي +Name[ast]=Autoarranque +Name[be]=Аўтаматычны запуск +Name[be@latin]=Aŭtamatyčnaje ŭklučeńnie +Name[bg]=Автоматично стартиране +Name[bn]=অটো-স্টার্ট +Name[bn_IN]=স্বয়ং-আরম্ভ +Name[br]=Emloc'h +Name[bs]=Samopokretanje +Name[ca]=Inici automàtic +Name[ca@valencia]=Inici automàtic +Name[cs]=Automatické spuštění +Name[csb]=Aùtomatné zrëszanié +Name[cy]=Hunan-gychwyn +Name[da]=Autostart +Name[de]=Autostart +Name[el]=Αυτόματη εκκίνηση +Name[en_GB]=Autostart +Name[eo]=Aŭtomata lanĉo +Name[es]=Autoarranque +Name[et]=Autostart +Name[eu]=Hasiera automatikoa +Name[fa]=آغاز خودکار +Name[fi]=Automaattikäynnistys +Name[fr]=Démarrage automatique +Name[fy]=Auto-úteinsette +Name[ga]=Tosú uathoibríoch +Name[gl]=Inicio automático +Name[gu]=આપમેળેશરૂ +Name[he]=הפעלה אוטומטית +Name[hi]=स्वतःप्रारंभ +Name[hne]=खुद से चालू +Name[hr]=Automatsko pokretanje +Name[hsb]=Awtostart +Name[hu]=Automatikus indítás +Name[ia]=Auto starta +Name[id]=Start Otomatis +Name[is]=Sjálfræsing +Name[it]=Avvio automatico +Name[ja]=自動起動 +Name[ka]=ავტოგაშვება +Name[kk]=Автобастау +Name[km]=ចាប់ផ្ដើម​ស្វ័យប្រវត្តិ +Name[kn]=ಸ್ವಯಮಾರಂಭ +Name[ko]=자동 시작 +Name[ku]=Bixweber Bide Destpêkirin +Name[lt]=Autostartas +Name[lv]=Autopalaišana +Name[mai]=स्वतः चालू +Name[mk]=Автостарт +Name[ml]=ഓട്ടോസ്റ്റാര്‍ട്ട് +Name[mr]=स्वप्रारंभ +Name[ms]=Automula +Name[nb]=Autostart +Name[nds]=Autostart +Name[nl]=Autostart +Name[nn]=Autostart +Name[or]=ସ୍ୱୟଂଚାଳନ +Name[pa]=ਆਟੋ-ਸਟਾਰਟ +Name[pl]=Samoczynne uruchamianie +Name[pt]=Arranque +Name[pt_BR]=Iniciar automaticamente +Name[ro]=Pornire automată +Name[ru]=Автозапуск +Name[si]=ක්‍ෂණික ඇරඹුම +Name[sk]=Automatické spustenie +Name[sl]=Samodejni zagon +Name[sr]=Самопокретање +Name[sr@ijekavian]=Самопокретање +Name[sr@ijekavianlatin]=Samopokretanje +Name[sr@latin]=Samopokretanje +Name[sv]=Automatisk start +Name[ta]=சுயதுவக்கம் +Name[te]=స్వయంచాలకప్రారంభం +Name[tg]=Худоғозӣ +Name[th]=เริ่มอัตโนมัติ +Name[tr]=Otomatik Başlat +Name[ug]=ئۆزلۈكىدىن قوزغات +Name[uk]=Автозапуск +Name[uz]=Avto-boshlash +Name[uz@cyrillic]=Авто-бошлаш +Name[vi]=Tự khởi chạy +Name[wa]=Enondaedje tot seu +Name[xh]=Isiqalo esizenzekelayo +Name[x-test]=xxAutostartxx +Name[zh_CN]=自动启动 +Name[zh_TW]=自動啟動 + +Comment=Manage which programs start up automatically with KDE. +Comment[bs]=Upravljanje koji će se programi automatski pokretati pomoću KDE. +Comment[ca]=Gestiona quins programes s'iniciaran automàticament amb el KDE. +Comment[ca@valencia]=Gestiona quins programes s'iniciaran automàticament amb el KDE. +Comment[cs]=Spravujte automatické spouštění programů při startu KDE. +Comment[da]=Håndtér hvilke programmer der automatisk starter op med KDE. +Comment[de]=Verwaltung der automatisch mit KDE zu startenden Anwendungen. +Comment[el]=Διαχείριση των προγραμμάτων που θα ξεκινούν αυτόματα με το KDE. +Comment[en_GB]=Manage which programs start up automatically with KDE. +Comment[es]=Gestionar qué programas se inician automáticamente con KDE. +Comment[et]=Määramine, millised programmid käivituvad automaatselt koos KDE-ga. +Comment[eu]=KDErekin automatikoki abiatuko diren programak kudeatu. +Comment[fi]=Aseta, mitkä ohjelmat käynnistetään automaattisesti KDE:n käynnistyessä. +Comment[ga]=Bainistigh na ríomhchláir a thosaíonn nuair a thosaíonn KDE. +Comment[gl]=Xestiona os programas que se inician xunto con KDE. +Comment[he]=נהל אילו תוכניות מופעלות ביחד עם KDE. +Comment[hu]=Annak kezelése, hogy mely programok induljanak automatikusan a KDE-vel. +Comment[ia]=Gere qual programma debe startar automaticamente con KDE. +Comment[is]=Stjórntæki til að stilla hvaða forrit eigi að ræsast sjálfkrafa með KDE. +Comment[kk]=KDE бастағанда автожегілетін бағдарламаларды басқару. +Comment[ko]=KDE를 시작할 때 같이 시작될 프로그램을 관리합니다. +Comment[lt]=Konfigūravimo įrankis valdyti programas, kurios paleidžiamos automatiškai kartu su KDE. +Comment[mr]=केडीई सह कोणते कार्यक्रम स्वप्रारंभ होतील ते नियंत्रीत करा. +Comment[nb]=Styr hvilke program som skal starte automatisk med KDE. +Comment[nds]=Programmen fastleggen, de automaatsch mit KDE opropen warrt +Comment[nl]=Beheren van programma's die automatisch met KDE opstarten. +Comment[pa]=ਪਰਬੰਧ ਕਰਦੀ ਹੈ ਕਿ ਕਿਹੜੇ ਪਰੋਗਰਾਮ ਕੇਡੀਈ (KDE) ਨਾਲ ਆਪਣੇ-ਆਪਣ ਚੱਲਣ। +Comment[pl]=Zdecyduj, które programy mają się uruchamiać wraz ze startem KDE. +Comment[pt]=Gerir os programas que são arrancados automaticamente com o KDE. +Comment[pt_BR]=Gerencia os programas que são carregados automaticamente com o KDE. +Comment[ro]=Gestionează ce programe se pornesc automat împreună cu KDE. +Comment[ru]=Управление программами, запускаемыми автоматически в начале сеанса KDE +Comment[sk]=Spravovať, ktoré programy spustiť automaticky s KDE. +Comment[sl]=Upravljanje programov, ki se samodejno zaženejo ob zagonu KDE. +Comment[sr]=Одредите који се програми покрећу са КДЕ‑ом по пријављивању. +Comment[sr@ijekavian]=Одредите који се програми покрећу са КДЕ‑ом по пријављивању. +Comment[sr@ijekavianlatin]=Odredite koji se programi pokreću sa KDE‑om po prijavljivanju. +Comment[sr@latin]=Odredite koji se programi pokreću sa KDE‑om po prijavljivanju. +Comment[sv]=Hantera vilka program som startas automatiskt när KDE startas. +Comment[tr]=Hangi programların KDE açılırken otomatik olarak başlatılacağını yönetin. +Comment[uk]=Керування програмами, які будуть запускатися разом з графічним середовищем KDE автоматично. +Comment[x-test]=xxManage which programs start up automatically with KDE.xx +Comment[zh_CN]=管理随 KDE 自动启动的程序 +Comment[zh_TW]=管理 KDE 要自動啟動哪些程式。 + +X-KDE-Keywords=Autostart Manager,autostart,startup,system startup,kde start,cron +X-KDE-Keywords[bs]=automatsko pokretanje upravitelja,automatsko pokretanje,pokretanje,sustav za pokretanje,početak kde,kompjuter izvodi zadatak za određeno vrijeme. +X-KDE-Keywords[ca]=Gestor d'inici automàtic,inici automàtic,inici,inici del sistema,inici del kde,cron +X-KDE-Keywords[ca@valencia]=Gestor d'inici automàtic,inici automàtic,inici,inici del sistema,inici del kde,cron +X-KDE-Keywords[da]=autostart,opstart,systemstart,kde start,cron +X-KDE-Keywords[de]=Autostartverwaltung,Autostart,Startvorgang,Systemstart,KDE-Start,Cron +X-KDE-Keywords[el]=διαχειριστής αυτόματης εκκίνησης,αυτόματη εκκίνηση,έναρξη,έναρξη συστήματος,έναρξη kde,cron +X-KDE-Keywords[en_GB]=Autostart Manager,autostart,startup,system startup,kde start,cron +X-KDE-Keywords[es]=Gestor de inicio automático,inicio automático,inicio,inicio del sistema,inicio de kde,cron +X-KDE-Keywords[et]=Autostardi haldur,autostart,käivitamine,süsteemi käivitamine,kde käivitamine,cron +X-KDE-Keywords[eu]=Hasiera automatikoaren kudeatzailea,hasiera automatikoa,abiarazi,sistema abiarazi,kde hasi,cron +X-KDE-Keywords[fi]=automaattikäynnistys,hallinta,käynnistys,järjestelmän käynnistys, järjestelmän käynnistyminen,kde:n käynnistys,kde:n käynnistyminen,cron +X-KDE-Keywords[fr]=Gestionnaire de démarrage, démarrage automatique, démarrage, démarrage du système, démarrage de kde, cron +X-KDE-Keywords[gl]=Xestor de inicio, inicio automático, inicio, sistema de arranque, inicio de kde, cron +X-KDE-Keywords[he]=Autostart Manager,autostart,startup,system startup,kde start,cron,הפעלה,התחלה +X-KDE-Keywords[hu]=Automatikus indítás kezelő,automatikus indítás,indulás,rendszerindulás,kde indulás,cron +X-KDE-Keywords[ia]=Gestor de autoinitio,autoinitio,initio,initio de systema.initio de kde,crom +X-KDE-Keywords[it]=Gestore avvio,avvio automatico,avvio,avvio del sistema,avvio di kde,cron +X-KDE-Keywords[kk]=Autostart Manager,autostart,startup,system startup,kde start,cron +X-KDE-Keywords[km]=ចាប់ផ្ដើម​កម្មវិធី​គ្រប់គ្រង​ដោយ​ស្វ័យ​ប្រវត្តិ ចាប់ផ្ដើម​ស្វ័យ​ប្រវត្តិ ចាប់ផ្ដើម ចាប់ផ្ដើម​ប្រព័ន្ធ ចាប់ផ្ដើម kde cron +X-KDE-Keywords[ko]=Autostart Manager,autostart,startup,system startup,kde start,cron,자동 시작,자동시작,시작프로그램,시스템 시작 +X-KDE-Keywords[lt]=Automatinio paleidimo tvarkyklė,automatinis paleidimas, sistemos paleidimas,kde paleidimas,cron +X-KDE-Keywords[mr]=स्वप्रारंभ व्यवस्थापक, स्वप्रारंभ, सुरुवात, सुरुवात प्रणाली, kde सुरुवात, क्रॉन +X-KDE-Keywords[nb]=Autostartbehandler,autostart,oppstart,systemstart,kde-start,cron +X-KDE-Keywords[nds]=Autostartpleger,Autostart,Starten,Hoochfohren,KDE-Start,Cron +X-KDE-Keywords[nl]=Autostartbeheerder,autostarten,opstarten,opstarten systeem,opstarten kde,cron +X-KDE-Keywords[pl]=Menadżer autostartu,autostart,uruchamianie,uruchamianie systemu,kde start,cron +X-KDE-Keywords[pt]=Gestor de arranque,arranque,início,arranque do sistema,início do kde,cron +X-KDE-Keywords[pt_BR]=Gerenciado de inicialização,inicialização,início,inicialização do sistema,início do kde,cron +X-KDE-Keywords[ru]=Autostart Manager,autostart,startup,system startup,kde start,cron,диспетчер автоматического запуска,автоматический запуск,автозапуск,загрузка системы,запуск kde +X-KDE-Keywords[sk]=Správca automatického spustenia,autostart,spustenie,spustenie systému,štart kde,cron +X-KDE-Keywords[sl]=upravljalnik samodejnega zagona,samodejni zagon,zagon,sistemski zagon,zagon kde,zagon sistema,cron +X-KDE-Keywords[sr]=Autostart Manager,autostart,startup,system startup,kde start,cron,самопокретање,менаџер самопокретања,покретање система +X-KDE-Keywords[sr@ijekavian]=Autostart Manager,autostart,startup,system startup,kde start,cron,самопокретање,менаџер самопокретања,покретање система +X-KDE-Keywords[sr@ijekavianlatin]=Autostart Manager,autostart,startup,system startup,kde start,cron,samopokretanje,menadžer samopokretanja,pokretanje sistema +X-KDE-Keywords[sr@latin]=Autostart Manager,autostart,startup,system startup,kde start,cron,samopokretanje,menadžer samopokretanja,pokretanje sistema +X-KDE-Keywords[sv]=Hantering av autostart,autostart,start,systemstart,kde-start,cron +X-KDE-Keywords[tr]=Otomatik Başlatma Yöneticisi, otomatik,başlatma,sistem başlangıcı,kde başlangıcı,görevler,cron +X-KDE-Keywords[uk]=Autostart Manager,autostart,startup,system startup,kde start,cron,керування автозапуском,автозапуск,запуск,запуск системи,запуск kde +X-KDE-Keywords[vi]=trình quản lý tự động chạy,tự động chạy,khởi động,khởi động hệ thống,chạy kde,cron +X-KDE-Keywords[x-test]=xxAutostart Manager,autostart,startup,system startup,kde start,cronxx +X-KDE-Keywords[zh_CN]=Autostart Manager,autostart,startup,system startup,kde start,cron,自动启动管理器,自动启动,启动,系统启动,kde 启动,任务调度 +X-KDE-Keywords[zh_TW]=Autostart Manager,autostart,startup,system startup,kde start,cron diff --git a/kcontrol/autostart/autostart.h b/kcontrol/autostart/autostart.h new file mode 100644 index 00000000..f429b71e --- /dev/null +++ b/kcontrol/autostart/autostart.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Stephen Leaf * + * smileaf@gmail.com * + * Copyright (C) 2008 by Montel Laurent * + * * + * 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 AUTOSTART_H +#define AUTOSTART_H + +#include +#include + +#include +#include + +#include "ui_autostartconfig.h" +#include "autostartitem.h" + +class Autostart: public KCModule +{ + Q_OBJECT + +public: + Autostart( QWidget* parent, const QVariantList& ); + ~Autostart(); + enum COL_TYPE { COL_NAME = 0, COL_COMMAND=1, COL_STATUS=2,COL_RUN=3 }; + void load(); + void save(); + void defaults(); + + QStringList listPathName() const { return m_pathName;} + +public slots: + void slotChangeStartup( ScriptStartItem* item, int index ); + +protected: + void addItem(DesktopStartItem *item, const QString& name, const QString& run, const QString& command, bool disabled ); + void addItem(ScriptStartItem *item, const QString& name, const QString& command, ScriptStartItem::ENV type ); + +private slots: + void slotAddProgram(); + void slotAddScript(); + void slotRemoveCMD(); + void slotEditCMD(QTreeWidgetItem*); + bool slotEditCMD(const KFileItem&); + void slotEditCMD(); + void slotSelectionChanged(); + void slotItemClicked( QTreeWidgetItem *, int); + void slotAdvanced(); + +private: + QTreeWidgetItem *m_programItem, *m_scriptItem; + QStringList m_paths; + QStringList m_pathName; + + Ui_AutostartConfig *widget; +}; + +#endif diff --git a/kcontrol/autostart/autostartconfig.ui b/kcontrol/autostart/autostartconfig.ui new file mode 100644 index 00000000..6dfdb8b8 --- /dev/null +++ b/kcontrol/autostart/autostartconfig.ui @@ -0,0 +1,82 @@ + + AutostartConfig + + + + 0 + 0 + 553 + 384 + + + + + + + false + + + false + + + + + + + Add Program... + + + + + + + Add Script... + + + + + + + &Remove + + + + + + + &Properties... + + + + + + + Qt::Vertical + + + + 79 + 141 + + + + + + + + Qt::Horizontal + + + + + + + Advanced... + + + + + + + + diff --git a/kcontrol/autostart/autostartitem.cpp b/kcontrol/autostart/autostartitem.cpp new file mode 100644 index 00000000..f052d709 --- /dev/null +++ b/kcontrol/autostart/autostartitem.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (C) 2008 by Montel Laurent * + * * + * 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 "autostartitem.h" +#include "autostart.h" + +#include +#include +#include +#include + +#include +#include +#include + +AutoStartItem::AutoStartItem( const QString &service, QTreeWidgetItem *parent, Autostart* ) + : QTreeWidgetItem( parent ) +{ + m_fileName = KUrl(service); +} + +AutoStartItem::~AutoStartItem() +{ + +} + +KUrl AutoStartItem::fileName() const +{ + return m_fileName; +} + +void AutoStartItem::setPath(const QString &path) +{ + Q_ASSERT( path.endsWith(QDir::separator()) ); + + if (path == m_fileName.directory(KUrl::AppendTrailingSlash)) + return; + + const QString& newFileName = path + m_fileName.fileName(); + KIO::move(m_fileName, KUrl(newFileName)); + + m_fileName = KUrl(newFileName); +} + +DesktopStartItem::DesktopStartItem( const QString &service, QTreeWidgetItem *parent, Autostart*autostart ) + : AutoStartItem( service, parent,autostart ) +{ + setCheckState ( Autostart::COL_STATUS,Qt::Checked ); +} + +DesktopStartItem::~DesktopStartItem() +{ +} + +ScriptStartItem::ScriptStartItem( const QString &service, QTreeWidgetItem *parent, Autostart* autostart ) + : AutoStartItem( service, parent,autostart ) +{ + m_comboBoxStartup = new QComboBox; + m_comboBoxStartup->addItems( autostart->listPathName() ); + + setText( 2, i18nc( "The program will be run", "Enabled" ) ); + QObject::connect( m_comboBoxStartup,SIGNAL(activated(int)),this,SLOT(slotStartupChanged(int)) ); + QObject::connect( this,SIGNAL(askChangeStartup(ScriptStartItem*,int)),autostart,SLOT(slotChangeStartup(ScriptStartItem*,int)) ); + treeWidget()->setItemWidget ( this, Autostart::COL_RUN, m_comboBoxStartup ); +} + +ScriptStartItem::~ScriptStartItem() +{ +} + +void ScriptStartItem::slotStartupChanged(int index) +{ + emit askChangeStartup(this, index); +} + +void ScriptStartItem::changeStartup(ScriptStartItem::ENV type ) +{ + switch( type ) + { + case ScriptStartItem::START: + m_comboBoxStartup->setCurrentIndex( 0 ); + break; + case ScriptStartItem::SHUTDOWN: + m_comboBoxStartup->setCurrentIndex( 1 ); + break; + case ScriptStartItem::PRE_START: + m_comboBoxStartup->setCurrentIndex( 2 ); + break; + default: + kWarning() << " startup type is not defined :" << type; + break; + } +} + +#include "autostartitem.moc" diff --git a/kcontrol/autostart/autostartitem.h b/kcontrol/autostart/autostartitem.h new file mode 100644 index 00000000..85622e87 --- /dev/null +++ b/kcontrol/autostart/autostartitem.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2008 by Montel Laurent * + * * + * 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 AUTOSTARTITEM_H +#define AUTOSTARTITEM_H + +#include +#include +#include + +class QComboBox; +class QTreeWidget; +class Autostart; + +class AutoStartItem : public QTreeWidgetItem, public QObject +{ +public: + AutoStartItem( const QString &service, QTreeWidgetItem *parent, Autostart* ); + ~AutoStartItem(); + + KUrl fileName() const; + + void setPath(const QString &path); + +private: + KUrl m_fileName; +}; + +class DesktopStartItem : public AutoStartItem +{ +public: + DesktopStartItem( const QString &service, QTreeWidgetItem *parent, Autostart* ); + ~DesktopStartItem(); +}; + + +class ScriptStartItem : public AutoStartItem +{ + Q_OBJECT + +public: + enum ENV { START=0, SHUTDOWN=1, PRE_START=2}; //rename + ScriptStartItem( const QString &service, QTreeWidgetItem *parent, Autostart* ); + ~ScriptStartItem(); + + void changeStartup( ScriptStartItem::ENV type ); + +signals: + void askChangeStartup(ScriptStartItem* item, int index); + +private slots: + + void slotStartupChanged(int index); + +private: + QComboBox *m_comboBoxStartup; +}; + +#endif diff --git a/kcontrol/bell/CMakeLists.txt b/kcontrol/bell/CMakeLists.txt new file mode 100644 index 00000000..8665c78d --- /dev/null +++ b/kcontrol/bell/CMakeLists.txt @@ -0,0 +1,21 @@ + + + +########### next target ############### + +set(kcm_bell_PART_SRCS bell.cpp ) + + +kde4_add_plugin(kcm_bell ${kcm_bell_PART_SRCS}) + + +target_link_libraries(kcm_bell ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY} ${X11_X11_LIB}) + +install(TARGETS kcm_bell DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES bell.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + +kde4_install_icons( ${ICON_INSTALL_DIR} ) diff --git a/kcontrol/bell/Messages.sh b/kcontrol/bell/Messages.sh new file mode 100644 index 00000000..cb6a4782 --- /dev/null +++ b/kcontrol/bell/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kcmbell.pot diff --git a/kcontrol/bell/bell.cpp b/kcontrol/bell/bell.cpp new file mode 100644 index 00000000..3d9395f6 --- /dev/null +++ b/kcontrol/bell/bell.cpp @@ -0,0 +1,253 @@ +/* + Copyright (c) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) + 1998 Bernd Wuebben + 2000 Matthias Elter + 2001 Carsten PFeiffer + + 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 + + +//Added by qt3to4: +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bell.h" +#include "bell.moc" + +#include +#include +#include +#include + + + +K_PLUGIN_FACTORY(KBellConfigFactory, registerPlugin();) +K_EXPORT_PLUGIN(KBellConfigFactory("kcmbell")) + + + +extern "C" +{ + KDE_EXPORT void kcminit_bell() + { + XKeyboardState kbd; + XKeyboardControl kbdc; + + XGetKeyboardControl(QX11Info::display(), &kbd); + + KConfig _config( "kcmbellrc", KConfig::NoGlobals ); + KConfigGroup config(&_config, "General"); + + kbdc.bell_percent = config.readEntry("Volume", kbd.bell_percent); + kbdc.bell_pitch = config.readEntry("Pitch", kbd.bell_pitch); + kbdc.bell_duration = config.readEntry("Duration", kbd.bell_duration); + XChangeKeyboardControl(QX11Info::display(), + KBBellPercent | KBBellPitch | KBBellDuration, + &kbdc); + } +} + +KBellConfig::KBellConfig(QWidget *parent, const QVariantList &args): + KCModule(KBellConfigFactory::componentData(), parent, args) +{ + QBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + + QGroupBox *box = new QGroupBox(i18n("Bell Settings"), this ); + QFormLayout *form = new QFormLayout(); + box->setLayout(form); + layout->addWidget(box); + + m_useBell = new QCheckBox( i18n("&Use system bell instead of system notification" ), box ); + m_useBell->setWhatsThis( i18n("You can use the standard system bell (PC speaker) or a " + "more sophisticated system notification, see the " + "\"System Notifications\" control module for the " + "\"Something Special Happened in the Program\" event.")); + connect(m_useBell, SIGNAL(toggled(bool)), SLOT(useBell(bool))); + form->addRow(m_useBell); + + setQuickHelp( i18n("

System Bell

Here you can customize the sound of the standard system bell," + " i.e. the \"beep\" you always hear when there is something wrong. Note that you can further" + " customize this sound using the \"Accessibility\" control module; for example, you can choose" + " a sound file to be played instead of the standard bell.")); + + m_volume = new KIntNumInput(50, box); + m_volume->setRange(0, 100, 5); + m_volume->setSuffix("%"); + m_volume->setSteps(5,25); + form->addRow(i18n("&Volume:"), m_volume); + m_volume->setWhatsThis( i18n("Here you can customize the volume of the system bell. For further" + " customization of the bell, see the \"Accessibility\" control module.") ); + + m_pitch = new KIntNumInput(800, box); + m_pitch->setRange(20, 2000, 20); + m_pitch->setSuffix(i18n(" Hz")); + m_pitch->setSteps(40,200); + form->addRow(i18n("&Pitch:"), m_pitch); + m_pitch->setWhatsThis( i18n("Here you can customize the pitch of the system bell. For further" + " customization of the bell, see the \"Accessibility\" control module.") ); + + m_duration = new KIntNumInput(100, box); + m_duration->setRange(1, 1000, 50); + m_duration->setSuffix(i18n(" msec")); + m_duration->setSteps(20,100); + form->addRow(i18n("&Duration:"), m_duration); + m_duration->setWhatsThis( i18n("Here you can customize the duration of the system bell. For further" + " customization of the bell, see the \"Accessibility\" control module.") ); + + m_testButton = new QPushButton(i18n("&Test"), box); + m_testButton->setObjectName("test"); + form->addRow(QString(), m_testButton); + connect( m_testButton, SIGNAL(clicked()), SLOT(ringBell())); + m_testButton->setWhatsThis( i18n("Click \"Test\" to hear how the system bell will sound using your changed settings.") ); + + // watch for changes + connect(m_volume, SIGNAL(valueChanged(int)), SLOT(changed())); + connect(m_pitch, SIGNAL(valueChanged(int)), SLOT(changed())); + connect(m_duration, SIGNAL(valueChanged(int)), SLOT(changed())); + + KAboutData *about = + new KAboutData(I18N_NOOP("kcmbell"), 0, ki18n("KDE Bell Control Module"), + 0, KLocalizedString(), KAboutData::License_GPL, + ki18n("(c) 1997 - 2001 Christian Czezatke, Matthias Elter")); + + about->addAuthor(ki18n("Christian Czezatke"), ki18n("Original author"), "e9025461@student.tuwien.ac.at"); + about->addAuthor(ki18n("Bernd Wuebben"), KLocalizedString(), "wuebben@kde.org"); + about->addAuthor(ki18n("Matthias Elter"), ki18n("Current maintainer"), "elter@kde.org"); + about->addAuthor(ki18n("Carsten Pfeiffer"), KLocalizedString(), "pfeiffer@kde.org"); + setAboutData(about); +} + +void KBellConfig::load() +{ + XKeyboardState kbd; + XGetKeyboardControl(QX11Info::display(), &kbd); + + m_volume->setValue(kbd.bell_percent); + m_pitch->setValue(kbd.bell_pitch); + m_duration->setValue(kbd.bell_duration); + + KConfig _cfg("kdeglobals", KConfig::NoGlobals); + KConfigGroup cfg(&_cfg, "General"); + m_useBell->setChecked(cfg.readEntry("UseSystemBell", false)); + useBell(m_useBell->isChecked()); + emit changed(false); +} + +void KBellConfig::save() +{ + XKeyboardControl kbd; + + int bellVolume = m_volume->value(); + int bellPitch = m_pitch->value(); + int bellDuration = m_duration->value(); + + kbd.bell_percent = bellVolume; + kbd.bell_pitch = bellPitch; + kbd.bell_duration = bellDuration; + XChangeKeyboardControl(QX11Info::display(), + KBBellPercent | KBBellPitch | KBBellDuration, + &kbd); + + KConfig _config("kcmbellrc", KConfig::NoGlobals); + KConfigGroup config(&_config, "General"); + config.writeEntry("Volume",bellVolume); + config.writeEntry("Pitch",bellPitch); + config.writeEntry("Duration",bellDuration); + + config.sync(); + + KConfig _cfg("kdeglobals", KConfig::NoGlobals); + KConfigGroup cfg(&_cfg, "General"); + cfg.writeEntry("UseSystemBell", m_useBell->isChecked()); + cfg.sync(); + + if (!m_useBell->isChecked()) + { + KConfig config("kaccessrc"); + + KConfigGroup group = config.group("Bell"); + group.writeEntry("SystemBell", false); + group.writeEntry("ArtsBell", false); + group.writeEntry("VisibleBell", false); + } +} + +void KBellConfig::ringBell() +{ + if (!m_useBell->isChecked()) { + KNotification::beep(QString(), this); + return; + } + + // store the old state + XKeyboardState old_state; + XGetKeyboardControl(QX11Info::display(), &old_state); + + // switch to the test state + XKeyboardControl kbd; + kbd.bell_percent = m_volume->value(); + kbd.bell_pitch = m_pitch->value(); + if (m_volume->value() > 0) + kbd.bell_duration = m_duration->value(); + else + kbd.bell_duration = 0; + XChangeKeyboardControl(QX11Info::display(), + KBBellPercent | KBBellPitch | KBBellDuration, + &kbd); + // ring bell + XBell(QX11Info::display(),0); + + // restore old state + kbd.bell_percent = old_state.bell_percent; + kbd.bell_pitch = old_state.bell_pitch; + kbd.bell_duration = old_state.bell_duration; + XChangeKeyboardControl(QX11Info::display(), + KBBellPercent | KBBellPitch | KBBellDuration, + &kbd); +} + +void KBellConfig::defaults() +{ + m_volume->setValue(100); + m_pitch->setValue(800); + m_duration->setValue(100); + m_useBell->setChecked( false ); + useBell( false ); +} + +void KBellConfig::useBell( bool on ) +{ + m_volume->setEnabled( on ); + m_pitch->setEnabled( on ); + m_duration->setEnabled( on ); + m_testButton->setEnabled( on ); + changed(); +} diff --git a/kcontrol/bell/bell.desktop b/kcontrol/bell/bell.desktop new file mode 100644 index 00000000..16d8ac08 --- /dev/null +++ b/kcontrol/bell/bell.desktop @@ -0,0 +1,239 @@ +[Desktop Entry] +Exec=kcmshell4 bell +Icon=preferences-desktop-notification-bell +Type=Service +X-KDE-ServiceTypes=KCModule,KCModuleInit +X-DocPath=kcontrol/bell/index.html +Categories=Qt;KDE;X-KDE-settings-sound; + +X-KDE-Library=kcm_bell +X-KDE-Init-Symbol=bell +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=application-and-system-notifications +X-KDE-Weight=60 + +Name=System Bell +Name[af]=Stelsel Klok +Name[ar]=جرس النظام +Name[ast]=Pitíu del sistema +Name[be]=Сістэмны званок +Name[be@latin]=Systemny hukavy syhnał +Name[bg]=Системен звук +Name[bn]=সিস্টেম ঘণ্টা +Name[bn_IN]=সিস্টেমের ঘন্টা +Name[br]=Kloc'h ar reizhiad +Name[bs]=Sistemsko zvono +Name[ca]=Timbre del sistema +Name[ca@valencia]=Timbre del sistema +Name[cs]=Systémový zvonek +Name[csb]=Systemowi brzãczk +Name[cy]=Cloch Cysawd +Name[da]=Systemklokke +Name[de]=Signalton +Name[el]=Μεγαφωνάκι συστήματος +Name[en_GB]=System Bell +Name[eo]=Sistempepo +Name[es]=Timbre del sistema +Name[et]=Süsteemne signaal +Name[eu]=Sistemaren soinua +Name[fa]=زنگ سیستم +Name[fi]=Järjestelmän varoitus +Name[fr]=Cloche du système +Name[fy]=Systeembel +Name[ga]=Cloigín an Chórais +Name[gl]=Badalada do sistema +Name[gu]=સિસ્ટમ ઘંટડી +Name[he]=פעמון המערכת +Name[hi]=तंत्र घंटी +Name[hne]=तंत्र घंटी +Name[hr]=Sistemsko zvono +Name[hsb]=Systemowy zwónčk +Name[hu]=Rendszercsengő +Name[ia]=Campana de systema +Name[id]=Bel Sistem +Name[is]=Kerfisbjalla +Name[it]=Campanella di sistema +Name[ja]=システムベル +Name[ka]=სისტემის ხმოვანი სიგნალი +Name[kk]=Жүйелік қоңырау +Name[km]=កណ្ដឹង​ប្រព័ន្ធ +Name[kn]=ವ್ಯವಸ್ಥಾ ಗಂಟೆ +Name[ko]=시스템 종소리 +Name[ku]=Zingila Pergalê +Name[lt]=Sistemos skambutis +Name[lv]=Sistēmas zvans +Name[mai]=तंत्र घंटी +Name[mk]=Системско ѕвонче +Name[ml]=സിസ്റ്റം മണി +Name[mr]=प्रणाली घंटी +Name[ms]=Loceng Sistem +Name[nb]=Systemlyd +Name[nds]=Systeempingel +Name[ne]=प्रणाली बेल +Name[nl]=Systeembel +Name[nn]=Systemlyd +Name[or]=ତନ୍ତ୍ର ଘଣ୍ଟି +Name[pa]=ਸਿਸਟਮ ਘੰਟੀ +Name[pl]=Brzęczyk systemowy +Name[pt]=Campainha do Sistema +Name[pt_BR]=Campainha do sistema +Name[ro]=Clopoțel de sistem +Name[ru]=Системный звуковой сигнал +Name[se]=Vuogádatjietna +Name[si]=පද්ධති සීනුව +Name[sk]=Zvonček +Name[sl]=Sistemski zvonec +Name[sr]=Системско звоно +Name[sr@ijekavian]=Системско звоно +Name[sr@ijekavianlatin]=Sistemsko zvono +Name[sr@latin]=Sistemsko zvono +Name[sv]=Systemsummer +Name[ta]=அமைப்பு மணி +Name[te]=వ్యవస్థ గంట +Name[tg]=Системаи занг +Name[th]=ออดระบบ +Name[tr]=Sistem Zili +Name[ug]=سىستېما قوڭغۇراق ئاۋازى +Name[uk]=Системний дзвінок +Name[uz]=Tizim tovush signali +Name[uz@cyrillic]=Тизим товуш сигнали +Name[vi]=Chuông hệ thống +Name[wa]=Xhuflet do sistinme +Name[xh]=Indlela yokusebenza Yentsimbi +Name[x-test]=xxSystem Bellxx +Name[zh_CN]=系统铃声 +Name[zh_TW]=系統鈴聲 + +Comment=System Bell Configuration +Comment[af]=Stelsel Klok Opstelling +Comment[ar]=إعداد جرس النظام +Comment[ast]=Configuración del pitíu del sistema +Comment[be]=Настаўленне сістэмнага званка +Comment[be@latin]=Nałady systemnaha hukavoha syhnału +Comment[bg]=Настройване звуковия сигнал на системата +Comment[bn]=সিস্টেম ঘণ্টা কনফিগারেশন +Comment[bn_IN]=সিস্টেমের ঘন্টা সংক্রান্ত কনফিগারেশন +Comment[br]=Kefluniañ kloc'h ar reizhiad +Comment[bs]=Postava sistemskog zvona +Comment[ca]=Configuració del timbre del sistema +Comment[ca@valencia]=Configuració del timbre del sistema +Comment[cs]=Nastavení systémového zvonku +Comment[csb]=Kònfigùracëjô systemòwégò brzãczka +Comment[cy]=Gosodiadau'r Cloch Cysawd +Comment[da]=Systemklokkeindstilling +Comment[de]=Einstellungen zum Signalton +Comment[el]=Διαμόρφωση για το μεγαφωνάκι του συστήματός σας +Comment[en_GB]=System Bell Configuration +Comment[eo]=Agordo de la sistempepo +Comment[es]=Configuración del timbre del sistema +Comment[et]=Süsteemse signaali seadistamine +Comment[eu]=Sistemaren soinuaren konfigurazioa +Comment[fa]=پیکربندی زنگ سیستم +Comment[fi]=Järjestelmän varoitusäänen asetus +Comment[fy]=Systeemlûden ynstelle +Comment[ga]=Cumraíocht Chloigín an Chórais +Comment[gl]=Configuración da badalada do sistema +Comment[gu]=સિસ્ટમ ઘંટડી રૂપરેખાંકન +Comment[he]=הגדרות פעמון המערכת +Comment[hi]=तंत्र घंटी कॉन्फ़िगरेशन +Comment[hne]=तंत्र घंटी कान्फिगरेसन +Comment[hr]=Konfiguracija sistemskog zvona +Comment[hsb]=Připrawjenje systemoweho zwónčka +Comment[hu]=A rendszercsengő beállításai +Comment[ia]=Configuration del campana de systema +Comment[id]=Konfigurasi Bel Sistem +Comment[is]=Stillingar kerfishljóða +Comment[ka]=სისტემის ხმოვანი სიგნალის კონფიგურაცია +Comment[kk]=Жүйелік қоңырауды баптау +Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​កណ្ដឹង​ប្រព័ន្ធ +Comment[kn]=ವ್ಯವಸ್ಥಾ ಗಂಟೆ ಸಂರಚನೆ +Comment[ko]=시스템 종소리 설정 +Comment[ku]=Veavakirina Zingila Pergalê +Comment[lt]=Sistemos skambučio derinimas +Comment[lv]=Sistēmas zvana konfigurācija +Comment[mai]=तंत्र घंटी कान्फिगरेशन +Comment[mk]=Конфигурација на системското ѕвонче +Comment[ml]=സിസ്റ്റത്തിന്റെ മണിയ്ക്കുള്ള ക്രമീകരണം +Comment[mr]=प्रणाली घंटी संयोजना +Comment[ms]=Konfigurasi Loceng Sistem +Comment[nb]=Systemlydoppsett +Comment[nds]=Systeempingel instellen +Comment[ne]=प्रणाली बेल कन्फिगरेसन +Comment[nl]=Systeemgeluiden instellen +Comment[nn]=Systemlydoppsett +Comment[or]=ତନ୍ତ୍ର ଘଣ୍ଟି ସଂରଚନା +Comment[pa]=ਸਿਸਟਮ ਘੰਟੀ ਸੰਰਚਨਾ +Comment[pl]=Ustawienia brzęczka systemowego +Comment[pt]=Configuração da Campainha do Sistema +Comment[pt_BR]=Configuração da campainha do sistema +Comment[ro]=Configurare Clopoțel de sistem +Comment[ru]=Настройка системного звукового сигнала +Comment[se]=Vuogádatjietnaheivehusat +Comment[si]=පද්ධති සීනු සැකසුම් +Comment[sk]=Nastavenie zvončeka +Comment[sl]=Nastavitve sistemskega zvonca +Comment[sr]=Постава системског звона +Comment[sr@ijekavian]=Постава системског звона +Comment[sr@ijekavianlatin]=Postava sistemskog zvona +Comment[sr@latin]=Postava sistemskog zvona +Comment[sv]=Anpassa systemets summer +Comment[ta]=அமைப்பின் மணி வடிவமைப்பு +Comment[te]=సిస్టమ్ బెల్ సాధనం +Comment[tg]=Танзимоти системаи занг +Comment[th]=ปรับแต่งออดระบบ +Comment[tr]=Sistem Zili Yapılandırması +Comment[ug]=سىستېما قوڭغۇرىقى سەپلىمىسى +Comment[uk]=Налаштування системного дзвінка +Comment[uz]=Tizim tovush signalini moslash +Comment[uz@cyrillic]=Тизим товуш сигналини мослаш +Comment[vi]=Cấu hình Chuông Hệ thống +Comment[wa]=Apontiaedje do xhuflet do sistinme +Comment[xh]=Uqwalaselo Lwendlela Yentsimbi +Comment[x-test]=xxSystem Bell Configurationxx +Comment[zh_CN]=系统铃声配置 +Comment[zh_TW]=系統鈴聲組態 + +X-KDE-Keywords=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker +X-KDE-Keywords[bs]=zvono,zvučni,zvuk,glasnoća,igralište,trajanje,visina tona,trajanje,PC zvučnici,unutarnji zvučnik,zvučnik,sustav zvona,sustav zvučnika,unutarnji PC zvučnik +X-KDE-Keywords[ca]=Campana,Àudio,So,Volum,To,Durada,Altaveu del PC,Altaveu intern,Altaveu,Campana del sistema,Altaveu del sistema,Altaveu intern del PC +X-KDE-Keywords[ca@valencia]=Campana,Àudio,So,Volum,To,Durada,Altaveu del PC,Altaveu intern,Altaveu,Campana del sistema,Altaveu del sistema,Altaveu intern del PC +X-KDE-Keywords[da]=Klokke,lyd,lydstyrke,volume,tone,varighed,pc-højtaler,intern højtaler,højtaler,systemklokke,systemhøjtaler,intern pc-højtaler +X-KDE-Keywords[de]=Signalton,Systemton,Klänge,Audio,Sound,Dauer,Lautstärke,Höhen,PC-Lautsprecher,Interner Lautsprecher,Lautsprecher,Systemsignalton,System-Lautsprecher,Interner PC-Lautsprecher +X-KDE-Keywords[el]=μεγαφωνάκι,ήχος,ήχος,ένταση,τόνος,διάρκεια,ηχείο PC,εσωτερικό ηχείο,ηχείο,κουδούνι συστήματος,ηχείο συστήματος,εσωτερικό ηχείο PC +X-KDE-Keywords[en_GB]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker +X-KDE-Keywords[es]=Campana,Audio,Sonido,Volumen,Pitch,Duración,Altavoz del PC,Altavoz interno,Altavoz,Campana del sistema,Altavoz del sistema,Altavoz interno del PC +X-KDE-Keywords[et]=Kell,audio,heli,helitugevus,toon,kestus,arvutikõlar,PC kõlar,kõlar,sisemine kõlar,süsteemne piiks,süsteemi piiks,süsteemi kõlar,PC sisemine kõlar +X-KDE-Keywords[eu]=kanpai,audio,soinu,bolumen,tonu,iraupen,PC bozgorailu,barneko bozgorailu,bozgorailu,sistemaren soinu,sistemaren bozgorailu, PC barneko bozgorailu +X-KDE-Keywords[fi]=varoitus,äänimerkki,ääni,äänenvoimakkuus,äänenkorkeus,kesto,PC-kaiutin,sisäinen kaiutin,kaiutin,järjestelmän äänimerkki,järjestelmäkaiutin,sisäinen PC-kaiutin +X-KDE-Keywords[fr]=Cloche, Audio, Son, Volume, Pas, Durée, Haut-parleur du PC, Haut-parleur interne, Haut parleur, Cloche du système, Haut-parleur du système, Haut-parleur interne du PC +X-KDE-Keywords[gl]=Badalada, campá, son, volume, altofalante, badalada do sistema +X-KDE-Keywords[he]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,ספיקר, שמע, משך, פעמון, גובה +X-KDE-Keywords[hu]=Csengő,Audio,Hang,Hangerő,Hangmagasság,Időtartam,PC hangszóró,Belső hangszóró,Hangszóró,Rendszercsengő,Rendszer hangszóró,Belső PC hangszóró +X-KDE-Keywords[ia]=Campana,Audio,Sono,Volumine,Accordatura,Duration,altoparlator de PC,altoparlator interne, Altoparlator,Campana de systema,altoparlator de systema,Altoparlator de PC interne +X-KDE-Keywords[it]=Campanella,Audio,Suono,Volume,Altezza,Durata,Altoparlanti PC,Altoparlanti interni,Altoparlante,Campanella di sistema,Altoparlanti di sistema,Altoparlanti interni pc +X-KDE-Keywords[kk]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker +X-KDE-Keywords[km]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker +X-KDE-Keywords[ko]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,오디오,사운드,음량,시간,스피커 +X-KDE-Keywords[mr]=घंटी, श्राव्य, ध्वनी, आवाज, आवाजाचा स्तर, अवधी, पी.सी.स्पीकर , इंटर्नल स्पीकर, स्पीकर प्रणाली घंटी, प्रणाली स्पीकर, अंतर्गत पी.सी. स्पीकर +X-KDE-Keywords[nb]=Bjelle, Lyd,Lydstyrke,Tone,Varighet,PC-høyttaler,Intern høyttaler,Høyttaler,Systembjelle,Systemhøyttaler, Intern PC-høyttaler +X-KDE-Keywords[nds]=Pingel,Kläng,Klang,Luutstärk,Toonhööchd,Duer,PC-Luutspreker,intern Luutspreker,Luutspreker,Systempingel,System-Luutspreker,intern PC-Luutspreker +X-KDE-Keywords[nl]=Bel,audio,geluid,volume,toonhoogte,duur,PC-speaker,interne speaker,speaker,systeembel,systeemspeaker,interne PC-speaker +X-KDE-Keywords[pl]=Dzwonek,Audio,Dźwięk,Głośność,Ton,Czas trwania +X-KDE-Keywords[pt]=Campainha,Áudio,Som,Volume,Frequência,Duração,Altifalante do PC,Altifalante Interno,Altifalante,Campainha do Sistema,Altifalante do Sistema,Altifalante Interno do PC +X-KDE-Keywords[pt_BR]=Campainha,Áudio,Som,Volume,Frequência,Duração,Alto-falante do PC,Alto-falante interno,Alto-falante,Campainha do sistema,Alto-falante do sistema,Alto-falante interno do PC +X-KDE-Keywords[ru]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,сигнал,аудио,звук,громкость,высота тона,длительность,колонки,динамики,встроенный динамик,сигнал системы,акустическая система,встроенная акустическая система +X-KDE-Keywords[sk]=Zvonček,zvuk,audio,hlasitosť,výška tónu,trvanie,PC speaker,vnútorný reproduktor,speaker,systémový zvonček,systémový reproduktor,vnútorný PC speaker +X-KDE-Keywords[sl]=zvonec,audio,avdio,zvok,glasnost,ton,višina tona,trajanje,zvočnik,notranji zvočnik,sistemski zvonec,sistemski zvočnik,piskanje,notranji PC zvočnik +X-KDE-Keywords[sr]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,звоно,аудио,звук,јачина,висина,трајање,системско звоно,системски звучник,унутрашњи звучник +X-KDE-Keywords[sr@ijekavian]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,звоно,аудио,звук,јачина,висина,трајање,системско звоно,системски звучник,унутрашњи звучник +X-KDE-Keywords[sr@ijekavianlatin]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,zvono,audio,zvuk,jačina,visina,trajanje,sistemsko zvono,sistemski zvučnik,unutrašnji zvučnik +X-KDE-Keywords[sr@latin]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,zvono,audio,zvuk,jačina,visina,trajanje,sistemsko zvono,sistemski zvučnik,unutrašnji zvučnik +X-KDE-Keywords[sv]=Summer,Ljud,Volym,Tonhöjd,Längd,PC-högtalare,Intern högtalare,Högtalare,Systemsummer,Systemhögtalare,Intern PC-högtalare +X-KDE-Keywords[tr]=Zil,Ses,Ses Düzeyi,Akort,Süre,PC Hoparlörü,İç Hoparlör,Hoparlör,Sistem Zili,Sistem Hoparlörü,Dahili PC Hoparlörü +X-KDE-Keywords[uk]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,дзвінок,гудок,звук,гучність,тон,тривалість,гучномовець,колонки,вбудовані колонки,системний дзвінок,вбудований гучномовець +X-KDE-Keywords[vi]=Chuông,âm thanh,âm lượng,thời lượng,loa PC,loa trong,loa,chuông hệ thống,loa hệ thống, loa PC trong +X-KDE-Keywords[x-test]=xxBell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speakerxx +X-KDE-Keywords[zh_CN]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker,铃声,声音,音量,音调,持续时间,PC 扬声器,内部扬声器,扬声器,PC 喇叭,内部喇叭,喇叭,系统铃声,系统扬声器,系统喇叭,内部 PC 扬声器,内部 PC 喇叭 +X-KDE-Keywords[zh_TW]=Bell,Audio,Sound,Volume,Pitch,Duration,PC Speaker,Internal Speaker,Speaker,System Bell,System Speaker,Internal PC Speaker + diff --git a/kcontrol/bell/bell.h b/kcontrol/bell/bell.h new file mode 100644 index 00000000..fda09b55 --- /dev/null +++ b/kcontrol/bell/bell.h @@ -0,0 +1,53 @@ +/* + Copyright (c) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) + 1998 Bernd Wuebben + 2000 Matthias Elter + + 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 __bell_h__ +#define __bell_h__ + +#include "kcmodule.h" + +class QCheckBox; +class KIntNumInput; +class QPushButton; + +class KBellConfig : public KCModule +{ + Q_OBJECT + + public: + KBellConfig(QWidget *parent, const QVariantList &args); + + void load(); + void save(); + void defaults(); + + protected Q_SLOTS: + void ringBell(); + void useBell( bool ); + + private: + QPushButton *m_testButton; + KIntNumInput *m_volume; + KIntNumInput *m_pitch; + KIntNumInput *m_duration; + QCheckBox *m_useBell; +}; + +#endif diff --git a/kcontrol/colors/CMakeLists.txt b/kcontrol/colors/CMakeLists.txt new file mode 100644 index 00000000..9c20d1bc --- /dev/null +++ b/kcontrol/colors/CMakeLists.txt @@ -0,0 +1,16 @@ +KDE4_NO_ENABLE_FINAL(colors) + +set(kcm_colors_PART_SRCS ../krdb/krdb.cpp colorscm.cpp previewwidget.cpp setpreviewwidget.cpp) + +kde4_add_ui_files(kcm_colors_PART_SRCS colorsettings.ui preview.ui setpreview.ui) + +kde4_add_plugin(kcm_colors ${kcm_colors_PART_SRCS}) +target_link_libraries(kcm_colors ${KDE4_KIO_LIBS} ${KDE4_KNEWSTUFF3_LIBS} ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES}) + +install(TARGETS kcm_colors DESTINATION ${PLUGIN_INSTALL_DIR}) +install( FILES colors.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES colorschemes.knsrc DESTINATION ${CONFIG_INSTALL_DIR} ) + +# built-in color schemes +FILE(GLOB schemefiles schemes/*.colors) +install( FILES ${schemefiles} DESTINATION ${DATA_INSTALL_DIR}/color-schemes ) diff --git a/kcontrol/colors/Messages.sh b/kcontrol/colors/Messages.sh new file mode 100644 index 00000000..71fb50be --- /dev/null +++ b/kcontrol/colors/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/kcmcolors.pot +rm -f rc.cpp diff --git a/kcontrol/colors/README.i18n b/kcontrol/colors/README.i18n new file mode 100644 index 00000000..1033fcb9 --- /dev/null +++ b/kcontrol/colors/README.i18n @@ -0,0 +1,54 @@ +There are two sets of preview strings in the color kcm, with special translation needs. In general, length of the translations, and "gist"-level clarity is more important than precise translation. It should be easy to identify what color role a string represents, but there are size considerations that should be taken into account. The tooltips should be translated normally. + + + +When translating the color kcm, it is helpful to understand the intended meaning of the various color roles in order to chose the best possible translation if more than one would be possible. Hopefully the sets (view, window, button, selection, tooltip) are obvious, as well as normal background/foreground. The others are as follows: + +Alternate [Background]: used in lists when every other row uses a different color; "different". +Inactive: comments, something which is old, unimportant/uninteresting/secondary text +Active: e.g. something new, something active (currently engaged in activity), something requesting attention, a hovered hyperlink +Link: hyperlink, somewhere the user can go, new history +Visited: visited hyperlinks, somewhere the user has been, old history +Negative: "bad", untrusted, unreliable, a mistake, an error the user made, an error that occurred +Neutral: warning, encrypted, anything "between" negative and positive +Positive: success, completion messages, trusted content + +For Link, although other uses are possible, translate as referring to hyperlinks to minimize user confusion. + + + +The "generic" preview uses these strings (all with disambiguation "color-kcm-preview"): +- Window Text +- Push Button +- Normal Text +- Selected Text +- link +- visited +- a +- i +- ! +- = +- + + +The two-word strings may be translated normally, though it is suggested to omit the translation of "Text" if the strings would be excessively (around 20+ characters) long and doing so does not cause confusion (i.e. substantially change the conveyed meaning). The "link" and "visited" strings should be translated according to the notes above, ideally keeping the length to four to eight characters; abbreviation (to not less than four characters if possible) is acceptable as the tooltips will provide more complete descriptions. + +The remaining one-character strings represent (respectively) the text roles active (a), inactive (i), negative (!), neutral (=) and positive (+). These should be translated as one- or two-character strings which uniquely correspond to the aforementioned text roles, ideally taking the first letter of the corresponding translation, or maintaining the symbols (!, =, +) as-is if culturally appropriate. + +Ideographic languages (e.g. Japanese, Mandarin, etc.) where the single-character strings can be replaced with one or two characters representing the full word should do so. These should also, if needed, consider a phonetic representation or relevant phrase for the longer elements, to keep the translations close to the same number of characters as the English. + + + +The "set" preview uses these strings (all with disambiguation "color-kcm-set-preview"): +- normal +- link +- visited +- active +- inactive +- alternate +- negative +- neutral +- positive +- hover +- focus + +These live in a preview widget that is two rows tall by nine items wide, and is often the determining factor in the minimum width of the dialog. For this reason, it is important to keep the strings SHORT. To ensure each text block is of sufficient size to provide an adequate preview, each should be at least a few characters long, but please try to limit them to no more than eight or ten characters on average. Abbreviation is fine and encouraged if necessary to achieve this average. In particular, PLEASE avoid adding the translated equivalent of " text" to these strings if at all possible; the tooltips will disambiguate if required. If these objectives cannot be achieved via direct translation, semantic translation (e.g. "negative" -> i18n("oops!"), "neutral" -> i18n("meh")) would be better. (Ideographic languages, which may need to ADD text to achieve a minimum length, should ignore the previous two sentences.) Note also that "hover" and "focus" are actually "decoration" roles, so e.g. "hover text" is incorrect (should be "hover decoration"). diff --git a/kcontrol/colors/TODO b/kcontrol/colors/TODO new file mode 100644 index 00000000..a0695b9f --- /dev/null +++ b/kcontrol/colors/TODO @@ -0,0 +1,3 @@ +query kwin for what WM colors should be shown for configuring(?) +options (i.e. "things on the first tab") not saved in schemes (in kdeglobals only) +sort schemes list, 'current' at 0, 'default' at 1, everything else sorted (possibly kde3-style, user schemes on top?) diff --git a/kcontrol/colors/colors.desktop b/kcontrol/colors/colors.desktop new file mode 100644 index 00000000..b73ee87f --- /dev/null +++ b/kcontrol/colors/colors.desktop @@ -0,0 +1,194 @@ +[Desktop Entry] +Exec=kcmshell4 colors +Icon=preferences-desktop-color +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/colors/index.html + +X-KDE-Library=kcm_colors +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=application-appearance +X-KDE-Weight=60 + +Name=Colors +Name[af]=Kleure +Name[ar]=الألوان +Name[ast]=Colores +Name[be]=Колеры +Name[be@latin]=Kolery +Name[bg]=Цветове +Name[bn]=রং +Name[bn_IN]=রং +Name[br]=Livioù +Name[bs]=Boje +Name[ca]=Colors +Name[ca@valencia]=Colors +Name[cs]=Barvy +Name[csb]=Farwë +Name[cy]=Lliwiau +Name[da]=Farver +Name[de]=Farben +Name[el]=Χρώματα +Name[en_GB]=Colours +Name[eo]=Koloroj +Name[es]=Colores +Name[et]=Värvid +Name[eu]=Koloreak +Name[fa]=رنگها +Name[fi]=Värit +Name[fr]=Couleurs +Name[fy]=Kleuren +Name[ga]=Dathanna +Name[gl]=Cores +Name[gu]=રંગો +Name[he]=צבעים +Name[hi]=रंग +Name[hne]=रंग +Name[hr]=Boje +Name[hsb]=Barby +Name[hu]=Színek +Name[ia]=Colores +Name[id]=Warna +Name[is]=Litir +Name[it]=Colori +Name[ja]=色 +Name[ka]=ცვეტები +Name[kk]=Түстер +Name[km]=ពណ៌ +Name[kn]=ಬಣ್ಣಗಳು +Name[ko]=색 +Name[ku]=Reng +Name[lt]=Spalvos +Name[lv]=Krāsas +Name[mai]=रँग +Name[mk]=Бои +Name[ml]=നിറങ്ങള്‍ +Name[mr]=रंग +Name[ms]=Warna +Name[nb]=Farger +Name[nds]=Klören +Name[ne]=रङ +Name[nl]=Kleuren +Name[nn]=Fargar +Name[oc]=Colors +Name[or]=ରଙ୍ଗ +Name[pa]=ਰੰਗ +Name[pl]=Kolory +Name[pt]=Cores +Name[pt_BR]=Cores +Name[ro]=Culori +Name[ru]=Цвета +Name[se]=Ivnnit +Name[si]=වර්‍ණ +Name[sk]=Farby +Name[sl]=Barve +Name[sr]=Боје +Name[sr@ijekavian]=Боје +Name[sr@ijekavianlatin]=Boje +Name[sr@latin]=Boje +Name[sv]=Färger +Name[ta]=வண்ணங்கள் +Name[te]=రంగులు +Name[tg]=Рангҳо +Name[th]=สี +Name[tr]=Renkler +Name[ug]=رەڭلەر +Name[uk]=Кольори +Name[uz]=Ranglar +Name[uz@cyrillic]=Ранглар +Name[vi]=Màu sắc +Name[wa]=Coleurs +Name[xh]=Imibala +Name[x-test]=xxColorsxx +Name[zh_CN]=颜色 +Name[zh_TW]=顏色 + +Comment=Change the colors used in applications +Comment[bs]=Promjeni boje koristene u aplikaciji +Comment[ca]=Canvia els colors utilitzats en les aplicacions +Comment[ca@valencia]=Canvia els colors utilitzats en les aplicacions +Comment[cs]=Změňte barvy použité v aplikacích +Comment[da]=Ændr de farver der bruges i programmer +Comment[de]=Änderung der von Programmen verwendeten Farben +Comment[el]=Αλλαγή των χρωμάτων που χρησιμοποιούνται στις εφαρμογές +Comment[en_GB]=Change the colours used in applications +Comment[es]=Cambiar los colores que usan las aplicaciones +Comment[et]=Rakendustes kasutatavate värvide muutmine +Comment[eu]=Aldatu aplikazioetan erabiltzen diren koloreak +Comment[fi]=Sovellusten värien asetukset +Comment[gl]=Cambia as cores usadas nos programas +Comment[he]=שנה את הצבעים בשימוש ביישומים +Comment[hu]=Az alkalmazásokban használt színek megváltoztatása +Comment[ia]=Modifica le colores usate in applicationes +Comment[kk]=Қолданбада пайдаланатын түстерін өзгерту +Comment[km]=ផ្លាស់ប្ដូរ​ពណ៌​ដែល​បាន​ប្រើ​ក្នុង​កម្មវិធី +Comment[ko]=프로그램에 사용되는 색을 변경합니다 +Comment[lt]=Keisti spalvas naudojamas programose +Comment[mr]=अनुप्रयोगांत वापरण्यात आलेले रंग बदला +Comment[nb]=Endre fargene som brukes i programmer +Comment[nds]=De Programmklören ännern +Comment[nl]=De in toepassingen gebruikte kleuren wijzigen +Comment[pa]=ਐਪਲੀਕੇਸ਼ਨ ਵਿੱਚ ਵਰਤੇ ਜਾਂਦੇ ਰੰਗ ਬਦਲੋ +Comment[pl]=Zmiana kolorów używanych w programach +Comment[pt]=Mudar as cores usadas nas aplicações +Comment[pt_BR]=Alterar as cores usadas nos aplicativos +Comment[ro]=Schimbă culorile folosite în aplicații +Comment[ru]=Изменение цветов, используемых в приложениях +Comment[sk]=Zmeniť farby použité v aplikáciách +Comment[sl]=Spremenite barve, ki se uporabljajo v programih +Comment[sr]=Промените боје коришћене у програмима +Comment[sr@ijekavian]=Промените боје коришћене у програмима +Comment[sr@ijekavianlatin]=Promenite boje korišćene u programima +Comment[sr@latin]=Promenite boje korišćene u programima +Comment[sv]=Ändra färgerna som används av program +Comment[tr]=Uygulamalarda kullanılacak renkleri yapılandır +Comment[uk]=Зміна кольорів, що використовуються у інтерфейсах програм +Comment[vi]=Thay đổi màu sắc được sử dụng trong các ứng dụng +Comment[x-test]=xxChange the colors used in applicationsxx +Comment[zh_CN]=更改应用程序所使用的颜色 +Comment[zh_TW]=變更用於應用程式的顏色 + +X-KDE-Keywords=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme +X-KDE-Keywords[bs]=boje,boje,tema,kontrast,dodatak bojama,tema u boji,stil boja,tema boja +X-KDE-Keywords[ca]=colors,esquema,contrast,colors d'estris,Esquema de color,estil de color, tema de color +X-KDE-Keywords[ca@valencia]=colors,esquema,contrast,colors d'estris,Esquema de color,estil de color, tema de color +X-KDE-Keywords[da]=farver,tema,kontrast,widget-farver,farvetema,farvestil,farveskema +X-KDE-Keywords[de]=Farben,Schema,Kontrast,Farbschema,Elemente +X-KDE-Keywords[el]=χρώματα,χρώματα,σχήμα,αντίθεση,χρώματα γραφικών συστατικών,χρωματικό σχήμα,χρωματικό στιλ,θέμα χρώματος +X-KDE-Keywords[en_GB]=colours,scheme,contrast,Widget colours,Colour Scheme,colour style,colour theme +X-KDE-Keywords[es]=colores,esquema,contraste,colores de elementos gráficos,Esquema de color,estilo de color,tema de color +X-KDE-Keywords[et]=värv,värvid,skeem,kontrast,vidina värvid,värviskeem,värvistiil,värviteema +X-KDE-Keywords[eu]=kolore,koloreak,eskema,kontraste,trepetaren koloreak,kolore-eskema,kolore-estilo, kolorearen gai +X-KDE-Keywords[fi]=värit,teema,kontrasti,käyttöliittymäelementtien värit,elementtien värit,väriteema,värityyli +X-KDE-Keywords[fr]=couleurs, couleurs, schéma, contraste, couleur des composants graphiques, schéma de couleur, style de couleur, thème de couleur +X-KDE-Keywords[ga]=dathanna,scéim,codarsnacht,dathanna Giuirléidí,Scéim Datha,téama datha +X-KDE-Keywords[gl]=cores,esquema,contraste,cores do widget,esquema de cores, tema de cores +X-KDE-Keywords[hu]=színek,színek,séma,kontraszt,Grafikai elemek színei,Színséma,színstílus,színtéma +X-KDE-Keywords[ia]=colores,colores,schema,contrasto,colores de Widget,Schema de Color,stilo de color, thema de color +X-KDE-Keywords[it]=colori,schema,contrasto,colore degli oggetti,schema di colore,stile colore,tema colore +X-KDE-Keywords[kk]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme +X-KDE-Keywords[km]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme +X-KDE-Keywords[ko]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme,색,색 배열,고대비 +X-KDE-Keywords[mr]=रंग, रंग, योजना, कॉन्ट्रास्ट, विजेट रंग, रंगयोजना, रंगप्रकार, रंगशैली +X-KDE-Keywords[nb]=farger,oppsett,kontrast,elementfarger,fargeoppsett,fargestil,fargetema +X-KDE-Keywords[nds]=Klöör,Klören,Schema,Kontrast,Lüttprogramm-Klören,Klöörschema,Klöörstil,Klöörmuster +X-KDE-Keywords[nl]=colors,colours, kleuren,scheme,schema,contrast,Widget colors,Widgetkleuren,Color Scheme,kleurschema,kleurstijl,kleurthema +X-KDE-Keywords[pl]=kolory,schemat,kontrast,kolory elementów interfejsu,zestaw kolorów,styl kolorów,motyw kolorów +X-KDE-Keywords[pt]=cores,esquema,contraste,cores dos elementos,esquema de cores,estilo de cores,tema de cores +X-KDE-Keywords[pt_BR]=cor,cores,esquema,contraste,Cores do widget,Esquema de cores,estilo de cores,tema de cores +X-KDE-Keywords[ru]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme,цвет,цвета,схема,контраст,цвета виджета,цветовая схема,цветовой стиль,цветовая тема +X-KDE-Keywords[sk]=farba,farby,schéma,kontrast,farby widgetov,Farebná schéma,štýl farieb,téma farieb +X-KDE-Keywords[sl]=barve,shema,tema,kontrast,barve gradnikov,barvna shema,barvna tema,barvni slog +X-KDE-Keywords[sr]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme,боје,шема,контраст,боје виџета,шема боја,стил боја,тема боја +X-KDE-Keywords[sr@ijekavian]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme,боје,шема,контраст,боје виџета,шема боја,стил боја,тема боја +X-KDE-Keywords[sr@ijekavianlatin]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme,boje,šema,kontrast,boje vidžeta,šema boja,stil boja,tema boja +X-KDE-Keywords[sr@latin]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme,boje,šema,kontrast,boje vidžeta,šema boja,stil boja,tema boja +X-KDE-Keywords[sv]=färger,schema,kontrast,Komponentfärger,Färgschema,färgstil,färgtema +X-KDE-Keywords[tr]=renkler,renk,şema,karşıtlık,kontrast,Parçacık renkleri,RenkŞeması,renk biçimi,renk teması +X-KDE-Keywords[uk]=кольори,кольори,схема,контраст,кольори віджетів,схема кольорів,стиль кольорів,тема кольорів,colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme +X-KDE-Keywords[x-test]=xxcolors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color themexx +X-KDE-Keywords[zh_CN]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme,颜色,配色方案,对比度,部件颜色,颜色方案,颜色风格,颜色主题 +X-KDE-Keywords[zh_TW]=colors,colours,scheme,contrast,Widget colors,Color Scheme,color style,color theme + +Categories=Qt;KDE;X-KDE-settings-looknfeel; diff --git a/kcontrol/colors/colorschemes.knsrc b/kcontrol/colors/colorschemes.knsrc new file mode 100644 index 00000000..cc4852d6 --- /dev/null +++ b/kcontrol/colors/colorschemes.knsrc @@ -0,0 +1,6 @@ +[KNewStuff3] +ProvidersUrl=http://download.kde.org/ocs/providers.xml +TargetDir=color-schemes +Uncompress=archive +Categories=KDE Color Scheme KDE4 +UploadCategories=KDE Color Scheme KDE4 diff --git a/kcontrol/colors/colorscm.cpp b/kcontrol/colors/colorscm.cpp new file mode 100644 index 00000000..b9b911f9 --- /dev/null +++ b/kcontrol/colors/colorscm.cpp @@ -0,0 +1,1469 @@ +/* KDE Display color scheme setup module + * Copyright (C) 2007 Matthew Woehlke + * Copyright (C) 2007 Jeremy Whiting + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "colorscm.h" + +#include "../krdb/krdb.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +K_PLUGIN_FACTORY( KolorFactory, registerPlugin(); ) +K_EXPORT_PLUGIN( KolorFactory("kcmcolors") ) + +//BEGIN WindecoColors +KColorCm::WindecoColors::WindecoColors(const KSharedConfigPtr &config) +{ + load(config); +} + +void KColorCm::WindecoColors::load(const KSharedConfigPtr &config) +{ + // NOTE: keep this in sync with kdelibs/kdeui/kernel/kglobalsettings.cpp + KConfigGroup group(config, "WM"); + m_colors[ActiveBackground] = group.readEntry("activeBackground", QColor(48, 174, 232)); + m_colors[ActiveForeground] = group.readEntry("activeForeground", QColor(255, 255, 255)); + m_colors[InactiveBackground] = group.readEntry("inactiveBackground", QColor(224, 223, 222)); + m_colors[InactiveForeground] = group.readEntry("inactiveForeground", QColor(75, 71, 67)); + m_colors[ActiveBlend] = group.readEntry("activeBlend", m_colors[ActiveForeground]); + m_colors[InactiveBlend] = group.readEntry("inactiveBlend", m_colors[InactiveForeground]); +} + +QColor KColorCm::WindecoColors::color(WindecoColors::Role role) const +{ + return m_colors[role]; +} +//END WindecoColors + +KColorCm::KColorCm(QWidget *parent, const QVariantList &) + : KCModule( KolorFactory::componentData(), parent ), m_disableUpdates(false), + m_loadedSchemeHasUnsavedChanges(false), m_dontLoadSelectedScheme(false), + m_previousSchemeItem(0) +{ + KAboutData* about = new KAboutData( + "kcmcolors", 0, ki18n("Colors"), 0, KLocalizedString(), + KAboutData::License_GPL, + ki18n("(c) 2007 Matthew Woehlke") + ); + about->addAuthor( ki18n("Matthew Woehlke"), KLocalizedString(), + "mw_triad@users.sourceforge.net" ); + about->addAuthor( ki18n("Jeremy Whiting"), KLocalizedString(), "jpwhiting@kde.org"); + setAboutData( about ); + + m_config = KSharedConfig::openConfig("kdeglobals"); + + setupUi(this); + schemeKnsButton->setIcon( KIcon("get-hot-new-stuff") ); + schemeKnsUploadButton->setIcon( KIcon("get-hot-new-stuff") ); + connect(colorSet, SIGNAL(currentIndexChanged(int)), this, SLOT(updateColorTable())); + connect(schemeList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(loadScheme(QListWidgetItem*,QListWidgetItem*))); + connect(applyToAlien, SIGNAL(toggled(bool)), this, SLOT(emitChanged())); + + // only needs to be called once + setupColorTable(); +} + +KColorCm::~KColorCm() +{ + m_config->markAsClean(); +} + +void KColorCm::populateSchemeList() +{ + // clear the list in case this is being called from reset button click + schemeList->clear(); + + // add entries + QIcon icon; + const QStringList schemeFiles = KGlobal::dirs()->findAllResources("data", "color-schemes/*.colors", KStandardDirs::NoDuplicates); + for (int i = 0; i < schemeFiles.size(); ++i) + { + // get the file name + const QString filename = schemeFiles.at(i); + const QFileInfo info(filename); + + // add the entry + KSharedConfigPtr config = KSharedConfig::openConfig(filename); + icon = createSchemePreviewIcon(config); + KConfigGroup group(config, "General"); + const QString name = group.readEntry("Name", info.baseName()); + QListWidgetItem * newItem = new QListWidgetItem(icon, name); + // stash the file basename for use later + newItem->setData(Qt::UserRole, info.baseName()); + schemeList->addItem(newItem); + } + schemeList->sortItems(); + + // add default entry (do this here so that the current and default entry appear at the top) + m_config->setReadDefaults(true); + icon = createSchemePreviewIcon(m_config); + schemeList->insertItem(0, new QListWidgetItem(icon, i18nc("Default color scheme", "Default"))); + m_config->setReadDefaults(false); + + // add current scheme entry + icon = createSchemePreviewIcon(m_config); + QListWidgetItem *currentitem = new QListWidgetItem(icon, i18nc("Current color scheme", "Current")); + schemeList->insertItem(0, currentitem); + schemeList->blockSignals(true); // don't emit changed signals + schemeList->setCurrentItem(currentitem); + schemeList->blockSignals(false); +} + +void KColorCm::updatePreviews() +{ + schemePreview->setPalette(m_config); + colorPreview->setPalette(m_config); + setPreview->setPalette(m_config, (KColorScheme::ColorSet)(colorSet->currentIndex() - 1)); + inactivePreview->setPalette(m_config, QPalette::Inactive); + disabledPreview->setPalette(m_config, QPalette::Disabled); +} + +void KColorCm::updateEffectsPage() +{ + m_disableUpdates = true; + + // NOTE: keep this in sync with kdelibs/kdeui/colors/kcolorscheme.cpp + KConfigGroup groupI(m_config, "ColorEffects:Inactive"); + inactiveIntensityBox->setCurrentIndex(abs(groupI.readEntry("IntensityEffect", 0))); + inactiveIntensitySlider->setValue(int(groupI.readEntry("IntensityAmount", 0.0) * 20.0) + 20); + inactiveColorBox->setCurrentIndex(abs(groupI.readEntry("ColorEffect", 2))); + if (inactiveColorBox->currentIndex() > 1) + { + inactiveColorSlider->setValue(int(groupI.readEntry("ColorAmount", 0.025) * 40.0)); + } + else + { + inactiveColorSlider->setValue(int(groupI.readEntry("ColorAmount", 0.05) * 20.0) + 20); + } + inactiveColorButton->setColor(groupI.readEntry("Color", QColor(112, 111, 110))); + inactiveContrastBox->setCurrentIndex(abs(groupI.readEntry("ContrastEffect", 2))); + inactiveContrastSlider->setValue(int(groupI.readEntry("ContrastAmount", 0.1) * 20.0)); + + // NOTE: keep this in sync with kdelibs/kdeui/colors/kcolorscheme.cpp + KConfigGroup groupD(m_config, "ColorEffects:Disabled"); + disabledIntensityBox->setCurrentIndex(groupD.readEntry("IntensityEffect", 2)); + disabledIntensitySlider->setValue(int(groupD.readEntry("IntensityAmount", 0.1) * 20.0) + 20); + disabledColorBox->setCurrentIndex(groupD.readEntry("ColorEffect", 0)); + if (disabledColorBox->currentIndex() > 1) + { + disabledColorSlider->setValue(int(groupD.readEntry("ColorAmount", 0.0) * 40.0)); + } + else + { + disabledColorSlider->setValue(int(groupD.readEntry("ColorAmount", 0.0) * 20.0) + 20); + } + disabledColorButton->setColor(groupD.readEntry("Color", QColor(56, 56, 56))); + disabledContrastBox->setCurrentIndex(groupD.readEntry("ContrastEffect", 1)); + disabledContrastSlider->setValue(int(groupD.readEntry("ContrastAmount", 0.65) * 20.0)); + + m_disableUpdates = false; + + // enable/disable controls + inactiveIntensitySlider->setDisabled(inactiveIntensityBox->currentIndex() == 0); + disabledIntensitySlider->setDisabled(disabledIntensityBox->currentIndex() == 0); + inactiveColorSlider->setDisabled(inactiveColorBox->currentIndex() == 0); + disabledColorSlider->setDisabled(disabledColorBox->currentIndex() == 0); + inactiveColorButton->setDisabled(inactiveColorBox->currentIndex() < 2); + disabledColorButton->setDisabled(disabledColorBox->currentIndex() < 2); + inactiveContrastSlider->setDisabled(inactiveContrastBox->currentIndex() == 0); + disabledContrastSlider->setDisabled(disabledContrastBox->currentIndex() == 0); +} + +void KColorCm::loadScheme(KSharedConfigPtr config) // const QString &path) +{ + KSharedConfigPtr temp = m_config; + m_config = config; + + updateColorSchemes(); + updateEffectsPage(); // intentionally before swapping back m_config + updatePreviews(); + + m_config = temp; + updateFromColorSchemes(); + updateFromEffectsPage(); + updateFromOptions(); + updateColorTable(); + + m_loadedSchemeHasUnsavedChanges = false; + //m_changed = false; +} + +void KColorCm::selectPreviousSchemeAgain() +{ + m_dontLoadSelectedScheme = true; + schemeList->setCurrentItem(m_previousSchemeItem); + m_dontLoadSelectedScheme = false; +} + +void KColorCm::loadScheme(QListWidgetItem *currentItem, QListWidgetItem *previousItem) +{ + m_previousSchemeItem = previousItem; + + if (m_dontLoadSelectedScheme) + { + return; + } + + if (currentItem != NULL) + { + if (m_loadedSchemeHasUnsavedChanges) // if changes made to loaded scheme + { + if (KMessageBox::Continue != KMessageBox::warningContinueCancel(this, + i18n("Selecting another scheme will discard any changes you have made"), + i18n("Are you sure?"), + KStandardGuiItem::cont(), + KStandardGuiItem::cancel(), + "noDiscardWarning")) // if the user decides to cancel + { + QTimer::singleShot(0, this, SLOT(selectPreviousSchemeAgain())); + return; + } + } + + // load it + + const QString name = currentItem->text(); + m_currentColorScheme = name; + const QString fileBaseName = currentItem->data(Qt::UserRole).toString(); + if (name == i18nc("Default color scheme", "Default")) + { + schemeRemoveButton->setEnabled(false); + schemeKnsUploadButton->setEnabled(false); + + KSharedConfigPtr config = m_config; + config->setReadDefaults(true); + loadScheme(config); + config->setReadDefaults(false); + // load the default scheme + emit changed(true); + } + else if (name == i18nc("Current color scheme", "Current")) + { + schemeRemoveButton->setEnabled(false); + schemeKnsUploadButton->setEnabled(false); + loadInternal(false); + } + else + { + const QString path = KGlobal::dirs()->findResource("data", + "color-schemes/" + fileBaseName + ".colors"); + + const int permissions = QFile(path).permissions(); + const bool canWrite = (permissions & QFile::WriteUser); + kDebug() << "checking permissions of " << path; + schemeRemoveButton->setEnabled(canWrite); + schemeKnsUploadButton->setEnabled(true); + + KSharedConfigPtr config = KSharedConfig::openConfig(path); + loadScheme(config); + + emit changed(true); + } + } +} + +void KColorCm::on_schemeRemoveButton_clicked() +{ + if (schemeList->currentItem() != NULL) + { + const QString path = KGlobal::dirs()->findResource("data", + "color-schemes/" + schemeList->currentItem()->data(Qt::UserRole).toString() + + ".colors"); + if (KIO::NetAccess::del(path, this)) + { + delete schemeList->takeItem(schemeList->currentRow()); + } + else + { + // deletion failed, so show an error message + KMessageBox::error(this, i18n("You do not have permission to delete that scheme"), i18n("Error")); + } + } +} + +void KColorCm::on_schemeImportButton_clicked() +{ + // get the path to the scheme to import + KUrl url = KFileDialog::getOpenUrl(KUrl(), QString(), this, i18n("Import Color Scheme")); + + if(url.isValid()) + { + // TODO: possibly untar or uncompress it + // open it + + // load the scheme + KSharedConfigPtr config = KSharedConfig::openConfig(url.path()); + + if (config->groupList().contains("Color Scheme")) + { + if (KMessageBox::Continue != KMessageBox::warningContinueCancel(this, + i18n("The scheme you have selected appears to be a KDE3 scheme.\n\n" + "KDE will attempt to import this scheme, however many color roles have been added since KDE3. " + "Some manual work will likely be required.\n\n" + "This scheme will not be saved automatically."), + i18n("Notice"))) + { + return; + } + + // convert KDE3 scheme to KDE4 scheme + KConfigGroup g(config, "Color Scheme"); + + colorSet->setCurrentIndex(0); + contrastSlider->setValue(g.readEntry("contrast", KGlobalSettings::contrast())); + shadeSortedColumn->setChecked(g.readEntry("shadeSortColumn", KGlobalSettings::shadeSortColumn())); + + m_commonColorButtons[0]->setColor(g.readEntry("windowBackground", m_colorSchemes[KColorScheme::View].background().color())); + m_commonColorButtons[1]->setColor(g.readEntry("windowForeground", m_colorSchemes[KColorScheme::View].foreground().color())); + m_commonColorButtons[2]->setColor(g.readEntry("background", m_colorSchemes[KColorScheme::Window].background().color())); + m_commonColorButtons[3]->setColor(g.readEntry("foreground", m_colorSchemes[KColorScheme::Window].foreground().color())); + m_commonColorButtons[4]->setColor(g.readEntry("buttonBackground", m_colorSchemes[KColorScheme::Button].background().color())); + m_commonColorButtons[5]->setColor(g.readEntry("buttonForeground", m_colorSchemes[KColorScheme::Button].foreground().color())); + m_commonColorButtons[6]->setColor(g.readEntry("selectBackground", m_colorSchemes[KColorScheme::Selection].background().color())); + m_commonColorButtons[7]->setColor(g.readEntry("selectForeground", m_colorSchemes[KColorScheme::Selection].foreground().color())); + m_commonColorButtons[8]->setColor(KColorUtils::mix(m_colorSchemes[KColorScheme::Selection].foreground().color(), + m_colorSchemes[KColorScheme::Selection].background().color())); + m_commonColorButtons[9]->setColor(KColorUtils::mix(m_colorSchemes[KColorScheme::View].foreground().color(), + m_colorSchemes[KColorScheme::View].background().color())); + // doesn't exist in KDE3: 10 ActiveText + m_commonColorButtons[11]->setColor(g.readEntry("linkColor", m_colorSchemes[KColorScheme::View].foreground(KColorScheme::LinkText).color())); + m_commonColorButtons[12]->setColor(g.readEntry("visitedLinkColor", m_colorSchemes[KColorScheme::View].foreground(KColorScheme::VisitedText).color())); + // doesn't exist in KDE3: 13-15 PositiveText, NeutralText, NegativeText + m_commonColorButtons[16]->setColor(g.readEntry("windowForeground", m_colorSchemes[KColorScheme::View].decoration(KColorScheme::FocusColor).color())); + m_commonColorButtons[17]->setColor(g.readEntry("selectBackground", m_colorSchemes[KColorScheme::View].decoration(KColorScheme::HoverColor).color())); + m_commonColorButtons[18]->setColor(g.readEntry("windowBackground", m_colorSchemes[KColorScheme::Tooltip].background().color())); + m_commonColorButtons[19]->setColor(g.readEntry("windowForeground", m_colorSchemes[KColorScheme::Tooltip].foreground().color())); + m_commonColorButtons[20]->setColor(g.readEntry("activeBackground", m_wmColors.color(WindecoColors::ActiveBackground))); + m_commonColorButtons[21]->setColor(g.readEntry("activeForeground", m_wmColors.color(WindecoColors::ActiveForeground))); + m_commonColorButtons[22]->setColor(g.readEntry("activeBlend", m_wmColors.color(WindecoColors::ActiveBlend))); + m_commonColorButtons[23]->setColor(g.readEntry("inactiveBackground", m_wmColors.color(WindecoColors::InactiveBackground))); + m_commonColorButtons[24]->setColor(g.readEntry("inactiveForeground", m_wmColors.color(WindecoColors::InactiveForeground))); + m_commonColorButtons[25]->setColor(g.readEntry("inactiveBlend", m_wmColors.color(WindecoColors::InactiveBlend))); + + colorSet->setCurrentIndex(1); + m_backgroundButtons[KColorScheme::AlternateBackground]->setColor(g.readEntry("alternateBackground", + m_colorSchemes[KColorScheme::View].background(KColorScheme::AlternateBackground).color())); + colorSet->setCurrentIndex(0); + } + else + { + // load KDE4 scheme + loadScheme(config); + + // save it + saveScheme(url.fileName()); + } + } +} + +void KColorCm::on_schemeKnsButton_clicked() +{ + KNS3::DownloadDialog dialog("colorschemes.knsrc", this); + dialog.exec(); + if ( ! dialog.changedEntries().isEmpty() ) + { + populateSchemeList(); + } +} + +void KColorCm::on_schemeKnsUploadButton_clicked() +{ + if (schemeList->currentItem() != NULL) + { + // check if the currently loaded scheme has unsaved changes + if (m_loadedSchemeHasUnsavedChanges) + { + KMessageBox::sorry(this, i18n("Please save the color scheme before uploading it."), + i18n("Please save")); + return; + } + + // find path + const QString basename = schemeList->currentItem()->data(Qt::UserRole).toString(); + const QString path = KGlobal::dirs()->findResource("data", + "color-schemes/" + basename + ".colors"); + if (path.isEmpty() ) // if the color scheme file wasn't found + { + kDebug() << "path for color scheme " << basename << " couldn't be found"; + return; + } + + // upload + KNS3::UploadDialog dialog("colorschemes.knsrc", this); + dialog.setUploadFile(KUrl(path) ); + dialog.exec(); + } +} + +void KColorCm::on_schemeSaveButton_clicked() +{ + QString previousName; + if (schemeList->currentItem() != NULL && schemeList->currentRow() > 1) + { + previousName = schemeList->currentItem()->data(Qt::DisplayRole).toString(); + } + // prompt for the name to save as + bool ok; + QString name = KInputDialog::getText(i18n("Save Color Scheme"), + i18n("&Enter a name for the color scheme:"), previousName, &ok, this); + if (ok) + { + saveScheme(name); + } +} + +void KColorCm::saveScheme(const QString &name) +{ + QString filename = name; + filename.remove('\''); // So Foo's does not become FooS + QRegExp fixer("[\\W,.-]+(.?)"); + int offset; + while ((offset = fixer.indexIn(filename)) >= 0) + filename.replace(offset, fixer.matchedLength(), fixer.cap(1).toUpper()); + filename.replace(0, 1, filename.at(0).toUpper()); + + // check if that name is already in the list + const QString path = KGlobal::dirs()->saveLocation("data", "color-schemes/") + + filename + ".colors"; + + QFile file(path); + const int permissions = file.permissions(); + const bool canWrite = (permissions & QFile::WriteUser); + // or if we can overwrite it if it exists + if (path.isEmpty() || !file.exists() || canWrite) + { + if(canWrite){ + int ret = KMessageBox::questionYesNo(this, + i18n("A color scheme with that name already exists.\nDo you want to overwrite it?"), + i18n("Save Color Scheme"), + KStandardGuiItem::overwrite(), + KStandardGuiItem::cancel()); + //on don't overwrite, select the already existing name. + if(ret == KMessageBox::No){ + QList foundItems = schemeList->findItems(name, Qt::MatchExactly); + if (foundItems.size() == 1) + schemeList->setCurrentRow(schemeList->row(foundItems[0])); + return; + } + } + + // go ahead and save it + QString newpath = KGlobal::dirs()->saveLocation("data", "color-schemes/"); + newpath += filename + ".colors"; + KSharedConfigPtr temp = m_config; + m_config = KSharedConfig::openConfig(newpath); + // then copy current colors into new config + updateFromColorSchemes(); + updateFromEffectsPage(); + KConfigGroup group(m_config, "General"); + group.writeEntry("Name", name); + // sync it + m_config->sync(); + + m_loadedSchemeHasUnsavedChanges = false; + + QList foundItems = schemeList->findItems(name, Qt::MatchExactly); + QIcon icon = createSchemePreviewIcon(m_config); + if (foundItems.size() < 1) + { + // add it to the list since it's not in there already + populateSchemeList(); + + // then select the new item + schemeList->setCurrentItem(schemeList->findItems(name, Qt::MatchExactly).at(0)); + } + else + { + // update the icon of the one that's in the list + foundItems[0]->setIcon(icon); + schemeList->setCurrentRow(schemeList->row(foundItems[0])); + } + + // set m_config back to the system one + m_config = temp; + + // store colorscheme name in global settings + m_currentColorScheme = name; + group = KConfigGroup(m_config, "General"); + group.writeEntry("ColorScheme", m_currentColorScheme); + + emit changed(true); + } + else if (!canWrite && file.exists()) + { + // give error message if !canWrite && file.exists() + KMessageBox::error(this, i18n("You do not have permission to overwrite that scheme"), i18n("Error")); + } +} + +void KColorCm::createColorEntry(const QString &text, const QString &key, QList &list, int index) +{ + KColorButton *button = new KColorButton(this); + button->setObjectName(QString::number(index)); + connect(button, SIGNAL(changed(QColor)), this, SLOT(colorChanged(QColor))); + list.append(button); + + m_colorKeys.insert(index, key); + + QTableWidgetItem *label = new QTableWidgetItem(text); + colorTable->setItem(index, 0, label); + colorTable->setCellWidget(index, 1, button); + colorTable->setRowHeight(index, button->sizeHint().height()); +} + +void KColorCm::variesClicked() +{ + // find which button was changed + const int row = sender()->objectName().toInt(); + + QColor color; + if(KColorDialog::getColor(color, this ) != QDialog::Rejected ) + { + changeColor(row, color); + m_stackedWidgets[row - 9]->setCurrentIndex(0); + } +} + +QPixmap KColorCm::createSchemePreviewIcon(const KSharedConfigPtr &config) +{ + const WindecoColors wm(config); + const uchar bits1[] = { 0xff, 0xff, 0xff, 0x2c, 0x16, 0x0b }; + const uchar bits2[] = { 0x68, 0x34, 0x1a, 0xff, 0xff, 0xff }; + const QSize bitsSize(24,2); + const QBitmap b1 = QBitmap::fromData(bitsSize, bits1); + const QBitmap b2 = QBitmap::fromData(bitsSize, bits2); + + QPixmap pixmap(23, 16); + pixmap.fill(Qt::black); // ### use some color other than black for borders? + + QPainter p(&pixmap); + + KColorScheme windowScheme(QPalette::Active, KColorScheme::Window, config); + p.fillRect( 1, 1, 7, 7, windowScheme.background()); + p.fillRect( 2, 2, 5, 2, QBrush(windowScheme.foreground().color(), b1)); + + KColorScheme buttonScheme(QPalette::Active, KColorScheme::Button, config); + p.fillRect( 8, 1, 7, 7, buttonScheme.background()); + p.fillRect( 9, 2, 5, 2, QBrush(buttonScheme.foreground().color(), b1)); + + p.fillRect(15, 1, 7, 7, wm.color(WindecoColors::ActiveBackground)); + p.fillRect(16, 2, 5, 2, QBrush(wm.color(WindecoColors::ActiveForeground), b1)); + + KColorScheme viewScheme(QPalette::Active, KColorScheme::View, config); + p.fillRect( 1, 8, 7, 7, viewScheme.background()); + p.fillRect( 2, 12, 5, 2, QBrush(viewScheme.foreground().color(), b2)); + + KColorScheme selectionScheme(QPalette::Active, KColorScheme::Selection, config); + p.fillRect( 8, 8, 7, 7, selectionScheme.background()); + p.fillRect( 9, 12, 5, 2, QBrush(selectionScheme.foreground().color(), b2)); + + p.fillRect(15, 8, 7, 7, wm.color(WindecoColors::InactiveBackground)); + p.fillRect(16, 12, 5, 2, QBrush(wm.color(WindecoColors::InactiveForeground), b2)); + + p.end(); + + return pixmap; +} + +void KColorCm::updateColorSchemes() +{ + m_colorSchemes.clear(); + + m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::View, m_config)); + m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Window, m_config)); + m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Button, m_config)); + m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Selection, m_config)); + m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Tooltip, m_config)); + + m_wmColors.load(m_config); +} + +void KColorCm::updateFromColorSchemes() +{ + // store colorscheme name in global settings + KConfigGroup group(m_config, "General"); + group.writeEntry("ColorScheme", m_currentColorScheme); + + for (int i = KColorScheme::View; i <= KColorScheme::Tooltip; ++i) + { + KConfigGroup group(m_config, colorSetGroupKey(i)); + group.writeEntry("BackgroundNormal", m_colorSchemes[i].background(KColorScheme::NormalBackground).color()); + group.writeEntry("BackgroundAlternate", m_colorSchemes[i].background(KColorScheme::AlternateBackground).color()); + group.writeEntry("ForegroundNormal", m_colorSchemes[i].foreground(KColorScheme::NormalText).color()); + group.writeEntry("ForegroundInactive", m_colorSchemes[i].foreground(KColorScheme::InactiveText).color()); + group.writeEntry("ForegroundActive", m_colorSchemes[i].foreground(KColorScheme::ActiveText).color()); + group.writeEntry("ForegroundLink", m_colorSchemes[i].foreground(KColorScheme::LinkText).color()); + group.writeEntry("ForegroundVisited", m_colorSchemes[i].foreground(KColorScheme::VisitedText).color()); + group.writeEntry("ForegroundNegative", m_colorSchemes[i].foreground(KColorScheme::NegativeText).color()); + group.writeEntry("ForegroundNeutral", m_colorSchemes[i].foreground(KColorScheme::NeutralText).color()); + group.writeEntry("ForegroundPositive", m_colorSchemes[i].foreground(KColorScheme::PositiveText).color()); + group.writeEntry("DecorationFocus", m_colorSchemes[i].decoration(KColorScheme::FocusColor).color()); + group.writeEntry("DecorationHover", m_colorSchemes[i].decoration(KColorScheme::HoverColor).color()); + } + + KConfigGroup WMGroup(m_config, "WM"); + WMGroup.writeEntry("activeBackground", m_wmColors.color(WindecoColors::ActiveBackground)); + WMGroup.writeEntry("activeForeground", m_wmColors.color(WindecoColors::ActiveForeground)); + WMGroup.writeEntry("inactiveBackground", m_wmColors.color(WindecoColors::InactiveBackground)); + WMGroup.writeEntry("inactiveForeground", m_wmColors.color(WindecoColors::InactiveForeground)); + WMGroup.writeEntry("activeBlend", m_wmColors.color(WindecoColors::ActiveBlend)); + WMGroup.writeEntry("inactiveBlend", m_wmColors.color(WindecoColors::InactiveBlend)); +} + +void KColorCm::updateFromOptions() +{ + KConfigGroup groupK(m_config, "KDE"); + groupK.writeEntry("contrast", contrastSlider->value()); + + KConfigGroup groupG(m_config, "General"); + groupG.writeEntry("shadeSortColumn", shadeSortedColumn->isChecked()); + + KConfigGroup groupI(m_config, "ColorEffects:Inactive"); + groupI.writeEntry("Enable", useInactiveEffects->isChecked()); + // only write this setting if it is not the default; this way we can change the default more easily in later KDE + // the setting will still written by explicitly checking/unchecking the box + if (inactiveSelectionEffect->isChecked()) + { + groupI.writeEntry("ChangeSelectionColor", true); + } + else + { + groupI.deleteEntry("ChangeSelectionColor"); + } +} + +void KColorCm::updateFromEffectsPage() +{ + if (m_disableUpdates) + { + // don't write the config as we are reading it! + return; + } + + KConfigGroup groupI(m_config, "ColorEffects:Inactive"); + KConfigGroup groupD(m_config, "ColorEffects:Disabled"); + + // intensity + groupI.writeEntry("IntensityEffect", inactiveIntensityBox->currentIndex()); + groupD.writeEntry("IntensityEffect", disabledIntensityBox->currentIndex()); + groupI.writeEntry("IntensityAmount", qreal(inactiveIntensitySlider->value() - 20) * 0.05); + groupD.writeEntry("IntensityAmount", qreal(disabledIntensitySlider->value() - 20) * 0.05); + + // color + groupI.writeEntry("ColorEffect", inactiveColorBox->currentIndex()); + groupD.writeEntry("ColorEffect", disabledColorBox->currentIndex()); + if (inactiveColorBox->currentIndex() > 1) + { + groupI.writeEntry("ColorAmount", qreal(inactiveColorSlider->value()) * 0.025); + } + else + { + groupI.writeEntry("ColorAmount", qreal(inactiveColorSlider->value() - 20) * 0.05); + } + if (disabledColorBox->currentIndex() > 1) + { + groupD.writeEntry("ColorAmount", qreal(disabledColorSlider->value()) * 0.025); + } + else + { + groupD.writeEntry("ColorAmount", qreal(disabledColorSlider->value() - 20) * 0.05); + } + groupI.writeEntry("Color", inactiveColorButton->color()); + groupD.writeEntry("Color", disabledColorButton->color()); + + // contrast + groupI.writeEntry("ContrastEffect", inactiveContrastBox->currentIndex()); + groupD.writeEntry("ContrastEffect", disabledContrastBox->currentIndex()); + groupI.writeEntry("ContrastAmount", qreal(inactiveContrastSlider->value()) * 0.05); + groupD.writeEntry("ContrastAmount", qreal(disabledContrastSlider->value()) * 0.05); + + // enable/disable controls + inactiveIntensitySlider->setDisabled(inactiveIntensityBox->currentIndex() == 0); + disabledIntensitySlider->setDisabled(disabledIntensityBox->currentIndex() == 0); + inactiveColorSlider->setDisabled(inactiveColorBox->currentIndex() == 0); + disabledColorSlider->setDisabled(disabledColorBox->currentIndex() == 0); + inactiveColorButton->setDisabled(inactiveColorBox->currentIndex() < 2); + disabledColorButton->setDisabled(disabledColorBox->currentIndex() < 2); + inactiveContrastSlider->setDisabled(inactiveContrastBox->currentIndex() == 0); + disabledContrastSlider->setDisabled(disabledContrastBox->currentIndex() == 0); +} + +void KColorCm::setupColorTable() +{ + // first setup the common colors table + commonColorTable->verticalHeader()->hide(); + commonColorTable->horizontalHeader()->hide(); + commonColorTable->setShowGrid(false); + commonColorTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); + int minWidth = QPushButton(i18n("Varies")).minimumSizeHint().width(); + commonColorTable->horizontalHeader()->setMinimumSectionSize(minWidth); + commonColorTable->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents); + + for (int i = 0; i < 26; ++i) + { + KColorButton * button = new KColorButton(this); + commonColorTable->setRowHeight(i, button->sizeHint().height()); + button->setObjectName(QString::number(i)); + connect(button, SIGNAL(changed(QColor)), this, SLOT(colorChanged(QColor))); + m_commonColorButtons << button; + + if (i > 8 && i < 18) + { + // Inactive Text row through Positive Text role all need a varies button + KPushButton * variesButton = new KPushButton(NULL); + variesButton->setText(i18n("Varies")); + variesButton->setObjectName(QString::number(i)); + connect(variesButton, SIGNAL(clicked()), this, SLOT(variesClicked())); + + QStackedWidget * widget = new QStackedWidget(this); + widget->addWidget(button); + widget->addWidget(variesButton); + m_stackedWidgets.append(widget); + + commonColorTable->setCellWidget(i, 1, widget); + } + else + { + commonColorTable->setCellWidget(i, 1, button); + } + } + + // then the colorTable that the colorSets will use + colorTable->verticalHeader()->hide(); + colorTable->horizontalHeader()->hide(); + colorTable->setShowGrid(false); + colorTable->setRowCount(12); + colorTable->horizontalHeader()->setMinimumSectionSize(minWidth); + colorTable->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents); + + createColorEntry(i18n("Normal Background"), "BackgroundNormal", m_backgroundButtons, 0); + createColorEntry(i18n("Alternate Background"), "BackgroundAlternate", m_backgroundButtons, 1); + createColorEntry(i18n("Normal Text"), "ForegroundNormal", m_foregroundButtons, 2); + createColorEntry(i18n("Inactive Text"), "ForegroundInactive", m_foregroundButtons, 3); + createColorEntry(i18n("Active Text"), "ForegroundActive", m_foregroundButtons, 4); + createColorEntry(i18n("Link Text"), "ForegroundLink", m_foregroundButtons, 5); + createColorEntry(i18n("Visited Text"), "ForegroundVisited", m_foregroundButtons, 6); + createColorEntry(i18n("Negative Text"), "ForegroundNegative", m_foregroundButtons, 7); + createColorEntry(i18n("Neutral Text"), "ForegroundNeutral", m_foregroundButtons, 8); + createColorEntry(i18n("Positive Text"), "ForegroundPositive", m_foregroundButtons, 9); + createColorEntry(i18n("Focus Decoration"), "DecorationFocus", m_decorationButtons, 10); + createColorEntry(i18n("Hover Decoration"), "DecorationHover", m_decorationButtons, 11); + + colorTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); + colorTable->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents); + + updateColorSchemes(); + updateColorTable(); +} + +void KColorCm::setCommonForeground(KColorScheme::ForegroundRole role, int stackIndex, + int buttonIndex) +{ + QColor color = m_colorSchemes[KColorScheme::View].foreground(role).color(); + for (int i = KColorScheme::Window; i < KColorScheme::Tooltip; ++i) + { + if (i == KColorScheme::Selection && role == KColorScheme::InactiveText) + break; + + if (m_colorSchemes[i].foreground(role).color() != color) + { + m_stackedWidgets[stackIndex]->setCurrentIndex(1); + return; + } + } + + m_stackedWidgets[stackIndex]->setCurrentIndex(0); + m_commonColorButtons[buttonIndex]->setColor(color); + m_loadedSchemeHasUnsavedChanges = true; +} + +void KColorCm::setCommonDecoration(KColorScheme::DecorationRole role, int stackIndex, + int buttonIndex) +{ + QColor color = m_colorSchemes[KColorScheme::View].decoration(role).color(); + for (int i = KColorScheme::Window; i < KColorScheme::Tooltip; ++i) + { + if (m_colorSchemes[i].decoration(role).color() != color) + { + m_stackedWidgets[stackIndex]->setCurrentIndex(1); + return; + } + } + + m_stackedWidgets[stackIndex]->setCurrentIndex(0); + m_commonColorButtons[buttonIndex]->setColor(color); + m_loadedSchemeHasUnsavedChanges = true; +} + +void KColorCm::updateColorTable() +{ + // subtract one here since the 0 item is "Common Colors" + const int currentSet = colorSet->currentIndex() - 1; + + if (currentSet == -1) + { + // common colors is selected + stackColors->setCurrentIndex(0); + stackPreview->setCurrentIndex(0); + + KColorButton * button; + foreach (button, m_commonColorButtons) + { + button->blockSignals(true); + } + + m_commonColorButtons[0]->setColor(m_colorSchemes[KColorScheme::View].background(KColorScheme::NormalBackground).color()); + m_commonColorButtons[1]->setColor(m_colorSchemes[KColorScheme::View].foreground(KColorScheme::NormalText).color()); + m_commonColorButtons[2]->setColor(m_colorSchemes[KColorScheme::Window].background(KColorScheme::NormalBackground).color()); + m_commonColorButtons[3]->setColor(m_colorSchemes[KColorScheme::Window].foreground(KColorScheme::NormalText).color()); + m_commonColorButtons[4]->setColor(m_colorSchemes[KColorScheme::Button].background(KColorScheme::NormalBackground).color()); + m_commonColorButtons[5]->setColor(m_colorSchemes[KColorScheme::Button].foreground(KColorScheme::NormalText).color()); + m_commonColorButtons[6]->setColor(m_colorSchemes[KColorScheme::Selection].background(KColorScheme::NormalBackground).color()); + m_commonColorButtons[7]->setColor(m_colorSchemes[KColorScheme::Selection].foreground(KColorScheme::NormalText).color()); + m_commonColorButtons[8]->setColor(m_colorSchemes[KColorScheme::Selection].foreground(KColorScheme::InactiveText).color()); + + setCommonForeground(KColorScheme::InactiveText, 0, 9); + setCommonForeground(KColorScheme::ActiveText, 1, 10); + setCommonForeground(KColorScheme::LinkText, 2, 11); + setCommonForeground(KColorScheme::VisitedText, 3, 12); + setCommonForeground(KColorScheme::NegativeText, 4, 13); + setCommonForeground(KColorScheme::NeutralText, 5, 14); + setCommonForeground(KColorScheme::PositiveText, 6, 15); + + setCommonDecoration(KColorScheme::FocusColor, 7, 16); + setCommonDecoration(KColorScheme::HoverColor, 8, 17); + + m_commonColorButtons[18]->setColor(m_colorSchemes[KColorScheme::Tooltip].background(KColorScheme::NormalBackground).color()); + m_commonColorButtons[19]->setColor(m_colorSchemes[KColorScheme::Tooltip].foreground(KColorScheme::NormalText).color()); + + m_commonColorButtons[20]->setColor(m_wmColors.color(WindecoColors::ActiveBackground)); + m_commonColorButtons[21]->setColor(m_wmColors.color(WindecoColors::ActiveForeground)); + m_commonColorButtons[22]->setColor(m_wmColors.color(WindecoColors::ActiveBlend)); + m_commonColorButtons[23]->setColor(m_wmColors.color(WindecoColors::InactiveBackground)); + m_commonColorButtons[24]->setColor(m_wmColors.color(WindecoColors::InactiveForeground)); + m_commonColorButtons[25]->setColor(m_wmColors.color(WindecoColors::InactiveBlend)); + + foreach (button, m_commonColorButtons) + { + button->blockSignals(false); + } + } + else + { + // a real color set is selected + setPreview->setPalette(m_config, (KColorScheme::ColorSet)currentSet); + stackColors->setCurrentIndex(1); + stackPreview->setCurrentIndex(1); + + for (int i = KColorScheme::NormalBackground; i <= KColorScheme::AlternateBackground; ++i) + { + m_backgroundButtons[i]->blockSignals(true); + m_backgroundButtons[i]->setColor(m_colorSchemes[currentSet].background(KColorScheme::BackgroundRole(i)).color()); + m_backgroundButtons[i]->blockSignals(false); + } + + for (int i = KColorScheme::NormalText; i <= KColorScheme::PositiveText; ++i) + { + m_foregroundButtons[i]->blockSignals(true); + m_foregroundButtons[i]->setColor(m_colorSchemes[currentSet].foreground(KColorScheme::ForegroundRole(i)).color()); + m_foregroundButtons[i]->blockSignals(false); + } + + for (int i = KColorScheme::FocusColor; i <= KColorScheme::HoverColor; ++i) + { + m_decorationButtons[i]->blockSignals(true); + m_decorationButtons[i]->setColor(m_colorSchemes[currentSet].decoration(KColorScheme::DecorationRole(i)).color()); + m_decorationButtons[i]->blockSignals(false); + } + } +} + +void KColorCm::colorChanged( const QColor &newColor ) +{ + // find which button was changed + const int row = sender()->objectName().toInt(); + changeColor(row, newColor); +} + +void KColorCm::changeColor(int row, const QColor &newColor) +{ + // update the m_colorSchemes for the selected colorSet + const int currentSet = colorSet->currentIndex() - 1; + + if (currentSet == -1) + { + // common colors is selected + switch (row) + { + case 0: + // View Background button + KConfigGroup(m_config, "Colors:View").writeEntry("BackgroundNormal", newColor); + break; + case 1: + // View Text button + KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundNormal", newColor); + break; + case 2: + // Window Background Button + KConfigGroup(m_config, "Colors:Window").writeEntry("BackgroundNormal", newColor); + break; + case 3: + // Window Text Button + KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundNormal", newColor); + break; + case 4: + // Button Background button + KConfigGroup(m_config, "Colors:Button").writeEntry("BackgroundNormal", newColor); + break; + case 5: + // Button Text button + KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundNormal", newColor); + break; + case 6: + // Selection Background Button + KConfigGroup(m_config, "Colors:Selection").writeEntry("BackgroundNormal", newColor); + break; + case 7: + // Selection Text Button + KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNormal", newColor); + break; + case 8: + // Selection Inactive Text Button + KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundInactive", newColor); + break; + + // buttons that could have varies in their place + case 9: + // Inactive Text Button (set all but Selection Inactive Text color) + KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundInactive", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundInactive", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundInactive", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundInactive", newColor); + break; + case 10: + // Active Text Button (set all active text colors) + KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundActive", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundActive", newColor); + KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundActive", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundActive", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundActive", newColor); + break; + case 11: + // Link Text Button (set all link text colors) + KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundLink", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundLink", newColor); + KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundLink", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundLink", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundLink", newColor); + break; + case 12: + // Visited Text Button (set all visited text colors) + KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundVisited", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundVisited", newColor); + KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundVisited", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundVisited", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundVisited", newColor); + break; + case 13: + // Negative Text Button (set all negative text colors) + KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundNegative", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundNegative", newColor); + KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNegative", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundNegative", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundNegative", newColor); + break; + case 14: + // Neutral Text Button (set all neutral text colors) + KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundNeutral", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundNeutral", newColor); + KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNeutral", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundNeutral", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundNeutral", newColor); + break; + case 15: + // Positive Text Button (set all positive text colors) + KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundPositive", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundPositive", newColor); + KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundPositive", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundPositive", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundPositive", newColor); + break; + + case 16: + // Focus Decoration Button (set all focus decoration colors) + KConfigGroup(m_config, "Colors:View").writeEntry("DecorationFocus", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("DecorationFocus", newColor); + KConfigGroup(m_config, "Colors:Selection").writeEntry("DecorationFocus", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("DecorationFocus", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("DecorationFocus", newColor); + break; + case 17: + // Hover Decoration Button (set all hover decoration colors) + KConfigGroup(m_config, "Colors:View").writeEntry("DecorationHover", newColor); + KConfigGroup(m_config, "Colors:Window").writeEntry("DecorationHover", newColor); + KConfigGroup(m_config, "Colors:Selection").writeEntry("DecorationHover", newColor); + KConfigGroup(m_config, "Colors:Button").writeEntry("DecorationHover", newColor); + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("DecorationHover", newColor); + break; + + case 18: + // Tooltip Background button + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("BackgroundNormal", newColor); + break; + case 19: + // Tooltip Text button + KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundNormal", newColor); + break; + case 20: + // Active Title Background + KConfigGroup(m_config, "WM").writeEntry("activeBackground", newColor); + break; + case 21: + // Active Title Text + KConfigGroup(m_config, "WM").writeEntry("activeForeground", newColor); + break; + case 22: + // Active Title Secondary + KConfigGroup(m_config, "WM").writeEntry("activeBlend", newColor); + break; + case 23: + // Inactive Title Background + KConfigGroup(m_config, "WM").writeEntry("inactiveBackground", newColor); + break; + case 24: + // Inactive Title Text + KConfigGroup(m_config, "WM").writeEntry("inactiveForeground", newColor); + break; + case 25: + // Inactive Title Secondary + KConfigGroup(m_config, "WM").writeEntry("inactiveBlend", newColor); + break; + } + m_commonColorButtons[row]->blockSignals(true); + m_commonColorButtons[row]->setColor(newColor); + m_commonColorButtons[row]->blockSignals(false); + } + else + { + QString group = colorSetGroupKey(currentSet); + KConfigGroup(m_config, group).writeEntry(m_colorKeys[row], newColor); + } + + QIcon icon = createSchemePreviewIcon(m_config); + schemeList->item(0)->setIcon(icon); + updateColorSchemes(); + updatePreviews(); + + m_loadedSchemeHasUnsavedChanges = true; + m_currentColorScheme = i18nc("Current color scheme", "Current"); + KConfigGroup group(m_config, "General"); + group.writeEntry("ColorScheme", m_currentColorScheme); + schemeRemoveButton->setEnabled(false); + schemeKnsUploadButton->setEnabled(false); + schemeList->blockSignals(true); // don't emit changed signals + schemeList->setCurrentRow(0); + schemeList->blockSignals(false); + + emit changed(true); +} + +QString KColorCm::colorSetGroupKey(int colorSet) +{ + QString group; + switch (colorSet) { + case KColorScheme::Window: + group = "Colors:Window"; + break; + case KColorScheme::Button: + group = "Colors:Button"; + break; + case KColorScheme::Selection: + group = "Colors:Selection"; + break; + case KColorScheme::Tooltip: + group = "Colors:Tooltip"; + break; + default: + group = "Colors:View"; + } + return group; +} + +void KColorCm::on_contrastSlider_valueChanged(int value) +{ + KConfigGroup group(m_config, "KDE"); + group.writeEntry("contrast", value); + + updatePreviews(); + + emit changed(true); +} + +void KColorCm::on_shadeSortedColumn_stateChanged(int state) +{ + KConfigGroup group(m_config, "General"); + group.writeEntry("shadeSortColumn", bool(state != Qt::Unchecked)); + + emit changed(true); +} + +void KColorCm::on_useInactiveEffects_stateChanged(int state) +{ + KConfigGroup group(m_config, "ColorEffects:Inactive"); + group.writeEntry("Enable", bool(state != Qt::Unchecked)); + + m_disableUpdates = true; + printf("re-init\n"); + inactiveSelectionEffect->setChecked(group.readEntry("ChangeSelectionColor", bool(state != Qt::Unchecked))); + m_disableUpdates = false; + + emit changed(true); +} + +void KColorCm::on_inactiveSelectionEffect_stateChanged(int state) +{ + if (m_disableUpdates) + { + // don't write the config as we are reading it! + return; + } + + KConfigGroup group(m_config, "ColorEffects:Inactive"); + group.writeEntry("ChangeSelectionColor", bool(state != Qt::Unchecked)); + + emit changed(true); +} + +void KColorCm::load() +{ + loadInternal(true); + + // get colorscheme name from global settings + KConfigGroup group(m_config, "General"); + m_currentColorScheme = group.readEntry("ColorScheme"); + if (m_currentColorScheme == i18nc("Current color scheme", "Current")) + { + m_loadedSchemeHasUnsavedChanges = true; + } + QList itemList = schemeList->findItems(m_currentColorScheme, Qt::MatchExactly); + if(!itemList.isEmpty()) // "Current" is already selected, so don't handle the case that itemList is empty + schemeList->setCurrentItem(itemList.at(0)); + + KConfig cfg("kcmdisplayrc", KConfig::NoGlobals); + group = KConfigGroup(&cfg, "X11"); + + applyToAlien->blockSignals(true); // don't emit SIGNAL(toggled(bool)) which would call SLOT(emitChanged()) + applyToAlien->setChecked(group.readEntry("exportKDEColors", true)); + applyToAlien->blockSignals(false); +} + +void KColorCm::loadOptions() +{ + contrastSlider->setValue(KGlobalSettings::contrast()); + shadeSortedColumn->setChecked(KGlobalSettings::shadeSortColumn()); + + KConfigGroup group(m_config, "ColorEffects:Inactive"); + useInactiveEffects->setChecked(group.readEntry("Enable", false)); + // NOTE: keep this in sync with kdelibs/kdeui/colors/kcolorscheme.cpp + // NOTE: remove extra logic from updateFromOptions and on_useInactiveEffects_stateChanged when this changes! + inactiveSelectionEffect->setChecked(group.readEntry("ChangeSelectionColor", group.readEntry("Enable", true))); +} + +void KColorCm::loadInternal(bool loadOptions_) +{ + // clean the config, in case we have changed the in-memory kconfig + m_config->markAsClean(); + m_config->reparseConfiguration(); + + // update the color table + updateColorSchemes(); + updateColorTable(); + + // fill in the color scheme list + populateSchemeList(); + + if (loadOptions_) + loadOptions(); + + updateEffectsPage(); + + updatePreviews(); + + m_loadedSchemeHasUnsavedChanges = false; + + emit changed(false); +} + +void KColorCm::save() +{ + QIcon icon = createSchemePreviewIcon(m_config); + schemeList->item(0)->setIcon(icon); + + KConfigGroup groupI(m_config, "ColorEffects:Inactive"); + + groupI.writeEntry("Enable", useInactiveEffects->isChecked()); + groupI.writeEntry("IntensityEffect", inactiveIntensityBox->currentIndex()); + groupI.writeEntry("ColorEffect", inactiveColorBox->currentIndex()); + groupI.writeEntry("ContrastEffect", inactiveContrastBox->currentIndex()); + + m_config->sync(); + KGlobalSettings::self()->emitChange(KGlobalSettings::PaletteChanged); +#ifdef Q_WS_X11 + // Send signal to all kwin instances + QDBusMessage message = + QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); + QDBusConnection::sessionBus().send(message); +#endif + + KConfig cfg("kcmdisplayrc", KConfig::NoGlobals); + KConfigGroup displayGroup(&cfg, "X11"); + + displayGroup.writeEntry("exportKDEColors", applyToAlien->isChecked()); + cfg.sync(); + + runRdb(KRdbExportQtColors | KRdbExportGtkTheme | ( applyToAlien->isChecked() ? KRdbExportColors : 0 ) ); + + emit changed(false); +} + +void KColorCm::defaults() +{ + // Switch to default scheme + for(int i = 0; i < schemeList->count(); ++i) { + QListWidgetItem *item = schemeList->item(i); + if(item->text() == i18nc("Default color scheme", "Default")) { + // If editing the default scheme, force a reload, else select the default scheme + if(schemeList->currentItem() == item) + loadScheme(item, item); + else + schemeList->setCurrentItem(item); + m_currentColorScheme = item->text(); + break; + } + } + + // Reset options (not part of scheme) + m_config->setReadDefaults(true); + loadOptions(); + m_config->setReadDefaults(false); + applyToAlien->setChecked(Qt::Checked); + + KCModule::defaults(); + emit changed(true); +} + +void KColorCm::emitChanged() +{ + emit changed(true); +} + +// inactive effects slots +void KColorCm::on_inactiveIntensityBox_currentIndexChanged(int index) +{ + Q_UNUSED( index ); + + updateFromEffectsPage(); + inactivePreview->setPalette(m_config, QPalette::Inactive); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_inactiveIntensitySlider_valueChanged(int value) +{ + Q_UNUSED( value ); + + updateFromEffectsPage(); + inactivePreview->setPalette(m_config, QPalette::Inactive); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_inactiveColorBox_currentIndexChanged(int index) +{ + Q_UNUSED( index ); + + updateFromEffectsPage(); + inactivePreview->setPalette(m_config, QPalette::Inactive); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_inactiveColorSlider_valueChanged(int value) +{ + Q_UNUSED( value ); + + updateFromEffectsPage(); + inactivePreview->setPalette(m_config, QPalette::Inactive); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_inactiveColorButton_changed(const QColor& color) +{ + Q_UNUSED( color ); + + updateFromEffectsPage(); + inactivePreview->setPalette(m_config, QPalette::Inactive); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_inactiveContrastBox_currentIndexChanged(int index) +{ + Q_UNUSED( index ); + + updateFromEffectsPage(); + inactivePreview->setPalette(m_config, QPalette::Inactive); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_inactiveContrastSlider_valueChanged(int value) +{ + Q_UNUSED( value ); + + updateFromEffectsPage(); + inactivePreview->setPalette(m_config, QPalette::Inactive); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +// disabled effects slots +void KColorCm::on_disabledIntensityBox_currentIndexChanged(int index) +{ + Q_UNUSED( index ); + + updateFromEffectsPage(); + disabledPreview->setPalette(m_config, QPalette::Disabled); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_disabledIntensitySlider_valueChanged(int value) +{ + Q_UNUSED( value ); + + updateFromEffectsPage(); + disabledPreview->setPalette(m_config, QPalette::Disabled); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_disabledColorBox_currentIndexChanged(int index) +{ + Q_UNUSED( index ); + + updateFromEffectsPage(); + disabledPreview->setPalette(m_config, QPalette::Disabled); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_disabledColorSlider_valueChanged(int value) +{ + Q_UNUSED( value ); + + updateFromEffectsPage(); + disabledPreview->setPalette(m_config, QPalette::Disabled); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_disabledColorButton_changed(const QColor& color) +{ + Q_UNUSED( color ); + + updateFromEffectsPage(); + disabledPreview->setPalette(m_config, QPalette::Disabled); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_disabledContrastBox_currentIndexChanged(int index) +{ + Q_UNUSED( index ); + + updateFromEffectsPage(); + disabledPreview->setPalette(m_config, QPalette::Disabled); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +void KColorCm::on_disabledContrastSlider_valueChanged(int value) +{ + Q_UNUSED( value ); + + updateFromEffectsPage(); + disabledPreview->setPalette(m_config, QPalette::Disabled); + + m_loadedSchemeHasUnsavedChanges = true; + + emit changed(true); +} + +#include "colorscm.moc" diff --git a/kcontrol/colors/colorscm.h b/kcontrol/colors/colorscm.h new file mode 100644 index 00000000..c88567ae --- /dev/null +++ b/kcontrol/colors/colorscm.h @@ -0,0 +1,216 @@ +/* KDE Display color scheme setup module + * Copyright (C) 2007 Matthew Woehlke + * Copyright (C) 2007 Jeremy Whiting + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __COLORSCM_H__ +#define __COLORSCM_H__ + +#include +#include +#include + +#include "ui_colorsettings.h" + +class QStackedWidget; +class QListWidgetItem; + +/** + * The Desktop/Colors tab in kcontrol. + */ +class KColorCm : public KCModule, public Ui::colorSettings +{ + Q_OBJECT + +public: + KColorCm(QWidget *parent, const QVariantList &); + ~KColorCm(); + +public Q_SLOTS: + + /// load the settings from the config + virtual void load(); + + /// save the current settings + virtual void save(); + + /// sets the configuration to sensible default values. + virtual void defaults(); + +private slots: + + /** set the colortable color buttons up according to the current colorset */ + void updateColorTable(); + + /** slot called when color on a KColorButton changes */ + void colorChanged( const QColor &newColor ); + + /** slot called when any varies button is clicked */ + void variesClicked(); + + /** slot called when the schemeList selection changes */ + void loadScheme(QListWidgetItem *currentItem, QListWidgetItem *previousItem); + + /** reselect the previously selected scheme in schemeList without loading it */ + void selectPreviousSchemeAgain(); + + /** slot called when the remove button is clicked*/ + void on_schemeRemoveButton_clicked(); + + /** slot called when the save button is clicked */ + void on_schemeSaveButton_clicked(); + + /** slot called when the import button is clicked */ + void on_schemeImportButton_clicked(); + + /** slot called when the get new schemes button is clicked */ + void on_schemeKnsButton_clicked(); + + /** slot called when the upload scheme button is clicked */ + void on_schemeKnsUploadButton_clicked(); + + /** null slot to emit changed(true) */ + void emitChanged(); + + // options slots + void on_contrastSlider_valueChanged(int value); + void on_shadeSortedColumn_stateChanged(int state); + void on_inactiveSelectionEffect_stateChanged(int state); + void on_useInactiveEffects_stateChanged(int state); + + // effects page slots + void on_inactiveIntensityBox_currentIndexChanged(int index); + void on_inactiveIntensitySlider_valueChanged(int value); + void on_inactiveColorBox_currentIndexChanged(int index); + void on_inactiveColorSlider_valueChanged(int value); + void on_inactiveColorButton_changed(const QColor & color); + void on_inactiveContrastBox_currentIndexChanged(int index); + void on_inactiveContrastSlider_valueChanged(int value); + + void on_disabledIntensityBox_currentIndexChanged(int index); + void on_disabledIntensitySlider_valueChanged(int value); + void on_disabledColorBox_currentIndexChanged(int index); + void on_disabledColorSlider_valueChanged(int value); + void on_disabledColorButton_changed(const QColor & color); + void on_disabledContrastBox_currentIndexChanged(int index); + void on_disabledContrastSlider_valueChanged(int value); + +private: + class WindecoColors { + public: + enum Role { + ActiveForeground = 0, + ActiveBackground = 1, + InactiveForeground = 2, + InactiveBackground = 3, + ActiveBlend = 4, + InactiveBlend = 5 + }; + + WindecoColors() {} + WindecoColors(const KSharedConfigPtr&); + virtual ~WindecoColors() {} + + void load(const KSharedConfigPtr&); + QColor color(Role) const; + private: + QColor m_colors[6]; + }; + + /** create a preview of a color scheme */ + static QPixmap createSchemePreviewIcon(const KSharedConfigPtr &config); + + /** load options from global */ + void loadOptions(); + + /** load from global */ + void loadInternal(bool loadOptions); + + /** load a scheme from a config file at a given path */ + void loadScheme(KSharedConfigPtr config); + + /** populate the schemeList with color schemes found on the system */ + void populateSchemeList(); + + /** update m_colorSchemes contents from the values in m_config */ + void updateColorSchemes(); + + /** update the effects page from the values in m_config */ + void updateEffectsPage(); + + /** update all preview panes from the values in m_config */ + void updatePreviews(); + + /** setup the colortable with its buttons and labels */ + void setupColorTable(); + + /** helper to create color entries */ + void createColorEntry(const QString &text, + const QString &key, + QList &list, + int index); + + /** copy color entries from color schemes into m_config */ + void updateFromColorSchemes(); + + /** copy effects page entries from controls into m_config */ + void updateFromEffectsPage(); + + /** copy options from controls into m_config */ + void updateFromOptions(); + + void changeColor(int row, const QColor &newColor); + + /** get the groupKey for the given colorSet */ + static QString colorSetGroupKey(int colorSet); + + /** save the current scheme with the given name + @param name name to save the scheme as + */ + void saveScheme(const QString &name); + + void setCommonForeground(KColorScheme::ForegroundRole role, + int stackIndex, + int buttonIndex); + void setCommonDecoration(KColorScheme::DecorationRole role, + int stackIndex, + int buttonIndex); + + QList m_backgroundButtons; + QList m_foregroundButtons; + QList m_decorationButtons; + QList m_commonColorButtons; + QList m_stackedWidgets; + QStringList m_colorKeys; + + QList m_colorSchemes; + WindecoColors m_wmColors; + QString m_currentColorScheme; + + KSharedConfigPtr m_config; + + bool m_disableUpdates; + bool m_loadedSchemeHasUnsavedChanges; + // don't (re)load the scheme, only select it in schemeList + bool m_dontLoadSelectedScheme; + + // the item previously selected in schemeList + QListWidgetItem *m_previousSchemeItem; +}; + +#endif diff --git a/kcontrol/colors/colorsettings.ui b/kcontrol/colors/colorsettings.ui new file mode 100644 index 00000000..cbc2e84d --- /dev/null +++ b/kcontrol/colors/colorsettings.ui @@ -0,0 +1,1298 @@ + + + colorSettings + + + + 0 + 0 + 477 + 422 + + + + + 0 + + + + + 0 + + + + &Scheme + + + + + + + 0 + 0 + + + + + 23 + 16 + + + + + + + + + + Get new color schemes from the Internet + + + Get &New Schemes... + + + + + + + false + + + Share the selected scheme on the Internet + + + &Upload Scheme... + + + + + + + Import a color scheme from a file + + + Import Scheme... + + + + + + + Save the current color scheme + + + Save Scheme... + + + + + + + false + + + Remove the selected scheme + + + Remove Scheme + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 0 + + + + Preview + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + + + + + + + + Options + + + + + + Apply inactive window color &effects + + + + + + + In&active selection changes color + + + + + + + Shade sorted column &in lists + + + + + + + true + + + Apply colors to &non-KDE4 applications + + + + + + + Shading of frames and lighting ("3D") effects + + + Shading + + + + 12 + + + 0 + + + + + Minimum + + + + + + + Qt::Horizontal + + + + 198 + 20 + + + + + + + + Maximum + + + + + + + Contrast + + + + + + + 10 + + + 5 + + + Qt::Horizontal + + + + + + + + + + Qt::Vertical + + + + 20 + 141 + + + + + + + + + Colors + + + + + + + 0 + 0 + + + + Color set: + + + + + + + + 0 + 0 + + + + Colorset to view/modify + + + + Common Colors + + + + + View + + + + + Window + + + + + Button + + + + + Selection + + + + + Tooltip + + + + + + + + 0 + + + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + 2 + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + New Row + + + + + 0 + + + + + 1 + + + + + View Background + + + + + View Text + + + + + Window Background + + + + + Window Text + + + + + Button Background + + + + + Button Text + + + + + Selection Background + + + + + Selection Text + + + + + Selection Inactive Text + + + + + Inactive Text + + + + + Active Text + + + + + Link Text + + + + + Visited Text + + + + + Negative Text + + + + + Neutral Text + + + + + Positive Text + + + + + Focus Decoration + + + + + Hover Decoration + + + + + Tooltip Background + + + + + Tooltip Text + + + + + Active Titlebar + + + + + Active Titlebar Text + + + + + Active Titlebar Secondary + + + + + Inactive Titlebar + + + + + Inactive Titlebar Text + + + + + Inactive Titlebar Secondary + + + + + + + + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + 2 + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Preview + + + + + + 0 + + + + + 0 + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + + + + + + + + + + + + Inactive + + + + + + Intensity: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Inactive intensity effect type + + + + None + + + + + Shade + + + + + Darken + + + + + Lighten + + + + + + + + false + + + Inactive intensity effect amount + + + 40 + + + 10 + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 69 + 22 + + + + + + + + Color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Inactive color effect type + + + + None + + + + + Desaturate + + + + + Fade + + + + + Tint + + + + + + + + false + + + Inactive color amount + + + 40 + + + 10 + + + Qt::Horizontal + + + + + + + false + + + Inactive color + + + + + + + Contrast: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Inactive contrast effect type + + + + None + + + + + Fade + + + + + Tint + + + + + + + + false + + + Inactive contrast effect amount + + + 20 + + + 5 + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 69 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + Preview + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + + + + + + + + Disabled + + + + + + Intensity: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Disabled intensity effect type + + + + None + + + + + Shade + + + + + Darken + + + + + Lighten + + + + + + + + false + + + Disabled intensity effect amount + + + 40 + + + 10 + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 69 + 22 + + + + + + + + Color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Disabled color effect type + + + + None + + + + + Desaturate + + + + + Fade + + + + + Tint + + + + + + + + false + + + Disabled color effect amount + + + 40 + + + 10 + + + Qt::Horizontal + + + + + + + false + + + Disabled color + + + + + + + Contrast: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Disabled contrast type + + + + None + + + + + Fade + + + + + Tint + + + + + + + + false + + + Disabled contrast amount + + + 20 + + + 10 + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 69 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + Preview + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + + + + + + + + + + + + KListWidget + QListWidget +
klistwidget.h
+
+ + KPushButton + QPushButton +
kpushbutton.h
+
+ + KColorButton + QPushButton +
kcolorbutton.h
+
+ + PreviewWidget + QWidget +
previewwidget.h
+ 1 +
+ + SetPreviewWidget + QWidget +
setpreviewwidget.h
+ 1 +
+
+ + tabWidget + schemeList + schemeKnsButton + schemeImportButton + schemeSaveButton + schemeRemoveButton + useInactiveEffects + inactiveSelectionEffect + shadeSortedColumn + applyToAlien + contrastSlider + colorSet + commonColorTable + inactiveIntensityBox + inactiveIntensitySlider + inactiveColorBox + inactiveColorSlider + inactiveContrastBox + inactiveContrastSlider + inactiveColorButton + disabledIntensityBox + disabledIntensitySlider + disabledColorBox + disabledColorSlider + disabledContrastBox + disabledContrastSlider + disabledColorButton + colorTable + + + +
diff --git a/kcontrol/colors/preview.ui b/kcontrol/colors/preview.ui new file mode 100644 index 00000000..8dde5c13 --- /dev/null +++ b/kcontrol/colors/preview.ui @@ -0,0 +1,336 @@ + + + preview + + + + 0 + 0 + 467 + 100 + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + Window text on Window Background + + + Window text + + + + + + + true + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 0 + + + 0 + + + + + + 2 + + + + + View Normal Text against View Normal Background + + + Normal text + + + + + + + + true + + + + View Link Text against View Normal Background + + + link + + + + + + + + true + + + + View Visited Text against View Normal Background + + + visited + + + + + + + View Active Text against View Normal Background + + + a + + + + + + + View Inactive Text against View Normal Background + + + i + + + + + + + View Negative Text against View Normal Background + + + ! + + + + + + + View Neutral Text against View Normal Background + + + = + + + + + + + View Positive Text against View Normal Background + + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 4 + 51 + + + + + + + + true + + + + 2 + + + + + Selection Normal Text against Selection Normal Background + + + Selected text + + + + + + + + true + + + + Selection Link Text against Selection Normal Background + + + link + + + + + + + + true + + + + Selection Visited Text against Selection Normal Background + + + visited + + + + + + + Selection Active Text against Selection Normal Background + + + a + + + + + + + Selection Inactive Text against Selection Normal Background + + + i + + + + + + + Selection Negative Text against Selection Normal Background + + + ! + + + + + + + Selection Neutral Text against Selection Normal Background + + + = + + + + + + + Selection Positive Text against Selection Normal Background + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 141 + 0 + + + + + + + + + + + Button text on Button Background + + + Push Button + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 0 + + + + + + + + + diff --git a/kcontrol/colors/previewwidget.cpp b/kcontrol/colors/previewwidget.cpp new file mode 100644 index 00000000..5be7567a --- /dev/null +++ b/kcontrol/colors/previewwidget.cpp @@ -0,0 +1,168 @@ +/* Preview widget for KDE Display color scheme setup module + * Copyright (C) 2007 Matthew Woehlke + * eventFilter code Copyright (C) 2007 Urs Wolfer + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "previewwidget.h" + +#include +#include + +#include + +PreviewWidget::PreviewWidget(QWidget *parent) : QFrame(parent) +{ + setupUi(this); + + // set correct colors on... lots of things + setAutoFillBackground(true); + frame->setBackgroundRole(QPalette::Base); + viewWidget->setBackgroundRole(QPalette::Base); + labelView0->setBackgroundRole(QPalette::Base); + labelView3->setBackgroundRole(QPalette::Base); + labelView4->setBackgroundRole(QPalette::Base); + labelView2->setBackgroundRole(QPalette::Base); + labelView1->setBackgroundRole(QPalette::Base); + labelView5->setBackgroundRole(QPalette::Base); + labelView6->setBackgroundRole(QPalette::Base); + labelView7->setBackgroundRole(QPalette::Base); + selectionWidget->setBackgroundRole(QPalette::Highlight); + labelSelection0->setBackgroundRole(QPalette::Highlight); + labelSelection3->setBackgroundRole(QPalette::Highlight); + labelSelection4->setBackgroundRole(QPalette::Highlight); + labelSelection2->setBackgroundRole(QPalette::Highlight); + labelSelection1->setBackgroundRole(QPalette::Highlight); + labelSelection5->setBackgroundRole(QPalette::Highlight); + labelSelection6->setBackgroundRole(QPalette::Highlight); + labelSelection7->setBackgroundRole(QPalette::Highlight); + + QList widgets = findChildren(); + foreach (QWidget* widget, widgets) + { + widget->installEventFilter(this); + widget->setFocusPolicy(Qt::NoFocus); + } +} + +PreviewWidget::~PreviewWidget() +{ +} + +bool PreviewWidget::eventFilter(QObject *, QEvent *ev) +{ + switch (ev->type()) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::Enter: + case QEvent::Leave: + case QEvent::Wheel: + case QEvent::ContextMenu: + return true; // ignore + default: + break; + } + return false; +} + +inline void copyPaletteBrush(QPalette &palette, QPalette::ColorGroup state, + QPalette::ColorRole role) +{ + palette.setBrush(QPalette::Active, role, palette.brush(state, role)); + if (state == QPalette::Disabled) + // ### hack, while Qt has no inactive+disabled state + // TODO copy from Inactive+Disabled to Inactive instead + palette.setBrush(QPalette::Inactive, role, + palette.brush(QPalette::Disabled, role)); +} + +void PreviewWidget::setPaletteRecursive(QWidget *widget, + const QPalette &palette) +{ + widget->setPalette(palette); + + const QObjectList children = widget->children(); + foreach (QObject *child, children) { + if (child->isWidgetType()) + setPaletteRecursive((QWidget*)child, palette); + } +} + +inline void adjustWidgetForeground(QWidget *widget, QPalette::ColorGroup state, + const KSharedConfigPtr &config, + QPalette::ColorRole color, + KColorScheme::ColorSet set, + KColorScheme::ForegroundRole role) +{ + QPalette palette = widget->palette(); + KColorScheme::adjustForeground(palette, role, color, set, config); + copyPaletteBrush(palette, state, color); + widget->setPalette(palette); +} + +void PreviewWidget::setPalette(const KSharedConfigPtr &config, + QPalette::ColorGroup state) +{ + QPalette palette = KGlobalSettings::createNewApplicationPalette(config); + + if (state != QPalette::Active) { + copyPaletteBrush(palette, state, QPalette::Base); + copyPaletteBrush(palette, state, QPalette::Text); + copyPaletteBrush(palette, state, QPalette::Window); + copyPaletteBrush(palette, state, QPalette::WindowText); + copyPaletteBrush(palette, state, QPalette::Button); + copyPaletteBrush(palette, state, QPalette::ButtonText); + copyPaletteBrush(palette, state, QPalette::Highlight); + copyPaletteBrush(palette, state, QPalette::HighlightedText); + copyPaletteBrush(palette, state, QPalette::AlternateBase); + copyPaletteBrush(palette, state, QPalette::Link); + copyPaletteBrush(palette, state, QPalette::LinkVisited); + copyPaletteBrush(palette, state, QPalette::Light); + copyPaletteBrush(palette, state, QPalette::Midlight); + copyPaletteBrush(palette, state, QPalette::Mid); + copyPaletteBrush(palette, state, QPalette::Dark); + copyPaletteBrush(palette, state, QPalette::Shadow); + } + + setPaletteRecursive(this, palette); + +#define ADJUST_WIDGET_FOREGROUND(w,c,s,r) \ + adjustWidgetForeground(w, state, config, QPalette::c, KColorScheme::s, KColorScheme::r); + + ADJUST_WIDGET_FOREGROUND(labelView1, Text, View, InactiveText); + ADJUST_WIDGET_FOREGROUND(labelView2, Text, View, ActiveText); + ADJUST_WIDGET_FOREGROUND(labelView3, Text, View, LinkText); + ADJUST_WIDGET_FOREGROUND(labelView4, Text, View, VisitedText); + ADJUST_WIDGET_FOREGROUND(labelView5, Text, View, NegativeText); + ADJUST_WIDGET_FOREGROUND(labelView6, Text, View, NeutralText); + ADJUST_WIDGET_FOREGROUND(labelView7, Text, View, PositiveText); + + ADJUST_WIDGET_FOREGROUND(labelSelection1, HighlightedText, Selection, InactiveText); + ADJUST_WIDGET_FOREGROUND(labelSelection2, HighlightedText, Selection, ActiveText); + ADJUST_WIDGET_FOREGROUND(labelSelection3, HighlightedText, Selection, LinkText); + ADJUST_WIDGET_FOREGROUND(labelSelection4, HighlightedText, Selection, VisitedText); + ADJUST_WIDGET_FOREGROUND(labelSelection5, HighlightedText, Selection, NegativeText); + ADJUST_WIDGET_FOREGROUND(labelSelection6, HighlightedText, Selection, NeutralText); + ADJUST_WIDGET_FOREGROUND(labelSelection7, HighlightedText, Selection, PositiveText); +} + +#include "previewwidget.moc" diff --git a/kcontrol/colors/previewwidget.h b/kcontrol/colors/previewwidget.h new file mode 100644 index 00000000..730b2f29 --- /dev/null +++ b/kcontrol/colors/previewwidget.h @@ -0,0 +1,49 @@ +/* Preview widget for KDE Display color scheme setup module + * Copyright (C) 2007 Matthew Woehlke + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __SCHEMEPREVIEW_H__ +#define __SCHEMEPREVIEW_H__ + +#include +#include + +#include + +#include "ui_preview.h" + +/** + * The Desktop/Colors tab in kcontrol. + */ +class PreviewWidget : public QFrame, Ui::preview +{ + Q_OBJECT + +public: + PreviewWidget(QWidget *parent); + virtual ~PreviewWidget(); + + void setPalette(const KSharedConfigPtr &config, + QPalette::ColorGroup state = QPalette::Active); + +protected: + void setPaletteRecursive(QWidget*, const QPalette&); + bool eventFilter(QObject *, QEvent *); +}; + +#endif diff --git a/kcontrol/colors/schemes/Honeycomb.colors b/kcontrol/colors/schemes/Honeycomb.colors new file mode 100644 index 00000000..2db8c570 --- /dev/null +++ b/kcontrol/colors/schemes/Honeycomb.colors @@ -0,0 +1,96 @@ +[ColorEffects:Disabled] +Color=48,43,30 +ColorAmount=0.125 +ColorEffect=2 +ContrastAmount=0.5 +ContrastEffect=1 +IntensityAmount=0.05 +IntensityEffect=0 + +[ColorEffects:Inactive] +Color=227,170,0 +ColorAmount=0.025 +ColorEffect=2 +ContrastAmount=0.25 +ContrastEffect=1 +IntensityAmount=0.05 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=136,138,133 +BackgroundNormal=186,189,183 +DecorationFocus=85,85,85 +DecorationHover=243,195,0 +ForegroundActive=191,92,0 +ForegroundInactive=117,80,25 +ForegroundLink=232,82,144 +ForegroundNegative=191,3,3 +ForegroundNeutral=43,116,199 +ForegroundNormal=0,0,0 +ForegroundPositive=0,137,43 +ForegroundVisited=100,74,155 + +[Colors:Selection] +BackgroundAlternate=243,195,0 +BackgroundNormal=227,170,0 +DecorationFocus=85,85,85 +DecorationHover=243,195,0 +ForegroundActive=191,92,0 +ForegroundInactive=255,235,85 +ForegroundLink=232,82,144 +ForegroundNegative=191,3,3 +ForegroundNeutral=43,116,199 +ForegroundNormal=255,255,255 +ForegroundPositive=0,137,43 +ForegroundVisited=100,74,155 + +[Colors:Tooltip] +BackgroundAlternate=255,235,85 +BackgroundNormal=255,242,153 +DecorationFocus=85,85,85 +DecorationHover=243,195,0 +ForegroundActive=191,92,0 +ForegroundInactive=117,80,25 +ForegroundLink=232,82,144 +ForegroundNegative=191,3,3 +ForegroundNeutral=43,116,199 +ForegroundNormal=64,48,0 +ForegroundPositive=0,137,43 +ForegroundVisited=100,74,155 + +[Colors:View] +BackgroundAlternate=255,251,231 +BackgroundNormal=255,255,255 +DecorationFocus=85,85,85 +DecorationHover=243,195,0 +ForegroundActive=191,92,0 +ForegroundInactive=117,80,25 +ForegroundLink=232,82,144 +ForegroundNegative=191,3,3 +ForegroundNeutral=43,116,199 +ForegroundNormal=0,0,0 +ForegroundPositive=0,137,43 +ForegroundVisited=100,74,155 + +[Colors:Window] +BackgroundAlternate=186,189,183 +BackgroundNormal=212,215,208 +DecorationFocus=85,85,85 +DecorationHover=243,195,0 +ForegroundActive=191,92,0 +ForegroundInactive=117,80,25 +ForegroundLink=232,82,144 +ForegroundNegative=191,3,3 +ForegroundNeutral=43,116,199 +ForegroundNormal=0,0,0 +ForegroundPositive=0,137,43 +ForegroundVisited=100,74,155 + +[General] +Name=Honeycomb + +[WM] +activeBackground=227,170,0 +activeForeground=255,255,255 +inactiveBackground=136,138,133 +inactiveForeground=46,52,54 diff --git a/kcontrol/colors/schemes/Norway.colors b/kcontrol/colors/schemes/Norway.colors new file mode 100644 index 00000000..abf78bcd --- /dev/null +++ b/kcontrol/colors/schemes/Norway.colors @@ -0,0 +1,96 @@ +[ColorEffects:Disabled] +Color=197,179,153 +ColorAmount=0.5 +ColorEffect=2 +ContrastAmount=0.25 +ContrastEffect=1 +IntensityAmount=0.25 +IntensityEffect=0 + +[ColorEffects:Inactive] +Color=213,198,176 +ColorAmount=0.1 +ColorEffect=2 +ContrastAmount=0.25 +ContrastEffect=1 +IntensityAmount=-0.05 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=246,240,227 +BackgroundNormal=247,242,232 +DecorationFocus=128,112,96 +DecorationHover=29,135,205 +ForegroundActive=0,197,204 +ForegroundInactive=197,179,153 +ForegroundLink=0,87,174 +ForegroundNegative=232,87,82 +ForegroundNeutral=227,170,0 +ForegroundNormal=0,0,0 +ForegroundPositive=120,183,83 +ForegroundVisited=100,74,155 + +[Colors:Selection] +BackgroundAlternate=27,131,196 +BackgroundNormal=29,132,205 +DecorationFocus=128,112,96 +DecorationHover=29,135,205 +ForegroundActive=0,197,204 +ForegroundInactive=144,192,232 +ForegroundLink=0,87,174 +ForegroundNegative=232,87,82 +ForegroundNeutral=227,170,0 +ForegroundNormal=255,255,255 +ForegroundPositive=120,183,83 +ForegroundVisited=100,74,155 + +[Colors:Tooltip] +BackgroundAlternate=250,248,241 +BackgroundNormal=253,252,251 +DecorationFocus=128,112,96 +DecorationHover=29,135,205 +ForegroundActive=0,197,204 +ForegroundInactive=197,179,153 +ForegroundLink=0,87,174 +ForegroundNegative=232,87,82 +ForegroundNeutral=227,170,0 +ForegroundNormal=0,0,0 +ForegroundPositive=120,183,83 +ForegroundVisited=100,74,155 + +[Colors:View] +BackgroundAlternate=250,246,239 +BackgroundNormal=253,252,250 +DecorationFocus=128,112,96 +DecorationHover=29,135,205 +ForegroundActive=0,197,204 +ForegroundInactive=197,179,153 +ForegroundLink=0,87,174 +ForegroundNegative=232,87,82 +ForegroundNeutral=227,170,0 +ForegroundNormal=0,0,0 +ForegroundPositive=120,183,83 +ForegroundVisited=100,74,155 + +[Colors:Window] +BackgroundAlternate=233,223,206 +BackgroundNormal=235,226,210 +DecorationFocus=128,112,96 +DecorationHover=29,135,205 +ForegroundActive=0,197,204 +ForegroundInactive=197,179,153 +ForegroundLink=0,87,174 +ForegroundNegative=232,87,82 +ForegroundNeutral=227,170,0 +ForegroundNormal=0,0,0 +ForegroundPositive=120,183,83 +ForegroundVisited=100,74,155 + +[General] +Name=Norway + +[WM] +activeBackground=29,135,205 +activeForeground=255,255,255 +inactiveBackground=128,112,96 +inactiveForeground=253,252,251 diff --git a/kcontrol/colors/schemes/ObsidianCoast.colors b/kcontrol/colors/schemes/ObsidianCoast.colors new file mode 100644 index 00000000..0245ee18 --- /dev/null +++ b/kcontrol/colors/schemes/ObsidianCoast.colors @@ -0,0 +1,95 @@ +[ColorEffects:Disabled] +ColorAmount=-0.8 +ColorEffect=0 +ContrastAmount=0.65 +ContrastEffect=1 +IntensityAmount=0.25 +IntensityEffect=2 + +[ColorEffects:Inactive] +Color=0,0,0 +ColorAmount=0.025 +ColorEffect=2 +ContrastAmount=0.4 +ContrastEffect=2 +IntensityAmount=0 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=66,65,64 +BackgroundNormal=64,63,62 +DecorationFocus=39,94,160 +DecorationHover=87,129,176 +ForegroundActive=150,191,240 +ForegroundInactive=120,119,117 +ForegroundLink=80,142,216 +ForegroundNegative=232,88,72 +ForegroundNeutral=192,162,95 +ForegroundNormal=232,230,227 +ForegroundPositive=120,183,83 +ForegroundVisited=142,121,165 + +[Colors:Selection] +BackgroundAlternate=22,68,120 +BackgroundNormal=24,72,128 +DecorationFocus=39,94,160 +DecorationHover=87,129,176 +ForegroundActive=150,191,240 +ForegroundInactive=81,119,166 +ForegroundLink=80,142,216 +ForegroundNegative=232,88,72 +ForegroundNeutral=192,162,95 +ForegroundNormal=255,255,255 +ForegroundPositive=120,183,83 +ForegroundVisited=142,121,165 + +[Colors:Tooltip] +BackgroundAlternate=17,51,86 +BackgroundNormal=16,48,80 +DecorationFocus=39,94,160 +DecorationHover=87,129,176 +ForegroundActive=150,191,240 +ForegroundInactive=120,119,117 +ForegroundLink=80,142,216 +ForegroundNegative=232,88,72 +ForegroundNeutral=192,162,95 +ForegroundNormal=196,209,224 +ForegroundPositive=120,183,83 +ForegroundVisited=142,121,165 + +[Colors:View] +BackgroundAlternate=36,35,35 +BackgroundNormal=32,31,31 +DecorationFocus=39,94,160 +DecorationHover=87,129,176 +ForegroundActive=150,191,240 +ForegroundInactive=120,119,117 +ForegroundLink=80,142,216 +ForegroundNegative=232,88,72 +ForegroundNeutral=192,162,95 +ForegroundNormal=212,210,207 +ForegroundPositive=120,183,83 +ForegroundVisited=142,121,165 + +[Colors:Window] +BackgroundAlternate=52,51,50 +BackgroundNormal=48,47,47 +DecorationFocus=39,94,160 +DecorationHover=87,129,176 +ForegroundActive=150,191,240 +ForegroundInactive=120,119,117 +ForegroundLink=80,142,216 +ForegroundNegative=232,88,72 +ForegroundNeutral=192,162,95 +ForegroundNormal=224,222,219 +ForegroundPositive=120,183,83 +ForegroundVisited=142,121,165 + +[General] +Name=Obsidian Coast + +[WM] +activeBackground=19,47,80 +activeForeground=255,255,255 +inactiveBackground=64,63,62 +inactiveForeground=128,127,125 diff --git a/kcontrol/colors/schemes/Oxygen.colors b/kcontrol/colors/schemes/Oxygen.colors new file mode 100644 index 00000000..da9116b3 --- /dev/null +++ b/kcontrol/colors/schemes/Oxygen.colors @@ -0,0 +1,103 @@ +[ColorEffects:Disabled] +Color=56,56,56 +ColorAmount=0 +ColorEffect=0 +ContrastAmount=0.65 +ContrastEffect=1 +IntensityAmount=0.1 +IntensityEffect=2 + +[ColorEffects:Inactive] +ChangeSelectionColor=true +Color=112,111,110 +ColorAmount=-0.9 +ColorEffect=1 +ContrastAmount=0.25 +ContrastEffect=2 +Enable=true +IntensityAmount=0 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=224,223,222 +BackgroundNormal=223,220,217 +DecorationFocus=58,167,221 +DecorationHover=110,214,255 +ForegroundActive=146,76,157 +ForegroundInactive=137,136,135 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=34,31,30 +ForegroundPositive=0,110,40 +ForegroundVisited=100,74,155 + +[Colors:Selection] +BackgroundAlternate=62,138,204 +BackgroundNormal=67,172,232 +DecorationFocus=58,167,221 +DecorationHover=110,214,255 +ForegroundActive=108,36,119 +ForegroundInactive=199,226,248 +ForegroundLink=0,49,110 +ForegroundNegative=156,14,14 +ForegroundNeutral=255,221,0 +ForegroundNormal=255,255,255 +ForegroundPositive=128,255,128 +ForegroundVisited=69,40,134 + +[Colors:Tooltip] +BackgroundAlternate=196,224,255 +BackgroundNormal=24,21,19 +DecorationFocus=58,167,221 +DecorationHover=110,214,255 +ForegroundActive=255,128,224 +ForegroundInactive=137,136,135 +ForegroundLink=88,172,255 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=231,253,255 +ForegroundPositive=0,110,40 +ForegroundVisited=150,111,232 + +[Colors:View] +BackgroundAlternate=248,247,246 +BackgroundNormal=255,255,255 +DecorationFocus=58,167,221 +DecorationHover=110,214,255 +ForegroundActive=146,76,157 +ForegroundInactive=137,136,135 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=31,28,27 +ForegroundPositive=0,110,40 +ForegroundVisited=100,74,155 + +[Colors:Window] +BackgroundAlternate=218,217,216 +BackgroundNormal=214,210,208 +DecorationFocus=58,167,221 +DecorationHover=110,214,255 +ForegroundActive=146,76,157 +ForegroundInactive=137,136,135 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=34,31,30 +ForegroundPositive=0,110,40 +ForegroundVisited=100,74,155 + +[General] +ColorScheme=Oxygen +Name=Oxygen +shadeSortColumn=true + +[KDE] +contrast=7 + +[WM] +activeBackground=48,174,232 +activeForeground=255,255,255 +inactiveBackground=224,223,222 +inactiveForeground=75,71,67 diff --git a/kcontrol/colors/schemes/OxygenCold.colors b/kcontrol/colors/schemes/OxygenCold.colors new file mode 100644 index 00000000..53d7777b --- /dev/null +++ b/kcontrol/colors/schemes/OxygenCold.colors @@ -0,0 +1,95 @@ +[ColorEffects:Disabled] +ColorAmount=0 +ColorEffect=0 +ContrastAmount=0.65 +ContrastEffect=1 +IntensityAmount=0.1 +IntensityEffect=2 + +[ColorEffects:Inactive] +Color=112,111,110 +ColorAmount=0.025 +ColorEffect=2 +ContrastAmount=0.1 +ContrastEffect=2 +IntensityAmount=0 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=224,223,222 +BackgroundNormal=232,231,230 +DecorationFocus=43,116,199 +DecorationHover=119,183,255 +ForegroundActive=255,128,224 +ForegroundInactive=136,135,134 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=20,19,18 +ForegroundPositive=0,110,40 +ForegroundVisited=69,40,134 + +[Colors:Selection] +BackgroundAlternate=62,138,204 +BackgroundNormal=65,139,212 +DecorationFocus=43,116,199 +DecorationHover=119,183,255 +ForegroundActive=255,128,224 +ForegroundInactive=165,193,228 +ForegroundLink=0,49,110 +ForegroundNegative=156,14,14 +ForegroundNeutral=255,221,0 +ForegroundNormal=255,255,255 +ForegroundPositive=128,255,128 +ForegroundVisited=69,40,134 + +[Colors:Tooltip] +BackgroundAlternate=196,224,255 +BackgroundNormal=192,218,255 +DecorationFocus=43,116,199 +DecorationHover=119,183,255 +ForegroundActive=255,128,224 +ForegroundInactive=96,112,128 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=20,19,18 +ForegroundPositive=0,110,40 +ForegroundVisited=69,40,134 + +[Colors:View] +BackgroundAlternate=248,247,246 +BackgroundNormal=255,255,255 +DecorationFocus=43,116,199 +DecorationHover=119,183,255 +ForegroundActive=255,128,224 +ForegroundInactive=136,135,134 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=20,19,18 +ForegroundPositive=0,110,40 +ForegroundVisited=69,40,134 + +[Colors:Window] +BackgroundAlternate=218,217,216 +BackgroundNormal=224,223,222 +DecorationFocus=43,116,199 +DecorationHover=119,183,255 +ForegroundActive=255,128,224 +ForegroundInactive=136,135,134 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=20,19,18 +ForegroundPositive=0,110,40 +ForegroundVisited=69,40,134 + +[General] +Name=Oxygen Cold + +[WM] +activeBackground=96,148,207 +activeForeground=255,255,255 +inactiveBackground=224,223,222 +inactiveForeground=20,19,18 diff --git a/kcontrol/colors/schemes/Steel.colors b/kcontrol/colors/schemes/Steel.colors new file mode 100644 index 00000000..3ebd8b4c --- /dev/null +++ b/kcontrol/colors/schemes/Steel.colors @@ -0,0 +1,95 @@ +[ColorEffects:Disabled] +ColorAmount=-0.9 +ColorEffect=0 +ContrastAmount=0.65 +ContrastEffect=1 +IntensityAmount=0.25 +IntensityEffect=2 + +[ColorEffects:Inactive] +Color=135,133,129 +ColorAmount=0.05 +ColorEffect=2 +ContrastAmount=0.25 +ContrastEffect=2 +IntensityAmount=0 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=224,223,216 +BackgroundNormal=232,231,223 +DecorationFocus=69,98,112 +DecorationHover=74,139,163 +ForegroundActive=232,87,82 +ForegroundInactive=148,133,111 +ForegroundLink=41,111,190 +ForegroundNegative=139,83,127 +ForegroundNeutral=191,165,103 +ForegroundNormal=0,0,0 +ForegroundPositive=67,102,46 +ForegroundVisited=100,74,155 + +[Colors:Selection] +BackgroundAlternate=118,154,165 +BackgroundNormal=123,160,173 +DecorationFocus=69,98,112 +DecorationHover=74,139,163 +ForegroundActive=232,87,82 +ForegroundInactive=178,197,204 +ForegroundLink=41,111,190 +ForegroundNegative=139,83,127 +ForegroundNeutral=191,165,103 +ForegroundNormal=255,255,255 +ForegroundPositive=67,102,46 +ForegroundVisited=100,74,155 + +[Colors:Tooltip] +BackgroundAlternate=216,228,231 +BackgroundNormal=219,231,235 +DecorationFocus=69,98,112 +DecorationHover=74,139,163 +ForegroundActive=232,87,82 +ForegroundInactive=148,133,111 +ForegroundLink=41,111,190 +ForegroundNegative=139,83,127 +ForegroundNeutral=191,165,103 +ForegroundNormal=37,34,28 +ForegroundPositive=67,102,46 +ForegroundVisited=100,74,155 + +[Colors:View] +BackgroundAlternate=250,250,248 +BackgroundNormal=255,255,255 +DecorationFocus=69,98,112 +DecorationHover=74,139,163 +ForegroundActive=232,87,82 +ForegroundInactive=148,133,111 +ForegroundLink=41,111,190 +ForegroundNegative=139,83,127 +ForegroundNeutral=191,165,103 +ForegroundNormal=0,0,0 +ForegroundPositive=67,102,46 +ForegroundVisited=100,74,155 + +[Colors:Window] +BackgroundAlternate=212,211,204 +BackgroundNormal=224,223,216 +DecorationFocus=69,98,112 +DecorationHover=74,139,163 +ForegroundActive=232,87,82 +ForegroundInactive=148,133,111 +ForegroundLink=41,111,190 +ForegroundNegative=139,83,127 +ForegroundNeutral=191,165,103 +ForegroundNormal=0,0,0 +ForegroundPositive=67,102,46 +ForegroundVisited=100,74,155 + +[General] +Name=Steel + +[WM] +activeBackground=74,139,163 +activeForeground=255,255,255 +inactiveBackground=208,206,192 +inactiveForeground=100,92,72 diff --git a/kcontrol/colors/schemes/WontonSoup.colors b/kcontrol/colors/schemes/WontonSoup.colors new file mode 100644 index 00000000..34ebaa99 --- /dev/null +++ b/kcontrol/colors/schemes/WontonSoup.colors @@ -0,0 +1,94 @@ +[ColorEffects:Disabled] +ColorAmount=0 +ColorEffect=0 +ContrastAmount=0.65 +ContrastEffect=1 +IntensityAmount=0.25 +IntensityEffect=2 + +[ColorEffects:Inactive] +ColorAmount=0 +ColorEffect=0 +ContrastAmount=0.25 +ContrastEffect=2 +IntensityAmount=0.05 +IntensityEffect=2 + +[Colors:Button] +BackgroundAlternate=90,98,109 +BackgroundNormal=82,88,99 +DecorationFocus=125,141,153 +DecorationHover=119,149,179 +ForegroundActive=255,255,255 +ForegroundInactive=135,143,154 +ForegroundLink=156,212,255 +ForegroundNegative=225,150,209 +ForegroundNeutral=218,198,115 +ForegroundNormal=210,222,240 +ForegroundPositive=145,221,100 +ForegroundVisited=64,128,255 + +[Colors:Selection] +BackgroundAlternate=111,126,144 +BackgroundNormal=120,136,156 +DecorationFocus=125,141,153 +DecorationHover=119,149,179 +ForegroundActive=255,255,255 +ForegroundInactive=174,192,218 +ForegroundLink=156,212,255 +ForegroundNegative=225,150,209 +ForegroundNeutral=218,198,115 +ForegroundNormal=209,225,244 +ForegroundPositive=145,221,100 +ForegroundVisited=64,128,255 + +[Colors:Tooltip] +BackgroundAlternate=171,181,195 +BackgroundNormal=182,193,208 +DecorationFocus=125,141,153 +DecorationHover=119,149,179 +ForegroundActive=255,255,255 +ForegroundInactive=112,118,128 +ForegroundLink=87,161,218 +ForegroundNegative=99,66,92 +ForegroundNeutral=86,78,45 +ForegroundNormal=42,44,48 +ForegroundPositive=57,86,38 +ForegroundVisited=46,95,185 + +[Colors:View] +BackgroundAlternate=67,71,80 +BackgroundNormal=60,64,72 +DecorationFocus=125,141,153 +DecorationHover=119,149,179 +ForegroundActive=255,255,255 +ForegroundInactive=135,143,154 +ForegroundLink=156,212,255 +ForegroundNegative=225,150,209 +ForegroundNeutral=218,198,115 +ForegroundNormal=210,222,240 +ForegroundPositive=145,221,100 +ForegroundVisited=64,128,255 + +[Colors:Window] +BackgroundAlternate=78,83,94 +BackgroundNormal=73,78,88 +DecorationFocus=125,141,153 +DecorationHover=119,149,179 +ForegroundActive=255,255,255 +ForegroundInactive=135,143,154 +ForegroundLink=156,212,255 +ForegroundNegative=225,150,209 +ForegroundNeutral=218,198,115 +ForegroundNormal=182,193,208 +ForegroundPositive=145,221,100 +ForegroundVisited=64,128,255 + +[General] +Name=Wonton Soup + +[WM] +activeBackground=138,151,166 +activeForeground=224,237,255 +inactiveBackground=82,89,99 +inactiveForeground=140,152,168 diff --git a/kcontrol/colors/schemes/Zion.colors b/kcontrol/colors/schemes/Zion.colors new file mode 100644 index 00000000..4427567d --- /dev/null +++ b/kcontrol/colors/schemes/Zion.colors @@ -0,0 +1,96 @@ +[ColorEffects:Disabled] +Color=210,205,218 +ColorAmount=-0.9 +ColorEffect=0 +ContrastAmount=0.65 +ContrastEffect=1 +IntensityAmount=0 +IntensityEffect=0 + +[ColorEffects:Inactive] +Color=0,0,0 +ColorAmount=0.5 +ColorEffect=1 +ContrastAmount=0.25 +ContrastEffect=1 +IntensityAmount=0 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=252,252,252 +BackgroundNormal=255,255,255 +DecorationFocus=128,128,128 +DecorationHover=0,0,0 +ForegroundActive=0,102,255 +ForegroundInactive=112,112,112 +ForegroundLink=0,0,192 +ForegroundNegative=128,0,0 +ForegroundNeutral=112,96,0 +ForegroundNormal=0,0,0 +ForegroundPositive=0,96,0 +ForegroundVisited=88,0,176 + +[Colors:Selection] +BackgroundAlternate=171,188,248 +BackgroundNormal=176,192,255 +DecorationFocus=128,128,128 +DecorationHover=0,0,0 +ForegroundActive=0,102,255 +ForegroundInactive=64,64,192 +ForegroundLink=0,0,192 +ForegroundNegative=128,0,0 +ForegroundNeutral=112,96,0 +ForegroundNormal=0,0,0 +ForegroundPositive=0,96,0 +ForegroundVisited=88,0,176 + +[Colors:Tooltip] +BackgroundAlternate=250,250,250 +BackgroundNormal=255,255,255 +DecorationFocus=128,128,128 +DecorationHover=0,0,0 +ForegroundActive=0,102,255 +ForegroundInactive=112,112,112 +ForegroundLink=0,0,192 +ForegroundNegative=128,0,0 +ForegroundNeutral=112,96,0 +ForegroundNormal=0,0,0 +ForegroundPositive=0,96,0 +ForegroundVisited=88,0,176 + +[Colors:View] +BackgroundAlternate=252,252,252 +BackgroundNormal=255,255,255 +DecorationFocus=128,128,128 +DecorationHover=0,0,0 +ForegroundActive=0,102,255 +ForegroundInactive=112,112,112 +ForegroundLink=0,0,192 +ForegroundNegative=128,0,0 +ForegroundNeutral=112,96,0 +ForegroundNormal=0,0,0 +ForegroundPositive=0,96,0 +ForegroundVisited=88,0,176 + +[Colors:Window] +BackgroundAlternate=248,248,248 +BackgroundNormal=252,252,252 +DecorationFocus=128,128,128 +DecorationHover=0,0,0 +ForegroundActive=0,102,255 +ForegroundInactive=112,112,112 +ForegroundLink=0,0,192 +ForegroundNegative=128,0,0 +ForegroundNeutral=112,96,0 +ForegroundNormal=0,0,0 +ForegroundPositive=0,96,0 +ForegroundVisited=88,0,176 + +[General] +Name=Zion + +[WM] +activeBackground=176,193,255 +activeForeground=0,0,0 +inactiveBackground=255,255,255 +inactiveForeground=0,0,0 diff --git a/kcontrol/colors/schemes/ZionReversed.colors b/kcontrol/colors/schemes/ZionReversed.colors new file mode 100644 index 00000000..36131d4a --- /dev/null +++ b/kcontrol/colors/schemes/ZionReversed.colors @@ -0,0 +1,96 @@ +[ColorEffects:Disabled] +Color=56,56,56 +ColorAmount=0.5 +ColorEffect=2 +ContrastAmount=0.5 +ContrastEffect=1 +IntensityAmount=0.05 +IntensityEffect=0 + +[ColorEffects:Inactive] +Color=0,0,0 +ColorAmount=0.5 +ColorEffect=1 +ContrastAmount=0.25 +ContrastEffect=2 +IntensityAmount=0 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=12,12,12 +BackgroundNormal=0,0,0 +DecorationFocus=192,192,192 +DecorationHover=255,255,255 +ForegroundActive=192,255,255 +ForegroundInactive=160,160,160 +ForegroundLink=128,181,255 +ForegroundNegative=255,128,172 +ForegroundNeutral=255,212,128 +ForegroundNormal=255,255,255 +ForegroundPositive=128,255,128 +ForegroundVisited=192,128,255 + +[Colors:Selection] +BackgroundAlternate=0,52,116 +BackgroundNormal=0,49,110 +DecorationFocus=192,192,192 +DecorationHover=255,255,255 +ForegroundActive=192,255,255 +ForegroundInactive=96,148,207 +ForegroundLink=128,181,255 +ForegroundNegative=255,128,172 +ForegroundNeutral=255,212,128 +ForegroundNormal=255,255,255 +ForegroundPositive=128,255,128 +ForegroundVisited=192,128,255 + +[Colors:Tooltip] +BackgroundAlternate=12,12,12 +BackgroundNormal=0,0,0 +DecorationFocus=192,192,192 +DecorationHover=255,255,255 +ForegroundActive=192,255,255 +ForegroundInactive=160,160,160 +ForegroundLink=128,181,255 +ForegroundNegative=255,128,172 +ForegroundNeutral=255,212,128 +ForegroundNormal=255,255,255 +ForegroundPositive=128,255,128 +ForegroundVisited=192,128,255 + +[Colors:View] +BackgroundAlternate=12,12,12 +BackgroundNormal=0,0,0 +DecorationFocus=192,192,192 +DecorationHover=255,255,255 +ForegroundActive=192,255,255 +ForegroundInactive=160,160,160 +ForegroundLink=128,181,255 +ForegroundNegative=255,128,172 +ForegroundNeutral=255,212,128 +ForegroundNormal=255,255,255 +ForegroundPositive=128,255,128 +ForegroundVisited=192,128,255 + +[Colors:Window] +BackgroundAlternate=20,20,20 +BackgroundNormal=16,16,16 +DecorationFocus=192,192,192 +DecorationHover=255,255,255 +ForegroundActive=192,255,255 +ForegroundInactive=160,160,160 +ForegroundLink=128,181,255 +ForegroundNegative=255,128,172 +ForegroundNeutral=255,212,128 +ForegroundNormal=255,255,255 +ForegroundPositive=128,255,128 +ForegroundVisited=192,128,255 + +[General] +Name=Zion (Reversed) + +[WM] +activeBackground=0,49,110 +activeForeground=255,255,255 +inactiveBackground=64,64,64 +inactiveForeground=128,128,128 diff --git a/kcontrol/colors/setpreview.ui b/kcontrol/colors/setpreview.ui new file mode 100644 index 00000000..09ae55de --- /dev/null +++ b/kcontrol/colors/setpreview.ui @@ -0,0 +1,347 @@ + + + setpreview + + + + 0 + 0 + 550 + 96 + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 0 + + + + + + + + Normal Text on Normal Background + + + normal + + + + + + + + + + + + + + true + + + + Link Text on Normal Background + + + link + + + + + + + + + + + + + + true + + + + Visited Text on Normal Background + + + visited + + + + + + + + + + Active Text on Normal Background + + + + + + active + + + + + + + + + + + + + Inactive Text on Normal Background + + + inactive + + + + + + + + + + + + + Negative Text on Normal Background + + + negative + + + + + + + + + + + + + Neutral Text on Normal Background + + + neutral + + + + + + + + + + + + + Positive Text on Normal Background + + + positive + + + + + + + + + + Hover on Normal Background + + + + + + hover + + + + + + + + + + + + + Normal Text on Normal Background + + + normal + + + + + + + + + + + + + + true + + + + Link Text on Link Background +(Note: Link Background is derived from Link Text and cannot be separately configured at this time) + + + link + + + + + + + + + + + + + + true + + + + Visited Text on Visited Background +(Note: Visited Background is derived from Visited Text and cannot be separately configured at this time) + + + visited + + + + + + + + + + + + + Active Text on Active Background +(Note: Active Background is derived from Active Text and cannot be separately configured at this time) + + + active + + + + + + + + + + + + + Inactive Text on Alternate Background + + + alternate + + + + + + + + + + + + + Negative Text on Negative Background +(Note: Negative Background is derived from Negative Text and cannot be separately configured at this time) + + + negative + + + + + + + + + + + + + Neutral Text on Neutral Background +(Note: Neutral Background is derived from Neutral Text and cannot be separately configured at this time) + + + neutral + + + + + + + + + + + + + Positive Text on Positive Background +(Note: Positive Background is derived from Positive Text and cannot be separately configured at this time) + + + positive + + + + + + + + + + + + + Focus on Normal Background + + + focus + + + + + + + + + + + diff --git a/kcontrol/colors/setpreviewwidget.cpp b/kcontrol/colors/setpreviewwidget.cpp new file mode 100644 index 00000000..98413c55 --- /dev/null +++ b/kcontrol/colors/setpreviewwidget.cpp @@ -0,0 +1,138 @@ +/* Preview widget for KDE Display color scheme setup module + * Copyright (C) 2007 Matthew Woehlke + * eventFilter code Copyright (C) 2007 Urs Wolfer + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "setpreviewwidget.h" + +#include + +void setAutoFill(QWidget* widget) +{ + widget->setAutoFillBackground(true); + widget->setBackgroundRole(QPalette::Base); +} + +SetPreviewWidget::SetPreviewWidget(QWidget *parent) : QFrame(parent) +{ + setupUi(this); + + // set correct colors on... lots of things + setAutoFillBackground(true); + setBackgroundRole(QPalette::Base); + setAutoFill(widgetBack0); + setAutoFill(widgetBack1); + setAutoFill(widgetBack2); + setAutoFill(widgetBack3); + setAutoFill(widgetBack4); + setAutoFill(widgetBack5); + setAutoFill(widgetBack6); + setAutoFill(widgetBack7); + setAutoFillBackground(true); +/* + frame->setBackgroundRole(QPalette::Base); + viewWidget->setBackgroundRole(QPalette::Base); + labelView0->setBackgroundRole(QPalette::Base); + labelView3->setBackgroundRole(QPalette::Base); + labelView4->setBackgroundRole(QPalette::Base); + labelView2->setBackgroundRole(QPalette::Base); + labelView1->setBackgroundRole(QPalette::Base); + labelView5->setBackgroundRole(QPalette::Base); + labelView6->setBackgroundRole(QPalette::Base); + labelView7->setBackgroundRole(QPalette::Base); + selectionWidget->setBackgroundRole(QPalette::Highlight); + labelSelection0->setBackgroundRole(QPalette::Highlight); + labelSelection3->setBackgroundRole(QPalette::Highlight); + labelSelection4->setBackgroundRole(QPalette::Highlight); + labelSelection2->setBackgroundRole(QPalette::Highlight); + labelSelection1->setBackgroundRole(QPalette::Highlight); + labelSelection5->setBackgroundRole(QPalette::Highlight); + labelSelection6->setBackgroundRole(QPalette::Highlight); + labelSelection7->setBackgroundRole(QPalette::Highlight); +*/ + + QList widgets = findChildren(); + foreach (QWidget* widget, widgets) + { + widget->installEventFilter(this); + widget->setFocusPolicy(Qt::NoFocus); + } +} + +SetPreviewWidget::~SetPreviewWidget() +{ +} + +bool SetPreviewWidget::eventFilter(QObject *, QEvent *ev) +{ + switch (ev->type()) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::Enter: + case QEvent::Leave: + case QEvent::Wheel: + case QEvent::ContextMenu: + return true; // ignore + default: + break; + } + return false; +} + +void SetPreviewWidget::setPalette(const KSharedConfigPtr &config, + KColorScheme::ColorSet set) +{ + QPalette palette = KGlobalSettings::createApplicationPalette(config); + KColorScheme::adjustBackground(palette, KColorScheme::NormalBackground, + QPalette::Base, set, config); + QFrame::setPalette(palette); + +#define SET_ROLE_PALETTE(n, f, b) \ + KColorScheme::adjustForeground(palette, KColorScheme::f, QPalette::Text, set, config); \ + labelFore##n->setPalette(palette); \ + KColorScheme::adjustBackground(palette, KColorScheme::b, QPalette::Base, set, config); \ + labelBack##n->setPalette(palette); \ + widgetBack##n->setPalette(palette); + + SET_ROLE_PALETTE(0, NormalText, NormalBackground); + SET_ROLE_PALETTE(1, InactiveText, AlternateBackground); + SET_ROLE_PALETTE(2, ActiveText, ActiveBackground); + SET_ROLE_PALETTE(3, LinkText, LinkBackground); + SET_ROLE_PALETTE(4, VisitedText, VisitedBackground); + SET_ROLE_PALETTE(5, NegativeText, NegativeBackground); + SET_ROLE_PALETTE(6, NeutralText, NeutralBackground); + SET_ROLE_PALETTE(7, PositiveText, PositiveBackground); + + KColorScheme kcs(QPalette::Active, set, config); + QBrush deco; + +#define SET_DECO_PALETTE(n, d) \ + deco = kcs.decoration(KColorScheme::d); \ + palette.setBrush(QPalette::Text, deco); \ + labelFore##n->setPalette(palette); \ + + SET_DECO_PALETTE(8, HoverColor); + SET_DECO_PALETTE(9, FocusColor); +} + +#include "setpreviewwidget.moc" diff --git a/kcontrol/colors/setpreviewwidget.h b/kcontrol/colors/setpreviewwidget.h new file mode 100644 index 00000000..78982a14 --- /dev/null +++ b/kcontrol/colors/setpreviewwidget.h @@ -0,0 +1,49 @@ +/* Colorset Preview widget for KDE Display color scheme setup module + * Copyright (C) 2008 Matthew Woehlke + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __SCHEMEPREVIEWSET_H__ +#define __SCHEMEPREVIEWSET_H__ + +#include +#include + +#include +#include + +#include "ui_setpreview.h" + +/** + * The Desktop/Colors tab in kcontrol. + */ +class SetPreviewWidget : public QFrame, Ui::setpreview +{ + Q_OBJECT + +public: + SetPreviewWidget(QWidget *parent); + virtual ~SetPreviewWidget(); + + void setPalette(const KSharedConfigPtr &config, KColorScheme::ColorSet); + +protected: + void setPaletteRecursive(QWidget*, const QPalette&); + bool eventFilter(QObject *, QEvent *); +}; + +#endif diff --git a/kcontrol/dateandtime/CMakeLists.txt b/kcontrol/dateandtime/CMakeLists.txt new file mode 100644 index 00000000..31a57d9c --- /dev/null +++ b/kcontrol/dateandtime/CMakeLists.txt @@ -0,0 +1,24 @@ +########### next target ############### + +set(kcm_clock_PART_SRCS dtime.cpp main.cpp ) + +kde4_add_ui_files(kcm_clock_PART_SRCS dateandtime.ui) +kde4_add_plugin(kcm_clock ${kcm_clock_PART_SRCS}) + +target_link_libraries(kcm_clock ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS} ) + +install(TARGETS kcm_clock DESTINATION ${PLUGIN_INSTALL_DIR} ) + +########### next target ############### + +kde4_add_executable(kcmdatetimehelper helper.cpp ${helper_mocs}) +target_link_libraries(kcmdatetimehelper ${KDE4_KDECORE_LIBS}) +install(TARGETS kcmdatetimehelper DESTINATION ${LIBEXEC_INSTALL_DIR}) + +kde4_install_auth_helper_files(kcmdatetimehelper org.kde.kcontrol.kcmclock root) + +kde4_install_auth_actions(org.kde.kcontrol.kcmclock kcmclock_actions.actions) + +########### install files ############### + +install( FILES clock.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/kcontrol/dateandtime/Messages.sh b/kcontrol/dateandtime/Messages.sh new file mode 100644 index 00000000..749f1801 --- /dev/null +++ b/kcontrol/dateandtime/Messages.sh @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/kcmkclock.pot diff --git a/kcontrol/dateandtime/clock.desktop b/kcontrol/dateandtime/clock.desktop new file mode 100644 index 00000000..b7b59a7a --- /dev/null +++ b/kcontrol/dateandtime/clock.desktop @@ -0,0 +1,196 @@ +[Desktop Entry] +Exec=kcmshell4 clock +Icon=preferences-system-time +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/clock/index.html + +X-KDE-Library=kcm_clock +X-KDE-ParentApp=kcontrol + +#should this be in system settings when we can get to it through the panel? +#Answer: Yes. +X-KDE-System-Settings-Parent-Category=system-administration + +Name=Date & Time +Name[af]=Datum & Tyd +Name[ar]=التاريخ و الوقت +Name[ast]=Data y hora +Name[be]=Дата і час +Name[be@latin]=Data j čas +Name[bg]=Дата и час +Name[bn]=তারিখ এবং সময় +Name[bn_IN]=তারিখ ও সময় +Name[br]=Deiziad hag eur +Name[bs]=Datum i vrijeme +Name[ca]=Data i hora +Name[ca@valencia]=Data i hora +Name[cs]=Datum a čas +Name[csb]=Datum ë czas +Name[cy]=Dyddiad ac Amser +Name[da]=Dato og tid +Name[de]=Datum & Zeit +Name[el]=Ημερομηνία & Ώρα +Name[en_GB]=Date & Time +Name[eo]=Dato kaj Tempo +Name[es]=Fecha y hora +Name[et]=Kuupäev ja kellaaeg +Name[eu]=Data eta ordua +Name[fa]=تاریخ و زمان +Name[fi]=Aika ja päiväys +Name[fr]=Date et heure +Name[fy]=Datum en Tiid +Name[ga]=Dáta agus Am +Name[gl]=Data e hora +Name[gu]=તારીખ & સમય +Name[he]=תאריך ושעה +Name[hi]=तारीख़ व समय +Name[hne]=तारीक अउ समय +Name[hr]=Datum i vrijeme +Name[hsb]=Datum & čas +Name[hu]=Dátum és idő +Name[ia]=Data & Tempore +Name[id]=Tanggal & Waktu +Name[is]=Dagsetning og tími +Name[it]=Data e ora +Name[ja]=日付と時刻 +Name[ka]=თარიღი და დრო +Name[kk]=Күн мен уақыт +Name[km]=កាល​បរិច្ឆេទ និង​ពេលវេលា +Name[kn]=ದಿನಾಂಕ ಮತ್ತು ಸಮಯ +Name[ko]=날짜와 시간 +Name[ku]=Roj & Dem +Name[lt]=Data ir laikas +Name[lv]=Datums un laiks +Name[mai]=दिनाँक आ समय +Name[mk]=Датум и време +Name[ml]=തീയതിയും സമയവും +Name[mr]=दिनांक व वेळ +Name[ms]=Tarikh & Masa +Name[nb]=Dato og klokkeslett +Name[nds]=Datum & Tiet +Name[ne]=मिति र समय +Name[nl]=Datum en Tijd +Name[nn]=Dato og klokkeslett +Name[oc]=Data e ora +Name[or]=ତାରିଖ ଏବଂ ସମୟ +Name[pa]=ਮਿਤੀ ਅਤੇ ਟਾਈਮ +Name[pl]=Data i czas +Name[pt]=Data e Hora +Name[pt_BR]=Data e hora +Name[ro]=Data și ora +Name[ru]=Дата и время +Name[se]=Dáhton ja áigi +Name[si]=දිනය සහ වේලාව +Name[sk]=Dátum a čas +Name[sl]=Datum in čas +Name[sr]=Датум и време +Name[sr@ijekavian]=Датум и вријеме +Name[sr@ijekavianlatin]=Datum i vrijeme +Name[sr@latin]=Datum i vreme +Name[sv]=Datum och tid +Name[ta]=தேதி & நேரம் +Name[te]=తేది & సమయం +Name[tg]=Сана ва вақт +Name[th]=วันและเวลา +Name[tr]=Tarih ve Saat +Name[ug]=چېسلا & ۋاقىت +Name[uk]=Дата і час +Name[uz]=Sana va vaqt +Name[uz@cyrillic]=Сана ва вақт +Name[vi]=Ngày & giờ +Name[wa]=Date et eure +Name[xh]=Umhla & Ixesha +Name[x-test]=xxDate & Timexx +Name[zh_CN]=日期和时间 +Name[zh_TW]=日期和時間 + +Comment=Configure date and time settings +Comment[bs]=Podesi datum i vrijeme +Comment[ca]=Configuració de l'arranjament de la data i de l'hora +Comment[ca@valencia]=Configuració de l'arranjament de la data i de l'hora +Comment[cs]=Nastavení voleb data a času +Comment[da]=Indstilling af dato og tid +Comment[de]=Einstellungen für Datum und Zeit ändern +Comment[el]=Διαμόρφωση ρυθμίσεων ώρας και ημερομηνίας +Comment[en_GB]=Configure date and time settings +Comment[es]=Configurar las preferencias de fecha y hora +Comment[et]=Kuupäeva ja kellaaja seadistamine +Comment[eu]=Konfiguratu data- eta ordu-ezarpenak +Comment[fi]=Aika-asetukset +Comment[ga]=Cumraigh socruithe dáta agus ama +Comment[gl]=Configurar as opcións da data e hora +Comment[he]=הגדר זמן ותאריך +Comment[hu]=Dátum- és időbeállítások +Comment[ia]=Configura preferentias de data e tempore +Comment[is]=Stilla dagsetningu og tíma +Comment[kk]=Күн мен уақыт параметрлерін баптау +Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​ការ​កំណត់កាលបរិច្ឆេទ និង​ពេលវេលា +Comment[ko]=날짜 및 시간 설정 변경 +Comment[lt]=Konfigūruoti datos ir laiko nustatymus +Comment[mr]=दिनांक व वेळ संयोजीत करा +Comment[nb]=Innstillinger for dato og tid +Comment[nds]=Instellen vun Datum un Tiet fastleggen +Comment[nl]=Instellingen van datum en tijd instellen +Comment[pa]=ਮਿਤੀ ਅਤੇ ਸਮਾਂ ਸੈਟਿੰਗ ਸੰਰਚਨਾ +Comment[pl]=Konfiguruj ustawienia daty i czasu +Comment[pt]=Configuração das opções da data e hora +Comment[pt_BR]=Configuração das opções de data e hora +Comment[ro]=Configurează opțiunile de dată și oră +Comment[ru]=Настройка даты и времени +Comment[sk]=Nastaviť nastavenia dátumu a času +Comment[sl]=Nastavi datum in čas +Comment[sr]=Поставке датума и времена +Comment[sr@ijekavian]=Поставке датума и времена +Comment[sr@ijekavianlatin]=Postavke datuma i vremena +Comment[sr@latin]=Postavke datuma i vremena +Comment[sv]=Anpassa inställningar av datum och tid +Comment[tr]=Tarih ve saat ayarlarını yapılandır +Comment[uk]=Налаштування параметрів дати і часу +Comment[vi]=Cấu hình thiết lập ngày giờ +Comment[x-test]=xxConfigure date and time settingsxx +Comment[zh_CN]=配置日期和时间设置 +Comment[zh_TW]=設定日期與時間 + +X-KDE-Keywords=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time +X-KDE-Keywords[bs]=sat,datum,vrijeme,vremenska zona,ntp,sinkronizirati,kalendar,lokalno vrijeme,regionalno vrijeme +X-KDE-Keywords[ca]=rellotge,data,hora,zona horària,ntp,sincronització,calendari,hora local,hora de la regió +X-KDE-Keywords[ca@valencia]=rellotge,data,hora,zona horària,ntp,sincronització,calendari,hora local,hora de la regió +X-KDE-Keywords[da]=ur,dato,tid,tidszone,ntp,synkroniser,kalender,lokal tid,regional tid +X-KDE-Keywords[de]=Uhr,Datum,Zeit,Zeitzone,ntp,synchronisation,abgleich,Kalender, +X-KDE-Keywords[el]=ρολόι,ημερομηνία,ώρα,ζώνη ώρας,ntp,συγχρονισμός,ημερολόγιο,τοπική ώρα,ώρα περιοχής +X-KDE-Keywords[en_GB]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time +X-KDE-Keywords[es]=reloj,fecha,hora,zona horaria,ntp,sincronizar,calendario,hora local,hora regional +X-KDE-Keywords[et]=kell,kuupäev,kellaaeg,ajavöönd,ntp,sünkroonimine,sünkroniseerimine,kalender,kohalik aeg,vööndiaeg +X-KDE-Keywords[eu]=erloju,data,ordu,ordu-zona,ntp,sinkronizatu,egutegi,ordu lokal,eskualdeko ordu +X-KDE-Keywords[fi]=kello,päivä,päiväys,päivämäärä,aika,aikavyöhyke,ntp,synkronointi,kalenteri,paikallinen aika,alueellinen aika +X-KDE-Keywords[fr]=horloge, date, heure, zone horaire, ntp, synchronisation, calendrier, heure locale, heure régionale +X-KDE-Keywords[gl]=reloxo, data, hora, fuso, fuso horario, ntp, sincronizar, calendario, almanaque, hora local +X-KDE-Keywords[hu]=óra,dátum,idő,időzóna,ntp,szinkronizáció,naptár,helyi idő,régió idő +X-KDE-Keywords[ia]=horologio,data,tempore,fuso horari,ntp,synchronisa,calendario,tempore local,tempore de region +X-KDE-Keywords[it]=orologio,data,ora,fuso orario,ntp,sincronizza,calendario,ora locale,ora regionale +X-KDE-Keywords[kk]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time +X-KDE-Keywords[km]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time +X-KDE-Keywords[ko]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time,시간,날짜,시간대,동기화 +X-KDE-Keywords[mr]=घड्याळ, दिनांक, वेळ, समय क्षेत्र, एन टी पी , सिन्क्रोनाइज़, दिनदर्शिका, स्थानिक वेळ, क्षेत्रीय वेळ +X-KDE-Keywords[nb]=klokke,dato,tid,tidssone,ntp,synkronisere,kalender,lokal tid,regiontid +X-KDE-Keywords[nds]=Klock,Datum,Tiet,Tietrebeet,NTP,synkroniseren,Kalenner,lokaal Tiet +X-KDE-Keywords[nl]=klok,datum,tijd,tijdzone,ntp,synchroniseren,agenda,lokale tijd,tijd in regio +X-KDE-Keywords[pl]=zegar,data,czas,strefa czasowa,ntp,synchronizuj,kalendarz,czas lokalny,czas regionalny +X-KDE-Keywords[pt]=relógio,data,hora,fuso-horário,ntp,sincronizar,calendário,hora local,hora regional +X-KDE-Keywords[pt_BR]=relógio,data,hora,fuso horário,ntp,sincronizar,calendário,hora local,hora regional +X-KDE-Keywords[ru]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time,время,дата,часы,часовой пояс,синхронизировать,календарь,местное время,локальное время,региональное время +X-KDE-Keywords[sk]=hodiny,dátum,čas,časové pásmo,ntp,synchronizácia,kalendár,miestny čas,regionálny čas +X-KDE-Keywords[sl]=ura,datum,čas,časovni pas,ntp,uskladitev,koledar,krajevni čas,območni čas +X-KDE-Keywords[sr]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time,сат,часовник,датум,време,временска зона,НТП,синхронизовати,календар,локално време +X-KDE-Keywords[sr@ijekavian]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time,сат,часовник,датум,време,временска зона,НТП,синхронизовати,календар,локално време +X-KDE-Keywords[sr@ijekavianlatin]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time,sat,časovnik,datum,vreme,vremenska zona,NTP,sinhronizovati,kalendar,lokalno vreme +X-KDE-Keywords[sr@latin]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time,sat,časovnik,datum,vreme,vremenska zona,NTP,sinhronizovati,kalendar,lokalno vreme +X-KDE-Keywords[sv]=klocka,datum,tid,tidszon,ntp,synkronisera,kalender,lokal tid,områdestid +X-KDE-Keywords[tr]=saat,tarih,zaman,zaman dilimi,ntp,eşzamanlama,takvim,yerel saat,bölge saati +X-KDE-Keywords[uk]=годинник,дата,час,часовий пояс,синхронізація,календар,місцевий час,clock,date,time,time zone,ntp,synchronize,calendar,local time,region time +X-KDE-Keywords[x-test]=xxclock,date,time,time zone,ntp,synchronize,calendar,local time,region timexx +X-KDE-Keywords[zh_CN]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time,时钟,日期,时间,时区,同步,日历,本地时间,区域时间 +X-KDE-Keywords[zh_TW]=clock,date,time,time zone,ntp,synchronize,calendar,local time,region time + +Categories=Qt;KDE;X-KDE-settings-system; diff --git a/kcontrol/dateandtime/dateandtime.ui b/kcontrol/dateandtime/dateandtime.ui new file mode 100644 index 00000000..ec3cd727 --- /dev/null +++ b/kcontrol/dateandtime/dateandtime.ui @@ -0,0 +1,198 @@ + + + Davide Bettio <davide.bettio@kdemail.net> + DateAndTime + + + + 0 + 0 + 613 + 463 + + + + + + + 0 + + + + Date and Time + + + + + + + + Set date and time &automatically: + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 13 + 21 + + + + + + + + Time server: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + timeServerList + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + Here you can change the system date's day of the month, month and year. + + + + + + + + 0 + 0 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Time Zone + + + + + + To change the local time zone, select your area from the list below. + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + Current local time zone: + + + + + + + true + + + Search + + + + + + + + + + + + + + + + KTimeZoneWidget + QTreeWidget +
ktimezonewidget.h
+
+ + KTreeWidgetSearchLine + KLineEdit +
ktreewidgetsearchline.h
+
+ + KLineEdit + QLineEdit +
klineedit.h
+
+ + KSeparator + QFrame +
kseparator.h
+
+ + KDatePicker + QFrame +
kdatepicker.h
+
+
+ + +
diff --git a/kcontrol/dateandtime/dtime.cpp b/kcontrol/dateandtime/dtime.cpp new file mode 100644 index 00000000..68485bb6 --- /dev/null +++ b/kcontrol/dateandtime/dtime.cpp @@ -0,0 +1,463 @@ +/* + * dtime.cpp + * + * Copyright (C) 1998 Luca Montecchiani + * + * Plasma analog-clock drawing code: + * + * Copyright 2007 by Aaron Seigo + * Copyright 2007 by Riccardo Iaconelli + * + * 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 "dtime.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dtime.moc" + +#include "helper.h" + +Dtime::Dtime(QWidget * parent) + : QWidget(parent) +{ + KGlobal::locale()->insertCatalog( "timezones4" ); + setupUi(this); + + connect(setDateTimeAuto, SIGNAL(toggled(bool)), this, SLOT(serverTimeCheck())); + connect(setDateTimeAuto, SIGNAL(toggled(bool)), SLOT(configChanged())); + + timeServerList->setEditable(false); + connect(timeServerList, SIGNAL(activated(int)), SLOT(configChanged())); + connect(timeServerList, SIGNAL(editTextChanged(QString)), SLOT(configChanged())); + connect(setDateTimeAuto, SIGNAL(toggled(bool)), timeServerList, SLOT(setEnabled(bool))); + timeServerList->setEnabled(false); + timeServerList->setEditable(true); + findNTPutility(); + if (ntpUtility.isEmpty()) { + setDateTimeAuto->setEnabled(false); + setDateTimeAuto->setToolTip(i18n("No NTP utility has been found. " + "Install 'ntpdate' or 'rdate' command to enable automatic " + "updating of date and time.")); + } + + QVBoxLayout *v2 = new QVBoxLayout( timeBox ); + v2->setMargin( 0 ); + + kclock = new Kclock( timeBox ); + kclock->setObjectName("Kclock"); + kclock->setMinimumSize(150,150); + v2->addWidget( kclock ); + + v2->addSpacing( KDialog::spacingHint() ); + + QHBoxLayout *v3 = new QHBoxLayout( ); + v2->addLayout( v3 ); + + v3->addStretch(); + + timeEdit = new QTimeEdit( timeBox ); + timeEdit->setWrapping(true); + timeEdit->setDisplayFormat(KGlobal::locale()->use12Clock() ? "hh:mm:ss ap" : "HH:mm:ss"); + v3->addWidget(timeEdit); + + v3->addStretch(); + + QString wtstr = i18n("Here you can change the system time. Click into the" + " hours, minutes or seconds field to change the relevant value, either" + " using the up and down buttons to the right or by entering a new value."); + timeEdit->setWhatsThis( wtstr ); + + connect( timeEdit, SIGNAL(timeChanged(QTime)), SLOT(set_time()) ); + connect( cal, SIGNAL(dateChanged(QDate)), SLOT(changeDate(QDate))); + + connect( &internalTimer, SIGNAL(timeout()), SLOT(timeout()) ); + + kclock->setEnabled(false); + + //Timezone + connect( tzonelist, SIGNAL(itemSelectionChanged()), SLOT(configChanged()) ); + tzonesearch->setTreeWidget(tzonelist); +} + +void Dtime::currentZone() +{ + KTimeZone localZone = KSystemTimeZones::local(); + + if (localZone.abbreviations().isEmpty()) { + m_local->setText(i18nc("%1 is name of time zone", "Current local time zone: %1", + KTimeZoneWidget::displayName(localZone))); + } else { + m_local->setText(i18nc("%1 is name of time zone, %2 is its abbreviation", + "Current local time zone: %1 (%2)", + KTimeZoneWidget::displayName(localZone), + QString::fromUtf8(localZone.abbreviations().first()))); + } +} + +void Dtime::serverTimeCheck() { + bool enabled = !setDateTimeAuto->isChecked(); + cal->setEnabled(enabled); + timeEdit->setEnabled(enabled); + //kclock->setEnabled(enabled); +} + +void Dtime::findNTPutility() +{ + const QString exePath = QLatin1String("/usr/sbin:/usr/bin:/sbin:/bin"); + foreach(const QString &possible_ntputility, QStringList() << "ntpdate" << "rdate" ) { + ntpUtility = KStandardDirs::findExe(possible_ntputility, exePath); + if (!ntpUtility.isEmpty()) { + return; + } + } +} + +void Dtime::set_time() +{ + if( ontimeout ) + return; + + internalTimer.stop(); + + time = timeEdit->time(); + kclock->setTime( time ); + + emit timeChanged( true ); +} + +void Dtime::changeDate(const QDate &d) +{ + date = d; + emit timeChanged( true ); +} + +void Dtime::configChanged(){ + emit timeChanged( true ); +} + +void Dtime::load() +{ + // The config is actually written to the system config, but the user does not have any local config, + // since there is nothing writing it. + KConfig _config( "kcmclockrc", KConfig::NoGlobals ); + KConfigGroup config(&_config, "NTP"); + timeServerList->clear(); + timeServerList->addItems(config.readEntry("servers", + i18n("Public Time Server (pool.ntp.org),\ +asia.pool.ntp.org,\ +europe.pool.ntp.org,\ +north-america.pool.ntp.org,\ +oceania.pool.ntp.org")).split(',', QString::SkipEmptyParts)); + setDateTimeAuto->setChecked(config.readEntry("enabled", false)); + + // Reset to the current date and time + time = QTime::currentTime(); + date = QDate::currentDate(); + cal->setDate(date); + + // start internal timer + internalTimer.start( 1000 ); + + timeout(); + + //Timezone + currentZone(); + + // read the currently set time zone + tzonelist->setSelected(KSystemTimeZones::local().name(), true); +} + +void Dtime::save( QVariantMap& helperargs ) +{ + // Save the order, but don't duplicate! + QStringList list; + if( timeServerList->count() != 0) + list.append(timeServerList->currentText()); + for ( int i=0; icount();i++ ) { + QString text = timeServerList->itemText(i); + if( !list.contains(text) ) + list.append(text); + // Limit so errors can go away and not stored forever + if( list.count() == 10) + break; + } + + helperargs["ntp"] = true; + helperargs["ntpServers"] = list; + helperargs["ntpEnabled"] = setDateTimeAuto->isChecked(); + + if(setDateTimeAuto->isChecked() && !ntpUtility.isEmpty()){ + // NTP Time setting - done in helper + timeServer = timeServerList->currentText(); + kDebug() << "Setting date from time server " << timeServer; + } + else { + // User time setting + QDateTime dt(date, QTime(timeEdit->time())); + + kDebug() << "Set date " << dt; + + helperargs["date"] = true; + helperargs["newdate"] = QString::number(dt.toTime_t()); + helperargs["olddate"] = QString::number(::time(0)); + } + + // restart time + internalTimer.start( 1000 ); + + QStringList selectedZones(tzonelist->selection()); + + if (selectedZones.count() > 0) { + QString selectedzone(selectedZones[0]); + helperargs["tz"] = true; + helperargs["tzone"] = selectedzone; + } else { + helperargs["tzreset"] = true; // // make the helper reset the timezone + } + + currentZone(); +} + +void Dtime::processHelperErrors( int code ) +{ + if( code & ClockHelper::NTPError ) { + KMessageBox::error( this, i18n("Unable to contact time server: %1.", timeServer) ); + setDateTimeAuto->setChecked( false ); + } + if( code & ClockHelper::DateError ) { + KMessageBox::error( this, i18n("Can not set date.")); + } + if( code & ClockHelper::TimezoneError) + KMessageBox::error( this, i18n("Error setting new time zone."), + i18n("Time zone Error")); +} + +void Dtime::timeout() +{ + // get current time + time = QTime::currentTime(); + + ontimeout = true; + timeEdit->setTime(time); + ontimeout = false; + + kclock->setTime( time ); +} + +QString Dtime::quickHelp() const +{ + return i18n("

Date & Time

This system settings module can be used to set the system date and" + " time. As these settings do not only affect you as a user, but rather the whole system, you" + " can only change these settings when you start the System Settings as root. If you do not have" + " the root password, but feel the system time should be corrected, please contact your system" + " administrator."); +} + +Kclock::Kclock(QWidget *parent) + : QWidget(parent) +{ + m_theme = new Plasma::Svg(this); + m_theme->setImagePath("widgets/clock"); + m_theme->setContainsMultipleImages(true); +} + +Kclock::~Kclock() +{ + delete m_theme; +} + +void Kclock::showEvent( QShowEvent *event ) +{ + setClockSize( size() ); + QWidget::showEvent( event ); +} + +void Kclock::resizeEvent( QResizeEvent * ) +{ + setClockSize( size() ); +} + +void Kclock::setClockSize(const QSize &size) +{ + int dim = qMin(size.width(), size.height()); + QSize newSize = QSize(dim, dim); + + if (newSize != m_faceCache.size()) { + m_faceCache = QPixmap(newSize); + m_handsCache = QPixmap(newSize); + m_glassCache = QPixmap(newSize); + + m_theme->resize(newSize); + m_repaintCache = RepaintAll; + } +} + +void Kclock::setTime(const QTime &time) +{ + if (time.minute() != this->time.minute() || time.hour() != this->time.hour()) { + if (m_repaintCache == RepaintNone) { + m_repaintCache = RepaintHands; + } + } + this->time = time; + update(); +} + +void Kclock::drawHand(QPainter *p, const QRect &rect, const qreal verticalTranslation, const qreal rotation, const QString &handName) +{ + // this code assumes the following conventions in the svg file: + // - the _vertical_ position of the hands should be set with respect to the center of the face + // - the _horizontal_ position of the hands does not matter + // - the _shadow_ elements should have the same vertical position as their _hand_ element counterpart + + QRectF elementRect; + QString name = handName + "HandShadow"; + if (m_theme->hasElement(name)) { + p->save(); + + elementRect = m_theme->elementRect(name); + if( rect.height() < 64 ) + elementRect.setWidth( elementRect.width() * 2.5 ); + static const QPoint offset = QPoint(2, 3); + + p->translate(rect.x() + (rect.width() / 2) + offset.x(), rect.y() + (rect.height() / 2) + offset.y()); + p->rotate(rotation); + p->translate(-elementRect.width()/2, elementRect.y()-verticalTranslation); + m_theme->paint(p, QRectF(QPointF(0, 0), elementRect.size()), name); + + p->restore(); + } + + p->save(); + + name = handName + "Hand"; + elementRect = m_theme->elementRect(name); + if (rect.height() < 64) { + elementRect.setWidth(elementRect.width() * 2.5); + } + + p->translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); + p->rotate(rotation); + p->translate(-elementRect.width()/2, elementRect.y()-verticalTranslation); + m_theme->paint(p, QRectF(QPointF(0, 0), elementRect.size()), name); + + p->restore(); +} + +void Kclock::paintInterface(QPainter *p, const QRect &rect) +{ + const bool m_showSecondHand = true; + + // compute hand angles + const qreal minutes = 6.0 * time.minute() - 180; + const qreal hours = 30.0 * time.hour() - 180 + + ((time.minute() / 59.0) * 30.0); + qreal seconds = 0; + if (m_showSecondHand) { + static const double anglePerSec = 6; + seconds = anglePerSec * time.second() - 180; + } + + // paint face and glass cache + QRect faceRect = m_faceCache.rect(); + if (m_repaintCache == RepaintAll) { + m_faceCache.fill(Qt::transparent); + m_glassCache.fill(Qt::transparent); + + QPainter facePainter(&m_faceCache); + QPainter glassPainter(&m_glassCache); + facePainter.setRenderHint(QPainter::SmoothPixmapTransform); + glassPainter.setRenderHint(QPainter::SmoothPixmapTransform); + + m_theme->paint(&facePainter, m_faceCache.rect(), "ClockFace"); + + glassPainter.save(); + QRectF elementRect = QRectF(QPointF(0, 0), m_theme->elementSize("HandCenterScrew")); + glassPainter.translate(faceRect.width() / 2 - elementRect.width() / 2, faceRect.height() / 2 - elementRect.height() / 2); + m_theme->paint(&glassPainter, elementRect, "HandCenterScrew"); + glassPainter.restore(); + + m_theme->paint(&glassPainter, faceRect, "Glass"); + + // get vertical translation, see drawHand() for more details + m_verticalTranslation = m_theme->elementRect("ClockFace").center().y(); + } + + // paint hour and minute hands cache + if (m_repaintCache == RepaintHands || m_repaintCache == RepaintAll) { + m_handsCache.fill(Qt::transparent); + + QPainter handsPainter(&m_handsCache); + handsPainter.drawPixmap(faceRect, m_faceCache, faceRect); + handsPainter.setRenderHint(QPainter::SmoothPixmapTransform); + + drawHand(&handsPainter, faceRect, m_verticalTranslation, hours, "Hour"); + drawHand(&handsPainter, faceRect, m_verticalTranslation, minutes, "Minute"); + } + + // reset repaint cache flag + m_repaintCache = RepaintNone; + + // paint caches and second hand + QRect targetRect = faceRect; + if (targetRect.width() < rect.width()) { + targetRect.moveLeft((rect.width() - targetRect.width()) / 2); + } + + p->drawPixmap(targetRect, m_handsCache, faceRect); + if (m_showSecondHand) { + p->setRenderHint(QPainter::SmoothPixmapTransform); + drawHand(p, targetRect, m_verticalTranslation, seconds, "Second"); + } + p->drawPixmap(targetRect, m_glassCache, faceRect); +} + +void Kclock::paintEvent( QPaintEvent * ) +{ + QPainter paint(this); + + paint.setRenderHint(QPainter::Antialiasing); + paintInterface(&paint, rect()); +} + diff --git a/kcontrol/dateandtime/dtime.h b/kcontrol/dateandtime/dtime.h new file mode 100644 index 00000000..1a90698c --- /dev/null +++ b/kcontrol/dateandtime/dtime.h @@ -0,0 +1,121 @@ +/* + * dtime.h + * + * Copyright (C) 1998 Luca Montecchiani + * + * 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 dtime_included +#define dtime_included + +#include "ui_dateandtime.h" + +#include +#include +#include +#include +#include +//Added by qt3to4: +#include + +#include +#include + +class Kclock; +class QTimeEdit; + +namespace Plasma { + class Svg; +} + +class Dtime : public QWidget, public Ui::DateAndTime +{ + Q_OBJECT + public: + Dtime( QWidget *parent=0 ); + + void save( QVariantMap &helperargs ); + void processHelperErrors( int code ); + void load(); + + QString quickHelp() const; + +Q_SIGNALS: + void timeChanged(bool); + + private Q_SLOTS: + void configChanged(); + void serverTimeCheck(); + void timeout(); + void set_time(); + void changeDate(const QDate&); + +private: + void currentZone(); + void findNTPutility(); + QString ntpUtility; + + QTimeEdit *timeEdit; + + Kclock *kclock; + + QTime time; + QDate date; + QTimer internalTimer; + + QString timeServer; + int BufI; + bool refresh; + bool ontimeout; +}; + +class Kclock : public QWidget +{ + Q_OBJECT + +public: + Kclock( QWidget *parent=0 ); + ~Kclock(); + + void setTime(const QTime&); + +protected: + virtual void paintEvent( QPaintEvent *event ); + virtual void showEvent( QShowEvent *event ); + virtual void resizeEvent( QResizeEvent *event ); + +private: + void setClockSize(const QSize &size); + void drawHand(QPainter *p, const QRect &rect, const qreal verticalTranslation, const qreal rotation, const QString &handName); + void paintInterface(QPainter *p, const QRect &rect); + +private: + QTime time; + Plasma::Svg *m_theme; + enum RepaintCache { + RepaintNone, + RepaintAll, + RepaintHands + }; + RepaintCache m_repaintCache; + QPixmap m_faceCache; + QPixmap m_handsCache; + QPixmap m_glassCache; + qreal m_verticalTranslation; +}; + +#endif // dtime_included diff --git a/kcontrol/dateandtime/helper.cpp b/kcontrol/dateandtime/helper.cpp new file mode 100644 index 00000000..21fc51a6 --- /dev/null +++ b/kcontrol/dateandtime/helper.cpp @@ -0,0 +1,266 @@ +/* + * tzone.cpp + * + * Copyright (C) 1998 Luca Montecchiani + * + * 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. + * + */ + +/* + + A helper that's run using KAuth and does the system modifications. + +*/ + +#include "helper.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(USE_SOLARIS) +#include +#include +#include +#include +#endif + +// We cannot rely on the $PATH environment variable, because D-Bus activation +// clears it. So we have to use a reasonable default. +static const QString exePath = QLatin1String("/usr/sbin:/usr/bin:/sbin:/bin"); + +static QString findNtpUtility() +{ + foreach(const QString &possible_ntputility, QStringList() << "ntpdate" << "rdate" ) { + const QString ntpUtility = KStandardDirs::findExe(possible_ntputility, exePath); + if (!ntpUtility.isEmpty()) { + return ntpUtility; + } + } + return QString(); +} + +int ClockHelper::ntp( const QStringList& ntpServers, bool ntpEnabled ) +{ + int ret = 0; + + // write to the system config file + QFile config_file(KDE_CONFDIR "/kcmclockrc"); + if(!config_file.exists()) { + config_file.open(QIODevice::WriteOnly); + config_file.close(); + config_file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther); + } + KConfig _config(config_file.fileName(), KConfig::SimpleConfig); + KConfigGroup config(&_config, "NTP"); + config.writeEntry("servers", ntpServers ); + config.writeEntry("enabled", ntpEnabled ); + + QString ntpUtility(findNtpUtility()); + + if ( ntpEnabled && !ntpUtility.isEmpty() ) { + // NTP Time setting + QString timeServer = ntpServers.first(); + if( timeServer.indexOf( QRegExp(".*\\(.*\\)$") ) != -1 ) { + timeServer.replace( QRegExp(".*\\("), "" ); + timeServer.replace( QRegExp("\\).*"), "" ); + // Would this be better?: s/^.*\(([^)]*)\).*$/\1/ + } + + KProcess proc; + proc << ntpUtility << timeServer; + if ( proc.execute() != 0 ) { + ret |= NTPError; + } + } else if( ntpEnabled ) { + ret |= NTPError; + } + + return ret; +} + +int ClockHelper::date( const QString& newdate, const QString& olddate ) +{ + struct timeval tv; + + tv.tv_sec = newdate.toULong() - olddate.toULong() + time(0); + tv.tv_usec = 0; + if (settimeofday(&tv, 0)) { + return DateError; + } + + QString hwclock = KStandardDirs::findExe("hwclock", exePath); + if (!hwclock.isEmpty()) { + KProcess::execute(hwclock, QStringList() << "--systohc"); + } + return 0; +} + +// on non-Solaris systems which do not use /etc/timezone? +int ClockHelper::tz( const QString& selectedzone ) +{ + int ret = 0; + + //only allow letters, numbers hyphen underscore plus and forward slash + //allowed pattern taken from time-util.c in systemd + if (!QRegExp("[a-zA-Z0-9-_+/]*").exactMatch(selectedzone)) { + return ret; + } + +#if defined(USE_SOLARIS) // MARCO + + KTemporaryFile tf; + tf.setPrefix("kde-tzone"); + tf.open(); + QTextStream ts(&tf); + + QFile fTimezoneFile(INITFILE); + bool updatedFile = false; + + if (fTimezoneFile.open(QIODevice::ReadOnly)) + { + bool found = false; + + QTextStream is(&fTimezoneFile); + + for (QString line = is.readLine(); !line.isNull(); + line = is.readLine()) + { + if (line.find("TZ=") == 0) + { + ts << "TZ=" << selectedzone << endl; + found = true; + } + else + { + ts << line << endl; + } + } + + if (!found) + { + ts << "TZ=" << selectedzone << endl; + } + + updatedFile = true; + fTimezoneFile.close(); + } + + if (updatedFile) + { + ts.device()->reset(); + fTimezoneFile.remove(); + + if (fTimezoneFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + QTextStream os(&fTimezoneFile); + + for (QString line = ts->readLine(); !line.isNull(); + line = ts->readLine()) + { + os << line << endl; + } + + fchmod(fTimezoneFile.handle(), + S_IXUSR | S_IRUSR | S_IRGRP | S_IXGRP | + S_IROTH | S_IXOTH); + fTimezoneFile.close(); + } + } + + + QString val = selectedzone; +#else + QString tz = "/usr/share/zoneinfo/" + selectedzone; + + QString zic = KStandardDirs::findExe("zic", exePath); + if (!zic.isEmpty()) { + KProcess::execute(zic, QStringList() << "-l" << selectedzone); + } else if (!QFile::remove("/etc/localtime")) { + ret |= TimezoneError; + } else if (!QFile::copy(tz, "/etc/localtime")) { + ret |= TimezoneError; + } + + QFile fTimezoneFile("/etc/timezone"); + + if (fTimezoneFile.exists() && fTimezoneFile.open(QIODevice::WriteOnly | QIODevice::Truncate) ) { + QTextStream t(&fTimezoneFile); + t << selectedzone; + fTimezoneFile.close(); + } + + QString val = ':' + tz; +#endif // !USE_SOLARIS + + setenv("TZ", val.toAscii(), 1); + tzset(); + + return ret; +} + +int ClockHelper::tzreset() +{ +#if !defined(USE_SOLARIS) // Do not update the System! + unlink( "/etc/timezone" ); + unlink( "/etc/localtime" ); + + setenv("TZ", "", 1); + tzset(); +#endif // !USE SOLARIS + return 0; +} + +ActionReply ClockHelper::save(const QVariantMap &args) +{ + bool _ntp = args.value("ntp").toBool(); + bool _date = args.value("date").toBool(); + bool _tz = args.value("tz").toBool(); + bool _tzreset = args.value("tzreset").toBool(); + + KComponentData data( "kcmdatetimehelper" ); + + int ret = 0; // error code +// The order here is important + if( _ntp ) + ret |= ntp( args.value("ntpServers").toStringList(), args.value("ntpEnabled").toBool()); + if( _date ) + ret |= date( args.value("newdate").toString(), args.value("olddate").toString() ); + if( _tz ) + ret |= tz( args.value("tzone").toString() ); + if( _tzreset ) + ret |= tzreset(); + + if (ret == 0) { + return ActionReply::SuccessReply; + } else { + ActionReply reply(ActionReply::HelperError); + reply.setErrorCode(ret); + return reply; + } +} + +KDE4_AUTH_HELPER_MAIN("org.kde.kcontrol.kcmclock", ClockHelper) diff --git a/kcontrol/dateandtime/helper.h b/kcontrol/dateandtime/helper.h new file mode 100644 index 00000000..fea71bae --- /dev/null +++ b/kcontrol/dateandtime/helper.h @@ -0,0 +1,51 @@ +/* + * main.h + * + * Copyright (C) 1998 Luca Montecchiani + * + * 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 CLOCK_HELPER_H +#define CLOCK_HELPER_H + +#include + +using namespace KAuth; + +class ClockHelper : public QObject +{ + Q_OBJECT + + public: + enum + { + CallError = 1 << 0, + TimezoneError = 1 << 1, + NTPError = 1 << 2, + DateError = 1 << 3 + }; + + public slots: + ActionReply save(const QVariantMap &map); + + private: + int ntp(const QStringList& ntpServers, bool ntpEnabled); + int date(const QString& newdate, const QString& olddate); + int tz(const QString& selectedzone); + int tzreset(); +}; + +#endif // CLOCK_HELPER_H diff --git a/kcontrol/dateandtime/kcmclock_actions.actions b/kcontrol/dateandtime/kcmclock_actions.actions new file mode 100644 index 00000000..14b4433b --- /dev/null +++ b/kcontrol/dateandtime/kcmclock_actions.actions @@ -0,0 +1,209 @@ +[Domain] +Name=Date and Time Control Module +Name[ar]=وحدة التحكم بالتاريخ والوقت +Name[ast]=Módulu de control de data y hora +Name[bg]=Управление на дата и час +Name[bn]=তারিখ এবং সময় নিয়ন্ত্রণ মডিউল +Name[bs]=Kontrolni modul datuma i vremena +Name[ca]=Mòdul de control de data i hora +Name[ca@valencia]=Mòdul de control de data i hora +Name[cs]=Ovládací modul data a času +Name[csb]=Mòduł kòntrolë datuma ë czasu +Name[da]=Kontrolmodul til dato og tid +Name[de]=Kontrollmodul für Datum und Zeit +Name[el]=Μονάδα ελέγχου ημερομηνίας και ώρας +Name[en_GB]=Date and Time Control Module +Name[eo]=Kontrol-Modulo de Dato kaj Tempo +Name[es]=Módulo de control de fecha y hora +Name[et]=Kuupäeva ja kellaaja juhtimismoodul +Name[eu]=Data eta ordua kontrolatzeko modulua +Name[fi]=Aika-asetukset +Name[fr]=Module de contrôle de la date et de l'heure +Name[fy]=Datum en tiid kontrôle module +Name[ga]=Modúl Rialaithe Dáta agus Am +Name[gl]=Módulo de control da data e hora +Name[gu]=તારીખ અને સમય નિયંત્રણ મોડ્યુલ +Name[he]=מודול הגדרות תאריך ושעה +Name[hi]=तारीख़ और समय तंत्र मोड्यूल +Name[hr]=Upravljački modul za datum i vrijeme +Name[hu]=Dátum és idő beállítómodul +Name[ia]=Modulo de controlo de data e tempore +Name[id]=Modul Kontrol Tanggal dan Waktu +Name[is]=Stjórneining fyrir dagsetningu og tíma +Name[it]=Modulo di controllo di data e ora +Name[ja]=日付と時刻の設定モジュール +Name[kk]=Күні мен уақытын басқару модулі +Name[km]=ម៉ូឌុល​ត្រួតពិនិត្យ​ពេលវេលា និងកាលបរិច្ឆេទ +Name[kn]=ದಿನಾಂಕ ಮತ್ತು ಸಮಯ ನಿಯಂತ್ರಣ ಘಟಕ +Name[ko]=날짜와 시간 제어 모듈 +Name[lt]=Datos ir laiko valdymo modulis +Name[lv]=Datuma un laika kontroles modulis +Name[mk]=Контролен модул за датум и време +Name[ml]=തീയതിയും സമയവും നിയന്ത്രിയ്ക്കുന്ന ഭാഗം +Name[mr]=दिनांक व वेळ नियंत्रण विभाग +Name[nb]=Styremodul for dato og tid +Name[nds]=Datum- un Tiet-Kuntrullmoduul +Name[nl]=Controlemodule van datum en tijd +Name[nn]=Kontrollmodul for dato og klokkeslett +Name[pa]=ਮਿਤੀ ਅਤੇ ਟਾਈਮ ਕੰਟਰੋਲ ਮੋਡੀਊਲ +Name[pl]=Moduł sterowania datą i czasem +Name[pt]=Módulo de Controlo da Data e Hora +Name[pt_BR]=Módulo de controle da data e hora +Name[ro]=Modul de control dată și oră +Name[ru]=Модуль настройки даты и времени +Name[si]=දිනය සහ වේලා පාලක මොඩියුලය +Name[sk]=Modul pre nastavenie dátumu a času +Name[sl]=Nadzorni modul za datum in čas +Name[sr]=Контролни модул датума и времена +Name[sr@ijekavian]=Контролни модул датума и времена +Name[sr@ijekavianlatin]=Kontrolni modul datuma i vremena +Name[sr@latin]=Kontrolni modul datuma i vremena +Name[sv]=Inställningsmodul för datum och tid +Name[tg]=Сана ва вақт +Name[th]=มอดูลควบคุมสำหรับวันและเวลา +Name[tr]=Tarih ve Saat Denetim Modülü +Name[ug]=چېسلا ۋە ۋاقىت تىزگىن بۆلىكى +Name[uk]=Модуль керування датою і часом +Name[vi]=Mô-đun điều khiển ngày giờ +Name[wa]=Module di controle del date eyet d' l' eure +Name[x-test]=xxDate and Time Control Modulexx +Name[zh_CN]=日期和时间控制模块 +Name[zh_TW]=日期與時間控制模組 +Icon=preferences-system-time + +[org.kde.kcontrol.kcmclock.save] +Name=Save the date/time settings +Name[ar]=احفظ إعدادات التاريخ والوقت +Name[ast]=Guardar les preferencies de data/hora +Name[bg]=Запазване настройките за дата и час +Name[bn]=তারিখ এবং সময় সেটিংস সংরক্ষণ করো +Name[bs]=Sačuvaj postavke datuma i vremena +Name[ca]=Desa la configuració de data i hora +Name[ca@valencia]=Guarda la configuració de data i hora +Name[cs]=Uložit nastavení data a času +Name[csb]=Zapiszë nastôw datuma ë czasu +Name[da]=Gem dato- og tidsindstillinger +Name[de]=Einstellungen für Datum und Zeit speichern +Name[el]=Αποθήκευση ρυθμίσεων ημερομηνίας και ώρας +Name[en_GB]=Save the date/time settings +Name[eo]=Konservu Agordon de dato kaj tempo +Name[es]=Guardar las preferencias de fecha/hora +Name[et]=Kuupäeva ja kellaaja seadistuste salvestamine +Name[eu]=Gorde data- eta ordu-ezarpenak +Name[fi]=Tallenna päiväyksen ja ajan asetukset +Name[fr]=Enregistrer les paramètres de date et d'heure +Name[fy]=Datum en tiid ynstellings bewarje +Name[ga]=Sábháil na socruithe dáta/ama +Name[gl]=Garda a configuración da data e hora +Name[gu]=તારીખ/સમય ગોઠવણીઓ સંગ્રહો +Name[he]=שמירת הגדרות התאריך והשעה +Name[hi]=तारीख़ तथा समय विन्यास सहेजें +Name[hr]=Spremi datumske/vremenske postavke +Name[hu]=A dátum- és időbeállítások mentése +Name[ia]=Salveguarda le preferentias de data & tempore +Name[id]=Simpan pengaturan tanggal/waktu +Name[is]=Vista stillingar dagssetningar og tíma +Name[it]=Salva le impostazioni di data e ora +Name[ja]=日付と時刻の設定を保存 +Name[kk]=Күн/уақыт параметрлерін сақтау +Name[km]=រក្សាទុកការកំណត់​ពេលវេលា/កាលបរិច្ឆេទ +Name[kn]=ದಿನಾಂಕ/ಸಮಯ ಸಂಯೋಜನೆಗಳನ್ನು ಉಳಿಸಿ +Name[ko]=날짜와 시간 설정 저장 +Name[lt]=Duomenų ir laiko nustatymai +Name[lv]=Saglabāt datuma/laika iestatījumus +Name[mk]=Зачувување на поставувања за датум и време +Name[ml]=തീയതിയുടെ/സമയത്തിന്റെ സജ്ജീകരണങ്ങള്‍ സൂക്ഷിയ്ക്കുക +Name[mr]=दिनांक व वेळ संयोजना साठवा +Name[nb]=Lagre dato og klokkeslett-innstillinger +Name[nds]=Instellen vun Datum un Tiet sekern +Name[nl]=Datum- en tijdinstellingen opslaan +Name[nn]=Lagra innstillingane for dato og klokkeslett +Name[pa]=ਮਿਤੀ/ਸਮਾਂ ਸੈਟਿੰਗ ਸੰਭਾਲੋ +Name[pl]=Zapisz ustawienia daty/czasu +Name[pt]=Mudar a configuração da data/hora +Name[pt_BR]=Salvar as configurações de data e hora +Name[ro]=Salvează configurările datei și orei +Name[ru]=Сохранить параметры даты и времени +Name[si]=දිනය/වේලාව සිටුවම් සුරකින්න +Name[sk]=Uložiť nastavenia dátumu a času +Name[sl]=Shranjevanje nastavitev datuma in časa +Name[sr]=Сачувај поставке датума и времена +Name[sr@ijekavian]=Сачувај поставке датума и времена +Name[sr@ijekavianlatin]=Sačuvaj postavke datuma i vremena +Name[sr@latin]=Sačuvaj postavke datuma i vremena +Name[sv]=Spara inställningar av datum och tid +Name[tg]=Танзимоти сана ва вақт +Name[th]=จัดเก็บการตั้งค่าวันและเวลา +Name[tr]=Tarih ve saat ayarlarını kaydet +Name[ug]=چېسلا/ۋاقىت تەڭشىكىنى ساقلايدۇ +Name[uk]=Зберегти параметри дати/часу +Name[wa]=Schaper ls apontiaedjes del date et d' l' eure +Name[x-test]=xxSave the date/time settingsxx +Name[zh_CN]=保存日期和时间设置 +Name[zh_TW]=儲存日期和時間設定值 +Description=System policies prevent you from saving the date/time settings. +Description[ar]=إن سياسات النظام لا تسمح لك بحفظ إعدادات الوقت والتاريخ +Description[ast]=Les polítiques del sistema impiden guardar les preferencies de data/hora. +Description[bg]=Системните правила не позволяват запазване на настройките за дата и час. +Description[bn]=সিস্টেম পলিসি আপনাকে তারিখ এবং সময় সেটিংস সংরক্ষণ করতে দিচ্ছে না। +Description[bs]=Sistemske smjernice sprečavaju upisivanje postavki datuma i vremena. +Description[ca]=Les polítiques del sistema impedeixen que deseu la configuració de data i hora. +Description[ca@valencia]=Les polítiques del sistema impedeixen que guardeu la configuració de data i hora. +Description[cs]=Nastavení systému vám znemožňuje uložit datum/čas. +Description[csb]=Przez systemòwi nastôw nié mòżé zapisac nastôwù datuma ë czasu. +Description[da]=Systempolitikker forhindrer dig i at gemme dato- og tidsindstillinger. +Description[de]=Die Einstellungen für Datum und Zeit können aufgrund einer Systemrichtlinie nicht gespeichert werden. +Description[el]=Οι πολιτικές του συστήματος αποτρέπουν την αποθήκευση των ρυθμίσεων ώρας/ημερομηνίας. +Description[en_GB]=System policies prevent you from saving the date/time settings. +Description[es]=Las políticas del sistema le impiden guardar las preferencias de fecha/hora. +Description[et]=Süsteemi reeglid takistavad kuupäeva ja kellaaja seadistuste salvestamist. +Description[eu]=Sistemako gidalerroek data- eta ordu-ezarpenak gordetzea eragozten dizute +Description[fi]=Järjestelmämenettelytavat estävät sinua tallentamasta päivämäärä/aika-asetuksia. +Description[fr]=La stratégie système vous empêche d'enregistrer les paramètres de date et d'heure. +Description[fy]=Systeem belied foarkomt dat jo datum en tiid ynstellings bewarje kinne. +Description[ga]=De bharr polasaí an chórais, níl cead agat socruithe an dáta/ama a shábháil. +Description[gl]=As políticas do sistema non permiten que garde a configuración da data e hora. +Description[he]=מדיניות המערכת מונעת ממך שמירת הגדרות התאריך והשעה. +Description[hr]=Pravila sustava vam brane spremanje datumskih/vremenskih postavki. +Description[hu]=A rendszer házirendjei nem engedik Önnek a dátum- és időbeállítások mentését. +Description[ia]=Le politicas de systema preveni te ex salveguardar le preferentias de tempore/data. +Description[id]=Kebijakan sistem menghalangi anda untuk menyimpan pengaturan tanggal/waktu. +Description[is]=Öryggisstillingar kerfisins koma í veg fyrir að þú getir vistað tíma/dagsetningu. +Description[it]=Le regole di condotta del sistema impediscono di salvare le impostazioni di data e ora. +Description[ja]=システムポリシーにより、日時設定を保存することができません。 +Description[kk]=Күн/уақыт параметрлерін сақтауды болдырмайтын жүйелік ережелері. +Description[km]=គោលនយោបាយ​ប្រព័ន្ធ​ ការពារ​អ្នក​​មិន​ឲ្យ​រក្សាទុក​ការកំណត់​កាលបរិច្ឆេទ/ពេលវេលា ។ +Description[kn]=ವ್ಯವಸ್ಥೆಯ ಕಾರ್ಯನೀತಿ ನಿಮ್ಮನ್ನು ಸಮಯ/ದಿನಾಂಕ ಸಂಯೋಜನೆಗಳನ್ನು ಉಳಿಸಿಕೊಳ್ಳುವುದರಿಂದ ತಡೆಯುತ್ತಿವೆ +Description[ko]=시스템 정책 때문에 날짜와 시간 설정을 저장할 수 없습니다. +Description[lt]=Sistemos taisyklės neleidžia jums įrašyti datos/laiko. +Description[lv]=Sistēmas politikas neļauj jums saglabāt datuma/laika iestatījumus. +Description[mk]=Политиката на системот Ве спречува да ги зачувате поставувањата за датум и време. +Description[ml]=സിസ്റ്റത്തിലെ നയങ്ങള്‍ തിയ്യതി/സമയം ക്രമീകരിയ്ക്കുന്നതില്‍ നിന്നും നിങ്ങളെ തടയുന്നു. +Description[mr]=प्रणाली धोरण दिनांक व वेळ संयोजना संचयीत करण्यास प्रतिबंध करत आहे. +Description[nb]=Systembestemmelser gjør at du ikke kan lagre dato/tid-innstillingene +Description[nds]=De Systeemregeln verlöövt nich, dat Du de Instellen för Datum un Tiet sekerst. +Description[nl]=Systeembeleid voorkwam dat u de datum- en tijdinstellingen kon opslaan. +Description[nn]=Systemreglane hindrar deg i å lagra innstillingane for dato og klokkeslett. +Description[pa]=ਸਿਸਟਮ ਪਾਲਸੀ ਤੁਹਾਨੂੰ ਮਿਤੀ/ਸਮਾਂ ਸੈਟਿੰਗ ਬਦਲਣ ਤੋਂ ਤੁਹਾਨੂੰ ਰੋਕਦੀ ਹੈ। +Description[pl]=Polityka systemu nie pozwala ci na zapisanie ustawień daty/czasu. +Description[pt]=As políticas do sistema proíbem a modificação da configuração de data/hora. +Description[pt_BR]=As políticas do sistema não permitem a modificação das configurações de data e hora. +Description[ro]=Politicile sistemului vă interzic salvarea configurărilor de dată și oră. +Description[ru]=Правила безопасности запрещают вам управлять системной датой и временем. +Description[si]=පද්ධති ප්‍රතිපත්තො ඔබව දිනය/වේලාව සැකසුම් සුරැකිම වලකාලයි. +Description[sk]=Systémové politiky vám zabránili uložiť nastavenie dátumu a času. +Description[sl]=Sistemski pravilniki vam onemogočajo, da bi shranili nastavitve datuma in časa. +Description[sr]=Системске смернице спречавају уписивање поставки датума и времена. +Description[sr@ijekavian]=Системске смјернице спречавају уписивање поставки датума и времена. +Description[sr@ijekavianlatin]=Sistemske smjernice sprečavaju upisivanje postavki datuma i vremena. +Description[sr@latin]=Sistemske smernice sprečavaju upisivanje postavki datuma i vremena. +Description[sv]=Systemets policy förhindrar att du sparar inställningar av datum och tid. +Description[th]=นโยบายของระบบเพื่อป้องกันจากการจัดเก็บการตั้งค่าต่าง ๆ ของวันและเวลา +Description[tr]=Sistem politikaları tarih saat ayarlarını kaydetmenizi engelliyor. +Description[ug]=سىستېما بىخەتەرلىك تەدبىرىڭىز چېسلا/ۋاقىت تەڭشەكلەرنى ساقلاشقا يول قويمايدۇ. +Description[uk]=Відповідно до загальносистемних правил, ви не можете зберігати параметри дати/часу. +Description[wa]=Les politikes do sistinme vos espaitchèt d' schaper les apontiaedjes del date/eure. +Description[x-test]=xxSystem policies prevent you from saving the date/time settings.xx +Description[zh_CN]=系统安全策略不允许您保存日期/时间设置。 +Description[zh_TW]=系統政策不允許您儲存日期與時間的設定 +Policy=auth_admin diff --git a/kcontrol/dateandtime/main.cpp b/kcontrol/dateandtime/main.cpp new file mode 100644 index 00000000..2fa0f3ec --- /dev/null +++ b/kcontrol/dateandtime/main.cpp @@ -0,0 +1,122 @@ +/* + * main.cpp + * + * Copyright (C) 1998 Luca Montecchiani + * + * 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 + +//Added by qt3to4: +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.moc" + +#include "dtime.h" +#include "helper.h" + +#include + +K_PLUGIN_FACTORY(KlockModuleFactory, registerPlugin();) +K_EXPORT_PLUGIN(KlockModuleFactory("kcmkclock")) + + +KclockModule::KclockModule(QWidget *parent, const QVariantList &) + : KCModule(KlockModuleFactory::componentData(), parent/*, name*/) +{ + KAboutData *about = + new KAboutData(I18N_NOOP("kcmclock"), 0, ki18n("KDE Clock Control Module"), + 0, KLocalizedString(), KAboutData::License_GPL, + ki18n("(c) 1996 - 2001 Luca Montecchiani")); + + about->addAuthor(ki18n("Luca Montecchiani"), ki18n("Original author"), "m.luca@usa.net"); + about->addAuthor(ki18n("Paul Campbell"), ki18n("Current Maintainer"), "paul@taniwha.com"); + about->addAuthor(ki18n("Benjamin Meyer"), ki18n("Added NTP support"), "ben+kcmclock@meyerhome.net"); + setAboutData( about ); + setQuickHelp( i18n("

Date & Time

This control module can be used to set the system date and" + " time. As these settings do not only affect you as a user, but rather the whole system, you" + " can only change these settings when you start the System Settings as root. If you do not have" + " the root password, but feel the system time should be corrected, please contact your system" + " administrator.")); + + KGlobal::locale()->insertCatalog("timezones4"); // For time zone translations + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(KDialog::spacingHint()); + + dtime = new Dtime(this); + layout->addWidget(dtime); + connect(dtime, SIGNAL(timeChanged(bool)), this, SIGNAL(changed(bool))); + + setButtons(Help|Apply); + + setNeedsAuthorization(true); + + process = NULL; +} + +void KclockModule::save() +{ + setDisabled(true); + + QVariantMap helperargs; + dtime->save( helperargs ); + + Action *action = authAction(); + action->setArguments(helperargs); + + ActionReply reply = action->execute(); + + if (reply.failed()) { + if (reply.type() == ActionReply::KAuthError) { + KMessageBox::error(this, i18n("Unable to authenticate/execute the action: %1, %2", reply.errorCode(), reply.errorDescription())); + } else { + dtime->processHelperErrors(reply.errorCode()); + } + } + else { + QDBusMessage msg = QDBusMessage::createSignal("/org/kde/kcmshell_clock", "org.kde.kcmshell_clock", "clockUpdated"); + QDBusConnection::sessionBus().send(msg); + } + + // NOTE: super nasty hack #1 + // Try to work around time mismatch between KSystemTimeZones' update of local + // timezone and reloading of data, so that the new timezone is taken into account. + // The Ultimate solution to this would be if KSTZ emitted a signal when a new + // local timezone was found. + QTimer::singleShot(5000, this, SLOT(load())); + + // setDisabled(false) happens in load(), since QTimer::singleShot is non-blocking +} + +void KclockModule::load() +{ + dtime->load(); + setDisabled(false); +} diff --git a/kcontrol/dateandtime/main.h b/kcontrol/dateandtime/main.h new file mode 100644 index 00000000..c1e52340 --- /dev/null +++ b/kcontrol/dateandtime/main.h @@ -0,0 +1,47 @@ +/* + * main.h + * + * Copyright (C) 1998 Luca Montecchiani + * + * 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_included +#define main_included + +#include + +class Dtime; +class QTabWidget; +class KProcess; + + +class KclockModule : public KCModule +{ + Q_OBJECT + +public: + KclockModule(QWidget *parent, const QVariantList &); + + void save(); + void load(); + +private: + QTabWidget *tab; + Dtime *dtime; + KProcess *process; +}; + +#endif // main_included diff --git a/kcontrol/desktoppaths/CMakeLists.txt b/kcontrol/desktoppaths/CMakeLists.txt new file mode 100644 index 00000000..0d94c9f6 --- /dev/null +++ b/kcontrol/desktoppaths/CMakeLists.txt @@ -0,0 +1,12 @@ +set(kcm_desktoppaths_PART_SRCS + globalpaths.cpp + kcmdesktoppaths.cpp +) + +kde4_add_plugin(kcm_desktoppaths ${kcm_desktoppaths_PART_SRCS}) + +target_link_libraries(kcm_desktoppaths ${KDE4_KCMUTILS_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS kcm_desktoppaths DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES desktoppath.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/kcontrol/desktoppaths/Messages.sh b/kcontrol/desktoppaths/Messages.sh new file mode 100644 index 00000000..fe3c1740 --- /dev/null +++ b/kcontrol/desktoppaths/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kcm_desktoppaths.pot diff --git a/kcontrol/desktoppaths/desktoppath.desktop b/kcontrol/desktoppaths/desktoppath.desktop new file mode 100644 index 00000000..2be2d092 --- /dev/null +++ b/kcontrol/desktoppaths/desktoppath.desktop @@ -0,0 +1,236 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/paths/index.html +Icon=system-file-manager +Exec=kcmshell4 desktoppath + +X-KDE-Library=kcm_desktoppaths +X-KDE-PluginKeyword=dpath +X-KDE-ParentApp=kcontrol +X-KDE-System-Settings-Parent-Category=account-details +X-KDE-Weight=60 + +Name=Paths +Name[af]=Soekgidse +Name[ar]=المسارات +Name[as]=পথ +Name[ast]=Caminos +Name[be]=Шляхі +Name[be@latin]=Ściežki +Name[bg]=Пътища +Name[bn]=পাথ (Paths) +Name[bn_IN]=পাথ +Name[br]=Hentoù +Name[bs]=Putanje +Name[ca]=Camins +Name[ca@valencia]=Camins +Name[cs]=Cesty +Name[csb]=Stegnë +Name[cy]=Llwybrau +Name[da]=Stier +Name[de]=Pfade +Name[el]=Κατάλογοι +Name[en_GB]=Paths +Name[eo]=Vojoj +Name[es]=Rutas +Name[et]=Otsinguteed +Name[eu]=Bide-izenak +Name[fa]=مسیرها +Name[fi]=Polut +Name[fr]=Emplacements +Name[fy]=Paden +Name[ga]=Conairí +Name[gl]=Rutas +Name[gu]=માર્ગો +Name[he]=נתיבים +Name[hi]=पथ +Name[hne]=पथ +Name[hr]=Putanje +Name[hsb]=Puće +Name[hu]=Elérési utak +Name[ia]=Percursos +Name[id]=Alamat +Name[is]=Slóðir +Name[it]=Percorsi +Name[ja]=パス +Name[ka]=ბილიკი +Name[kk]=Жолдар +Name[km]=ផ្លូវ +Name[kn]=ಪಥಗಳು (ಪಾತ್) +Name[ko]=경로 +Name[ku]=Rêç +Name[lt]=Keliai +Name[lv]=Ceļi +Name[mai]=पथ +Name[mk]=Патеки +Name[ml]=വഴികള്‍ +Name[mr]=मार्ग +Name[ms]=Laluan +Name[nb]=Stier +Name[nds]=Padden +Name[ne]=मार्ग +Name[nl]=Paden +Name[nn]=Stiar +Name[oc]=Camins +Name[or]=ପଥଗୁଡ଼ିକ +Name[pa]=ਮਾਰਗ +Name[pl]=Ścieżki +Name[pt]=Localizações +Name[pt_BR]=Caminhos +Name[ro]=Căi +Name[ru]=Пути +Name[se]=Bálgát +Name[si]=මාර්‍ග +Name[sk]=Cesty +Name[sl]=Poti +Name[sr]=Путање +Name[sr@ijekavian]=Путање +Name[sr@ijekavianlatin]=Putanje +Name[sr@latin]=Putanje +Name[sv]=Sökvägar +Name[ta]=பாதைகள் +Name[te]=దారులు +Name[tg]=Роҳчаҳо +Name[th]=พาธ +Name[tr]=Yollar +Name[ug]=يول +Name[uk]=Шляхи +Name[uz]=Yoʻllar +Name[uz@cyrillic]=Йўллар +Name[vi]=Đường dẫn +Name[wa]=Tchimins +Name[xh]=Umendo +Name[x-test]=xxPathsxx +Name[zh_CN]=路径 +Name[zh_TW]=路徑 + +Comment=Change the location important files are stored +Comment[af]=Verander die ligging belangrik lêers word gestoor +Comment[ar]=غيّر المكان المُستخدم لتخزين الملفات المهمة +Comment[as]=গুৰুত্বপূৰ্ণ নথিপত্ৰ সংৰক্ষণ কৰাৰ স্থান সলনি কৰক +Comment[ast]=Camudar l'allugamientu de ficheros importantes +Comment[be]=Змена тэчак для захавання важных файлаў +Comment[be@latin]=Źmiani miescy, dzie zachoŭvajucca važnyja fajły +Comment[bg]=Настройване местоположението на важните файлове +Comment[bn]=বিভিন্ন গুরুত্বপূর্ণ ফাইল কোন অবস্থানে থাকবে তা পরিবর্তন করুন +Comment[bn_IN]=গুরুত্বপূর্ণ ফাইল সংরক্ষণের স্থান পরিবর্তন করুন +Comment[bs]=Promijenite lokaciju gdje su smješteni važni datoteke +Comment[ca]=Canvia la localització d'on seran desats els fitxers importants +Comment[ca@valencia]=Canvia la localització d'on seran guardats els fitxers importants +Comment[cs]=Změna umístění důležitých souborů +Comment[csb]=Môl trzëmaniô wôżnëch lopków +Comment[cy]=Newid lle mae ffeiliau pwysig yn cael eu cadw +Comment[da]=Ændr stedet hvor vigtige filer gemmes +Comment[de]=Ordner für wichtige Dateien ändern +Comment[el]=Αλλάξτε την τοποθεσία στην οποία αποθηκεύονται σημαντικά αρχεία +Comment[en_GB]=Change the location important files are stored +Comment[eo]=Ŝanĝi la lokon, kie oni konservas gravajn dosierojn +Comment[es]=Cambiar la ubicación de archivos importantes +Comment[et]=Oluliste failide asukoha muutmine +Comment[eu]=Aldatu fitxategi garrantzitsuak gordetzen diren kokalekua +Comment[fa]=تغییر محل ذخیره پرونده‌های مهم +Comment[fi]=Tärkeiden tiedostojen tallennuspaikkojen asetukset +Comment[fy]=Hjir kinne jo de lokaasje fan it bewarjen fan belangrike triemmen wizigje +Comment[ga]=Athraigh an suíomh ina stóráiltear comhaid thábhachtacha +Comment[gl]=Muda o lugar onde se gardan os ficheiros importantes +Comment[gu]=મહત્વની ફાઇલો સંગ્રહ થાય તે સ્થાન બદલો +Comment[he]=שינוי המיקומים בהם מאוחסנים קבצים חשובים +Comment[hi]=महत्वपूर्ण फ़ाइलों के रखने का स्थान बदलें +Comment[hne]=जरूरी फाइल मन के रखे के जगह बदलव +Comment[hr]=Promijenite lokaciju za smještaj važnih datoteka +Comment[hsb]=Městna změnić, hdźež so wažne dataje namakaja +Comment[hu]=Néhány fontosabb elérési utat lehet itt beállítani +Comment[ia]=Modifica le location ubi files importante es immagazinate +Comment[id]=Ubah lokasi berkas penting disimpan +Comment[is]=Breyta staðsetningu mikilvægra skráa +Comment[ka]=მნიშვნელოვანი ფაილბის გეზის ცვლილება შენახულია +Comment[kk]=Маңызды файлдар орналасатын орындарын өзгерту +Comment[km]=ផ្លាស់ប្ដូរ​​ទីតាំង​ដែល​ត្រូវ​ទុក​ឯកសារ​សំខាន់ៗ +Comment[kn]=ಮಖ್ಯ ಕಡತಗಳನ್ನು ಸಂಗ್ರಹಿಸಲಾಗುವ ಸ್ಥಳವನ್ನು ಬದಲಾಯಿಸು +Comment[ko]=중요한 파일이 저장되는 곳 설정 +Comment[ku]=Ciyê ku pelên girîng lê tomar dibin biguherîne +Comment[lt]=Pakeiskite svarbių failų saugojimo vietą +Comment[lv]=Mainīt nozīmīgu failu atrašanās vietas +Comment[mai]=महत्वपूर्ण फाइलसभ केर रखबाक स्थान बदलू +Comment[mk]=Сменете ја локацијата каде што се чуваат важни датотеки +Comment[ml]=പ്രധാനപ്പെട്ട ഫയലുകള്‍ സൂക്ഷിച്ച സ്ഥാനം മാറ്റുക +Comment[mr]=महत्वपूर्ण फाईल संयोजनाचे स्थान बदला +Comment[ms]=Ubah lokasi fail penting disimpan +Comment[nb]=Endre plasseringa av viktige filer +Comment[nds]=Den Oort för wichtige Dateien ännern +Comment[ne]=महत्वपूर्ण फाइल भण्डारण गरिएको स्थान परिवर्तन गर्नुहोस् +Comment[nl]=Hier kunt u de locatie voor het opslaan van belangrijke bestanden wijzigen +Comment[nn]=Endra plasseringa av viktige filer +Comment[or]=ଦରକାରି ଫାଇଲଗୁଡ଼ିକୁ ସଂରକ୍ଷିତ କରାଯାଇଥିବା ସ୍ଥାନକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ +Comment[pa]=ਜ਼ਰੂਰੀ ਫਾਇਲਾਂ ਸੰਭਾਲਣ ਲਈ ਟਿਕਾਣਾ ਤਬਦੀਲ +Comment[pl]=Zmiana miejsca przechowywania ważnych plików +Comment[pt]=Alterar as localizações onde os ficheiros importantes estão guardados +Comment[pt_BR]=Altera o local de armazenamento dos arquivos importantes +Comment[ro]=Modifică locul de stocare a fișierelor importante +Comment[ru]=Пути к важным файлам +Comment[se]=Rievdat báikkiid gosa dehálaš fiillat bidjut +Comment[si]=වැදගත් ගොනු ගබඩා කර ඇති ස්ථානය වෙනස් කරන්න +Comment[sk]=Zmena umiestnenia dôležitých súborov +Comment[sl]=Spremenite mesta shranjevanja pomembnih datotek +Comment[sr]=Промените локацију где су смештени важни фајлови +Comment[sr@ijekavian]=Промијените локацију гдје су смјештени важни фајлови +Comment[sr@ijekavianlatin]=Promijenite lokaciju gdje su smješteni važni fajlovi +Comment[sr@latin]=Promenite lokaciju gde su smešteni važni fajlovi +Comment[sv]=Ändra plats för lagring av viktiga filer +Comment[ta]=முக்கிய கோப்புகள் சேகரிக்கப்பட்டுள்ள இடத்தை மாற்று +Comment[te]=ముఖ్యమైన దస్త్రములు నిల్వవుంచు స్థానమును మార్చుము +Comment[tg]=Ҷойгиршавии файлҳои лозимӣ +Comment[th]=เปลี่ยนตำแหน่งที่เก็บแฟ้มที่สำคัญต่าง ๆ +Comment[tr]=Önemli dosyaların kaydedildiği yerleri düzenle +Comment[ug]=مۇھىم ھۆججەت ساقلايدىغان ئورۇننى ئۆزگەرت +Comment[uk]=Зміна адреси зберігання важливих файлів +Comment[uz]=Muhim fayllarning joylashgan joyini oʻzgartirish +Comment[uz@cyrillic]=Муҳим файлларнинг жойлашган жойини ўзгартириш +Comment[vi]=Thay đổi đường dẫn tới các tập tin quan trọng +Comment[wa]=Candjî l' eplaeçmint ki les fitchîs impôrtants sont wårdés +Comment[xh]=Tshintsha indawo apho zibekwa kona iifayile ezibalulekileyo +Comment[x-test]=xxChange the location important files are storedxx +Comment[zh_CN]=更改重要文件存储的位置 +Comment[zh_TW]=改變儲存重要檔案的位置 +X-KDE-Keywords=konqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,pictures +X-KDE-Keywords[bs]=konqueror, delfin, datoteke, menadžer datoteka, put, putevi, desktop, upute, autostart, preuuzimanja, muzika, dokumenti, filmovi, slike +X-KDE-Keywords[ca]=konqueror,dolphin,fitxers,gestor de fitxers,camí,camins,escriptori,directoris,inici automàtic,baixades,música,documents,pel·lícules,imatges +X-KDE-Keywords[ca@valencia]=konqueror,dolphin,fitxers,gestor de fitxers,camí,camins,escriptori,directoris,inici automàtic,baixades,música,documents,pel·lícules,imatges +X-KDE-Keywords[da]=konqueror,dolphin,filhåndtering,stifinder,stier,skrivebord,mapper,autostart,downoad,hentninger,musik,dokumenter,film,billeder,filer,sti +X-KDE-Keywords[de]=Konqueror,Dolphin,Dateien,Dateimanager,Dateiverwaltung,Pfade,Arbeitsfläche,Verzeichnisse,Ordner,Autostart,Download,Herunterladen,Musik,Dokumente,Filme,Bilder +X-KDE-Keywords[el]=konqueror,dolphin,αρχεία,διαχειριστής αρχείων,διαδρομή, διαδρομές,επιφάνεια εργασίας,κατάλογοι,αυτόματη εκκίνηση,λήψεις,μουσική,έγγραφα,κινηματογραφία,εικόνες +X-KDE-Keywords[en_GB]=konqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,pictures +X-KDE-Keywords[es]=konqueror,dolphin,archivos,gestor de archivos,ruta,rutas,escritorio,directorios,autoinicio,descargas,música,documentos,películas,imágenes +X-KDE-Keywords[et]=konqueror,dolphin,failid,failihaldur,asukohad,töölaud,kataloogid,autostart,allalaadimised,muusika,dokumendid,filmid,pildid +X-KDE-Keywords[eu]=konqueror,dolphin,fitxategi,fitxategi-kudeatzaile,bide-izen, bide-izenak,mahaigain,direktorio,hasi automatikoki,deskargak,musika,dokumentuak,filmak,irudiak +X-KDE-Keywords[fi]=konqueror,dolphin,tiedostot,tiedostonhallinta,polku,polut,työpöytä,hakemistot,kansiot,automaattikäynnistys,lataukset,musiikki,asiakirjat,elokuvat,kuvat +X-KDE-Keywords[fr]=konqueror, dolphin, fichiers, gestionnaire de fichiers, emplacement, emplacements, bureau, dossiers, démarrage automatique, téléchargements, musique, documents, films, images +X-KDE-Keywords[ga]=konqueror,dolphin,comhaid,bainisteoir comhad,conairí,cosáin,deasc,comhadlanna,tosú uathoibríoch,íosluchtuithe,ceol,cáipéisí,scannáin,pictiúir,grianghraif +X-KDE-Keywords[gl]=konqueror, dolphin, ficheiros, xestor de ficheiros, ruta, rutas, escritorio, cartafoles, inicio automático, descargas, música, documentos, películas, imaxes +X-KDE-Keywords[hu]=konqueror,dolphin,fájlok,fájlkezelő,elérési út, elérési utak,asztal,mappák, automatikus indítás,letöltések,zene,dokumentumok,filmek,képek +X-KDE-Keywords[ia]=konqueror,dolphin,files,gerente de file,percurso,percursos,scriptorio,directorios,autoinitio,discargamentos, musica,documentos,pelliculas,photos +X-KDE-Keywords[it]=konqueror,dolphin,file,gestore dei file,percorso,percorsi,desktop,cartelle,avvio automatico,scaricamenti,musica,documenti,film,immagini +X-KDE-Keywords[kk]=konqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,pictures +X-KDE-Keywords[km]=konqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,pictures +X-KDE-Keywords[ko]=konqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,pictures,파일,파일 관리자,탐색기,디렉터리,다운로드,음악,문서,비디오,그림 +X-KDE-Keywords[mr]=कॉन्करर , डॉल्फीन, फाईल्स, फाईल मेनेजर, पाथस , डेस्कटॉप , डीरेक्टरिज , ऑटोस्टार्ट, डाउनलोडस,म्युझिक, डॉक्युमेंट, मूव्हीज, पिक्चर्स +X-KDE-Keywords[nb]=konqueror,dolphin,filer,filbehandler,sti,stier,skrivebord,mapper,autostart,nedlastinger,musikk,dokumenter,filmer,bilder +X-KDE-Keywords[nds]=Konqueror,Dolphin,Dateien,Dateipleger,Padden,Schriefdisch,Ornern,Vertekens,Autostart,Daalladen,Musik,Dokmenten,Filmen,Biller +X-KDE-Keywords[nl]=konqueror,dolphin,bestanden,bestandsbeheerder,pad,paden,bureaublad,mappen,autostart,downloads,muziek,documenten,films,afbeeldingen +X-KDE-Keywords[pl]=konqueror,dolphin,pliki,menadżer plików,ścieżka,ścieżki,pulpit,katalogi,auto-uruchamianie, pobierania,muzyka,dokumenty,filmy,zdjęcia,autostart +X-KDE-Keywords[pt]=konqueror,gestor de ficheiros,localizações,ecrã,pastas,arranque,transferências,música,documentos,filmes,imagens +X-KDE-Keywords[pt_BR]=konqueror,dolphin,arquivos,gerenciador de arquivos,localização,localizações,caminho,caminhos,área de trabalho,pastas,inicialização,downloads,música,documentos,filmes,imagens +X-KDE-Keywords[ru]=konqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,pictures,файлы,диспетчер файлов,путь,местоположение,рабочий стол,директории,каталоги,папки,автозапуск,загрузки,музыка,документы,фильмы,видео,картинки +X-KDE-Keywords[sk]=konqueror,dolphin,súbory,správca súborov,cesta,cesty,plocha,adresáre,automatické spustenie,sťahovania,hudba,dokumenty,filmy,obrázky +X-KDE-Keywords[sl]=konqueror,dolphin,datoteke,upravljalnik datotek,datotečni upravljalnik,poti,namizje,mape,samodejni zagon,prejeto,prejemi,glasba,dokumenti,filmi,slike +X-KDE-Keywords[sr]=konqueror,dolphin,files,filemanager,path,paths,desktop,directories,autostart,downloads,music,documents,movies,pictures,К‑освајач,Делфин,фајлови,менаџер фајлова,путање,путања,површ,фасцикле,самопокретање,преузимање,музика,документи,филмови,слике +X-KDE-Keywords[sr@ijekavian]=konqueror,dolphin,files,filemanager,path,paths,desktop,directories,autostart,downloads,music,documents,movies,pictures,К‑освајач,Делфин,фајлови,менаџер фајлова,путање,путања,површ,фасцикле,самопокретање,преузимање,музика,документи,филмови,слике +X-KDE-Keywords[sr@ijekavianlatin]=konqueror,dolphin,files,filemanager,path,paths,desktop,directories,autostart,downloads,music,documents,movies,pictures,K‑osvajač,Dolphin,fajlovi,menadžer fajlova,putanje,putanja,površ,fascikle,samopokretanje,preuzimanje,muzika,dokumenti,filmovi,slike +X-KDE-Keywords[sr@latin]=konqueror,dolphin,files,filemanager,path,paths,desktop,directories,autostart,downloads,music,documents,movies,pictures,K‑osvajač,Dolphin,fajlovi,menadžer fajlova,putanje,putanja,površ,fascikle,samopokretanje,preuzimanje,muzika,dokumenti,filmovi,slike +X-KDE-Keywords[sv]=konqueror,dolphin,filer,filhanterare,sökväg,sökvägar,skrivbord,kataloger,automatisk start,nerladdningar,musik,dokument,filmer,bilder +X-KDE-Keywords[tr]=konqueror,dolphin,dosyalar,dosya yöneticisi,yol, yollar,masaüstü,dizinler,otomatik başlat,indirmeler,müzik,belgeler,filmler,resimler +X-KDE-Keywords[uk]=konqueror,dolphin,files,filemanager,paths,desktop,directories,autostart,downloads,music,documents,movies,pictures,файл,дельфін,керування,менеджер,шляхи,стільниця,каталог,каталоги,автоматично,автоматичний,запуск,звантаження,завантаження,музика,документи,фільми,відео,зображення,знімки,фотографії +X-KDE-Keywords[x-test]=xxkonqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,picturesxx +X-KDE-Keywords[zh_CN]=konqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,pictures,文件,文件管理器,路径,桌面,目录,自动启动,下载,音乐,文档,电影,图片 +X-KDE-Keywords[zh_TW]=konqueror,dolphin,files,filemanager,path, paths,desktop,directories,autostart,downloads,music,documents,movies,pictures diff --git a/kcontrol/desktoppaths/globalpaths.cpp b/kcontrol/desktoppaths/globalpaths.cpp new file mode 100644 index 00000000..845757af --- /dev/null +++ b/kcontrol/desktoppaths/globalpaths.cpp @@ -0,0 +1,419 @@ +/** + * Copyright (c) Martin R. Jones 1996 + * Copyright (c) Bernd Wuebben 1998 + * Copyright (c) Christian Tibirna 1998 + * Copyright 1998-2007 David Faure + * Copyright (c) 2010 Matthias Fuchs + * + * 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. + */ + +// +// +// "Desktop Options" Tab for KDesktop configuration +// +// (c) Martin R. Jones 1996 +// (c) Bernd Wuebben 1998 +// +// Layouts +// (c) Christian Tibirna 1998 +// Port to KControl, split from Misc Tab, Port to KControl2 +// (c) David Faure 1998 +// Desktop menus, paths +// (c) David Faure 2000 + + +// Own +#include "globalpaths.h" + +// Qt +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kcmdesktoppaths.h" + +//----------------------------------------------------------------------------- + +DesktopPathConfig::DesktopPathConfig(QWidget *parent, const QVariantList &) + : KCModule( KcmDesktopPaths::componentData(), parent ) +{ + QFormLayout *lay = new QFormLayout(this); + lay->setMargin(0); + + setQuickHelp( i18n("

Paths

\n" + "This module allows you to choose where in the filesystem the " + "files on your desktop should be stored.\n" + "Use the \"Whats This?\" (Shift+F1) to get help on specific options.")); + + urDesktop = addRow(lay, i18n("Desktop path:"), + i18n("This folder contains all the files" + " which you see on your desktop. You can change the location of this" + " folder if you want to, and the contents will move automatically" + " to the new location as well.")); + + urAutostart = addRow(lay, i18n("Autostart path:"), + i18n("This folder contains applications or" + " links to applications (shortcuts) that you want to have started" + " automatically whenever KDE starts. You can change the location of this" + " folder if you want to, and the contents will move automatically" + " to the new location as well.")); + + urDocument = addRow(lay, i18n("Documents path:"), + i18n("This folder will be used by default to " + "load or save documents from or to.")); + + urDownload = addRow(lay, i18n("Downloads path:"), + i18n("This folder will be used by default to " + "save your downloaded items.")); + + urMovie = addRow(lay, i18n("Movies path:"), + i18n("This folder will be used by default to " + "load or save movies from or to.")); + + urPicture = addRow(lay, i18n("Pictures path:"), + i18n("This folder will be used by default to " + "load or save pictures from or to.")); + + urMusic = addRow(lay, i18n("Music path:"), + i18n("This folder will be used by default to " + "load or save music from or to.")); +} + +KUrlRequester* DesktopPathConfig::addRow(QFormLayout *lay, const QString& label, const QString& whatsThis) +{ + KUrlRequester* ur = new KUrlRequester(this); + ur->setMode(KFile::Directory | KFile::LocalOnly); + lay->addRow(label, ur); + connect(ur, SIGNAL(textChanged(QString)), this, SLOT(changed())); + lay->labelForField(ur)->setWhatsThis(whatsThis); + ur->setWhatsThis(whatsThis); + return ur; +} + +void DesktopPathConfig::load() +{ + // Desktop Paths + urDesktop->setUrl( KGlobalSettings::desktopPath() ); + urAutostart->setUrl( KGlobalSettings::autostartPath() ); + urDocument->setUrl( KGlobalSettings::documentPath() ); + urDownload->setUrl( KGlobalSettings::downloadPath() ); + urMovie->setUrl( KGlobalSettings::videosPath() ); + urPicture->setUrl( KGlobalSettings::picturesPath() ); + urMusic->setUrl( KGlobalSettings::musicPath() ); + emit changed(false); +} + +void DesktopPathConfig::defaults() +{ + // Desktop Paths - keep defaults in sync with kglobalsettings.cpp + urDesktop->setUrl( QString(QDir::homePath() + "/Desktop") ); + urAutostart->setUrl( QString(KGlobal::dirs()->localkdedir() + "Autostart/") ); + urDocument->setUrl( QString(QDir::homePath() + "/Documents") ); + urDownload->setUrl( QString(QDir::homePath() + "/Downloads") ); + urMovie->setUrl( QString(QDir::homePath() + "/Movies") ); + urPicture->setUrl( QString(QDir::homePath() + "/Pictures") ); + urMusic->setUrl( QString(QDir::homePath() + "/Music") ); +} + +// the following method is copied from kdelibs/kdecore/config/kconfiggroup.cpp +static bool cleanHomeDirPath( QString &path, const QString &homeDir ) +{ +#ifdef Q_WS_WIN //safer + if (!QDir::convertSeparators(path).startsWith(QDir::convertSeparators(homeDir))) + return false; +#else + if (!path.startsWith(homeDir)) + return false; +#endif + + int len = homeDir.length(); + // replace by "$HOME" if possible + if (len && (path.length() == len || path[len] == '/')) { + path.replace(0, len, QString::fromLatin1("$HOME")); + return true; + } else + return false; +} + +// TODO this functionality is duplicated in libkonq - keep it only there and export + +static QString translatePath( QString path ) // krazy:exclude=passbyvalue +{ + // keep only one single '/' at the beginning - needed for cleanHomeDirPath() + while (path[0] == '/' && path[1] == '/') + path.remove(0,1); + + // we probably should escape any $ ` and \ characters that may occur in the path, but the Qt code that reads back + // the file doesn't unescape them so not much point in doing so + + // All of the 3 following functions to return the user's home directory + // can return different paths. We have to test all them. + const QString homeDir0 = QFile::decodeName(qgetenv("HOME")); + const QString homeDir1 = QDir::homePath(); + const QString homeDir2 = QDir(homeDir1).canonicalPath(); + if (cleanHomeDirPath(path, homeDir0) || + cleanHomeDirPath(path, homeDir1) || + cleanHomeDirPath(path, homeDir2) ) { + // kDebug() << "Path was replaced\n"; + } + + return path; +} + +void DesktopPathConfig::save() +{ + KSharedConfig::Ptr config = KGlobal::config(); + KConfigGroup configGroup( config, "Paths" ); + + bool pathChanged = false; + bool autostartMoved = false; + + KUrl desktopURL( KGlobalSettings::desktopPath() ); + + KUrl autostartURL( KGlobalSettings::autostartPath() ); + KUrl newAutostartURL = urAutostart->url(); + + if ( !urDesktop->url().equals( desktopURL, KUrl::CompareWithoutTrailingSlash ) ) + { + // Test which other paths were inside this one (as it is by default) + // and for each, test where it should go. + // * Inside destination -> let them be moved with the desktop (but adjust name if necessary) + // * Not inside destination -> move first + // !!! + kDebug() << "desktopURL=" << desktopURL; + QString urlDesktop = urDesktop->url().toLocalFile(); + if ( !urlDesktop.endsWith('/')) + urlDesktop+='/'; + + if ( desktopURL.isParentOf( autostartURL ) ) + { + kDebug() << "Autostart is on the desktop"; + + // Either the Autostart field wasn't changed (-> need to update it) + if ( newAutostartURL.equals( autostartURL, KUrl::CompareWithoutTrailingSlash ) ) + { + // Hack. It could be in a subdir inside desktop. Hmmm... Argl. + urAutostart->setUrl( QString(urlDesktop + "Autostart/") ); + kDebug() << "Autostart is moved with the desktop"; + autostartMoved = true; + } + // or it has been changed (->need to move it from here) + else + { + KUrl futureAutostartURL; + futureAutostartURL.setUrl( urlDesktop + "Autostart/" ); + if ( newAutostartURL.equals( futureAutostartURL, KUrl::CompareWithoutTrailingSlash ) ) + autostartMoved = true; + else + autostartMoved = moveDir( KUrl( KGlobalSettings::autostartPath() ), KUrl( urAutostart->url() ), i18n("Autostart") ); + } + } + + if ( moveDir( KUrl( KGlobalSettings::desktopPath() ), KUrl( urlDesktop ), i18n("Desktop") ) ) + { + //save in XDG path + const QString userDirsFile(KGlobal::dirs()->localxdgconfdir() + QLatin1String("user-dirs.dirs")); + KConfig xdgUserConf( userDirsFile, KConfig::SimpleConfig ); + KConfigGroup g( &xdgUserConf, "" ); + g.writeEntry( "XDG_DESKTOP_DIR", QString("\"" + translatePath( urlDesktop ) + "\"") ); + pathChanged = true; + } + } + + if ( !newAutostartURL.equals( autostartURL, KUrl::CompareWithoutTrailingSlash ) ) + { + if (!autostartMoved) + autostartMoved = moveDir( KUrl( KGlobalSettings::autostartPath() ), KUrl( urAutostart->url() ), i18n("Autostart") ); + if (autostartMoved) + { + configGroup.writePathEntry( "Autostart", urAutostart->url().toLocalFile(), KConfigBase::Normal | KConfigBase::Global ); + pathChanged = true; + } + } + + config->sync(); + + if (xdgSavePath(urDocument, KGlobalSettings::documentPath(), "XDG_DOCUMENTS_DIR", i18n("Documents"))) + pathChanged = true; + + if (xdgSavePath(urDownload, KGlobalSettings::downloadPath(), "XDG_DOWNLOAD_DIR", i18n("Downloads"))) + pathChanged = true; + + if (xdgSavePath(urMovie, KGlobalSettings::videosPath(), "XDG_VIDEOS_DIR", i18n("Movies"))) + pathChanged = true; + + if (xdgSavePath(urPicture, KGlobalSettings::picturesPath(), "XDG_PICTURES_DIR", i18n("Pictures"))) + pathChanged = true; + + if (xdgSavePath(urMusic, KGlobalSettings::musicPath(), "XDG_MUSIC_DIR", i18n("Music"))) + pathChanged = true; + + if (pathChanged) { + kDebug() << "sending message SettingsChanged"; + KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_PATHS); + } +} + +bool DesktopPathConfig::xdgSavePath(KUrlRequester* ur, const KUrl& currentUrl, const char* xdgKey, const QString& type) +{ + KUrl newUrl = ur->url(); + //url might be empty, use QDir::homePath (the default for xdg) then + if (!newUrl.isValid()) { + newUrl = KUrl(QDir::homePath()); + } + if (!newUrl.equals(currentUrl, KUrl::CompareWithoutTrailingSlash)) { + const QString path = newUrl.toLocalFile(); + if (!QDir(path).exists()) { + // Check permissions + if (KStandardDirs::makeDir(path)) { + QDir().rmdir(path); // rmdir again, so that we get a fast rename + } else { + KMessageBox::sorry(this, KIO::buildErrorString(KIO::ERR_COULD_NOT_MKDIR, path)); + ur->setUrl(currentUrl); // revert + return false; + } + } + if (moveDir(currentUrl, newUrl, type)) { + //save in XDG user-dirs.dirs config file, this is where KGlobalSettings/QDesktopServices reads from. + const QString userDirsFile(KGlobal::dirs()->localxdgconfdir() + QLatin1String("user-dirs.dirs")); + KConfig xdgUserConf(userDirsFile, KConfig::SimpleConfig); + KConfigGroup g(&xdgUserConf, ""); + g.writeEntry(xdgKey, QString("\"" + translatePath(path) + "\"")); + return true; + } + } + return false; +} + +bool DesktopPathConfig::moveDir( const KUrl & src, const KUrl & dest, const QString & type ) +{ + if (!src.isLocalFile() || !dest.isLocalFile()) + return true; + if (!QFile::exists(src.toLocalFile())) + return true; + // Do not move $HOME! #193057 + const QString translatedPath = translatePath(src.toLocalFile()); + if (translatedPath == "$HOME" || translatedPath == "$HOME/") { + return true; + } + + m_ok = true; + + QString question; + KGuiItem yesItem; + KGuiItem noItem; + if (QFile::exists(dest.toLocalFile())) { + // TODO: check if the src dir is empty? Nothing to move, then... + question = i18n("The path for '%1' has been changed.\nDo you want the files to be moved from '%2' to '%3'?", + type, src.toLocalFile(), + dest.toLocalFile()); + yesItem = KGuiItem(i18nc("Move files from old to new place", "Move")); + noItem = KGuiItem(i18nc("Use the new directory but do not move files", "Do not Move")); + } else { + question = i18n("The path for '%1' has been changed.\nDo you want to move the directory '%2' to '%3'?", + type, src.toLocalFile(), + dest.toLocalFile()); + yesItem = KGuiItem(i18nc("Move the directory", "Move")); + noItem = KGuiItem(i18nc("Use the new directory but do not move anything", "Do not Move")); + } + + // Ask for confirmation before moving the files + if (KMessageBox::questionYesNo(this, question, i18n("Confirmation Required"), + yesItem, noItem) + == KMessageBox::Yes ) + { + if (QFile::exists(dest.toLocalFile())) { + // Destination already exists -- should always be the case, for most types, + // but maybe not for the complex autostart case (to be checked...) + m_copyToDest = dest; + m_copyFromSrc = src; + KIO::ListJob* job = KIO::listDir( src ); + job->setAutoDelete(false); // see below + job->ui()->setWindow(this); + job->ui()->setAutoErrorHandlingEnabled(true); + connect(job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)), + this, SLOT(slotEntries(KIO::Job*,KIO::UDSEntryList))); + // slotEntries will move every file/subdir individually into the dest + job->exec(); + if (m_ok) { + QDir().rmdir(src.toLocalFile()); // hopefully it's empty by now + } + delete job; + } + else + { + kDebug() << "Direct move from" << src << "to" << dest; + KIO::Job * job = KIO::move( src, dest ); + job->ui()->setWindow(this); + connect(job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*))); + job->exec(); + } + } + kDebug() << "DesktopPathConfig::slotResult returning " << m_ok; + return m_ok; +} + +void DesktopPathConfig::slotEntries(KIO::Job*, const KIO::UDSEntryList& list) +{ + QListIterator it(list); + while (it.hasNext()) { + KFileItem file(it.next(), m_copyFromSrc, true, true); + kDebug() << file.url(); + if (file.url() == m_copyFromSrc || file.url().fileName() == "..") { + continue; + } + + KIO::Job * moveJob = KIO::move(file.url(), m_copyToDest); + moveJob->ui()->setWindow(this); + connect(moveJob, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*))); + moveJob->exec(); // sub-event loop here. : the main job is not autodeleted because it would be deleted here + } +} + +void DesktopPathConfig::slotResult( KJob * job ) +{ + if (job->error()) { + if ( job->error() != KIO::ERR_DOES_NOT_EXIST ) + m_ok = false; + + // If the source doesn't exist, no wonder we couldn't move the dir. + // In that case, trust the user and set the new setting in any case. + + static_cast(job)->ui()->showErrorMessage(); + } +} + +#include "globalpaths.moc" diff --git a/kcontrol/desktoppaths/globalpaths.h b/kcontrol/desktoppaths/globalpaths.h new file mode 100644 index 00000000..2833a66b --- /dev/null +++ b/kcontrol/desktoppaths/globalpaths.h @@ -0,0 +1,84 @@ +/** + * Copyright (c) Martin R. Jones 1996 + * Copyright 1998-2007 David Faure + * + * 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. + */ + +// Summarized history: +// +// "Desktop Icons Options" Tab for KDesktop configuration +// Martin Jones +// +// Port to KControl, split from "Misc" Tab, Port to KControl2 +// (c) David Faure 1998 +// Desktop menus, paths +// (c) David Faure 2000 + +#ifndef __GLOBALPATHS_H +#define __GLOBALPATHS_H + +#include +#include +#include +#include + +class QFormLayout; +class KJob; +class KUrlRequester; +class QStringList; + +namespace KIO { class Job; } + +//----------------------------------------------------------------------------- +// The "Path" Tab contains : +// The paths for Desktop, Autostart and Documents + +class DesktopPathConfig : public KCModule +{ + Q_OBJECT +public: + DesktopPathConfig( QWidget *parent, const QVariantList &args ); + virtual void load(); + virtual void save(); + virtual void defaults(); + +private Q_SLOTS: + void slotEntries( KIO::Job * job, const KIO::UDSEntryList& list); + +private: + KUrlRequester* addRow(QFormLayout *lay, const QString& label, const QString& whatsThis); + bool xdgSavePath(KUrlRequester* ur, const KUrl& currentUrl, const char* xdgKey, const QString& type); + + // Desktop Paths + KUrlRequester *urDesktop; + KUrlRequester *urAutostart; + KUrlRequester *urDocument; + KUrlRequester *urDownload; + KUrlRequester *urMovie; + KUrlRequester *urPicture; + KUrlRequester *urMusic; + + bool moveDir( const KUrl & src, const KUrl & dest, const QString & type ); + bool m_ok; + KUrl m_copyToDest; // used when the destination directory already exists + KUrl m_copyFromSrc; + +private Q_SLOTS: + void slotResult( KJob * job ); +}; + +#endif + diff --git a/kcontrol/desktoppaths/kcmdesktoppaths.cpp b/kcontrol/desktoppaths/kcmdesktoppaths.cpp new file mode 100644 index 00000000..e7809fe8 --- /dev/null +++ b/kcontrol/desktoppaths/kcmdesktoppaths.cpp @@ -0,0 +1,29 @@ +/* This file is part of the KDE project + Copyright (C) 2006-2007 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "kcmdesktoppaths.h" +#include "globalpaths.h" + +#include +#include + +K_PLUGIN_FACTORY_DEFINITION(KcmDesktopPaths, + registerPlugin("dpath"); + ) +K_EXPORT_PLUGIN(KcmDesktopPaths("kcm_desktoppaths")) diff --git a/kcontrol/desktoppaths/kcmdesktoppaths.h b/kcontrol/desktoppaths/kcmdesktoppaths.h new file mode 100644 index 00000000..0c6295cb --- /dev/null +++ b/kcontrol/desktoppaths/kcmdesktoppaths.h @@ -0,0 +1,27 @@ +/* This file is part of the KDE project + Copyright (C) 2006-2007 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef KCMDESKTOPPATHS_H +#define KCMDESKTOPPATHS_H + +#include + +K_PLUGIN_FACTORY_DECLARATION(KcmDesktopPaths) + +#endif // KCMDESKTOPPATHS_H diff --git a/kcontrol/desktoptheme/CMakeLists.txt b/kcontrol/desktoptheme/CMakeLists.txt new file mode 100644 index 00000000..a93fb41d --- /dev/null +++ b/kcontrol/desktoptheme/CMakeLists.txt @@ -0,0 +1,16 @@ +# Project Needs a name ofcourse +project(desktoptheme) + +set(kcmdesktoptheme_SRCS kcmdesktoptheme.cpp desktopthemedetails.cpp thememodel.cpp) +kde4_add_ui_files(kcmdesktoptheme_SRCS DesktopTheme.ui DesktopThemeDetails.ui) + +kde4_add_plugin(kcm_desktoptheme ${kcmdesktoptheme_SRCS}) +target_link_libraries(kcm_desktoptheme ${X11_LIBRARIES} + ${KDE4_KDEUI_LIBS} ${KDE4_KPARTS_LIBS} ${KDE4_KNEWSTUFF3_LIBS} + ${KDE4_KCMUTILS_LIBRARY} ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS kcm_desktoptheme DESTINATION ${PLUGIN_INSTALL_DIR} ) + +########### install files ############### +install( FILES desktoptheme.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/kcontrol/desktoptheme/DesktopTheme.ui b/kcontrol/desktoptheme/DesktopTheme.ui new file mode 100644 index 00000000..7fe2bf6f --- /dev/null +++ b/kcontrol/desktoptheme/DesktopTheme.ui @@ -0,0 +1,81 @@ + + + DesktopTheme + + + + 0 + 0 + 669 + 460 + + + + + + + 0 + + + + Theme + + + + + + + + + Qt::Horizontal + + + + 462 + 20 + + + + + + + + true + + + Get New Themes... + + + + + + + + Details + + + + + + + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+ + DesktopThemeDetails + QWidget +
desktopthemedetails.h
+ 1 +
+
+ + +
diff --git a/kcontrol/desktoptheme/DesktopThemeDetails.ui b/kcontrol/desktoptheme/DesktopThemeDetails.ui new file mode 100644 index 00000000..9df3536e --- /dev/null +++ b/kcontrol/desktoptheme/DesktopThemeDetails.ui @@ -0,0 +1,395 @@ + + + DesktopThemeItems + + + + 0 + 0 + 661 + 487 + + + + + 0 + 0 + + + + + 200 + 700 + + + + Desktop Theme Details + + + + + + + + + + 0 + 0 + + + + Choose an item and customize it by assigning it a theme + + + You can set any theme to any item. The available themes for the item are in the dropdown box on the right. + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + false + + + false + + + + + + + + 0 + 0 + + + + + + + Enable more options + + + This will expand the dialog and give you options to export your custom theme as well as to remove a theme. + + + More + + + + + + + + + true + + + Remove the selected theme + + + Clicking this button will remove the selected theme. You will be asked for confirmation. + + + Remove Theme + + + + + + + true + + + Save your theme in a zip archive + + + You can save your theme in a zip archive in order to share it with the community. + + + Export Theme to File... + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + Qt::Horizontal + + + + + + + + + New theme name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_newThemeName + + + + + + + Custom theme name + + + Give a name to your custom theme. + + + + + + + Author: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_newThemeAuthor + + + + + + + Custom theme author + + + Enter the author name of your custom theme. + + + + + + + Version: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_newThemeVersion + + + + + + + Custom theme version number + + + Enter the version number of your custom theme. + + + + + + + + + + + Description: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_newThemeDescription + + + + + + + + 0 + 0 + + + + Custom theme description + + + Enter a description which will explain your custom theme. + + + + + + + + + + + + Qt::Vertical + + + + + + + Select theme from above to customize + + + + + + + + 0 + 0 + + + + + + + + + Theme Author + + + Qt::AlignLeading + + + + + + + + 75 + true + + + + Theme Name + + + Qt::AlignCenter + + + + + + + Theme Version + + + Qt::AlignRight + + + + + + + + + The theme description goes here... + + + Qt::AlignCenter + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 130 + + + + + + + + + 187 + 187 + 187 + + + + + + + + + 187 + 187 + 187 + + + + + + + + + 255 + 255 + 255 + + + + + + + + Available themes + + + Choose a start theme in this list then customize some items below. All less important items not listed below will use this start theme. + + + Qt::ScrollBarAlwaysOff + + + false + + + QListView::IconMode + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+
+ + +
diff --git a/kcontrol/desktoptheme/Messages.sh b/kcontrol/desktoptheme/Messages.sh new file mode 100755 index 00000000..14b32ad9 --- /dev/null +++ b/kcontrol/desktoptheme/Messages.sh @@ -0,0 +1,4 @@ +#! /bin/sh +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/kcm_desktopthemedetails.pot +rm -f rc.cpp diff --git a/kcontrol/desktoptheme/desktoptheme.desktop b/kcontrol/desktoptheme/desktoptheme.desktop new file mode 100644 index 00000000..756bd032 --- /dev/null +++ b/kcontrol/desktoptheme/desktoptheme.desktop @@ -0,0 +1,187 @@ +[Desktop Entry] +Exec=kcmshell4 desktoptheme +Icon=preferences-desktop +Type=Service + +X-KDE-ServiceTypes=KCModule +X-KDE-Library=kcm_desktoptheme +X-KDE-ParentApp=kcontrol +X-KDE-System-Settings-Parent-Category=desktop-appearance +X-DocPath=kcontrol/desktopthemedetails/index.html + +Name=Desktop Theme +Name[ar]=سمة سطح المكتب +Name[ast]=Tema d'escritoriu +Name[bg]=Тема за работния плот +Name[bn]=ডেস্কটপ থীম +Name[bs]=Tema površi +Name[ca]=Tema d'escriptori +Name[ca@valencia]=Tema d'escriptori +Name[cs]=Motiv plochy +Name[da]=Skrivebordstema +Name[de]=Arbeitsflächen-Design +Name[el]=Θέμα επιφάνειας εργασίας +Name[en_GB]=Desktop Theme +Name[es]=Tema de escritorio +Name[et]=Töölauateema +Name[eu]=Mahaigaineko gaia +Name[fi]=Työpöytäteema +Name[fr]=Thème de bureau +Name[ga]=Téama Deisce +Name[gl]=Tema do escritorio +Name[gu]=ડેસ્કટોપ થીમ +Name[he]=ערכת־הנושא לשולחן־העבודה +Name[hi]=डेस्कटॉप प्रसंग +Name[hr]=Tema radne površine +Name[hu]=Asztali téma +Name[ia]=Thema de scriptorio +Name[id]=Tema Desktop +Name[is]=Skjáborðsþema +Name[it]=Tema del desktop +Name[ja]=デスクトップテーマ +Name[kk]=Үстел нақышы +Name[km]=ស្បែក​ផ្ទៃតុ +Name[kn]=ಗಣಕತೆರೆ ಪರಿಸರವಿನ್ಯಾಸ +Name[ko]=데스크톱 테마 +Name[lt]=Darbastalio tema +Name[lv]=Darbvirsmas tēma +Name[mr]=डेस्कटॉप शैली +Name[nb]=Skrivebordstema +Name[nds]=Schriefdischmuster +Name[nl]=Bureaubladthema +Name[nn]=Skrivebordstema +Name[pa]=ਡੈਸਕਟਾਪ ਥੀਮ +Name[pl]=Wystrój pulpitu +Name[pt]=Tema do Ambiente de Trabalho +Name[pt_BR]=Tema da área de trabalho +Name[ro]=Tematica de birou +Name[ru]=Тема рабочего стола +Name[si]=වැඩතල තේමාව +Name[sk]=Téma plochy +Name[sl]=Namizna tema +Name[sr]=Тема површи +Name[sr@ijekavian]=Тема површи +Name[sr@ijekavianlatin]=Tema površi +Name[sr@latin]=Tema površi +Name[sv]=Skrivbordstema +Name[tg]=Мавзӯъи мизи корӣ +Name[th]=ชุดตกแต่งพื้นที่ทำงาน +Name[tr]=Masaüstü Teması +Name[ug]=ئۈستەلئۈستى ئۆرنىكى +Name[uk]=Тема стільниці +Name[vi]=Sắc thái màn hình +Name[wa]=Tinme do scribanne +Name[x-test]=xxDesktop Themexx +Name[zh_CN]=桌面主题 +Name[zh_TW]=桌面主題 +Comment=Customize the desktop theme +Comment[ar]=خصص عناصر السمة سطح المكتب بشكل منفرد +Comment[ast]=Personalizar el tema d'escritoriu +Comment[bg]=Настройки на теми за работния плот +Comment[bn]=ডেস্কটপ থীম পছন্দমত বদলান +Comment[bs]=Prilagodite temu površi +Comment[ca]=Personalitza el tema d'escriptori +Comment[ca@valencia]=Personalitza el tema d'escriptori +Comment[cs]=Upravit vzhled plochy +Comment[da]=Tilpas skrivebordstemaet +Comment[de]=Arbeitsflächen-Design anpassen +Comment[el]=Προσαρμογή θέματος της επιφάνειας εργασίας +Comment[en_GB]=Customise the desktop theme +Comment[es]=Personalizar el tema de escritorio +Comment[et]=Töölauateema kohandamine +Comment[eu]=Pertsonalizatu mahaigaineko gaia +Comment[fi]=Työpöytäteeman asetukset +Comment[ga]=Saincheap an téama deisce +Comment[gl]=Personaliza o tema do escritorio +Comment[he]=התאמה אישית של ערכת־הנושא לשולחן־העבודה +Comment[hi]=डेस्कटॉप प्रसंग मनपसंद बनाएँ +Comment[hr]=Prilagodba teme radne površine +Comment[hu]=Az asztali téma testreszabása +Comment[ia]=Personalisar le thema de scriptorio +Comment[id]=Sesuaikan tema desktop +Comment[is]=Sérsníða skjáborðsþema +Comment[kk]=Үстел нақышын өзінше баптап алу +Comment[km]=ប្ដូរ​ស្បែក​ផ្ទៃតុ​តាមបំណង +Comment[kn]=ಗಣಕತೆರೆ ಪರಿಸರವಿನ್ಯಾಸವನ್ನು ಇಚ್ಛೆಗೆ ತಕ್ಕಂತೆ ಹೊಂದಿಸಿ +Comment[ko]=테마 사용자 정의 +Comment[lt]=Derinti darbastalio temą +Comment[lv]=Pielāgot darbivrsmas tēmu +Comment[mr]=डेस्कटॉप शैलीत ऐच्छिक बदल करा +Comment[nb]=Still inn temaet for skrivebordet +Comment[nds]=Dat Schriefdischmuster topassen +Comment[nl]=Pas het bureaubladthema aan +Comment[nn]=Tilpass skrivebordstemaet +Comment[pa]=ਡੈਸਕਟਾਪ ਥੀਮ ਕਸਟਮਾਈਜ਼ ਕਰੋ +Comment[pl]=Dostosowywanie wystroju pulpitu +Comment[pt]=Personalizar o tema do ambiente de trabalho +Comment[pt_BR]=Personaliza o tema da área de trabalho +Comment[ro]=Particularizează tematica de birou +Comment[ru]=Настройка темы рабочего стола +Comment[si]=වැඩතල තේමාව රිසිකරණය කරන්න +Comment[sk]=Prispôsobenie témy plochy +Comment[sl]=Prilagodite namizno temo +Comment[sr]=Прилагодите тему површи +Comment[sr@ijekavian]=Прилагодите тему површи +Comment[sr@ijekavianlatin]=Prilagodite temu površi +Comment[sr@latin]=Prilagodite temu površi +Comment[sv]=Anpassa skrivbordstemat +Comment[tg]=Танзимоти мавзӯъи мизи корӣ +Comment[th]=ปรับแต่งชุดตกแต่งพื้นที่ทำงานด้วยตนเอง +Comment[tr]=Masaüstü temasını özelleştir +Comment[ug]=ئۈستەلئۈستى ئۆرنىكىنى ئۆزلەشتۈرىدۇ +Comment[uk]=Налаштування теми стільниці +Comment[vi]=Tuỳ chỉnh sắc thái màn hình +Comment[wa]=Mete a vosse môde li tinme do scribanne +Comment[x-test]=xxCustomize the desktop themexx +Comment[zh_CN]=定制桌面主题 +Comment[zh_TW]=自訂桌面主題 +X-KDE-Keywords=Desktop Theme +X-KDE-Keywords[ar]=سمة سطح المكتب +X-KDE-Keywords[bs]=Tema površi +X-KDE-Keywords[ca]=Tema d'escriptori +X-KDE-Keywords[ca@valencia]=Tema d'escriptori +X-KDE-Keywords[cs]=Motiv plochy +X-KDE-Keywords[da]=Skrivebordstema +X-KDE-Keywords[de]=Arbeitsflächen-Design +X-KDE-Keywords[el]=Θέμα επιφάνειας εργασίας +X-KDE-Keywords[en_GB]=Desktop Theme +X-KDE-Keywords[es]=Tema de escritorio +X-KDE-Keywords[et]=Töölauateema +X-KDE-Keywords[eu]=Mahaigaineko gaia +X-KDE-Keywords[fi]=Työpöytäteema +X-KDE-Keywords[fr]=Thème du bureau +X-KDE-Keywords[ga]=Téama Deisce +X-KDE-Keywords[gl]=Tema do escritorio +X-KDE-Keywords[he]=ערכת־הנושא +X-KDE-Keywords[hu]=Asztali téma +X-KDE-Keywords[ia]=Thema de scriptorio +X-KDE-Keywords[is]=Skjáborðsþema +X-KDE-Keywords[it]=Tema del desktop +X-KDE-Keywords[kk]=Desktop Theme,Үстел нақышы +X-KDE-Keywords[km]=រូបរាង​ផ្ទៃតុ +X-KDE-Keywords[ko]=데스크톱 테마 +X-KDE-Keywords[lt]=Darbastalio tema +X-KDE-Keywords[mr]=डेस्कटॉप शैली +X-KDE-Keywords[nb]=Skrivebordstema +X-KDE-Keywords[nds]=Schriefdischmuster +X-KDE-Keywords[nl]=Bureaubladthema +X-KDE-Keywords[pa]=ਡੈਸਕਟਾਪ ਥੀਮ +X-KDE-Keywords[pl]=Wystrój pulpitu +X-KDE-Keywords[pt]=Tema do Ambiente de Trabalho +X-KDE-Keywords[pt_BR]=Tema da área de trabalho +X-KDE-Keywords[ro]=Tematica de birou +X-KDE-Keywords[ru]=Тема рабочего стола +X-KDE-Keywords[sk]=Téma plochy +X-KDE-Keywords[sl]=Namizna tema +X-KDE-Keywords[sr]=Desktop Theme,тема површи +X-KDE-Keywords[sr@ijekavian]=Desktop Theme,тема површи +X-KDE-Keywords[sr@ijekavianlatin]=Desktop Theme,tema površi +X-KDE-Keywords[sr@latin]=Desktop Theme,tema površi +X-KDE-Keywords[sv]=Skrivbordstema +X-KDE-Keywords[tr]=Masaüstü Teması +X-KDE-Keywords[ug]=ئۈستەلئۈستى ئۆرنىكى +X-KDE-Keywords[uk]=тема,стільниця +X-KDE-Keywords[vi]=Sắc thái màn hình +X-KDE-Keywords[x-test]=xxDesktop Themexx +X-KDE-Keywords[zh_CN]=Desktop Theme,桌面主题 +X-KDE-Keywords[zh_TW]=Desktop Theme diff --git a/kcontrol/desktoptheme/desktopthemedetails.cpp b/kcontrol/desktoptheme/desktopthemedetails.cpp new file mode 100644 index 00000000..295edd92 --- /dev/null +++ b/kcontrol/desktoptheme/desktopthemedetails.cpp @@ -0,0 +1,582 @@ +/* + Copyright (c) 2008 Andrew Lake + Copyright (c) 2010 Jeremy Whiting + + 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. +*/ + +#include "desktopthemedetails.h" + +#include "thememodel.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ThemeItemNameType { + const char* m_type; + const char* m_displayItemName; + const char* m_themeItemPath; + const char* m_iconName; +}; + +const ThemeItemNameType themeCollectionName[] = { + { "Color Scheme", I18N_NOOP2("plasma name", "Color Scheme"),"colors", "preferences-desktop-color"}, + { "Panel Background", I18N_NOOP2("plasma name", "Panel Background"),"widgets/panel-background", "plasma"}, + { "Kickoff", I18N_NOOP2("plasma name", "Kickoff"), "dialogs/kickoff", "kde"}, + { "Task Items", I18N_NOOP2("plasma name", "Task Items"), "widgets/tasks", "preferences-system-windows"}, + { "Widget Background", I18N_NOOP2("plasma name", "Widget Background"), "widgets/background", "plasma"}, + { "Translucent Background", I18N_NOOP2("plasma name", "Translucent Background"), "widgets/translucentbackground", "plasma"}, + { "Dialog Background", I18N_NOOP2("plasma name", "Dialog Background"), "dialogs/background", "plasma"}, + { "Analog Clock", I18N_NOOP2("plasma name", "Analog Clock"), "widgets/clock", "chronometer"}, + { "Notes", I18N_NOOP2("plasma name", "Notes"), "widgets/notes", "view-pim-notes"}, + { "Tooltip", I18N_NOOP2("plasma name", "Tooltip"), "widgets/tooltip", "plasma"}, + { "Pager", I18N_NOOP2("plasma name", "Pager"), "widgets/pager", "plasma"}, + { "Run Command Dialog", I18N_NOOP2("plasma name", "Run Command Dialog"), "dialogs/krunner", "system-run"}, + { "Shutdown Dialog", I18N_NOOP2("plasma name", "Shutdown Dialog"), "dialogs/shutdowndialog", "system-shutdown"}, + { "Icons", I18N_NOOP2("plasma name", "Icons"), "icons/", "preferences-desktop-icons"}, + { 0, 0,0,0 } // end of data +}; + + +DesktopThemeDetails::DesktopThemeDetails(QWidget* parent) + : QWidget(parent), + m_themeModel(0) + +{ + setWindowIcon(KIcon("preferences-desktop")); + setupUi(this); + + QFont font = QFont(); + font.setBold(true); + font.setPointSize(1.2*font.pointSize()); + m_themeInfoName->setFont(font); + + m_enableAdvanced->setChecked(false); + toggleAdvancedVisible(); + + + m_themeModel = new ThemeModel(this); + m_theme->setModel(m_themeModel); + m_theme->setItemDelegate(new ThemeDelegate(m_theme)); + + reloadConfig(); + + connect(m_theme->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(themeSelectionChanged(QItemSelection,QItemSelection))); + + connect(m_enableAdvanced, SIGNAL(toggled(bool)), this, SLOT(toggleAdvancedVisible())); + connect(m_removeThemeButton, SIGNAL(clicked()), this, SLOT(removeTheme())); + connect(m_exportThemeButton, SIGNAL(clicked()), this, SLOT(exportTheme())); + + connect(m_newThemeName, SIGNAL(editingFinished()), this, SLOT(newThemeInfoChanged())); + + m_baseTheme = "default"; + m_themeCustomized = false; + resetThemeDetails(); + adjustSize(); +} + +DesktopThemeDetails::~DesktopThemeDetails() +{ + cleanup(); +} + +void DesktopThemeDetails::cleanup() +{ +} + +void DesktopThemeDetails::reloadConfig() +{ + // Theme + KConfigGroup cfg = KConfigGroup(KSharedConfig::openConfig("plasmarc"), "Theme"); + const QString theme = cfg.readEntry("name", "default"); + m_theme->setCurrentIndex(m_themeModel->indexOf(theme)); + +} + +void DesktopThemeDetails::save() +{ + QString themeRoot; + KStandardDirs dirs; + if (m_newThemeName->text().isEmpty()) { + themeRoot = ".customized"; + //Toggle customized theme directory name to ensure theme reload + if (QDir(dirs.locateLocal("data", "desktoptheme/" + themeRoot + '/', false)).exists()) { + themeRoot = themeRoot + '1'; + } + } else { + themeRoot = m_newThemeName->text().replace(' ',"_").remove(QRegExp("[^A-Za-z0-9_]")); + } + + //Save theme items + QFile customSettingsFile; + bool customSettingsFileOpen = false; + + if (m_themeCustomized || !m_newThemeName->text().isEmpty()) { + + clearCustomized(themeRoot); + + //Copy all files from the base theme + QString baseSource = dirs.locate("data", "desktoptheme/" + m_baseTheme + "/metadata.desktop"); + baseSource = baseSource.left(baseSource.lastIndexOf('/', -1)); + KIO::CopyJob *copyBaseTheme = KIO::copyAs(KUrl(baseSource), KUrl(dirs.locateLocal("data", "desktoptheme/" + themeRoot, true)), KIO::HideProgressInfo); + KIO::NetAccess::synchronousRun(copyBaseTheme, this); + + //Prepare settings file for customized theme + if (isCustomized(themeRoot)) { + customSettingsFile.setFileName(dirs.locateLocal("data", "desktoptheme/" + themeRoot + "/settings")); + customSettingsFileOpen = customSettingsFile.open(QFile::WriteOnly); + if (customSettingsFileOpen) { + QTextStream out(&customSettingsFile); + out << "baseTheme=" + m_baseTheme + "\r\n";; + } + } + QString settingsSource; + + //Copy each item theme file to new theme folder + QHashIterator i(m_itemThemeReplacements); + while (i.hasNext()) { + i.next(); + //Get root directory where item should reside (relative to theme root) + QString itemRoot = ""; + if (m_itemPaths[i.key()].lastIndexOf('/', -1) != -1) { + itemRoot= m_itemPaths[i.key()].left(m_itemPaths[i.key()].lastIndexOf('/', -1)); + } + //Setup source and destination + QString source; + QString dest; + if (i.value() != -1) { + //Source is a theme + source = "desktoptheme/" + m_themeRoots[i.value()] + '/' + m_itemPaths[i.key()] + '*'; + dest = "desktoptheme/" + themeRoot + '/' + itemRoot + '/'; + settingsSource = m_themeRoots[i.value()]; + } else { + //Source is a file + source = m_itemFileReplacements[i.key()]; + dest = "desktoptheme/" + themeRoot + '/' + itemRoot + '/'; + settingsSource = m_itemFileReplacements[i.key()]; + } + + + //Delete item files at destination before copying (possibly there from base theme copy) + const QStringList deleteFiles = dirs.findAllResources("data", "desktoptheme/" + themeRoot + '/' + m_itemPaths[i.key()] + '*', + KStandardDirs::NoDuplicates); + for (int j = 0; j < deleteFiles.size(); ++j) { + KIO::DeleteJob *dj = KIO::del(KUrl(deleteFiles.at(j)), KIO::HideProgressInfo); + KIO::NetAccess::synchronousRun(dj, this); + } + + //Copy item(s) + dest = dirs.locateLocal("data", dest, true); + QStringList copyFiles; + if (i.value() != -1) { + copyFiles = dirs.findAllResources("data", source, KStandardDirs::NoDuplicates); //copy from theme + } else { + copyFiles << source; //copy from file + } + for (int j = 0; j < copyFiles.size(); ++j) { + KIO::CopyJob *cj = KIO::copy(KUrl(copyFiles.at(j)), KUrl(dest), KIO::HideProgressInfo); + KIO::NetAccess::synchronousRun(cj, this); + } + + //Record settings file + if (customSettingsFileOpen) { + QTextStream out(&customSettingsFile); + out << m_items.key(i.key()) + "=" + settingsSource +"\r\n"; + } + } + if (customSettingsFileOpen) customSettingsFile.close(); + + // Create new theme FDO desktop file + QFile::remove(dirs.locateLocal("data", "desktoptheme/" + themeRoot + "/metadata.desktop", false)); + KDesktopFile df(dirs.locateLocal("data", "desktoptheme/" + themeRoot + "/metadata.desktop")); + KConfigGroup cg = df.desktopGroup(); + if (isCustomized(themeRoot)) { + cg.writeEntry("Name",i18n("(Customized)")); + cg.writeEntry("Comment", i18n("User customized theme")); + cg.writeEntry("X-KDE-PluginInfo-Name", themeRoot); + } else { + cg.writeEntry("Name", m_newThemeName->text()); + cg.writeEntry("Comment", m_newThemeDescription->text()); + cg.writeEntry("X-KDE-PluginInfo-Author", m_newThemeAuthor->text()); + cg.writeEntry("X-KDE-PluginInfo-Version", m_newThemeVersion->text()); + } + cg.sync(); + + m_themeCustomized = false; + } + + m_themeModel->reload(); + if (m_themeModel->indexOf(themeRoot).isValid()) { + m_theme->setCurrentIndex(m_themeModel->indexOf(themeRoot)); + QString themeName = m_theme->currentIndex().data(Qt::DisplayRole).toString(); + setDesktopTheme(themeRoot); + } + resetThemeDetails(); +} + +void DesktopThemeDetails::removeTheme() +{ + bool removeTheme = true; + KConfigGroup cfg = KConfigGroup(KSharedConfig::openConfig("plasmarc"), "Theme"); + QString activeTheme = cfg.readEntry("name", "default"); + const QString theme = m_theme->currentIndex().data(ThemeModel::PackageNameRole).toString(); + const QString themeName = m_theme->currentIndex().data(Qt::DisplayRole).toString(); + + + if (m_themeCustomized) { + if(KMessageBox::questionYesNo(this, i18n("Theme items have been changed. Do you still wish remove the \"%1\" theme?", themeName), i18n("Remove Desktop Theme")) == KMessageBox::No) { + removeTheme = false; + } + } else { + if (theme == "default") { + KMessageBox::information(this, i18n("Removal of the default desktop theme is not allowed."), i18n("Remove Desktop Theme")); + removeTheme = false; + } else { + if(KMessageBox::questionYesNo(this, i18n("Are you sure you wish remove the \"%1\" theme?", themeName), i18n("Remove Desktop Theme")) == KMessageBox::No) { + removeTheme = false; + } + } + + } + KStandardDirs dirs; + if (removeTheme) { + if (theme == activeTheme) { + setDesktopTheme("default"); + activeTheme = "default"; + } + if (QDir(dirs.locateLocal("data", "desktoptheme/" + theme, false)).exists()) { + KIO::DeleteJob *deleteTheme = KIO::del(KUrl(dirs.locateLocal("data", "desktoptheme/" + theme, false)), KIO::HideProgressInfo); + KIO::NetAccess::synchronousRun(deleteTheme, this); + } + } + m_themeModel->reload(); + reloadConfig(); + m_theme->setCurrentIndex(m_themeModel->indexOf(activeTheme)); +} + +void DesktopThemeDetails::exportTheme() +{ + const QString theme = m_theme->currentIndex().data(ThemeModel::PackageNameRole).toString(); + + if (m_themeCustomized || + (isCustomized(theme) && m_newThemeName->text() == "")) { + KMessageBox::information(this, i18n("Please apply theme item changes (with a new theme name) before attempting to export theme."), i18n("Export Desktop Theme")); + } else { + QString themeStoragePath = theme; + + KStandardDirs dirs; + const QString themePath = dirs.findResource("data", "desktoptheme/" + themeStoragePath + "/metadata.desktop"); + if (!themePath.isEmpty()){ + QString expFileName = KFileDialog::getSaveFileName(KUrl(), "*.zip", this, i18n("Export theme to file")); + if (!expFileName.endsWith(".zip")) + expFileName = expFileName + ".zip"; + if (!expFileName.isEmpty()) { + KUrl path(themePath); + KZip expFile(expFileName); + expFile.open(QIODevice::WriteOnly); + expFile.addLocalDirectory(path.directory (), themeStoragePath); + expFile.close(); + } + } + } + +} + +void DesktopThemeDetails::loadThemeItems() +{ + // Set up items, item paths and icons + m_items.clear(); // clear theme items + m_itemPaths.clear(); // clear theme item paths + m_itemIcons.clear(); + for (int i = 0; themeCollectionName[i].m_type; ++i) { + m_items[themeCollectionName[i].m_type] = i; + m_itemPaths[i] = themeCollectionName[i].m_themeItemPath; + m_itemIcons[i] = themeCollectionName[i].m_iconName; + } + + // Get installed themes + m_themes.clear(); // clear installed theme list + m_themeRoots.clear(); // clear installed theme root paths + KStandardDirs dirs; + QStringList themes = dirs.findAllResources("data", "desktoptheme/*/metadata.desktop", + KStandardDirs::NoDuplicates); + themes.sort(); + int j=0; + for (int i = 0; i < themes.size(); ++i) { + QString theme = themes.at(i); + int themeSepIndex = theme.lastIndexOf('/', -1); + QString themeRoot = theme.left(themeSepIndex); + int themeNameSepIndex = themeRoot.lastIndexOf('/', -1); + QString packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1); + KDesktopFile df(theme); + QString name = df.readName(); + if (name.isEmpty()) { + name = packageName; + } + + if (!isCustomized(packageName) && (m_themeRoots.key(packageName, -1) == -1)) { + m_themes[name] = j; + m_themeRoots[j] = packageName; + ++j; + } + } + + // Set up default item replacements + m_itemThemeReplacements.clear(); + m_itemFileReplacements.clear(); + QString currentTheme = m_theme->currentIndex().data(ThemeModel::PackageNameRole).toString(); + + if (!isCustomized(currentTheme)) { + // Set default replacements to current theme + QHashIterator i(m_items); + while (i.hasNext()) { + i.next(); + m_itemThemeReplacements[i.value()] = m_themeRoots.key(currentTheme); + } + m_baseTheme = currentTheme; + } else { + // Set default replacements to customized theme settings + QFile customSettingsFile(dirs.locateLocal("data", "desktoptheme/" + currentTheme +"/settings")); + if (customSettingsFile.open(QFile::ReadOnly)) { + QTextStream in(&customSettingsFile); + QString line; + QStringList settingsPair; + while (!in.atEnd()) { + line = in.readLine(); + settingsPair = line.split('='); + if (settingsPair.at(0) == "baseTheme") { + m_baseTheme = settingsPair.at(1); + } else { + if (m_themeRoots.key(settingsPair.at(1), -1) != -1) { // theme for current item exists + m_itemThemeReplacements[m_items[settingsPair.at(0)]] = m_themeRoots.key(settingsPair.at(1)); + } else if (QFile::exists(settingsPair.at(1))) { + m_itemThemeReplacements[m_items[settingsPair.at(0)]] = -1; + m_itemFileReplacements[m_items[settingsPair.at(0)]] = settingsPair.at(1); + } + } + } + customSettingsFile.close(); + } + } + + // Build displayed list of theme items + m_themeItemList->setRowCount(m_items.size()); + m_themeItemList->setColumnCount(2); + m_themeItemList->setHorizontalHeaderLabels(QStringList()<< i18n("Theme Item")< i(m_items); + while (i.hasNext()) { + i.next(); + displayedItem = displayedItemText(i.value()); + m_themeItemList->setItem(i.value(), 0, new QTableWidgetItem(displayedItem)); + m_themeItemList->item(i.value(),0)->setIcon(KIcon(m_itemIcons[i.value()])); + m_themeItemList->setCellWidget(i.value(), 1, new QComboBox()); + updateReplaceItemList(i.value()); + m_themeItemList->resizeColumnToContents(1); + } + m_themeItemList->setSelectionBehavior(QAbstractItemView::SelectRows); + m_themeItemList->verticalHeader()->hide(); + m_themeItemList->horizontalHeader()->setStretchLastSection(true); + m_themeItemList->horizontalHeader()->setMinimumSectionSize(120); + m_themeItemList->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents);; + m_themeItemList->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);; + m_themeItemList->setCurrentCell(0, 1); +} + +void DesktopThemeDetails::updateReplaceItemList(const int& item) +{ + QString currentTheme = m_theme->currentIndex().data(ThemeModel::PackageNameRole).toString(); + + + // Repopulate combobox droplist + QComboBox *itemComboBox = static_cast(m_themeItemList->cellWidget(item,1)); + disconnect(itemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(replacementItemChanged())); + itemComboBox->clear(); + for (int i = 0; i < m_themes.size(); ++i) { + QString displayedDropListItem = i18n("%1 %2", m_themes.key(i), displayedItemText(item)); + itemComboBox->addItem(displayedDropListItem); + } + itemComboBox->addItem(i18n("File...")); + + // Set combobox value to current replacement + if (m_itemThemeReplacements[item] != -1) { + itemComboBox->setCurrentIndex(m_itemThemeReplacements[item]); + } else { + itemComboBox->addItem(m_itemFileReplacements[item]); + itemComboBox->setCurrentIndex(itemComboBox->findText(m_itemFileReplacements[item])); + } + connect(itemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(replacementItemChanged())); +} + +void DesktopThemeDetails::replacementItemChanged() +{ + //Check items to see if theme has been customized + m_themeCustomized = true; + QHashIterator i(m_items); + while (i.hasNext()) { + i.next(); + QComboBox *itemComboBox = static_cast(m_themeItemList->cellWidget(i.value(), 1)); + int replacement = itemComboBox->currentIndex(); + if (replacement <= (m_themes.size() - 1)) { + // Item replacement source is a theme + m_itemThemeReplacements[i.value()] = itemComboBox->currentIndex(); + } else if (replacement > (m_themes.size() - 1)) { + // Item replacement source is a file + if (itemComboBox->currentText() == i18n("File...")) { + //Get the filename for the replacement item + QString translated_key = i18nc("plasma name", qPrintable( i.key() ) ); + QString fileReplacement = KFileDialog::getOpenFileName(KUrl(), QString(), this, i18n("Select File to Use for %1",translated_key)); + if (!fileReplacement.isEmpty()) { + m_itemFileReplacements[i.value()] = fileReplacement; + int index = itemComboBox->findText(fileReplacement); + if (index == -1) itemComboBox->addItem(fileReplacement); + disconnect(itemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(replacementItemChanged())); + itemComboBox->setCurrentIndex(itemComboBox->findText(fileReplacement)); + connect(itemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(replacementItemChanged())); + m_itemThemeReplacements[i.value()] = -1; //source is not a theme + m_itemFileReplacements[i.value()] = itemComboBox->currentText(); + } else { + // Reset combobox to previous value if no file is selected + if (m_itemThemeReplacements[i.value()] != -1) { + itemComboBox->setCurrentIndex(m_itemThemeReplacements[i.value()]); + } else { + itemComboBox->setCurrentIndex(itemComboBox->findText(m_itemFileReplacements[i.value()])); + } + m_themeCustomized = false; + } + } else { + m_itemThemeReplacements[i.value()] = -1; //source is not a theme + m_itemFileReplacements[i.value()] = itemComboBox->currentText(); + } + } + } + + if (m_themeCustomized) emit changed(); +} + +void DesktopThemeDetails::newThemeInfoChanged() +{ + emit changed(); +} + +void DesktopThemeDetails::resetThemeDetails() +{ + QString theme = m_theme->currentIndex().data(ThemeModel::PackageNameRole).toString(); + + m_themeInfoName->setText(m_theme->currentIndex().data(Qt::DisplayRole).toString()); + m_themeInfoDescription->setText(m_theme->currentIndex().data(ThemeModel::PackageDescriptionRole).toString()); + QString author = m_theme->currentIndex().data(ThemeModel::PackageAuthorRole).toString(); + + if (!author.isEmpty()) { + m_themeInfoAuthor->setText(i18n(" Author: %1",author)); + } else { + m_themeInfoAuthor->setText(""); + } + QString version = m_theme->currentIndex().data(ThemeModel::PackageVersionRole).toString(); + if (!version.isEmpty()) { + m_themeInfoVersion->setText(i18n("Version: %1",version)); + } else { + m_themeInfoVersion->setText(""); + } + + loadThemeItems(); + + m_newThemeName->clear(); + m_newThemeAuthor->clear(); + m_newThemeVersion->clear(); + m_newThemeDescription->clear(); + m_themeCustomized = false; + } + +void DesktopThemeDetails::toggleAdvancedVisible() +{ + m_newThemeNameLabel->setVisible(m_enableAdvanced->isChecked()); + m_newThemeName->setVisible(m_enableAdvanced->isChecked()); + m_newThemeAuthor->setVisible(m_enableAdvanced->isChecked()); + m_newThemeAuthorLabel->setVisible(m_enableAdvanced->isChecked()); + m_newThemeVersion->setVisible(m_enableAdvanced->isChecked()); + m_newThemeVersionLabel->setVisible(m_enableAdvanced->isChecked()); + m_newThemeDescriptionLabel->setVisible(m_enableAdvanced->isChecked()); + m_newThemeDescription->setVisible(m_enableAdvanced->isChecked()); + m_exportThemeButton->setVisible(m_enableAdvanced->isChecked()); + m_removeThemeButton->setVisible(m_enableAdvanced->isChecked()); + m_advancedLine->setVisible(m_enableAdvanced->isChecked()); +} + +bool DesktopThemeDetails::isCustomized(const QString& theme) { + if (theme == ".customized" || theme == ".customized1") { + return true; + } else { + return false; + } +} + +void DesktopThemeDetails::clearCustomized(const QString& themeRoot) { + KStandardDirs dirs; + + if ((isCustomized(themeRoot))) { + // Remove both possible unnamed customized directories + if (QDir(dirs.locateLocal("data", "desktoptheme/.customized", false)).exists()) { + KIO::DeleteJob *clearCustom = KIO::del(KUrl(dirs.locateLocal("data", "desktoptheme/.customized", false)), KIO::HideProgressInfo); + KIO::NetAccess::synchronousRun(clearCustom, this); + } + if (QDir(dirs.locateLocal("data", "desktoptheme/.customized1", false)).exists()) { + KIO::DeleteJob *clearCustom1 = KIO::del(KUrl(dirs.locateLocal("data", "desktoptheme/.customized1", false)), KIO::HideProgressInfo); + KIO::NetAccess::synchronousRun(clearCustom1, this); + } + } else { + if (QDir(dirs.locateLocal("data", "desktoptheme/" + themeRoot, false)).exists()) { + KIO::DeleteJob *clearCustom = KIO::del(KUrl(dirs.locateLocal("data", "desktoptheme/" + themeRoot, false)), KIO::HideProgressInfo); + KIO::NetAccess::synchronousRun(clearCustom, this); + } + } +} + +QString DesktopThemeDetails::displayedItemText(int item) { + QString displayedText = m_items.key(item); + for (int i = 0; themeCollectionName[i].m_type; ++i) { + if (themeCollectionName[i].m_type == m_items.key(item)) { + displayedText = i18nc("plasma name", themeCollectionName[i].m_displayItemName); + } + } + return displayedText; +} + +void DesktopThemeDetails::themeSelectionChanged(const QItemSelection newSelection, const QItemSelection oldSelection) +{ + QString theme = m_theme->currentIndex().data(ThemeModel::PackageNameRole).toString(); + if (theme == "default") { + m_removeThemeButton->setEnabled(false); + } else { + m_removeThemeButton->setEnabled(true); + } + resetThemeDetails(); + Q_UNUSED(newSelection); + Q_UNUSED(oldSelection); +} + +void DesktopThemeDetails::setDesktopTheme(QString themeRoot) +{ + KConfig config(KStandardDirs::locate("config", "plasmarc")); + KConfigGroup cg = KConfigGroup(&config, "Theme"); + if (themeRoot == "default") { + cg.deleteEntry("name"); + } else { + cg.writeEntry("name", themeRoot); + } + cg.sync(); +} diff --git a/kcontrol/desktoptheme/desktopthemedetails.h b/kcontrol/desktoptheme/desktopthemedetails.h new file mode 100644 index 00000000..241ea029 --- /dev/null +++ b/kcontrol/desktoptheme/desktopthemedetails.h @@ -0,0 +1,68 @@ +/* + Copyright (c) 2007 Paolo Capriotti + Copyright (c) 2008 by Petri Damsten + + 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. +*/ + +#ifndef DESKTOPTHEMEDETAILS_H +#define DESKTOPTHEMEDETAILS_H + +#include "ui_DesktopThemeDetails.h" + +#include + +class ThemeModel; + +class DesktopThemeDetails : public QWidget, public Ui::DesktopThemeItems +{ + Q_OBJECT +public: + DesktopThemeDetails(QWidget* parent); + ~DesktopThemeDetails(); + + void reloadConfig(); + +public slots: + void replacementItemChanged(); + void resetThemeDetails(); + void toggleAdvancedVisible(); + void save(); + void removeTheme(); + void exportTheme(); + void newThemeInfoChanged(); + +Q_SIGNALS: + void changed(); + +private: + void updateReplaceItemList(const int& item); + void loadThemeItems(); + QString displayedItemText(int item); + bool isCustomized(const QString& theme); + void clearCustomized(const QString& themeRoot); + void setDesktopTheme(QString themeRoot); + +private slots: + void cleanup(); + void themeSelectionChanged(const QItemSelection newSelection, const QItemSelection oldSelection); + +private: + ThemeModel* m_themeModel; + + QHash m_items; // theme items + QHash m_itemPaths; // theme item paths + QHash m_itemIcons; //theme item icons + QHash m_themes; // installed themes + QHash m_themeRoots; // installed themes root paths + QHash m_itemThemeReplacements; // source theme for item replacements + QHashm_itemFileReplacements; //non-theme source files for item replacements + + bool m_themeCustomized; + QString m_baseTheme; +}; + +#endif // DESKTOPTHEMEDETAILS_H diff --git a/kcontrol/desktoptheme/kcmdesktoptheme.cpp b/kcontrol/desktoptheme/kcmdesktoptheme.cpp new file mode 100644 index 00000000..9657fe59 --- /dev/null +++ b/kcontrol/desktoptheme/kcmdesktoptheme.cpp @@ -0,0 +1,183 @@ +/* + * KCMDesktopTheme + * Copyright (C) 2002 Karol Szwed + * Copyright (C) 2002 Daniel Molkentin + * Copyright (C) 2007 Urs Wolfer + * Copyright (C) 2009 by Davide Bettio + + * Portions Copyright (C) 2007 Paolo Capriotti + * Portions Copyright (C) 2007 Ivan Cukic + * Portions Copyright (C) 2008 by Petri Damsten + * Portions Copyright (C) 2000 TrollTech AS. + * + * 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. + */ + +#include "kcmdesktoptheme.h" + +#include "thememodel.h" + + +#include +#include +#include +#include + +#include + +/**** DLL Interface for kcontrol ****/ + +#include +#include + +K_PLUGIN_FACTORY(KCMDesktopThemeFactory, registerPlugin();) +K_EXPORT_PLUGIN(KCMDesktopThemeFactory("kcmdesktoptheme","kcm_desktopthemedetails")) + + +KCMDesktopTheme::KCMDesktopTheme( QWidget* parent, const QVariantList& ) + : KCModule( KCMDesktopThemeFactory::componentData(), parent ) +{ + setQuickHelp( i18n("

Desktop Theme

" + "This module allows you to modify the visual appearance " + "of the desktop.")); + + setupUi(this); + + m_bDesktopThemeDirty = false; + m_bDetailsDirty = false; + + KAutostart plasmaNetbookAutoStart("plasma-netbook"); + m_isNetbook = plasmaNetbookAutoStart.autostarts(); + + KGlobal::dirs()->addResourceType("themes", "data", "kstyle/themes"); + + KAboutData *about = + new KAboutData( I18N_NOOP("KCMDesktopTheme"), 0, + ki18n("KDE Desktop Theme Module"), + 0, KLocalizedString(), KAboutData::License_GPL, + ki18n("(c) 2002 Karol Szwed, Daniel Molkentin")); + + about->addAuthor(ki18n("Karol Szwed"), KLocalizedString(), "gallium@kde.org"); + about->addAuthor(ki18n("Daniel Molkentin"), KLocalizedString(), "molkentin@kde.org"); + about->addAuthor(ki18n("Ralf Nolden"), KLocalizedString(), "nolden@kde.org"); + setAboutData( about ); + + m_newThemeButton->setIcon(KIcon("get-hot-new-stuff")); + + m_themeModel = new ThemeModel(this); + m_theme->setModel(m_themeModel); + m_theme->setItemDelegate(new ThemeDelegate(m_theme)); + m_theme->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + + connect(m_detailsWidget, SIGNAL(changed()), this, SLOT(detailChanged())); + + connect(m_theme->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(setDesktopThemeDirty())); + connect(m_newThemeButton, SIGNAL(clicked()), this, SLOT(getNewThemes())); +} + + +KCMDesktopTheme::~KCMDesktopTheme() +{ +} + +void KCMDesktopTheme::load() +{ + KConfig config( "kdeglobals", KConfig::FullConfig ); + + loadDesktopTheme(); + + m_bDesktopThemeDirty = false; + m_bDetailsDirty = false; + + emit changed( false ); +} + + +void KCMDesktopTheme::save() +{ + // Don't do anything if we don't need to. + if ( !( m_bDesktopThemeDirty) && !(m_bDetailsDirty) ) + return; + + //Desktop theme + if ( m_bDesktopThemeDirty ) + { + QString theme = m_themeModel->data(m_theme->currentIndex(), ThemeModel::PackageNameRole).toString(); + if (m_isNetbook) { + KConfigGroup cg(KSharedConfig::openConfig("plasmarc"), "Theme-plasma-netbook"); + cg.writeEntry("name", theme); + } else { + Plasma::Theme::defaultTheme()->setThemeName(theme); + } + } + + if (m_bDetailsDirty) + { + m_detailsWidget->save(); + } + + // Clean up + m_bDesktopThemeDirty = false; + m_bDetailsDirty = false; + emit changed( false ); +} + +void KCMDesktopTheme::defaults() +{ + // TODO: reset back to default theme? +} + +void KCMDesktopTheme::setDesktopThemeDirty() +{ + m_bDesktopThemeDirty = true; + emit changed(true); +} + +void KCMDesktopTheme::getNewThemes() +{ + KNS3::DownloadDialog dialog("plasma-themes.knsrc", this); + dialog.exec(); + KNS3::Entry::List entries = dialog.changedEntries(); + + if (entries.size() > 0) { + loadDesktopTheme(); + } +} + +void KCMDesktopTheme::loadDesktopTheme() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + m_themeModel->reload(); + QString themeName; + if (m_isNetbook) { + KConfigGroup cg(KSharedConfig::openConfig("plasmarc"), "Theme-plasma-netbook"); + themeName = cg.readEntry("name", "air-netbook"); + } else { + themeName = Plasma::Theme::defaultTheme()->themeName(); + } + m_theme->setCurrentIndex(m_themeModel->indexOf(themeName)); + QApplication::restoreOverrideCursor(); +} + +void KCMDesktopTheme::detailChanged() +{ + m_bDetailsDirty = true; + emit changed(true); +} + +#include "kcmdesktoptheme.moc" + +// vim: set noet ts=4: diff --git a/kcontrol/desktoptheme/kcmdesktoptheme.h b/kcontrol/desktoptheme/kcmdesktoptheme.h new file mode 100644 index 00000000..873eac79 --- /dev/null +++ b/kcontrol/desktoptheme/kcmdesktoptheme.h @@ -0,0 +1,71 @@ +/* + * KCMDesktopTheme + * Copyright (C) 2002 Karol Szwed + * Copyright (C) 2002 Daniel Molkentin + * Copyright (C) 2007 Urs Wolfer + * + * Portions Copyright (C) TrollTech AS. + * + * Based on kcmstyle which is based on kcmdisplay + * Copyright (C) 1997-2002 kcmdisplay Authors. + * (see Help -> About Style Settings) + * + * 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. + */ + +#ifndef KCMDESKTOPTHEME_H +#define KCMDESKTOPTHEME_H + +#include + +#include "ui_DesktopTheme.h" + +class ThemeModel; + +class KCMDesktopTheme : public KCModule, public Ui::DesktopTheme +{ + Q_OBJECT + +public: + KCMDesktopTheme( QWidget* parent, const QVariantList& ); + ~KCMDesktopTheme(); + + virtual void load(); + virtual void save(); + virtual void defaults(); + +protected Q_SLOTS: + void loadDesktopTheme(); + + void setDesktopThemeDirty(); + + void getNewThemes(); + + void detailChanged(); +private: + static QString toolbarButtonText(int index); + static int toolbarButtonIndex(const QString &text); + + bool m_bDesktopThemeDirty; + bool m_bDetailsDirty; + + ThemeModel* m_themeModel; + + bool m_isNetbook; +}; + +#endif // KCMDESKTOPTHEME_H + +// vim: set noet ts=4: diff --git a/kcontrol/desktoptheme/thememodel.cpp b/kcontrol/desktoptheme/thememodel.cpp new file mode 100644 index 00000000..4d679149 --- /dev/null +++ b/kcontrol/desktoptheme/thememodel.cpp @@ -0,0 +1,209 @@ +/* + * ThemeModel + * Copyright (C) 2002 Karol Szwed + * Copyright (C) 2002 Daniel Molkentin + * Copyright (C) 2007 Urs Wolfer + * Copyright (C) 2009 by Davide Bettio + + * Portions Copyright (C) 2007 Paolo Capriotti + * Portions Copyright (C) 2007 Ivan Cukic + * Portions Copyright (C) 2008 by Petri Damsten + * Portions Copyright (C) 2000 TrollTech AS. + * + * 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. + */ + +#include "thememodel.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +ThemeModel::ThemeModel( QObject *parent ) +: QAbstractListModel( parent ) +{ + reload(); +} + +ThemeModel::~ThemeModel() +{ + clearThemeList(); +} + +void ThemeModel::clearThemeList() +{ + foreach (const ThemeInfo& themeInfo, m_themes) { + delete themeInfo.svg; + } + m_themes.clear(); +} + +void ThemeModel::reload() +{ + reset(); + clearThemeList(); + + // get all desktop themes + KStandardDirs dirs; + const QStringList themes = dirs.findAllResources("data", "desktoptheme/*/metadata.desktop", + KStandardDirs::NoDuplicates); + foreach (const QString &theme, themes) { + int themeSepIndex = theme.lastIndexOf('/', -1); + QString themeRoot = theme.left(themeSepIndex); + int themeNameSepIndex = themeRoot.lastIndexOf('/', -1); + QString packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1); + + KDesktopFile df(theme); + + if (df.noDisplay()) { + continue; + } + + QString name = df.readName(); + if (name.isEmpty()) { + name = packageName; + } + const QString comment = df.readComment(); + const QString author = df.desktopGroup().readEntry("X-KDE-PluginInfo-Author",QString()); + const QString version = df.desktopGroup().readEntry("X-KDE-PluginInfo-Version",QString()); + + + Plasma::FrameSvg *svg = new Plasma::FrameSvg(this); + const QString svgFile = themeRoot + "/widgets/background.svg"; + if (QFile::exists(svgFile)) { + svg->setImagePath(svgFile); + } else { + svg->setImagePath(svgFile + "z"); + } + svg->setEnabledBorders(Plasma::FrameSvg::AllBorders); + ThemeInfo info; + info.package = packageName; + info.description = comment; + info.author = author; + info.version = version; + info.svg = svg; + info.themeRoot = themeRoot; + m_themes[name] = info; + } + + beginInsertRows(QModelIndex(), 0, m_themes.size()); + endInsertRows(); +} + +int ThemeModel::rowCount(const QModelIndex &) const +{ + return m_themes.size(); +} + +QVariant ThemeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() >= m_themes.size()) { + return QVariant(); + } + + QMap::const_iterator it = m_themes.constBegin(); + for (int i = 0; i < index.row(); ++i) { + ++it; + } + + switch (role) { + case Qt::DisplayRole: + return it.key(); + case PackageNameRole: + return (*it).package; + case SvgRole: + return qVariantFromValue((void*)(*it).svg); + case PackageDescriptionRole: + return (*it).description; + case PackageAuthorRole: + return (*it).author; + case PackageVersionRole: + return (*it).version; + default: + return QVariant(); + } +} + +QModelIndex ThemeModel::indexOf(const QString &name) const +{ + QMapIterator it(m_themes); + int i = -1; + while (it.hasNext()) { + ++i; + if (it.next().value().package == name) { + return index(i, 0); + } + } + + return QModelIndex(); +} + +ThemeDelegate::ThemeDelegate(QObject* parent) +: QAbstractItemDelegate(parent) +{ +} + +void ThemeDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QString title = index.model()->data(index, Qt::DisplayRole).toString(); + QString package = index.model()->data(index, ThemeModel::PackageNameRole).toString(); + + QStyleOptionViewItemV4 opt(option); + QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); + + // draw image + Plasma::FrameSvg *svg = static_cast( + index.model()->data(index, ThemeModel::SvgRole).value()); + svg->resizeFrame(QSize(option.rect.width() - (2 * MARGIN), 100 - (2 * MARGIN))); + QRect imgRect = QRect(option.rect.topLeft(), + QSize(option.rect.width() - (2 * MARGIN), 100 - (2 * MARGIN))) + .translated(MARGIN, MARGIN); + svg->paintFrame(painter, QPoint(option.rect.left() + MARGIN, option.rect.top() + MARGIN)); + + // draw text + painter->save(); + QFont font = painter->font(); + font.setWeight(QFont::Bold); + const QString colorFile = KStandardDirs::locate("data", "desktoptheme/" + package + "/colors"); + if (!colorFile.isEmpty()) { + KSharedConfigPtr colors = KSharedConfig::openConfig(colorFile); + KColorScheme colorScheme(QPalette::Active, KColorScheme::Window, colors); + painter->setPen(colorScheme.foreground(KColorScheme::NormalText).color()); + } + painter->setFont(font); + painter->drawText(option.rect, Qt::AlignCenter | Qt::TextWordWrap, title); + painter->restore(); +} + +QSize ThemeDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const +{ + return QSize(152, 100); +} + + diff --git a/kcontrol/desktoptheme/thememodel.h b/kcontrol/desktoptheme/thememodel.h new file mode 100644 index 00000000..0dfc5051 --- /dev/null +++ b/kcontrol/desktoptheme/thememodel.h @@ -0,0 +1,87 @@ +/* + * ThemeModel + * Copyright (C) 2002 Karol Szwed + * Copyright (C) 2002 Daniel Molkentin + * Copyright (C) 2007 Urs Wolfer + * Copyright (C) 2009 by Davide Bettio + + * Portions Copyright (C) 2007 Paolo Capriotti + * Portions Copyright (C) 2007 Ivan Cukic + * Portions Copyright (C) 2008 by Petri Damsten + * Portions Copyright (C) 2000 TrollTech AS. + * + * 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. + */ + +#ifndef THEMEMODEL_H +#define THEMEMODEL_H + +#include + +namespace Plasma +{ + class FrameSvg; +} + +//Theme selector code by Andre Duffeck (modified to add package description) +class ThemeInfo +{ +public: + QString package; + Plasma::FrameSvg *svg; + QString description; + QString author; + QString version; + QString themeRoot; +}; + +class ThemeModel : public QAbstractListModel +{ +public: + enum { PackageNameRole = Qt::UserRole, + SvgRole = Qt::UserRole + 1, + PackageDescriptionRole = Qt::UserRole + 2, + PackageAuthorRole = Qt::UserRole + 3, + PackageVersionRole = Qt::UserRole + 4 + }; + + ThemeModel(QObject *parent = 0); + virtual ~ThemeModel(); + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QModelIndex indexOf(const QString &path) const; + void reload(); + void clearThemeList(); +private: + QMap m_themes; +}; + +class ThemeDelegate : public QAbstractItemDelegate +{ +public: + ThemeDelegate(QObject * parent = 0); + + virtual void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const; +private: + static const int MARGIN = 10; +}; + + +#endif diff --git a/kcontrol/fonts/CMakeLists.txt b/kcontrol/fonts/CMakeLists.txt new file mode 100644 index 00000000..9aabb974 --- /dev/null +++ b/kcontrol/fonts/CMakeLists.txt @@ -0,0 +1,35 @@ + +KDE4_NO_ENABLE_FINAL(fonts) + +if(FONTCONFIG_FOUND) + include_directories(${FONTCONFIG_INCLUDE_DIR}) +endif(FONTCONFIG_FOUND) +include_directories(${FREETYPE_INCLUDE_DIRS}) + +########### next target ############### + +set(kcm_fonts_PART_SRCS ../krdb/krdb.cpp fonts.cpp) + +if(Q_WS_X11) + set(kcm_fonts_PART_SRCS ${kcm_fonts_PART_SRCS} ${libkxftconfig_SRCS}) +endif(Q_WS_X11) + +kde4_add_plugin(kcm_fonts ${kcm_fonts_PART_SRCS}) + + +target_link_libraries(kcm_fonts ${KDE4_KDEUI_LIBS} ${FREETYPE_LIBRARIES} ${QT_QTXML_LIBRARY}) + +if(Q_WS_X11) + if(FONTCONFIG_FOUND) + target_link_libraries(kcm_fonts ${FONTCONFIG_LIBRARIES}) + endif(FONTCONFIG_FOUND) + + target_link_libraries(kcm_fonts ${X11_LIBRARIES}) +endif(Q_WS_X11) + +install(TARGETS kcm_fonts DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES fonts.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/kcontrol/fonts/Messages.sh b/kcontrol/fonts/Messages.sh new file mode 100644 index 00000000..c49832c6 --- /dev/null +++ b/kcontrol/fonts/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kcmfonts.pot diff --git a/kcontrol/fonts/fonts.cpp b/kcontrol/fonts/fonts.cpp new file mode 100644 index 00000000..67eccd47 --- /dev/null +++ b/kcontrol/fonts/fonts.cpp @@ -0,0 +1,851 @@ +// KDE Display fonts setup tab +// +// Copyright (c) Mark Donohoe 1997 +// lars Knoll 1999 +// Rik Hemsley 2000 +// +// Ported to kcontrol2 by Geert Jansen. + +#include + +#include "fonts.h" +#include "fonts.moc" + +#include + +#include +#include +#include +#include +#include +#include + +//Added by qt3to4: +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../krdb/krdb.h" + +#ifdef HAVE_FREETYPE +#include +#ifdef FT_LCD_FILTER_H +#include FT_FREETYPE_H +#include FT_LCD_FILTER_H +#endif +#endif + +#ifdef Q_WS_X11 +#include +#endif + +#ifdef Q_WS_X11 +// X11 headers +#undef Bool +#undef Unsorted +#undef None +#endif + +static const char * const aa_rgb_xpm[]={ +"12 12 3 1", +"a c #0000ff", +"# c #00ff00", +". c #ff0000", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa"}; +static const char * const aa_bgr_xpm[]={ +"12 12 3 1", +". c #0000ff", +"# c #00ff00", +"a c #ff0000", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa", +"....####aaaa"}; +static const char * const aa_vrgb_xpm[]={ +"12 12 3 1", +"a c #0000ff", +"# c #00ff00", +". c #ff0000", +"............", +"............", +"............", +"............", +"############", +"############", +"############", +"############", +"aaaaaaaaaaaa", +"aaaaaaaaaaaa", +"aaaaaaaaaaaa", +"aaaaaaaaaaaa"}; +static const char * const aa_vbgr_xpm[]={ +"12 12 3 1", +". c #0000ff", +"# c #00ff00", +"a c #ff0000", +"............", +"............", +"............", +"............", +"############", +"############", +"############", +"############", +"aaaaaaaaaaaa", +"aaaaaaaaaaaa", +"aaaaaaaaaaaa", +"aaaaaaaaaaaa"}; + +static const char* const * const aaPixmaps[]={ aa_rgb_xpm, aa_bgr_xpm, aa_vrgb_xpm, aa_vbgr_xpm }; + +/**** DLL Interface ****/ +K_PLUGIN_FACTORY(FontFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(FontFactory("kcmfonts")) + +/**** FontUseItem ****/ + +FontUseItem::FontUseItem( + QWidget * parent, + const QString &name, + const QString &grp, + const QString &key, + const QString &rc, + const QFont &default_fnt, + bool f +) + : KFontRequester(parent, f), + _rcfile(rc), + _rcgroup(grp), + _rckey(key), + _default(default_fnt) +{ + KAcceleratorManager::setNoAccel( this ); + setTitle( name ); + readFont(); +} + +void FontUseItem::setDefault() +{ + setFont( _default, isFixedOnly() ); +} + +void FontUseItem::readFont() +{ + KConfig *config; + + bool deleteme = false; + if (_rcfile.isEmpty()) + config = KGlobal::config().data(); + else + { + config = new KConfig(_rcfile); + deleteme = true; + } + + KConfigGroup group(config, _rcgroup); + QFont tmpFnt(_default); + setFont( group.readEntry(_rckey, tmpFnt), isFixedOnly() ); + if (deleteme) delete config; +} + +void FontUseItem::writeFont() +{ + KConfig *config; + + if (_rcfile.isEmpty()) { + config = KGlobal::config().data(); + KConfigGroup(config, _rcgroup).writeEntry(_rckey, font(), KConfig::Normal|KConfig::Global); + } else { + config = new KConfig(KStandardDirs::locateLocal("config", _rcfile)); + KConfigGroup(config, _rcgroup).writeEntry(_rckey, font()); + config->sync(); + delete config; + } +} + +void FontUseItem::applyFontDiff( const QFont &fnt, int fontDiffFlags ) +{ + QFont _font( font() ); + + if (fontDiffFlags & KFontChooser::FontDiffSize) { + _font.setPointSizeF( fnt.pointSizeF() ); + } + if (fontDiffFlags & KFontChooser::FontDiffFamily) { + if (!isFixedOnly() || QFontInfo(fnt).fixedPitch()) _font.setFamily( fnt.family() ); + } + if (fontDiffFlags & KFontChooser::FontDiffStyle) { + _font.setWeight( fnt.weight() ); + _font.setStyle( fnt.style() ); + _font.setUnderline( fnt.underline() ); +#if QT_VERSION >= 0x040800 + _font.setStyleName( fnt.styleName() ); +#endif + } + + setFont( _font, isFixedOnly() ); +} + +/**** FontAASettings ****/ +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) +FontAASettings::FontAASettings(QWidget *parent) + : KDialog( parent ), + changesMade(false) +{ + setObjectName( "FontAASettings" ); + setModal( true ); + setCaption( i18n("Configure Anti-Alias Settings") ); + setButtons( Ok|Cancel ); + + QWidget *mw=new QWidget(this); + QFormLayout *layout=new QFormLayout(mw); + layout->setMargin(0); + + excludeRange=new QCheckBox(i18n("E&xclude range:"), mw); + QHBoxLayout *rangeLayout = new QHBoxLayout(); + excludeFrom=new KDoubleNumInput(0, 72, 8.0, mw, 1, 1); + excludeFrom->setSuffix(i18n(" pt")); + rangeLayout->addWidget(excludeFrom); + excludeToLabel=new QLabel(i18n(" to "), mw); + rangeLayout->addWidget(excludeToLabel); + excludeTo=new KDoubleNumInput(0, 72, 15.0, mw, 1, 1); + excludeTo->setSuffix(i18n(" pt")); + rangeLayout->addWidget(excludeTo); + layout->addRow(excludeRange, rangeLayout); + + QString subPixelWhatsThis = i18n("

If you have a TFT or LCD screen you" + " can further improve the quality of displayed fonts by selecting" + " this option.
Sub-pixel rendering is also known as ClearType(tm).
" + " In order for sub-pixel rendering to" + " work correctly you need to know how the sub-pixels of your display" + " are aligned.

" + "

On TFT or LCD displays a single pixel is actually composed of" + " three sub-pixels, red, green and blue. Most displays" + " have a linear ordering of RGB sub-pixel, some have BGR.
" + " This feature does not work with CRT monitors.

" ); + + useSubPixel=new QCheckBox(i18n("&Use sub-pixel rendering:"), mw); + useSubPixel->setWhatsThis( subPixelWhatsThis ); + + subPixelType=new QComboBox(mw); + layout->addRow(useSubPixel, subPixelType); + + subPixelType->setEditable(false); + subPixelType->setWhatsThis( subPixelWhatsThis ); + + for(int t=KXftConfig::SubPixel::None+1; t<=KXftConfig::SubPixel::Vbgr; ++t) + subPixelType->addItem(QPixmap(aaPixmaps[t-1]), i18n(KXftConfig::description((KXftConfig::SubPixel::Type)t).toUtf8())); + + QLabel *hintingLabel=new QLabel(i18n("Hinting style: "), mw); + hintingStyle=new QComboBox(mw); + hintingStyle->setEditable(false); + layout->addRow(hintingLabel, hintingStyle); + for(int s=KXftConfig::Hint::NotSet+1; s<=KXftConfig::Hint::Full; ++s) + hintingStyle->addItem(i18n(KXftConfig::description((KXftConfig::Hint::Style)s).toUtf8())); + + QString hintingText(i18n("Hinting is a process used to enhance the quality of fonts at small sizes.")); + hintingStyle->setWhatsThis( hintingText); + hintingLabel->setWhatsThis( hintingText); + load(); + enableWidgets(); + setMainWidget(mw); + + connect(excludeRange, SIGNAL(toggled(bool)), SLOT(changed())); + connect(useSubPixel, SIGNAL(toggled(bool)), SLOT(changed())); + connect(excludeFrom, SIGNAL(valueChanged(double)), SLOT(changed())); + connect(excludeTo, SIGNAL(valueChanged(double)), SLOT(changed())); + connect(subPixelType, SIGNAL(activated(QString)), SLOT(changed())); + connect(hintingStyle, SIGNAL(activated(QString)), SLOT(changed())); +} + +bool FontAASettings::load() +{ + double from, to; + KXftConfig xft; + + if(xft.getExcludeRange(from, to)) + excludeRange->setChecked(true); + else + { + excludeRange->setChecked(false); + from=8.0; + to=15.0; + } + + excludeFrom->setValue(from); + excludeTo->setValue(to); + + KXftConfig::SubPixel::Type spType; + + if(!xft.getSubPixelType(spType) || KXftConfig::SubPixel::None==spType) + useSubPixel->setChecked(false); + else + { + int idx=getIndex(spType); + + if(idx>-1) + { + useSubPixel->setChecked(true); + subPixelType->setCurrentIndex(idx); + } + else + useSubPixel->setChecked(false); + } + + KXftConfig::Hint::Style hStyle; + + if(!xft.getHintStyle(hStyle) || KXftConfig::Hint::NotSet==hStyle) + { + KConfig kglobals("kdeglobals", KConfig::NoGlobals); + + hStyle=KXftConfig::Hint::Medium; + xft.setHintStyle(hStyle); + xft.apply(); // Save this setting + KConfigGroup(&kglobals, "General").writeEntry("XftHintStyle", KXftConfig::toStr(hStyle)); + kglobals.sync(); + runRdb(KRdbExportXftSettings | KRdbExportGtkTheme); + } + + hintingStyle->setCurrentIndex(getIndex(hStyle)); + + enableWidgets(); + + return xft.getAntiAliasing(); +} + +bool FontAASettings::save( bool useAA ) +{ + KXftConfig xft; + KConfig kglobals("kdeglobals", KConfig::NoGlobals); + KConfigGroup grp(&kglobals, "General"); + + xft.setAntiAliasing( useAA ); + + if(excludeRange->isChecked()) + xft.setExcludeRange(excludeFrom->value(), excludeTo->value()); + else + xft.setExcludeRange(0, 0); + + KXftConfig::SubPixel::Type spType(useSubPixel->isChecked() + ? getSubPixelType() + : KXftConfig::SubPixel::None); + + xft.setSubPixelType(spType); + grp.writeEntry("XftSubPixel", KXftConfig::toStr(spType)); + grp.writeEntry("XftAntialias", useAA); + + bool mod=false; + KXftConfig::Hint::Style hStyle(getHintStyle()); + + xft.setHintStyle(hStyle); + + QString hs(KXftConfig::toStr(hStyle)); + + if(!hs.isEmpty() && hs!=grp.readEntry("XftHintStyle")) + { + grp.writeEntry("XftHintStyle", hs); + mod=true; + } + kglobals.sync(); + + if(!mod) + mod=xft.changed(); + + xft.apply(); + + return mod; +} + +void FontAASettings::defaults() +{ + excludeRange->setChecked(false); + excludeFrom->setValue(8.0); + excludeTo->setValue(15.0); + useSubPixel->setChecked(false); + hintingStyle->setCurrentIndex(getIndex(KXftConfig::Hint::Medium)); + enableWidgets(); +} + +int FontAASettings::getIndex(KXftConfig::SubPixel::Type spType) +{ + int pos=-1; + int index; + + for(index=0; indexcount(); ++index) + if(subPixelType->itemText(index)==i18n(KXftConfig::description(spType).toUtf8())) + { + pos=index; + break; + } + + return pos; +} + +KXftConfig::SubPixel::Type FontAASettings::getSubPixelType() +{ + int t; + + for(t=KXftConfig::SubPixel::None; t<=KXftConfig::SubPixel::Vbgr; ++t) + if(subPixelType->currentText()==i18n(KXftConfig::description((KXftConfig::SubPixel::Type)t).toUtf8())) + return (KXftConfig::SubPixel::Type)t; + + return KXftConfig::SubPixel::None; +} + +int FontAASettings::getIndex(KXftConfig::Hint::Style hStyle) +{ + int pos=-1; + int index; + + for(index=0; indexcount(); ++index) + if(hintingStyle->itemText(index)==i18n(KXftConfig::description(hStyle).toUtf8())) + { + pos=index; + break; + } + + return pos; +} + + +KXftConfig::Hint::Style FontAASettings::getHintStyle() +{ + int s; + + for(s=KXftConfig::Hint::NotSet; s<=KXftConfig::Hint::Full; ++s) + if(hintingStyle->currentText()==i18n(KXftConfig::description((KXftConfig::Hint::Style)s).toUtf8())) + return (KXftConfig::Hint::Style)s; + + return KXftConfig::Hint::Medium; +} + +void FontAASettings::enableWidgets() +{ + excludeFrom->setEnabled(excludeRange->isChecked()); + excludeTo->setEnabled(excludeRange->isChecked()); + excludeToLabel->setEnabled(excludeRange->isChecked()); + subPixelType->setEnabled(useSubPixel->isChecked()); +#ifdef FT_LCD_FILTER_H + static int ft_has_subpixel = -1; + if( ft_has_subpixel == -1 ) { + FT_Library ftLibrary; + if(FT_Init_FreeType(&ftLibrary) == 0) { + ft_has_subpixel = ( FT_Library_SetLcdFilter(ftLibrary, FT_LCD_FILTER_DEFAULT ) + == FT_Err_Unimplemented_Feature ) ? 0 : 1; + FT_Done_FreeType(ftLibrary); + } + } + useSubPixel->setEnabled(ft_has_subpixel); + subPixelType->setEnabled(ft_has_subpixel); +#endif +} +#endif + +void FontAASettings::changed() +{ +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + changesMade=true; + enableWidgets(); +#endif +} + +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) +int FontAASettings::exec() +{ + int i=KDialog::exec(); + + if(!i) + load(); // Reset settings... + + return i && changesMade; +} +#endif + +/**** KFonts ****/ + +KFonts::KFonts(QWidget *parent, const QVariantList &args) + : KCModule(FontFactory::componentData(), parent, args) +{ + QStringList nameGroupKeyRc; + + nameGroupKeyRc + << i18nc("font usage", "General") << "General" << "font" << "" + << i18nc("font usage", "Fixed width") << "General" << "fixed" << "" + << i18nc("font usage", "Small") << "General" << "smallestReadableFont" << "" + << i18nc("font usage", "Toolbar") << "General" << "toolBarFont" << "" + << i18nc("font usage", "Menu") << "General" << "menuFont" << "" + << i18nc("font usage", "Window title") << "WM" << "activeFont" << "" + << i18nc("font usage", "Taskbar") << "General" << "taskbarFont" << "" + << i18nc("font usage", "Desktop") << "General" << "desktopFont" << ""; + + QList defaultFontList; + + // NOTE: keep in sync with kdelibs/kdeui/kernel/kglobalsettings.cpp + +#ifdef Q_WS_MAC + QFont f0("Lucida Grande", 13); // general/menu/desktop + QFont f1("Monaco", 10); + QFont f2("Lucida Grande", 11); // toolbar +#elif defined(Q_WS_MAEMO_5) || defined(MEEGO_EDITION_HARMATTAN) + QFont f0("Sans Serif", 16); // general/menu/desktop + QFont f1("Monospace", 16; + QFont f2("Sans Serif", 16); // toolbar +#else + QFont f0("Sans Serif", 9); // general/menu/desktop + QFont f1("Monospace", 9); + QFont f2("Sans Serif", 8); // toolbar +#endif + QFont f3("Sans Serif", 8); // window title + QFont f4("Sans Serif", 9); // taskbar + QFont f5("Sans Serif", 8); // smallestReadableFont + + defaultFontList << f0 << f1 << f5 << f2 << f0 << f3 << f4 << f0; + + QList fixedList; + + fixedList + << false + << true + << false + << false + << false + << false + << false + << false; + + QStringList quickHelpList; + + quickHelpList + << i18n("Used for normal text (e.g. button labels, list items).") + << i18n("A non-proportional font (i.e. typewriter font).") + << i18n("Smallest font that is still readable well.") + << i18n("Used to display text beside toolbar icons.") + << i18n("Used by menu bars and popup menus.") + << i18n("Used by the window titlebar.") + << i18n("Used by the taskbar.") + << i18n("Used for desktop icons."); + + QVBoxLayout * layout = new QVBoxLayout(this ); + layout->setMargin(0); + + QGridLayout * fontUseLayout = new QGridLayout( ); + layout->addLayout( fontUseLayout ); + fontUseLayout->setColumnStretch(0, 0); + fontUseLayout->setColumnStretch(1, 1); + fontUseLayout->setColumnStretch(2, 0); + + QList::ConstIterator defaultFontIt(defaultFontList.begin()); + QList::ConstIterator fixedListIt(fixedList.begin()); + QStringList::ConstIterator quickHelpIt(quickHelpList.begin()); + QStringList::ConstIterator it(nameGroupKeyRc.begin()); + + unsigned int count = 0; + + while (it != nameGroupKeyRc.constEnd()) { + + QString name = *it; it++; + QString group = *it; it++; + QString key = *it; it++; + QString file = *it; it++; + + FontUseItem * i = + new FontUseItem( + this, + name, + group, + key, + file, + *defaultFontIt++, + *fixedListIt++ + ); + + fontUseList.append(i); + connect(i, SIGNAL(fontSelected(QFont)), SLOT(fontSelected())); + + QLabel * fontUse = new QLabel(i18nc("Font role", "%1: ", name), this); + fontUse->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + fontUse->setWhatsThis( *quickHelpIt++); + + fontUseLayout->addWidget(fontUse, count, 0); + fontUseLayout->addWidget(i, count, 1); + + ++count; + } + + QHBoxLayout *hblay = new QHBoxLayout(); + layout->addLayout(hblay); + hblay->addStretch(); + QPushButton * fontAdjustButton = new QPushButton(i18n("Ad&just All Fonts..."), this); + fontAdjustButton->setWhatsThis( i18n("Click to change all fonts")); + hblay->addWidget( fontAdjustButton ); + connect(fontAdjustButton, SIGNAL(clicked()), SLOT(slotApplyFontDiff())); + + layout->addSpacing(KDialog::spacingHint()); + + QGridLayout* lay = new QGridLayout(); + layout->addLayout(lay); + lay->setColumnStretch( 3, 10 ); +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + QLabel* label=0L; + label = new QLabel( i18n( "Use a&nti-aliasing:" ), this ); + label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + lay->addWidget( label, 0, 0 ); + cbAA = new QComboBox( this ); + cbAA->insertItem( AAEnabled, i18nc( "Use anti-aliasing", "Enabled" )); // change AASetting type if order changes + cbAA->insertItem( AASystem, i18nc( "Use anti-aliasing", "System Settings" )); + cbAA->insertItem( AADisabled, i18nc( "Use anti-aliasing", "Disabled" )); + cbAA->setWhatsThis(i18n("If this option is selected, KDE will smooth the edges of curves in fonts.")); + + aaSettingsButton = new QPushButton( i18n( "Configure..." ), this); + connect(aaSettingsButton, SIGNAL(clicked()), SLOT(slotCfgAa())); + label->setBuddy( cbAA ); + lay->addWidget( cbAA, 0, 1 ); + lay->addWidget( aaSettingsButton, 0, 2 ); + // Initialize aaSettingsButton state based on the current cbAA->currentIndex value, will be eventually updated at load() + slotUseAntiAliasing(); + + connect(cbAA, SIGNAL(currentIndexChanged(int)), SLOT(slotUseAntiAliasing())); +#endif +#ifdef Q_WS_X11 + checkboxForceDpi = new QCheckBox( i18n( "Force fonts DPI:" ), this ); + lay->addWidget( checkboxForceDpi, 1, 0 ); + spinboxDpi = new QSpinBox( this ); + spinboxDpi->setRange(1, 1000); + spinboxDpi->setSingleStep(24); // The common DPI values 72, 96 and 120 are multiples of 24 + QString whatsthis = i18n( + "

This option forces a specific DPI value for fonts. It may be useful" + " when the real DPI of the hardware is not detected properly and it" + " is also often misused when poor quality fonts are used that do not" + " look well with DPI values other than 96 or 120 DPI.

" + "

The use of this option is generally discouraged. For selecting proper DPI" + " value a better option is explicitly configuring it for the whole X server if" + " possible (e.g. DisplaySize in xorg.conf or adding -dpi value to" + " ServerLocalArgs= in $KDEDIR/share/config/kdm/kdmrc). When fonts do not render" + " properly with real DPI value better fonts should be used or configuration" + " of font hinting should be checked.

" ); + spinboxDpi->setWhatsThis(whatsthis); + checkboxForceDpi->setChecked(false); + spinboxDpi->setEnabled(false); + connect( spinboxDpi, SIGNAL( valueChanged(int)), SLOT( changed())); + connect( checkboxForceDpi, SIGNAL( toggled(bool)), SLOT( changed())); + connect( checkboxForceDpi, SIGNAL( toggled(bool)), spinboxDpi, SLOT( setEnabled(bool))); + lay->addWidget( spinboxDpi, 1, 1 ); +#endif + layout->addStretch(1); + +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + aaSettings=new FontAASettings(this); +#endif + +} + +KFonts::~KFonts() +{ + QList::Iterator it(fontUseList.begin()), + end(fontUseList.end()); + + for(; it!=end; ++it) + delete (*it); + fontUseList.clear(); +} + +void KFonts::fontSelected() +{ + emit changed(true); +} + +void KFonts::defaults() +{ + for ( int i = 0; i < (int) fontUseList.count(); i++ ) + fontUseList.at( i )->setDefault(); + +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + useAA = AASystem; + cbAA->setCurrentIndex( useAA ); + aaSettings->defaults(); +#endif +#ifdef Q_WS_X11 + checkboxForceDpi->setChecked( false ); + spinboxDpi->setValue( 96 ); +#endif + emit changed(true); +} + +void KFonts::load() +{ + QList::Iterator it(fontUseList.begin()), + end(fontUseList.end()); + + for(; it!=end; ++it) + (*it)->readFont(); + +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + useAA_original = useAA = aaSettings->load() ? AAEnabled : AADisabled; + cbAA->setCurrentIndex( useAA ); +#endif + + KConfig _cfgfonts( "kcmfonts" ); + KConfigGroup cfgfonts(&_cfgfonts, "General"); +#ifdef Q_WS_X11 + int dpicfg = cfgfonts.readEntry( "forceFontDPI", 0 ); + if (dpicfg <= 0) { + checkboxForceDpi->setChecked(false); + spinboxDpi->setValue(96); + dpi_original = 0; + } else { + checkboxForceDpi->setChecked(true); + spinboxDpi->setValue(dpicfg); + dpi_original = dpicfg; + }; +#endif +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + if( cfgfonts.readEntry( "dontChangeAASettings", true )) { + useAA_original = useAA = AASystem; + cbAA->setCurrentIndex( useAA ); + } +#endif + + emit changed(false); +} + +void KFonts::save() +{ + QList::Iterator it(fontUseList.begin()), + end(fontUseList.end()); + + for(; it!=end; ++it) + (*it)->writeFont(); + + KGlobal::config()->sync(); + + KConfig _cfgfonts( "kcmfonts" ); + KConfigGroup cfgfonts(&_cfgfonts, "General"); +#ifdef Q_WS_X11 + int dpi = ( checkboxForceDpi->isChecked() ? spinboxDpi->value() : 0 ); + cfgfonts.writeEntry( "forceFontDPI", dpi ); +#endif +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + cfgfonts.writeEntry( "dontChangeAASettings", cbAA->currentIndex() == AASystem ); +#endif + cfgfonts.sync(); +#ifdef Q_WS_X11 + // if the setting is reset in the module, remove the dpi value, + // otherwise don't explicitly remove it and leave any possible system-wide value + if( dpi == 0 && dpi_original != 0 ) { + KProcess proc; + proc << "xrdb" << "-quiet" << "-remove" << "-nocpp"; + proc.start(); + if (proc.waitForStarted()) { + proc.write( QByteArray( "Xft.dpi\n" ) ); + proc.closeWriteChannel(); + proc.waitForFinished(); + } + } +#endif + + KGlobalSettings::self()->emitChange(KGlobalSettings::FontChanged); + + kapp->processEvents(); // Process font change ourselves + + + // Don't overwrite global settings unless explicitly asked for - e.g. the system + // fontconfig setup may be much more complex than this module can provide. + // TODO: With AASystem the changes already made by this module should be reverted somehow. +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + bool aaSave = false; + if( cbAA->currentIndex() != AASystem ) + aaSave = aaSettings->save( useAA == AAEnabled ); + + if( aaSave || (useAA != useAA_original) || dpi != dpi_original) { + KMessageBox::information(this, + i18n( + "

Some changes such as anti-aliasing or DPI will only affect newly started applications.

" + ), i18n("Font Settings Changed"), "FontSettingsChanged"); + useAA_original = useAA; + dpi_original = dpi; + } +#else +#ifdef Q_WS_X11 + if(dpi != dpi_original) { + KMessageBox::information(this, + i18n( + "

Some changes such as DPI will only affect newly started applications.

" + ), i18n("Font Settings Changed"), "FontSettingsChanged"); + dpi_original = dpi; + } +#endif +#endif + runRdb(KRdbExportXftSettings | KRdbExportGtkTheme); + + emit changed(false); +} + + +void KFonts::slotApplyFontDiff() +{ + QFont font = QFont(fontUseList.first()->font()); + KFontChooser::FontDiffFlags fontDiffFlags = 0; + int ret = KFontDialog::getFontDiff(font,fontDiffFlags,KFontChooser::NoDisplayFlags,this); + + if (ret == KDialog::Accepted && fontDiffFlags) + { + for ( int i = 0; i < (int) fontUseList.count(); i++ ) + fontUseList.at( i )->applyFontDiff( font,fontDiffFlags ); + emit changed(true); + } +} + +void KFonts::slotUseAntiAliasing() +{ +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + useAA = static_cast< AASetting >( cbAA->currentIndex()); + aaSettingsButton->setEnabled(useAA == AAEnabled); + emit changed(true); +#endif +} + +void KFonts::slotCfgAa() +{ +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + if(aaSettings->exec()) + { + emit changed(true); + } +#endif +} + +// vim:ts=2:sw=2:tw=78 diff --git a/kcontrol/fonts/fonts.desktop b/kcontrol/fonts/fonts.desktop new file mode 100644 index 00000000..0a97f8b7 --- /dev/null +++ b/kcontrol/fonts/fonts.desktop @@ -0,0 +1,239 @@ +[Desktop Entry] +Exec=kcmshell4 fonts +Icon=preferences-desktop-font +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/fonts/index.html + +X-KDE-Library=kcm_fonts +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=application-appearance +X-KDE-Weight=80 + +Name=Fonts +Name[af]=Skriftipes +Name[ar]=الخطوط +Name[ast]=Tribes de lletra +Name[be]=Шрыфты +Name[be@latin]=Šryfty +Name[bg]=Шрифтове +Name[bn]=ফন্ট +Name[bn_IN]=ফন্ট +Name[br]=Fontoù +Name[bs]=Fontovi +Name[ca]=Tipus de lletra +Name[ca@valencia]=Tipus de lletra +Name[cs]=Písma +Name[csb]=Fòntë +Name[cy]=Ffontiau +Name[da]=Skrifttyper +Name[de]=Schriftarten +Name[el]=Γραμματοσειρές +Name[en_GB]=Fonts +Name[eo]=Tiparoj +Name[es]=Tipos de letra +Name[et]=Fondid +Name[eu]=Letra-tipoak +Name[fa]=قلمها +Name[fi]=Fontit +Name[fr]=Polices de caractères +Name[fy]=Lettertypen +Name[ga]=Clónna +Name[gl]=Tipos de letra +Name[gu]=ફોન્ટ્સ +Name[he]=גופנים +Name[hi]=फ़ॉन्ट्स +Name[hne]=फोंट +Name[hr]=Fontovi +Name[hsb]=Pisma +Name[hu]=Betűtípusok +Name[ia]=Fontes +Name[id]=Fonta +Name[is]=Letur +Name[it]=Caratteri +Name[ja]=フォント +Name[ka]=ფონტები +Name[kk]=Қаріптер +Name[km]=ពុម្ព​អក្សរ +Name[kn]=ಅಕ್ಷರಶೈಲಿಗಳು +Name[ko]=글꼴 +Name[ku]=Curenivîs +Name[lt]=Šriftai +Name[lv]=Fonti +Name[mai]=फान्ट +Name[mk]=Фонтови +Name[ml]=അക്ഷരസഞ്ചയങ്ങള്‍ +Name[mr]=फॉन्ट +Name[ms]=Fon +Name[nb]=Skrifttyper +Name[nds]=Schriftoorden +Name[ne]=फन्ट +Name[nl]=Lettertypen +Name[nn]=Skrifter +Name[oc]=Poliças +Name[or]=ଅକ୍ଷର ରୂପ +Name[pa]=ਫੋਂਟ +Name[pl]=Czcionki +Name[pt]=Tipos de Letra +Name[pt_BR]=Fontes +Name[ro]=Fonturi +Name[ru]=Шрифты +Name[se]=Fonttat +Name[si]=අකුරු +Name[sk]=Písma +Name[sl]=Pisave +Name[sr]=Фонтови +Name[sr@ijekavian]=Фонтови +Name[sr@ijekavianlatin]=Fontovi +Name[sr@latin]=Fontovi +Name[sv]=Teckensnitt +Name[ta]=எழுத்துருக்கள் +Name[te]=ఫాంట్‍స్ +Name[tg]=Ҳарфҳо +Name[th]=แบบอักษรต่างๆ +Name[tr]=Yazı Tipleri +Name[ug]=خەت نۇسخا +Name[uk]=Шрифти +Name[uz]=Shriftlar +Name[uz@cyrillic]=Шрифтлар +Name[vi]=Phông chữ +Name[wa]=Fontes +Name[xh]=Uhlobo lwamagama +Name[x-test]=xxFontsxx +Name[zh_CN]=字体 +Name[zh_TW]=字型 + +Comment=Font settings +Comment[af]=Skrif tipe instellings +Comment[ar]=إعدادات الخطوط +Comment[ast]=Preferencies de les tribes de lletra +Comment[be]=Настаўленні шрыфтоў +Comment[be@latin]=Nałady šryftoŭ +Comment[bg]=Настройки на системните шрифтове +Comment[bn]=ফন্ট সেটিংস +Comment[bn_IN]=ফন্ট সংক্রান্ত বৈশিষ্ট্য +Comment[br]=Kefluniañ ar fontoù +Comment[bs]=Postavke fonta +Comment[ca]=Arranjament del tipus de lletra +Comment[ca@valencia]=Arranjament del tipus de lletra +Comment[cs]=Nastavení písem +Comment[csb]=Nastôw fòntów +Comment[cy]=Gosodiadau Ffontiau +Comment[da]=Skrifttypeindstillinger +Comment[de]=Schriftarten-Einstellungen +Comment[el]=Ρυθμίσεις γραμματοσειρών +Comment[en_GB]=Font settings +Comment[eo]=Tiparagordo +Comment[es]=Preferencias de los tipos de letra +Comment[et]=Fontide seadistused +Comment[eu]=Letra-tipoen ezarpenak +Comment[fa]=تنظیمات قلم +Comment[fi]=Fonttiasetukset +Comment[fy]=Lettertypen ynstellings +Comment[ga]=Socruithe na gclónna +Comment[gl]=Configuración dos tipos de letra +Comment[gu]=ફોન્ટ ગોઠવણીઓ +Comment[he]=הגדרות גופנים +Comment[hi]=फ़ॉन्ट्स विन्यास +Comment[hne]=फोंट सेटिंग +Comment[hr]=Postavke fontova +Comment[hsb]=Nastajenja za pisma +Comment[hu]=Betűtípus-beállítások +Comment[ia]=Preferentias de font +Comment[id]=Pengaturan fonta +Comment[is]=Stillingar leturs +Comment[ka]=ფონტების კონფიგურაცია +Comment[kk]=Қаріптерін орнату +Comment[km]=ការ​កំណត់​ពុម្ព​អក្សរ +Comment[kn]=ಅಕ್ಷರಶೈಲಿ ಸಂಯೋಜನೆಗಳು +Comment[ko]=글꼴 설정 +Comment[ku]=Mîhengên curenivîsan +Comment[lt]=Šriftų nustatymai +Comment[lv]=Fontu parametri +Comment[mai]=फान्ट्स बिन्यास +Comment[mk]=Поставувања на фонтовите +Comment[ml]=അക്ഷരസഞ്ചയത്തിന്റെ സജ്ജീകരണങ്ങള്‍ +Comment[mr]=फॉन्ट संयोजना +Comment[ms]=Seting Fon +Comment[nb]=Skriftinnstillinger +Comment[nds]=Schriftoorden instellen +Comment[ne]=फन्ट सेटिङ +Comment[nl]=Lettertypeninstellingen +Comment[nn]=Skriftinnstillingar +Comment[oc]=Paramètres de poliça +Comment[or]=ଅକ୍ଷର ରୂପ ସଂଚଚନା +Comment[pa]=ਫੋਂਟ ਸੈਟਿੰਗ +Comment[pl]=Ustawienia czcionek +Comment[pt]=Configuração dos tipos de letra +Comment[pt_BR]=Configurações das fontes +Comment[ro]=Configurări font +Comment[ru]=Настройка шрифтов +Comment[se]=Fontaheivehusat +Comment[si]=අකුරු සැකසුම් +Comment[sk]=Nastavenie písiem +Comment[sl]=Nastavitve pisav +Comment[sr]=Поставке фонтова +Comment[sr@ijekavian]=Поставке фонтова +Comment[sr@ijekavianlatin]=Postavke fontova +Comment[sr@latin]=Postavke fontova +Comment[sv]=Anpassa teckensnitt +Comment[ta]=எழுத்துரு அமைப்புகள் +Comment[te]=ఫాంట్ అమరికలు +Comment[tg]=Танзимоти ҳарфҳо +Comment[th]=ตั้งค่าแบบอักษรต่างๆ +Comment[tr]=Yazı tipi ayarları +Comment[ug]=خەت نۇسخا تەڭشەك +Comment[uk]=Налаштування шрифтів +Comment[uz]=Shriftlarni moslash +Comment[uz@cyrillic]=Шрифтларни мослаш +Comment[vi]=Thiết lập phông chữ +Comment[wa]=Apontiaedje des fontes +Comment[xh]=Izicwangciso zohlobo lwamagama +Comment[x-test]=xxFont settingsxx +Comment[zh_CN]=字体设置 +Comment[zh_TW]=字型設定 + +X-KDE-Keywords=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts +X-KDE-Keywords[bs]=slova,veličina slova,stil,znakovi,postaviti znakove,ploča,kontrolna ploča,pozadina,upravitelj datoteka,alatne trake,meni,naslov prozora,naslov,DPI,niskopropusni,slova pozadine,slova na alatnoj traci,obilježja,opći fontovi +X-KDE-Keywords[ca]=tipus de lletres,mida de tipus de lletra,estils,joc de caràcters,jocs de caràcters,plafó,plafó de control,escriptoris,Gestor de fitxers,Barres d'eines,Menú,Títol de finestra,Títol,DPI,antialiàsing,tipus de lletra d'escriptori,tipus de lletra de barra d'eines,caràcter,tipus de lletra general +X-KDE-Keywords[ca@valencia]=tipus de lletres,mida de tipus de lletra,estils,joc de caràcters,jocs de caràcters,plafó,plafó de control,escriptoris,Gestor de fitxers,Barres d'eines,Menú,Títol de finestra,Títol,DPI,antialiàsing,tipus de lletra d'escriptori,tipus de lletra de barra d'eines,caràcter,tipus de lletra general +X-KDE-Keywords[da]=skrifttyper,skriftstørrelse,stile,tegnsæt,panel,kontrolpanel,skriveborde,filhåndtering,værktøjslinjer,menu,vinduestitel,titel,DPI,anti-aliasing,værktøjslinjer,tegn +X-KDE-Keywords[de]=Schriftarten,Schriftgrößen,Stile,Zeichensätze,Kontrollleiste,Stile,Dateiverwaltung,Arbeitsflächen,Werkzeugleisten,Menüs,Fenstertitel,Titel,DPI,Antialiasing,Arbeitsflächeschriften,Werkzeugleistenschriften,Zeichen,Allgemeine Schriftarten +X-KDE-Keywords[el]=γραμματοσειρές,μέγεθος γραμματοσειράς,στιλ,σύνολα χαρακτήρων,πίνακας,πίνακας ελέγχου,επιφάνειες εργασίας,διαχειριστής αρχείων,γραμμές εργαλείων,μενού,τίτλος παραθύρου,τίτλος,DPI,εξομάλυνση,γραμματοσειρές επιφάνειας εργασίας,γραμματοσειρές γραμμής εργαλείων,χαρακτήρας,γενικές γραμματοσειρές +X-KDE-Keywords[en_GB]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts +X-KDE-Keywords[es]=tipos de letra,tamaño del tipo de letra,estilos,juegos de caracteres,panel,panel de control panel,escritorios,Gestor de archivos,Barras de herramientas,Menú,Título de la ventana,Título,DPI,suavizado de texto,tipos de letra del escritorio,tipos de letra de las barras de herramientas,carácter,tipos de letra generales +X-KDE-Keywords[et]=fondid,fondi suurus,kodeering,kooditabel,paneel,juhtpaneel,töölauad,failihaldur,tööriistaribad,menüü,aken,tiitel,nimetus,nimi,DPI,antialias,töölaua fondid,tööriistariba fondid,märk,märgid,sümbolid,üldised fondid +X-KDE-Keywords[eu]=letra-tipoak,letra-tamaina,estiloak,karaktere-jokoak,panela,kontrol-panela,mahaigain,fitxategi-kudeatzaile,tresna-barra,menu,leihoaren titulu,titulu,DPI,antialiasing,mahaigaineko letra-tripo,tresna-barrako letra-tipo,karaktere,letra-tipo orokor +X-KDE-Keywords[fi]=kirjasimet,fontit,kirjasinkoko,fonttikoko,tyylit,merkistöt,paneeli,ohjauskeskus,työpöydät,Tiedostonhallinta,Työkalurivit,Työkalupalkit,Valikko,Ikkunan otsikko,Otsikko,DPI,antialiasointi,työpöytäkirjasimet,työpöytäfontit,työkalurivikirjasimet, työkalurivien kirjasimet, työkalurivifontit, työkalurivien fontit,merkki,yleiskirjasimet,yleiset kirjasimet,yleisfontit,yleiset fontit +X-KDE-Keywords[fr]=polices, taille de police, styles, tables de caractères, jeux de caractères, tableau de bord, bureaux, Gestionnaire de Fichiers, Barre d'outils, Menu, Titre de fenêtre, Titre, DPI, anti crénelage, polices du bureau, police de barre d'outils, caractère, polices générales +X-KDE-Keywords[ga]=clónna,clófhoirne,clómhéid,stíleanna,tacair charachtar,painéal,painéal rialaithe,deasca,Bainisteoir Comhad,Barraí Uirlisí,Roghchlár,Teideal Fuinneoige,Teideal,PSO,frithailiasáil,clónna deisce,clófhoirne deisce,clónna barra uirlisí,carachtar,clónna ginearálta,clófhoirne ginearálta +X-KDE-Keywords[gl]=tipo de letra, letra, tamaño da letra, carácter, caracteres, conxunto de caracteres, glifo, panel, control, panel de control, antialiasing, suavizado +X-KDE-Keywords[hu]=betűkészletek,betűméret,stílusok,karakterkészletek,karakterkészletek,panel,beállítópanel,asztalok,Fájlkezelő,Eszköztárak,Menü,Ablakcím,Cím,DPI,élsimítás,asztal betűkészletek,eszköztár betűkészletek,karakter,általános betűkészletek +X-KDE-Keywords[ia]=fonts,grandor de font,stilos,insimules de characteres,insimules de characteres,pannello,pannello de controlo,scriptorios,Gerente de File,Barra de instrumentos,menu,Titulo de Fenestra,Titulo,DPI,anti-aliasing,fonts de scriptorio, fonts de barra de titulo, character,fonts general +X-KDE-Keywords[it]=caratteri,dimensione dei caratteri,stili,codifiche,insiemi di caratteri,pannello,pannello di controllo,desktop,gestore dei file,barre degli strumenti,menu,titolo della finestra,titolo,DPI,anti-aliasing,caratteri del desktop,caratteri della barra degli strumenti,carattere,caratteri generali +X-KDE-Keywords[kk]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts +X-KDE-Keywords[km]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts +X-KDE-Keywords[ko]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts,글꼴,스타일,창 제목,글자 +X-KDE-Keywords[mr]=फॉन्ट्स, फॉन्ट साईज, कॅरेक्टर, कॅरेक्टर सेटस, पँनल, कन्ट्रोल पँनल, डेस्कटॉप्स, फाईल मेनेजर, टूलबार्स, मेन्यू, चौकट टाईटल, टाईटल, डी पी आय , अन्टी अलायझिंग, डेस्कटॉप फॉन्टस, टूलबार फॉन्टस, कॅरेक्टर, जनरल फॉन्ट्स +X-KDE-Keywords[nb]=skrifter,skriftstørrelse,stiler,tegnsett,panel,kontrollpanel,skrivebord,filbehandler,Verktøylinje,Meny,Vindiustittel,tittel,DPI,kantutjevning,skrivebordsskrifter,verktøylinjeskrifter,generelle skrifter +X-KDE-Keywords[nds]=Schriftoorden,Schrift,Stilen,Tekensetten,Paneel,Stüerpaneel,Schriefdisch,Dateipleger,Warktüüchbalkens,Menü,Finstertitel,Titel,DPI,Kantstreken,anti-aliasing,Schriefdisch,Teken +X-KDE-Keywords[nl]=lettertypes,lettertype,tekengrootte,stijlen,tekensets,paneel,besturingspaneel,bureaubladen,bestandsbeheerder,werkbalken,menu,venstertitel,titel,DPI,anti-aliasing,lettertypen van bureaublad,lettertypen van werkbalk,teken,algemene lettertypes +X-KDE-Keywords[pl]=czcionki,rozmiar czcionki,style,zestaw znaków,panel,panel sterowania,pulpity,Menadżer plików,Paski narzędzi,Menu,Tytuł okna,Tytuł,DPI,wygładzanie,czcionki pulpitu,czcionki pasków narzędzi,znak,czcionki ogólne +X-KDE-Keywords[pt]=tipos de letra,tamanho de letra,estilos,codificações,codificações de caracteres,painel,painel de controlo,ecrãs,gestor de ficheiros,barras de ferramentas,menu,título da janela,título,PPP,suavização,tipos de letra do ecrã,tipos de letra da barra de ferramentas,carácter,tipos de letra gerais +X-KDE-Keywords[pt_BR]=fontes,tamanho da fonte,estilos,codificações,codificações de caracteres,painel,painel de controle,áreas de trabalho,gerenciador de arquivos,barras de ferramentas,Menu,Título da janela,Título,PPP,anti-aliasing,fontes da área de trabalho,fontes da barra de ferramentas,caractere,fontes gerais +X-KDE-Keywords[ru]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts,шрифты,размер шрифтов,стили,кодировки,панель,панель управления,рабочие столы,диспетчер файлов,панель инструментов,меню,заголовок окна,заголовок,сглаживание,шрифты рабочего стола,шрифты панели инструментов,символы,общие шрифты +X-KDE-Keywords[sk]=písmo,veľkosť písma,štýly,znakové sady,sady znakov,panel,ovládací panel,plochy,Správca súborov,Panely nástrojov,Ponuka,Titulok okna,Titulok,DPI,anti-aliasing,písma plochy,písma nástrojových panelov,znak,všeobecné písma +X-KDE-Keywords[sl]=pisave,velikost pisav,slogi,nabori znakov,znakovni nabori,pult,nadzorna plošča,namizja,upravljalnik datotek,datotečni upravljalnik,orodjarne,orodne vrstice,meni,naslov okna,naslovna vrstica,naslov,ločljivost,točk na palec,glajenje robov,namizne pisave,pisave namizja,pisave orodjarne, pisave orodne vrstice,znak,splošne pisave +X-KDE-Keywords[sr]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts,фонт,величина фонта,стил,кодирање,панел,контролни панел,површ,менаџер фајлова,траке алатки,мени,наслов прозора,тпи,омекшавање,фонт површи,фонт траке алатки,знакови,општи фонт +X-KDE-Keywords[sr@ijekavian]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts,фонт,величина фонта,стил,кодирање,панел,контролни панел,површ,менаџер фајлова,траке алатки,мени,наслов прозора,тпи,омекшавање,фонт површи,фонт траке алатки,знакови,општи фонт +X-KDE-Keywords[sr@ijekavianlatin]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts,font,veličina fonta,stil,kodiranje,panel,kontrolni panel,površ,menadžer fajlova,trake alatki,meni,naslov prozora,tpi,omekšavanje,font površi,font trake alatki,znakovi,opšti font +X-KDE-Keywords[sr@latin]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts,font,veličina fonta,stil,kodiranje,panel,kontrolni panel,površ,menadžer fajlova,trake alatki,meni,naslov prozora,tpi,omekšavanje,font površi,font trake alatki,znakovi,opšti font +X-KDE-Keywords[sv]=teckensnitt,teckenstorlek,stil,teckenuppsättningar,panel,kontrollpanel,skrivbord,Filhanterare,Verktygsrader,Meny,Fönsternamn,Namn,Punkter/tum,kantutjämning,skrivbordsteckensnitt,verktygsradsteckensnitt,tecken,allmänna teckensnitt +X-KDE-Keywords[tr]=yazı tipi,yazı tipi boyutu,karakterler,karakter setleri,panel,denetim paneli,masaüstleri,Dosya Yöneticisi,Araç Çubukları,Menü,Pencere Başlığı,Başlık,DPI,yumuşatma,anti-aliasing,masaüstü yazı tipleri,araç çubuğu yazı tipleri,karakter,genel yazı tipleri +X-KDE-Keywords[uk]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts,шрифт,шрифти,розмір,розмір шрифту,стиль,стилі,гарнітура,гарнітури,кодування,набір,символ,символи,набір символів,панель,панель керування,стільниця,стільниці,файл,керування,керування файлами,менеджер,панель інструментів,меню,заголовок,заголовок вікна,роздільність,згладжування,шрифти стільниці,шрифти панелі,символ,загальні шрифти +X-KDE-Keywords[x-test]=xxfonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fontsxx +X-KDE-Keywords[zh_CN]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts,字体字体大小,样式,字符集,面板,控制面板,桌面,文件管理器,工具栏,菜单,窗口标题,标题,反锯齿,桌面字体,工具栏字体,字符,常规字体 +X-KDE-Keywords[zh_TW]=fonts,font size,styles,charsets,character sets,panel,control panel,desktops,FileManager,Toolbars,Menu,Window Title,Title,DPI,anti-aliasing,desktop fonts,toolbar fonts,character,general fonts + +Categories=Qt;KDE;X-KDE-settings-looknfeel; diff --git a/kcontrol/fonts/fonts.h b/kcontrol/fonts/fonts.h new file mode 100644 index 00000000..e98d0604 --- /dev/null +++ b/kcontrol/fonts/fonts.h @@ -0,0 +1,127 @@ +//----------------------------------------------------------------------------- +// +// kdisplay, fonts tab +// +// Copyright (c) Mark Donohoe 1997 +// Lars Knoll 1999 + +#ifndef FONTS_H +#define FONTS_H + +#include +#include + +#include +#include +#include + +#include "kxftconfig.h" + +class QCheckBox; +class QComboBox; +class QSpinBox; +class KDoubleNumInput; +class FontAASettings; + +class FontUseItem : public KFontRequester +{ + Q_OBJECT + +public: + FontUseItem(QWidget * parent, const QString &name, const QString &grp, + const QString &key, const QString &rc, const QFont &default_fnt, + bool fixed = false); + + void readFont(); + void writeFont(); + void setDefault(); + void applyFontDiff(const QFont &fnt, int fontDiffFlags); + + const QString& rcFile() { return _rcfile; } + const QString& rcGroup() { return _rcgroup; } + const QString& rcKey() { return _rckey; } + +private: + QString _rcfile; + QString _rcgroup; + QString _rckey; + QFont _default; +}; + +class FontAASettings : public KDialog +{ + Q_OBJECT + +public: + +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + FontAASettings(QWidget *parent); + + bool save( bool useAA ); + bool load(); + void defaults(); + int getIndex(KXftConfig::SubPixel::Type spType); + KXftConfig::SubPixel::Type getSubPixelType(); + int getIndex(KXftConfig::Hint::Style hStyle); + KXftConfig::Hint::Style getHintStyle(); + void enableWidgets(); + int exec(); +#endif + +protected Q_SLOTS: + + void changed(); + +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) +private: + + QCheckBox *excludeRange; + QCheckBox *useSubPixel; + KDoubleNumInput *excludeFrom; + KDoubleNumInput *excludeTo; + QComboBox *subPixelType; + QComboBox *hintingStyle; + QLabel *excludeToLabel; + bool changesMade; +#endif +}; + +/** + * The Desktop/fonts tab in kcontrol. + */ +class KFonts : public KCModule +{ + Q_OBJECT + +public: + KFonts(QWidget *parent, const QVariantList &); + ~KFonts(); + + virtual void load(); + virtual void save(); + virtual void defaults(); + +protected Q_SLOTS: + void fontSelected(); + void slotApplyFontDiff(); + void slotUseAntiAliasing(); + void slotCfgAa(); + +private: +#if defined(HAVE_FONTCONFIG) && defined (Q_WS_X11) + enum AASetting { AAEnabled, AASystem, AADisabled }; + AASetting useAA, useAA_original; + QComboBox *cbAA; + QPushButton *aaSettingsButton; + FontAASettings *aaSettings; +#endif +#ifdef Q_WS_X11 + int dpi_original; + QCheckBox *checkboxForceDpi; + QSpinBox* spinboxDpi; +#endif + QList fontUseList; +}; + +#endif + diff --git a/kcontrol/fonts/kxftconfig.cpp b/kcontrol/fonts/kxftconfig.cpp new file mode 100644 index 00000000..410bf015 --- /dev/null +++ b/kcontrol/fonts/kxftconfig.cpp @@ -0,0 +1,847 @@ +/* + Copyright (c) 2002 Craig Drummond + + 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 "kxftconfig.h" +#ifdef HAVE_FONTCONFIG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace std; + +static int point2Pixel(double point) +{ + return (int)(((point*QX11Info::appDpiY())/72.0)+0.5); +} + +static int pixel2Point(double pixel) +{ + return (int)(((pixel*72.0)/(double)QX11Info::appDpiY())+0.5); +} + +static bool equal(double d1, double d2) +{ + return (fabs(d1 - d2) < 0.0001); +} + +static QString dirSyntax(const QString &d) +{ + if(!d.isNull()) + { + QString ds(d); + + ds.replace("//", "/"); + + int slashPos=ds.lastIndexOf('/'); + + if(slashPos!=(((int)ds.length())-1)) + ds.append('/'); + + return ds; + } + + return d; +} + +static bool check(const QString &path, unsigned int fmt, bool checkW=false) +{ + KDE_struct_stat info; + QByteArray pathC(QFile::encodeName(path)); + + return 0==KDE_lstat(pathC, &info) && (info.st_mode&S_IFMT)==fmt && + (!checkW || 0==::access(pathC, W_OK)); +} + +inline bool fExists(const QString &p) +{ + return check(p, S_IFREG, false); +} + +inline bool dWritable(const QString &p) +{ + return check(p, S_IFDIR, true); +} + +static QString getDir(const QString &f) +{ + QString d(f); + + int slashPos=d.lastIndexOf('/'); + + if(-1!=slashPos) + d.remove(slashPos+1, d.length()); + + return dirSyntax(d); +} + +static time_t getTimeStamp(const QString &item) +{ + KDE_struct_stat info; + + return !item.isNull() && 0==KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0; +} + +// +// Obtain location of config file to use. +QString getConfigFile() +{ + FcStrList *list=FcConfigGetConfigFiles(FcConfigGetCurrent()); + QStringList files; + FcChar8 *file; + QString home(dirSyntax(QDir::homePath())); + + while((file=FcStrListNext(list))) + { + QString f((const char *)file); + + if(fExists(f) && 0==f.indexOf(home)) + files.append(f); + } + FcStrListDone(list); + + // + // Go through list of files, looking for the preferred one... + if(files.count()) + { + QStringList::const_iterator it(files.begin()), + end(files.end()); + + for(; it!=end; ++it) + if(-1!=(*it).indexOf(QRegExp("/\\.?fonts\\.conf$"))) + return *it; + return files.front(); // Just return the 1st one... + } + else // Hmmm... no known files? + { + if(FcGetVersion() >= 21000) + { + QString targetPath(KGlobal::dirs()->localxdgconfdir()+"fontconfig"); + QDir target(targetPath); + if(!target.exists()) + target.mkpath(targetPath); + return targetPath+"/fonts.conf"; + } + else + return home+"/.fonts.conf"; + } +} + +static QString getEntry(QDomElement element, const char *type, unsigned int numAttributes, ...) +{ + if(numAttributes==element.attributes().length()) + { + va_list args; + unsigned int arg; + bool ok=true; + + va_start(args, numAttributes); + + for(arg=0; arg"; + static const char qtDocTypeLine[] = ""; + static const char docTypeLine[] = ""; + + QString str(m_doc.toString()); + int idx; + + if(0!=str.indexOf("=0 || to>=0) && foundFalse) + { + m_excludeRange.from=from < to ? from : to; + m_excludeRange.to =from < to ? to : from; + m_excludeRange.node=n; + } + else if((pixelFrom>=0 || pixelTo>=0) && foundFalse) + { + m_excludePixelRange.from=pixelFrom < pixelTo ? pixelFrom : pixelTo; + m_excludePixelRange.to =pixelFrom < pixelTo ? pixelTo : pixelFrom; + m_excludePixelRange.node=n; + } + } + break; + default: + break; + } + } + } + n=n.nextSibling(); + } +} + +void KXftConfig::applySubPixelType() +{ + QDomElement matchNode = m_doc.createElement("match"), + typeNode = m_doc.createElement("const"), + editNode = m_doc.createElement("edit"); + QDomText typeText = m_doc.createTextNode(toStr(m_subPixel.type)); + + matchNode.setAttribute("target", "font"); + editNode.setAttribute("mode", "assign"); + editNode.setAttribute("name", "rgba"); + editNode.appendChild(typeNode); + typeNode.appendChild(typeText); + matchNode.appendChild(editNode); + if(m_subPixel.node.isNull()) + m_doc.documentElement().appendChild(matchNode); + else + m_doc.documentElement().replaceChild(matchNode, m_subPixel.node); + m_subPixel.node=matchNode; +} + +void KXftConfig::applyHintStyle() +{ + applyHinting(); + + if(Hint::NotSet==m_hint.style || m_hint.toBeRemoved) + { + if(!m_hint.node.isNull()) + { + m_doc.documentElement().removeChild(m_hint.node); + m_hint.node.clear(); + } + } + else + { + QDomElement matchNode = m_doc.createElement("match"), + typeNode = m_doc.createElement("const"), + editNode = m_doc.createElement("edit"); + QDomText typeText = m_doc.createTextNode(toStr(m_hint.style)); + + matchNode.setAttribute("target", "font"); + editNode.setAttribute("mode", "assign"); + editNode.setAttribute("name", "hintstyle"); + editNode.appendChild(typeNode); + typeNode.appendChild(typeText); + matchNode.appendChild(editNode); + if(m_hint.node.isNull()) + m_doc.documentElement().appendChild(matchNode); + else + m_doc.documentElement().replaceChild(matchNode, m_hint.node); + m_hint.node=matchNode; + } +} + +void KXftConfig::applyHinting() +{ + QDomElement matchNode = m_doc.createElement("match"), + typeNode = m_doc.createElement("bool"), + editNode = m_doc.createElement("edit"); + QDomText typeText = m_doc.createTextNode(m_hinting.set ? "true" : "false"); + + matchNode.setAttribute("target", "font"); + editNode.setAttribute("mode", "assign"); + editNode.setAttribute("name", "hinting"); + editNode.appendChild(typeNode); + typeNode.appendChild(typeText); + matchNode.appendChild(editNode); + if(m_hinting.node.isNull()) + m_doc.documentElement().appendChild(matchNode); + else + m_doc.documentElement().replaceChild(matchNode, m_hinting.node); + m_hinting.node=matchNode; +} + +void KXftConfig::applyExcludeRange(bool pixel) +{ + Exclude &range=pixel ? m_excludePixelRange : m_excludeRange; + + if(equal(range.from, 0) && equal(range.to, 0)) + { + if(!range.node.isNull()) + { + m_doc.documentElement().removeChild(range.node); + range.node.clear(); + } + } + else + { + QString fromString, + toString; + + fromString.setNum(range.from); + toString.setNum(range.to); + + QDomElement matchNode = m_doc.createElement("match"), + fromTestNode = m_doc.createElement("test"), + fromNode = m_doc.createElement("double"), + toTestNode = m_doc.createElement("test"), + toNode = m_doc.createElement("double"), + editNode = m_doc.createElement("edit"), + boolNode = m_doc.createElement("bool"); + QDomText fromText = m_doc.createTextNode(fromString), + toText = m_doc.createTextNode(toString), + boolText = m_doc.createTextNode("false"); + + matchNode.setAttribute("target", "font"); // CPD: Is target "font" or "pattern" ???? + fromTestNode.setAttribute("qual", "any"); + fromTestNode.setAttribute("name", pixel ? "pixelsize" : "size"); + fromTestNode.setAttribute("compare", "more_eq"); + fromTestNode.appendChild(fromNode); + fromNode.appendChild(fromText); + toTestNode.setAttribute("qual", "any"); + toTestNode.setAttribute("name", pixel ? "pixelsize" : "size"); + toTestNode.setAttribute("compare", "less_eq"); + toTestNode.appendChild(toNode); + toNode.appendChild(toText); + editNode.setAttribute("mode", "assign"); + editNode.setAttribute("name", "antialias"); + editNode.appendChild(boolNode); + boolNode.appendChild(boolText); + matchNode.appendChild(fromTestNode); + matchNode.appendChild(toTestNode); + matchNode.appendChild(editNode); + + if(!m_antiAliasing.node.isNull()) + m_doc.documentElement().removeChild(range.node); + m_doc.documentElement().appendChild(matchNode); + range.node=matchNode; + } +} + +bool KXftConfig::getAntiAliasing() const +{ + return m_antiAliasing.set; +} + +void KXftConfig::setAntiAliasing( bool set ) +{ + if(set!=m_antiAliasing.set) + { + m_antiAliasing.set = set; + m_madeChanges = true; + } +} + +void KXftConfig::applyAntiAliasing() +{ + QDomElement matchNode = m_doc.createElement("match"), + typeNode = m_doc.createElement("bool"), + editNode = m_doc.createElement("edit"); + QDomText typeText = m_doc.createTextNode(m_antiAliasing.set ? "true" : "false"); + + matchNode.setAttribute("target", "font"); + editNode.setAttribute("mode", "assign"); + editNode.setAttribute("name", "antialias"); + editNode.appendChild(typeNode); + typeNode.appendChild(typeText); + matchNode.appendChild(editNode); + if(!m_antiAliasing.node.isNull()) + m_doc.documentElement().removeChild(m_antiAliasing.node); + m_doc.documentElement().appendChild(matchNode); + m_antiAliasing.node=matchNode; +} + +// KXftConfig only parses one config file, user's .fonts.conf usually. +// If that one doesn't exist, then KXftConfig doesn't know if antialiasing +// is enabled or not. So try to find out the default value from the default font. +// Maybe there's a better way *shrug*. +bool KXftConfig::aliasingEnabled() +{ + FcPattern *pattern = FcPatternCreate(); + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + FcResult result; + FcPattern *f = FcFontMatch( 0, pattern, &result ); + FcBool antialiased = FcTrue; + FcPatternGetBool( f, FC_ANTIALIAS, 0, &antialiased ); + FcPatternDestroy( f ); + FcPatternDestroy( pattern ); + return antialiased == FcTrue; +} + +#endif diff --git a/kcontrol/fonts/kxftconfig.h b/kcontrol/fonts/kxftconfig.h new file mode 100644 index 00000000..0df61645 --- /dev/null +++ b/kcontrol/fonts/kxftconfig.h @@ -0,0 +1,167 @@ +#ifndef __KXFTCONFIG_H__ +#define __KXFTCONFIG_H__ + +/* + Copyright (c) 2002 Craig Drummond + + 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 + +#ifdef HAVE_FONTCONFIG + +#include + +#include +#include + +class KXftConfig +{ + public: + + struct Item + { + Item(QDomNode &n) : node(n), toBeRemoved(false) {} + Item() : toBeRemoved(false) {} + virtual void reset() { node.clear(); toBeRemoved=false; } + bool added() { return node.isNull(); } + + QDomNode node; + + virtual ~Item() {} + bool toBeRemoved; + }; + + struct SubPixel : public Item + { + enum Type + { + None, + Rgb, + Bgr, + Vrgb, + Vbgr + }; + + SubPixel(Type t, QDomNode &n) : Item(n), type(t) {} + SubPixel(Type t=None) : type(t) {} + + void reset() { Item::reset(); type=None; } + + Type type; + }; + + struct Exclude : public Item + { + Exclude(double f, double t, QDomNode &n) : Item(n), from(f), to(t) {} + Exclude(double f=0, double t=0) : from(f), to(t) {} + + void reset() { Item::reset(); from=to=0; } + + double from, + to; + }; + + struct Hint : public Item + { + enum Style + { + NotSet, + None, + Slight, + Medium, + Full + }; + + Hint(Style s, QDomNode &n) : Item(n), style(s) {} + Hint(Style s=NotSet) : style(s) {} + + void reset() { Item::reset(); style=NotSet; } + + Style style; + }; + + struct Hinting : public Item + { + Hinting(bool s, QDomNode &n) : Item(n), set(s) {} + Hinting(bool s=true) : set(s) {} + + void reset() { Item::reset(); set=true; } + + bool set; + }; + + struct AntiAliasing : public Item + { + AntiAliasing(bool s, QDomNode &n) : Item(n), set(s) {} + AntiAliasing(bool s=true) : set(s) {} + + void reset() { Item::reset(); set=true; } + + bool set; + }; + + public: + + explicit KXftConfig(); + + virtual ~KXftConfig(); + + bool reset(); + bool apply(); + bool getSubPixelType(SubPixel::Type &type); + void setSubPixelType(SubPixel::Type type); // SubPixel::None => turn off sub-pixel rendering + bool getExcludeRange(double &from, double &to); + void setExcludeRange(double from, double to); // from:0, to:0 => turn off exclude range + bool getHintStyle(Hint::Style &style); + void setHintStyle(Hint::Style style); + void setAntiAliasing(bool set); + bool getAntiAliasing() const; + bool changed() { return m_madeChanges; } + static QString description(SubPixel::Type t); + static const char * toStr(SubPixel::Type t); + static QString description(Hint::Style s); + static const char * toStr(Hint::Style s); + + private: + + void readContents(); + void applySubPixelType(); + void applyHintStyle(); + void applyAntiAliasing(); + void setHinting(bool set); + void applyHinting(); + void applyExcludeRange(bool pixel); + bool aliasingEnabled(); + + private: + + SubPixel m_subPixel; + Exclude m_excludeRange, + m_excludePixelRange; + Hint m_hint; + Hinting m_hinting; + AntiAliasing m_antiAliasing; + QDomDocument m_doc; + QString m_file; + bool m_madeChanges; + time_t m_time; +}; + +#endif + +#endif diff --git a/kcontrol/hardware/CMakeLists.txt b/kcontrol/hardware/CMakeLists.txt new file mode 100644 index 00000000..d938c974 --- /dev/null +++ b/kcontrol/hardware/CMakeLists.txt @@ -0,0 +1,9 @@ + +add_subdirectory( display ) + +if (CMAKE_SYSTEM_NAME MATCHES Linux) + # this one doesn't seem to be very portable, Alex + add_subdirectory( joystick ) +endif (CMAKE_SYSTEM_NAME MATCHES Linux) + + diff --git a/kcontrol/hardware/display/CMakeLists.txt b/kcontrol/hardware/display/CMakeLists.txt new file mode 100644 index 00000000..59174bae --- /dev/null +++ b/kcontrol/hardware/display/CMakeLists.txt @@ -0,0 +1,19 @@ + + + +########### next target ############### + +set(kcm_display_PART_SRCS display.cpp ) + + +kde4_add_plugin(kcm_display ${kcm_display_PART_SRCS}) + + +target_link_libraries(kcm_display ${KDE4_KCMUTILS_LIBS} ${QT_QTGUI_LIBRARY} ${KDE4_KDEUI_LIBS}) + +install(TARGETS kcm_display DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES display.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/kcontrol/hardware/display/Messages.sh b/kcontrol/hardware/display/Messages.sh new file mode 100644 index 00000000..561ccd0d --- /dev/null +++ b/kcontrol/hardware/display/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/display.pot diff --git a/kcontrol/hardware/display/display.cpp b/kcontrol/hardware/display/display.cpp new file mode 100644 index 00000000..8746d098 --- /dev/null +++ b/kcontrol/hardware/display/display.cpp @@ -0,0 +1,118 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Nadeem Hasan + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "display.h" +#include +#include + +K_PLUGIN_FACTORY(DisplayFactory, + registerPlugin(); + ) +K_EXPORT_PLUGIN(DisplayFactory("display")) + +KCMDisplay::KCMDisplay( QWidget *parent, const QVariantList & ) + : KCModule( DisplayFactory::componentData(), parent ) + , m_changed(false) +{ + m_tabs = new QTabWidget( this ); + + addTab( "randr", i18n( "Size && Orientation" ) ); + addTab( "nvidiadisplay", i18n( "Graphics Adaptor" ) ); + addTab( "nvidia3d", i18n( "3D Options" ) ); + addTab( "kgamma", i18n( "Monitor Gamma" ) ); + if ( QApplication::desktop()->isVirtualDesktop() ) + addTab( "xinerama", i18n( "Multiple Monitors" ) ); + addTab( "energy", i18n( "Power Control" ) ); + + QVBoxLayout *top = new QVBoxLayout( this ); + top->setMargin( 0 ); + top->setSpacing( KDialog::spacingHint() ); + top->addWidget( m_tabs ); + + setButtons( Apply ); + load(); +} + +void KCMDisplay::addTab( const QString &name, const QString &label ) +{ + QWidget *page = new QWidget( m_tabs ); + QVBoxLayout *top = new QVBoxLayout( page ); + top->setMargin( KDialog::marginHint() ); + + KCModule *kcm = KCModuleLoader::loadModule( name, KCModuleLoader::None,page ); + + if ( kcm ) + { + top->addWidget( kcm ); + m_tabs->addTab( page, label ); + + connect( kcm, SIGNAL(changed(bool)), SLOT(moduleChanged(bool)) ); + m_modules.insert(kcm, false); + } + else + delete page; +} + +void KCMDisplay::load() +{ + for (QMap::ConstIterator it = m_modules.constBegin(); it != m_modules.constEnd(); ++it) + it.key()->load(); +} + +void KCMDisplay::save() +{ + for (QMap::Iterator it = m_modules.begin(); it != m_modules.end(); ++it) + if (it.value()) + it.key()->save(); +} + +void KCMDisplay::moduleChanged( bool isChanged ) +{ + QMap::Iterator currentModule = m_modules.find(static_cast(const_cast(sender()))); + Q_ASSERT(currentModule != m_modules.end()); + if (currentModule.value() == isChanged) + return; + + currentModule.value() = isChanged; + + bool c = false; + + for (QMap::ConstIterator it = m_modules.constBegin(); it != m_modules.constEnd(); ++it) { + if (it.value()) { + c = true; + break; + } + } + + if (m_changed != c) { + m_changed = c; + emit changed(c); + } +} + +#include "display.moc" diff --git a/kcontrol/hardware/display/display.desktop b/kcontrol/hardware/display/display.desktop new file mode 100644 index 00000000..5b434ceb --- /dev/null +++ b/kcontrol/hardware/display/display.desktop @@ -0,0 +1,187 @@ +[Desktop Entry] +Exec=kcmshell4 display +Icon=preferences-desktop-display +Type=Service +X-KDE-ServiceTypes=KCModule + +X-KDE-Library=kcm_display +X-KDE-ParentApp=kcontrol + +Name=Display +Name[af]=Skerm +Name[ar]=العرض +Name[ast]=Pantalla +Name[be]=Экран +Name[be@latin]=Ekran +Name[bg]=Екран +Name[bn]=ডিসপ্লে +Name[bn_IN]=প্রদর্শন +Name[br]=Diskwel +Name[bs]=Ekran +Name[ca]=Pantalla +Name[ca@valencia]=Pantalla +Name[cs]=Obrazovka +Name[csb]=Ekran +Name[cy]= Arddangos +Name[da]=Skærm +Name[de]=Anzeige +Name[el]=Οθόνη +Name[en_GB]=Display +Name[eo]=Vidigilo +Name[es]=Pantalla +Name[et]=Monitor +Name[eu]=Pantaila +Name[fa]=نمایش +Name[fi]=Näyttö +Name[fy]=Byldskerm +Name[ga]=Scáileán +Name[gl]=Pantalla +Name[gu]=ડિસ્પ્લે +Name[he]=תצוגה +Name[hi]=प्रदर्शक +Name[hne]=प्रदर्सक +Name[hr]=Zaslon +Name[hsb]=Wobrazowka +Name[hu]=Megjelenítés +Name[ia]=Monstrator +Name[id]=Tampilan +Name[is]=Skjár +Name[ka]=ჩვენება +Name[kk]=Дисплей +Name[km]=ការ​បង្ហាញ +Name[kn]=ಪ್ರದರ್ಶಕ +Name[ko]=표시 +Name[ku]=Dîmender +Name[lt]=Ekranas +Name[lv]=Ekrāns +Name[mai]=देखाबू +Name[mk]=Приказ +Name[ml]=പ്രദര്‍ശനം +Name[mr]=डिस्प्ले +Name[ms]=Paparan +Name[nb]=Bildeskjerm +Name[nds]=Schirm +Name[ne]=प्रदर्शन गर्नुहोस् +Name[nl]=Beeldscherm +Name[oc]=Visualizar +Name[or]=ପ୍ରଦର୍ଶକ +Name[pa]=ਡਿਸਪਲੇਅ +Name[pl]=Wyświetlanie +Name[pt]=Ecrã +Name[pt_BR]=Tela +Name[ro]=Afișare +Name[ru]=Экран +Name[se]=Šearbma +Name[si]=සංදර්ශනය +Name[sk]=Obrazovka +Name[sl]=Zaslon +Name[sr]=Екран +Name[sr@ijekavian]=Екран +Name[sr@ijekavianlatin]=Ekran +Name[sr@latin]=Ekran +Name[sv]=Bildskärm +Name[ta]=காட்சி +Name[te]=ప్రదర్శన +Name[tg]=Экран +Name[th]=การแสดงผล +Name[tr]=Ekran +Name[ug]=كۆرسەت +Name[uk]=Дисплей +Name[uz]=Displey +Name[uz@cyrillic]=Дисплей +Name[vi]=Màn hình +Name[wa]=Håynaedje +Name[x-test]=xxDisplayxx +Name[zh_CN]=显示 +Name[zh_TW]=顯示 +Comment=Display Settings +Comment[af]=Skerm Instellings +Comment[ar]=إعدادات العرض +Comment[ast]=Preferencies de la pantalla +Comment[be]=Настаўленні экрану +Comment[be@latin]=Nałady ekrana +Comment[bg]=Настройки на екрана +Comment[bn]=ডিসপ্লে সেটিংস +Comment[bn_IN]=প্রদর্শন সংক্রান্ত বৈশিষ্ট্য +Comment[br]=Kefluniañ an diskwel +Comment[bs]=Postavke ekrana +Comment[ca]=Arranjament de la pantalla +Comment[ca@valencia]=Arranjament de la pantalla +Comment[cs]=Nastavení obrazovky +Comment[csb]=Ùstôw ekranu +Comment[cy]=Gosodiadau Arddangos +Comment[da]=Skærmindstillinger +Comment[de]=Anzeige-Einstellungen +Comment[el]=Ρυθμίσεις οθόνης +Comment[en_GB]=Display Settings +Comment[eo]=Vidigila agordo +Comment[es]=Preferencias de la pantalla +Comment[et]=Monitoride seadistused +Comment[eu]=Pantailaren ezarpenak +Comment[fa]=نمایش تنظیمات +Comment[fi]=Näytön asetukset +Comment[fr]=Configuration de l'affichage +Comment[fy]=Byldskerm ynstellings +Comment[ga]=Socruithe an Scáileáin +Comment[gl]=Configuración da pantalla +Comment[gu]=ડિસ્પ્લે ગોઠવણીઓ +Comment[he]=הגדרות תצוגה +Comment[hi]=प्रकटन विन्यास +Comment[hne]=देखइया सेटिंग +Comment[hr]=Postavke zaslona +Comment[hsb]=Nastajenja za wobrazowku +Comment[hu]=Megjelenési beállítások +Comment[ia]=Monstra preferentias +Comment[id]=Pengaturan Tampilan +Comment[is]=Stillingar skjás +Comment[it]=Impostazioni dello schermo +Comment[ja]=ディスプレイの設定 +Comment[ka]=დისპლეის კონფიგურირება +Comment[kk]=Дисплей баптаулары +Comment[km]=កំណត់​ការ​បង្ហាញ +Comment[kn]=ಪ್ರದರ್ಶಕದ ಸಂಯೋಜನೆಗಳು +Comment[ko]=디스플레이 설정 +Comment[ku]=Mîhengên Dîmenderê +Comment[lt]=Ekrano parametrai +Comment[lv]=Ekrāna parametri +Comment[mai]=जमावट देखाबू +Comment[mk]=Поставувања на приказот +Comment[ml]=പ്രദര്‍ശനത്തിന്റെ സജ്ജീകരണങ്ങള്‍ +Comment[mr]=डिस्प्ले संयोजना +Comment[ms]=Seting Paparan +Comment[nb]=Skjerminnstillinger +Comment[nds]=Dorstellen inrichten +Comment[ne]=सेटिङ प्रदर्शन गर्नुहोस् +Comment[nl]=Beeldscherminstellingen +Comment[nn]=Skjerminnstillingar +Comment[or]=ପ୍ରଦର୍ଶକ ସଂରଚନା +Comment[pa]=ਡਿਸਪਲੇਅ ਸੈਟਿੰਗ +Comment[pl]=Ustawienia ekranu +Comment[pt]=Configuração do ecrã +Comment[pt_BR]=Configurações da tela +Comment[ro]=Configurări afișare +Comment[ru]=Настройка экрана +Comment[se]=Šearbmaheivehusat +Comment[si]=සංදර්ශන සැකසුම් +Comment[sk]=Nastavenie obrazovky +Comment[sl]=Nastavitve zaslona +Comment[sr]=Поставке екрана +Comment[sr@ijekavian]=Поставке екрана +Comment[sr@ijekavianlatin]=Postavke ekrana +Comment[sr@latin]=Postavke ekrana +Comment[sv]=Anpassa bildskärm +Comment[ta]=அமைப்புகளை காட்டு +Comment[te]=ప్రదర్శన అమరికలు +Comment[tg]=Танзимоти экран +Comment[th]=ตั้งค่าต่าง ๆ ของการแสดงผล +Comment[tr]=Ekran Ayarları +Comment[ug]=كۆرۈنمە يۈز تەڭشىكى +Comment[uk]=Налаштування дисплея +Comment[uz]=Displeyning moslamalari +Comment[uz@cyrillic]=Дисплейнинг мосламалари +Comment[vi]=Thiết lập hiển thị +Comment[wa]=Apontiaedjes do Håynaedje +Comment[x-test]=xxDisplay Settingsxx +Comment[zh_CN]=显示设置 +Comment[zh_TW]=顯示設定 +Categories=Qt;KDE;X-KDE-settings-hardware; diff --git a/kcontrol/hardware/display/display.h b/kcontrol/hardware/display/display.h new file mode 100644 index 00000000..7e0c3422 --- /dev/null +++ b/kcontrol/hardware/display/display.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Nadeem Hasan + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef DISPLAY_H +#define DISPLAY_H + +#include + +class QTabWidget; + +class KCMDisplay : public KCModule +{ + Q_OBJECT + + public: + KCMDisplay( QWidget *parent, const QVariantList & ); + void load(); + void save(); + + private Q_SLOTS: + void moduleChanged(bool isChanged); + + private: + void addTab( const QString &name, const QString &label ); + + QTabWidget *m_tabs; + QMap m_modules; + bool m_changed; +}; + +#endif // DISPLAY_H + diff --git a/kcontrol/hardware/joystick/CMakeLists.txt b/kcontrol/hardware/joystick/CMakeLists.txt new file mode 100644 index 00000000..6028a2d8 --- /dev/null +++ b/kcontrol/hardware/joystick/CMakeLists.txt @@ -0,0 +1,26 @@ + + + +########### next target ############### + +set(kcm_joystick_PART_SRCS + joystick.cpp + joywidget.cpp + poswidget.cpp + joydevice.cpp + caldialog.cpp ) + + +kde4_add_plugin(kcm_joystick ${kcm_joystick_PART_SRCS}) + + +target_link_libraries(kcm_joystick ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${QT_QTGUI_LIBRARY}) + +install(TARGETS kcm_joystick DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES joystick.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + +# diff --git a/kcontrol/hardware/joystick/Messages.sh b/kcontrol/hardware/joystick/Messages.sh new file mode 100644 index 00000000..1d116ceb --- /dev/null +++ b/kcontrol/hardware/joystick/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/joystick.pot diff --git a/kcontrol/hardware/joystick/caldialog.cpp b/kcontrol/hardware/joystick/caldialog.cpp new file mode 100644 index 00000000..23accecb --- /dev/null +++ b/kcontrol/hardware/joystick/caldialog.cpp @@ -0,0 +1,200 @@ +/*************************************************************************** + * Copyright (C) 2003 by Martin Koller + * kollix@aon.at + * This file is part of the KDE Control Center Module for Joysticks + * + * 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 "caldialog.h" +#include "joydevice.h" + +#include +#include +#include + +#include +#include +#include +#include +//-------------------------------------------------------------- + +CalDialog::CalDialog(QWidget *parent, JoyDevice *joy) + : KDialog( parent ), + joydev(joy) +{ + setObjectName( "calibrateDialog" ); + setModal( true ); + setCaption( i18n("Calibration") ); + setButtons( Cancel | User1 ); + setDefaultButton( User1 ); + setButtonGuiItem( User1, KGuiItem( i18n("Next") ) ); + + KVBox *main = new KVBox( this ); + setMainWidget( main ); + + text = new QLabel(main); + text->setMinimumHeight(200); + valueLbl = new QLabel(main); + connect(this,SIGNAL(user1Clicked()),this,SLOT(slotUser1())); +} + +//-------------------------------------------------------------- + +void CalDialog::calibrate() +{ + text->setText(i18n("Please wait a moment to calculate the precision")); + setResult(-1); + show(); + + // calibrate precision (which min,max delivers the joystick in its center position) + // get values through the normal idle procedure + QTimer ti; + ti.setSingleShot(true); // single shot + ti.start(2000); // in 2 seconds + + // normally I'd like to hide the 'Next' button in this step, + // but it does not work - which means: in the steps after the first, + // the 'Next' button does not have the focus (to be the default button) + + do + { + qApp->processEvents(QEventLoop::AllEvents, 2000); + } + while ( ti.isActive() && (result() != QDialog::Rejected) ); + + if ( result() == QDialog::Rejected ) return; // user cancelled the dialog + + joydev->calcPrecision(); + + int i, lastVal; + int min[2], center[2], max[2]; + QString hint; + + for (i = 0; i < joydev->numAxes(); i++) + { + if ( i == 0 ) + hint = i18n("(usually X)"); + else if ( i == 1 ) + hint = i18n("(usually Y)"); + else + hint = ""; + + // minimum position + text->setText(i18n("Calibration is about to check the value range your device delivers.

" + "Please move axis %1 %2 on your device to the minimum position.

" + "Press any button on the device or click on the 'Next' button " + "to continue with the next step.
", i+1, hint)); + waitButton(i, true, lastVal); + + if ( result() == QDialog::Rejected ) return; // user cancelled the dialog + + joydev->resetMinMax(i, lastVal); + if ( result() != -2 ) waitButton(i, false, lastVal); + + if ( result() == QDialog::Rejected ) return; // user cancelled the dialog + + min[0] = joydev->axisMin(i); + min[1] = joydev->axisMax(i); + + // center position + text->setText(i18n("Calibration is about to check the value range your device delivers.

" + "Please move axis %1 %2 on your device to the center position.

" + "Press any button on the device or click on the 'Next' button " + "to continue with the next step.
", i+1, hint)); + waitButton(i, true, lastVal); + + if ( result() == QDialog::Rejected ) return; // user cancelled the dialog + + joydev->resetMinMax(i, lastVal); + if ( result() != -2 ) waitButton(i, false, lastVal); + + if ( result() == QDialog::Rejected ) return; // user canceled the dialog + + center[0] = joydev->axisMin(i); + center[1] = joydev->axisMax(i); + + // maximum position + text->setText(i18n("Calibration is about to check the value range your device delivers.

" + "Please move axis %1 %2 on your device to the maximum position.

" + "Press any button on the device or click on the 'Next' button " + "to continue with the next step.
", i+1, hint)); + waitButton(i, true, lastVal); + + if ( result() == QDialog::Rejected ) return; // user cancelled the dialog + + joydev->resetMinMax(i, lastVal); + if ( result() != -2 ) waitButton(i, false, lastVal); + + if ( result() == QDialog::Rejected ) return; // user canceled the dialog + + max[0] = joydev->axisMin(i); + max[1] = joydev->axisMax(i); + + joydev->calcCorrection(i, min, center, max); + } + + JoyDevice::ErrorCode ret = joydev->applyCalibration(); + + if ( ret != JoyDevice::SUCCESS ) + { + KMessageBox::error(this, joydev->errText(ret), i18n("Communication Error")); + reject(); + } + + KMessageBox::information(this, i18n("You have successfully calibrated your device"), i18n("Calibration Success")); + accept(); +} + +//-------------------------------------------------------------- + +void CalDialog::waitButton(int axis, bool press, int &lastVal) +{ + JoyDevice::EventType type; + int number, value; + bool button = false; + lastVal = 0; + + setResult(-1); + // loop until the user presses a button on the device or on the dialog + do + { + qApp->processEvents(QEventLoop::AllEvents, 100); + + if ( joydev->getEvent(type, number, value) ) + { + button = ( (type == JoyDevice::BUTTON) && (press ? (value == 1) : (value == 0)) ); + + if ( (type == JoyDevice::AXIS) && (number == axis) ) + valueLbl->setText(i18n("Value Axis %1: %2", axis+1, lastVal = value)); + } + } + while ( !button && (result() == -1) ); +} + +//-------------------------------------------------------------- +// Next button + +void CalDialog::slotUser1() +{ + setResult(-2); +} + +//-------------------------------------------------------------- + +#include "caldialog.moc" + +//-------------------------------------------------------------- diff --git a/kcontrol/hardware/joystick/caldialog.h b/kcontrol/hardware/joystick/caldialog.h new file mode 100644 index 00000000..1e4202c5 --- /dev/null +++ b/kcontrol/hardware/joystick/caldialog.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2003 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 _CALDIALOG_H_ +#define _CALDIALOG_H_ + +#include + +#include + +class JoyDevice; + +// the dialog which tells the user all steps to calibrate the device + +class CalDialog : public KDialog +{ + Q_OBJECT + + public: + CalDialog(QWidget *parent, JoyDevice *joy); + + void calibrate(); + + private: + void waitButton(int axis, bool press, int &lastVal); + + private slots: + virtual void slotUser1(); + + private: + JoyDevice *joydev; + + QLabel *text; + QLabel *valueLbl; +}; + +#endif diff --git a/kcontrol/hardware/joystick/joydevice.cpp b/kcontrol/hardware/joystick/joydevice.cpp new file mode 100644 index 00000000..bbe7527a --- /dev/null +++ b/kcontrol/hardware/joystick/joydevice.cpp @@ -0,0 +1,402 @@ +/*************************************************************************** + * Copyright (C) 2003 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 "joydevice.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//-------------------------------------------------------------- + +JoyDevice::JoyDevice(const QString &devicefile) + : devName(devicefile), joyFd(-1), buttons(0), axes(0), + amin(0), amax(0), corr(0), origCorr(0) +{ +} + +//-------------------------------------------------------------- + +QString JoyDevice::errText(ErrorCode code) const +{ + switch ( code ) + { + case SUCCESS: return ""; + + case OPEN_FAILED: + { + return i18n("The given device %1 could not be opened: %2", + devName, strerror(errno)); + } + + case NO_JOYSTICK: + { + return i18n("The given device %1 is not a joystick.", devName); + } + + case ERR_GET_VERSION: + { + return i18n("Could not get kernel driver version for joystick device %1: %2", + devName, strerror(errno)); + } + + case WRONG_VERSION: + { + int version = 0; + int fd = ::open(devName.toLatin1(), O_RDONLY); + if ( fd != -1 ) + { + ::ioctl(fd, JSIOCGVERSION, &version); + ::close(fd); + } + + KLocalizedString loc = ki18n("The current running kernel driver version (%1.%2.%3) is not the one this module was compiled for (%4.%5.%6)."); + loc.subs(version >> 16); + loc.subs((version >> 8) & 0xFF); + loc.subs(version & 0xFF); + loc.subs(JS_VERSION >> 16); + loc.subs((JS_VERSION >> 8) & 0xFF); + loc.subs(JS_VERSION & 0xFF); + return loc.toString(); + } + + case ERR_GET_BUTTONS: + { + return i18n("Could not get number of buttons for joystick device %1: %2", + devName, strerror(errno)); + } + + case ERR_GET_AXES: + { + return i18n("Could not get number of axes for joystick device %1: %2", + devName, strerror(errno)); + } + + case ERR_GET_CORR: + { + return i18n("Could not get calibration values for joystick device %1: %2", + devName, strerror(errno)); + } + + case ERR_RESTORE_CORR: + { + return i18n("Could not restore calibration values for joystick device %1: %2", + devName, strerror(errno)); + } + + case ERR_INIT_CAL: + { + return i18n("Could not initialize calibration values for joystick device %1: %2", + devName, strerror(errno)); + } + + case ERR_APPLY_CAL: + { + return i18n("Could not apply calibration values for joystick device %1: %2", + devName, strerror(errno)); + } + + default: return i18n("internal error - code %1 unknown", int(code)); + } +} + +//-------------------------------------------------------------- + +JoyDevice::ErrorCode JoyDevice::open() +{ + if ( joyFd != -1 ) return JoyDevice::SUCCESS; // already open + + int fd = ::open(devName.toLatin1(), O_RDONLY); + + if ( fd == -1 ) + return JoyDevice::OPEN_FAILED; + + // we could open the devicefile, now check if a joystick is attached + char name[128]; + + if ( ::ioctl(fd, JSIOCGNAME(sizeof(name)), &name) == -1 ) + { + ::close(fd); + return JoyDevice::NO_JOYSTICK; + } + + // check the kernel driver version + int version; + if ( ::ioctl(fd, JSIOCGVERSION, &version) == -1 ) + { + ::close(fd); + return JoyDevice::ERR_GET_VERSION; + } + + if ( version != JS_VERSION ) + { + ::close(fd); + return JoyDevice::WRONG_VERSION; + } + + char bt = 0, ax = 0; + if ( ::ioctl(fd, JSIOCGBUTTONS, &bt) == -1 ) + { + ::close(fd); + return JoyDevice::ERR_GET_BUTTONS; + } + + if ( ::ioctl(fd, JSIOCGAXES, &ax) == -1 ) + { + ::close(fd); + return JoyDevice::ERR_GET_AXES; + } + + struct js_corr *oldCorr = new struct js_corr[ax]; + + if ( ::ioctl(fd, JSIOCGCORR, oldCorr) == -1 ) + { + ::close(fd); + delete [] oldCorr; + return JoyDevice::ERR_GET_CORR; + } + + descr = name; + joyFd = fd; + axes = ax; + buttons = bt; + origCorr = oldCorr; + corr = new struct js_corr[axes]; + + amin = new int[axes]; + amax = new int[axes]; + + int i; + + for (i = 0; i < axes; i++) + resetMinMax(i); + + return JoyDevice::SUCCESS; +} + +//-------------------------------------------------------------- + +void JoyDevice::close() +{ + if ( joyFd == -1 ) return; + + ::close(joyFd); + + joyFd = -1; + descr = ""; + + delete [] amin; + delete [] amax; + amin = 0; + amax = 0; + + delete [] corr; + corr = 0; + delete [] origCorr; + origCorr = 0; +} + +//-------------------------------------------------------------- + +int JoyDevice::axisMin(int axis) const +{ + if ( (axis < 0) || (axis >= axes) ) return 0; + + return amin[axis]; +} + +//-------------------------------------------------------------- + +int JoyDevice::axisMax(int axis) const +{ + if ( (axis < 0) || (axis >= axes) ) return 0; + + return amax[axis]; +} + +//-------------------------------------------------------------- + +JoyDevice::ErrorCode JoyDevice::initCalibration() +{ + if ( joyFd == -1 ) return JoyDevice::ERR_INIT_CAL; + + int i; + + // Reset all current correction values + for (i = 0; i < axes; i++) + { + corr[i].type = JS_CORR_NONE; + corr[i].prec = 0; + } + + if ( ::ioctl(joyFd, JSIOCSCORR, corr) == -1 ) + return JoyDevice::ERR_INIT_CAL; + + for (i = 0; i < axes; i++) + corr[i].type = JS_CORR_BROKEN; + + return JoyDevice::SUCCESS; +} + +//-------------------------------------------------------------- + +JoyDevice::ErrorCode JoyDevice::applyCalibration() +{ + if ( joyFd == -1 ) return JoyDevice::ERR_APPLY_CAL; + + if ( ::ioctl(joyFd, JSIOCSCORR, corr) == -1 ) + return JoyDevice::ERR_APPLY_CAL; + + return JoyDevice::SUCCESS; +} + +//-------------------------------------------------------------- + +void JoyDevice::resetMinMax(int axis, int value) +{ + amin[axis] = value; + amax[axis] = value; +} + +//-------------------------------------------------------------- + +void JoyDevice::calcPrecision() +{ + if ( !corr ) return; + + int i; + + for (i = 0; i < axes; i++) + { + corr[i].prec = amax[i] - amin[i]; + kDebug() << "Precision for axis: " << i << ": " << corr[i].prec; + } +} + +//-------------------------------------------------------------- + +JoyDevice::ErrorCode JoyDevice::restoreCorr() +{ + if ( joyFd == -1 ) return JoyDevice::SUCCESS; + + if ( ::ioctl(joyFd, JSIOCSCORR, origCorr) == -1 ) + return JoyDevice::ERR_RESTORE_CORR; + else + return JoyDevice::SUCCESS; +} + +//-------------------------------------------------------------- + +JoyDevice::~JoyDevice() +{ + close(); +} + +//-------------------------------------------------------------- + +bool JoyDevice::getEvent(JoyDevice::EventType &type, int &number, int &value) +{ + number = value = 0; + + int ret; + + fd_set readSet; + + FD_ZERO(&readSet); + FD_SET(joyFd, &readSet); + + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + + ret = ::select(joyFd + 1, &readSet, 0, 0, &timeout); + + if ( ret == 1 ) // got an event from the joystick + { + struct js_event e; + + if ( ::read(joyFd, &e, sizeof(struct js_event)) == sizeof(struct js_event) ) + { + if ( e.type & JS_EVENT_BUTTON ) + { + type = JoyDevice::BUTTON; + value = e.value; + number = e.number; + + return true; + } + + if ( e.type & JS_EVENT_AXIS ) + { + type = JoyDevice::AXIS; + value = e.value; + number = e.number; + + // store min, max values + if ( e.value < amin[number] ) amin[number] = e.value; + if ( e.value > amax[number] ) amax[number] = e.value; + + return true; + } + } + } + + return false; // no event +} + +//-------------------------------------------------------------- + +void JoyDevice::calcCorrection(int axis, int *min, int *center, int *max) +{ + const int MIN = 0; + const int MAX = 1; + + double a, b, c, d; + + a = center[MIN]; // inputs.cmin[1]; + b = center[MAX]; // inputs.cmax[1]; + c = 32767.0 / (center[MIN] - min[MAX]); // (inputs.cmin[1] - inputs.cmax[0]); + d = 32767.0 / (max[MIN] - center[MAX]); // (inputs.cmin[2] - inputs.cmax[1]); + + corr[axis].coef[0] = (int)rint(a); + corr[axis].coef[1] = (int)rint(b); + corr[axis].coef[2] = (int)rint(c*16384.0); + corr[axis].coef[3] = (int)rint(d*16384.0); + + kDebug() << "min min: " << min[0] << " max: " << min[1] ; + kDebug() << "max min: " << max[0] << " max: " << max[1] ; + kDebug() << "Correction values for axis: " << axis << ": " + << corr[axis].coef[0] << ", " + << corr[axis].coef[1] << ", " + << corr[axis].coef[2] << ", " + << corr[axis].coef[3] << endl; +} + +//-------------------------------------------------------------- diff --git a/kcontrol/hardware/joystick/joydevice.h b/kcontrol/hardware/joystick/joydevice.h new file mode 100644 index 00000000..4c26581e --- /dev/null +++ b/kcontrol/hardware/joystick/joydevice.h @@ -0,0 +1,117 @@ +/*************************************************************************** + * Copyright (C) 2003 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 _JOYDEVICE_H_ +#define _JOYDEVICE_H_ + +#include + +#include + +#ifdef Q_OS_LINUX +#undef __STRICT_ANSI__ +#include +#define __STRICT_ANSI__ +#endif + +#ifdef Q_OS_FREEBSD +#include +#endif + +// helper class which holds all current values, file descriptor, etc. for +// one device +class JoyDevice +{ + public: + enum ErrorCode + { + SUCCESS, + OPEN_FAILED, + NO_JOYSTICK, + WRONG_VERSION, + ERR_GET_VERSION, + ERR_GET_BUTTONS, + ERR_GET_AXES, + ERR_GET_CORR, + ERR_RESTORE_CORR, + ERR_INIT_CAL, + ERR_APPLY_CAL + }; + + enum EventType + { + BUTTON, + AXIS + }; + + // devicefile to use, e.g. "/dev/js0" + JoyDevice(const QString &devicefile); + ~JoyDevice(); + + // returns one of the error-codes from above + ErrorCode open(); + + // return descriptive error text for given error code + QString errText(ErrorCode code) const; + + int fd() const { return joyFd; } + void close(); + ErrorCode restoreCorr(); + + // return devicefilename from constructor + const QString &device() const { return devName; } + + // descriptive text for this device read from the driver + QString text() const { return descr; } + + int numButtons() const { return buttons; } + int numAxes() const { return axes; } + int axisMin(int axis) const; + int axisMax(int axis) const; + + // read next event from device; returns true if there was an event during the short timeout + bool getEvent(JoyDevice::EventType &type, int &number, int &value); + + // methods for calibration + ErrorCode initCalibration(); // must be called first + void calcPrecision(); + + void resetMinMax(int axis, int value = 0); + + // calculate correction values + // min[2], center[2], max[2], index 0 == minimum, index 1 == maximum + void calcCorrection(int axis, int *min, int *center, int *max); + ErrorCode applyCalibration(); + + private: + QString devName; // device filename + QString descr; // descriptive text + int joyFd; + + int buttons; + int axes; + int *amin; // axes min values + int *amax; // axes max values + + struct js_corr *corr; // calibration values during the calib. steps + struct js_corr *origCorr; // original calibration correction values +}; + +#endif diff --git a/kcontrol/hardware/joystick/joystick.cpp b/kcontrol/hardware/joystick/joystick.cpp new file mode 100644 index 00000000..7009643d --- /dev/null +++ b/kcontrol/hardware/joystick/joystick.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 2003 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 "joystick.h" +#include "joywidget.h" +#include "joydevice.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +//--------------------------------------------------------------------------------------------- + +K_PLUGIN_FACTORY(JoystickFactory, registerPlugin();) +K_EXPORT_PLUGIN(JoystickFactory("joystick")) + +//--------------------------------------------------------------------------------------------- + +Joystick::Joystick(QWidget *parent, const QVariantList &) + : KCModule(JoystickFactory::componentData(), parent) +{ + setButtons(Help); + setAboutData(new KAboutData("kcmjoystick", 0, ki18n("KDE Joystick Control Module"), "1.0", + ki18n("KDE System Settings Module to test Joysticks"), + KAboutData::License_GPL, ki18n("(c) 2004, Martin Koller"), + KLocalizedString(), "kollix@aon.at")); + + setQuickHelp( i18n("

Joystick

" + "This module helps to check if your joystick is working correctly.
" + "If it delivers wrong values for the axes, you can try to solve this with " + "the calibration.
" + "This module tries to find all available joystick devices " + "by checking /dev/js[0-4] and /dev/input/js[0-4]
" + "If you have another device file, enter it in the combobox.
" + "The Buttons list shows the state of the buttons on your joystick, the Axes list " + "shows the current value for all axes.
" + "NOTE: the current Linux device driver (Kernel 2.4, 2.6) can only autodetect" + "
    " + "
  • 2-axis, 4-button joystick
  • " + "
  • 3-axis, 4-button joystick
  • " + "
  • 4-axis, 4-button joystick
  • " + "
  • Saitek Cyborg 'digital' joysticks
  • " + "
" + "(For details you can check your Linux source/Documentation/input/joystick.txt)" + )); + + joyWidget = new JoyWidget(this); + + QVBoxLayout *top = new QVBoxLayout(this); + top->setMargin(0); + top->setSpacing(KDialog::spacingHint()); + top->addWidget(joyWidget); +} + +//--------------------------------------------------------------------------------------------- + +void Joystick::load() +{ + joyWidget->init(); +} + +//--------------------------------------------------------------------------------------------- + +void Joystick::defaults() +{ + joyWidget->resetCalibration(); + + emit changed(true); +} + +//--------------------------------------------------------------------------------------------- + +#include "joystick.moc" diff --git a/kcontrol/hardware/joystick/joystick.desktop b/kcontrol/hardware/joystick/joystick.desktop new file mode 100644 index 00000000..a0aef4ac --- /dev/null +++ b/kcontrol/hardware/joystick/joystick.desktop @@ -0,0 +1,226 @@ +[Desktop Entry] +Exec=kcmshell4 joystick + +X-DocPath=kcontrol/joystick/index.html +Terminal=false +Type=Service +Icon=preferences-desktop-gaming +Categories=Qt;KDE;X-KDE-settings-hardware; + +X-KDE-ServiceTypes=KCModule +X-KDE-Library=kcm_joystick +X-KDE-Test-Module=true +X-KDE-System-Settings-Parent-Category=input-devices +X-KDE-ParentApp=kcontrol +X-KDE-Weight=70 + +Comment=Joystick settings +Comment[ar]=إعدادات عصى الألعاب +Comment[ast]=Preferencies del Joystick +Comment[be@latin]=Nałady džojstyka +Comment[bg]=Настройки на джойстик +Comment[bn]=জয়স্টিক সেটিংস +Comment[bn_IN]=জয়-স্টিক সংক্রান্ত বৈশিষ্ট্য +Comment[bs]=Postavke džojstika +Comment[ca]=Arranjament de la palanca de control +Comment[ca@valencia]=Arranjament de la palanca de control +Comment[cs]=Nastavení joysticku +Comment[csb]=Nastôw joysticka +Comment[da]=Joystick-indstillinger +Comment[de]=Joystick-Einstellungen +Comment[el]=Ρυθμίσεις χειριστηρίου +Comment[en_GB]=Joystick settings +Comment[eo]=Ludbastonaj agordoj +Comment[es]=Preferencias del Joystick +Comment[et]=Juhtpuldi seadistused +Comment[eu]=Kontrol-palankaren ezarpenak +Comment[fi]=Peliohjainten asetukset +Comment[fy]=Joystick ynstellings +Comment[ga]=Socruithe an luamháin stiúrtha +Comment[gl]=Configuración do joystick +Comment[gu]=જોયસ્ટિક ગોઠવણીઓ +Comment[he]=הגדרות ג'ויסטיק +Comment[hi]=जॉयस्टिक विन्यास +Comment[hne]=जायस्टिक सेटिंग +Comment[hr]=Postavke igraće palice (joysticka) +Comment[hsb]=Nastajenja za joystick +Comment[hu]=Botkormány-beállítások +Comment[ia]=Preferentias de Joystick +Comment[id]=Pengaturan tongkat ria +Comment[is]=Stillingar stýripinna +Comment[kk]=Джойстик параметрлері +Comment[km]=ការ​កំណត់ Joystick +Comment[kn]=ಅಂಕೆಗೋಲು (ಜಾಯ್ ಸ್ಟಿಕ್) ಸಂಯೋಜನೆಗಳು +Comment[ko]=조이스틱 설정 +Comment[ku]=Mîhengên joystik +Comment[lt]=Valdymo svirties nustatymai +Comment[lv]=Kursorsviras iestatījumi +Comment[mai]=ज्वायस्टिक सेटिंग +Comment[mk]=Поставувања за палката за играње +Comment[ml]=ജോയ്സ്റ്റിക് സജ്ജീകരണങ്ങള്‍ +Comment[mr]=जॉयस्टीक् संयोजना +Comment[nb]=Styrespakinnstillinger +Comment[nds]=Joystick instellen +Comment[nl]=Joystick instellen +Comment[nn]=Innstillingar for styrespakar +Comment[or]=Joystick ସଂରଚନା +Comment[pa]=ਜਾਏਸਟਿੱਕ ਸੈਟਿੰਗ +Comment[pl]=Ustawienia joysticka +Comment[pt]=Configuração do 'joystick' +Comment[pt_BR]=Configurações do joystick +Comment[ro]=Configurări joystick +Comment[ru]=Настройка джойстика +Comment[si]=Joystick සැකසුම් +Comment[sk]=Nastavenie joysticku +Comment[sl]=Nastavitve igralne palice +Comment[sr]=Поставке џојстика +Comment[sr@ijekavian]=Поставке џојстика +Comment[sr@ijekavianlatin]=Postavke džojstika +Comment[sr@latin]=Postavke džojstika +Comment[sv]=Anpassa styrspak +Comment[ta]=ஜாய்ஸ்டிக் அமைப்புகள் +Comment[te]=Joystick అమరికలు +Comment[tg]=Танзимоти ҷойстик +Comment[th]=ตั้งค่าต่าง ๆ ของแท่งควบคุม +Comment[tr]=Oyun çubuğu ayarları +Comment[ug]=ئويۇن دەستە تەڭشەكلەر +Comment[uk]=Параметри джойстика +Comment[vi]=Thiết lập tay điều khiển trò chơi +Comment[wa]=Apontiaedje del djîsse di djeu +Comment[x-test]=xxJoystick settingsxx +Comment[zh_CN]=游戏杆设置 +Comment[zh_TW]=搖桿設定 +Name=Joystick +Name[af]=Joystick +Name[ar]=عصا الألعاب +Name[ast]=Joystick +Name[be]=Джойстык +Name[be@latin]=Džojstyk +Name[bg]=Джойстик +Name[bn]=জয়-স্টিক +Name[bn_IN]=জয়-স্টিক +Name[br]=Lanker-c'hoari +Name[bs]=Džojstik +Name[ca]=Palanca de control +Name[ca@valencia]=Palanca de control +Name[cs]=Joystick +Name[csb]=Joystick +Name[cy]=Ffôn reoli +Name[da]=Joystick +Name[de]=Joystick +Name[el]=Χειριστήριο +Name[en_GB]=Joystick +Name[eo]=Stirstango +Name[es]=Joystick +Name[et]=Juhtpult +Name[eu]=Kontrol-palanka +Name[fa]=اهرم کنترل +Name[fi]=Peliohjain +Name[fr]=Joystick +Name[fy]=Joystick +Name[ga]=Luamhán Stiúrtha +Name[gl]=Joystick +Name[gu]=જોયસ્ટિક +Name[he]=ג'ויסטיק +Name[hi]=जॉयस्टिक +Name[hne]=जायस्टिक +Name[hr]=Igraća palica +Name[hsb]=Joystick +Name[hu]=Botkormány +Name[ia]=Joystick +Name[id]=Tongkat Ria +Name[is]=Stýripinnar +Name[it]=Joystick +Name[ja]=ジョイスティック +Name[ka]=ჯოისტიკი +Name[kk]=Джойстик +Name[km]=យ៉យស្ទីក +Name[kn]=ಅಂಕೆಗೋಲು (ಜಾಯ್ ಸ್ಟಿಕ್) +Name[ko]=조이스틱 +Name[ku]=Joystîk +Name[lt]=Valdymo svirtis +Name[lv]=Kursorsvira +Name[mai]=जायस्टिक +Name[mk]=Џојстик +Name[ml]=ജോയ്സ്റ്റിക് +Name[mr]=जॉयस्टिक +Name[ms]=Kayu Bidik +Name[nb]=Styrespak +Name[nds]=Joystick +Name[ne]=जोयस्टिक +Name[nl]=Joystick +Name[nn]=Styrespak +Name[or]=Joystick +Name[pa]=ਜਾਏਸਟਿੱਕ +Name[pl]=Joystick +Name[pt]=Joystick +Name[pt_BR]=Joystick +Name[ro]=Joystick +Name[ru]=Джойстик +Name[se]=Stivrensággi +Name[si]=ජෝයිස්ටික් +Name[sk]=Joystick +Name[sl]=Igralna palica +Name[sr]=Џојстик +Name[sr@ijekavian]=Џојстик +Name[sr@ijekavianlatin]=Džojstik +Name[sr@latin]=Džojstik +Name[sv]=Styrspak +Name[ta]=இயக்கு கருவி +Name[te]=జాయ్ స్టిక్ +Name[tg]=Ҷойстик +Name[th]=แท่งควบคุม +Name[tr]=Oyun Çubuğu +Name[ug]=ئويۇن دەستىسى(رول) +Name[uk]=Джойстик +Name[uz]=Joystik +Name[uz@cyrillic]=Жойстик +Name[vi]=Tay điều khiển +Name[wa]=Djîsse di djeu +Name[xh]=Uvuyo +Name[x-test]=xxJoystickxx +Name[zh_CN]=游戏杆 +Name[zh_TW]=搖桿 + +X-KDE-Keywords=joystick,gamepad,controller +X-KDE-Keywords[bs]=dzojstik +X-KDE-Keywords[ca]=palanca de control,comandament de joc,controlador +X-KDE-Keywords[ca@valencia]=palanca de control,comandament de joc,controlador +X-KDE-Keywords[da]=joystick,gamepad,controller +X-KDE-Keywords[de]=Joystick,Gamepad,Spielsteuerung +X-KDE-Keywords[el]=χειριστήριο,πληκτρολόγιο παιχνιδιών,ελεγκτής +X-KDE-Keywords[en_GB]=joystick,gamepad,controller +X-KDE-Keywords[es]=joystick,gamepad,controlador +X-KDE-Keywords[et]=juhtpult,juhtkang,kontroller +X-KDE-Keywords[eu]=kontrol-palanka,joko-teklatua,kontroladorea +X-KDE-Keywords[fi]=peliohjain,sauvaohjain,ohjain +X-KDE-Keywords[fr]=joystick, gamepad, contrôleur +X-KDE-Keywords[ga]=luamhán stiúrtha,ceap cluiche,rialaitheoir +X-KDE-Keywords[gl]=joystick, gamepad, controlador +X-KDE-Keywords[hu]=botkormány,játéktábla,vezérlő +X-KDE-Keywords[ia]=joystick,gamepad,controlator +X-KDE-Keywords[it]=joystick,gamepad,controller +X-KDE-Keywords[kk]=joystick,gamepad,controller +X-KDE-Keywords[km]=joystick,gamepad,controller +X-KDE-Keywords[ko]=joystick,gamepad,controller,조이스틱,컨트롤러 +X-KDE-Keywords[mr]=जॉयस्टिक, गेमपॅड, कन्ट्रोलर +X-KDE-Keywords[nb]=styrespak,spillepute,kontroller +X-KDE-Keywords[nds]=Stüerknüppel,Speelknüppel,Speelstüer-Reedschap,Speelstüern,Stüern,Kontroller,Speelkuntrull +X-KDE-Keywords[nl]=joystick,spelpad,besturing +X-KDE-Keywords[pa]=ਜਾਏਸਟਿੱਕ,ਗੇਮਪੈਡ,ਕੰਟਰੋਲਰ +X-KDE-Keywords[pl]=joystick,gamepad,kontroler +X-KDE-Keywords[pt]=joystick,comando,controlador +X-KDE-Keywords[pt_BR]=joystick,gamepad,controle +X-KDE-Keywords[ru]=joystick,gamepad,controller,джойстик,геймпад,контроллер +X-KDE-Keywords[sk]=joystick,gamepad,ovládač +X-KDE-Keywords[sl]=igralna palica,igralni plošček,igralne naprave,krmilnik +X-KDE-Keywords[sr]=joystick,gamepad,controller,џојстик,гејмпад,управљач +X-KDE-Keywords[sr@ijekavian]=joystick,gamepad,controller,џојстик,гејмпад,управљач +X-KDE-Keywords[sr@ijekavianlatin]=joystick,gamepad,controller,džojstik,gejmpad,upravljač +X-KDE-Keywords[sr@latin]=joystick,gamepad,controller,džojstik,gejmpad,upravljač +X-KDE-Keywords[sv]=styrspak,handkontroll,styrning +X-KDE-Keywords[tr]=oyun çubuğu, denetleyici,joystick, oyun oynama kolu +X-KDE-Keywords[uk]=joystick,gamepad,джойстик,геймпад,контролер +X-KDE-Keywords[x-test]=xxjoystick,gamepad,controllerxx +X-KDE-Keywords[zh_CN]=joystick,gamepad,controller,手柄,摇杆,控制器 +X-KDE-Keywords[zh_TW]=joystick,gamepad,controller diff --git a/kcontrol/hardware/joystick/joystick.h b/kcontrol/hardware/joystick/joystick.h new file mode 100644 index 00000000..fedf3a4b --- /dev/null +++ b/kcontrol/hardware/joystick/joystick.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2003 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 _JOYSTICK_H_ +#define _JOYSTICK_H_ + +#define KDE3_SUPPORT +#include +#undef KDE3_SUPPORT + +class JoyWidget; + + +/* on FreeBSD the header already has a struct joystick, so we can't use the same name here, Alex */ +class Joystick: public KCModule +{ + Q_OBJECT + + public: + explicit Joystick(QWidget *parent = 0, const QVariantList &list = QVariantList()); + + virtual void load(); + virtual void defaults(); + + private: + JoyWidget *joyWidget; +}; + +#endif diff --git a/kcontrol/hardware/joystick/joywidget.cpp b/kcontrol/hardware/joystick/joywidget.cpp new file mode 100644 index 00000000..8c4cfa5d --- /dev/null +++ b/kcontrol/hardware/joystick/joywidget.cpp @@ -0,0 +1,418 @@ +/*************************************************************************** + * Copyright (C) 2003,2012 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 "joywidget.h" +#include "joydevice.h" +#include "poswidget.h" +#include "caldialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +//-------------------------------------------------------------- +static QString PRESSED = I18N_NOOP("PRESSED"); +//-------------------------------------------------------------- + +class TableWidget : public QTableWidget +{ + public: + TableWidget(int row, int col) : QTableWidget(row, col) {} + + virtual QSize sizeHint() const + { + return QSize(150, 100); // return a smaller size than the Qt default(256, 192) + } +}; + +//-------------------------------------------------------------- + +JoyWidget::JoyWidget(QWidget *parent) + : QWidget(parent), idle(0), joydev(0) +{ + QVBoxLayout *mainVbox = new QVBoxLayout(this); + mainVbox->setSpacing(KDialog::spacingHint()); + mainVbox->setMargin(0); + + // create area to show an icon + message if no joystick was detected + { + messageBox = new KMessageWidget(this); + messageBox->setMessageType(KMessageWidget::Error); + messageBox->setCloseButtonVisible(false); + messageBox->hide(); + + mainVbox->addWidget(messageBox); + } + + QHBoxLayout *devHbox = new QHBoxLayout; + devHbox->setSpacing(KDialog::spacingHint()); + devHbox->addWidget(new QLabel(i18n("Device:"))); + devHbox->addWidget(device = new KComboBox(true)); + + device->setInsertPolicy(QComboBox::NoInsert); + KUrlCompletion *kc = new KUrlCompletion(KUrlCompletion::FileCompletion); + device->setCompletionObject(kc); + device->setAutoDeleteCompletionObject(true); + connect(device, SIGNAL(activated(QString)), this, SLOT(deviceChanged(QString))); + connect(device, SIGNAL(returnPressed(QString)), this, SLOT(deviceChanged(QString))); + devHbox->setStretchFactor(device, 3); + + QHBoxLayout *hbox = new QHBoxLayout; + hbox->setSpacing(KDialog::spacingHint()); + + mainVbox->addLayout(devHbox); + mainVbox->addLayout(hbox); + + QVBoxLayout *vboxLeft = new QVBoxLayout; + vboxLeft->setSpacing(KDialog::spacingHint()); + vboxLeft->addWidget(new QLabel(i18nc("Cue for deflection of the stick", "Position:"))); + vboxLeft->addWidget(xyPos = new PosWidget); + + vboxLeft->addWidget(trace = new QCheckBox(i18n("Show trace"))); + connect(trace, SIGNAL(toggled(bool)), this, SLOT(traceChanged(bool))); + + QVBoxLayout *vboxMid = new QVBoxLayout; + vboxMid->setSpacing(KDialog::spacingHint()); + + QVBoxLayout *vboxRight = new QVBoxLayout; + vboxRight->setSpacing(KDialog::spacingHint()); + + // calculate the column width we need + QFontMetrics fm(font()); + int colWidth = qMax(fm.width(PRESSED), fm.width("-32767")) + 10; // -32767 largest string + + vboxMid->addWidget(new QLabel(i18n("Buttons:"))); + buttonTbl = new TableWidget(0, 1); + buttonTbl->setSelectionMode(QAbstractItemView::NoSelection); + buttonTbl->setEditTriggers(QAbstractItemView::NoEditTriggers); + buttonTbl->setHorizontalHeaderLabels(QStringList(i18n("State"))); + buttonTbl->setSortingEnabled(false); + buttonTbl->horizontalHeader()->setClickable(false); + buttonTbl->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + buttonTbl->horizontalHeader()->resizeSection(0, colWidth); + buttonTbl->verticalHeader()->setClickable(false); + vboxMid->addWidget(buttonTbl); + + vboxRight->addWidget(new QLabel(i18n("Axes:"))); + axesTbl = new TableWidget(0, 1); + axesTbl->setSelectionMode(QAbstractItemView::NoSelection); + axesTbl->setEditTriggers(QAbstractItemView::NoEditTriggers); + axesTbl->setHorizontalHeaderLabels(QStringList(i18n("Value"))); + axesTbl->setSortingEnabled(false); + axesTbl->horizontalHeader()->setClickable(false); + axesTbl->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + axesTbl->horizontalHeader()->resizeSection(0, colWidth); + axesTbl->verticalHeader()->setClickable(false); + vboxRight->addWidget(axesTbl); + + hbox->addLayout(vboxLeft); + hbox->addLayout(vboxMid); + hbox->addLayout(vboxRight); + + // calibrate button + calibrate = new QPushButton(i18n("Calibrate")); + connect(calibrate, SIGNAL(clicked()), this, SLOT(calibrateDevice())); + calibrate->setEnabled(false); + + vboxLeft->addStretch(); + vboxLeft->addWidget(calibrate); + + // set up a timer for idle processing of joystick events + idle = new QTimer(this); + connect(idle, SIGNAL(timeout()), this, SLOT(checkDevice())); + + // check which devicefiles we have + init(); +} + +//-------------------------------------------------------------- + +JoyWidget::~JoyWidget() +{ + delete joydev; +} + +//-------------------------------------------------------------- + +void JoyWidget::init() +{ + // check which devicefiles we have + int i; + bool first = true; + char dev[30]; + + device->clear(); + buttonTbl->setRowCount(0); + axesTbl->setRowCount(0); + + for (i = 0; i < 5; i++) // check the first 5 devices + { + sprintf(dev, "/dev/js%d", i); // first look in /dev + JoyDevice *joy = new JoyDevice(dev); + + if ( joy->open() != JoyDevice::SUCCESS ) + { + delete joy; + sprintf(dev, "/dev/input/js%d", i); // then look in /dev/input + joy = new JoyDevice(dev); + + if ( joy->open() != JoyDevice::SUCCESS ) + { + delete joy; + continue; // try next number + } + } + + // we found one + + device->addItem(QString("%1 (%2)").arg(joy->text()).arg(joy->device())); + + // display values for first device + if ( first ) + { + showDeviceProps(joy); // this sets the joy object into this->joydev + first = false; + } + else + delete joy; + } + + /* KDE 4: Remove this check(and i18n) when all KCM wrappers properly test modules */ + if ( device->count() == 0 ) + { + messageBox->show(); + messageBox->setText(QString("%1").arg( + i18n("No joystick device automatically found on this computer.
" + "Checks were done in /dev/js[0-4] and /dev/input/js[0-4]
" + "If you know that there is one attached, please enter the correct device file."))); + } +} + +//-------------------------------------------------------------- + +void JoyWidget::traceChanged(bool state) +{ + xyPos->showTrace(state); +} + +//-------------------------------------------------------------- + +void JoyWidget::restoreCurrDev() +{ + if ( !joydev ) // no device open + { + device->setEditText(""); + calibrate->setEnabled(false); + } + else + { + // try to find the current open device in the combobox list + int index = device->findText(joydev->device(), Qt::MatchContains); + + if ( index == -1 ) // the current open device is one the user entered (not in the list) + device->setEditText(joydev->device()); + else + device->setEditText(device->itemText(index)); + } +} + +//-------------------------------------------------------------- + +void JoyWidget::deviceChanged(const QString &dev) +{ + // find "/dev" in given string + int start, stop; + QString devName; + + if ( (start = dev.indexOf("/dev")) == -1 ) + { + KMessageBox::sorry(this, + i18n("The given device name is invalid (does not contain /dev).\n" + "Please select a device from the list or\n" + "enter a device file, like /dev/js0."), i18n("Unknown Device")); + + restoreCurrDev(); + return; + } + + if ( (stop = dev.indexOf(")", start)) != -1 ) // seems to be text selected from our list + devName = dev.mid(start, stop - start); + else + devName = dev.mid(start); + + if ( joydev && (devName == joydev->device()) ) return; // user selected the current device; ignore it + + JoyDevice *joy = new JoyDevice(devName); + JoyDevice::ErrorCode ret = joy->open(); + + if ( ret != JoyDevice::SUCCESS ) + { + KMessageBox::error(this, joy->errText(ret), i18n("Device Error")); + + delete joy; + restoreCurrDev(); + return; + } + + showDeviceProps(joy); +} + +//-------------------------------------------------------------- + +void JoyWidget::showDeviceProps(JoyDevice *joy) +{ + joydev = joy; + + buttonTbl->setRowCount(joydev->numButtons()); + + axesTbl->setRowCount(joydev->numAxes()); + if ( joydev->numAxes() >= 2 ) + { + axesTbl->setVerticalHeaderItem(0, new QTableWidgetItem(i18n("1(x)"))); + axesTbl->setVerticalHeaderItem(1, new QTableWidgetItem(i18n("2(y)"))); + } + + calibrate->setEnabled(true); + idle->start(0); + + // make both tables use the same space for header; this looks nicer + // TODO: Don't know how to do this in Qt4; the following does no longer work + // Probably by setting a sizeHint for every single header item ? + /* + buttonTbl->verticalHeader()->setFixedWidth(qMax(buttonTbl->verticalHeader()->width(), + axesTbl->verticalHeader()->width())); + axesTbl->verticalHeader()->setFixedWidth(buttonTbl->verticalHeader()->width()); + */ +} + +//-------------------------------------------------------------- + +void JoyWidget::checkDevice() +{ + if ( !joydev ) return; // no open device yet + + JoyDevice::EventType type; + int number, value; + + if ( !joydev->getEvent(type, number, value) ) + return; + + if ( type == JoyDevice::BUTTON ) + { + if ( ! buttonTbl->item(number, 0) ) + buttonTbl->setItem(number, 0, new QTableWidgetItem()); + + if ( value == 0 ) // button release + buttonTbl->item(number, 0)->setText("-"); + else + buttonTbl->item(number, 0)->setText(PRESSED); + } + + if ( type == JoyDevice::AXIS ) + { + if ( number == 0 ) // x-axis + xyPos->changeX(value); + + if ( number == 1 ) // y-axis + xyPos->changeY(value); + + if ( ! axesTbl->item(number, 0) ) + axesTbl->setItem(number, 0, new QTableWidgetItem()); + + axesTbl->item(number, 0)->setText(QString("%1").arg(int(value))); + } +} + +//-------------------------------------------------------------- + +void JoyWidget::calibrateDevice() +{ + if ( !joydev ) return; // just to be save + + JoyDevice::ErrorCode ret = joydev->initCalibration(); + + if ( ret != JoyDevice::SUCCESS ) + { + KMessageBox::error(this, joydev->errText(ret), i18n("Communication Error")); + return; + } + + if ( KMessageBox::messageBox(this, KMessageBox::Information, + i18n("Calibration is about to check the precision.

" + "Please move all axes to their center position and then " + "do not touch the joystick anymore.

" + "Click OK to start the calibration.
"), + i18n("Calibration"), + KStandardGuiItem::ok(), KStandardGuiItem::cancel()) != KMessageBox::Ok ) + return; + + idle->stop(); // stop the joystick event getting; this must be done inside the calibrate dialog + + CalDialog dlg(this, joydev); + dlg.calibrate(); + + // user canceled somewhere during calibration, therefore the device is in a bad state + if ( dlg.result() == QDialog::Rejected ) + joydev->restoreCorr(); + + idle->start(0); // continue with event getting +} + +//-------------------------------------------------------------- + +void JoyWidget::resetCalibration() +{ + if ( !joydev ) return; // just to be save + + JoyDevice::ErrorCode ret = joydev->restoreCorr(); + + if ( ret != JoyDevice::SUCCESS ) + { + KMessageBox::error(this, joydev->errText(ret), i18n("Communication Error")); + } + else + { + KMessageBox::information(this, + i18n("Restored all calibration values for joystick device %1.", joydev->device()), + i18n("Calibration Success")); + } +} + +//-------------------------------------------------------------- + +#include "joywidget.moc" diff --git a/kcontrol/hardware/joystick/joywidget.h b/kcontrol/hardware/joystick/joywidget.h new file mode 100644 index 00000000..74e99d17 --- /dev/null +++ b/kcontrol/hardware/joystick/joywidget.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2003,2005,2006 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 _JOYWIDGET_H_ +#define _JOYWIDGET_H_ + +#include + +class JoyDevice; + +class PosWidget; +class QLabel; +class QTableWidget; +class QTimer; +class KComboBox; +class KMessageWidget; +class QPushButton; +class QCheckBox; +class QFrame; + +// the widget which displays all buttons, values, etc. +class JoyWidget : public QWidget +{ + Q_OBJECT + + public: + JoyWidget(QWidget *parent = 0); + + ~JoyWidget(); + + // initialize list of possible devices and open the first available + void init(); + + public Q_SLOTS: + // reset calibration values to their value when this KCM was started + void resetCalibration(); + + private Q_SLOTS: + void checkDevice(); + void deviceChanged(const QString &dev); + void traceChanged(bool); + void calibrateDevice(); + + private: + void showDeviceProps(JoyDevice *joy); // fill widgets with given device parameters + void restoreCurrDev(); // restores the content of the combobox to reflect the current open device + + private: + KMessageWidget *messageBox; // in case of no device, show here a message rather than in a dialog + KComboBox *device; + PosWidget *xyPos; + QTableWidget *buttonTbl; + QTableWidget *axesTbl; + QCheckBox *trace; + QPushButton *calibrate; + + QTimer *idle; + + JoyDevice *joydev; +}; + +#endif diff --git a/kcontrol/hardware/joystick/poswidget.cpp b/kcontrol/hardware/joystick/poswidget.cpp new file mode 100644 index 00000000..50b3b0fb --- /dev/null +++ b/kcontrol/hardware/joystick/poswidget.cpp @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 2003,2005,2006 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 "poswidget.h" + +#include + +#define XY_WIDTH 220 +#define MARK_WIDTH 10 +#define MAX_POINTS 500 + +//----------------------------------------------------------------- + +PosWidget::PosWidget(QWidget *parent) + : QWidget(parent), x(0), y(0), trace(false) +{ + setMinimumSize(XY_WIDTH, XY_WIDTH); + setMaximumSize(XY_WIDTH, XY_WIDTH); + + QPalette palette; + palette.setColor(backgroundRole(), Qt::white); + setPalette(palette); +} + +//----------------------------------------------------------------- + +void PosWidget::paintEvent(QPaintEvent *) +{ + QPainter paint(this); + + // draw a frame + paint.drawRect(0, 0, width()-1, height()-1); + paint.setPen(Qt::gray); + + // draw a center grid + paint.drawLine(XY_WIDTH/2, 1, + XY_WIDTH/2, XY_WIDTH - 2); + + paint.drawLine(1, XY_WIDTH/2, + XY_WIDTH - 2, XY_WIDTH/2); + + // draw the trace of previous points + if ( trace ) + { + paint.setPen(Qt::black); + + for (int i = 0; i < tracePoints.count()-2; i++) + paint.drawLine(tracePoints[i], tracePoints[i+1]); + + if ( tracePoints.count() > 0 ) + paint.drawLine(tracePoints[tracePoints.count()-1], QPoint(x, y)); + } + + // draw the current position marker + paint.setPen(Qt::blue); + + paint.drawLine(x - MARK_WIDTH/2, y - MARK_WIDTH/2, + x + MARK_WIDTH/2, y + MARK_WIDTH/2); + + paint.drawLine(x - MARK_WIDTH/2, y + MARK_WIDTH/2, + x + MARK_WIDTH/2, y - MARK_WIDTH/2); +} + +//----------------------------------------------------------------- + +void PosWidget::changeX(int newX) +{ + // transform coordinates from joystick to widget coordinates + newX = int((newX/65535.0)*XY_WIDTH + XY_WIDTH/2); + + if ( x == newX ) return; // avoid unnecessary redraw + + if ( trace ) + { + tracePoints.append(QPoint(x, y)); + if ( tracePoints.count() == MAX_POINTS ) + tracePoints.removeFirst(); + } + + x = newX; + update(); +} + +//----------------------------------------------------------------- + +void PosWidget::changeY(int newY) +{ + // transform coordinates from joystick to widget coordinates + newY = int((newY/65535.0)*XY_WIDTH + XY_WIDTH/2); + + if ( y == newY ) return; // avoid unnecessary redraw + + if ( trace ) + { + tracePoints.append(QPoint(x, y)); + if ( tracePoints.count() == MAX_POINTS ) + tracePoints.removeFirst(); + } + + y = newY; + update(); +} + +//----------------------------------------------------------------- + +void PosWidget::showTrace(bool t) +{ + trace = t; + tracePoints.clear(); + + update(); +} + +//----------------------------------------------------------------- + +#include "poswidget.moc" diff --git a/kcontrol/hardware/joystick/poswidget.h b/kcontrol/hardware/joystick/poswidget.h new file mode 100644 index 00000000..671cfedf --- /dev/null +++ b/kcontrol/hardware/joystick/poswidget.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2003,2005,2006 by Martin Koller * + * kollix@aon.at * + * This file is part of the KDE Control Center Module for Joysticks * + * * + * 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 _POSWIDGET_H_ +#define _POSWIDGET_H_ + +#include +#include +class QPaintEvent; + +/** + Widget to display the joystick-selected (x,y) position +*/ +class PosWidget : public QWidget +{ + Q_OBJECT + + public: + PosWidget(QWidget *parent = 0); + + void changeX(int x); + void changeY(int y); + + // define if a trace of the moving joystick shall be displayed + // changing it will erase all previous marks from the widget + void showTrace(bool t); + + protected: + virtual void paintEvent(QPaintEvent *); + + private: + int x, y; + bool trace; + QList tracePoints; +}; + +#endif diff --git a/kcontrol/input/AUTHORS b/kcontrol/input/AUTHORS new file mode 100644 index 00000000..2ab4353d --- /dev/null +++ b/kcontrol/input/AUTHORS @@ -0,0 +1,7 @@ +Mouse & Keyboard Configuration Modules: + + Pat Dowler (dowler@pt1B1106.FSH.UVic.CA) + +Conversion to kcontrol applet: + + Matthias Hoelzer (hoelzer@physik.uni-wuerzburg.de) diff --git a/kcontrol/input/CMakeLists.txt b/kcontrol/input/CMakeLists.txt new file mode 100644 index 00000000..394c551e --- /dev/null +++ b/kcontrol/input/CMakeLists.txt @@ -0,0 +1,107 @@ + +add_subdirectory( pics ) +KDE4_NO_ENABLE_FINAL(input) + +macro_optional_find_package(USB) +macro_bool_to_01(LIBUSB_FOUND HAVE_LIBUSB) +set_package_properties(USB PROPERTIES DESCRIPTION "User level access to USB devices" + URL "http://libusb.sourceforge.net" + TYPE OPTIONAL + PURPOSE "Provides Logitech mouse support in KControl." + ) + +configure_file (config-kcontrol-input.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kcontrol-input.h ) + +include_directories( ${KDE4_INCLUDES} ) + + +if (LIBUSB_FOUND) + include_directories( ${LIBUSB_INCLUDE_DIR} ) +endif (LIBUSB_FOUND) + + +if(X11_Xcursor_FOUND) + set( libnoinst_SRCS + xcursor/themepage.cpp + xcursor/thememodel.cpp + xcursor/cursortheme.cpp + xcursor/xcursortheme.cpp + xcursor/previewwidget.cpp + xcursor/itemdelegate.cpp + xcursor/sortproxymodel.cpp + ../krdb/krdb.cpp ) + kde4_add_ui_files( libnoinst_SRCS xcursor/themepage.ui ) + include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/xcursor/ ) +else(X11_Xcursor_FOUND) + set( libnoinst_SRCS core/themepage.cpp ) + include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/core/ ) +endif(X11_Xcursor_FOUND) + + + +########### next target ############### + +set(kapplymousetheme_SRCS kapplymousetheme.cpp ) + + +kde4_add_executable(kapplymousetheme ${kapplymousetheme_SRCS}) + +target_link_libraries(kapplymousetheme +${KDE4_KDEUI_LIBS} ${X11_Xrender_LIB} ${X11_X11_LIB}) +if (X11_Xcursor_FOUND) + target_link_libraries(kapplymousetheme ${X11_Xcursor_LIB}) +endif (X11_Xcursor_FOUND) + +install(TARGETS kapplymousetheme ${INSTALL_TARGETS_DEFAULT_ARGS}) + + +########### next target ############### + +set(kcm_input_PART_SRCS mouse.cpp main.cpp logitechmouse.cpp) + + +kde4_add_ui_files(kcm_input_PART_SRCS kmousedlg.ui logitechmouse_base.ui ) + +kde4_add_plugin(kcm_input ${kcm_input_PART_SRCS}) + + +target_link_libraries(kcm_input ${KDE4_KIO_LIBS} ${X11_LIBRARIES}) +if (LIBUSB_FOUND) + target_link_libraries(kcm_input ${LIBUSB_LIBRARIES}) +endif (LIBUSB_FOUND) +if (X11_Xcursor_FOUND) + target_link_libraries(kcm_input ${X11_Xcursor_LIB}) +endif (X11_Xcursor_FOUND) +if (X11_Xfixes_FOUND) + target_link_libraries(kcm_input ${X11_Xfixes_LIB}) +endif (X11_Xfixes_FOUND) + +install(TARGETS kcm_input DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### next target ############### + +set(kcm_cursortheme_PART_SRCS kcmcursortheme.cpp ${libnoinst_SRCS}) + +kde4_add_plugin(kcm_cursortheme ${kcm_cursortheme_PART_SRCS}) + + +target_link_libraries(kcm_cursortheme ${KDE4_KIO_LIBS} ${KDE4_KNEWSTUFF3_LIBS} ${X11_LIBRARIES}) + +if (X11_Xcursor_FOUND) + target_link_libraries(kcm_cursortheme ${X11_Xcursor_LIB}) +endif (X11_Xcursor_FOUND) +if (X11_Xfixes_FOUND) + target_link_libraries(kcm_cursortheme ${X11_Xfixes_LIB}) +endif (X11_Xfixes_FOUND) + +install(TARGETS kcm_cursortheme DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES mouse.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES cursortheme.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES cursor_large_black.pcf.gz cursor_large_white.pcf.gz cursor_small_white.pcf.gz DESTINATION ${DATA_INSTALL_DIR}/kcminput ) +install( FILES xcursor/xcursor.knsrc DESTINATION ${CONFIG_INSTALL_DIR} ) + diff --git a/kcontrol/input/ChangeLog b/kcontrol/input/ChangeLog new file mode 100644 index 00000000..2d9b8d54 --- /dev/null +++ b/kcontrol/input/ChangeLog @@ -0,0 +1,11 @@ +2002-07-01 Fabian Wolf + * added option to select a white cursor + +2000-03-14 David Faure + + * mouse.cpp: Added global settings for SC/DC/AutoSelect/ChangeCursor + * mousedefaults.h: New file, to store default values + +1998-11-30 Alex Zepeda + + * Makefile.am: Move all the icons into pics/ && pics/mini/ diff --git a/kcontrol/input/Messages.sh b/kcontrol/input/Messages.sh new file mode 100644 index 00000000..b039def2 --- /dev/null +++ b/kcontrol/input/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC `find -name \*.ui` >> rc.cpp || exit 11 +$XGETTEXT *.cpp */*.cpp -o $podir/kcminput.pot +rm -f rc.cpp diff --git a/kcontrol/input/config-kcontrol-input.h.cmake b/kcontrol/input/config-kcontrol-input.h.cmake new file mode 100644 index 00000000..ce817d8e --- /dev/null +++ b/kcontrol/input/config-kcontrol-input.h.cmake @@ -0,0 +1,3 @@ +/* Defined if you have libusb */ +#cmakedefine HAVE_LIBUSB 1 + diff --git a/kcontrol/input/consoleUserPerms b/kcontrol/input/consoleUserPerms new file mode 100755 index 00000000..015df642 --- /dev/null +++ b/kcontrol/input/consoleUserPerms @@ -0,0 +1,42 @@ +#!/bin/bash +# +# /etc/hotplug/usb/consoleUserPerms +# +# Sets up newly plugged in USB device so that the user who owns +# the console according to pam_console can access it from user space +# +# Note that for this script to work, you'll need all of the following: +# a) a line in the file /etc/hotplug/usb.usermap or another usermap file +# in /etc/hotplug/usb/ that corresponds to the device you are using. +# b) a setup using pam_console creates the respective lock files +# containing the name of the respective user. You can check for that +# by executing "echo `cat /var/{run,lock}/console.lock`" and +# verifying the appropriate user is mentioned somewhere there. +# c) a Linux kernel supporting hotplug and usbdevfs +# d) the hotplug package (http://linux-hotplug.sourceforge.net/) +# +# In the usermap file, the first field "usb module" should be named +# "consoleUserPerms" to invoke this script. +# + +if [ "${ACTION}" = "add" ] && [ -f "${DEVICE}" ] +then + # New code, using lock files instead of copying /dev/console permissions + # This also works with non-kdm logins (e.g. on a virtual terminal) + # Idea and code from Nalin Dahyabhai + if [ -f /var/run/console.lock ] + then + CONSOLEOWNER=`cat /var/run/console.lock` + elif [ -f /var/lock/console.lock ] + then + CONSOLEOWNER=`cat /var/lock/console.lock` + else + CONSOLEOWNER= + fi + if [ -n "$CONSOLEOWNER" ] + then + chmod 0000 "${DEVICE}" + chown "$CONSOLEOWNER" "${DEVICE}" + chmod 0600 "${DEVICE}" + fi +fi diff --git a/kcontrol/input/core/bitmaps.h b/kcontrol/input/core/bitmaps.h new file mode 100644 index 00000000..1a8e272e --- /dev/null +++ b/kcontrol/input/core/bitmaps.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2003 Fredrik Höglund + * + * 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. + */ + +#ifndef __BITMAPS_H +#define __BITMAPS_H + + +static const char* const arrow_large_black_xpm[] = { +"24 24 3 1", +"# c None", +"a c #000000", +". c #ffffff", +"#####..#################", +"#####.a.################", +"#####.aa.###############", +"#####.aaa.##############", +"#####.aaaa.#############", +"#####.aaaaa.############", +"#####.aaaaaa.###########", +"#####.aaaaaaa.##########", +"#####.aaaaaaaa.#########", +"#####.aaaaaaaaa.########", +"#####.aaaaaaaaaa.#######", +"#####.aaaaaaaaaaa.######", +"#####.aaaaaaaaaaaa.#####", +"#####.aaaaaaaa....######", +"#####.aaaaaaa.##########", +"#####.aaa.aaaa.#########", +"#####.aa.#.aaa.#########", +"#####.a.##.aaaa.########", +"#####..####.aaa.########", +"###########.aaaa.#######", +"############.aaa.#######", +"############.aaa.#######", +"#############...########", +"########################"}; + + +static const char* const arrow_small_black_xpm[]={ +"24 24 3 1", +"# c None", +"a c #000000", +". c #ffffff", +"########################", +"########################", +"########################", +"########################", +"#######..###############", +"#######.a.##############", +"#######.aa.#############", +"#######.aaa.############", +"#######.aaaa.###########", +"#######.aaaaa.##########", +"#######.aaaaaa.#########", +"#######.aaaaaaa.########", +"#######.aaaaaaaa.#######", +"#######.aaaaa....#######", +"#######.aa.aa.##########", +"#######.a.#.aa.#########", +"#######..##.aa.#########", +"############.aa.########", +"############.aa.########", +"#############..#########", +"########################", +"########################", +"########################", +"########################"}; + + +static const char* const arrow_large_white_xpm[] = { +"24 24 3 1", +"# c None", +"a c #ffffff", +". c #000000", +"#####..#################", +"#####.a.################", +"#####.aa.###############", +"#####.aaa.##############", +"#####.aaaa.#############", +"#####.aaaaa.############", +"#####.aaaaaa.###########", +"#####.aaaaaaa.##########", +"#####.aaaaaaaa.#########", +"#####.aaaaaaaaa.########", +"#####.aaaaaaaaaa.#######", +"#####.aaaaaaaaaaa.######", +"#####.aaaaaaaaaaaa.#####", +"#####.aaaaaaaa....######", +"#####.aaaaaaa.##########", +"#####.aaa.aaaa.#########", +"#####.aa.#.aaa.#########", +"#####.a.##.aaaa.########", +"#####..####.aaa.########", +"###########.aaaa.#######", +"############.aaa.#######", +"############.aaa.#######", +"#############...########", +"########################"}; + + +static const char* const arrow_small_white_xpm[]={ +"24 24 3 1", +"# c None", +"a c #ffffff", +". c #000000", +"########################", +"########################", +"########################", +"########################", +"#######..###############", +"#######.a.##############", +"#######.aa.#############", +"#######.aaa.############", +"#######.aaaa.###########", +"#######.aaaaa.##########", +"#######.aaaaaa.#########", +"#######.aaaaaaa.########", +"#######.aaaaaaaa.#######", +"#######.aaaaa....#######", +"#######.aa.aa.##########", +"#######.a.#.aa.#########", +"#######..##.aa.#########", +"############.aa.########", +"############.aa.########", +"#############..#########", +"########################", +"########################", +"########################", +"########################"}; + +#endif diff --git a/kcontrol/input/core/themepage.cpp b/kcontrol/input/core/themepage.cpp new file mode 100644 index 00000000..5e8ffc42 --- /dev/null +++ b/kcontrol/input/core/themepage.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2003 Fredrik Höglund + * + * Based on the large cursor code written by Rik Hemsley, + * Copyright (c) 2000 Rik Hemsley + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "themepage.h" +#include +#include "themepage.moc" + +#include "bitmaps.h" + + + +ThemePage::ThemePage( QWidget* parent, const char* name ) + : QWidget( parent ) +{ + setObjectName(name); + QBoxLayout *layout = new QVBoxLayout( this ); + layout->setMargin( KDialog::marginHint() ); + layout->setSpacing( KDialog::spacingHint() ); + + layout->addWidget(new QLabel( i18n("Select the cursor theme you want to use:"), this )); + + // Create the theme list view + listview = new QTreeWidget( this ); + QStringList lstHeader; + lstHeader<setHeaderLabels( lstHeader ); + listview->setSelectionMode( QAbstractItemView::SingleSelection ); + listview->setRootIsDecorated( false ); + connect( listview, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)) + , this, SLOT(selectionChanged(QTreeWidgetItem*,QTreeWidgetItem*)) ); + layout->addWidget( listview ); + insertThemes(); +} + + +ThemePage::~ThemePage() +{ +} + + +void ThemePage::selectionChanged( QTreeWidgetItem*current,QTreeWidgetItem*previous ) +{ + Q_UNUSED( previous ); + selectedTheme = current->data( 0, Qt::UserRole + 1 ).toString(); + emit changed( selectedTheme != currentTheme ); +} + + +void ThemePage::save() +{ + if ( currentTheme == selectedTheme ) + return; + + bool whiteCursor = selectedTheme.right( 5 ) == "White"; + bool largeCursor = selectedTheme.left( 5 ) == "Large"; + + KConfig config( "kcminputrc" ); + KConfigGroup c( &config, "Mouse" ); + c.writeEntry( "LargeCursor", largeCursor ); + c.writeEntry( "WhiteCursor", whiteCursor ); + + currentTheme = selectedTheme; + + fixCursorFile(); + + KMessageBox::information( this, i18n("You have to restart KDE for these " + "changes to take effect."), i18n("Cursor Settings Changed"), + "CursorSettingsChanged" ); +} + + +void ThemePage::load() +{ + bool largeCursor, whiteCursor; + + KConfig config( "kcminputrc" ); + KConfigGroup c( &config, "Mouse" ); + largeCursor = c.readEntry( "LargeCursor", false); + whiteCursor = c.readEntry( "WhiteCursor", false); + + if ( largeCursor ) + currentTheme = whiteCursor ? "LargeWhite" : "LargeBlack"; + else + currentTheme = whiteCursor ? "SmallWhite" : "SmallBlack"; + + selectedTheme = currentTheme; + for ( int i = 0;i topLevelItemCount();++i ) + { + QTreeWidgetItem *item = listview->topLevelItem( i ); + if ( item && item->data(0, Qt::UserRole + 1 ) == currentTheme ) + { + listview->setCurrentItem( item ); + } + } +} + + +void ThemePage::defaults() +{ + currentTheme = selectedTheme = "SmallBlack"; + for ( int i = 0;i topLevelItemCount();++i ) + { + QTreeWidgetItem *item = listview->topLevelItem( i ); + if ( item && item->data(0, Qt::UserRole + 1 ) == currentTheme ) + { + listview->setCurrentItem( item ); + } + } +} + + +void ThemePage::insertThemes() +{ + QList lstChildren; + QTreeWidgetItem *item = new QTreeWidgetItem(listview ); + + item->setData( 0, Qt::DisplayRole,i18n("Small black") ); + item->setData( 1, Qt::DisplayRole, i18n("Small black cursors") ); + item->setData( 0, Qt::DecorationRole, QPixmap( arrow_small_black_xpm ) ); + item->setData( 0, Qt::UserRole + 1,"SmallBlack" ); + lstChildren<setData( 0, Qt::DisplayRole, i18n("Large black") ); + item->setData( 1, Qt::DisplayRole, i18n("Large black cursors") ); + item->setData( 0, Qt::DecorationRole, QPixmap( arrow_large_black_xpm ) ); + item->setData( 0, Qt::UserRole + 1,"LargeBlack" ); + lstChildren<setData( 0, Qt::DisplayRole, i18n("Small white") ); + item->setData( 1, Qt::DisplayRole, i18n("Small white cursors") ); + item->setData( 0, Qt::DecorationRole, QPixmap(arrow_small_white_xpm ) ); + item->setData( 0, Qt::UserRole + 1,"SmallWhite" ); + lstChildren<setData( 0, Qt::DisplayRole, i18n("Large white") ); + item->setData( 1, Qt::DisplayRole, i18n("Large white cursors") ); + item->setData( 0, Qt::DecorationRole, QPixmap( arrow_large_white_xpm ) ); + item->setData( 0, Qt::UserRole + 1, "LargeWhite" ); + lstChildren<addTopLevelItems( lstChildren ); +} + + +void ThemePage::fixCursorFile() +{ + // Make sure we have the 'font' resource dir registered and can find the + // override dir. + // + // Next, if the user wants large cursors, copy the font + // cursor_large.pcf.gz to (localkdedir)/share/fonts/override/cursor.pcf.gz. + // Else remove the font cursor.pcf.gz from (localkdedir)/share/fonts/override. + // + // Run mkfontdir to update fonts.dir in that dir. + + KGlobal::dirs()->addResourceType( "font", 0, "share/fonts/" ); + KIO::mkdir( QDir::homePath() + "/.fonts/kde-override" ); + QString overrideDir = QDir::homePath() + "/.fonts/kde-override/"; + + KUrl installedFont; + installedFont.setPath( overrideDir + "cursor.pcf.gz" ); + + if ( currentTheme == "SmallBlack" ) + KIO::NetAccess::del( installedFont, this ); + else { + KUrl source; + + if ( currentTheme == "LargeBlack" ) + source.setPath( KStandardDirs::locate("data", "kcminput/cursor_large_black.pcf.gz") ); + else if ( currentTheme == "LargeWhite" ) + source.setPath( KStandardDirs::locate("data", "kcminput/cursor_large_white.pcf.gz") ); + else if ( currentTheme == "SmallWhite" ) + source.setPath( KStandardDirs::locate("data", "kcminput/cursor_small_white.pcf.gz") ); + + KIO::Job* job = KIO::file_copy( source, installedFont, -1, KIO::Overwrite ); + job->exec(); + } + + QString cmd = KGlobal::dirs()->findExe( "mkfontdir" ); + if ( !cmd.isEmpty() ) + { + KProcess p; + p << cmd << overrideDir; + p.execute(); + } +} + +// vim: set noet ts=4 sw=4: diff --git a/kcontrol/input/core/themepage.h b/kcontrol/input/core/themepage.h new file mode 100644 index 00000000..b264422a --- /dev/null +++ b/kcontrol/input/core/themepage.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2003 Fredrik Höglund + * + * 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. + */ + +#ifndef __THEMEPAGE_H +#define __THEMEPAGE_H + +class QTreeWidget; +class QTreeWidgetItem; + +class ThemePage : public QWidget +{ + Q_OBJECT + + public: + explicit ThemePage( QWidget* parent = 0, const char* name = 0 ); + ~ThemePage(); + + // Called by the KCM + void save(); + void load(); + void defaults(); + + Q_SIGNALS: + void changed( bool ); + + private Q_SLOTS: + void selectionChanged( QTreeWidgetItem *,QTreeWidgetItem* ); + + private: + void insertThemes(); + void fixCursorFile(); + + QTreeWidget *listview; + QString currentTheme, selectedTheme; +}; + +#endif // __THEMEPAGE_H + +// vim: set noet ts=4 sw=4: diff --git a/kcontrol/input/cursor_large.bdf b/kcontrol/input/cursor_large.bdf new file mode 100644 index 00000000..24118928 --- /dev/null +++ b/kcontrol/input/cursor_large.bdf @@ -0,0 +1,4447 @@ +STARTFONT 2.1 +FONT cursor +SIZE 47 78 78 +FONTBOUNDINGBOX 45 42 -21 -23 +STARTPROPERTIES 13 +COPYRIGHT "(C) 2000 Rik Hemsley " +POINT_SIZE 470 +FONT "cursor" +WEIGHT 10 +RESOLUTION 107 +RESOLUTION_X 78 +RESOLUTION_Y 78 +X_HEIGHT -1 +QUAD_WIDTH 20 +DEFAULT_CHAR 0 +FONT_ASCENT 23 +FONT_DESCENT 24 +_XMBDFED_INFO "Edited with xmbdfed 4.3." +ENDPROPERTIES +CHARS 154 +STARTCHAR D +ENCODING 0 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 1 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR C002 +ENCODING 2 +SWIDTH 1139 0 +DWIDTH 58 0 +BBX 12 21 -10 -22 +BITMAP +0010 +0030 +0070 +00F0 +01F0 +03F0 +07F0 +0FF0 +1FF0 +3FF0 +7FF0 +FFF0 +0FF0 +07F0 +0F70 +0E30 +1E10 +1C00 +3C00 +3800 +3800 +ENDCHAR +STARTCHAR C003 +ENCODING 3 +SWIDTH 1414 0 +DWIDTH 72 0 +BBX 14 23 -11 -23 +BITMAP +000C +001C +003C +007C +00FC +01FC +03FC +07FC +0FFC +1FFC +3FFC +7FFC +FFFC +7FFC +07FC +0FFC +0FBC +1F9C +1F0C +3F00 +3E00 +3E00 +1C00 +ENDCHAR +STARTCHAR C004 +ENCODING 4 +SWIDTH 137 0 +DWIDTH 7 0 +BBX 11 15 -4 -2 +BITMAP +FFE0 +FFE0 +FFE0 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +FFE0 +7FC0 +3F80 +1F00 +0E00 +0400 +ENDCHAR +STARTCHAR C004 +ENCODING 5 +SWIDTH 176 0 +DWIDTH 9 0 +BBX 15 17 -6 -3 +BITMAP +3FF8 +7FFC +7FFC +7FFC +3FF8 +07C0 +07C0 +07C0 +07C0 +FFFE +7FFC +3FF8 +1FF0 +0FE0 +07C0 +0380 +0100 +ENDCHAR +STARTCHAR C004 +ENCODING 6 +SWIDTH 137 0 +DWIDTH 7 0 +BBX 11 15 -4 -16 +BITMAP +0400 +0E00 +1F00 +3F80 +7FC0 +FFE0 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +FFE0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR C004 +ENCODING 7 +SWIDTH 176 0 +DWIDTH 9 0 +BBX 15 17 -6 -17 +BITMAP +0100 +0380 +07C0 +0FE0 +1FF0 +3FF8 +7FFC +FFFE +07C0 +07C0 +07C0 +07C0 +3FF8 +7FFC +7FFC +7FFC +3FF8 +ENDCHAR +STARTCHAR D +ENCODING 8 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 9 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 10 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 11 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR C014 +ENCODING 12 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 21 21 0 -3 +BITMAP +E00000 +E00000 +E00000 +E00100 +E00380 +E087C0 +E0CF80 +E0FF00 +E0FE00 +E0FC00 +E0FC00 +E0FE00 +E0FF00 +E00000 +E00000 +E00000 +E00000 +E00000 +FFFFF8 +FFFFF8 +FFFFF8 +ENDCHAR +STARTCHAR C014 +ENCODING 13 +SWIDTH 432 0 +DWIDTH 22 0 +BBX 23 23 -1 -4 +BITMAP +700000 +F80000 +F80000 +F80080 +F881C0 +F8C3E0 +F8E7F0 +F8FFE0 +F8FFC0 +F8FF80 +F8FF00 +F8FF00 +F8FF80 +F8FFC0 +F8FFE0 +F80000 +F80000 +F80000 +FFFFFC +FFFFFE +FFFFFE +FFFFFE +FFFFFC +ENDCHAR +STARTCHAR C014 +ENCODING 14 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 21 21 -18 -3 +BITMAP +000038 +000038 +000038 +040038 +0E0038 +1F0838 +0F9838 +07F838 +03F838 +01F838 +01F838 +03F838 +07F838 +000038 +000038 +000038 +000038 +000038 +FFFFF8 +FFFFF8 +FFFFF8 +ENDCHAR +STARTCHAR C014 +ENCODING 15 +SWIDTH 432 0 +DWIDTH 22 0 +BBX 23 23 -19 -4 +BITMAP +00001C +00003E +00003E +02003E +07023E +0F863E +1FCE3E +0FFE3E +07FE3E +03FE3E +01FE3E +01FE3E +03FE3E +07FE3E +0FFE3E +00003E +00003E +00003E +7FFFFE +FFFFFE +FFFFFE +FFFFFE +7FFFFE +ENDCHAR +STARTCHAR C020 +ENCODING 16 +SWIDTH 216 0 +DWIDTH 11 0 +BBX 19 20 -8 -3 +BITMAP +00E000 +00E000 +00E000 +00E000 +00E000 +00E000 +00E000 +0FFE00 +07FC00 +03F800 +01F000 +00E000 +004000 +000000 +000000 +000000 +000000 +FFFFE0 +FFFFE0 +FFFFE0 +ENDCHAR +STARTCHAR C020 +ENCODING 17 +SWIDTH 235 0 +DWIDTH 12 0 +BBX 21 22 -9 -4 +BITMAP +007000 +00F800 +00F800 +00F800 +00F800 +00F800 +00F800 +1FFFC0 +0FFF80 +07FF00 +03FE00 +01FC00 +00F800 +007000 +002000 +000000 +000000 +7FFFF0 +FFFFF8 +FFFFF8 +FFFFF8 +7FFFF0 +ENDCHAR +STARTCHAR D +ENCODING 18 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 19 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 20 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 21 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR C026 +ENCODING 22 +SWIDTH 137 0 +DWIDTH 7 0 +BBX 11 20 -4 -21 +BITMAP +0400 +0400 +0E00 +0E00 +1F00 +1F00 +3F80 +3F80 +7FC0 +7FC0 +FFE0 +CE60 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0400 +ENDCHAR +STARTCHAR C026 +ENCODING 23 +SWIDTH 157 0 +DWIDTH 8 0 +BBX 13 22 -5 -22 +BITMAP +0200 +0700 +0700 +0F80 +0F80 +1FC0 +1FC0 +3FE0 +3FE0 +7FF0 +7FF0 +FFF8 +FFF8 +6FB0 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0700 +0200 +ENDCHAR +STARTCHAR D +ENCODING 24 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 25 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 26 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 27 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 28 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 29 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR quotedbl +ENCODING 30 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 24 23 -10 -13 +BITMAP +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +002800 +FFC7FF +FF83FF +FFC7FF +002800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +ENDCHAR +STARTCHAR numbersign +ENCODING 31 +SWIDTH 294 0 +DWIDTH 15 0 +BBX 26 25 -11 -14 +BITMAP +001C0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +7FF7FF80 +FFE3FFC0 +FFC1FFC0 +FFE3FFC0 +7FF7FF80 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +001C0000 +ENDCHAR +STARTCHAR D +ENCODING 32 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 33 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 24 23 -10 -13 +BITMAP +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +002800 +FFC7FF +FF83FF +FFC7FF +002800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 294 0 +DWIDTH 15 0 +BBX 26 25 -11 -14 +BITMAP +001C0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +7FF7FF80 +FFE3FFC0 +FFC1FFC0 +FFE3FFC0 +7FF7FF80 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +001C0000 +ENDCHAR +STARTCHAR D +ENCODING 36 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 37 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 38 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 39 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 40 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 41 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 15 23 -6 -13 +BITMAP +0100 +0380 +07C0 +0FE0 +1FF0 +3FF8 +7BBC +F39E +638C +0380 +0380 +0380 +0380 +0380 +E38C +F39E +7BBC +3FF8 +1FF0 +0FE0 +07C0 +0380 +0100 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 196 0 +DWIDTH 10 0 +BBX 17 25 -7 -14 +BITMAP +008000 +01C000 +03E000 +07F000 +0FF800 +1FFC00 +3FFE00 +7FFF00 +FFFF80 +7BEF00 +33E600 +03E000 +03E000 +03E000 +33E600 +7BEF00 +FFFF80 +7FFF00 +3FFE00 +1FFC00 +0FF800 +07F000 +03E000 +01C000 +008000 +ENDCHAR +STARTCHAR C002 +ENCODING 44 +SWIDTH 1139 0 +DWIDTH 58 0 +BBX 12 21 -10 -22 +BITMAP +0010 +0030 +0070 +00F0 +01F0 +03F0 +07F0 +0FF0 +1FF0 +3FF0 +7FF0 +FFF0 +0FF0 +07F0 +0F70 +0E30 +1E10 +1C00 +3C00 +3800 +3800 +ENDCHAR +STARTCHAR C003 +ENCODING 45 +SWIDTH 1414 0 +DWIDTH 72 0 +BBX 14 23 -11 -23 +BITMAP +000C +001C +003C +007C +00FC +01FC +03FC +07FC +0FFC +1FFC +3FFC +7FFC +FFFC +7FFC +07FC +0FFC +0FBC +1F9C +1F0C +3F00 +3E00 +3E00 +1C00 +ENDCHAR +STARTCHAR C002 +ENCODING 46 +SWIDTH 1139 0 +DWIDTH 58 0 +BBX 12 21 -10 -22 +BITMAP +0010 +0030 +0070 +00F0 +01F0 +03F0 +07F0 +0FF0 +1FF0 +3FF0 +7FF0 +FFF0 +0FF0 +07F0 +0F70 +0E30 +1E10 +1C00 +3C00 +3800 +3800 +ENDCHAR +STARTCHAR C003 +ENCODING 47 +SWIDTH 1414 0 +DWIDTH 72 0 +BBX 14 23 -11 -23 +BITMAP +000C +001C +003C +007C +00FC +01FC +03FC +07FC +0FFC +1FFC +3FFC +7FFC +FFFC +7FFC +07FC +0FFC +0FBC +1F9C +1F0C +3F00 +3E00 +3E00 +1C00 +ENDCHAR +STARTCHAR D +ENCODING 48 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 49 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR 2 +ENCODING 50 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 21 23 -9 -13 +BITMAP +00F800 +C3FE00 +E7FF80 +FFC3C0 +DF00E0 +CE0060 +C60020 +C30000 +FF8000 +FF8000 +000000 +000000 +000000 +000FF8 +000FF8 +000618 +200318 +300398 +3C07D8 +1E1FF8 +0FFF38 +03FE18 +00F800 +ENDCHAR +STARTCHAR 2 +ENCODING 51 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 21 23 -9 -13 +BITMAP +00F800 +C3FE00 +E7FF80 +FFC3C0 +FF00E0 +FE0060 +FE0020 +FF0000 +FF8000 +FF8000 +000000 +000000 +000000 +000FF8 +000FF8 +0007F8 +2003F8 +3003F8 +3C07F8 +1E1FF8 +0FFF38 +03FE18 +00F800 +ENDCHAR +STARTCHAR 4 +ENCODING 52 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 27 27 -12 -15 +BITMAP +00040000 +000E0000 +001F0000 +003F8000 +007FC000 +007FC000 +000E0000 +000E0000 +000E0000 +0C0E0600 +1C0E0700 +3C0E0780 +7FFFFFC0 +FFFFFFE0 +7FFFFFC0 +3C0E0780 +1C0E0700 +0C0E0600 +000E0000 +000E0000 +000E0000 +007FC000 +007FC000 +003F8000 +001F0000 +000E0000 +00040000 +ENDCHAR +STARTCHAR 4 +ENCODING 53 +SWIDTH 314 0 +DWIDTH 16 0 +BBX 29 29 -13 -16 +BITMAP +00020000 +00070000 +000F8000 +001FC000 +003FE000 +007FF000 +007FF000 +003FE000 +000F8000 +060F8300 +0F0F8780 +1F0F87C0 +3FFFFFE0 +7FFFFFF0 +FFFFFFF8 +7FFFFFF0 +3FFFFFE0 +1F0F87C0 +0F0F8780 +060F8300 +000F8000 +003FE000 +007FF000 +007FF000 +003FE000 +001FC000 +000F8000 +00070000 +00020000 +ENDCHAR +STARTCHAR D +ENCODING 54 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 55 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 56 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 57 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR less +ENCODING 58 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 23 21 -21 -21 +BITMAP +001FFC +00FFFE +01E006 +0307FC +060FF8 +0C0060 +0C07C0 +0C0FC0 +0C0060 +1E07C0 +330FC0 +6180C0 +C0C780 +C06F00 +603C00 +318C00 +199800 +0C3000 +066000 +03C000 +018000 +ENDCHAR +STARTCHAR equal +ENCODING 59 +SWIDTH 432 0 +DWIDTH 22 0 +BBX 23 21 -21 -21 +BITMAP +001FFC +00FFFE +01FFFE +03FFFC +07FFF8 +0FFFE0 +0FFFC0 +0FFFC0 +0FFFE0 +1FFFC0 +3FFFC0 +7FFFC0 +FFFF80 +FFFF00 +7FFC00 +3FFC00 +1FF800 +0FF000 +07E000 +03C000 +018000 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 962 0 +DWIDTH 49 0 +BBX 23 21 1 -21 +BITMAP +7FF000 +FFFE00 +C00F00 +7FC180 +3FE0C0 +0C0060 +07C060 +07E060 +0C0060 +07C0F0 +07E198 +06030C +03C606 +01EC06 +00780C +006318 +003330 +001860 +000CC0 +000780 +000300 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 923 0 +DWIDTH 47 0 +BBX 23 21 1 -21 +BITMAP +7FF000 +FFFE00 +FFFF00 +7FFF80 +3FFFC0 +0FFFE0 +07FFE0 +07FFE0 +0FFFE0 +07FFF0 +07FFF8 +07FFFC +03FFFE +01FFFE +007FFC +007FF8 +003FF0 +001FE0 +000FC0 +000780 +000300 +ENDCHAR +STARTCHAR D +ENCODING 62 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 63 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 64 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 65 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 66 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 67 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR C020 +ENCODING 70 +SWIDTH 216 0 +DWIDTH 11 0 +BBX 20 19 0 -11 +BITMAP +E00000 +E00000 +E00000 +E00000 +E00800 +E01800 +E03800 +E07800 +E0FFF0 +E1FFF0 +E0FFF0 +E07800 +E03800 +E01800 +E00800 +E00000 +E00000 +E00000 +E00000 +ENDCHAR +STARTCHAR C020 +ENCODING 71 +SWIDTH 235 0 +DWIDTH 12 0 +BBX 22 21 -1 -12 +BITMAP +700000 +F80000 +F80000 +F80200 +F80600 +F80E00 +F81E00 +F83E00 +F87FF8 +F8FFFC +F9FFFC +F8FFFC +F87FF8 +F83E00 +F81E00 +F80E00 +F80600 +F80200 +F80000 +F80000 +700000 +ENDCHAR +STARTCHAR D +ENCODING 72 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 73 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 74 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 75 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 76 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 77 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 78 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 79 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 80 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 81 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 82 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 83 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 84 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 85 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +D800 +CC00 +CC00 +6600 +6600 +3300 +3300 +1980 +1980 +0CC0 +0CC0 +0660 +0660 +03F0 +0330 +01F0 +00E0 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FC00 +7E00 +7E00 +3F00 +3F00 +1F80 +1F80 +0FC0 +0FC0 +07E0 +07E0 +03F0 +03F0 +01F0 +00E0 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 353 0 +DWIDTH 18 0 +BBX 17 17 1 -2 +BITMAP +003F80 +007F00 +00FC00 +01F000 +03C000 +07FE00 +01FC00 +03F000 +07C000 +0F0000 +1FF000 +07E000 +0F8000 +1E0000 +380000 +600000 +800000 +ENDCHAR +STARTCHAR X +ENCODING 89 +SWIDTH 392 0 +DWIDTH 20 0 +BBX 20 19 0 -3 +BITMAP +001FF0 +003FE0 +007FC0 +00FF80 +01FE00 +03FFC0 +07FF80 +0FFF00 +03FE00 +07F800 +0FFE00 +1FFC00 +3FF800 +0FF000 +0FC000 +3F0000 +7C0000 +F00000 +C00000 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 15 15 -6 -9 +BITMAP +0380 +0380 +0380 +0380 +0380 +0380 +FFFE +FFFE +FFFE +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR Z +ENCODING 91 +SWIDTH 196 0 +DWIDTH 10 0 +BBX 17 17 -7 -10 +BITMAP +01C000 +03E000 +03E000 +03E000 +03E000 +03E000 +7FFF00 +FFFF80 +FFFF80 +FFFF80 +7FFF00 +03E000 +03E000 +03E000 +03E000 +03E000 +01C000 +ENDCHAR +STARTCHAR D +ENCODING 92 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 93 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR C002 +ENCODING 94 +SWIDTH 1139 0 +DWIDTH 58 0 +BBX 12 21 -10 -22 +BITMAP +0010 +0030 +0070 +00F0 +01F0 +03F0 +07F0 +0FF0 +1FF0 +3FF0 +7FF0 +FFF0 +0FF0 +07F0 +0F70 +0E30 +1E10 +1C00 +3C00 +3800 +3800 +ENDCHAR +STARTCHAR C003 +ENCODING 95 +SWIDTH 1414 0 +DWIDTH 72 0 +BBX 14 23 -11 -23 +BITMAP +000C +001C +003C +007C +00FC +01FC +03FC +07FC +0FFC +1FFC +3FFC +7FFC +FFFC +7FFC +07FC +0FFC +0FBC +1F9C +1F0C +3F00 +3E00 +3E00 +1C00 +ENDCHAR +STARTCHAR C020 +ENCODING 96 +SWIDTH 216 0 +DWIDTH 11 0 +BBX 20 19 -17 -11 +BITMAP +000070 +000070 +000070 +000070 +010070 +018070 +01C070 +01E070 +FFF070 +FFF870 +FFF070 +01E070 +01C070 +018070 +010070 +000070 +000070 +000070 +000070 +ENDCHAR +STARTCHAR C020 +ENCODING 97 +SWIDTH 235 0 +DWIDTH 12 0 +BBX 22 21 -18 -12 +BITMAP +000038 +00007C +00007C +01007C +01807C +01C07C +01E07C +01F07C +7FF87C +FFFC7C +FFFE7C +FFFC7C +7FF87C +01F07C +01E07C +01C07C +01807C +01007C +00007C +00007C +000038 +ENDCHAR +STARTCHAR D +ENCODING 98 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 99 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 100 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 101 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 102 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 103 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 104 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 105 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 157 0 +DWIDTH 8 0 +BBX 13 20 -5 -2 +BITMAP +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +FFF8 +7FF0 +3FE0 +1FC0 +0F80 +0700 +0200 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 176 0 +DWIDTH 9 0 +BBX 15 22 -6 -3 +BITMAP +06C0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +7FFC +FFFE +7FFC +3FF8 +1FF0 +0FE0 +07C0 +0380 +0100 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 25 13 -12 -7 +BITMAP +02002000 +06003000 +0E003800 +1E003C00 +3FFFFE00 +7FFFFF00 +FE003F80 +7FFFFF00 +3FFFFE00 +1E003C00 +0E003800 +06003000 +02002000 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 274 0 +DWIDTH 14 0 +BBX 27 15 -13 -8 +BITMAP +01001000 +03803800 +07803C00 +0F803E00 +1FFFFF00 +3FFFFF80 +7FFFFFC0 +FFFFFFE0 +7FFFFFC0 +3FFFFF80 +1FFFFF00 +0F803E00 +07803C00 +03803800 +01001000 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 412 0 +DWIDTH 21 0 +BBX 20 13 1 -8 +BITMAP +020000 +060000 +0E0000 +1E0000 +3FFFF0 +7FFFF0 +FE0000 +7FFFF0 +3FFFF0 +1E0000 +0E0000 +060000 +020000 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 432 0 +DWIDTH 22 0 +BBX 22 15 0 -9 +BITMAP +010000 +038000 +078000 +0F8000 +1FFFF8 +3FFFFC +7FFFFC +FFFFF8 +7FFFFC +3FFFFC +1FFFF8 +0F8000 +078000 +038000 +010000 +ENDCHAR +STARTCHAR n +ENCODING 112 +SWIDTH 412 0 +DWIDTH 21 0 +BBX 20 13 -18 -8 +BITMAP +000400 +000600 +000700 +000780 +FFFFC0 +FFFFE0 +0007F0 +FFFFE0 +FFFFC0 +000780 +000700 +000600 +000400 +ENDCHAR +STARTCHAR o +ENCODING 113 +SWIDTH 432 0 +DWIDTH 22 0 +BBX 22 15 -19 -9 +BITMAP +000200 +000700 +000780 +0007C0 +7FFFE0 +FFFFF0 +FFFFF8 +7FFFFC +FFFFF8 +FFFFF0 +7FFFE0 +0007C0 +000780 +000700 +000200 +ENDCHAR +STARTCHAR j +ENCODING 114 +SWIDTH 157 0 +DWIDTH 8 0 +BBX 13 20 -5 -21 +BITMAP +0200 +0700 +0F80 +1FC0 +3FE0 +7FF0 +FFF8 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +ENDCHAR +STARTCHAR k +ENCODING 115 +SWIDTH 176 0 +DWIDTH 9 0 +BBX 15 22 -6 -22 +BITMAP +0100 +0380 +07C0 +0FE0 +1FF0 +3FF8 +7FFC +FFFE +7FFC +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +06C0 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 137 0 +DWIDTH 7 0 +BBX 13 25 -5 -14 +BITMAP +0200 +0700 +0F80 +1FC0 +3FE0 +7FF0 +FFF8 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +0D80 +FFF8 +7FF0 +3FE0 +1FC0 +0F80 +0700 +0200 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 157 0 +DWIDTH 8 0 +BBX 15 27 -6 -15 +BITMAP +0100 +0380 +07C0 +0FE0 +1FF0 +3FF8 +7FFC +FFFE +7FFC +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +0FE0 +7FFC +FFFE +7FFC +3FF8 +1FF0 +0FE0 +07C0 +0380 +0100 +ENDCHAR +STARTCHAR D +ENCODING 118 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 119 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 120 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 121 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 122 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 123 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 39 0 +DWIDTH 2 0 +BBX 15 26 -13 -22 +BITMAP +000A +0054 +00A0 +0000 +1CAA +1D54 +1C00 +1C20 +3E14 +7F0A +FF80 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +FF80 +FF80 +FF80 +FF80 +C180 +FF80 +FF80 +FF80 +ENDCHAR +STARTCHAR bar +ENCODING 125 +SWIDTH 39 0 +DWIDTH 2 0 +BBX 15 26 -13 -22 +BITMAP +000E +007C +00E0 +0000 +1CFE +1DFE +1C00 +1C60 +3E3C +7F0E +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +ENDCHAR +STARTCHAR D +ENCODING 126 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 127 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 128 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 129 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR quotedbl +ENCODING 130 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 24 23 -10 -13 +BITMAP +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +002800 +FFC7FF +FF83FF +FFC7FF +002800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +003800 +ENDCHAR +STARTCHAR numbersign +ENCODING 131 +SWIDTH 294 0 +DWIDTH 15 0 +BBX 26 25 -11 -14 +BITMAP +001C0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +7FF7FF80 +FFE3FFC0 +FFC1FFC0 +FFE3FFC0 +7FF7FF80 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +003E0000 +001C0000 +ENDCHAR +STARTCHAR D +ENCODING 132 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 133 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR C014 +ENCODING 134 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 21 21 0 -21 +BITMAP +FFFFF8 +FFFFF8 +FFFFF8 +E00000 +E00000 +E00000 +E00000 +E00000 +E0FF00 +E0FE00 +E0FC00 +E0FC00 +E0FE00 +E0FF00 +E0CF80 +E087C0 +E00380 +E00100 +E00000 +E00000 +E00000 +ENDCHAR +STARTCHAR C014 +ENCODING 135 +SWIDTH 432 0 +DWIDTH 22 0 +BBX 23 23 -1 -22 +BITMAP +FFFFFC +FFFFFE +FFFFFE +FFFFFE +FFFFFC +F80000 +F80000 +F80000 +F8FFE0 +F8FFC0 +F8FF80 +F8FF00 +F8FF00 +F8FF80 +F8FFC0 +F8FFE0 +F8E7F0 +F8C3E0 +F881C0 +F80080 +F80000 +F80000 +700000 +ENDCHAR +STARTCHAR C014 +ENCODING 136 +SWIDTH 510 0 +DWIDTH 26 0 +BBX 21 21 -18 -21 +BITMAP +FFFFF8 +FFFFF8 +FFFFF8 +000038 +000038 +000038 +000038 +000038 +07F838 +03F838 +01F838 +01F838 +03F838 +07F838 +0F9838 +1F0838 +0E0038 +040038 +000038 +000038 +000038 +ENDCHAR +STARTCHAR C014 +ENCODING 137 +SWIDTH 432 0 +DWIDTH 22 0 +BBX 23 23 -19 -22 +BITMAP +7FFFFE +FFFFFE +FFFFFE +FFFFFE +7FFFFE +00003E +00003E +00003E +0FFE3E +07FE3E +03FE3E +01FE3E +01FE3E +03FE3E +07FE3E +0FFE3E +1FCE3E +0F863E +07023E +02003E +00003E +00003E +00001C +ENDCHAR +STARTCHAR C020 +ENCODING 138 +SWIDTH 216 0 +DWIDTH 11 0 +BBX 19 20 -8 -20 +BITMAP +FFFFE0 +FFFFE0 +FFFFE0 +000000 +000000 +000000 +000000 +004000 +00E000 +01F000 +03F800 +07FC00 +0FFE00 +00E000 +00E000 +00E000 +00E000 +00E000 +00E000 +00E000 +ENDCHAR +STARTCHAR C020 +ENCODING 139 +SWIDTH 235 0 +DWIDTH 12 0 +BBX 21 22 -9 -21 +BITMAP +7FFFF0 +FFFFF8 +FFFFF8 +FFFFF8 +7FFFF0 +000000 +000000 +002000 +007000 +00F800 +01FC00 +03FE00 +07FF00 +0FFF80 +1FFFC0 +00F800 +00F800 +00F800 +00F800 +00F800 +00F800 +007000 +ENDCHAR +STARTCHAR D +ENCODING 140 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 141 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 142 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 143 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 144 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 145 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 146 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 147 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR D +ENCODING 148 +SWIDTH 255 0 +DWIDTH 13 0 +BBX 12 21 1 -22 +BITMAP +8000 +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FF00 +FE00 +EF00 +C700 +8780 +0380 +03C0 +01C0 +01C0 +ENDCHAR +STARTCHAR E +ENCODING 149 +SWIDTH 530 0 +DWIDTH 27 0 +BBX 14 23 0 -23 +BITMAP +C000 +E000 +F000 +F800 +FC00 +FE00 +FF00 +FF80 +FFC0 +FFE0 +FFF0 +FFF8 +FFFC +FFF8 +FF80 +FFC0 +F7C0 +E7E0 +C3E0 +03F0 +01F0 +01F0 +00E0 +ENDCHAR +STARTCHAR C226 +ENCODING 150 +SWIDTH 235 0 +DWIDTH 12 0 +BBX 23 37 -10 -20 +BITMAP +007C00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +03FF80 +0FFFE0 +1F01F0 +3C0078 +383838 +70381C +70381C +60380C +E0380E +E0380E +E0380E +E03C0E +E01E0E +600F0C +70079C +70031C +380038 +3C0078 +1F01F0 +0FFFE0 +03FF80 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +007C00 +ENDCHAR +STARTCHAR C226 +ENCODING 151 +SWIDTH 235 0 +DWIDTH 12 0 +BBX 23 37 -10 -20 +BITMAP +007C00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +03FF80 +0FFFE0 +1FFFF0 +3FFFF8 +3FFFF8 +7FFFFC +7FFFFC +7FFFFC +FFFFFE +FFFFFE +FFFFFE +FFFFFE +FFFFFE +7FFFFC +7FFFFC +7FFFFC +3FFFF8 +3FFFF8 +1FFFF0 +0FFFE0 +03FF80 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +00FE00 +007C00 +ENDCHAR +STARTCHAR C230 +ENCODING 152 +SWIDTH 373 0 +DWIDTH 19 0 +BBX 11 21 -4 -12 +BITMAP +FBE0 +FFE0 +1F00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +1F00 +FFE0 +FBE0 +ENDCHAR +STARTCHAR C231 +ENCODING 153 +SWIDTH 157 0 +DWIDTH 8 0 +BBX 13 23 -5 -13 +BITMAP +7DF0 +FFF8 +FFF8 +7FF0 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +0F80 +7FF0 +FFF8 +FFF8 +7DF0 +ENDCHAR +ENDFONT diff --git a/kcontrol/input/cursor_large_black.pcf.gz b/kcontrol/input/cursor_large_black.pcf.gz new file mode 100644 index 00000000..c9b45839 Binary files /dev/null and b/kcontrol/input/cursor_large_black.pcf.gz differ diff --git a/kcontrol/input/cursor_large_white.pcf.gz b/kcontrol/input/cursor_large_white.pcf.gz new file mode 100644 index 00000000..57feedc9 Binary files /dev/null and b/kcontrol/input/cursor_large_white.pcf.gz differ diff --git a/kcontrol/input/cursor_small_white.pcf.gz b/kcontrol/input/cursor_small_white.pcf.gz new file mode 100644 index 00000000..618905ea Binary files /dev/null and b/kcontrol/input/cursor_small_white.pcf.gz differ diff --git a/kcontrol/input/cursortheme.desktop b/kcontrol/input/cursortheme.desktop new file mode 100644 index 00000000..15b2d45a --- /dev/null +++ b/kcontrol/input/cursortheme.desktop @@ -0,0 +1,167 @@ +[Desktop Entry] +Exec=kcmshell4 cursortheme +Icon=edit-select +Type=Service + +X-KDE-ServiceTypes=KCModule +X-KDE-Library=kcm_cursortheme +X-KDE-ParentApp=kcontrol +X-KDE-System-Settings-Parent-Category=desktop-appearance +X-DocPath=kcontrol/cursortheme/index.html + +Name=Cursor Theme +Name[ar]=سِمة المؤشر +Name[ast]=Tema de cursores +Name[bg]=Тема за курсора +Name[bn]=কার্সর থীম +Name[bs]=Tema pokazivača +Name[ca]=Tema de cursor +Name[ca@valencia]=Tema de cursor +Name[cs]=Motiv kurzorů +Name[da]=Markørtema +Name[de]=Zeigerdesigns +Name[el]=Θέμα δρομέα +Name[en_GB]=Cursor Theme +Name[es]=Tema de cursores +Name[et]=Kursoriteema +Name[eu]=Kurtsorearen gaia +Name[fi]=Osoitinteema +Name[fr]=Thème du pointeur de la souris +Name[ga]=Téama Cúrsóra +Name[gl]=Tema do cursor +Name[he]=ערכת־נושא למצביע העכבר +Name[hi]=संकेतक प्रसंग +Name[hr]=Tema pokazivača +Name[hu]=Kurzortéma +Name[ia]=Thema de cursor +Name[is]=Bendilþema +Name[it]=Tema dei cursori +Name[ja]=カーソルテーマ +Name[kk]=Меңзер нақышы +Name[km]=ស្បែក​ទស្សន៍ទ្រនិច +Name[kn]=ಸ್ಥಳಸೂಚಕ (ಕರ್ಸರ್) ಪರಿಸರವಿನ್ಯಾಸ +Name[ko]=커서 테마 +Name[lt]=Žymeklių tema +Name[lv]=Kursora tēma +Name[mr]=कर्सर शैली +Name[nb]=Pekertema +Name[nds]=Wieserutsehn +Name[nl]=Cursorthema +Name[pa]=ਕਰਸਰ ਥੀਮ +Name[pl]=Zestawy kursorów +Name[pt]=Tema de Cursores +Name[pt_BR]=Tema de cursores +Name[ro]=Tematica de cursor +Name[ru]=Тема курсоров +Name[sk]=Téma kurzora +Name[sl]=Tema kazalke +Name[sr]=Тема показивача +Name[sr@ijekavian]=Тема показивача +Name[sr@ijekavianlatin]=Tema pokazivača +Name[sr@latin]=Tema pokazivača +Name[sv]=Muspekartema +Name[th]=ชุดเคอร์เซอร์ +Name[tr]=İmleç Teması +Name[ug]=نۇربەلگە ئۆرنىكى +Name[uk]=Тема вказівника +Name[vi]=Sắc thái con trỏ +Name[wa]=Tinme do cursoe +Name[x-test]=xxCursor Themexx +Name[zh_CN]=光标主题 +Name[zh_TW]=游標主題 + +Comment=Customize the mouse cursor appearance +Comment[ar]=خصص مظهر سِمة مؤشر الفأرة +Comment[ast]=Personalizar l'apariencia del cursor del mur +Comment[bg]=Настройки на изгледа на курсора на мишката +Comment[bn]=মাউস কার্সর-এর চেহারা পছন্দমত বদলান +Comment[bs]=Prilagodite izgled pokazivača miša +Comment[ca]=Personalitza l'aparença del cursor del ratolí +Comment[ca@valencia]=Personalitza l'aparença del cursor del ratolí +Comment[cs]=Upravit vzhled kurzoru myši +Comment[da]=Tilpas musemarkørens udseende +Comment[de]=Das Erscheinungsbild des Mauszeigers anpassen +Comment[el]=Προσαρμογή εμφάνισης του δείκτη ποντικιού +Comment[en_GB]=Customise the mouse cursor appearance +Comment[es]=Personalizar la apariencia del cursor del ratón +Comment[et]=Hiirekursori välimuse kohandamine +Comment[eu]=Pertsonalizatu saguaren kurtsorearen itxura +Comment[fi]=Hiiren osoittimen ulkoasuasetukset +Comment[gl]=Personaliza o tema do cursor +Comment[he]=התאמה אישית של מראה מצביע העכבר +Comment[hr]=Podesi izgled pokazivača miša +Comment[hu]=Az egérmutató megjelenésének testreszabása +Comment[ia]=Personalisa le apparentia de cursor de mus +Comment[is]=Sérsníða útlit músarbendilsins +Comment[kk]=Меңзер нақышын өзінше баптап алу +Comment[km]=ប្ដូរ​រូបរាង​ទស្សន៍ទ្រនិច​កណ្ដុរ​តាម​បំណង +Comment[ko]=마우스 커서 모양 사용자 정의 +Comment[lt]=Derinti pelės žymeklio išvaizdą +Comment[lv]=Pielāgot peles kursora izskatu +Comment[mr]=कर्सर शैलीत ऐच्छिक बदल करा +Comment[nb]=Sett opp utseende for musepekeren +Comment[nds]=Dat Muuswieser-Utsehn topassen +Comment[nl]=Het uiterlijk van de muiscursor aanpassen +Comment[pa]=ਮਾਊਸ ਕਰਸਰ ਦਿੱਖ ਆਪਣੀ ਪਸੰਦ ਦੀ ਬਣਾਉ +Comment[pl]=Dostosowywanie wyglądu kursora myszy +Comment[pt]=Personalizar a aparência do cursor do rato +Comment[pt_BR]=Personaliza a aparência do cursor do mouse +Comment[ro]=Particularizează tematica de cursor +Comment[ru]=Настройка внешнего вида курсора мыши +Comment[sk]=Prispôsobenie vzhľadu kurzora myši +Comment[sl]=Prilagodite videz kazalke miške +Comment[sr]=Прилагодите изглед показивача миша +Comment[sr@ijekavian]=Прилагодите изглед показивача миша +Comment[sr@ijekavianlatin]=Prilagodite izgled pokazivača miša +Comment[sr@latin]=Prilagodite izgled pokazivača miša +Comment[sv]=Anpassa muspekarens utseende +Comment[th]=ปรับแต่งชุดเคอร์เซอร์ของเมาส์เอง +Comment[tr]=Fare işaretçisi görünümünü özelleştir +Comment[ug]=چاشقىنەك نۇربەلگە قىياپىتىنى ئۆزلەشتۈر +Comment[uk]=Налаштування вигляду вказівника миші на екрані +Comment[vi]=Tuỳ chỉnh diện mạo con trỏ chuột +Comment[wa]=Mete a vosse môde li rivnance do cursoe del sori +Comment[x-test]=xxCustomize the mouse cursor appearancexx +Comment[zh_CN]=定制鼠标指针外观 +Comment[zh_TW]=自訂滑鼠游標外觀 + +X-KDE-Keywords=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance +X-KDE-Keywords[bs]=miš,kursor,tema,pojavljivanje kurosra,boja kursora,tema kursora,tema miša,pojavljivanje miša,površina miša,pokazatelj boja,pojava boja +X-KDE-Keywords[ca]=Ratolí,Cursor,Tema,Aparença de cursor,Color de cursor,Tema de cursor,Tema de ratolí,Aparença de ratolí,Pells de ratolí,Colors d'apuntador,Aparença d'apuntador +X-KDE-Keywords[ca@valencia]=Ratolí,Cursor,Tema,Aparença de cursor,Color de cursor,Tema de cursor,Tema de ratolí,Aparença de ratolí,Pells de ratolí,Colors d'apuntador,Aparença d'apuntador +X-KDE-Keywords[da]=Mus,markør,cursor,tema,markørens udseende,markørfarve,markørtema,musetema,musens udseende,museskin +X-KDE-Keywords[de]=Maus,Zeiger,Mauszeiger,Zeigerfarbe,Zeigerdesign +X-KDE-Keywords[el]=ποντίκι,δρομέας,θέμα,εμφάνιση δρομέα,χρώμα δρομέα,θέμα δρομέα,θέμα ποντικιού,εμφάνιση ποντικιού,θέματα ποντικιού,χρώματα δείκτη,εμφάνιση δείκτη +X-KDE-Keywords[en_GB]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Colour,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colours,Pointer Appearance +X-KDE-Keywords[es]=Ratón,Cursor,Tema,Apariencia del cursor,Color del cursor,Tema del cursor,Tema del ratón,Apariencia del ratón,Pieles del ratón,Colores del puntero,Apariencia del puntero +X-KDE-Keywords[et]=Hiir,Kursor,Teema,Kursori välimus,Kursori värv,Kursori teema,Hiireteema,Hiire välimus,Hiire nahad,Osutusseadme värvid,Osutusseadme välimus +X-KDE-Keywords[eu]=sagu,kurtsore,gai,kurtsorearen itsura,kurtsorearen kolorea,saguaren gaia,saguaren itxura,saguaren azalak,erakuslearen koloreak,erakuslearen itxura +X-KDE-Keywords[fi]=hiiri,osoitin,teema,osoittimen ulkoasu,osoittimen väri,osoitinteema,hiiren teema,hiiriteema,hiiren ulkoasu,hiiriteemat,osoitinvärit +X-KDE-Keywords[fr]=Souris, Curseur, Thème, Apparence du curseur, Couleur du curseur, Thème de curseurs, Thème de la souris, Apparence de la souris, Revêtement de la souris, Couleur du pointeur, Apparence du pointeur +X-KDE-Keywords[gl]=rato, cursor, tema, aparencia do cursor, cor do cursor, tema do cursor, tema do rato, aparencia do rato, cor do rato, punteiro, cor do punteiro, aparencia do punteiro, tema do punteiro +X-KDE-Keywords[hu]=Egér,Kurzor,Téma,Kurzormegjelenés,Kurzorszín,Kurzortéma,Egértéma,Egérmegjelenés,Egérfelületek,Mutató színek,Mutató megjelenés +X-KDE-Keywords[ia]=Mus,Cursor,Thema,Apparentia,Cursor,Color,Thema de Cursor,Thema de Mus, Apparentia de Mus,Pelles de Mus,Colores de punctator,Apparentia de punctator +X-KDE-Keywords[it]=Mouse,Cursore,Aspetto cursore,Colore cursore,Tema cursore,Tema mouse,Aspetto mouse,Skin mouse,Colore puntatore,Aspetto puntatore +X-KDE-Keywords[kk]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance +X-KDE-Keywords[km]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance +X-KDE-Keywords[ko]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance,마우스,커서,커서 테마,포인터 +X-KDE-Keywords[mr]=माऊस, कर्सर, थीम, कर्सर, अपिरिअन्स, कर्सर, कलर, कर्सर थीम, माऊस थीम, माऊस अपिरिअन्स, माऊस स्कीन्स, पॉईटर अपिरिअन्स +X-KDE-Keywords[nb]=Mus,peker,tema,pekerutseende,pekerfarge,pekertema,musetema,musutseende,museskins,pekerfarger,pekeerutseende +X-KDE-Keywords[nds]=Muus,Wieser,Muster, Wieserutsehn,Klöör,Utsehn +X-KDE-Keywords[nl]=Muis,Cursor,Thema,Uiterlijk van cursor,kleur van cursor,Thema van cursor,Thema van muis,uiterlijk van muis,Muisoppervlak,Kleuren van aanwijzer,Uiterlijk van aanwijzer +X-KDE-Keywords[pl]=Mysz,Kursor,Motyw,Wygląd kursora,Kolor kursora,Motyw kursora,Motyw myszy,Wygląd myszy,Skórki myszy,Kolory wskaźnika,Wygląd wskaźnika +X-KDE-Keywords[pt]=Rato,Cursor,Tema,Aparência do Cursor,Cor do Cursor,Tema do Cursor,Tema do Rato,Aparência do Rato,Visuais do Rato,Cores do Cursor +X-KDE-Keywords[pt_BR]=Mouse,Cursor,Tema,Aparência do cursor,Cor do cursor,Tema do cursor,Tema do mouse,Aparência do mouse,Visuais do mouse,Cores do ponteiro,Aparência do ponteiro +X-KDE-Keywords[ru]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance,мышь,курсор,тема,внешний вид курсора мыши,цвет указателя,внешний вид указателя +X-KDE-Keywords[sk]=Myš, kurzor,téma,vzhľad kurzora,farba kurzora,téma kurzora,téma myši,vzhľad myši,skiny myši,farby ukazovateľa,vzhľad ukazovateľa +X-KDE-Keywords[sl]=miška,kazalec,kurzor,kazalka,tema,videz kazalca,videz kazalke,barva kazalca,barva kazalke,tema kazalcev,tema kazalk,tema miške,videz miške,preobleke miške,teme miške +X-KDE-Keywords[sr]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance,миш,показивач,курсор,тема,изглед показивача,боја показивача,тема показивача,тема миша,изглед миша,пресвлаке миша,боје показивача +X-KDE-Keywords[sr@ijekavian]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance,миш,показивач,курсор,тема,изглед показивача,боја показивача,тема показивача,тема миша,изглед миша,пресвлаке миша,боје показивача +X-KDE-Keywords[sr@ijekavianlatin]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance,miš,pokazivač,kursor,tema,izgled pokazivača,boja pokazivača,tema pokazivača,tema miša,izgled miša,presvlake miša,boje pokazivača +X-KDE-Keywords[sr@latin]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance,miš,pokazivač,kursor,tema,izgled pokazivača,boja pokazivača,tema pokazivača,tema miša,izgled miša,presvlake miša,boje pokazivača +X-KDE-Keywords[sv]=Mus,Pekare,Tema,Utseende,Färg,Pekartema,Mustema,Musutseende,Musskal,Pekarfärger,Pekarutseende +X-KDE-Keywords[tr]=Fare,İşaretçi,Tema,İşaretçi Görünümü,İşaretçi Rengi,İşaretçi Teması,Fare Teması,Fare Görünümü,Fare Kabuğu,İşaretçi Renkleri,İşaretçi Görünümü +X-KDE-Keywords[uk]=миша,вказівник,тема,вигляд вказівника,колір вказівника,тема вказівника,тема миші,вигляд миші,Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance +X-KDE-Keywords[x-test]=xxMouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearancexx +X-KDE-Keywords[zh_CN]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance,鼠标,指针,主题,指针外观,指针颜色,指针主题,鼠标主题,鼠标外观,鼠标皮肤,指针外观 +X-KDE-Keywords[zh_TW]=Mouse,Cursor,Theme,Cursor Appearance,Cursor Color,Cursor Theme,Mouse Theme,Mouse Appearance,Mouse Skins,Pointer Colors,Pointer Appearance diff --git a/kcontrol/input/kapplymousetheme.cpp b/kcontrol/input/kapplymousetheme.cpp new file mode 100644 index 00000000..c9bc511b --- /dev/null +++ b/kcontrol/input/kapplymousetheme.cpp @@ -0,0 +1,91 @@ +/* + * main.cpp + * + * Copyright (c) 1999 Matthias Hoelzer-Kluepfel + * Copyright (c) 2005 Lubos Lunak + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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 +#include + +#ifdef HAVE_XCURSOR +# include +#endif + +static Display* dpy; +Display* QX11Info::display() { return dpy; } +Qt::HANDLE QX11Info::appRootWindow(int) { return DefaultRootWindow( dpy ); } + +static bool isEmpty( const char* str ) + { + if( str == NULL ) + return true; + while( isspace( *str )) + ++str; + return *str == '\0'; + } + +int main( int argc, char* argv[] ) + { + if( argc != 3 ) + return 1; + dpy = XOpenDisplay( NULL ); + if( dpy == NULL ) + return 2; + int ret = 0; +#ifdef HAVE_XCURSOR + const char* theme = argv[ 1 ]; + const char* size = argv[ 2 ]; + + // Note: If you update this code, update kapplymousetheme as well. + + // use a default value for theme only if it's not configured at all, not even in X resources + if( isEmpty( theme ) + && isEmpty( XGetDefault( QX11Info::display(), "Xcursor", "theme" )) + && isEmpty( XcursorGetTheme( QX11Info::display()))) + { + theme = "default"; + ret = 10; // means to switch to default + } + + // Apply the KDE cursor theme to ourselves + if( !isEmpty( theme )) + XcursorSetTheme(QX11Info::display(), theme ); + + if (!isEmpty( size )) + XcursorSetDefaultSize(QX11Info::display(), atoi( size )); + + // Load the default cursor from the theme and apply it to the root window. + Cursor handle = XcursorLibraryLoadCursor(QX11Info::display(), "left_ptr"); + XDefineCursor(QX11Info::display(), QX11Info::appRootWindow(), handle); + XFreeCursor(QX11Info::display(), handle); // Don't leak the cursor + +#else + ( void ) QX11Info::display(); + ( void ) QX11Info::appRootWindow(); + ( void ) argv; +#endif + XCloseDisplay( dpy ); + return ret; + } diff --git a/kcontrol/input/kcmcursortheme.cpp b/kcontrol/input/kcmcursortheme.cpp new file mode 100644 index 00000000..19d22d66 --- /dev/null +++ b/kcontrol/input/kcmcursortheme.cpp @@ -0,0 +1,69 @@ +/* + * Copyright © 2003-2007 Fredrik Höglund + * + * 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 "kcmcursortheme.h" + +#include +#include + +K_PLUGIN_FACTORY(CursorThemeConfigFactory, + registerPlugin(); +) +K_EXPORT_PLUGIN(CursorThemeConfigFactory("kcm_cursortheme", "kcminput")) + + +CursorThemeConfig::CursorThemeConfig(QWidget *parent, const QVariantList &args) + : KCModule(CursorThemeConfigFactory::componentData(), parent, args) +{ + QLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + + themepage = new ThemePage(this); + connect(themepage, SIGNAL(changed(bool)), SLOT(changed())); + layout->addWidget(themepage); + + KAboutData* aboutData = new KAboutData("kcm_cursortheme", 0, ki18n("Cursor Theme"), + 0, KLocalizedString(), KAboutData::License_GPL, ki18n("(c) 2003-2007 Fredrik Höglund")); + aboutData->addAuthor(ki18n("Fredrik Höglund")); + setAboutData(aboutData); +} + +CursorThemeConfig::~CursorThemeConfig() +{ + /* */ +} + +void CursorThemeConfig::load() +{ + themepage->load(); + emit changed(false); +} + +void CursorThemeConfig::save() +{ + themepage->save(); + emit changed(false); +} + +void CursorThemeConfig::defaults() +{ + themepage->defaults(); + changed(); +} + +#include "kcmcursortheme.moc" diff --git a/kcontrol/input/kcmcursortheme.h b/kcontrol/input/kcmcursortheme.h new file mode 100644 index 00000000..f955f4d1 --- /dev/null +++ b/kcontrol/input/kcmcursortheme.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2003-2007 Fredrik Höglund + * + * 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 KCMCURSORTHEME_H +#define KCMCURSORTHEME_H + +#include +#include "themepage.h" + +class CursorThemeConfig : public KCModule +{ + Q_OBJECT + +public: + CursorThemeConfig(QWidget *parent, const QVariantList &); + ~CursorThemeConfig(); + +public: + void load(); + void save(); + void defaults(); + +private: + ThemePage *themepage; +}; + +#endif diff --git a/kcontrol/input/kmousedlg.ui b/kcontrol/input/kmousedlg.ui new file mode 100644 index 00000000..b48a6065 --- /dev/null +++ b/kcontrol/input/kmousedlg.ui @@ -0,0 +1,295 @@ + + + KMouseDlg + + + + 0 + 0 + 416 + 329 + + + + + + + + + + + + 0 + 0 + + + + Button Order + + + true + + + + + + Righ&t handed + + + true + + + + + + + Le&ft handed + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 1 + 1 + + + + + + + + + + + Change the direction of scrolling for the mouse wheel or the 4th and 5th mouse buttons. + + + Re&verse scroll direction + + + + + + + + + + 0 + 0 + + + + + 96 + 80 + + + + true + + + + + + + + + Icons + + + + + + Dou&ble-click to open files and folders (select icons on first click) + + + false + + + + + + + &Single-click to open files and folders + + + true + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + Cha&nge pointer shape over icons + + + true + + + + + + + A&utomatically select icons + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + false + + + + 0 + 0 + + + + Delay + + + 0 + + + 2000 + + + 125 + + + ms + + + true + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 1 + + + + + + + + + KIntNumInput + QWidget +
knuminput.h
+
+
+ + rightHanded + leftHanded + cbScrollPolarity + doubleClick + singleClick + cb_pointershape + cbAutoSelect + + + kdialog.h + + + + + singleClick + toggled(bool) + cb_pointershape + setEnabled(bool) + + + 40 + 209 + + + 69 + 240 + + + + + singleClick + toggled(bool) + cbAutoSelect + setEnabled(bool) + + + 40 + 209 + + + 69 + 264 + + + + +
diff --git a/kcontrol/input/logitechmouse.cpp b/kcontrol/input/logitechmouse.cpp new file mode 100644 index 00000000..8010406a --- /dev/null +++ b/kcontrol/input/logitechmouse.cpp @@ -0,0 +1,421 @@ +/* + * logitechmouse.cpp + * + * Copyright (C) 2004 Brad Hards + * + * 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 + +#include +#include +#include +#include + +#include +#include +#ifdef HAVE_LIBUSB +#include + +#include "logitechmouse.h" + +LogitechMouse::LogitechMouse( struct usb_device *usbDev, int mouseCapabilityFlags, QWidget* parent, const char* name ) + : LogitechMouseBase( parent ) + , m_resolution( 0 ) +{ + if ( !name ) + setObjectName( "LogitechMouse" ); + + cordlessNameLabel->setText( i18n("Mouse type: %1", objectName() ) ); + + m_mouseCapabilityFlags = mouseCapabilityFlags; + + m_usbDeviceHandle = usb_open( usbDev ); + + if ( !m_usbDeviceHandle ) { + kWarning() << "Error opening usbfs file: " << usb_strerror() ; + return; + } + + if ( mouseCapabilityFlags & USE_CH2 ) { + m_useSecondChannel = 0x0100; + } else { + m_useSecondChannel = 0x0000; + } + + permissionProblemText->hide(); + + if ( mouseCapabilityFlags & HAS_RES ) { + updateResolution(); + resolutionSelector->setEnabled( true ); + + connect( button400cpi, SIGNAL(clicked()), parent, SLOT(changed()) ); + connect( button800cpi, SIGNAL(clicked()), parent, SLOT(changed()) ); + + if ( 4 == resolution() ) { + button800cpi->setChecked( true ); + } else if ( 3 == resolution() ) { + button400cpi->setChecked( true ); + } else { + // it must have failed, try to help out + resolutionSelector->setEnabled(false); + permissionProblemText->show(); + } + } + + if ( mouseCapabilityFlags & HAS_CSR ) { + + initCordlessStatusReporting(); + + // Do a name + cordlessNameLabel->setText( i18n("Mouse type: %1", cordlessName() ) ); + cordlessNameLabel->setEnabled( true ); + + // Display the battery power level - the level gets updated in updateGUI() + batteryBox->setEnabled( true ); + + // Channel + channelSelector->setEnabled( true ); + // if the channel is changed, we need to turn off the timer, otherwise it + // just resets the button to reflect the current status. The timer is + // started again when we applyChanges() + connect( channel1, SIGNAL(clicked()), this, SLOT(stopTimerForNow()) ); + connect( channel1, SIGNAL(clicked()), parent, SLOT(changed()) ); + if ( isDualChannelCapable() ) { + channel2->setEnabled( true ); + connect( channel2, SIGNAL(clicked()), this, SLOT(stopTimerForNow()) ); + connect( channel2, SIGNAL(clicked()), parent, SLOT(changed()) ); + } + + updateGUI(); + } + +} + +LogitechMouse::~LogitechMouse() +{ + if ( m_usbDeviceHandle ) + usb_close( m_usbDeviceHandle ); +} + +void LogitechMouse::initCordlessStatusReporting() +{ + updateCordlessStatus(); + doUpdate = new QTimer( this ); // will be automatically deleted + connect( doUpdate, SIGNAL(timeout()), this, SLOT(updateGUI()) ); + doUpdate->start( 20000 ); +} + +void LogitechMouse::updateCordlessStatus() +{ + QByteArray status(8, '\0'); + + int result = -1; + + if ( m_usbDeviceHandle ) + result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR | USB_ENDPOINT_IN,0x09, + (0x0003 | m_useSecondChannel), + (0x0000 | m_useSecondChannel), + status.data(), + 0x0008, + 1000); + + if (0 > result) { + // We probably have a permission problem + m_channel = 0; + channelSelector->setEnabled( false ); + batteryBox->setEnabled( false ); + cordlessNameLabel->hide(); + permissionProblemText->show(); + } else { + // kDebug() << "P6 (connect status): " << (status[0] & 0xFF); + if ( status[0] & 0x20 ) { // mouse is talking + m_connectStatus = ( status[0] & 0x80 ); + m_mousePowerup = ( status[0] & 0x40 ); + m_receiverUnlock = ( status[0] & 0x10 ); + m_waitLock = ( status[0] & 0x08 ); + } + + // kDebug() << "P0 (receiver type): " << (status[1] & 0xFF); + /* + 0x38 = pid C501 + 0x39 = pid C502 + 0x3B = pid C504 + 0x3C = pid C508 + 0x3D = pid C506 + 0x3E = pid C505 + */ + + m_cordlessNameIndex = (status[2] & 0xFF); + + m_batteryLevel = (status[3] & 0x07 ); + if ( status[3] & 0x08 ) { + m_channel = 2; + } else { + m_channel = 1; + } + + m_cordlessSecurity = ( ( status[4] ) & ( status[5] << 8 ) ); + + m_caseShape = ( status[6] & 0x7F ); + + // kDebug() << "PB1 (device Capabilities): " << (status[7] & 0xFF); + m_numberOfButtons = 2 + ( status[7] & 0x07 ); // 9 means something more than 8 + m_twoChannelCapable = ( status[7] & 0x40 ); + m_verticalRoller = ( status[7] & 0x08 ); + m_horizontalRoller = ( status[7] & 0x10 ); + m_has800cpi = ( status[7] & 0x20 ); + } + +} + +void LogitechMouse::updateGUI() +{ + updateCordlessStatus(); + + batteryBar->setValue( batteryLevel() ); + + if ( isDualChannelCapable() ) { + if ( 2 == channel() ) { + channel2->setChecked( true ); + } else if ( 1 == channel() ) { + channel1->setChecked( true ); + } // else it might have failed - we don't do anything + } +} + +void LogitechMouse::stopTimerForNow() +{ + doUpdate->stop(); +} + +void LogitechMouse::applyChanges() +{ + if ( m_mouseCapabilityFlags & HAS_RES ) { + if ( ( resolution() == 4 ) && ( button400cpi->isChecked() ) ) { + // then we are in 800cpi mode, but want 400cpi + setLogitechTo400(); + } else if ( ( resolution() == 3 ) && (button800cpi->isChecked() ) ) { + // then we are in 400 cpi mode, but want 800 cpi + setLogitechTo800(); + } + } + + if ( isDualChannelCapable() ) { + if ( ( channel() == 2 ) && ( channel1->isChecked() ) ) { + // we are on channel 2, but want channel 1 + setChannel1(); + KMessageBox::information(this, i18n("RF channel 1 has been set. Please press Connect button on mouse to re-establish link"), i18n("Press Connect Button") ); + } else if ( ( channel() == 1 ) && ( channel2->isChecked() ) ) { + // we are on channel 1, but want channel 2 + setChannel2(); + KMessageBox::information(this, i18n("RF channel 2 has been set. Please press Connect button on mouse to re-establish link"), i18n("Press Connect Button") ); + } + + initCordlessStatusReporting(); + } +} + +void LogitechMouse::save(KConfig * /*config*/) +{ + kDebug() << "Logitech mouse settings not saved - not implemented yet"; +} + +quint8 LogitechMouse::resolution() +{ + // kDebug() << "resolution: " << m_resolution; + if ( 0 == m_resolution ) { + updateResolution(); + } + return m_resolution; +} + +void LogitechMouse::updateResolution() +{ + char resolution; + + int result = -1; + + if ( m_usbDeviceHandle ) + result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR | USB_ENDPOINT_IN, + 0x01, + 0x000E, + 0x0000, + &resolution, + 0x0001, + 100); + + // kDebug() << "resolution is: " << resolution; + if (0 > result) { + kWarning() << "Error getting resolution from device : " << usb_strerror() ; + m_resolution = 0; + } else { + m_resolution = resolution; + } +} + +void LogitechMouse::setLogitechTo800() +{ + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR, + 0x02, + 0x000E, + 4, + NULL, + 0x0000, + 100); + if (0 > result) { + kWarning() << "Error setting resolution on device: " << usb_strerror() ; + } +} + +void LogitechMouse::setLogitechTo400() +{ + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR, + 0x02, + 0x000E, + 3, + NULL, + 0x0000, + 100); + if (0 > result) { + kWarning() << "Error setting resolution on device: " << usb_strerror() ; + } +} + +quint8 LogitechMouse::batteryLevel() const +{ + return m_batteryLevel; +} + + +quint8 LogitechMouse::channel() const +{ + return m_channel; +} + +bool LogitechMouse::isDualChannelCapable() const +{ + return m_twoChannelCapable; +} + +void LogitechMouse::setChannel1() +{ + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR, + 0x02, + (0x0008 | m_useSecondChannel), + (0x0000 | m_useSecondChannel), + NULL, + 0x0000, + 1000); + + if (0 > result) { + kWarning() << "Error setting mouse to channel 1 : " << usb_strerror() ; + } + +} + +void LogitechMouse::setChannel2() +{ + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR, + 0x02, + (0x0008 | m_useSecondChannel), + (0x0001 | m_useSecondChannel), + NULL, + 0x0000, + 1000); + + if (0 > result) { + kWarning() << "Error setting mouse to channel 2 : " << usb_strerror() ; + } + +} + +QString LogitechMouse::cordlessName() const +{ + switch ( m_cordlessNameIndex ) { + case 0x00: + return i18nc( "no cordless mouse", "none" ); + break; + case 0x04: + return i18n( "Cordless Mouse" ); + break; + case 0x05: + return i18n( "Cordless Wheel Mouse" ); + break; + case 0x06: + return i18n( "Cordless MouseMan Wheel" ); + break; + case 0x07: + return i18n( "Cordless Wheel Mouse" ); + break; + case 0x08: + return i18n( "Cordless Wheel Mouse" ); + break; + case 0x09: + return i18n( "Cordless TrackMan Wheel" ); + break; + case 0x0A: + return i18n( "TrackMan Live" ); + break; + case 0x0C: + return i18n( "Cordless TrackMan FX" ); + break; + case 0x0D: + return i18n( "Cordless MouseMan Optical" ); + break; + case 0x0E: + return i18n( "Cordless Optical Mouse" ); + break; + case 0x0F: + return i18n( "Cordless Mouse" ); + break; + case 0x12: + return i18n( "Cordless MouseMan Optical (2ch)" ); + break; + case 0x13: + return i18n( "Cordless Optical Mouse (2ch)" ); + break; + case 0x14: + return i18n( "Cordless Mouse (2ch)" ); + break; + case 0x82: + return i18n( "Cordless Optical TrackMan" ); + break; + case 0x8A: + return i18n( "MX700 Cordless Optical Mouse" ); + break; + case 0x8B: + return i18n( "MX700 Cordless Optical Mouse (2ch)" ); + break; + default: + return i18n( "Unknown mouse"); + } +} + +#include "logitechmouse.moc" + +#endif + diff --git a/kcontrol/input/logitechmouse.h b/kcontrol/input/logitechmouse.h new file mode 100644 index 00000000..cc4f5f62 --- /dev/null +++ b/kcontrol/input/logitechmouse.h @@ -0,0 +1,107 @@ +/* + * logitechmouse.h + * + * Copyright (C) 2004 Brad Hards + * + * 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 __LOGITECHMOUSE_H__ +#define __LOGITECHMOUSE_H__ + +#include + +#include + +#include + +#include "ui_logitechmouse_base.h" + +#include + +#define VENDOR_LOGITECH 0x046D +#define HAS_RES 0x01 /* mouse supports variable resolution */ +#define HAS_SS 0x02 /* mouse supports smart scroll control */ +#define HAS_CSR 0x04 /* mouse supports cordless status reporting and control */ +#define HAS_SSR 0x08 /* mouse supports smart scroll reporting */ +#define USE_CH2 0x10 /* mouse needs to use the second channel */ + +class LogitechMouseBase : public QWidget, public Ui::LogitechMouseBase +{ +public: + LogitechMouseBase( QWidget *parent ) : QWidget( parent ) { + setupUi( this ); + } +}; + + + +class LogitechMouse : public LogitechMouseBase +{ + Q_OBJECT + +public: + LogitechMouse( struct usb_device *usbDev, int mouseCapabilityFlags, QWidget* parent = 0, const char* name=0); + ~LogitechMouse(); + void applyChanges(); + void save(KConfig *config); + +protected Q_SLOTS: + void setChannel1(); + void setChannel2(); + void updateGUI(); + void stopTimerForNow(); + +private: + void initCordlessStatusReporting(); + void updateCordlessStatus(); + + void setLogitechTo400(); + void setLogitechTo800(); + + QString cordlessName() const ; + quint8 resolution(); + void updateResolution(); + quint8 batteryLevel() const; + quint8 channel() const; + bool isDualChannelCapable() const; + + QTimer *doUpdate; + + struct usb_dev_handle *m_usbDeviceHandle; + bool m_connectStatus; // true if the CONNECT button on the mouse is pressed + bool m_mousePowerup; // true if we are doing "just out of the box" auto-locking + bool m_receiverUnlock; // true if mouse has been disconnected by a long press + // of the receiver's CONNECT button + bool m_waitLock; // true if receiver searching for new mouse because the + // CONNECT button on the receiver was pressed + quint8 m_batteryLevel; + quint8 m_channel; + quint8 m_cordlessNameIndex; // this gets convered into a QString in cordlessName() + quint16 m_cordlessSecurity; + quint16 m_useSecondChannel; + quint8 m_caseShape; + quint8 m_numberOfButtons; + quint8 m_resolution; + bool m_twoChannelCapable; // true if the mouse supports dual channels + bool m_verticalRoller; // true if the mouse has a vertical roller (wheel) + bool m_horizontalRoller; // true if the mouse has a horizontal roller (wheel) + bool m_has800cpi; // true if the mouse does 800cpi resolution + int m_mouseCapabilityFlags; +}; + +#endif + diff --git a/kcontrol/input/logitechmouse.usermap b/kcontrol/input/logitechmouse.usermap new file mode 100644 index 00000000..65da520c --- /dev/null +++ b/kcontrol/input/logitechmouse.usermap @@ -0,0 +1,35 @@ +# script match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info +# Wheel Mouse Optical +consoleUserPerms 0x0003 0x046d 0xc00e 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# MouseMan Traveler +consoleUserPerms 0x0003 0x046d 0xc00f 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# MouseMan Dual Optical +consoleUserPerms 0x0003 0x046d 0xc012 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# MX310 Optical Mouse +consoleUserPerms 0x0003 0x046d 0xc01b 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# MX510 Optical Mouse +consoleUserPerms 0x0003 0x046d 0xc01d 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# MX300 Optical Mouse +consoleUserPerms 0x0003 0x046d 0xc024 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# MX500 Optical Mouse +consoleUserPerms 0x0003 0x046d 0xc025 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# iFeel Mouse +consoleUserPerms 0x0003 0x046d 0xc031 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# Mouse Receiver +consoleUserPerms 0x0003 0x046d 0xc501 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# Dual Receiver +consoleUserPerms 0x0003 0x046d 0xc502 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# Cordless Freedom Optical +consoleUserPerms 0x0003 0x046d 0xc504 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# Cordless Elite Duo +consoleUserPerms 0x0003 0x046d 0xc505 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# MX700 Optical Mouse +consoleUserPerms 0x0003 0x046d 0xc506 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# Cordless Optical Trackman +consoleUserPerms 0x0003 0x046d 0xc508 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# Cordless MX Duo Receiver +consoleUserPerms 0x0003 0x046d 0xc50b 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# MX100 Laser Mouse +consoleUserPerms 0x0003 0x046d 0xc50e 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 +# Receiver for Cordless Presenter +consoleUserPerms 0x0003 0x046d 0xc702 0x0000 0xffff 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 diff --git a/kcontrol/input/logitechmouse_base.ui b/kcontrol/input/logitechmouse_base.ui new file mode 100644 index 00000000..13ac59e5 --- /dev/null +++ b/kcontrol/input/logitechmouse_base.ui @@ -0,0 +1,134 @@ + + LogitechMouseBase + + + + + + Cordless Name + + + false + + + + + + + false + + + Sensor Resolution + + + + + + 400 counts per inch + + + 1 + + + + + + + 800 counts per inch + + + 1 + + + + + + + + + + false + + + Battery Level + + + + + + 7 + + + + + + + + + + false + + + RF Channel + + + + + + Channel 1 + + + true + + + 3 + + + + + + + false + + + Channel 2 + + + 3 + + + + + + + + + + You have a Logitech Mouse connected, and libusb was found at compile time, but it was not possible to access this mouse. This is probably caused by a permissions problem - you should consult the manual on how to fix this. + + + Qt::AlignVCenter + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/kcontrol/input/main.cpp b/kcontrol/input/main.cpp new file mode 100644 index 00000000..0f9f33a6 --- /dev/null +++ b/kcontrol/input/main.cpp @@ -0,0 +1,91 @@ +/* + * main.cpp + * + * Copyright (c) 1999 Matthias Hoelzer-Kluepfel + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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 +#include + +#include "mouse.h" +#include + +#include +#include + +#include +#ifdef HAVE_XCURSOR +# include +#endif + +extern "C" +{ + KDE_EXPORT void kcminit_mouse() + { + KConfig *config = new KConfig("kcminputrc", KConfig::NoGlobals ); + MouseSettings settings; + settings.load(config); + settings.apply(true); // force + +#ifdef HAVE_XCURSOR + KConfigGroup group = config->group("Mouse"); + QString theme = group.readEntry("cursorTheme", QString()); + QString size = group.readEntry("cursorSize", QString()); + + // Note: If you update this code, update kapplymousetheme as well. + + // use a default value for theme only if it's not configured at all, not even in X resources + if( theme.isEmpty() + && QByteArray( XGetDefault( QX11Info::display(), "Xcursor", "theme" )).isEmpty() + && QByteArray( XcursorGetTheme( QX11Info::display())).isEmpty()) + { + theme = "default"; + } + + // Apply the KDE cursor theme to ourselves + if( !theme.isEmpty()) + XcursorSetTheme(QX11Info::display(), QFile::encodeName(theme)); + + if (!size.isEmpty()) + XcursorSetDefaultSize(QX11Info::display(), size.toUInt()); + + // Load the default cursor from the theme and apply it to the root window. + Cursor handle = XcursorLibraryLoadCursor(QX11Info::display(), "left_ptr"); + XDefineCursor(QX11Info::display(), QX11Info::appRootWindow(), handle); + XFreeCursor(QX11Info::display(), handle); // Don't leak the cursor + + // Tell klauncher to set the XCURSOR_THEME and XCURSOR_SIZE environment + // variables when launching applications. + if(!theme.isEmpty()) + KToolInvocation::klauncher()->setLaunchEnv("XCURSOR_THEME", theme); + if( !size.isEmpty()) + KToolInvocation::klauncher()->setLaunchEnv("XCURSOR_SIZE", size); + +#endif + + delete config; + } +} + + diff --git a/kcontrol/input/mouse.cpp b/kcontrol/input/mouse.cpp new file mode 100644 index 00000000..cebb1747 --- /dev/null +++ b/kcontrol/input/mouse.cpp @@ -0,0 +1,821 @@ +/* + * mouse.cpp + * + * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * + * Layout management, enhancements: + * Copyright (c) 1999 Dirk A. Mueller + * + * SC/DC/AutoSelect/ChangeCursor: + * Copyright (c) 2000 David Faure + * + * Double click interval, drag time & dist + * Copyright (c) 2000 Bernd Gehrmann + * + * Large cursor support + * Visual activation TODO: speed + * Copyright (c) 2000 Rik Hemsley + * + * White cursor support + * TODO: give user the option to choose a certain cursor font + * -> Theming + * + * General/Advanced tabs + * Copyright (c) 2000 Brad Hughes + * + * redesign for KDE 2.2 + * Copyright (c) 2001 Ralf Nolden + * + * Logitech mouse support + * Copyright (C) 2004 Brad Hards + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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 +#undef Below +#undef Above +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mouse.h" + +#include +#include +#include +#include +#include + +#undef Below + + +K_PLUGIN_FACTORY(MouseConfigFactory, + registerPlugin(); // mouse + ) +K_EXPORT_PLUGIN(MouseConfigFactory("kcminput")) + +MouseConfig::MouseConfig(QWidget *parent, const QVariantList &args) + : KCModule(MouseConfigFactory::componentData(), parent, args) +{ + + + setQuickHelp( i18n("

Mouse

This module allows you to choose various" + " options for the way in which your pointing device works. Your" + " pointing device may be a mouse, trackball, or some other hardware" + " that performs a similar function.")); + + QString wtstr; + + QBoxLayout *top = new QVBoxLayout(this); + top->setMargin(0); + + tabwidget = new QTabWidget(this); + top->addWidget(tabwidget); + + generalTab = new KMouseDlg(this); + QButtonGroup *group = new QButtonGroup( generalTab ); + group->setExclusive( true ); + group->addButton( generalTab->singleClick ); + group->addButton( generalTab->doubleClick ); + + tabwidget->addTab(generalTab, i18n("&General")); + + group = new QButtonGroup( generalTab ); + group->setExclusive( true ); + group->addButton( generalTab->rightHanded,RIGHT_HANDED ); + group->addButton( generalTab->leftHanded,LEFT_HANDED ); + + connect(group, SIGNAL(buttonClicked(int)), this, SLOT(changed())); + connect(group, SIGNAL(buttonClicked(int)), this, SLOT(slotHandedChanged(int))); + + wtstr = i18n("If you are left-handed, you may prefer to swap the" + " functions of the left and right buttons on your pointing device" + " by choosing the 'left-handed' option. If your pointing device" + " has more than two buttons, only those that function as the" + " left and right buttons are affected. For example, if you have" + " a three-button mouse, the middle button is unaffected."); + generalTab->handedBox->setWhatsThis( wtstr ); + + connect(generalTab->doubleClick, SIGNAL(clicked()), SLOT(changed())); + + wtstr = i18n("The default behavior in KDE is to select and activate" + " icons with a single click of the left button on your pointing" + " device. This behavior is consistent with what you would expect" + " when you click links in most web browsers. If you would prefer" + " to select with a single click, and activate with a double click," + " check this option."); + generalTab->doubleClick->setWhatsThis( wtstr ); + + wtstr = i18n("Activates and opens a file or folder with a single click."); + generalTab->singleClick->setWhatsThis( wtstr ); + + + connect(generalTab->cbAutoSelect, SIGNAL(clicked()), this, SLOT(changed())); + + wtstr = i18n("If you check this option, pausing the mouse pointer" + " over an icon on the screen will automatically select that icon." + " This may be useful when single clicks activate icons, and you" + " want only to select the icon without activating it."); + generalTab->cbAutoSelect->setWhatsThis( wtstr ); + + wtstr = i18n("If you have checked the option to automatically select" + " icons, this slider allows you to select how long the mouse pointer" + " must be paused over the icon before it is selected."); + generalTab->slAutoSelect->setWhatsThis( wtstr ); + + connect(generalTab->slAutoSelect, SIGNAL(valueChanged(int)), this, SLOT(changed())); + + connect(generalTab->cb_pointershape, SIGNAL(clicked()), this, SLOT(changed())); + + connect(generalTab->singleClick, SIGNAL(clicked()), this, SLOT(changed())); + connect(generalTab->singleClick, SIGNAL(clicked()), this, SLOT(slotClick())); + connect(generalTab->singleClick, SIGNAL(clicked()), this, SLOT(slotSmartSliderEnabling())); + + connect( generalTab->doubleClick, SIGNAL(clicked()), this, SLOT(slotClick()) ); + connect( generalTab->cbAutoSelect, SIGNAL(clicked()), this, SLOT(slotClick()) ); + connect(generalTab->cbAutoSelect, SIGNAL(clicked()), this, SLOT(slotSmartSliderEnabling())); + + + // Only allow setting reversing scroll polarity if we have scroll buttons + unsigned char map[20]; + if ( XGetPointerMapping(QX11Info::display(), map, 20) >= 5 ) + { + generalTab->cbScrollPolarity->setEnabled( true ); + generalTab->cbScrollPolarity->show(); + } + else + { + generalTab->cbScrollPolarity->setEnabled( false ); + generalTab->cbScrollPolarity->hide(); + } + connect(generalTab->cbScrollPolarity, SIGNAL(clicked()), this, SLOT(changed())); + connect(generalTab->cbScrollPolarity, SIGNAL(clicked()), this, SLOT(slotScrollPolarityChanged())); + + // Advanced tab + advancedTab = new QWidget(0); + advancedTab->setObjectName("Advanced Tab"); + tabwidget->addTab(advancedTab, i18n("Advanced")); + + QFormLayout *lay = new QFormLayout(advancedTab); + + accel = new KDoubleNumInput(0.1, 20, 2, advancedTab, 0.1, 1); + accel->setSuffix(i18n(" x")); + lay->addRow(i18n("Pointer acceleration:"), accel); + connect(accel, SIGNAL(valueChanged(double)), this, SLOT(changed())); + + wtstr = i18n("

This option allows you to change the relationship" + " between the distance that the mouse pointer moves on the" + " screen and the relative movement of the physical device" + " itself (which may be a mouse, trackball, or some other" + " pointing device.)

" + " A high value for the acceleration will lead to large" + " movements of the mouse pointer on the screen even when" + " you only make a small movement with the physical device." + " Selecting very high values may result in the mouse pointer" + " flying across the screen, making it hard to control.

"); + accel->setWhatsThis( wtstr ); + + thresh = new KIntNumInput(20, advancedTab); + thresh->setRange(0,20,1); + thresh->setSteps(1,1); + lay->addRow(i18n("Pointer threshold:"), thresh); + connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(slotThreshChanged(int))); + slotThreshChanged(thresh->value()); + + wtstr = i18n("

The threshold is the smallest distance that the" + " mouse pointer must move on the screen before acceleration" + " has any effect. If the movement is smaller than the threshold," + " the mouse pointer moves as if the acceleration was set to 1X;

" + " thus, when you make small movements with the physical device," + " there is no acceleration at all, giving you a greater degree" + " of control over the mouse pointer. With larger movements of" + " the physical device, you can move the mouse pointer" + " rapidly to different areas on the screen.

"); + thresh->setWhatsThis( wtstr ); + + // It would be nice if the user had a test field. + // Selecting such values in milliseconds is not intuitive + doubleClickInterval = new KIntNumInput(2000, advancedTab); + doubleClickInterval->setRange(0, 2000, 100); + doubleClickInterval->setSuffix(i18n(" msec")); + doubleClickInterval->setSteps(100, 100); + lay->addRow(i18n("Double click interval:"), doubleClickInterval); + connect(doubleClickInterval, SIGNAL(valueChanged(int)), this, SLOT(changed())); + + wtstr = i18n("The double click interval is the maximal time" + " (in milliseconds) between two mouse clicks which" + " turns them into a double click. If the second" + " click happens later than this time interval after" + " the first click, they are recognized as two" + " separate clicks."); + doubleClickInterval->setWhatsThis( wtstr ); + + dragStartTime = new KIntNumInput(2000, advancedTab); + dragStartTime->setRange(0, 2000, 100); + dragStartTime->setSuffix(i18n(" msec")); + dragStartTime->setSteps(100, 100); + lay->addRow(i18n("Drag start time:"), dragStartTime); + connect(dragStartTime, SIGNAL(valueChanged(int)), this, SLOT(changed())); + + wtstr = i18n("If you click with the mouse (e.g. in a multi-line" + " editor) and begin to move the mouse within the" + " drag start time, a drag operation will be initiated."); + dragStartTime->setWhatsThis( wtstr ); + + dragStartDist = new KIntNumInput(20, advancedTab); + dragStartDist->setRange(1, 20, 1); + dragStartDist->setSteps(1,1); + lay->addRow(i18n("Drag start distance:"), dragStartDist); + connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(slotDragStartDistChanged(int))); + slotDragStartDistChanged(dragStartDist->value()); + + wtstr = i18n("If you click with the mouse and begin to move the" + " mouse at least the drag start distance, a drag" + " operation will be initiated."); + dragStartDist->setWhatsThis( wtstr ); + + wheelScrollLines = new KIntNumInput(3, advancedTab); + wheelScrollLines->setRange(1, 12, 1); + wheelScrollLines->setSteps(1,1); + lay->addRow(i18n("Mouse wheel scrolls by:"), wheelScrollLines); + connect(wheelScrollLines, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(wheelScrollLines, SIGNAL(valueChanged(int)), SLOT(slotWheelScrollLinesChanged(int))); + slotWheelScrollLinesChanged(wheelScrollLines->value()); + + wtstr = i18n("If you use the wheel of a mouse, this value determines the number of lines to scroll for each wheel movement. Note that if this number exceeds the number of visible lines, it will be ignored and the wheel movement will be handled as a page up/down movement."); + wheelScrollLines->setWhatsThis(wtstr); + +{ + QWidget *mouse = new QWidget(this); + mouse->setObjectName("Mouse Navigation"); + tabwidget->addTab(mouse, i18n("Mouse Navigation")); + + QFormLayout *form = new QFormLayout(mouse); + + mouseKeys = new QCheckBox(i18n("&Move pointer with keyboard (using the num pad)"), mouse); + form->addRow(mouseKeys); + + mk_delay = new KIntNumInput(mouse); + mk_delay->setRange(1, 1000, 50); + mk_delay->setSuffix(i18n(" msec")); + form->addRow(i18n("&Acceleration delay:"), mk_delay); + + mk_interval = new KIntNumInput(0, mouse); + mk_interval->setRange(1, 1000, 10); + mk_interval->setSuffix(i18n(" msec")); + form->addRow(i18n("R&epeat interval:"), mk_interval); + + mk_time_to_max = new KIntNumInput(0, mouse); + mk_time_to_max->setRange(100, 10000, 200); + mk_time_to_max->setSuffix(i18n(" msec")); + form->addRow(i18n("Acceleration &time:"), mk_time_to_max); + + mk_max_speed = new KIntNumInput(0, mouse); + mk_max_speed->setRange(1, 2000, 20); + mk_max_speed->setSuffix(i18n(" pixel/sec")); + form->addRow(i18n("Ma&ximum speed:"), mk_max_speed); + + mk_curve = new KIntNumInput(0, mouse); + mk_curve->setRange(-1000, 1000, 100); + form->addRow(i18n("Acceleration &profile:"), mk_curve); + + connect(mouseKeys, SIGNAL(clicked()), this, SLOT(checkAccess())); + connect(mouseKeys, SIGNAL(clicked()), this, SLOT(changed())); + connect(mk_delay, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(mk_interval, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(mk_time_to_max, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(mk_max_speed, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(mk_curve, SIGNAL(valueChanged(int)), this, SLOT(changed())); +} + + settings = new MouseSettings; + + // This part is for handling features on Logitech USB mice. + // It only works if libusb is available. +#ifdef HAVE_LIBUSB + + static const + struct device_table { + int idVendor; + int idProduct; + const char* Model; + const char* Name; + int flags; + } device_table[] = { + { VENDOR_LOGITECH, 0xC00E, "M-BJ58", "Wheel Mouse Optical", HAS_RES }, + { VENDOR_LOGITECH, 0xC00F, "M-BJ79", "MouseMan Traveler", HAS_RES }, + { VENDOR_LOGITECH, 0xC012, "M-BL63B", "MouseMan Dual Optical", HAS_RES }, + { VENDOR_LOGITECH, 0xC01B, "M-BP86", "MX310 Optical Mouse", HAS_RES }, + { VENDOR_LOGITECH, 0xC01D, "M-BS81A", "MX510 Optical Mouse", HAS_RES | HAS_SS | HAS_SSR }, + { VENDOR_LOGITECH, 0xC024, "M-BP82", "MX300 Optical Mouse", HAS_RES }, + { VENDOR_LOGITECH, 0xC025, "M-BP81A", "MX500 Optical Mouse", HAS_RES | HAS_SS | HAS_SSR }, + { VENDOR_LOGITECH, 0xC031, "M-UT58A", "iFeel Mouse (silver)", HAS_RES }, + { VENDOR_LOGITECH, 0xC501, "C-BA4-MSE", "Mouse Receiver", HAS_CSR }, + { VENDOR_LOGITECH, 0xC502, "C-UA3-DUAL", "Dual Receiver", HAS_CSR | USE_CH2}, + { VENDOR_LOGITECH, 0xC504, "C-BD9-DUAL", "Cordless Freedom Optical", HAS_CSR | USE_CH2 }, + { VENDOR_LOGITECH, 0xC505, "C-BG17-DUAL", "Cordless Elite Duo", HAS_SS | HAS_SSR | HAS_CSR | USE_CH2}, + { VENDOR_LOGITECH, 0xC506, "C-BF16-MSE", "MX700 Optical Mouse", HAS_SS | HAS_CSR }, + { VENDOR_LOGITECH, 0xC508, "C-BA4-MSE", "Cordless Optical TrackMan", HAS_SS | HAS_CSR }, + { VENDOR_LOGITECH, 0xC50B, "967300-0403", "Cordless MX Duo Receiver", HAS_SS|HAS_CSR }, + { VENDOR_LOGITECH, 0xC50E, "M-RAG97", "MX1000 Laser Mouse", HAS_SS | HAS_CSR }, + { VENDOR_LOGITECH, 0xC702, "C-UF15", "Receiver for Cordless Presenter", HAS_CSR }, + { 0, 0, 0, 0, 0 } + }; + + usb_init(); + usb_find_busses(); + usb_find_devices(); + + struct usb_bus *bus; + struct usb_device *dev; + + for (bus = usb_busses; bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + for (int n = 0; device_table[n].idVendor; n++) + if ( (device_table[n].idVendor == dev->descriptor.idVendor) && + (device_table[n].idProduct == dev->descriptor.idProduct) ) { + // OK, we have a device that appears to be one of the ones we support + LogitechMouse *mouse = new LogitechMouse( dev, device_table[n].flags, this, device_table[n].Name ); + settings->logitechMouseList.append(mouse); + tabwidget->addTab( (QWidget*)mouse, device_table[n].Name ); + } + } + } + +#endif + + KAboutData* about = new KAboutData("kcmmouse", 0, ki18n("Mouse"), 0, KLocalizedString(), + KAboutData::License_GPL, ki18n("(c) 1997 - 2005 Mouse developers")); + about->addAuthor(ki18n("Patrick Dowler")); + about->addAuthor(ki18n("Dirk A. Mueller")); + about->addAuthor(ki18n("David Faure")); + about->addAuthor(ki18n("Bernd Gehrmann")); + about->addAuthor(ki18n("Rik Hemsley")); + about->addAuthor(ki18n("Brad Hughes")); + about->addAuthor(ki18n("Ralf Nolden")); + about->addAuthor(ki18n("Brad Hards")); + setAboutData( about ); +} + +void MouseConfig::checkAccess() +{ + mk_delay->setEnabled(mouseKeys->isChecked()); + mk_interval->setEnabled(mouseKeys->isChecked()); + mk_time_to_max->setEnabled(mouseKeys->isChecked()); + mk_max_speed->setEnabled(mouseKeys->isChecked()); + mk_curve->setEnabled(mouseKeys->isChecked()); +} + + +MouseConfig::~MouseConfig() +{ + delete settings; +} + +double MouseConfig::getAccel() +{ + return accel->value(); +} + +void MouseConfig::setAccel(double val) +{ + accel->setValue(val); +} + +int MouseConfig::getThreshold() +{ + return thresh->value(); +} + +void MouseConfig::setThreshold(int val) +{ + thresh->setValue(val); +} + + +int MouseConfig::getHandedness() +{ + if (generalTab->rightHanded->isChecked()) + return RIGHT_HANDED; + else + return LEFT_HANDED; +} + +void MouseConfig::setHandedness(int val) +{ + generalTab->rightHanded->setChecked(false); + generalTab->leftHanded->setChecked(false); + if (val == RIGHT_HANDED){ + generalTab->rightHanded->setChecked(true); + generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); + } + else{ + generalTab->leftHanded->setChecked(true); + generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); + } + settings->m_handedNeedsApply = true; +} + +void MouseConfig::load() +{ + KConfig config( "kcminputrc" ); + settings->load(&config); + + generalTab->rightHanded->setEnabled(settings->handedEnabled); + generalTab->leftHanded->setEnabled(settings->handedEnabled); + if ( generalTab->cbScrollPolarity->isEnabled() ) + generalTab->cbScrollPolarity->setEnabled(settings->handedEnabled); + generalTab->cbScrollPolarity->setChecked( settings->reverseScrollPolarity ); + + setAccel(settings->accelRate); + setThreshold(settings->thresholdMove); + setHandedness(settings->handed); + + doubleClickInterval->setValue(settings->doubleClickInterval); + dragStartTime->setValue(settings->dragStartTime); + dragStartDist->setValue(settings->dragStartDist); + wheelScrollLines->setValue(settings->wheelScrollLines); + + generalTab->singleClick->setChecked( settings->singleClick ); + generalTab->doubleClick->setChecked(!settings->singleClick); + generalTab->cb_pointershape->setChecked(settings->changeCursor); + generalTab->cbAutoSelect->setChecked( settings->autoSelectDelay >= 0 ); + if ( settings->autoSelectDelay < 0 ) + generalTab->slAutoSelect->setValue( 0 ); + else + generalTab->slAutoSelect->setValue( settings->autoSelectDelay ); + slotClick(); + + + KConfig ac("kaccessrc"); + + KConfigGroup group = ac.group("Mouse"); + mouseKeys->setChecked(group.readEntry("MouseKeys", false)); + mk_delay->setValue(group.readEntry("MKDelay", 160)); + + int interval = group.readEntry("MKInterval", 5); + mk_interval->setValue(interval); + + // Default time to reach maximum speed: 5000 msec + int time_to_max = group.readEntry("MKTimeToMax", (5000+interval/2)/interval); + time_to_max = group.readEntry("MK-TimeToMax", time_to_max*interval); + mk_time_to_max->setValue(time_to_max); + + // Default maximum speed: 1000 pixels/sec + // (The old default maximum speed from KDE <= 3.4 + // (100000 pixels/sec) was way too fast) + long max_speed = group.readEntry("MKMaxSpeed", interval); + max_speed = max_speed * 1000 / interval; + if (max_speed > 2000) + max_speed = 2000; + max_speed = group.readEntry("MK-MaxSpeed", int(max_speed)); + mk_max_speed->setValue(max_speed); + + mk_curve->setValue(group.readEntry("MKCurve", 0)); + + checkAccess(); + + emit changed(false); +} + +void MouseConfig::save() +{ + settings->accelRate = getAccel(); + settings->thresholdMove = getThreshold(); + settings->handed = getHandedness(); + + settings->doubleClickInterval = doubleClickInterval->value(); + settings->dragStartTime = dragStartTime->value(); + settings->dragStartDist = dragStartDist->value(); + settings->wheelScrollLines = wheelScrollLines->value(); + settings->singleClick = !generalTab->doubleClick->isChecked(); + settings->autoSelectDelay = generalTab->cbAutoSelect->isChecked()? generalTab->slAutoSelect->value():-1; +// settings->changeCursor = generalTab->singleClick->isChecked(); + settings->changeCursor = generalTab->cb_pointershape->isChecked(); + settings->reverseScrollPolarity = generalTab->cbScrollPolarity->isChecked(); + + settings->apply(); + KConfig config( "kcminputrc" ); + settings->save(&config); + + KConfig ac("kaccessrc"); + + KConfigGroup group = ac.group("Mouse"); + + int interval = mk_interval->value(); + group.writeEntry("MouseKeys", mouseKeys->isChecked()); + group.writeEntry("MKDelay", mk_delay->value()); + group.writeEntry("MKInterval", interval); + group.writeEntry("MK-TimeToMax", mk_time_to_max->value()); + group.writeEntry("MKTimeToMax", + (mk_time_to_max->value() + interval/2)/interval); + group.writeEntry("MK-MaxSpeed", mk_max_speed->value()); + group.writeEntry("MKMaxSpeed", + (mk_max_speed->value()*interval + 500)/1000); + group.writeEntry("MKCurve", mk_curve->value()); + group.sync(); + group.writeEntry("MKCurve", mk_curve->value()); + + // restart kaccess + KToolInvocation::startServiceByDesktopName("kaccess"); + + emit changed(false); +} + +void MouseConfig::defaults() +{ + setThreshold(2); + setAccel(2); + setHandedness(RIGHT_HANDED); + generalTab->cbScrollPolarity->setChecked( false ); + doubleClickInterval->setValue(400); + dragStartTime->setValue(500); + dragStartDist->setValue(4); + wheelScrollLines->setValue(3); + generalTab->doubleClick->setChecked( !KDE_DEFAULT_SINGLECLICK ); + generalTab->cbAutoSelect->setChecked( KDE_DEFAULT_AUTOSELECTDELAY != -1 ); + generalTab->slAutoSelect->setValue( KDE_DEFAULT_AUTOSELECTDELAY == -1 ? 50 : KDE_DEFAULT_AUTOSELECTDELAY ); + generalTab->singleClick->setChecked( KDE_DEFAULT_SINGLECLICK ); + generalTab->cb_pointershape->setChecked(KDE_DEFAULT_CHANGECURSOR); + slotClick(); + + mouseKeys->setChecked(false); + mk_delay->setValue(160); + mk_interval->setValue(5); + mk_time_to_max->setValue(5000); + mk_max_speed->setValue(1000); + mk_curve->setValue(0); + + checkAccess(); + + changed(); +} + +void MouseConfig::slotClick() +{ + // Autoselect has a meaning only in single-click mode + generalTab->cbAutoSelect->setEnabled(!generalTab->doubleClick->isChecked() || generalTab->singleClick->isChecked()); + // Delay has a meaning only for autoselect + bool bDelay = generalTab->cbAutoSelect->isChecked() && ! generalTab->doubleClick->isChecked(); + generalTab->slAutoSelect->setEnabled( bDelay ); +} + +/** No descriptions */ +void MouseConfig::slotHandedChanged(int val){ + if(val==RIGHT_HANDED) + generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); + else + generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); + settings->m_handedNeedsApply = true; +} + +void MouseSettings::load(KConfig *config) +{ + int accel_num, accel_den, threshold; + double accel; + XGetPointerControl( QX11Info::display(), + &accel_num, &accel_den, &threshold ); + accel = float(accel_num) / float(accel_den); + + // get settings from X server + int h = RIGHT_HANDED; + unsigned char map[20]; + num_buttons = XGetPointerMapping(QX11Info::display(), map, 20); + + handedEnabled = true; + + // ## keep this in sync with KGlobalSettings::mouseSettings + if( num_buttons == 1 ) + { + /* disable button remapping */ + handedEnabled = false; + } + else if( num_buttons == 2 ) + { + if ( (int)map[0] == 1 && (int)map[1] == 2 ) + h = RIGHT_HANDED; + else if ( (int)map[0] == 2 && (int)map[1] == 1 ) + h = LEFT_HANDED; + else + /* custom button setup: disable button remapping */ + handedEnabled = false; + } + else + { + middle_button = (int)map[1]; + if ( (int)map[0] == 1 && (int)map[2] == 3 ) + h = RIGHT_HANDED; + else if ( (int)map[0] == 3 && (int)map[2] == 1 ) + h = LEFT_HANDED; + else + { + /* custom button setup: disable button remapping */ + handedEnabled = false; + } + } + + KConfigGroup group = config->group("Mouse"); + double a = group.readEntry("Acceleration",-1.0); + if (a == -1) + accelRate = accel; + else + accelRate = a; + + int t = group.readEntry("Threshold",-1); + if (t == -1) + thresholdMove = threshold; + else + thresholdMove = t; + + QString key = group.readEntry("MouseButtonMapping"); + if (key == "RightHanded") + handed = RIGHT_HANDED; + else if (key == "LeftHanded") + handed = LEFT_HANDED; +#ifdef __GNUC__ +#warning was key == NULL how was this working? is key.isNull() what the coder meant? +#endif + else if (key.isNull()) + handed = h; + reverseScrollPolarity = group.readEntry( "ReverseScrollPolarity", false); + m_handedNeedsApply = false; + + // SC/DC/AutoSelect/ChangeCursor + group = config->group("KDE"); + doubleClickInterval = group.readEntry("DoubleClickInterval", 400); + dragStartTime = group.readEntry("StartDragTime", 500); + dragStartDist = group.readEntry("StartDragDist", 4); + wheelScrollLines = group.readEntry("WheelScrollLines", 3); + + singleClick = group.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK); + autoSelectDelay = group.readEntry("AutoSelectDelay", KDE_DEFAULT_AUTOSELECTDELAY); + changeCursor = group.readEntry("ChangeCursor", KDE_DEFAULT_CHANGECURSOR); +} + +void MouseConfig::slotThreshChanged(int value) +{ + thresh->setSuffix(i18np(" pixel", " pixels", value)); +} + +void MouseConfig::slotDragStartDistChanged(int value) +{ + dragStartDist->setSuffix(i18np(" pixel", " pixels", value)); +} + +void MouseConfig::slotWheelScrollLinesChanged(int value) +{ + wheelScrollLines->setSuffix(i18np(" line", " lines", value)); +} + +void MouseSettings::apply(bool force) +{ + XChangePointerControl( QX11Info::display(), + true, true, int(qRound(accelRate*10)), 10, thresholdMove); + + // 256 might seems extreme, but X has already been known to return 32, + // and we don't want to truncate things. Xlib limits the table to 256 bytes, + // so it's a good uper bound.. + unsigned char map[256]; + num_buttons = XGetPointerMapping(QX11Info::display(), map, 256); + + int remap=(num_buttons>=1); + if (handedEnabled && (m_handedNeedsApply || force)) { + if( num_buttons == 1 ) + { + map[0] = (unsigned char) 1; + } + else if( num_buttons == 2 ) + { + if (handed == RIGHT_HANDED) + { + map[0] = (unsigned char) 1; + map[1] = (unsigned char) 3; + } + else + { + map[0] = (unsigned char) 3; + map[1] = (unsigned char) 1; + } + } + else // 3 buttons and more + { + if (handed == RIGHT_HANDED) + { + map[0] = (unsigned char) 1; + map[1] = (unsigned char) middle_button; + map[2] = (unsigned char) 3; + } + else + { + map[0] = (unsigned char) 3; + map[1] = (unsigned char) middle_button; + map[2] = (unsigned char) 1; + } + if( num_buttons >= 5 ) + { + // Apps seem to expect logical buttons 4,5 are the vertical wheel. + // With mice with more than 3 buttons (not including wheel) the physical + // buttons mapped to logical 4,5 may not be physical 4,5 , so keep + // this mapping, only possibly reversing them. + int pos; + for( pos = 0; pos < num_buttons; ++pos ) + if( map[pos] == 4 || map[pos] == 5 ) + break; + if( pos < num_buttons - 1 ) + { + map[pos] = reverseScrollPolarity ? (unsigned char) 5 : (unsigned char) 4; + map[pos+1] = reverseScrollPolarity ? (unsigned char) 4 : (unsigned char) 5; + } + } + } + int retval; + if (remap) + while ((retval=XSetPointerMapping(QX11Info::display(), map, + num_buttons)) == MappingBusy) + /* keep trying until the pointer is free */ + { }; + m_handedNeedsApply = false; + } + + // This iterates through the various Logitech mice, if we have support. + #ifdef HAVE_LIBUSB + LogitechMouse *logitechMouse; + Q_FOREACH( logitechMouse, logitechMouseList ) { + logitechMouse->applyChanges(); + } + #endif +} + +void MouseSettings::save(KConfig *config) +{ + KConfigGroup group = config->group("Mouse"); + group.writeEntry("Acceleration",accelRate); + group.writeEntry("Threshold",thresholdMove); + if (handed == RIGHT_HANDED) + group.writeEntry("MouseButtonMapping",QString("RightHanded")); + else + group.writeEntry("MouseButtonMapping",QString("LeftHanded")); + group.writeEntry( "ReverseScrollPolarity", reverseScrollPolarity ); + + group = config->group("KDE"); + group.writeEntry("DoubleClickInterval", doubleClickInterval, KConfig::Persistent|KConfig::Global); + group.writeEntry("StartDragTime", dragStartTime, KConfig::Persistent|KConfig::Global); + group.writeEntry("StartDragDist", dragStartDist, KConfig::Persistent|KConfig::Global); + group.writeEntry("WheelScrollLines", wheelScrollLines, KConfig::Persistent|KConfig::Global); + group.writeEntry("SingleClick", singleClick, KConfig::Persistent|KConfig::Global); + group.writeEntry("AutoSelectDelay", autoSelectDelay, KConfig::Persistent|KConfig::Global); + group.writeEntry("ChangeCursor", changeCursor,KConfig::Persistent|KConfig::Global); + // This iterates through the various Logitech mice, if we have support. +#ifdef HAVE_LIBUSB + LogitechMouse *logitechMouse; + Q_FOREACH( logitechMouse, logitechMouseList ) { + logitechMouse->save(config); + } +#endif + config->sync(); + KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_MOUSE); +} + +void MouseConfig::slotScrollPolarityChanged() +{ + settings->m_handedNeedsApply = true; +} + +void MouseConfig::slotSmartSliderEnabling() +{ + bool enabled = generalTab->singleClick->isChecked() ? generalTab->cbAutoSelect->isChecked() : false; + generalTab->slAutoSelect->setEnabled(enabled); +} + +#include "mouse.moc" diff --git a/kcontrol/input/mouse.desktop b/kcontrol/input/mouse.desktop new file mode 100644 index 00000000..81c029e9 --- /dev/null +++ b/kcontrol/input/mouse.desktop @@ -0,0 +1,237 @@ +[Desktop Entry] +Exec=kcmshell4 mouse +Icon=preferences-desktop-mouse +Type=Service +X-KDE-ServiceTypes=KCModule,KCModuleInit +X-DocPath=kcontrol/mouse/index.html + +X-KDE-Library=kcm_input +X-KDE-Init-Symbol=mouse +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=input-devices +X-KDE-Weight=60 + +Name=Mouse +Name[af]=Muis +Name[ar]=الفأرة +Name[ast]=Mur +Name[be]=Мыш +Name[be@latin]=Myš +Name[bg]=Мишка +Name[bn]=মাউস +Name[bn_IN]=মাউস +Name[br]=Logodenn +Name[bs]=Miš +Name[ca]=Ratolí +Name[ca@valencia]=Ratolí +Name[cs]=Myš +Name[csb]=Mësz +Name[cy]=Llygoden +Name[da]=Mus +Name[de]=Maus +Name[el]=Ποντίκι +Name[en_GB]=Mouse +Name[eo]=Muso +Name[es]=Ratón +Name[et]=Hiir +Name[eu]=Sagua +Name[fa]=موشی +Name[fi]=Hiiri +Name[fr]=Souris +Name[fy]=Mûs +Name[ga]=Luch +Name[gl]=Rato +Name[gu]=માઉસ +Name[he]=עכבר +Name[hi]=माउस +Name[hne]=मुसुवा +Name[hr]=Miš +Name[hsb]=Myš +Name[hu]=Egér +Name[ia]=Mus +Name[id]=Tetikus +Name[is]=Mús +Name[it]=Mouse +Name[ja]=マウス +Name[ka]=თაგვი +Name[kk]=Тышқан +Name[km]=កណ្ដុរ +Name[kn]=ಮೂಷಕ (ಮೌಸ್) +Name[ko]=마우스 +Name[ku]=Mişk +Name[lt]=Pelė +Name[lv]=Pele +Name[mai]=माउस +Name[mk]=Глушец +Name[ml]=മൌസ് +Name[mr]=माऊस +Name[ms]=Tetikus +Name[nb]=Mus +Name[nds]=Muus +Name[ne]=माउस +Name[nl]=Muis +Name[nn]=Mus +Name[oc]=Mirga +Name[or]=ମାଉସ +Name[pa]=ਮਾਊਸ +Name[pl]=Mysz +Name[pt]=Rato +Name[pt_BR]=Mouse +Name[ro]=Maus +Name[ru]=Мышь +Name[se]=Sáhpán +Name[si]=මවුසය +Name[sk]=Myš +Name[sl]=Miška +Name[sr]=Миш +Name[sr@ijekavian]=Миш +Name[sr@ijekavianlatin]=Miš +Name[sr@latin]=Miš +Name[sv]=Mus +Name[ta]=சுட்டி +Name[te]=మౌస్ +Name[tg]=Муш +Name[th]=เมาส์ +Name[tr]=Fare +Name[ug]=چاشقىنەك +Name[uk]=Мишка +Name[uz]=Sichqoncha +Name[uz@cyrillic]=Сичқонча +Name[vi]=Chuột +Name[wa]=Sori +Name[xh]=Mouse +Name[x-test]=xxMousexx +Name[zh_CN]=鼠标 +Name[zh_TW]=滑鼠 + +Comment=Mouse settings +Comment[af]=Muis instellings +Comment[ar]=إعدادات الفأرة +Comment[ast]=Preferencies sobre'l mur +Comment[be]=Настаўленні мышы +Comment[be@latin]=Nałady myšy +Comment[bg]=Настройки на мишка +Comment[bn]=মাউস সেটিংস +Comment[bn_IN]=মাউস সংক্রান্ত বৈশিষ্ট্য +Comment[br]=Kefluniañ al logodenn +Comment[bs]=Postavke miša +Comment[ca]=Arranjament del ratolí +Comment[ca@valencia]=Arranjament del ratolí +Comment[cs]=Nastavení myši +Comment[csb]=Nastôw mëszë +Comment[cy]=Gosodiadau Llygoden +Comment[da]=Indstilling af mus +Comment[de]=Einstellung der Maus +Comment[el]=Ρυθμίσεις Ποντικιού +Comment[en_GB]=Mouse settings +Comment[eo]=Agordo de la muso +Comment[es]=Preferencias sobre el ratón +Comment[et]=Hiire seadistused +Comment[eu]=Saguaren ezarpenak +Comment[fa]=تنظیمات موشی +Comment[fi]=Hiiren asetukset +Comment[fy]=Mûsynstellings +Comment[ga]=Socruithe luiche +Comment[gl]=Configuración do rato +Comment[gu]=માઉસ ગોઠવણીઓ +Comment[he]=הגדרות העכבר +Comment[hi]=माउस विन्यास +Comment[hne]=मुसुवा सेटिंग +Comment[hr]=Postavke miša +Comment[hsb]=Nastajenja za myš +Comment[hu]=Az egér beállításai +Comment[ia]=Preferentias de mus +Comment[id]=Pengaturan tetikus +Comment[is]=Stillingar músar +Comment[ka]=თაგვის კონფიგურაცია +Comment[kk]=Тышқан параметрлері +Comment[km]=ការ​កំណត់​កណ្ដុរ +Comment[kn]=ಮೂಷಕದ (ಮೌಸ್) ಸಂಯೋಜನೆಗಳು +Comment[ko]=마우스 설정 +Comment[ku]=Mîhengên Mişkî +Comment[lt]=Pelės parametrai +Comment[lv]=Peles parametri +Comment[mai]=माउस बिन्यास +Comment[mk]=Поставувања на глушецот +Comment[ml]=മൌസിന്റെ സജ്ജീകരണങ്ങള്‍ +Comment[mr]=माऊस संयोजना +Comment[ms]=Seting tetikus +Comment[nb]=Musinnstillinger +Comment[nds]=De Muus instellen +Comment[ne]=माउस सेटिङ +Comment[nl]=Muisinstellingen +Comment[nn]=Musinnstillingar +Comment[or]=ମାଉସ ବିନ୍ୟାସ +Comment[pa]=ਮਾਊਸ ਸੈਟਿੰਗ +Comment[pl]=Ustawienia myszy +Comment[pt]=Configuração do rato +Comment[pt_BR]=Configurações do mouse +Comment[ro]=Configurări maus +Comment[ru]=Настройка мыши +Comment[se]=Sáhpánheivehusat +Comment[si]=මවුසයේ සැකසුම් +Comment[sk]=Nastavenie myši +Comment[sl]=Nastavitve miške +Comment[sr]=Поставке миша +Comment[sr@ijekavian]=Поставке миша +Comment[sr@ijekavianlatin]=Postavke miša +Comment[sr@latin]=Postavke miša +Comment[sv]=Anpassa mus +Comment[ta]=சுட்டி அமைப்புகள் +Comment[te]=మౌస్ అమరికలు +Comment[tg]=Танзимоти муш +Comment[th]=ตั้งค่าต่างๆ ของเมาส์ +Comment[tr]=Fare ayarları +Comment[ug]=چاشقىنەك تەڭشەك +Comment[uk]=Налаштування миші +Comment[uz]=Sichqonchaning moslamalari +Comment[uz@cyrillic]=Сичқончанинг мосламалари +Comment[vi]=Thiết lập con chuột +Comment[wa]=Apontiaedjes del sori +Comment[xh]=Izicwangciso ze mouse +Comment[x-test]=xxMouse settingsxx +Comment[zh_CN]=鼠标设置 +Comment[zh_TW]=滑鼠設定 + +X-KDE-Keywords=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation +X-KDE-Keywords[bs]=Miš, Brzina kretanja miša, Prag osjetljivosti miša, Tasteri miša, Oblik kursora, Ulazni Uređaji, Mapiranje tastera, Klik, Ikone, feedback (povratna veza), Pokazivači, Vuči (drag), Dupli klik, Jedan Klik, Mapiranje, Dešnjak, Ljevak, Uređaj koji je Pokazivač (miš, Trackball, Joystick), Točkić za pomicanje (gore ili dolje), Emulatija Miša, Navigacija Miša, Miš Povucite i ispustite(drag and drop), Skrolanje Mišem, Osjetljivost Miša, Pomjeranje miša pomoću brojevne tastature, Emulacija miša pomoću brojevne tastature +X-KDE-Keywords[ca]=Ratolí,Acceleració de ratolí,Llindar de ratolí,Botons de ratolí,Selecció,Ombra de cursor,Dispositius d'entrada,Mapatge de boton,Clic,icones,reacció,Apuntadors,Arrossegar,Clic doble,Clic normal,mapatge,dretà,esquerrà,Dispositiu apuntador,Roda de ratolí,Emulació de ratolí,Navegació amb ratolí,Arrossegar i deixar anar de ratolí,Desplaçament amb ratolí,Sensitivitat de ratolí,Moure el ratolí amb teclat numèric,Emulació de ratolí amb teclat numèric +X-KDE-Keywords[ca@valencia]=Ratolí,Acceleració de ratolí,Llindar de ratolí,Botons de ratolí,Selecció,Ombra de cursor,Dispositius d'entrada,Mapatge de boton,Clic,icones,reacció,Apuntadors,Arrossegar,Clic doble,Clic normal,mapatge,dretà,esquerrà,Dispositiu apuntador,Roda de ratolí,Emulació de ratolí,Navegació amb ratolí,Arrossegar i deixar anar de ratolí,Desplaçament amb ratolí,Sensitivitat de ratolí,Moure el ratolí amb teclat numèric,Emulació de ratolí amb teclat numèric +X-KDE-Keywords[da]=Mus,Museacceleration,musetærskel,museknapper,markering,markørform,Input-enheder,knapkobling,klik,ikoner,feedback,Pointers,træk,dobbeltklik,enkeltklik,kobling,højrehåndet,venstrehåndet,pegeenhed,musehjul,museemulering,musenavigation,træk og slip,muserulning,scrolling,musefølsomhed,bevæg mus med numerisk tastatur,markører,cursor,rulning +X-KDE-Keywords[de]=Maus,Mausbeschleunigung,Mausschwellwert,Maustasten,Auswahl,Cursor,Cursor-Form,Eingabegeräte,Knöpfe,Buttons,Zuordnungen,Klicks,Zeigegeräte,Doppelklick,Rechtshänder,Linkshänder,Ziehen,Mausrad,Maus-Emulation,Maus-Navigation,Ziehen und Ablegen mit der Maus,Blättern mit der Maus,Maus-Empfindlichkeit,Mauszeiger mit der Zahlentastatur verschieben,Maus-Emulation mit der Zahlentastatur +X-KDE-Keywords[el]=ποντίκι,επιτάχυνση ποντικιού,κατώφλι ποντικιού,κουμπιά ποντικιού,επιλογή,σχήμα δρομέα,συσκευές εισόδου,χαρτογράφηση κουμπιών,κλικ,εικονίδια,ανάδραση,δείκτες,έλξη,διπλό κλικ,μονό κλικ,χαρτογράφηση,δεξιόχειρας,αριστερόχειρας,συσκευή δείκτη,τροχός ποντικιού,εξομοίωση ποντικιού,πλοήγηση ποντικιού,έλξη και απόθεση ποντικιού,κύλιση ποντικιού,ευαισθησία ποντικιού,κίνηση ποντικιού με το αριθμητικό πληκτρολόγιο,εξομοίωση ποντικιού αριθμητικού πληκτρολογίου +X-KDE-Keywords[en_GB]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation +X-KDE-Keywords[es]=Ratón,Aceleración de ratón,Umbral del ratón,Botones del ratón,Selección,Forma del cursor,Dispositivos de entrada,Mapeo de botones,Clic,iconos,reacción,Punteros,Arrastrar,Doble clic,clic sencillo,mapeo,diestro,zurdo,Dispositivo apuntador,Rueda del ratón,Emulación del ratón,Navegación con el ratón,Arrastrar y soltar con el ratón,Desplazamiento con el ratón,Sensibilidad del ratón,Mover el ratón con el teclado numérico,Emulación del ratón con el teclado numérico +X-KDE-Keywords[et]=hiir,hiire kiirendamine,hiire lävi,hiirenupud,valik,kursori kuju,sisendseadmed,nuppude seostamine,klõps,klõpsamine,ikoonid,tagasiside,lohistamine,topeltklõps,ühekordne klõps,seostamine,paremakäelised,vasakukäelised,osutusseade,hiireratas,hiire emuleerimine,hiirega liikumine,hiirega lohistamine,hiirega kerimine,hiire tundlikkus,hiire liigutamine numbriklahvistikuga,hiire numbriklahvistiku emuleerimine +X-KDE-Keywords[eu]=sagu,saguaren azelerazio,saguaren atalase,saguaren botoiak,hautapena,kurtsorearen forma,sarrerako gailuak,botoiak mapatzea,klik,ikonoak,oharrak,erakusle,arrastatu,klik bikoitza,klik bakarra,mapatze,eskuina,ezkerra,erakuslearen gailu,saguaren gurpil,saguaren emulazio,sagu bidezko nabigazio,saguaren bidez arrastatu eta jaregin,saguaren bidez korritu,saguaren sentikortasuna,sagua zenbakizko teklatuarekin mugitzea,sagua emulatzea zenbakizko teklatuarekin +X-KDE-Keywords[fi]=Hiiri,Osoittimen kiihdytys,Osoittimen raja-arvo,Hiiripainikkeet,Valinta,Osoittimen muoto,Syöttölaitteet,Syötelaitteet,Painikkeiden kuvaus,Napsauta,Napsautus,kuvakkeet,tuntuma,Osoittimet,Raahaus,Kaksoisnapsautus,kuvaus,oikeakätinen,oikeakätisyys,vasenkätinen,vasenkätisyys,osoitinlaite,hiiren rulla,hiiren emulointi,hiirinavigointi,hiiren vedä ja pudota,hiiren vieritys,hiiren herkkyys,hiiren liikuttaminen numeronäppäimistöltä +X-KDE-Keywords[fr]=Souris, Accélération de la souris, Seuil de la souris, Boutons de la souris, Sélection, Forme du curseur, Périphériques d'entrée, affectation des boutons, Clic, icônes, réaction, Pointeurs, Glisser, Double clic, Simple clic, affectation, droitier, gaucher, Périphérique de pointage, Roulette de la souris, Émulation de la souris, Navigation de la souris, Glisser-déposer, Défilement de la souris, Sensibilité de la souris, Déplacement de la souris avec le pavé numérique, Émulation de la souris du pavé numérique +X-KDE-Keywords[gl]=rato, aceleración do rato, limiar do rato, botóns do rato, selección, escolla, forma do rato, dispositivos de entrada, mapas de botóns, premer, clic, iconas, punteiro, arrastrar, duplo clic, dobre clic, dereito, zurdo, dispositivo do punteiro, roda do rato, emulación do rato, navegación co rato, arrastrar e soltar co rato, sensibilidade do rato, mover o rato co teclado numérico, teclado numérico +X-KDE-Keywords[hu]=Egér,Egérgyorsítás,Egérküszöb,Egérgombok,Kijelölés,Kurzorforma,Beviteli eszközök,Gombhozzárendelés,Kattintás,ikonok,visszajelzés,Mutatók,Fogás,Dupla kattintás,Egyszeres kattintás,leképezés,jobb kezes,bal kezes,Mutató eszköz,Egérgörgő,Egéremuláció,Egérnavigáció,Egér fogd és vidd,Egérgörgetés,Egér érzékenység,Egér mozgatása numerikus billentyűkkel,Egér numerikus billentyűzet emuláció +X-KDE-Keywords[ia]=Mus,Acceleration de mus,Limine de mus,Buttones de mus,Selection,Forma de cursor, Dispositivos de ingresso,Mappatura de button,Click,icones,retro-information,Punctatores,Trahe,DupleClick,Singule click,mappar,con mano dextere, con mano sinistre,Dispositivo punctator,Rota de Mus,Emulation de mus,Navigation de mus,Traher e Poner con Mus, Rolar con Mus,Sensibilitate de mus, Move Mus con NumPad,Emulation Mus con NumPad +X-KDE-Keywords[it]=mouse,accelerazione del mouse,soglia del mouse,pulsanti del mouse,selezione,forma del cursore,dispositivi di ingresso,mappatura dei pulsanti,clic,icone,segnale di avvio,puntatori,trascinamento,doppio clic,singolo clic,mappatura,destrorso,mancino,dispositivo di puntamento,rotellina del mouse,emulazione del mouse,navigazione con il mouse, trascinamento con il mouse, scorrimento con il mouse, sensibilità del mouse,muovi il mouse con il tastierino numerico,emulazione mouse con il tastierino numerico +X-KDE-Keywords[kk]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation +X-KDE-Keywords[km]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation +X-KDE-Keywords[ko]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation,마우스,마우스 가속,시간,커서 모양,입력 장치,클릭,드래그,왼손잡이,오른손잡이,마우스 휠,마우스 탐색, 마우스 스크롤,감도,스크롤,휠 +X-KDE-Keywords[mr]=माऊस, माऊस एक्सलरेशन, माऊस थ्रेशहोल्ड, माऊस बटन्स, सिलेक्शन, कर्सर शेप, इनपुट डिव्हाईस, बटन मेपिंग, क्लिक, आयकॉनस, फीडबेक, पॉईटर, ड्रग डबल, क्लिक, सिंगल क्लिक, मेपिंग, राईट हेन्डेड ,पॉईटर डिव्हाईस,माऊस, व्हील, माऊस इम्यूलेशन, माऊस,नेव्हीगेशन, माऊस ड्रेग व ड्रोप,न्यूम पॅड, माऊस न्यूम पॅड इम्यूलेशन +X-KDE-Keywords[nb]=Mus,Pekerakselerasjon,Pekerterskel,knapper,valg,pekerform,Inndataenheter,knappeavbildning,Klikk, ikoner,oppstartsmelding,Pekere,Dra,Dobbeltklikk,Enkeltklikk,Knapperekkefølge,høyrehendt,venstrehendt,Pekerenhet,Musehjul,Musemulering,Musenavigasjon,Dra og slipp med Mus, Muserulling,Flytt mus med talltastatur,Museemulering med talltastatur +X-KDE-Keywords[nds]=Muus,Muusbeslünigen,Wieser-Süll,Muusgauheit,Muusknööp,Köör,Blinkerform,Ingaavreedschappen,Knoop-Toornen,Klick,Lüttbiller,Rückmellen,Wiesers,Dregen,Dubbelklick,Towiesen,Rechtepoot,Linkepoot,Wiesreedschap,Muusrad,Muusemuleren,Muusstüern,Dregen un Droppen,Trecken,Afsetten,Fallenlaten,Rullen,Föhlsamkeit,Tallenblock +X-KDE-Keywords[nl]=muis,muisversnelling,muisdrempel,muisknoppen,selectie,cursorvorm,invoerapparaten,knoppenmapping,klik,pictogrammen,terugkoppeling,aanwijzer,slepen,dubbelklik,klik,mapping,rechtshandig,linkshandig,aanwijsapparaat,muiswiel,muisemulatie,muisnavigatie,slepen en laten vallen met muis,schuiven met de muis,muisgevoeligheid,muis bewegen met num-pad,emulatie van num-pad met muis +X-KDE-Keywords[pl]=Mysz,Przyspieszenie myszy,Próg myszy,Przyciski myszy,Zaznaczenie, Kształt kursora,Urządzenia wejścia,Mapowanie przycisków,Kliknięcie,ikony,odczucie,Wskaźniki,Przeciągnięcie,Podwójne kliknięcie,mapowanie,praworęczny,leworęczny, Urządzenie wskazujące,Rolka myszy,Emulacja myszy,Nawigacja myszą,Przeciąganie i upuszczanie myszą,Przewijanie myszą,Czułość myszy,Przemieszczaj myszą przy użyciu klawiatury numerycznej,Emulacja myszy klawiaturą numeryczną +X-KDE-Keywords[pt]=Rato,aceleração do rato,limiar do rato,botões do rato,selecção,forma do cursor,dispositivos de entrada,associação de botões,click,ícones,reacção,cursores,arrastar,duplo-click,associação,destro,esquerdino,ponteiro,roda do rato,emulação do rato,navegação do rato,arrastamento com o rato,deslocamento do rato,sensibilidade do rato,mover o rato com cursores,emulação do rato com teclado numérico +X-KDE-Keywords[pt_BR]=Mouse,aceleração do mouse,limiar do mouse,botões do mouse,seleção,forma do cursor,dispositivos de entrada,associação de botões,clique,ícones,feedback,ponteiros,arrastar,clique duplo,clique simples,associação,destro,canhoto, ponteiro,roda do mouse,emulação do mouse,navegação do mouse,arrastar e soltar com o mouse,deslocamento do mouse,sensibilidade do mouse,mover o mouse com o teclado numérico,emulação do mouse com o teclado numérico +X-KDE-Keywords[ru]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation,мышь,ускорение мыши,границы мыши,кнопки мыши,выбор,форма курсора,устройство ввода,назначение клавиш,клик,значки,обратная связь,указатели,перемещение,двойной клик,двойной щелчок,одиночный клик,одиночный щелчок,правая рука,левая рука,праворукая,леворукая,колесо мыши,эмуляция мыши,управление мышью, навигация мыши,прокрутка,чувствительность,управление мышью через цифровую клавиатуру +X-KDE-Keywords[sk]=Myš,Zrýchlenie myši,Prah myši,Tlačidlá myši,Výber,Tvar kurzora,Vstupné zariadenia,Mapovanie tlačidiel,Klik,ikony,odozva,Ukazovatele,Drag,Dvojklik,Jednoduchý klik,mapovanie,pre pravákov,pre ľavákov,ukazovacie zariadenie,koliesko myši,emulácia myši,navigácia myši,drag and drop myši,rolovanie myši,citlivosť myši,pohyb myši numerickou klávesnicou,emulácia myši numerickou klávesnicou +X-KDE-Keywords[sl]=miška,pospešek miške,prag miške,gumbi miške,miškini gumbi,izbor,oblika kazalca,oblika kazalke,vhodne naprave,preslikava gumbov,klik,ikone,povratne informacije,odziv,kazalci,kazalke,vleka,dvojni klik,dvoklik,enojni klik,preslikava,desničar,levičar,kazalna naprava,kolešček miške,miškin kolešček,posnemanje miške,krmarjenje z miško,vleka in spuščanje z miško,pomikanje z miško,občutljivost miške,miškina občutljivost,premikanje miške s številčnico,posnemanje s številčnico +X-KDE-Keywords[sr]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation,миш,убрзање миша,праг миша,дугмад миша,избор,облик показивача,облик курсора,улазни уређаји,мапирање дугмади,клик,иконе,одзив,превлачење,двоклик,десноруки,леворуки,показивачки уређај,точкић миша,осетљивост миша,кретање мишем,емулација миша,емулација миша преко нумеричке тастатуре +X-KDE-Keywords[sr@ijekavian]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation,миш,убрзање миша,праг миша,дугмад миша,избор,облик показивача,облик курсора,улазни уређаји,мапирање дугмади,клик,иконе,одзив,превлачење,двоклик,десноруки,леворуки,показивачки уређај,точкић миша,осетљивост миша,кретање мишем,емулација миша,емулација миша преко нумеричке тастатуре +X-KDE-Keywords[sr@ijekavianlatin]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation,miš,ubrzanje miša,prag miša,dugmad miša,izbor,oblik pokazivača,oblik kursora,ulazni uređaji,mapiranje dugmadi,klik,ikone,odziv,prevlačenje,dvoklik,desnoruki,levoruki,pokazivački uređaj,točkić miša,osetljivost miša,kretanje mišem,emulacija miša,emulacija miša preko numeričke tastature +X-KDE-Keywords[sr@latin]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation,miš,ubrzanje miša,prag miša,dugmad miša,izbor,oblik pokazivača,oblik kursora,ulazni uređaji,mapiranje dugmadi,klik,ikone,odziv,prevlačenje,dvoklik,desnoruki,levoruki,pokazivački uređaj,točkić miša,osetljivost miša,kretanje mišem,emulacija miša,emulacija miša preko numeričke tastature +X-KDE-Keywords[sv]=Mus,Musacceleration,Muströskel,Musknappar,Val,Pekarform,Indataenheter,Knappavbildning,Klick,ikoner,återmatning,Pekare,Dra,Dubbelklick,avbildning,högerhänt,vänsterhänt,pekarenhet,mushjul,musemulering,musnavigering,mus drag och släpp,musrullning,muskänslighet,flytta musen med numeriskt tangentbord,emulering av mus med numeriskt tangentbord +X-KDE-Keywords[tr]=Fare,Fare Hızlandırma,Fare Eşiği,Fare Düğmeleri,Seçim,İşaretçi Şekli,Girdi Aygıtları,Düğme Haritalama,Tıklama,simgeler,geri bildirim,İşaretçiler,Sürükle,Çift Tıklama,Tek Tıklama,haritalama,sağlak,solak,İşaretçi Aygıtı,Fare Tekeri,Fare Benzetimi,Fare Gezinmesi,Fare Sürükle Bırak,Fare Kaydırması,Fare Hassasiyeti,Fareyi Sayısal Tuşlarla Hareket Ettir,Fare Sayısal Tuş Benzetimi +X-KDE-Keywords[uk]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,DoubleClick,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation,миша,прискорення,поріг,порогове значення,кнопка,вибір,вказівник,форма,введення,кнопки,клацання,піктограми,значки,іконки,супровід,вказівники,перетягування,подвійне клацання,відповідність,праворукий,шульга,лівша,пристрій вказівника,коліщатко миші,емуляція миші,імітація миші,навігація за допомогою миші,перетягування зі скиданням мишею,гортання мишею,чутливість миші,миша з цифровою панеллю,емуляція цифрової панелі миші +X-KDE-Keywords[x-test]=xxMouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulationxx +X-KDE-Keywords[zh_CN]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation,鼠标,鼠标加速,鼠标阀值,鼠标按键,选择,光标形状,输入设备,按键映射,点击,图标,反馈,指针,拖拽,双击,映射,右手习惯,左手习惯,光标设备,指针设备,鼠标滚轮,鼠标模拟,鼠标导航,鼠标拖拽,鼠标滚动,鼠标灵敏度,小键盘移动鼠标,小键盘鼠标模拟 +X-KDE-Keywords[zh_TW]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation +Categories=Qt;KDE;X-KDE-settings-hardware; diff --git a/kcontrol/input/mouse.h b/kcontrol/input/mouse.h new file mode 100644 index 00000000..d926a991 --- /dev/null +++ b/kcontrol/input/mouse.h @@ -0,0 +1,160 @@ +/* + * mouse.h + * + * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * + * Layout management, enhancements: + * Copyright (c) 1999 Dirk A. Mueller + * + * SC/DC/AutoSelect/ChangeCursor: + * Copyright (c) 2000 David Faure + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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 +#include +#include + +#include + +#include +#include + +#include +#include +#ifdef HAVE_LIBUSB +#include "logitechmouse.h" +#endif + +#include +#include "ui_kmousedlg.h" + +#define RIGHT_HANDED 0 +#define LEFT_HANDED 1 + +class QCheckBox; +class QSlider; +class QTabWidget; + +class KMouseDlg : public QWidget, public Ui::KMouseDlg +{ +public: + KMouseDlg( QWidget *parent ) : QWidget( parent ) { + setupUi( this ); + } +}; + + +class MouseSettings +{ +public: + void save(KConfig *); + void load(KConfig *); + void apply(bool force=false); +public: + int num_buttons; + int middle_button; + bool handedEnabled; + bool m_handedNeedsApply; + int handed; + double accelRate; + int thresholdMove; + int doubleClickInterval; + int dragStartTime; + int dragStartDist; + bool singleClick; + int autoSelectDelay; + bool changeCursor; + int wheelScrollLines; + bool reverseScrollPolarity; + + #ifdef HAVE_LIBUSB + // TODO: In Qt4, replace with a better container. + QList logitechMouseList; + #endif +}; + +class MouseConfig : public KCModule +{ + Q_OBJECT +public: + MouseConfig(QWidget *parent, const QVariantList &args); + ~MouseConfig(); + + void save(); + void load(); + void defaults(); + +private Q_SLOTS: + + void slotClick(); + /** No descriptions */ + void slotHandedChanged(int val); + void slotScrollPolarityChanged(); + void checkAccess(); + void slotThreshChanged(int value); + void slotDragStartDistChanged(int value); + void slotWheelScrollLinesChanged(int value); + void slotSmartSliderEnabling(); + +private: + + double getAccel(); + int getThreshold(); + int getHandedness(); + + void setAccel(double); + void setThreshold(int); + void setHandedness(int); + + KDoubleNumInput *accel; + KIntNumInput *thresh; + KIntNumInput *doubleClickInterval; + KIntNumInput *dragStartTime; + KIntNumInput *dragStartDist; + KIntNumInput *wheelScrollLines; + +// QRadioButton *leftHanded, *rightHanded; +// QCheckBox *doubleClick; +// QCheckBox *cbAutoSelect; + QLabel *lDelay; +// QSlider *slAutoSelect; +// QCheckBox *cbVisualActivate; +// QCheckBox *cbCursor; +// QCheckBox *cbLargeCursor; + + QTabWidget *tabwidget; + QWidget *advancedTab; + KMouseDlg* generalTab; + MouseSettings *settings; + + QCheckBox *mouseKeys; + KIntNumInput *mk_delay, *mk_interval, *mk_time_to_max, *mk_max_speed, + *mk_curve; + + +}; + +#endif + diff --git a/kcontrol/input/pics/CMakeLists.txt b/kcontrol/input/pics/CMakeLists.txt new file mode 100644 index 00000000..4ef49ea1 --- /dev/null +++ b/kcontrol/input/pics/CMakeLists.txt @@ -0,0 +1 @@ +install( FILES mouse_rh.png mouse_lh.png DESTINATION ${DATA_INSTALL_DIR}/kcminput/pics ) diff --git a/kcontrol/input/pics/mouse_lh.png b/kcontrol/input/pics/mouse_lh.png new file mode 100644 index 00000000..796d5994 Binary files /dev/null and b/kcontrol/input/pics/mouse_lh.png differ diff --git a/kcontrol/input/pics/mouse_lh.svgz b/kcontrol/input/pics/mouse_lh.svgz new file mode 100644 index 00000000..fa44476a Binary files /dev/null and b/kcontrol/input/pics/mouse_lh.svgz differ diff --git a/kcontrol/input/pics/mouse_rh.png b/kcontrol/input/pics/mouse_rh.png new file mode 100644 index 00000000..1d70d897 Binary files /dev/null and b/kcontrol/input/pics/mouse_rh.png differ diff --git a/kcontrol/input/pics/mouse_rh.svgz b/kcontrol/input/pics/mouse_rh.svgz new file mode 100644 index 00000000..fc2b069a Binary files /dev/null and b/kcontrol/input/pics/mouse_rh.svgz differ diff --git a/kcontrol/input/xcursor/cursortheme.cpp b/kcontrol/input/xcursor/cursortheme.cpp new file mode 100644 index 00000000..2c8c260d --- /dev/null +++ b/kcontrol/input/xcursor/cursortheme.cpp @@ -0,0 +1,155 @@ +/* + * Copyright © 2006-2007 Fredrik Höglund + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "themepage.h" +#include "cursortheme.h" + +#include + +#ifdef HAVE_XFIXES +# include +# include +#endif + + +CursorTheme::CursorTheme(const QString &title, const QString &description) +{ + setTitle(title); + setDescription(description); + setSample("left_ptr"); + setIsHidden(false); + setIsWritable(false); +} + + +QPixmap CursorTheme::icon() const +{ + if (m_icon.isNull()) + m_icon = createIcon(); + + return m_icon; +} + + +QImage CursorTheme::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()); +} + + +QPixmap CursorTheme::loadPixmap(const QString &name, int size) const +{ + QImage image = loadImage(name, size); + if (image.isNull()) + return QPixmap(); + + return QPixmap::fromImage(image); +} + + +static int nominalCursorSize(int iconSize) +{ + for (int i = 512; i > 8; i /= 2) + { + if (i < iconSize) + return i; + + if ((i * .75) < iconSize) + return int(i * .75); + } + + return 8; +} + + +QPixmap CursorTheme::createIcon() const +{ + int iconSize = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize); + int cursorSize = nominalCursorSize(iconSize); + QSize size = QSize(iconSize, iconSize); + + QPixmap pixmap = createIcon(cursorSize); + + if (!pixmap.isNull()) + { + // Scale the pixmap if it's larger than the preferred icon size + if (pixmap.width() > size.width() || pixmap.height() > size.height()) + pixmap = pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + + return pixmap; +} + + +QPixmap CursorTheme::createIcon(int size) const +{ + QPixmap pixmap; + QImage image = loadImage(sample(), size); + + if (image.isNull() && sample() != "left_ptr") + image = loadImage("left_ptr", size); + + if (!image.isNull()) + { + pixmap = QPixmap::fromImage(image); + } + + return pixmap; +} + + +void CursorTheme::setCursorName(QCursor &cursor, const QString &name) const +{ +#ifdef HAVE_XFIXES + static bool haveXfixes = ThemePage::haveXfixes(); + + if (haveXfixes) + { + XFixesSetCursorName(QX11Info::display(), cursor.handle(), + QFile::encodeName(name)); + } +#endif +} + diff --git a/kcontrol/input/xcursor/cursortheme.h b/kcontrol/input/xcursor/cursortheme.h new file mode 100644 index 00000000..672239b6 --- /dev/null +++ b/kcontrol/input/xcursor/cursortheme.h @@ -0,0 +1,143 @@ +/* + * Copyright © 2006-2007 Fredrik Höglund + * + * 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. + */ + +#ifndef CURSORTHEME_H +#define CURSORTHEME_H + +#include +#include + +/** + * This is the abstract base class for all cursor themes stored in a + * CursorThemeModel and previewed in a PreviewWidget. + * + * All cursor themes have a title, a description, an icon, and an internal + * name, all of which, except for the internal name, CursorThemeModel + * supplies to item views. + * + * A cursor theme may also have a path to the directory where the theme + * is located in the filesystem. If isWritable() returns true, This directory + * may be deleted in order to remove the theme at the users request. + * + * Subclasses must reimplement loadImage() and loadCursor(), which are + * called by PreviewWidget to load cursors and cursor images. Subclasses may + * optionally reimplement loadPixmap(), which in the default implementation + * calls loadImage(), and converts the returned image to a pixmap. + * Subclasses may also reimplement the protected function createIcon(), + * which creates the icon pixmap that's supplied to item views. The default + * implementation calls loadImage() to load the sample cursor, and creates + * the icon from that. + */ +class CursorTheme +{ + public: + enum ItemDataRole { + // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) + // to define additional roles. + DisplayDetailRole = 0x24A3DAF8 + }; + + CursorTheme() {} + CursorTheme(const QString &title, const QString &description = QString()); + virtual ~CursorTheme() {} + + const QString title() const { return m_title; } + const QString description() const { return m_description; } + const QString sample() const { return m_sample; } + const QString name() const { return m_name; } + const QString path() const { return m_path; } + /** @returns A list of the available sizes in this cursor theme, + @warning This list may be empty if the engine doesn't support + the recognition of the size. */ + const QList availableSizes() const + { return m_availableSizes; } + bool isWritable() const { return m_writable; } + bool isHidden() const { return m_hidden; } + QPixmap icon() const; + + /// Hash value for the internal name + uint hash() const { return m_hash; } + + /// 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. + virtual QImage loadImage(const QString &name, int size = 0) const = 0; + + /// Convenience function. Default implementation calls + /// QPixmap::fromImage(loadImage()); + virtual QPixmap loadPixmap(const QString &name, int size = 0) const; + + /// 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. + virtual QCursor loadCursor(const QString &name, int size = 0) const = 0; + + /** Creates the icon returned by @ref icon(). Don't use this function + directly but use @ref icon() instead, because @ref icon() caches + the icon. + @returns A pixmap with a cursor (usually left_ptr) that can + be used as icon for this theme. The size is adopted to + standard icon sizes.*/ + virtual QPixmap createIcon() const; + /** @returns A pixmap with a cursor (usually left_ptr) that can + be used as icon for this theme. */ + virtual QPixmap createIcon(int size) const; + + protected: + void setTitle( const QString &title ) { m_title = title; } + void setDescription( const QString &desc ) { m_description = desc; } + void setSample( const QString &sample ) { m_sample = sample; } + inline void setName( const QString &name ); + void setPath( const QString &path ) { m_path = path; } + void setAvailableSizes( const QList &availableSizes ) + { m_availableSizes = availableSizes; } + void setIcon( const QPixmap &icon ) { m_icon = icon; } + void setIsWritable( bool val ) { m_writable = val; } + void setIsHidden( bool val ) { m_hidden = val; } + + /// Convenience function for cropping an image. + QImage autoCropImage( const QImage &image ) const; + + // Convenience function that uses Xfixes to tag a cursor with a name + void setCursorName(QCursor &cursor, const QString &name) const; + + QString m_title; + QString m_description; + QString m_path; + QList m_availableSizes; + QString m_sample; + mutable QPixmap m_icon; + bool m_writable:1; + bool m_hidden:1; + + private: + QString m_name; + uint m_hash; + + friend class CursorThemeModel; +}; + +void CursorTheme::setName(const QString &name) +{ + m_name = name; + m_hash = qHash(name); +} + +#endif // CURSORTHEME_H + diff --git a/kcontrol/input/xcursor/itemdelegate.cpp b/kcontrol/input/xcursor/itemdelegate.cpp new file mode 100644 index 00000000..e7370056 --- /dev/null +++ b/kcontrol/input/xcursor/itemdelegate.cpp @@ -0,0 +1,174 @@ +/* + * Copyright © 2006-2007 Fredrik Höglund + * + * 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. + */ + +#include "itemdelegate.h" +#include "cursortheme.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, CursorTheme::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(); + if (!secondRow.isEmpty()) { + textAreaHeight += 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/kcontrol/input/xcursor/itemdelegate.h b/kcontrol/input/xcursor/itemdelegate.h new file mode 100644 index 00000000..9acb0e97 --- /dev/null +++ b/kcontrol/input/xcursor/itemdelegate.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2006-2007 Fredrik Höglund + * + * 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. + */ + +#ifndef ITEMDELEGATE_H +#define ITEMDELEGATE_H + +#include + +class QPainter; + +class ItemDelegate : public QAbstractItemDelegate +{ + 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/kcontrol/input/xcursor/previewwidget.cpp b/kcontrol/input/xcursor/previewwidget.cpp new file mode 100644 index 00000000..aff149bc --- /dev/null +++ b/kcontrol/input/xcursor/previewwidget.cpp @@ -0,0 +1,229 @@ +/* + * Copyright © 2003-2007 Fredrik Höglund + * + * 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. + */ + +#include +#include + +#include "previewwidget.h" + +#include +#include + +#include "cursortheme.h" + + + +namespace { + + // Preview cursors + const char * const cursor_names[] = + { + "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 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 CursorTheme *theme, const QString &name, int size ); + ~PreviewCursor() {} + + const QPixmap &pixmap() const { return m_pixmap; } + Cursor handle() const { return m_cursor.handle(); } + int width() const { return m_pixmap.width(); } + int height() const { return m_pixmap.height(); } + inline QRect rect() const; + void setPosition( const QPoint &p ) { m_pos = p; } + void setPosition( int x, int y ) { m_pos = QPoint(x, y); } + QPoint position() const { return m_pos; } + operator const QCursor& () const { return m_cursor; } + operator const QPixmap& () const { return pixmap(); } + + private: + QPixmap m_pixmap; + QCursor m_cursor; + QPoint m_pos; +}; + + +PreviewCursor::PreviewCursor(const CursorTheme *theme, const QString &name, int size) +{ + // Create the preview pixmap + QImage image = theme->loadImage(name, size); + + if (image.isNull()) + return; + + m_pixmap = QPixmap::fromImage(image); + + // Load the cursor + m_cursor = theme->loadCursor(name, size); + // ### perhaps we should tag the cursor so it doesn't get + // replaced when a new theme is applied +} + + +QRect PreviewCursor::rect() const +{ + return QRect(m_pos, m_pixmap.size()) + .adjusted(-(cursorSpacing / 2), -(cursorSpacing / 2), + cursorSpacing / 2, cursorSpacing / 2); +} + + + +// ------------------------------------------------------------------------------ + + + +PreviewWidget::PreviewWidget(QWidget *parent) : QWidget(parent) +{ + setMouseTracking(true); + current = NULL; +} + + +PreviewWidget::~PreviewWidget() +{ + qDeleteAll(list); + list.clear(); +} + + +QSize PreviewWidget::sizeHint() const +{ + int totalWidth = 0; + int maxHeight = 0; + + foreach (const PreviewCursor *c, list) + { + totalWidth += c->width(); + maxHeight = qMax(c->height(), maxHeight); + } + + totalWidth += (list.count() - 1) * cursorSpacing; + maxHeight = qMax(maxHeight, widgetMinHeight); + + return QSize(qMax(totalWidth, widgetMinWidth), qMax(height(), maxHeight)); +} + + +void PreviewWidget::layoutItems() +{ + if (!list.isEmpty()) + { + QSize size = sizeHint(); + int cursorWidth = size.width() / list.count(); + int nextX = (width() - size.width()) / 2; + + foreach (PreviewCursor *c, list) + { + c->setPosition(nextX + (cursorWidth - c->width()) / 2, + (height() - c->height()) / 2); + nextX += cursorWidth; + } + } + + needLayout = false; +} + + +void PreviewWidget::setTheme(const CursorTheme *theme, const int size) +{ + qDeleteAll(list); + list.clear(); + + if (theme) + { + for (int i = 0; i < numCursors; i++) + list << new PreviewCursor(theme, cursor_names[i], size); + + needLayout = true; + updateGeometry(); + } + + current = NULL; + update(); +} + + +void PreviewWidget::paintEvent(QPaintEvent *) +{ + QPainter p(this); + + if (needLayout) + layoutItems(); + + foreach(const PreviewCursor *c, list) + { + if (c->pixmap().isNull()) + continue; + + p.drawPixmap(c->position(), *c); + } +} + + +void PreviewWidget::mouseMoveEvent(QMouseEvent *e) +{ + if (needLayout) + layoutItems(); + + foreach (const PreviewCursor *c, list) + { + if (c->rect().contains(e->pos())) + { + if (c != current) + { + setCursor(*c); + current = c; + } + return; + } + } + + setCursor(Qt::ArrowCursor); + current = NULL; +} + + +void PreviewWidget::resizeEvent(QResizeEvent *) +{ + if (!list.isEmpty()) + needLayout = true; +} + diff --git a/kcontrol/input/xcursor/previewwidget.h b/kcontrol/input/xcursor/previewwidget.h new file mode 100644 index 00000000..4a11e2d2 --- /dev/null +++ b/kcontrol/input/xcursor/previewwidget.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2003-2007 Fredrik Höglund + * + * 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. + */ + +#ifndef PREVIEWWIDGET_H +#define PREVIEWWIDGET_H + +#include + +class CursorTheme; +class PreviewCursor; + +class PreviewWidget : public QWidget +{ + public: + PreviewWidget(QWidget *parent); + ~PreviewWidget(); + + void setTheme(const CursorTheme *theme, const int size); + void setUseLables(bool); + QSize sizeHint() const; + + protected: + void paintEvent(QPaintEvent *); + void mouseMoveEvent(QMouseEvent *); + void resizeEvent(QResizeEvent *); + + private: + void layoutItems(); + + QList list; + const PreviewCursor *current; + bool needLayout:1; +}; + +#endif // PREVIEWWIDGET_H + diff --git a/kcontrol/input/xcursor/sortproxymodel.cpp b/kcontrol/input/xcursor/sortproxymodel.cpp new file mode 100644 index 00000000..b9d63092 --- /dev/null +++ b/kcontrol/input/xcursor/sortproxymodel.cpp @@ -0,0 +1,50 @@ +/* + * Copyright © 2006-2007 Fredrik Höglund + * + * 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. + */ + +#include +#include "sortproxymodel.h" +#include "cursortheme.h" + + +int SortProxyModel::compare(const QModelIndex &left, const QModelIndex &right, int role) const +{ + const QAbstractItemModel *model = sourceModel(); + + QString first = model->data(left, role).toString(); + QString second = model->data(right, role).toString(); + + if (filterCaseSensitivity() == Qt::CaseSensitive) + { + first = first.toLower(); + second = second.toLower(); + } + + return QString::localeAwareCompare(first, second); +} + + +bool SortProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + const int result = compare(left, right, Qt::DisplayRole); + + if (result != 0) + return (result < 0); + else + return compare(left, right, CursorTheme::DisplayDetailRole) < 0; +} diff --git a/kcontrol/input/xcursor/sortproxymodel.h b/kcontrol/input/xcursor/sortproxymodel.h new file mode 100644 index 00000000..95c9646c --- /dev/null +++ b/kcontrol/input/xcursor/sortproxymodel.h @@ -0,0 +1,77 @@ +/* + * Copyright © 2006-2007 Fredrik Höglund + * + * 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. + */ + +#ifndef SORTPROXYMODEL_H +#define SORTPROXYMODEL_H + +#include +#include + +/** + * SortProxyModel is a sorting proxy model intended to be used in combination + * with the ItemDelegate class. + * + * First it compares the Qt::DisplayRoles, and if they match it compares + * the CursorTheme::DisplayDetailRoles. + * + * The model assumes both display roles are QStrings. + */ +class SortProxyModel : public QSortFilterProxyModel +{ + public: + SortProxyModel(QObject *parent = 0) : QSortFilterProxyModel(parent) {} + ~SortProxyModel() {} + inline const CursorTheme *theme(const QModelIndex &index) const; + inline QModelIndex findIndex(const QString &name) const; + inline QModelIndex defaultIndex() const; + inline void removeTheme(const QModelIndex &index); + + private: + int compare(const QModelIndex &left, const QModelIndex &right, int role) const; + + protected: + bool lessThan(const QModelIndex &left, const QModelIndex &right) const; +}; + + +const CursorTheme *SortProxyModel::theme(const QModelIndex &index) const +{ + CursorThemeModel *model = static_cast(sourceModel()); + return model->theme(mapToSource(index)); +} + +QModelIndex SortProxyModel::findIndex(const QString &name) const +{ + CursorThemeModel *model = static_cast(sourceModel()); + return mapFromSource(model->findIndex(name)); +} + +QModelIndex SortProxyModel::defaultIndex() const +{ + CursorThemeModel *model = static_cast(sourceModel()); + return mapFromSource(model->defaultIndex()); +} + +void SortProxyModel::removeTheme(const QModelIndex &index) +{ + CursorThemeModel *model = static_cast(sourceModel()); + model->removeTheme(mapToSource(index)); +} + +#endif // SORTPROXYMODEL_H diff --git a/kcontrol/input/xcursor/thememodel.cpp b/kcontrol/input/xcursor/thememodel.cpp new file mode 100644 index 00000000..bb6effb9 --- /dev/null +++ b/kcontrol/input/xcursor/thememodel.cpp @@ -0,0 +1,413 @@ +/* + * Copyright © 2005-2007 Fredrik Höglund + * + * 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. + */ + + +#include +#include +#include +#include +#include + +#include "thememodel.h" +#include "thememodel.moc" +#include "xcursortheme.h" + +#include +#include + +// Check for older version +#if !defined(XCURSOR_LIB_MAJOR) && defined(XCURSOR_MAJOR) +# define XCURSOR_LIB_MAJOR XCURSOR_MAJOR +# define XCURSOR_LIB_MINOR XCURSOR_MINOR +#endif + + + +CursorThemeModel::CursorThemeModel(QObject *parent) + : QAbstractTableModel(parent) +{ + insertThemes(); +} + +CursorThemeModel::~CursorThemeModel() +{ + qDeleteAll(list); + list.clear(); +} + +void CursorThemeModel::refreshList() +{ + beginResetModel(); + qDeleteAll(list); + list.clear(); + endResetModel(); + insertThemes(); +} + +QVariant CursorThemeModel::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 i18n("Name"); + + case DescColumn: + return i18n("Description"); + + default: return QVariant(); + } + } + + // Numbered vertical header lables + return QString(section); +} + + +QVariant CursorThemeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= list.count()) + return QVariant(); + + const CursorTheme *theme = list.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 == CursorTheme::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 CursorThemeModel::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 CursorTheme *CursorThemeModel::theme(const QModelIndex &index) +{ + if (!index.isValid()) + return NULL; + + if (index.row() < 0 || index.row() >= list.count()) + return NULL; + + return list.at(index.row()); +} + + +QModelIndex CursorThemeModel::findIndex(const QString &name) +{ + uint hash = qHash(name); + + for (int i = 0; i < list.count(); i++) + { + const CursorTheme *theme = list.at(i); + if (theme->hash() == hash) + return index(i, 0); + } + + return QModelIndex(); +} + + +QModelIndex CursorThemeModel::defaultIndex() +{ + return findIndex(defaultName); +} + + +const QStringList CursorThemeModel::searchPaths() +{ + if (!baseDirs.isEmpty()) + return baseDirs; + +#if XCURSOR_LIB_MAJOR == 1 && XCURSOR_LIB_MINOR < 1 + // These are the default paths Xcursor will scan for cursor themes + QString path("~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons"); + + // If XCURSOR_PATH is set, use that instead of the default path + char *xcursorPath = std::getenv("XCURSOR_PATH"); + if (xcursorPath) + path = xcursorPath; +#else + // Get the search path from Xcursor + QString path = XcursorLibraryPath(); +#endif + + // Separate the paths + baseDirs = path.split(':', QString::SkipEmptyParts); + + // Remove duplicates + QMutableStringListIterator i(baseDirs); + 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 + baseDirs.replaceInStrings(QRegExp("^~\\/"), QDir::home().path() + '/'); + return baseDirs; +} + + +bool CursorThemeModel::hasTheme(const QString &name) const +{ + const uint hash = qHash(name); + + foreach (const CursorTheme *theme, list) + if (theme->hash() == hash) + return true; + + return false; +} + + +bool CursorThemeModel::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 + KConfig config(dir.path() + "/index.theme", KConfig::NoGlobals); + KConfigGroup cg(&config, "Icon Theme"); + + // Recurse through the list of inherited themes, to check if one of them + // is a cursor theme. + QStringList inherits = cg.readEntry("Inherits", QStringList()); + foreach (const QString &inherit, inherits) + { + // Avoid possible DoS + if (inherit == theme) + continue; + + if (isCursorTheme(inherit, depth + 1)) + return true; + } + } + + return false; +} + + +bool CursorThemeModel::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())) + defaultName = 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")) + { + XCursorTheme theme(themeDir); + if (!theme.inherits().isEmpty()) + defaultName = theme.inherits().at(0); + } + return true; + } + + defaultName = QLatin1String("default"); + return false; +} + + +void CursorThemeModel::processThemeDir(const QDir &themeDir) +{ + 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 (defaultName.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) + return; + + // Create a cursor theme object for the theme dir + XCursorTheme *theme = new XCursorTheme(themeDir); + + // Skip this theme if it's hidden. + if (theme->isHidden()) { + 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 + beginInsertRows(QModelIndex(), list.size(), list.size()); + list.append(theme); + endInsertRows(); +} + + +void CursorThemeModel::insertThemes() +{ + // Scan each base dir for Xcursor themes and add them to the list. + foreach (const QString &baseDir, searchPaths()) + { + QDir dir(baseDir); + if (!dir.exists()) + continue; + + // Process each subdir in the directory + foreach (const QString &name, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) + { + // 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) || !dir.cd(name)) + continue; + + processThemeDir(dir); + dir.cdUp(); // Return to the base dir + } + } + + // The theme Xcursor will end up using if no theme is configured + if (defaultName.isNull() || !hasTheme(defaultName)) + defaultName = QLatin1String("KDE_Classic"); +} + + +bool CursorThemeModel::addTheme(const QDir &dir) +{ + XCursorTheme *theme = new XCursorTheme(dir); + + // Don't add the theme to the list if it's hidden + if (theme->isHidden()) { + delete theme; + return false; + } + + // ### If the theme is hidden, the user will probably find it strange that it + // doesn't appear in the list view. There also won't be a way for the user + // to delete the theme using the KCM. Perhaps a warning about this should + // be issued, and the user be given a chance to undo the installation. + + // 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 < list.count(); i++) + { + if (list.at(i)->hash() == theme->hash()) { + removeTheme(index(i, 0)); + break; + } + } + + // Append the theme to the list + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + list.append(theme); + endInsertRows(); + + return true; +} + + +void CursorThemeModel::removeTheme(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + beginRemoveRows(QModelIndex(), index.row(), index.row()); + delete list.takeAt(index.row()); + endRemoveRows(); +} + diff --git a/kcontrol/input/xcursor/thememodel.h b/kcontrol/input/xcursor/thememodel.h new file mode 100644 index 00000000..bcf046a9 --- /dev/null +++ b/kcontrol/input/xcursor/thememodel.h @@ -0,0 +1,114 @@ +/* + * Copyright © 2005-2007 Fredrik Höglund + * + * 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. + */ + +#ifndef THEMEMODEL_H +#define THEMEMODEL_H + +#include +#include + +class QDir; +class CursorTheme; + +// The two TableView/TreeView columns provided by the model +enum Columns { NameColumn = 0, DescColumn }; + + +/** + * The CursorThemeModel 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 CursorThemeModel : public QAbstractTableModel +{ + Q_OBJECT + + public: + CursorThemeModel(QObject *parent = 0); + ~CursorThemeModel(); + 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 CursorTheme *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(); + + /// Refresh the list of themes by checking what's on disk. + void refreshList(); + + 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: + QList list; + QStringList baseDirs; + QString defaultName; +}; + +int CursorThemeModel::rowCount(const QModelIndex &) const +{ + return list.count(); +} + +int CursorThemeModel::columnCount(const QModelIndex &) const +{ + return 2; +} + +#endif // THEMEMODEL_H diff --git a/kcontrol/input/xcursor/themepage.cpp b/kcontrol/input/xcursor/themepage.cpp new file mode 100644 index 00000000..53880d5a --- /dev/null +++ b/kcontrol/input/xcursor/themepage.cpp @@ -0,0 +1,581 @@ +/* + * Copyright © 2003-2007 Fredrik Höglund + * + * 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. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +#include +#include "../../krdb/krdb.h" + +#include +#include +#include +#include + +#include "themepage.h" +#include "themepage.moc" + +#include "thememodel.h" +#include "itemdelegate.h" +#include "sortproxymodel.h" +#include "cursortheme.h" + +#include +#include + +#ifdef HAVE_XFIXES +# include +#endif + + +ThemePage::ThemePage(QWidget *parent) + : QWidget(parent) +{ + setupUi(this); + installKnsButton->setIcon(KIcon("get-hot-new-stuff")); + installButton->setIcon(KIcon("document-import")); + removeButton->setIcon(KIcon("edit-delete")); + + model = new CursorThemeModel(this); + + proxy = new SortProxyModel(this); + proxy->setSourceModel(model); + proxy->setFilterCaseSensitivity(Qt::CaseSensitive); + proxy->sort(NameColumn, Qt::AscendingOrder); + + // Get the icon size for QListView + int size = style()->pixelMetric(QStyle::PM_LargeIconSize); + + view->setModel(proxy); + view->setItemDelegate(new ItemDelegate(this)); + view->setIconSize(QSize(size, size)); + view->setSelectionMode(QAbstractItemView::SingleSelection); + + // Make sure we find out about selection changes + connect(view->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + SLOT(selectionChanged())); + + // Make sure we find out about size changes + connect(sizeComboBox, + SIGNAL(currentIndexChanged(int)), + SLOT(sizeChanged())); + + // Make sure we find out about user activity + connect(sizeComboBox, + SIGNAL(activated(int)), + SLOT(preferredSizeChanged())); + + // 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. + if (!model->searchPaths().contains(QDir::homePath() + "/.icons") || !iconsIsWritable()) { + installButton->setEnabled(false); + installKnsButton->setEnabled(false); + } + + connect(installKnsButton, SIGNAL(clicked()), SLOT(getNewClicked())); + connect(installButton, SIGNAL(clicked()), SLOT(installClicked())); + connect(removeButton, SIGNAL(clicked()), SLOT(removeClicked())); +} + + +ThemePage::~ThemePage() +{ +} + + +bool ThemePage::iconsIsWritable() const +{ + const QFileInfo icons = QFileInfo(QDir::homePath() + "/.icons"); + const QFileInfo home = QFileInfo(QDir::homePath()); + + return ((icons.exists() && icons.isDir() && icons.isWritable()) || + (!icons.exists() && home.isWritable())); +} + + +void ThemePage::updateSizeComboBox() +{ + // clear the combo box + sizeComboBox->clear(); + + // refill the combo box and adopt its icon size + QModelIndex selected = selectedIndex(); + int maxIconWidth = 0; + int maxIconHeight = 0; + if (selected.isValid()) + { + const CursorTheme *theme = proxy->theme(selected); + const QList sizes = theme->availableSizes(); + QIcon m_icon; + if (sizes.size() > 1) // only refill the combobox if there is more that 1 size + { + int i; + QList comboBoxList; + QPixmap m_pixmap; + + // insert the items + m_pixmap = theme->createIcon(0); + if (m_pixmap.width() > maxIconWidth) + maxIconWidth = m_pixmap.width(); + if (m_pixmap.height() > maxIconHeight) + maxIconHeight = m_pixmap.height(); + sizeComboBox->addItem( + QIcon(m_pixmap), + i18nc("@item:inlistbox size", "resolution dependent"), + 0); + comboBoxList << 0; + foreach (i, sizes) + { + m_pixmap = theme->createIcon(i); + if (m_pixmap.width() > maxIconWidth) + maxIconWidth = m_pixmap.width(); + if (m_pixmap.height() > maxIconHeight) + maxIconHeight = m_pixmap.height(); + sizeComboBox->addItem(QIcon(m_pixmap), QString::number(i), i); + comboBoxList << i; + }; + + // select an item + int selectItem = comboBoxList.indexOf(preferredSize); + if (selectItem < 0) // preferredSize not available for this theme + { + /* Search the value next to preferredSize. The first entry (0) + is ignored. (If preferredSize would have been 0, then we + would had found it yet. As preferredSize is not 0, we won't + default to "automatic size".)*/ + int j; + int distance; + int smallestDistance; + selectItem = 1; + j = comboBoxList.value(selectItem); + smallestDistance = j < preferredSize ? preferredSize - j : j - preferredSize; + for (int i = 2; i < comboBoxList.size(); ++i) + { + j = comboBoxList.value(i); + distance = j < preferredSize ? preferredSize - j : j - preferredSize; + if (distance < smallestDistance || (distance == smallestDistance && j > preferredSize)) + { + smallestDistance = distance; + selectItem = i; + }; + } + }; + sizeComboBox->setCurrentIndex(selectItem); + }; + }; + sizeComboBox->setIconSize(QSize(maxIconWidth, maxIconHeight)); + + // enable or disable the combobox + KConfig c("kcminputrc"); + KConfigGroup cg(&c, "Mouse"); + if (cg.isEntryImmutable("cursorSize")) { + sizeComboBox->setEnabled(false); + sizeLabel->setEnabled(false); + } else { + sizeComboBox->setEnabled(sizeComboBox->count() > 0); + sizeLabel->setEnabled(sizeComboBox->count() > 0); + }; +} + + +int ThemePage::selectedSize() const +{ + if (sizeComboBox->isEnabled() && sizeComboBox->currentIndex() >= 0) + return sizeComboBox->itemData(sizeComboBox->currentIndex(), Qt::UserRole).toInt(); + return 0; +} + + +void ThemePage::updatePreview() +{ + QModelIndex selected = selectedIndex(); + + if (selected.isValid()) { + const CursorTheme *theme = proxy->theme(selected); + preview->setTheme(theme, selectedSize()); + removeButton->setEnabled(theme->isWritable()); + } else { + preview->setTheme(NULL, 0); + removeButton->setEnabled(false); + }; +} + + +bool ThemePage::haveXfixes() +{ + bool result = false; + +#ifdef HAVE_XFIXES + int event_base, error_base; + if (XFixesQueryExtension(QX11Info::display(), &event_base, &error_base)) + { + int major, minor; + XFixesQueryVersion(QX11Info::display(), &major, &minor); + result = (major >= 2); + } +#endif + + return result; +} + + +bool ThemePage::applyTheme(const CursorTheme *theme, const int size) +{ + // 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 HAVE_XFIXES && XFIXES_MAJOR >= 2 && XCURSOR_LIB_VERSION >= 10105 + if (!theme) + return false; + + if (!haveXfixes()) + return false; + + QByteArray themeName = QFile::encodeName(theme->name()); + + // Set up the proper launch environment for newly started apps + KToolInvocation::klauncher()->setLaunchEnv("XCURSOR_THEME", themeName); + + // Update the Xcursor X resources + runRdb(0); + + // Notify all applications that the cursor theme has changed + KGlobalSettings::self()->emitChange(KGlobalSettings::CursorChanged); + + // 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" << "copy" << "move" << "link"; + + // 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"; + + foreach (const QString &name, names) + { + QCursor cursor = theme->loadCursor(name, size); + XFixesChangeCursorByName(x11Info().display(), cursor.handle(), QFile::encodeName(name)); + } + + return true; +#else + Q_UNUSED(theme) + return false; +#endif +} + + +void ThemePage::save() +{ + const CursorTheme *theme = selectedIndex().isValid() ? proxy->theme(selectedIndex()) : NULL; + const int size = selectedSize(); + + KConfig config("kcminputrc"); + KConfigGroup c(&config, "Mouse"); + if (theme) + { + c.writeEntry("cursorTheme", theme->name()); + }; + c.writeEntry("cursorSize", size); + preferredSize = size; + c.sync(); + + if (!applyTheme(theme, size)) + { + KMessageBox::information(this, + i18n("You have to restart KDE for these changes to take effect."), + i18n("Cursor Settings Changed"), "CursorSettingsChanged"); + } + + appliedIndex = selectedIndex(); + appliedSize = size; +} + + +void ThemePage::load() +{ + view->selectionModel()->clear(); + // Get the name of the theme libXcursor currently uses + QString currentTheme = XcursorGetTheme(x11Info().display()); + + // Get the name of the theme KDE is configured to use + KConfig c("kcminputrc"); + KConfigGroup cg(&c, "Mouse"); + currentTheme = cg.readEntry("cursorTheme", currentTheme); + + // Find the theme in the listview + if (!currentTheme.isEmpty()) + appliedIndex = proxy->findIndex(currentTheme); + else + appliedIndex = proxy->defaultIndex(); + + // Disable the listview and the buttons if we're in kiosk mode + if (cg.isEntryImmutable("cursorTheme")) + { + view->setEnabled(false); + installButton->setEnabled(false); + removeButton->setEnabled(false); + } + + // Load cursor size + int size = cg.readEntry("cursorSize", 0); + if (size <= 0) + preferredSize = 0; + else + preferredSize = size; + updateSizeComboBox(); // This handles also the kiosk mode + + appliedSize = size; + + const CursorTheme *theme = proxy->theme(appliedIndex); + + if (appliedIndex.isValid()) + { + // Select the current theme + view->setCurrentIndex(appliedIndex); + view->scrollTo(appliedIndex, QListView::PositionAtCenter); + + // Update the preview widget as well + preview->setTheme(theme, size); + } + + if (!theme || !theme->isWritable()) + removeButton->setEnabled(false); +} + + +void ThemePage::defaults() +{ + view->selectionModel()->clear(); + QModelIndex defaultIndex = proxy->findIndex("Oxygen_Black"); + view->setCurrentIndex(defaultIndex); + preferredSize = 0; + updateSizeComboBox(); +} + + +void ThemePage::selectionChanged() +{ + updateSizeComboBox(); + updatePreview(); + + emit changed(appliedIndex != selectedIndex()); +} + +QModelIndex ThemePage::selectedIndex() const +{ + QModelIndexList selection = view->selectionModel()->selectedIndexes(); + if (!selection.isEmpty()) { + return (selection.at(0)); + } + return QModelIndex(); +} + +void ThemePage::sizeChanged() +{ + updatePreview(); + emit changed(selectedSize() != appliedSize); +} + +void ThemePage::preferredSizeChanged() +{ + int index = sizeComboBox->currentIndex(); + if (index >= 0) + preferredSize = sizeComboBox->itemData(index, Qt::UserRole).toInt(); + else + preferredSize = 0; +} + +void ThemePage::getNewClicked() +{ + KNS3::DownloadDialog dialog("xcursor.knsrc", this); + if (dialog.exec()) { + KNS3::Entry::List list = dialog.changedEntries(); + if (list.count() > 0) + model->refreshList(); + } +} + +void ThemePage::installClicked() +{ + // Get the URL for the theme we're going to install + KUrl url = KUrlRequesterDialog::getUrl(QString(), this, i18n("Drag or Type Theme URL")); + + if (url.isEmpty()) + return; + + QString tempFile; + if (!KIO::NetAccess::download(url, tempFile, this)) + { + QString text; + + if (url.isLocalFile()) + text = i18n("Unable to find the cursor theme archive %1.", + url.prettyUrl()); + else + text = i18n("Unable to download the cursor theme archive; " + "please check that the address %1 is correct.", + url.prettyUrl()); + + KMessageBox::sorry(this, text); + return; + } + + if (!installThemes(tempFile)) + KMessageBox::error(this, i18n("The file %1 does not appear to be a valid " + "cursor theme archive.", url.fileName())); + + KIO::NetAccess::removeTempFile(tempFile); +} + + +void ThemePage::removeClicked() +{ + // We don't have to check if the current index is valid, since + // the remove button will be disabled when there's no selection. + const CursorTheme *theme = proxy->theme(selectedIndex()); + + // Don't let the user delete the currently configured theme + if (selectedIndex() == appliedIndex) { + KMessageBox::sorry(this, i18n("You cannot delete the theme you are currently " + "using.
You have to switch to another theme first.
")); + return; + } + + // Get confirmation from the user + QString question = i18n("Are you sure you want to remove the " + "%1 cursor theme?
" + "This will delete all the files installed by this theme.
", + theme->title()); + + int answer = KMessageBox::warningContinueCancel(this, question, + i18n("Confirmation"), KStandardGuiItem::del()); + + if (answer != KMessageBox::Continue) + return; + + // Delete the theme from the harddrive + KIO::del(KUrl(theme->path())); // async + + // Remove the theme from the model + proxy->removeTheme(selectedIndex()); + + // TODO: + // Since it's possible to substitute cursors in a system theme by adding a local + // theme with the same name, we shouldn't remove the theme from the list if it's + // still available elsewhere. We could add a + // bool CursorThemeModel::tryAddTheme(const QString &name), and call that, but + // since KIO::del() is an asynchronos operation, the theme we're deleting will be + // readded to the list again before KIO has removed it. +} + + +bool ThemePage::installThemes(const QString &file) +{ + KTar archive(file); + + if (!archive.open(QIODevice::ReadOnly)) + return false; + + const KArchiveDirectory *archiveDir = archive.directory(); + QStringList themeDirs; + + // Extract the dir names of the cursor themes in the archive, and + // append them to themeDirs + foreach(const QString &name, archiveDir->entries()) + { + const KArchiveEntry *entry = archiveDir->entry(name); + if (entry->isDirectory() && entry->name().toLower() != "default") + { + const KArchiveDirectory *dir = static_cast(entry); + if (dir->entry("index.theme") && dir->entry("cursors")) + themeDirs << dir->name(); + } + } + + if (themeDirs.isEmpty()) + return false; + + // The directory we'll install the themes to + QString destDir = QDir::homePath() + "/.icons/"; + KStandardDirs::makeDir(destDir); // Make sure the directory exists + + // Process each cursor theme in the archive + foreach (const QString &dirName, themeDirs) + { + QDir dest(destDir + dirName); + if (dest.exists()) + { + QString question = i18n("A theme named %1 already exists in your icon " + "theme folder. Do you want replace it with this one?", dirName); + + int answer = KMessageBox::warningContinueCancel(this, question, + i18n("Overwrite Theme?"), + KStandardGuiItem::overwrite()); + + if (answer != KMessageBox::Continue) + continue; + + // ### If the theme that's being replaced is the current theme, it + // will cause cursor inconsistencies in newly started apps. + } + + // ### Should we check if a theme with the same name exists in a global theme dir? + // If that's the case it will effectively replace it, even though the global theme + // won't be deleted. Checking for this situation is easy, since the global theme + // will be in the listview. Maybe this should never be allowed since it might + // result in strange side effects (from the average users point of view). OTOH + // a user might want to do this 'upgrade' a global theme. + + const KArchiveDirectory *dir = static_cast + (archiveDir->entry(dirName)); + dir->copyTo(dest.path()); + model->addTheme(dest); + } + + archive.close(); + return true; +} + diff --git a/kcontrol/input/xcursor/themepage.h b/kcontrol/input/xcursor/themepage.h new file mode 100644 index 00000000..3b21dd9d --- /dev/null +++ b/kcontrol/input/xcursor/themepage.h @@ -0,0 +1,99 @@ +/* + * Copyright © 2003-2007 Fredrik Höglund + * + * 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. + */ + +#ifndef THEMEPAGE_H +#define THEMEPAGE_H + +#include +#include + +#include "ui_themepage.h" + +class CursorThemeModel; +class SortProxyModel; +class CursorTheme; + +class ThemePage : public QWidget, private Ui::ThemePage +{ + Q_OBJECT + + public: + ThemePage(QWidget* parent = 0); + ~ThemePage(); + + // Called by the KCM + void save(); + void load(); + void defaults(); + + static bool haveXfixes(); + + signals: + void changed(bool); + + private slots: + void selectionChanged(); + /** Updates the preview. If the size has changed, it also emits changed() */ + void sizeChanged(); + /** Sets #preferredSize to the item that is currently selected in sizeComboBox. + If none is selected, it is set to 0. */ + void preferredSizeChanged(); + /** Updates the size combo box. It loads the size list of the selected cursor + theme with the corresponding icons and chooses an appropriate entry. It + enables the combo box and the label if the theme provides more than one + size, otherwise it disables it. If the size setting is looked in kiosk + mode, it stays always disabled. */ + void updateSizeComboBox(); + void getNewClicked(); + void installClicked(); + void removeClicked(); + + private: + /** @returns 0 if in the UI "automatic size" is selected, otherwise + returns the custom size. */ + int selectedSize() const; + /** Holds the last size that was choosen by the user. Example: The user chooses + theme1 which provides the sizes 24 and 36. He chooses 36. preferredSize gets + set to 36. Now, he switchs to theme2 which provides the sizes 30 and 40. + preferredSize still is 36, so the UI will default to 40, which is next to 36. + Now, he chooses theme3 which provides the sizes 34 and 44. preferredSize is + still 36, so the UI defaults to 34. Now the user changes manually to 44. This + will also change preferredSize. */ + int preferredSize; + void updatePreview(); + QModelIndex selectedIndex() const; + bool installThemes(const QString &file); + /** Applies a given theme, using XFixes, XCursor and KGlobalSettings. + @param theme The cursor theme to be applied. It is save to pass 0 here + (will result in \e false as return value). + @param size The size hint that is used to select the cursor size. + @returns If the changes could be applied. Will return \e false if \e theme is + 0 or if the XFixes and XCursor libraries aren't available in the required + version, otherwise returns \e true. */ + bool applyTheme(const CursorTheme *theme, const int size); + bool iconsIsWritable() const; + + CursorThemeModel *model; + SortProxyModel *proxy; + + int appliedSize; + // This index refers to the CursorThemeModel, not the proxy or the view + QPersistentModelIndex appliedIndex; +}; + +#endif // THEMEPAGE_H diff --git a/kcontrol/input/xcursor/themepage.ui b/kcontrol/input/xcursor/themepage.ui new file mode 100644 index 00000000..be736638 --- /dev/null +++ b/kcontrol/input/xcursor/themepage.ui @@ -0,0 +1,120 @@ + + + ThemePage + + + + 0 + 0 + 541 + 360 + + + + + + + Select the cursor theme you want to use (hover preview to test cursor): + + + + + + + + 0 + 0 + + + + + 0 + 48 + + + + + + + + + 0 + 1 + + + + true + + + QAbstractItemView::ScrollPerPixel + + + + + + + Get new color schemes from the Internet + + + Get New Theme... + + + + + + + Install From File... + + + + + + + Remove Theme + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToMinimumContentsLengthWithIcon + + + + 0 + 0 + + + + + + + + Size: + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+ + PreviewWidget + QWidget +
previewwidget.h
+ 1 +
+
+ + +
diff --git a/kcontrol/input/xcursor/xcursor.knsrc b/kcontrol/input/xcursor/xcursor.knsrc new file mode 100644 index 00000000..27f5b765 --- /dev/null +++ b/kcontrol/input/xcursor/xcursor.knsrc @@ -0,0 +1,6 @@ +[KNewStuff3] +ProvidersUrl=http://download.kde.org/ocs/providers.xml +Categories=X11 Mouse Theme +InstallPath=.icons +Uncompress=archive + diff --git a/kcontrol/input/xcursor/xcursortheme.cpp b/kcontrol/input/xcursor/xcursortheme.cpp new file mode 100644 index 00000000..7f6ae00b --- /dev/null +++ b/kcontrol/input/xcursor/xcursortheme.cpp @@ -0,0 +1,231 @@ +/* + * Copyright © 2006-2007 Fredrik Höglund + * + * 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. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "xcursortheme.h" + + +// Static variable holding alternative names for some cursors +QHash XCursorTheme::alternatives; + +XCursorTheme::XCursorTheme(const QDir &themeDir) + : CursorTheme(themeDir.dirName()) +{ + // Directory information + setName(themeDir.dirName()); + setPath(themeDir.path()); + setIsWritable(QFileInfo(themeDir.path()).isWritable()); // ### perhaps this shouldn't be cached + + if (themeDir.exists("index.theme")) + parseIndexFile(); + + QString cursorFile = path() + "/cursors/left_ptr"; + QList sizeList; + XcursorImages *images = XcursorFilenameLoadAllImages(qPrintable(cursorFile)); + if (images) + { + for (int i = 0; i < images->nimage; ++i) + { + if (!sizeList.contains(images->images[i]->size)) + sizeList.append(images->images[i]->size); + }; + XcursorImagesDestroy(images); + qSort(sizeList.begin(), sizeList.end()); + m_availableSizes = sizeList; + }; + if (!sizeList.isEmpty()) + { + QString sizeListString = QString::number(sizeList.takeFirst()); + while (!sizeList.isEmpty()) + { + sizeListString.append(", "); + sizeListString.append(QString::number(sizeList.takeFirst())); + }; + QString tempString = i18nc( + "@info/plain The argument is the list of available sizes (in pixel). Example: " + "'Available sizes: 24' or 'Available sizes: 24, 36, 48'", + "(Available sizes: %1)", + sizeListString); + if (m_description.isEmpty()) + m_description = tempString; + else + m_description = m_description + ' ' + tempString; + }; +} + + +void XCursorTheme::parseIndexFile() +{ + KConfig config(path() + "/index.theme", KConfig::NoGlobals); + KConfigGroup cg(&config, "Icon Theme"); + + m_title = cg.readEntry("Name", m_title); + m_description = cg.readEntry("Comment", m_description); + m_sample = cg.readEntry("Example", m_sample); + m_hidden = cg.readEntry("Hidden", false); + m_inherits = cg.readEntry("Inherits", QStringList()); +} + + +QString XCursorTheme::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", "fcf1c3c7cd4491d801f1e1c78f100000"); + alternatives.insert("size_fdiag", "c7088f0f3e6c8088236ef8e1e3e70000"); + 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()); +} + + +XcursorImage *XCursorTheme::xcLoadImage(const QString &image, int size) const +{ + QByteArray cursorName = QFile::encodeName(image); + QByteArray themeName = QFile::encodeName(name()); + + return XcursorLibraryLoadImage(cursorName, themeName, size); +} + + +XcursorImages *XCursorTheme::xcLoadImages(const QString &image, int size) const +{ + QByteArray cursorName = QFile::encodeName(image); + QByteArray themeName = QFile::encodeName(name()); + + return XcursorLibraryLoadImages(cursorName, themeName, size); +} + + +int XCursorTheme::autodetectCursorSize() const +{ + /* This code is basically borrowed from display.c of the XCursor library + We can't use "int XcursorGetDefaultSize(Display *dpy)" because if + previously the cursor size was set to a custom value, it would return + this custom value. */ + int size = 0; + int dpi = 0; + Display *dpy = QX11Info::display(); + // The string "v" is owned and will be destroyed by Xlib + char *v = XGetDefault(dpy, "Xft", "dpi"); + if (v) + dpi = atoi(v); + if (dpi) + size = dpi * 16 / 72; + if (size == 0) + { + int dim; + if (DisplayHeight(dpy, DefaultScreen(dpy)) < + DisplayWidth(dpy, DefaultScreen(dpy))) + { + dim = DisplayHeight(dpy, DefaultScreen(dpy)); + } else { + dim = DisplayWidth(dpy, DefaultScreen(dpy)); + }; + size = dim / 48; + } + return size; +} + + +QCursor XCursorTheme::loadCursor(const QString &name, int size) const +{ + if (size <= 0) + size = autodetectCursorSize(); + + // Load the cursor images + XcursorImages *images = xcLoadImages(name, size); + + if (!images) + images = xcLoadImages(findAlternative(name), size); + + if (!images) + return QCursor(); + + // Create the cursor + Cursor handle = XcursorImagesLoadCursor(QX11Info::display(), images); + QCursor cursor = QCursor(Qt::HANDLE(handle)); // QCursor takes ownership of the handle + XcursorImagesDestroy(images); + + setCursorName(cursor, name); + return cursor; +} + + +QImage XCursorTheme::loadImage(const QString &name, int size) const +{ + if (size <= 0) + size = autodetectCursorSize(); + + // Load the image + XcursorImage *xcimage = xcLoadImage(name, size); + + if (!xcimage) + xcimage = xcLoadImage(findAlternative(name), size); + + 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; +} + diff --git a/kcontrol/input/xcursor/xcursortheme.h b/kcontrol/input/xcursor/xcursortheme.h new file mode 100644 index 00000000..310dd55a --- /dev/null +++ b/kcontrol/input/xcursor/xcursortheme.h @@ -0,0 +1,71 @@ +/* + * Copyright © 2006-2007 Fredrik Höglund + * + * 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. + */ + +#ifndef XCURSORTHEME_H +#define XCURSORTHEME_H + +#include + +#include "cursortheme.h" + +class QDir; + +struct _XcursorImage; +struct _XcursorImages; + +typedef _XcursorImage XcursorImage; +typedef _XcursorImages XcursorImages; + +/** + * The XCursorTheme class is a CursorTheme implementation for Xcursor themes. + */ +class XCursorTheme : public CursorTheme +{ + public: + /** + * Initializes itself from the @p dir information, and parses the + * index.theme file if the dir has one. + */ + XCursorTheme(const QDir &dir); + virtual ~XCursorTheme() {} + + const QStringList inherits() const { return m_inherits; } + QImage loadImage(const QString &name, int size = 0) const; + QCursor loadCursor(const QString &name, int size = 0) const; + + protected: + XCursorTheme(const QString &title, const QString &desc) + : CursorTheme(title, desc) {} + void setInherits(const QStringList &val) { m_inherits = val; } + + private: + XcursorImage *xcLoadImage(const QString &name, int size) const; + XcursorImages *xcLoadImages(const QString &name, int size) const; + void parseIndexFile(); + QString findAlternative(const QString &name) const; + /** Returns the size that the XCursor library would use if no + cursor size is given. This depends mainly on Xft.dpi. */ + int autodetectCursorSize() const; + + QStringList m_inherits; + static QHash alternatives; +}; + +#endif // XCURSORTHEME_H + diff --git a/kcontrol/keyboard/CMakeLists.txt b/kcontrol/keyboard/CMakeLists.txt new file mode 100644 index 00000000..973a39d4 --- /dev/null +++ b/kcontrol/keyboard/CMakeLists.txt @@ -0,0 +1,146 @@ +SET(CMAKE_REQUIRED_LIBRARIES -lXi) +CHECK_FUNCTION_EXISTS(_XiGetDevicePresenceNotifyEvent XiGetDevicePresenceNotifyEvent_EXISTS) + +if( X11_Xinput_FOUND AND XiGetDevicePresenceNotifyEvent_EXISTS ) + set(XiGetDevicePresence_FOUND 1) + ADD_DEFINITIONS(-DHAVE_XINPUT_AND_DEVICE_NOTIFY=1) +else( X11_Xinput_FOUND AND XiGetDevicePresenceNotifyEvent_EXISTS ) + MESSAGE(STATUS "_XiGetDevicePresenceNotifyEvent is not found, libXi version 1.2.0 or later is required to keep layouts with keyboard hotplugging") +endif( X11_Xinput_FOUND AND XiGetDevicePresenceNotifyEvent_EXISTS ) + +set ( text_paint_LIB ${KDE4_PLASMA_LIBS} ) + + + +### kded daemon ### + +set( kded_keyboard_SRCS + keyboard_daemon.cpp + layout_memory.cpp + layout_memory_persister.cpp + x11_helper.cpp + xinput_helper.cpp + xkb_helper.cpp + keyboard_config.cpp + keyboard_hardware.cpp + numlockx.c + bindings.cpp +# next are temporary for sys tray UI + layout_tray_icon.cpp + layouts_menu.cpp + flags.cpp + xkb_rules.cpp +) + +kde4_add_plugin(kded_keyboard ${kded_keyboard_SRCS}) + +target_link_libraries(kded_keyboard + ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES} + ${text_paint_LIB} + ${QT_QTXML_LIBRARY} ${X11_Xkbfile_LIB} + ) + +if(X11_XTest_FOUND) + target_link_libraries(kded_keyboard ${X11_XTest_LIB}) +endif(X11_XTest_FOUND) + +if(XiGetDevicePresence_FOUND) + target_link_libraries(kded_keyboard ${X11_Xinput_LIB}) +endif(XiGetDevicePresence_FOUND) + +install( TARGETS kded_keyboard DESTINATION ${PLUGIN_INSTALL_DIR} ) +install( FILES keyboard.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded ) + + +### plasma applet ### + +set( plasma_applet_keyboard_SRCS + keyboard_applet.cpp + flags.cpp + keyboard_config.cpp + xkb_rules.cpp + x11_helper.cpp + xkb_helper.cpp + layouts_menu.cpp +) + +kde4_add_plugin(plasma_applet_keyboard ${plasma_applet_keyboard_SRCS}) + +target_link_libraries(plasma_applet_keyboard + ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS} ${QT_QTXML_LIBRARY} ${X11_Xkbfile_LIB} ${X11_LIBRARIES} + ${text_paint_LIB} +) + +install( TARGETS plasma_applet_keyboard DESTINATION ${PLUGIN_INSTALL_DIR} ) +install( FILES plasma_applet_keyboard.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + + +### widget lib ### + +set( keyboard_layout_widget_SRCS + layout_widget.cpp + keyboard_config.cpp + flags.cpp + x11_helper.cpp + xkb_helper.cpp +) + +# MODULE? +kde4_add_plugin(keyboard_layout_widget ${keyboard_layout_widget_SRCS}) + +target_link_libraries(keyboard_layout_widget + ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES} + ${text_paint_LIB} + ${QT_QTXML_LIBRARY} ${X11_Xkbfile_LIB} +) + +install( TARGETS keyboard_layout_widget DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +### kcm keyboard ### +include_directories("preview") + +set(kcm_keyboard_PART_SRCS + kcm_keyboard.cpp + kcm_keyboard_widget.cpp + kcm_view_models.cpp + kcm_add_layout_dialog.cpp + keyboard_config.cpp + x11_helper.cpp + xkb_helper.cpp + xkb_rules.cpp + flags.cpp + iso_codes.cpp + kcmmisc.cpp + bindings.cpp + preview/keyaliases.cpp + preview/keyboardlayout.cpp + preview/keyboardpainter.cpp + preview/keysymbols.cpp + preview/keysymhelper.cpp + preview/kbpreviewframe.cpp + preview/keysym2ucs.cpp +) + + +kde4_add_ui_files(kcm_keyboard_PART_SRCS kcm_keyboard.ui kcm_add_layout_dialog.ui kcmmiscwidget.ui) + +kde4_add_plugin(kcm_keyboard ${kcm_keyboard_PART_SRCS}) + +target_link_libraries(kcm_keyboard + ${KDE4_KIO_LIBS} ${X11_Xkbfile_LIB} ${X11_LIBRARIES} + ${text_paint_LIB} +) + +install(TARGETS kcm_keyboard DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install( FILES kcm_keyboard.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + +# Images + +add_subdirectory( pics ) + + +# Unit tests + +add_subdirectory( tests ) diff --git a/kcontrol/keyboard/Messages.sh b/kcontrol/keyboard/Messages.sh new file mode 100755 index 00000000..8d527522 --- /dev/null +++ b/kcontrol/keyboard/Messages.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env bash +$EXTRACTRC kcm*.ui >> rc.cpp +$XGETTEXT rc.cpp kcmmisc.cpp preview/*.cpp -o $podir/kcmkeyboard.pot +$XGETTEXT kcm_*.cpp keyboard_*.cpp layout_*.cpp flags.cpp layouts_menu.cpp bindings.cpp -o $podir/kxkb.pot +rm -f rc.cpp diff --git a/kcontrol/keyboard/README b/kcontrol/keyboard/README new file mode 100644 index 00000000..25c50b47 --- /dev/null +++ b/kcontrol/keyboard/README @@ -0,0 +1,44 @@ +This is new project to replace keyboard (kcmmisc) and kxkb +to manage keyboard harware configuration and layouts. + +Components: + +kcm_init: +* no kcm_init - all initialization (including after keyboard hot-plug) is done by kded daemon + +Keyboard daemon: +* configures keyboard layouts on start +* provides DBUS API "org.kde.KXKB/kxkb" +* listens to window/desktop switching if layout switch mode is not global +* listens to new keyboard devices and reinitializes keyboard layouts and hardware settings +* listens to Global KDE Shortcut to switch layouts +* listens to Global Shortcut settings change +* listens to keyboard configuration changes +* provides systray icon for layout + +Keyboard applet: +* displays current layout with text and (optionally flag) +* allows to toggle layouts by click or set them with context menu + +Layout widget: +* displays current layout with text embedded in another widget (e.g. lock dialog) +* currently only short text (no flag or long text) +* dynamically loaded as a plugin + +KCM Module: +* allows to configure keyboard hardware, layouts and xkb options (advanced) + +Advantages (over old code): +* One UI module to configure keyboard layouts and hardware +* Allows to configure keyboard model/xkb options without configuring layouts +* Less cluttered layout configuration control (add layout is separate) +* Layout control/DBus interface is separate from the indicator +* Does not require libxklvier +* Takes language names from iso-codes project +* Takes country names/translations from xkeyboard-config project +* Information about current layouts is always taken from X server, so should be more robust +* Cleaner code (rewritten from scratch) +* Due to many points above should start faster (though no benchmarks performed) + +New features: +* Allow selection of keyboard layout by language diff --git a/kcontrol/keyboard/TODO b/kcontrol/keyboard/TODO new file mode 100644 index 00000000..2e58efb2 --- /dev/null +++ b/kcontrol/keyboard/TODO @@ -0,0 +1,37 @@ +Tests: +* tests + +Core: +* better handling when layouts set manually and not present in config + +KCM UI: +* use listboxes instead of combos in add layout dialog +* allow multiple layouts to be added in same dialog? + +KCM UI cleanup: +* layouts, sizes, alignment etc in kcm + +plasma applet: + +kxkb part: +* tooltip (currently does not work in lockdlg for some reason) + +tray icon: + +Code cleanup: +* rules, iso_codes: + better error handling + +Improvement: +* remove XInput libs from plasma applet and layout widget (find a nicer way) +* optimize fetching groups and layouts (cache them) / fetch current group directly +* refactor/optimize/clean the code +* refactor client code for D-BUS API to use library instead? + +External improvements: +* Add KSharedConfig::configChanged() signal +* make iso-codes external package +* make flags external package + +Documentation: +* update documentation for keyboard module diff --git a/kcontrol/keyboard/bindings.cpp b/kcontrol/keyboard/bindings.cpp new file mode 100644 index 00000000..1e5cbe87 --- /dev/null +++ b/kcontrol/keyboard/bindings.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "bindings.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "x11_helper.h" +#include "flags.h" + + +static const char* actionName = I18N_NOOP("Switch to Next Keyboard Layout"); +static const char* COMPONENT_NAME = I18N_NOOP("KDE Keyboard Layout Switcher"); + + +KeyboardLayoutActionCollection::KeyboardLayoutActionCollection(QObject* parent, bool configAction_): + KActionCollection(parent, KComponentData(KAboutData(COMPONENT_NAME, 0, ki18n(COMPONENT_NAME), 0))), + configAction(configAction_) +{ + KAction* toggleAction = addAction( actionName ); + toggleAction->setText( i18n(actionName) ); + toggleAction->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::Key_K)); + if( configAction ) { + toggleAction->setProperty("isConfigurationAction", true); + } + kDebug() << "Keyboard layout toggle shortcut" << toggleAction->globalShortcut().toString(); +} + +KeyboardLayoutActionCollection::~KeyboardLayoutActionCollection() +{ + clear(); +} + +KAction* KeyboardLayoutActionCollection::getToggeAction() +{ + return static_cast(action(0)); +} + +KAction* KeyboardLayoutActionCollection::createLayoutShortcutActon(const LayoutUnit& layoutUnit, const Rules* rules, bool autoload) +{ + QString longLayoutName = Flags::getLongText( layoutUnit, rules ); + QString actionName = "Switch keyboard layout to "; + actionName += longLayoutName; + KAction* action = addAction( actionName ); + action->setText( i18n("Switch keyboard layout to %1", longLayoutName) ); + KAction::GlobalShortcutLoading loading = autoload ? KAction::Autoloading : KAction::NoAutoloading; + KShortcut shortcut = autoload ? KShortcut() : KShortcut(layoutUnit.getShortcut()); + action->setGlobalShortcut(shortcut, KAction::ShortcutTypes(KAction::ActiveShortcut /*| KAction::DefaultShortcut*/), loading); + action->setData(layoutUnit.toString()); + if( configAction ) { + action->setProperty("isConfigurationAction", true); + } + kDebug() << "Registered layout shortcut" << action->globalShortcut(KAction::ActiveShortcut).primary().toString() << "for" << action->text() << "lu.shortcut" << layoutUnit.getShortcut().toString(); + return action; +} + +void KeyboardLayoutActionCollection::setToggleShortcut(const QKeySequence& keySequence) +{ + KShortcut shortcut(keySequence); + getToggeAction()->setGlobalShortcut(shortcut, KAction::ActiveShortcut, KAction::NoAutoloading); + kDebug() << "Saving keyboard layout KDE shortcut" << shortcut.toString(); +} + +//KAction* KeyboardLayoutActionCollection::setShortcut(LayoutUnit& layoutUnit, const QKeySequence& keySequence, const Rules* rules) +//{ +// KAction* action = getAction(layoutUnit); +// if( action == NULL && ! keySequence.isEmpty() ) { +// action = createLayoutShortcutActon(layoutUnit, rules, false); +// } +// else if( action != NULL && keySequence.isEmpty() ){ +//// action->setGlobalShortcut(KShortcut(keySequence), KAction::ActiveShortcut, KAction::NoAutoloading); // do we need this? +// removeAction(action); +// action = NULL; +// } +//// if( configAction ) { +//// layoutUnit.setShortcut(keySequence); // shortcut was restored +//// } +// return action; +//} + +void KeyboardLayoutActionCollection::setLayoutShortcuts(QList& layoutUnits, const Rules* rules) +{ + for (QList::iterator i = layoutUnits.begin(); i != layoutUnits.end(); ++i) { + LayoutUnit& layoutUnit = *i; + if( ! layoutUnit.getShortcut().isEmpty() ) { + createLayoutShortcutActon(layoutUnit, rules, false); + } + } + kDebug() << "Cleaning component shortcuts on save" << KGlobalAccel::cleanComponent(COMPONENT_NAME); +} + +void KeyboardLayoutActionCollection::loadLayoutShortcuts(QList& layoutUnits, const Rules* rules) +{ + for (QList::iterator i = layoutUnits.begin(); i != layoutUnits.end(); ++i) { + LayoutUnit& layoutUnit = *i; + KAction* action = createLayoutShortcutActon(layoutUnit, rules, true); + QKeySequence shortcut = action->globalShortcut(KAction::ActiveShortcut).primary(); // shortcut was restored + if( ! shortcut.isEmpty() ) { + kDebug() << "Restored shortcut for" << layoutUnit.toString() << shortcut; + layoutUnit.setShortcut(shortcut); + } + else { + kDebug() << "Skipping empty shortcut for" << layoutUnit.toString(); + removeAction(action); + } + } + kDebug() << "Cleaning component shortcuts on load" << KGlobalAccel::cleanComponent(COMPONENT_NAME); +} + +//KAction* KeyboardLayoutActionCollection::getAction(const LayoutUnit& layoutUnit) +//{ +// for(int i=1; idata() == layoutUnit.toString() ) +// return static_cast(action(i)); +// } +// return NULL; +//} + +void KeyboardLayoutActionCollection::resetLayoutShortcuts() +{ + for(int i=1; i(action(i))->setGlobalShortcut(KShortcut(), KAction::ShortcutTypes(KAction::ActiveShortcut | KAction::DefaultShortcut), KAction::NoAutoloading); + } +} diff --git a/kcontrol/keyboard/bindings.h b/kcontrol/keyboard/bindings.h new file mode 100644 index 00000000..09a9bdc7 --- /dev/null +++ b/kcontrol/keyboard/bindings.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 BINDINGS_H_ +#define BINDINGS_H_ + +#include + + +//class QObject; +class KAction; +class Rules; +class LayoutUnit; +template class QList; + + +class KeyboardLayoutActionCollection : public KActionCollection { +public: + KeyboardLayoutActionCollection(QObject* parent, bool configAction); + virtual ~KeyboardLayoutActionCollection(); + + KAction* getToggeAction(); +// KAction* getAction(const LayoutUnit& layoutUnit); + KAction* createLayoutShortcutActon(const LayoutUnit& layoutUnit, const Rules* rules, bool autoload); +// KAction* setShortcut(LayoutUnit& layoutUnit, const QKeySequence& keySequence, const Rules* rules); + void setLayoutShortcuts(QList& layoutUnits, const Rules* rules); + void setToggleShortcut(const QKeySequence& keySequence); + void loadLayoutShortcuts(QList& layoutUnits, const Rules* rules); + void resetLayoutShortcuts(); + +private: + bool configAction; +}; + +//KActionCollection* createGlobalActionCollection(QObject *parent, KAction** mainAction); +//KAction* createLayoutShortcutActon(KActionCollection* actionCollection, const LayoutUnit& layoutUnit, const Rules* rules); + +#endif /* BINDINGS_H_ */ diff --git a/kcontrol/keyboard/flags.cpp b/kcontrol/keyboard/flags.cpp new file mode 100644 index 00000000..582e376d --- /dev/null +++ b/kcontrol/keyboard/flags.cpp @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "flags.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "x11_helper.h" + +//for text handling +#include "keyboard_config.h" +#include "xkb_rules.h" + + +static const int FLAG_MAX_WIDTH = 21; +static const int FLAG_MAX_HEIGHT = 14; +static const char flagTemplate[] = "l10n/%1/flag.png"; + +Flags::Flags(): + svg(NULL) +{ + transparentPixmap = new QPixmap(FLAG_MAX_WIDTH, FLAG_MAX_HEIGHT); + transparentPixmap->fill(Qt::transparent); +} + +Flags::~Flags() +{ + if( svg != NULL ) { + disconnect(svg, SIGNAL(repaintNeeded()), this, SLOT(themeChanged())); + delete svg; + } + delete transparentPixmap; +} + +const QIcon Flags::getIcon(const QString& layout) +{ + if( ! iconMap.contains(layout) ) { + iconMap[ layout ] = createIcon(layout); + } + return iconMap[ layout ]; +} + +QIcon Flags::createIcon(const QString& layout) +{ + QIcon icon; + if( ! layout.isEmpty() ) { + if( layout == "epo" ) { + QString file = KStandardDirs::locate("data", "kcmkeyboard/pics/epo.png"); + icon.addFile(file); + } + else { + QString countryCode = getCountryFromLayoutName( layout ); + if( ! countryCode.isEmpty() ) { + QString file = KStandardDirs::locate("locale", QString(flagTemplate).arg(countryCode)); + // kDebug() << "Creating icon for" << layout << "with" << file; + icon.addFile(file); + } + } + } + return icon; +} + + +//static +//const QStringList NON_COUNTRY_LAYOUTS = QString("ara,brai,epo,latam,mao").split(","); + +QString Flags::getCountryFromLayoutName(const QString& layout) const +{ + QString countryCode = layout; + + if( countryCode == "nec_vndr/jp" ) + return "jp"; + +// if( NON_COUNTRY_LAYOUTS.contain(layout) ) + if( countryCode.length() > 2 ) + return ""; + + return countryCode; +} + +//TODO: move this to some other class? + +QString Flags::getShortText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) +{ + if( layoutUnit.isEmpty() ) + return QString("--"); + + QString layoutText = layoutUnit.layout; + + foreach(const LayoutUnit& lu, keyboardConfig.layouts) { + if( layoutUnit.layout == lu.layout && layoutUnit.variant == lu.variant ) { + layoutText = lu.getDisplayName(); + break; + } + } + +//TODO: good autolabel +// if( layoutText == layoutUnit.layout && layoutUnit.getDisplayName() != layoutUnit.layout ) { +// layoutText = layoutUnit.getDisplayName(); +// } + + return layoutText; +} + +QString Flags::getFullText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig, const Rules* rules) +{ + QString shortText = Flags::getShortText(layoutUnit, keyboardConfig); + QString longText = Flags::getLongText(layoutUnit, rules); + return i18nc("short layout label - full layout name", "%1 - %2", shortText, longText); +} + +static QString getDisplayText(const QString& layout, const QString& variant, const Rules* rules) +{ + if( variant.isEmpty() ) + return layout; + if( rules == NULL || rules->version == "1.0" ) + return i18nc("layout - variant", "%1 - %2", layout, variant); + return variant; +} + +QString Flags::getLongText(const LayoutUnit& layoutUnit, const Rules* rules) +{ + if( rules == NULL ) { + return getDisplayText(layoutUnit.layout, layoutUnit.variant, rules); + } + + QString layoutText = layoutUnit.layout; + const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); + if( layoutInfo != NULL ) { + layoutText = layoutInfo->description; + + if( ! layoutUnit.variant.isEmpty() ) { + const VariantInfo* variantInfo = layoutInfo->getVariantInfo(layoutUnit.variant); + QString variantText = variantInfo != NULL ? variantInfo->description : layoutUnit.variant; + + layoutText = getDisplayText(layoutText, variantText, rules); + } + } + + return layoutText; +} + +static +QString getPixmapKey(const KeyboardConfig& keyboardConfig) +{ + switch(keyboardConfig.indicatorType) { + case KeyboardConfig::SHOW_FLAG: + return "_fl"; + case KeyboardConfig::SHOW_LABEL_ON_FLAG: + return "_bt"; + case KeyboardConfig::SHOW_LABEL: + return "_lb"; + } + return "_"; // should not happen +} + +void Flags::drawLabel(QPainter& painter, const QString& layoutText, bool flagShown) +{ + QFont font = painter.font(); + + QRect rect = painter.window(); +// int fontSize = layoutText.length() == 2 +// ? height * 7 / 10 +// : height * 5 / 10; + + int fontSize = rect.height();// * 7 /10; + + font.setPixelSize(fontSize); + font.setWeight(QFont::DemiBold); + + QFontMetrics fm = painter.fontMetrics(); + int width = fm.width(layoutText); + + if( width > rect.width() * 2 / 3 ) { + fontSize = round( (double)fontSize * ((double)rect.width()*2/3) / width ); + } + + int smallestReadableSize = KGlobalSettings::smallestReadableFont().pixelSize(); + if( fontSize < smallestReadableSize ) { + fontSize = smallestReadableSize; + } + font.setPixelSize(fontSize); + +#ifdef DONT_USE_PLASMA + painter.setFont(font); + painter.setPen(Qt::white); + painter.drawText(QRect(rect).adust(1,1,0,0), Qt::AlignCenter | Qt::AlignHCenter, layoutText); + painter.setPen(Qt::black); + painter.drawText(rect, Qt::AlignCenter | Qt::AlignHCenter, layoutText); +#else + // we init svg so that we get notification about theme change + getSvg(); + + QColor textColor = flagShown ? Qt::black : Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); + QColor shadowColor = flagShown ? Qt::white : Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor); + QPoint offset = QPoint(0, 0); + + // QPixmap pixmap = Plasma::PaintUtils::texturedText(layoutText, font, svg); + QPixmap labelPixmap = Plasma::PaintUtils::shadowText(layoutText, font, textColor, shadowColor, offset, 3); + + int y = round((rect.height() - labelPixmap.height()) / 2.0); + int x = round((rect.width() - labelPixmap.width()) / 2.0); + painter.drawPixmap(QPoint(x, y), labelPixmap); +#endif +} + +const QIcon Flags::getIconWithText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) +{ + QString keySuffix(getPixmapKey(keyboardConfig)); + QString key(layoutUnit.toString() + keySuffix); + if( iconOrTextMap.contains(key) ) { + return iconOrTextMap[ key ]; + } + + if( keyboardConfig.indicatorType == KeyboardConfig::SHOW_FLAG ) { + QIcon icon = getIcon(layoutUnit.layout); + if( ! icon.isNull() ) { + iconOrTextMap[ key ] = icon; + return icon; + } + } + + QString layoutText = Flags::getShortText(layoutUnit, keyboardConfig); + + const QSize TRAY_ICON_SIZE(21, 14); + QPixmap pixmap = QPixmap(TRAY_ICON_SIZE); + pixmap.fill(Qt::transparent); + + QPainter painter(&pixmap); +// p.setRenderHint(QPainter::SmoothPixmapTransform); +// p.setRenderHint(QPainter::Antialiasing); + + if( keyboardConfig.indicatorType == KeyboardConfig::SHOW_LABEL_ON_FLAG ) { + QIcon iconf = createIcon(layoutUnit.layout); + iconf.paint(&painter, painter.window(), Qt::AlignCenter); + } + + drawLabel(painter, layoutText, keyboardConfig.isFlagShown()); + + painter.end(); + + QIcon icon(pixmap); + iconOrTextMap[ key ] = icon; + + return icon; +} + +Plasma::Svg* Flags::getSvg() +{ + if( svg == NULL ) { + svg = new Plasma::Svg; + svg->setImagePath("widgets/labeltexture"); + svg->setContainsMultipleImages(true); + connect(svg, SIGNAL(repaintNeeded()), this, SLOT(themeChanged())); + } + return svg; +} + +void Flags::themeChanged() +{ +// kDebug() << "Theme changed, new text color" << Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); + clearCache(); + emit pixmapChanged(); +} + +void Flags::clearCache() +{ +// kDebug() << "Clearing flag pixmap cache"; + iconOrTextMap.clear(); +} diff --git a/kcontrol/keyboard/flags.h b/kcontrol/keyboard/flags.h new file mode 100644 index 00000000..06ec831b --- /dev/null +++ b/kcontrol/keyboard/flags.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 FLAGS_H_ +#define FLAGS_H_ + +#include +#include +#include + +class QPixmap; +class QIcon; +class LayoutUnit; +class KeyboardConfig; +class Rules; +class QPainter; +namespace Plasma { + class Svg; +} + +class Flags : public QObject +{ + Q_OBJECT + +public: + Flags(); + virtual ~Flags(); + + const QIcon getIcon(const QString& layout); + const QIcon getIconWithText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig); + const QPixmap& getTransparentPixmap() const { return *transparentPixmap; } + + static QString getLongText(const LayoutUnit& layoutUnit, const Rules* rules); + static QString getShortText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig); + static QString getFullText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig, const Rules* rules); + +public Q_SLOTS: + void themeChanged(); + void clearCache(); + +Q_SIGNALS: + void pixmapChanged(); + +private: + QIcon createIcon(const QString& layout); + QString getCountryFromLayoutName(const QString& fullLayoutName) const; + void drawLabel(QPainter& painter, const QString& layoutText, bool flagShown); + Plasma::Svg* getSvg(); + + QMap iconMap; + QMap iconOrTextMap; + QPixmap* transparentPixmap; + Plasma::Svg* svg; +}; + +#endif /* FLAGS_H_ */ diff --git a/kcontrol/keyboard/iso_codes.cpp b/kcontrol/keyboard/iso_codes.cpp new file mode 100644 index 00000000..0ffbbd92 --- /dev/null +++ b/kcontrol/keyboard/iso_codes.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "iso_codes.h" + +#include +#include +#include + +#include + + +class IsoCodesPrivate { +public: + IsoCodesPrivate(const QString& isoCode_, const QString& isoCodesXmlDir_): + isoCode(isoCode_), + isoCodesXmlDir(isoCodesXmlDir_), + loaded(false) + {} + void buildIsoEntryList(); + + const QString isoCode; + const QString isoCodesXmlDir; + QList isoEntryList; + bool loaded; +}; + +class XmlHandler : public QXmlDefaultHandler +{ +public: + XmlHandler(const QString& isoCode_, QList& isoEntryList_): + isoCode(isoCode_), + qName("iso_"+isoCode+"_entry"), + isoEntryList(isoEntryList_) {} + + bool startElement(const QString &namespaceURI, const QString &localName, + const QString &qName, const QXmlAttributes &attributes); +// bool fatalError(const QXmlParseException &exception); +// QString errorString() const; + +private: + const QString isoCode; + const QString qName; + QList& isoEntryList; +}; + +bool XmlHandler::startElement(const QString &/*namespaceURI*/, const QString &/*localName*/, + const QString &qName, const QXmlAttributes &attributes) +{ + if( qName == this->qName ) { + IsoCodeEntry entry; + for(int i=0; iinsertCatalog(QString("iso_")+d->isoCode); +} + +IsoCodes::~IsoCodes() +{ + KGlobal::locale()->removeCatalog(QString("iso_")+d->isoCode); + delete d; +} + +QList IsoCodes::getEntryList() +{ + if( ! d->loaded ) { + d->buildIsoEntryList(); + } + return d->isoEntryList; +} + +//const char* IsoCodes::iso_639="639"; +const char* IsoCodes::iso_639_3="639_3"; +const char* IsoCodes::attr_name="name"; +//const char* IsoCodes::attr_iso_639_2B_code="iso_639_2B_code"; +//const char* IsoCodes::attr_iso_639_2T_code="iso_639_2T_code"; +//const char* IsoCodes::attr_iso_639_1_code="iso_639_1_code"; +const char* IsoCodes::attr_iso_639_3_id="id"; + +const IsoCodeEntry* IsoCodes::getEntry(const QString& attributeName, const QString& attributeValue) +{ + if( ! d->loaded ) { + d->buildIsoEntryList(); + } + for(QList::Iterator it = d->isoEntryList.begin(); it != d->isoEntryList.end(); ++it) { + const IsoCodeEntry* isoCodeEntry = &(*it); + if( isoCodeEntry->value(attributeName) == attributeValue ) + return isoCodeEntry; + } + return NULL; +} + +void IsoCodesPrivate::buildIsoEntryList() +{ + loaded = true; + + QFile file(QString("%1/iso_%2.xml").arg(isoCodesXmlDir, isoCode)); + if( !file.open(QFile::ReadOnly | QFile::Text) ) { + kError() << "Can't open the xml file" << file.fileName(); + return; + } + + XmlHandler xmlHandler(isoCode, isoEntryList); + + QXmlSimpleReader reader; + reader.setContentHandler(&xmlHandler); + reader.setErrorHandler(&xmlHandler); + + QXmlInputSource xmlInputSource(&file); + + if( ! reader.parse(xmlInputSource) ) { + kError() << "Failed to parse the xml file" << file.fileName(); + return; + } + + kDebug() << "Loaded" << isoEntryList.count() << ("iso entry definitions for iso"+isoCode) << "from" << file.fileName(); +} diff --git a/kcontrol/keyboard/iso_codes.h b/kcontrol/keyboard/iso_codes.h new file mode 100644 index 00000000..6a337392 --- /dev/null +++ b/kcontrol/keyboard/iso_codes.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 ISO_CODES_H_ +#define ISO_CODES_H_ + +#include +#include +#include + + +/** + * Represents an item for iso-* standards which consists of attributes and their values + */ +struct IsoCodeEntry: public QMap +{ +}; + +class IsoCodesPrivate; + +/** + * Represents a set of codes for iso-* standards. + * Uses iso-codes project to read and localize the values. + */ +class IsoCodes +{ +public: +// static const char* iso_639; + static const char* iso_639_3; + + static const char* attr_name; +// static const char* attr_iso_639_2B_code; +// static const char* attr_iso_639_2T_code; +// static const char* attr_iso_639_1_code; + static const char* attr_iso_639_3_id; + + /** + * @param isoCode Code for iso standard, i.e. "639", for convenience there's iso_* constants defined + */ + explicit IsoCodes(const QString& isoCode, const QString& isoCodesXmlDir="/usr/share/xml/iso-codes"); + ~IsoCodes(); + + /** + * @return Returns the list of items for this iso-* standard + */ + QList getEntryList(); + /** + * @return Returns the item for which given attribute has specified value + */ + const IsoCodeEntry* getEntry(const QString& attributeName, const QString& attributeValue); + +private: + IsoCodesPrivate* const d; +}; + +#endif /* ISO_CODES_H_ */ diff --git a/kcontrol/keyboard/kcm_add_layout_dialog.cpp b/kcontrol/keyboard/kcm_add_layout_dialog.cpp new file mode 100644 index 00000000..444da8ea --- /dev/null +++ b/kcontrol/keyboard/kcm_add_layout_dialog.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "kcm_add_layout_dialog.h" +#include +#include + +#include "xkb_rules.h" +#include "flags.h" +#include "iso_codes.h" + +#include "ui_kcm_add_layout_dialog.h" + + +AddLayoutDialog::AddLayoutDialog(const Rules* rules_, Flags* flags_, bool showLabel, QWidget* parent): + QDialog(parent), + rules(rules_), + flags(flags_), + selectedLanguage("no_language") +{ + layoutDialogUi = new Ui_AddLayoutDialog(); + layoutDialogUi->setupUi(this); + + QSet languages; + foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { + QSet langs = QSet::fromList(layoutInfo->languages); + languages.unite( langs ); + } + IsoCodes isoCodes(IsoCodes::iso_639_3); + foreach(const QString& lang, languages) { + const IsoCodeEntry* isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_3_id, lang); +// const IsoCodeEntry* isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_2B_code, lang); +// if( isoCodeEntry == NULL ) { +// isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_2T_code, lang); +// } + QString name = isoCodeEntry != NULL ? i18n(isoCodeEntry->value(IsoCodes::attr_name).toUtf8()) : lang; + layoutDialogUi->languageComboBox->addItem(name, lang); + } + layoutDialogUi->languageComboBox->model()->sort(0); + layoutDialogUi->languageComboBox->insertItem(0, i18n("Any language"), ""); + layoutDialogUi->languageComboBox->setCurrentIndex(0); + + if( showLabel ) { + layoutDialogUi->labelEdit->setMaxLength(LayoutUnit::MAX_LABEL_LENGTH); + } + else { + layoutDialogUi->labelLabel->setVisible(false); + layoutDialogUi->labelEdit->setVisible(false); + } + + languageChanged(0); + connect(layoutDialogUi->languageComboBox, SIGNAL(activated(int)), this, SLOT(languageChanged(int))); + connect(layoutDialogUi->layoutComboBox, SIGNAL(activated(int)), this, SLOT(layoutChanged(int))); + connect(layoutDialogUi->prevbutton,SIGNAL(clicked()),this,SLOT(preview())); +} + +void AddLayoutDialog::languageChanged(int langIdx) +{ + QString lang = layoutDialogUi->languageComboBox->itemData(langIdx).toString(); + if( lang == selectedLanguage ) + return; + + QPixmap emptyPixmap(layoutDialogUi->layoutComboBox->iconSize()); + emptyPixmap.fill(Qt::transparent); + + layoutDialogUi->layoutComboBox->clear(); + int defaultIndex = -1; + int i = 0; + foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { + if( lang.isEmpty() || layoutInfo->isLanguageSupportedByLayout(lang) ) { + if( flags ) { + QIcon icon(flags->getIcon(layoutInfo->name)); + if( icon.isNull() ) { + icon = QIcon(emptyPixmap); // align text with no icons + } + layoutDialogUi->layoutComboBox->addItem(icon, layoutInfo->description, layoutInfo->name); + } + else { + layoutDialogUi->layoutComboBox->addItem(layoutInfo->description, layoutInfo->name); + } + + // try to guess best default layout selection for given language + if( ! lang.isEmpty() && defaultIndex == -1 && layoutInfo->isLanguageSupportedByDefaultVariant(lang) ) { + defaultIndex = i; + } + i++; + } + } + if( defaultIndex == -1 ) { + defaultIndex = 0; + } + + layoutDialogUi->layoutComboBox->model()->sort(0); + layoutDialogUi->layoutComboBox->setCurrentIndex(defaultIndex); + layoutChanged(defaultIndex); + + selectedLanguage = lang; +} + +void AddLayoutDialog::layoutChanged(int layoutIdx) +{ + QString layoutName = layoutDialogUi->layoutComboBox->itemData(layoutIdx).toString(); + if( layoutName == selectedLayout ) + return; + + QString lang = layoutDialogUi->languageComboBox->itemData(layoutDialogUi->languageComboBox->currentIndex()).toString(); + + layoutDialogUi->variantComboBox->clear(); + const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutName); + foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { + if( lang.isEmpty() || layoutInfo->isLanguageSupportedByVariant(variantInfo, lang) ) { + layoutDialogUi->variantComboBox->addItem(variantInfo->description, variantInfo->name); + } + } + + layoutDialogUi->variantComboBox->model()->sort(0); + + if( lang.isEmpty() || layoutInfo->isLanguageSupportedByDefaultVariant(lang) ) { + layoutDialogUi->variantComboBox->insertItem(0, i18nc("variant", "Default"), ""); + } + layoutDialogUi->variantComboBox->setCurrentIndex(0); + + layoutDialogUi->labelEdit->setText(layoutName); + + selectedLayout = layoutName; +} + +void AddLayoutDialog::accept() +{ + selectedLayoutUnit.layout = layoutDialogUi->layoutComboBox->itemData(layoutDialogUi->layoutComboBox->currentIndex()).toString(); + selectedLayoutUnit.variant = layoutDialogUi->variantComboBox->itemData(layoutDialogUi->variantComboBox->currentIndex()).toString(); + QString label = layoutDialogUi->labelEdit->text(); + if( label == selectedLayoutUnit.layout ) { + label = ""; + } + selectedLayoutUnit.setDisplayName( label ); + selectedLayoutUnit.setShortcut(layoutDialogUi->kkeysequencewidget->keySequence()); + QDialog::accept(); +} + + +void AddLayoutDialog::preview(){ + int index = layoutDialogUi->variantComboBox->currentIndex(); + QString variant = layoutDialogUi->variantComboBox->itemData(index).toString(); + KeyboardPainter* layoutPreview = new KeyboardPainter(); + layoutPreview->generateKeyboardLayout(selectedLayout, variant); + layoutPreview->setModal(true); + layoutPreview->exec(); + delete layoutPreview; +} diff --git a/kcontrol/keyboard/kcm_add_layout_dialog.h b/kcontrol/keyboard/kcm_add_layout_dialog.h new file mode 100644 index 00000000..5273347d --- /dev/null +++ b/kcontrol/keyboard/kcm_add_layout_dialog.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KCM_ADD_LAYOUT_DIALOG_H_ +#define KCM_ADD_LAYOUT_DIALOG_H_ + +#include + +#include "keyboard_config.h" +#include "preview/keyboardpainter.h" + +class Rules; +class Flags; +class Ui_AddLayoutDialog; + +class AddLayoutDialog: public QDialog +{ + Q_OBJECT + +public: + AddLayoutDialog(const Rules* rules, Flags* flags, bool showLabel, QWidget* parent=NULL); + + LayoutUnit getSelectedLayoutUnit() { return selectedLayoutUnit; } + QString getvariant(QString variant); + void accept(); + +public Q_SLOTS: + void languageChanged(int langIdx); + void layoutChanged(int layoutIdx); + void preview(); + +private: + const Rules* rules; + Flags* flags; + Ui_AddLayoutDialog* layoutDialogUi; + QString selectedLanguage; + QString selectedLayout; + LayoutUnit selectedLayoutUnit; +}; + + +#endif /* KCM_ADD_LAYOUT_DIALOG_H_ */ diff --git a/kcontrol/keyboard/kcm_add_layout_dialog.ui b/kcontrol/keyboard/kcm_add_layout_dialog.ui new file mode 100644 index 00000000..78304fbc --- /dev/null +++ b/kcontrol/keyboard/kcm_add_layout_dialog.ui @@ -0,0 +1,149 @@ + + + AddLayoutDialog + + + + 0 + 0 + 525 + 270 + + + + Add Layout + + + + + + + 0 + 0 + + + + + + + + Layout: + + + + + + + + 0 + 0 + + + + + + + + Shortcut: + + + + + + + Variant: + + + + + + + + + + Label: + + + + + + + Limit selection by language: + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + Preview + + + + + + + + KKeySequenceWidget + QWidget +
kkeysequencewidget.h
+
+
+ + + + buttonBox + accepted() + AddLayoutDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AddLayoutDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/kcontrol/keyboard/kcm_keyboard.cpp b/kcontrol/keyboard/kcm_keyboard.cpp new file mode 100644 index 00000000..da75d28b --- /dev/null +++ b/kcontrol/keyboard/kcm_keyboard.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "kcm_keyboard.h" + +#include +#include +#include +#include + +#include +#include +//#include + +#include "kcm_keyboard_widget.h" +#include "x11_helper.h" +#include "keyboard_config.h" +#include "xkb_rules.h" +#include "keyboard_dbus.h" + +#include "xkb_helper.h" + +//temp hack +#include "kcmmisc.h" + + +K_PLUGIN_FACTORY(KeyboardModuleFactory, registerPlugin();) +K_EXPORT_PLUGIN(KeyboardModuleFactory("kcmkeyboard")) + +KCMKeyboard::KCMKeyboard(QWidget *parent, const QVariantList &args) + : KCModule(KeyboardModuleFactory::componentData(), parent/*, name*/) +{ + KGlobal::locale()->insertCatalog("kxkb"); + KGlobal::locale()->insertCatalog("kcmmisc"); + + KAboutData *about = + new KAboutData("kcmkeyboard", 0, ki18n("KDE Keyboard Control Module"), + 0, KLocalizedString(), KAboutData::License_GPL, + ki18n("(c) 2010 Andriy Rysin")); + + setAboutData( about ); + setQuickHelp( i18n("

Keyboard

This control module can be used to configure keyboard" + " parameters and layouts.")); + + + rules = Rules::readRules(Rules::READ_EXTRAS); + + keyboardConfig = new KeyboardConfig(); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(KDialog::spacingHint()); + + widget = new KCMKeyboardWidget(rules, keyboardConfig, componentData(), args, parent); + layout->addWidget(widget); + + connect(widget, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); + + setButtons(Help|Default|Apply); +} + +KCMKeyboard::~KCMKeyboard() +{ + delete keyboardConfig; + delete rules; +} + +void KCMKeyboard::defaults() +{ + keyboardConfig->setDefaults(); + widget->updateUI(); + widget->getKcmMiscWidget()->defaults(); + emit changed(true); +} + +void KCMKeyboard::load() +{ + keyboardConfig->load(); + widget->updateUI(); + widget->getKcmMiscWidget()->load(); +} + +//static void initializeKeyboardSettings(); +void KCMKeyboard::save() +{ + keyboardConfig->save(); + widget->save(); + widget->getKcmMiscWidget()->save(); + + QDBusMessage message = QDBusMessage::createSignal(KEYBOARD_DBUS_OBJECT_PATH, KEYBOARD_DBUS_SERVICE_NAME, KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE); + QDBusConnection::sessionBus().send(message); +} diff --git a/kcontrol/keyboard/kcm_keyboard.desktop b/kcontrol/keyboard/kcm_keyboard.desktop new file mode 100644 index 00000000..258cc28f --- /dev/null +++ b/kcontrol/keyboard/kcm_keyboard.desktop @@ -0,0 +1,238 @@ +[Desktop Entry] +Exec=kcmshell4 kcm_keyboard +Icon=preferences-desktop-keyboard +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/keyboard/index.html +Categories=Qt;KDE;X-KDE-settings-hardware; + +X-KDE-Library=kcm_keyboard +X-KDE-Init-Symbol=keyboard +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=input-devices +X-KDE-Weight=50 +OnlyShowIn=KDE; + +Name=Keyboard +Name[af]=Sleutelbord +Name[ar]=لوحة المفاتيح +Name[ast]=Tecláu +Name[be]=Клавіятура +Name[be@latin]=Klavijatura +Name[bg]=Клавиатура +Name[bn]=কীবোর্ড +Name[bn_IN]=কি-বোর্ড +Name[br]=Stokellaoueg +Name[bs]=Tastatura +Name[ca]=Teclat +Name[ca@valencia]=Teclat +Name[cs]=Klávesnice +Name[csb]=Klawiatura +Name[cy]=Bysellfwrdd +Name[da]=Tastatur +Name[de]=Tastatur +Name[el]=Πληκτρολόγιο +Name[en_GB]=Keyboard +Name[eo]=Klavaro +Name[es]=Teclado +Name[et]=Klaviatuur +Name[eu]=Teklatua +Name[fa]=صفحه کلید +Name[fi]=Näppäimistö +Name[fr]=Clavier +Name[fy]=Toetseboerd +Name[ga]=Méarchlár +Name[gl]=Teclado +Name[gu]=કીબોર્ડ +Name[he]=מקלדת +Name[hi]=कुंजीपट +Name[hne]=कुंजीपट +Name[hr]=Tipkovnica +Name[hsb]=Tastatura +Name[hu]=Billentyűzet +Name[ia]=Claviero +Name[id]=Papan Ketik +Name[is]=Lyklaborð +Name[it]=Tastiera +Name[ja]=キーボード +Name[ka]=კლავიატურა +Name[kk]=Перенетақта +Name[km]=ក្ដារ​ចុច +Name[kn]=ಕೀಲಿಮಣೆ +Name[ko]=키보드 +Name[ku]=Klavye +Name[lt]=Klaviatūra +Name[lv]=Tastatūra +Name[mai]=कुँजीपटल +Name[mk]=Тастатура +Name[ml]=കീബോര്‍ഡ് +Name[mr]=कळफलक +Name[nb]=Tastatur +Name[nds]=Tastatuur +Name[ne]=कुञ्जीपाटी +Name[nl]=Toetsenbord +Name[nn]=Tastatur +Name[oc]=Clavièr +Name[or]=କିବୋର୍ଡ଼ +Name[pa]=ਕੀਬੋਰਡ +Name[pl]=Klawiatura +Name[pt]=Teclado +Name[pt_BR]=Teclado +Name[ro]=Tastatură +Name[ru]=Клавиатура +Name[se]=Boallobeavdi +Name[si]=යතුරුපුවරුව +Name[sk]=Klávesnica +Name[sl]=Tipkovnica +Name[sr]=Тастатура +Name[sr@ijekavian]=Тастатура +Name[sr@ijekavianlatin]=Tastatura +Name[sr@latin]=Tastatura +Name[sv]=Tangentbord +Name[ta]=விசைப்பலகை +Name[te]=కీబోర్డ్ +Name[tg]=Клавиатура +Name[th]=แป้นพิมพ์ +Name[tr]=Klavye +Name[ug]=ھەرپتاختا +Name[uk]=Клавіатура +Name[uz]=Tugmatag +Name[uz@cyrillic]=Тугматаг +Name[vi]=Bàn phím +Name[wa]=Taprece +Name[xh]=Ibhodi enezitshixo +Name[x-test]=xxKeyboardxx +Name[zh_CN]=键盘 +Name[zh_TW]=鍵盤 + +Comment=Keyboard settings +Comment[af]=Sleutelbord instellings +Comment[ar]=إعدادات لوحة المفاتيح +Comment[ast]=Preferencies del tecláu +Comment[be]=Настаўленні клавіятуры +Comment[be@latin]=Nałady klavijatury +Comment[bg]=Настройки на клавиатура +Comment[bn]=কীবোর্ড সেটিংস +Comment[bn_IN]=কি-বোর্ড সংক্রান্ত বৈশিষ্ট্য +Comment[br]=Kefluniañ ar stokellaoueg +Comment[bs]=Postavke tastature +Comment[ca]=Arranjament del teclat +Comment[ca@valencia]=Arranjament del teclat +Comment[cs]=Nastavení klávesnice +Comment[csb]=Nastôw klawiaturë +Comment[cy]=Gosodiadau Bysellfwrdd +Comment[da]=Tastaturindstillinger +Comment[de]=Einstellung der Tastatur +Comment[el]=Ρυθμίσεις πληκτρολογίου +Comment[en_GB]=Keyboard settings +Comment[eo]=Agordo de la klavaro +Comment[es]=Preferencias del teclado +Comment[et]=Klaviatuuri seadistused +Comment[eu]=Teklatuaren ezarpenak +Comment[fa]=تنظیمات صفحه کلید +Comment[fi]=Näppäimistön asetukset +Comment[fy]=Toetseboerd ynstelle +Comment[ga]=Socruithe Méarchláir +Comment[gl]=Configuración do teclado +Comment[gu]=કીબોર્ડ ગોઠવણીઓ +Comment[he]=הגדרות המקלדת +Comment[hi]=कुंजीपट विन्यास +Comment[hne]=कुंजीपट सेटिंग +Comment[hr]=Postavke tipkovnice +Comment[hsb]=Nastajenja za tastaturu +Comment[hu]=A billentyűzet beállításai +Comment[ia]=Preferentias de claviero +Comment[id]=Pengaturan Papan Ketik +Comment[is]=Stillingar lyklaborðs +Comment[ka]=კლავიატურის კონფიგურაცია +Comment[kk]=Перенетақтаны баптау +Comment[km]=ការ​កំណត់​ក្ដារចុច +Comment[kn]=ಕೀಲಿಮಣೆ ಸಂಯೋಜನೆಗಳು +Comment[ko]=키보드 설정 +Comment[ku]=Mîhengên Klavyeyê +Comment[lt]=Klaviatūros parametrai +Comment[lv]=Tastatūras parametri +Comment[mai]=कुंजीपट बिन्यास +Comment[mk]=Поставувања на тастатурата +Comment[ml]=കീബോര്‍ഡിന്റെ സജ്ജീകരണങ്ങള്‍ +Comment[mr]=कळफलक संयोजना +Comment[nb]=Tastaturinnstillinger +Comment[nds]=De Tastatuur instellen +Comment[ne]=कुञ्जीपाटी सेटिङ +Comment[nl]=Toetsenbord instellen +Comment[nn]=Tastaturinnstillingar +Comment[oc]=Paramètres de clavièr +Comment[or]=କିବୋର୍ଡ଼ ସଂରଚନା +Comment[pa]=ਕੀਬੋਰਡ ਸੈਟਿੰਗ +Comment[pl]=Ustawienia klawiatury +Comment[pt]=Configuração do teclado +Comment[pt_BR]=Configurações do teclado +Comment[ro]=Configurări tastatură +Comment[ru]=Настройка клавиатуры +Comment[se]=Boallobeavdeheivehusat +Comment[si]=යතුරුපුවරු සැකසුම් +Comment[sk]=Nastavenie klávesnice +Comment[sl]=Nastavitve tipkovnice +Comment[sr]=Поставке тастатуре +Comment[sr@ijekavian]=Поставке тастатуре +Comment[sr@ijekavianlatin]=Postavke tastature +Comment[sr@latin]=Postavke tastature +Comment[sv]=Anpassa tangentbordets inställningar +Comment[ta]=விசைப்பலகை அமைப்புகள் +Comment[te]=కీబోర్డ్ అమరికలు +Comment[tg]=Танзимоти клавиатура +Comment[th]=ตั้งค่าต่าง ๆ ของแป้นพิมพ์ +Comment[tr]=Klavye ayarları +Comment[ug]=ھەرپتاختا تەڭشەك +Comment[uk]=Параметри клавіатури +Comment[uz]=Tugmatagning moslamalari +Comment[uz@cyrillic]=Тугматагнинг мосламалари +Comment[vi]=Thiết lập bàn phím +Comment[wa]=Apontiaedje del taprece +Comment[xh]=Izicwangciso zebhodi enezitshixo +Comment[x-test]=xxKeyboard settingsxx +Comment[zh_CN]=键盘设置 +Comment[zh_TW]=鍵盤設定 + +X-KDE-Keywords=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key +X-KDE-Keywords[bs]=tastatura,ponavljanje tastature,kliknute glasnoću,umetnuti uređaj,ponoviti,glasnoća,NumLock,NumPad,tip tastature,model tastature,izgled tastature,izgled tipki,jezik,rezervna tastatura,uključivanje tastature,Ctrl tipka,velika slova,esperanto,cirkumfleks,ukloniti X server,LED tastatura,sastavljene tipke +X-KDE-Keywords[ca]=Teclat,Repetició de teclat,Volum de clic,Dispositius d'entrada,repetició,volum,BloqNum,NumPad,Tipus de teclat,Model de teclat,Disposició de teclat,Idioma,Teclat alternatiu,Commutació de teclat,Tecla Ctrl,Bloq Maj,Esperanto,Circumflex,Matar servidor X,LED de teclat,Tecla compose +X-KDE-Keywords[ca@valencia]=Teclat,Repetició de teclat,Volum de clic,Dispositius d'entrada,repetició,volum,BloqNum,NumPad,Tipus de teclat,Model de teclat,Disposició de teclat,Idioma,Teclat alternatiu,Commutació de teclat,Tecla Ctrl,Bloq Maj,Esperanto,Circumflex,Matar servidor X,LED de teclat,Tecla compose +X-KDE-Keywords[da]=Tastatur,keyboard,tastaturgentagelse,klikvolume,inputenheder,gentag,lydstyrke,NumLock,numerisk tastatur,tastaturtype,tastaturmodel,tastaturlayout,tastelayout,sprog,alternativt tastatur,skift af tastatur,Ctrl-tast,lås skift,caps lock,Esperanto,Circumflex,dræb X Server,LED-tastatur,Compose-tast +X-KDE-Keywords[de]=Tastatur,Tastenwiederholung,Klicklautstärke,Eingabegeräte,Wiederholung,Lautstärke,Zahlen-Feststelltaste,Zahlenblock,Tastaturtyp,Tastaturmodell,Tastaturlayout,Tastenlayout,Sprache,Alternative Tastatur,Tastaturwechsel,Tastaturbelegung,Strg-Taste,Umschalttaste,Esperanto,Zirkumflex,X-Server beenden,Tastatur LED,Compose-Taste +X-KDE-Keywords[el]=πληκτρολόγιο,επανάληψη πληκτρολογίου,ένταση κλικ,συσκευές εισόδου,επανάληψη,ένταση,NumLock,αριθμητικό πληκτρολόγιο,τύπος πληκτρολογίου,μοντέλο πληκτρολογίου,διάταξη πληκτρολογίου,γλώσσα,εναλλακτικό πληκτρολόγιο,εναλλαγή πληκτρολογίου,πλήκτρο Ctrl,Caps Lock,Esperanto,Circumflex,Kill X Server,LED πληκτρολόγιο,πλήκτρο σύνθεσης +X-KDE-Keywords[en_GB]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key +X-KDE-Keywords[es]=Teclado,Repetición del teclado,Volumen del clic,Dispositivos de entrada,repetición,volumen,Bloqueo numérico,Teclado numérico,Tipo de teclado,Modelo de teclado,Disposición del teclado,Disposición de las teclas,Idioma,Teclado alternativo,Cambiar de teclado,Tecla Ctrl,Bloqueo de mayúsculas,Esperanto,Circunflejo,Matar el servidor X,LED del teclado,Tecla de composición +X-KDE-Keywords[et]=Klaviatuur,Klaviatuurikordus,Klõpsu helitugevus,Sisendseadmed,kordus,helitugevus,NumLock,NumPad,numbriklahvistik,Klaviatuurimudel,Klaviatuuri mudel,Klaviatuuripaigutus,Klaviatuuri paigutus,Paigutus,Keel,Alternatiivne klaviatuur,Klaviatuuri vahetamine,Ctrl,Caps Lock,Esperanto,Tsirkumfleks,Katus,X-serveri tapmine,LDE-klaviatuur,Muuteklahv +X-KDE-Keywords[eu]=teklatu, teklatuaren errepikapen,klikaren bolumena,sarrerako gailuak,errepikatu,bolumena,BlokZenb,zenbakizko teklatu,teklatu mota,teklatuaren modeloa,teklatu-diseinua,teklen diseinua,hizkuntza, teklatu alternatiboa,teklatua aldatzea,ktrl tekla,BlokMaius,esperanto,zirkunflexua,hil X zerbitzaria,LED teklatua,tekla konposatua +X-KDE-Keywords[fi]=näppäimistö,näppäimistön toisto,näppäilyäänen voimakkuus,syöttölaitteet,toisto,numlock,numerolukko,numpad,numeronäppäimistö,näppäimistön tyyppi,näppäimistön malli,näppäimistöasettelu,näppäinasettelu,kieli,vaihtoehtoinen näppäimistö,näppäimistön vaihto,näppäimistön vaihtaminen,Ctrl-näppäin,caps lock,Esperanto,tapa X-palvelin,LED-näppäimistö,compose-näppäin +X-KDE-Keywords[fr]=Clavier, Répétition du clavier, Volume du clic, Périphériques d'entrée, répétition, volume, Verrouillage numérique, Pavé numérique, Type de clavier, Modèle de clavier, Disposition du clavier, Disposition des touches, Langue, Clavier alternatif, Changement de clavier, Touche Ctrl, Verrouillage des majuscule, Espéranto, Circonflexe, Tuer le serveur X, Voyants du clavier, Touche de composition +X-KDE-Keywords[gl]=teclado, repetición de teclas, volume do clic, dispositivo de entrada, repetición, volume, Bloq núm, Bloq num, tipo de teclado, modelo, disposición idioma, teclado alternativo, troco de teclado, Ctrl, Bloq maiús, til, circunflexo, matar o servidor X, LED +X-KDE-Keywords[hu]=Billentyűzet,Billentyűzet ismétlés,Kattintási hangerő,Beviteli eszközök,ismétlés,hangerő,NumLock,Numerikus billentyűzet,Billentyűzet típus,Billentyűzet modell,Billentyűzetkiosztás,Nyelv,Alternatív billentyűzet,Billentyűzetváltó,Ctrl billentyű,Caps Lock,Eszperantó,Ékezet,X kiszolgáló kilövése,LED billentyűzet,Levélírás billentyű +X-KDE-Keywords[ia]=Claviero,Repetition de claviero,Volumine de click,Dispositivos de ingresso,volumine, NumLock,Typo de claviero,modello de Claviero,disposition de claviero, Disposition de clave, Linguage,Claviero alternate,commutation de claviero,Clave Ctrl,Caps Lock,Esperanto, Circumflexe,Occide X Server, Claviero LED, Clave composite +X-KDE-Keywords[it]=tastiera,ripetizione tastiera,clic volume,dispositivi di ingresso,ripetizione,volume,bloc num,tastierino numerico,tipo tastiera, modello tastiera,mappatura tastiera,mappatura tasto,lingua,tastiera alternativa,cambio tastiera, tasto ctrl,maiusc,esperanto,circonflesso,uccidi server x,led tastiera,tasto composizione +X-KDE-Keywords[kk]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key +X-KDE-Keywords[km]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key +X-KDE-Keywords[ko]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key,키보드,키보드 반복,입력 장치, 숫자패드,키보드 종류,레이아웃,입력,언어 +X-KDE-Keywords[mr]=की-बोर्ड,की-बोर्ड रिपीट, क्लिक व्हॉल्यूम, इनपुट डिव्हाइस, रिपीट, व्हॉल्यूम,न्यूम.लॉक,न्यूम.पॅड,की-बोर्ड टाईप, की-बोर्ड मॉडेल, की-बोर्ड लेआउट, कि लेआउट, कि लेआउट, भाषा, वैकल्पिक की-बोर्ड,की-बोर्ड स्विचिंग,सी.टी.आर.एल.की, कॅप्स लॉक, एस्परांटो,सर्कम्फलेकस,किल एक्स सर्व्हर, एल.इ.डी की बोर्ड, कंपोज की +X-KDE-Keywords[nb]=Tastatur,Tasterepetisjon,Klikklydstyrke,Inndataenheter,repeter,lydstyrke,NumLock,NumPad.Tastaturtype,Tastaturmodell,Tastaturutforming,Tateutlegg,Språk,Alternativt tastatur,Tastaturbytte,CTRL-tast,Caps Lock,Esperanto,circumflex,Drep X-tjener,LED-tastatur,Sammensett-tast +X-KDE-Keywords[nds]=Tastatuur,Tastwedderhalen,Tastluutstärk,Ingaavreedschappen, wedderhalen,Luutstärk,NumLock,TallenRast,Tallenblock,Tastatuurtyp,Tastatuurmodell,Tasttoornen,Layout,Spraak,Anner Tastatuur,Tastatuurwesseln,Ctrl,Strg,GrootschrRast, Grootschriev-Rast,Caps Lock,capslock,butenlannsch,Bookstaven,Akzent,Sünnertekens,X-Server afscheten +X-KDE-Keywords[nl]=Toetsenbord,Toetsenbordherhaling,Klikvolume,Invoerapparaten,herhaling,volume,NumLock,NumPad,Type toetsenbord,Model toetsenbord,Toetsenbordindeling,Toetsenindeling,Taal,Toetsenbord alterneren,Toetsenbord omschakelen,Ctrl-toets,Caps Lock,Esperanto,Circumflex,Kill X Server,LED-toetsenbord,Compositietoets +X-KDE-Keywords[pl]=Klawiatura,Powtórzenia klawiatury,Głośność kliknięcia,Urządzenia wejścia,powtórzenie,głośność +X-KDE-Keywords[pt]=Teclado,repetição do teclado,volume do 'click',dispositivos de entrada,repetição,volume,NumLock,NumPad,Tipo de teclado,Modelo de teclado,Disposição do teclado,Disposição das teclas,Língua,Teclado alternativo,Mudança de teclado,Ctrl,Caps Lock,Esperanto,Circunflexo,Matar o Servidor X,LED do Teclado,Tecla Compose +X-KDE-Keywords[pt_BR]=Teclado,repetição do teclado,volume do clique,dispositivos de entrada,repetição,volume,NumLock,NumPad,Tipo de teclado,Modelo de teclado,Leiaute do teclado,Leiaute das teclas,Idioma,Teclado alternativo,Mudança de teclado,Tecla Ctrl,Caps Lock,Esperanto,Circunflexo,Finalizar o servidor X,LED do teclado,Tecla Compose +X-KDE-Keywords[ru]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key,клавиатура,повтор клавиши,громкость щелчка,громкость клика,устройство ввода,повтор,громкость,цифровая клавиатура,тип клавиатуры,модель клавиатуры,раскладка клавиатуры,расположение клавиш,язык,альтернативная клавиатура,переключение клавиатуры +X-KDE-Keywords[sk]=Klávesnica,opakovanie klávesnice,hlasitosť kliknutia,vstupné zariadenia,opakovanie, halsitosť,NumLock, NumPad,typ klávesnice,model klávesnice,rozloženie klávesnice,rozloženie kláves,jazyk, alternatívna klávesnica,prepínanie klávesnice,Ctrl,Caps Lock,Esperanto, Circumflex,zabiť X server,LED klávesnica,zložená klávesa +X-KDE-Keywords[sl]=tipkovnica,ponavljanje tipkovnice,tipkovno ponavljanje,glasnost klika,vhodne naprave,ponavljanje,glasnost,numlock,številčnica,vrsta tipkovnice,model tipkovnice,razporeditev tipk,razporeditev tipkovnice,jezik,nadomestna tipkovnica,alternativna tipkovnica,preklapljanje tipkovnice,ctrl,tipka ctrl,capslock,esperanto,cirkumfleks,končaj strežnik x,led,lučke,tipka za sestavljanje +X-KDE-Keywords[sr]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key,тастатура,понављање тастатуре,јачина клика,улазни уређаји,понављање,јачина,NumLock,нумеричка тастатура,тип тастатуре,модел тастатуре,распоред тастатуре,распоред тастера,језик,алтернативна тастатура,мењач тастатуре,Ctrl,CapsLock,есперанто,циркумфлекс,ЛЕД тастатура,укини икс сервер +X-KDE-Keywords[sr@ijekavian]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key,тастатура,понављање тастатуре,јачина клика,улазни уређаји,понављање,јачина,NumLock,нумеричка тастатура,тип тастатуре,модел тастатуре,распоред тастатуре,распоред тастера,језик,алтернативна тастатура,мењач тастатуре,Ctrl,CapsLock,есперанто,циркумфлекс,ЛЕД тастатура,укини икс сервер +X-KDE-Keywords[sr@ijekavianlatin]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key,tastatura,ponavljanje tastature,jačina klika,ulazni uređaji,ponavljanje,jačina,NumLock,numerička tastatura,tip tastature,model tastature,raspored tastature,raspored tastera,jezik,alternativna tastatura,menjač tastature,Ctrl,CapsLock,esperanto,cirkumfleks,LED tastatura,ukini X server +X-KDE-Keywords[sr@latin]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key,tastatura,ponavljanje tastature,jačina klika,ulazni uređaji,ponavljanje,jačina,NumLock,numerička tastatura,tip tastature,model tastature,raspored tastature,raspored tastera,jezik,alternativna tastatura,menjač tastature,Ctrl,CapsLock,esperanto,cirkumfleks,LED tastatura,ukini X server +X-KDE-Keywords[sv]=Tangentbord,Tangentbordsupprepning,Klickvolym,Indataenheter,upprepa,volym,NumLock,Numeriskt tangentbord,Tangentbordstyp,Tangentbordsmodell,Tangentbordslayout,Språk,Alternativt tangentbord,Tangentbordsbyte,Ctrl-tangent,Caps Lock,Esperanto,Circumflex,Döda X-server,LED-tangentbord,Compose-tangent +X-KDE-Keywords[tr]=Klavye,Klavye tekrarlaması,Tıklama sesi,Girdi Aygıtları,tekrarla,ses,NumLock,Sayısal Tuşlar,Klavye tipi,Klavye modeli,Klavye düzeni,Tuş düzeni,Dil,Klavyeyi Değiştir,Klavye Seçimi,Ctrl Tuşu,Caps Lock,Esperanto,İnceltme İşareti,X Sunucuyu Sonlandır,LED Klavye,Tuş Düzeni Oluştur +X-KDE-Keywords[uk]=клавіатура,повторення натискань,гучність клацання,пристрої введення,повторення,гучність,тип клавіатури,розкладка клавіатури,мова,інша клавіатура,інша розкладка,перемикання розкладок,клавіша Ctrl,есперанто,циркумфлекс,лампочки на клавіатурі,клавіша перемикання,Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key +X-KDE-Keywords[vi]=Bàn phím, lặp bàn phím, âm lượng nhấn nút,thiết bị nhập,lặp lại,âm lượng,NumLock,NumPad, kiểu bàn phím,mẫu bàn phím,loại bàn phím, bố trí phím,ngôn ngữ,bàn phím thay thế,chuyển đổi bàn phím,phím Ctrl,Caps Lock, Esperanto,Circumflex,tắt máy chủ X,bàn phím LED,phím tổ hợp +X-KDE-Keywords[x-test]=xxKeyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Keyxx +X-KDE-Keywords[zh_CN]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key,键盘,键盘重复,按键音量,输入设备,重复,音量,数字锁定,数字键盘,小键盘,键盘类型,键盘模型,键盘布局,按键布局,语言,额外键盘,键盘切换,Ctrl 键,大写锁定,杀死 X 服务器,LED 键盘灯,Compose 键,死键 +X-KDE-Keywords[zh_TW]=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key diff --git a/kcontrol/keyboard/kcm_keyboard.h b/kcontrol/keyboard/kcm_keyboard.h new file mode 100644 index 00000000..c88fe3dd --- /dev/null +++ b/kcontrol/keyboard/kcm_keyboard.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KCM_KEYBOARD_H_ +#define KCM_KEYBOARD_H_ + +#include + +class KCMKeyboardWidget; +class KeyboardConfig; +class Rules; + +class KCMKeyboard: public KCModule +{ +Q_OBJECT + +public: + KCMKeyboard(QWidget *parent, const QVariantList &); + virtual ~KCMKeyboard(); + + void save(); + void load(); + void defaults(); + +private: + Rules* rules; + KeyboardConfig* keyboardConfig; + KCMKeyboardWidget *widget; +}; + +#endif /* KCM_KEYBOARD_H_ */ diff --git a/kcontrol/keyboard/kcm_keyboard.ui b/kcontrol/keyboard/kcm_keyboard.ui new file mode 100644 index 00000000..f64eeea4 --- /dev/null +++ b/kcontrol/keyboard/kcm_keyboard.ui @@ -0,0 +1,478 @@ + + + TabWidget + + + + 0 + 0 + 677 + 485 + + + + 1 + + + + Hardware + + + + + + + 1 + 0 + + + + Keyboard &model: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + keyboardModelComboBox + + + + + + + + 2 + 0 + + + + Here you can choose a keyboard model. This setting is independent of your keyboard layout and refers to the "hardware" model, i.e. the way your keyboard is manufactured. Modern keyboards that come with your computer usually have two extra keys and are referred to as "104-key" models, which is probably what you want if you do not know what kind of keyboard you have. + + + + 15 + + + QComboBox::AdjustToContentsOnFirstShow + + + + + + + + 1 + 1 + + + + + 0 + 100 + + + + + 0 + 0 + + + + + 0 + + + + + + + + + Layouts + + + + + + + + Layout Indicator + + + + + + Show layout indicator + + + + + + + Show for single layout + + + + + + + Show flag + + + + + + + Show label + + + + + + + Show label on flag + + + + + + + + + + If you select "Application" or "Window" switching policy, changing the keyboard layout will only affect the current application or window. + + + Switching Policy + + + + + + &Global + + + true + + + + + + + &Desktop + + + + + + + &Application + + + + + + + &Window + + + + + + + + + + Shortcuts for Switching Layout + + + + + + Main shortcuts: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + xkbGrpShortcutBtn + + + + + + + This is a shortcut for switching layouts which is handled by X.org. It allows modifier-only shortcuts. + + + None + + + + + + + ... + + + + + + + 3rd level shortcuts: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + xkb3rdLevelShortcutBtn + + + + + + + This is a shortcut for switching to a third level of the active layout (if it has one) which is handled by X.org. It allows modifier-only shortcuts. + + + None + + + + + + + ... + + + + + + + Alternative shortcut: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kdeKeySequence + + + + + + + This is a shortcut for switching layouts which is handled by KDE. It does not support modifier-only shortcuts and also may not work in some situations (e.g. if popup is active or from screensaver). + + + false + + + + + + + + + + + + true + + + Configure layouts + + + false + + + true + + + + + + + + Add + + + + + + + false + + + Remove + + + + + + + false + + + Move Up + + + + + + + false + + + Move Down + + + + + + + false + + + Preview + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + Spare layouts + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 15 + 20 + + + + + + + + + + + true + + + + + + Main layout count: + + + + + + + + + + Qt::Horizontal + + + + 431 + 20 + + + + + + + + + + + + + + + Advanced + + + + + + &Configure keyboard options + + + + + + + false + + + QAbstractItemView::NoSelection + + + true + + + + + + + + + KButtonGroup + QGroupBox +
kbuttongroup.h
+ 1 +
+ + KKeySequenceWidget + QWidget +
kkeysequencewidget.h
+
+
+ + + + changed(bool) + +
diff --git a/kcontrol/keyboard/kcm_keyboard_widget.cpp b/kcontrol/keyboard/kcm_keyboard_widget.cpp new file mode 100644 index 00000000..c9a69103 --- /dev/null +++ b/kcontrol/keyboard/kcm_keyboard_widget.cpp @@ -0,0 +1,691 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "kcm_keyboard_widget.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "keyboard_config.h" +#include "preview/keyboardpainter.h" +#include "xkb_rules.h" +#include "flags.h" +#include "x11_helper.h" +#include "kcm_view_models.h" +#include "kcm_add_layout_dialog.h" +#include "bindings.h" + +#include "kcmmisc.h" + +#include "ui_kcm_add_layout_dialog.h" + + +static const QString GROUP_SWITCH_GROUP_NAME("grp"); +static const QString LV3_SWITCH_GROUP_NAME("lv3"); +//static const QString RESET_XKB_OPTIONS("-option"); + +static const int TAB_HARDWARE = 0; +static const int TAB_LAYOUTS = 1; +static const int TAB_ADVANCED = 2; + +static const int MIN_LOOPING_COUNT = 2; + + +KCMKeyboardWidget::KCMKeyboardWidget(Rules* rules_, KeyboardConfig* keyboardConfig_, + const KComponentData componentData_, const QVariantList &args, QWidget* /*parent*/): + rules(rules_), + componentData(componentData_), + actionCollection(NULL), + uiUpdating(false) +{ + flags = new Flags(); + keyboardConfig = keyboardConfig_; + + uiWidget = new Ui::TabWidget; + uiWidget->setupUi(this); + + kcmMiscWidget = new KCMiscKeyboardWidget(uiWidget->lowerHardwareWidget); + uiWidget->lowerHardwareWidget->layout()->addWidget( kcmMiscWidget ); + connect(kcmMiscWidget, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); + + if( rules != NULL ) { + initializeKeyboardModelUI(); + initializeXkbOptionsUI(); + initializeLayoutsUI(); + } + else { + uiWidget->tabLayouts->setEnabled(false); + uiWidget->tabAdvanced->setEnabled(false); + uiWidget->keyboardModelComboBox->setEnabled(false); + } + + handleParameters(args); +} + +KCMKeyboardWidget::~KCMKeyboardWidget() +{ + delete flags; +} + +void KCMKeyboardWidget::handleParameters(const QVariantList &args) +{ + // TODO: improve parameter handling + setCurrentIndex(TAB_HARDWARE); + foreach(const QVariant& arg, args) { + if( arg.type() == QVariant::String ) { + QString str = arg.toString(); + if( str == "--tab=layouts" ) { + setCurrentIndex(TAB_LAYOUTS); + } + else if( str == "--tab=advanced" ) { + setCurrentIndex(TAB_ADVANCED); + } + } + } +} + +void KCMKeyboardWidget::save() +{ + if( rules == NULL ) + return; + + if( actionCollection != NULL ) { + actionCollection->resetLayoutShortcuts(); + actionCollection->clear(); + delete actionCollection; + } + actionCollection = new KeyboardLayoutActionCollection(this, true); + actionCollection->setToggleShortcut(uiWidget->kdeKeySequence->keySequence()); + actionCollection->setLayoutShortcuts(keyboardConfig->layouts, rules); + + //TODO: skip if no change in shortcuts? + KGlobalSettings::emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_SHORTCUTS); +} + +void KCMKeyboardWidget::updateUI() +{ + if( rules == NULL ) + return; + + uiWidget->layoutsTableView->setModel(uiWidget->layoutsTableView->model()); + layoutsTableModel->refresh(); + uiWidget->layoutsTableView->resizeRowsToContents(); + + uiUpdating = true; + updateHardwareUI(); + updateXkbOptionsUI(); + updateSwitcingPolicyUI(); + updateLayoutsUI(); + updateShortcutsUI(); + uiUpdating = false; +} + +void KCMKeyboardWidget::uiChanged() +{ + if( rules == NULL ) + return; + + ((LayoutsTableModel*)uiWidget->layoutsTableView->model())->refresh(); +// this collapses the tree so use more fine-grained updates +// ((LayoutsTableModel*)uiWidget->xkbOptionsTreeView->model())->refresh(); + + if( uiUpdating ) + return; + + keyboardConfig->showIndicator = uiWidget->showIndicatorChk->isChecked(); + keyboardConfig->showSingle = uiWidget->showSingleChk->isChecked(); + + keyboardConfig->configureLayouts = uiWidget->layoutsGroupBox->isChecked(); + keyboardConfig->keyboardModel = uiWidget->keyboardModelComboBox->itemData(uiWidget->keyboardModelComboBox->currentIndex()).toString(); + + if( uiWidget->showFlagRadioBtn->isChecked() ) { + keyboardConfig->indicatorType = KeyboardConfig::SHOW_FLAG; + } + else + if( uiWidget->showLabelRadioBtn->isChecked() ) { + keyboardConfig->indicatorType = KeyboardConfig::SHOW_LABEL; + } + else { +// if( uiWidget->showFlagRadioBtn->isChecked() ) { + keyboardConfig->indicatorType = KeyboardConfig::SHOW_LABEL_ON_FLAG; + } + + keyboardConfig->resetOldXkbOptions = uiWidget->configureKeyboardOptionsChk->isChecked(); + + if( uiWidget->switchByDesktopRadioBtn->isChecked() ) { + keyboardConfig->switchingPolicy = KeyboardConfig::SWITCH_POLICY_DESKTOP; + } + else + if( uiWidget->switchByApplicationRadioBtn->isChecked() ) { + keyboardConfig->switchingPolicy = KeyboardConfig::SWITCH_POLICY_APPLICATION; + } + else + if( uiWidget->switchByWindowRadioBtn->isChecked() ) { + keyboardConfig->switchingPolicy = KeyboardConfig::SWITCH_POLICY_WINDOW; + } + else { + keyboardConfig->switchingPolicy = KeyboardConfig::SWITCH_POLICY_GLOBAL; + } + + updateXkbShortcutsButtons(); + + updateLoopCount(); + int loop = uiWidget->layoutLoopCountSpinBox->text().isEmpty() + ? KeyboardConfig::NO_LOOPING + : uiWidget->layoutLoopCountSpinBox->value(); + keyboardConfig->layoutLoopCount = loop; + + layoutsTableModel->refresh(); + + emit changed(true); +} + +void KCMKeyboardWidget::initializeKeyboardModelUI() +{ + foreach(ModelInfo* modelInfo, rules->modelInfos) { + QString vendor = modelInfo->vendor; + if( vendor.isEmpty() ) { + vendor = i18nc("unknown keyboard model vendor", "Unknown"); + } + uiWidget->keyboardModelComboBox->addItem(i18nc("vendor | keyboard model", "%1 | %2", vendor, modelInfo->description), modelInfo->name); + } + uiWidget->keyboardModelComboBox->model()->sort(0); + connect(uiWidget->keyboardModelComboBox, SIGNAL(activated(int)), this, SLOT(uiChanged())); +} + +void KCMKeyboardWidget::addLayout() +{ + if( keyboardConfig->layouts.count() >= X11Helper::ARTIFICIAL_GROUP_LIMIT_COUNT ) { // artificial limit now + QMessageBox msgBox; + msgBox.setText(i18np("Only up to %1 keyboard layout is supported", "Only up to %1 keyboard layouts are supported", X11Helper::ARTIFICIAL_GROUP_LIMIT_COUNT)); + // more information https://bugs.freedesktop.org/show_bug.cgi?id=19501 + msgBox.exec(); + return; + } + + AddLayoutDialog dialog(rules, keyboardConfig->isFlagShown() ? flags : NULL, keyboardConfig->isLabelShown(), this); + dialog.setModal(true); + if( dialog.exec() == QDialog::Accepted ) { + keyboardConfig->layouts.append( dialog.getSelectedLayoutUnit() ); + layoutsTableModel->refresh(); + uiWidget->layoutsTableView->resizeRowsToContents(); + uiChanged(); + } + + updateLoopCount(); +} + +static +inline int min(int x, int y) { return x < y ? x : y; } + +void KCMKeyboardWidget::updateLoopCount() +{ + int maxLoop = min(X11Helper::MAX_GROUP_COUNT, keyboardConfig->layouts.count() - 1); + uiWidget->layoutLoopCountSpinBox->setMaximum(maxLoop); + + bool layoutsConfigured = uiWidget->layoutsGroupBox->isChecked(); + + if( maxLoop < MIN_LOOPING_COUNT ) { + uiWidget->layoutLoopingCheckBox->setEnabled(false); + uiWidget->layoutLoopingCheckBox->setChecked(false); + } + else if( maxLoop >= X11Helper::MAX_GROUP_COUNT ) { + uiWidget->layoutLoopingCheckBox->setEnabled(false); + uiWidget->layoutLoopingCheckBox->setChecked(true); + } + else { + uiWidget->layoutLoopingCheckBox->setEnabled(layoutsConfigured); + } + + uiWidget->layoutLoopingGroupBox->setEnabled( + layoutsConfigured && uiWidget->layoutLoopingCheckBox->isChecked()); + + if( uiWidget->layoutLoopingCheckBox->isChecked() ) { + if( uiWidget->layoutLoopCountSpinBox->text().isEmpty() ) { + uiWidget->layoutLoopCountSpinBox->setValue(maxLoop); +// keyboardConfig->layoutLoopCount = maxLoop; + } + } + else { + uiWidget->layoutLoopCountSpinBox->clear(); +// keyboardConfig->layoutLoopCount = KeyboardConfig::NO_LOOPING; + } +} + +void KCMKeyboardWidget::initializeLayoutsUI() +{ + layoutsTableModel = new LayoutsTableModel(rules, flags, keyboardConfig, uiWidget->layoutsTableView); + uiWidget->layoutsTableView->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed); + uiWidget->layoutsTableView->setModel(layoutsTableModel); + uiWidget->layoutsTableView->setIconSize( flags->getTransparentPixmap().size() ); + + //TODO: do we need to delete this delegate or parent will take care of it? + VariantComboDelegate* variantDelegate = new VariantComboDelegate(keyboardConfig, rules, uiWidget->layoutsTableView); + uiWidget->layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::VARIANT_COLUMN, variantDelegate); + + LabelEditDelegate* labelDelegate = new LabelEditDelegate(keyboardConfig, uiWidget->layoutsTableView); + uiWidget->layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::DISPLAY_NAME_COLUMN, labelDelegate); + + KKeySequenceWidgetDelegate* shortcutDelegate = new KKeySequenceWidgetDelegate(keyboardConfig, uiWidget->layoutsTableView); + uiWidget->layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::SHORTCUT_COLUMN, shortcutDelegate); + + //TODO: is it ok to hardcode sizes? any better approach? + uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::MAP_COLUMN, 70); + uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::LAYOUT_COLUMN, 200); + uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::VARIANT_COLUMN, 200); + uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::DISPLAY_NAME_COLUMN, 50); + uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::SHORTCUT_COLUMN, 130); + + connect(layoutsTableModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(uiChanged())); + + uiWidget->layoutLoopCountSpinBox->setMinimum(MIN_LOOPING_COUNT); + +#ifdef DRAG_ENABLED + uiWidget->layoutsTableView->setDragEnabled(true); + uiWidget->layoutsTableView->setAcceptDrops(true); +#endif + + uiWidget->moveUpBtn->setIcon(KIcon("arrow-up")); + uiWidget->moveDownBtn->setIcon(KIcon("arrow-down")); + uiWidget->addLayoutBtn->setIcon(KIcon("list-add")); + uiWidget->removeLayoutBtn->setIcon(KIcon("list-remove")); + + KIcon clearIcon = qApp->isLeftToRight() ? KIcon("edit-clear-locationbar-rtl") : KIcon("edit-clear-locationbar-ltr"); + uiWidget->xkbGrpClearBtn->setIcon(clearIcon); + uiWidget->xkb3rdLevelClearBtn->setIcon(clearIcon); + + KIcon configIcon = KIcon("configure"); + uiWidget->xkbGrpShortcutBtn->setIcon(configIcon); + uiWidget->xkb3rdLevelShortcutBtn->setIcon(configIcon); + + uiWidget->kdeKeySequence->setModifierlessAllowed(false); + + connect(uiWidget->addLayoutBtn, SIGNAL(clicked(bool)), this, SLOT(addLayout())); + connect(uiWidget->removeLayoutBtn, SIGNAL(clicked(bool)), this, SLOT(removeLayout())); +// connect(uiWidget->layoutsTable, SIGNAL(itemSelectionChanged()), this, SLOT(layoutSelectionChanged())); + connect(uiWidget->layoutsTableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(layoutSelectionChanged())); + +// connect(uiWidget->moveUpBtn, SIGNAL(triggered(QAction*)), this, SLOT(moveUp())); +// connect(uiWidget->moveDownBtn, SIGNAL(triggered(QAction*)), this, SLOT(moveDown())); + connect(uiWidget->moveUpBtn, SIGNAL(clicked(bool)), this, SLOT(moveUp())); + connect(uiWidget->moveDownBtn, SIGNAL(clicked(bool)), this, SLOT(moveDown())); + + connect(uiWidget->previewbutton,SIGNAL(clicked(bool)),this,SLOT(previewLayout())); + + connect(uiWidget->xkbGrpClearBtn, SIGNAL(clicked(bool)), this, SLOT(clearGroupShortcuts())); + connect(uiWidget->xkb3rdLevelClearBtn, SIGNAL(clicked(bool)), this, SLOT(clear3rdLevelShortcuts())); + +// connect(uiWidget->xkbGrpClearBtn, SIGNAL(triggered(QAction*)), this, SLOT(uiChanged())); +// connect(uiWidget->xkb3rdLevelClearBtn, SIGNAL(triggered(QAction*)), this, SLOT(uiChanged())); + connect(uiWidget->kdeKeySequence, SIGNAL(keySequenceChanged(QKeySequence)), this, SLOT(uiChanged())); + connect(uiWidget->switchingPolicyButtonGroup, SIGNAL(clicked(int)), this, SLOT(uiChanged())); + + connect(uiWidget->xkbGrpShortcutBtn, SIGNAL(clicked(bool)), this, SLOT(scrollToGroupShortcut())); + connect(uiWidget->xkb3rdLevelShortcutBtn, SIGNAL(clicked(bool)), this, SLOT(scrollTo3rdLevelShortcut())); + + // connect(uiWidget->configureLayoutsChk, SIGNAL(toggled(bool)), uiWidget->layoutsGroupBox, SLOT(setEnabled(bool))); + connect(uiWidget->layoutsGroupBox, SIGNAL(toggled(bool)), this, SLOT(configureLayoutsChanged())); + + connect(uiWidget->showIndicatorChk, SIGNAL(clicked(bool)), this, SLOT(uiChanged())); + connect(uiWidget->showIndicatorChk, SIGNAL(toggled(bool)), uiWidget->showSingleChk, SLOT(setEnabled(bool))); + connect(uiWidget->showFlagRadioBtn, SIGNAL(clicked(bool)), this, SLOT(uiChanged())); + connect(uiWidget->showLabelRadioBtn, SIGNAL(clicked(bool)), this, SLOT(uiChanged())); + connect(uiWidget->showLabelOnFlagRadioBtn, SIGNAL(clicked(bool)), this, SLOT(uiChanged())); + connect(uiWidget->showSingleChk, SIGNAL(toggled(bool)), this, SLOT(uiChanged())); + + connect(uiWidget->layoutLoopingCheckBox, SIGNAL(clicked(bool)), this, SLOT(uiChanged())); + connect(uiWidget->layoutLoopCountSpinBox, SIGNAL(valueChanged(int)), this, SLOT(uiChanged())); +} + +void KCMKeyboardWidget::previewLayout(){ + QMessageBox q; + QModelIndex index = uiWidget->layoutsTableView->currentIndex() ; + QModelIndex idcountry = index.sibling(index.row(),0) ; + QString country=uiWidget->layoutsTableView->model()->data(idcountry).toString(); + QModelIndex idvariant = index.sibling(index.row(),2) ; + QString variant=uiWidget->layoutsTableView->model()->data(idvariant).toString(); + if(index.row()==-1 || index.column()==-1){ + q.setText(i18n("No layout selected ")); + q.exec(); + } + else{ + KeyboardPainter* layoutPreview = new KeyboardPainter(); + const LayoutInfo* layoutInfo = rules->getLayoutInfo(country); + foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { + if(variant==variantInfo->description){ + variant=variantInfo->name; + break; + } + } + layoutPreview->generateKeyboardLayout(country,variant); + layoutPreview->exec(); + layoutPreview->setModal(true); + } +} + +void KCMKeyboardWidget::configureLayoutsChanged() +{ + if( uiWidget->layoutsGroupBox->isChecked() && keyboardConfig->layouts.isEmpty() ) { + populateWithCurrentLayouts(); + } + uiChanged(); +} + +static QPair getSelectedRowRange(const QModelIndexList& selected) +{ + if( selected.isEmpty() ) { + return QPair(-1, -1); + } + + QList rows; + foreach(const QModelIndex& index, selected) { + rows << index.row(); + } + qSort(rows); + return QPair(rows[0], rows[rows.size()-1]); +} + +void KCMKeyboardWidget::layoutSelectionChanged() +{ + QModelIndexList selected = uiWidget->layoutsTableView->selectionModel()->selectedIndexes(); + uiWidget->removeLayoutBtn->setEnabled( ! selected.isEmpty() ); + QPair rowsRange( getSelectedRowRange(selected) ); + uiWidget->moveUpBtn->setEnabled( ! selected.isEmpty() && rowsRange.first > 0); + uiWidget->previewbutton->setEnabled(! selected.isEmpty()); + uiWidget->moveDownBtn->setEnabled( ! selected.isEmpty() && rowsRange.second < keyboardConfig->layouts.size()-1 ); +} + +void KCMKeyboardWidget::removeLayout() +{ + if( ! uiWidget->layoutsTableView->selectionModel()->hasSelection() ) + return; + + QModelIndexList selected = uiWidget->layoutsTableView->selectionModel()->selectedIndexes(); + QPair rowsRange( getSelectedRowRange(selected) ); + foreach(const QModelIndex& idx, selected) { + if( idx.column() == 0 ) { + keyboardConfig->layouts.removeAt(rowsRange.first); + } + } + layoutsTableModel->refresh(); + uiChanged(); + + if( keyboardConfig->layouts.size() > 0 ) { + int rowToSelect = rowsRange.first; + if( rowToSelect >= keyboardConfig->layouts.size() ) { + rowToSelect--; + } + + QModelIndex topLeft = layoutsTableModel->index(rowToSelect, 0, QModelIndex()); + QModelIndex bottomRight = layoutsTableModel->index(rowToSelect, layoutsTableModel->columnCount(topLeft)-1, QModelIndex()); + QItemSelection selection(topLeft, bottomRight); + uiWidget->layoutsTableView->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); + uiWidget->layoutsTableView->setFocus(); + } + + layoutSelectionChanged(); + + updateLoopCount(); +} + +void KCMKeyboardWidget::moveUp() +{ + moveSelectedLayouts(-1); +} + +void KCMKeyboardWidget::moveDown() +{ + moveSelectedLayouts(1); +} + +void KCMKeyboardWidget::moveSelectedLayouts(int shift) +{ + QItemSelectionModel* selectionModel = uiWidget->layoutsTableView->selectionModel(); + if( selectionModel == NULL || !selectionModel->hasSelection() ) + return; + + QModelIndexList selected = selectionModel->selectedRows(); + if( selected.count() < 1 ) + return; + + int newFirstRow = selected[0].row() + shift; + int newLastRow = selected[ selected.size()-1 ].row() + shift; + + if( newFirstRow >= 0 && newLastRow <= keyboardConfig->layouts.size() - 1 ) { + QList selectionRows; + foreach(const QModelIndex& index, selected) { + int newRowIndex = index.row() + shift; + keyboardConfig->layouts.move(index.row(), newRowIndex); + selectionRows << newRowIndex; + } + uiChanged(); + + QItemSelection selection; + foreach(int row, selectionRows) { + QModelIndex topLeft = layoutsTableModel->index(row, 0, QModelIndex()); + QModelIndex bottomRight = layoutsTableModel->index(row, layoutsTableModel->columnCount(topLeft)-1, QModelIndex()); + selection << QItemSelectionRange(topLeft, bottomRight); + } + uiWidget->layoutsTableView->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); + uiWidget->layoutsTableView->setFocus(); + } +} + +void KCMKeyboardWidget::scrollToGroupShortcut() +{ + this->setCurrentIndex(TAB_ADVANCED); + if( ! uiWidget->configureKeyboardOptionsChk->isChecked() ) { + uiWidget->configureKeyboardOptionsChk->setChecked(true); + } + ((XkbOptionsTreeModel*)uiWidget->xkbOptionsTreeView->model())->gotoGroup(GROUP_SWITCH_GROUP_NAME, uiWidget->xkbOptionsTreeView); +} + +void KCMKeyboardWidget::scrollTo3rdLevelShortcut() +{ + this->setCurrentIndex(TAB_ADVANCED); + if( ! uiWidget->configureKeyboardOptionsChk->isChecked() ) { + uiWidget->configureKeyboardOptionsChk->setChecked(true); + } + ((XkbOptionsTreeModel*)uiWidget->xkbOptionsTreeView->model())->gotoGroup(LV3_SWITCH_GROUP_NAME, uiWidget->xkbOptionsTreeView); +} + +void KCMKeyboardWidget::clearGroupShortcuts() +{ + clearXkbGroup(GROUP_SWITCH_GROUP_NAME); +} + +void KCMKeyboardWidget::clear3rdLevelShortcuts() +{ + clearXkbGroup(LV3_SWITCH_GROUP_NAME); +} + +void KCMKeyboardWidget::clearXkbGroup(const QString& groupName) +{ + for(int ii=keyboardConfig->xkbOptions.count()-1; ii>=0; ii--) { + if( keyboardConfig->xkbOptions[ii].startsWith(groupName + Rules::XKB_OPTION_GROUP_SEPARATOR) ) { + keyboardConfig->xkbOptions.removeAt(ii); + } + } + ((XkbOptionsTreeModel*)uiWidget->xkbOptionsTreeView->model())->reset(); + uiWidget->xkbOptionsTreeView->update(); + updateXkbShortcutsButtons(); + emit changed(true); +} + +static +bool xkbOptionGroupLessThan(const OptionGroupInfo* og1, const OptionGroupInfo* og2) +{ + return og1->description.toLower() < og2->description.toLower(); +} +static +bool xkbOptionLessThan(const OptionInfo* o1, const OptionInfo* o2) +{ + return o1->description.toLower() < o2->description.toLower(); +} + +void KCMKeyboardWidget::initializeXkbOptionsUI() +{ + qSort(rules->optionGroupInfos.begin(), rules->optionGroupInfos.end(), xkbOptionGroupLessThan); + foreach(OptionGroupInfo* optionGroupInfo, rules->optionGroupInfos) { + qSort(optionGroupInfo->optionInfos.begin(), optionGroupInfo->optionInfos.end(), xkbOptionLessThan); + } + + XkbOptionsTreeModel* model = new XkbOptionsTreeModel(rules, keyboardConfig, uiWidget->xkbOptionsTreeView); + uiWidget->xkbOptionsTreeView->setModel(model); + connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(uiChanged())); + + connect(uiWidget->configureKeyboardOptionsChk, SIGNAL(toggled(bool)), this, SLOT(configureXkbOptionsChanged())); + // connect(uiWidget->configureKeyboardOptionsChk, SIGNAL(toggled(bool)), this, SLOT(uiChanged())); + connect(uiWidget->configureKeyboardOptionsChk, SIGNAL(toggled(bool)), uiWidget->xkbOptionsTreeView, SLOT(setEnabled(bool))); +} + +void KCMKeyboardWidget::configureXkbOptionsChanged() +{ + if( uiWidget->configureKeyboardOptionsChk->isChecked() && keyboardConfig->xkbOptions.isEmpty() ) { + populateWithCurrentXkbOptions(); + } + ((LayoutsTableModel*)uiWidget->xkbOptionsTreeView->model())->refresh(); + uiChanged(); +} + +void KCMKeyboardWidget::updateSwitcingPolicyUI() +{ + switch (keyboardConfig->switchingPolicy){ + case KeyboardConfig::SWITCH_POLICY_DESKTOP: + uiWidget->switchByDesktopRadioBtn->setChecked(true); + break; + case KeyboardConfig::SWITCH_POLICY_APPLICATION: + uiWidget->switchByApplicationRadioBtn->setChecked(true); + break; + case KeyboardConfig::SWITCH_POLICY_WINDOW: + uiWidget->switchByWindowRadioBtn->setChecked(true); + break; + default: + case KeyboardConfig::SWITCH_POLICY_GLOBAL: + uiWidget->switchByGlobalRadioBtn->setChecked(true); + } +} + +void KCMKeyboardWidget::updateXkbShortcutButton(const QString& groupName, QPushButton* button) +{ + QStringList grpOptions; + if( keyboardConfig->resetOldXkbOptions ) { + QRegExp regexp = QRegExp("^" + groupName + Rules::XKB_OPTION_GROUP_SEPARATOR); + grpOptions = keyboardConfig->xkbOptions.filter(regexp); + } + switch( grpOptions.size() ) { + case 0: + button->setText(i18nc("no shortcuts defined", "None")); + break; + case 1: { + const QString& option = grpOptions.first(); + const OptionGroupInfo* optionGroupInfo = rules->getOptionGroupInfo(groupName); + const OptionInfo* optionInfo = optionGroupInfo->getOptionInfo(option); + if( optionInfo == NULL || optionInfo->description == NULL ) { + kError() << "Could not find option info for " << option; + button->setText(grpOptions.first()); + } + else { + button->setText(optionInfo->description); + } + } + break; + default: + button->setText(i18np("%1 shortcut", "%1 shortcuts", grpOptions.size())); + } +} + +void KCMKeyboardWidget::updateXkbShortcutsButtons() +{ + updateXkbShortcutButton(GROUP_SWITCH_GROUP_NAME, uiWidget->xkbGrpShortcutBtn); + updateXkbShortcutButton(LV3_SWITCH_GROUP_NAME, uiWidget->xkb3rdLevelShortcutBtn); +} + +void KCMKeyboardWidget::updateShortcutsUI() +{ + updateXkbShortcutsButtons(); + + delete actionCollection; + actionCollection = new KeyboardLayoutActionCollection(this, true); + KAction* toggleAction = actionCollection->getToggeAction(); + uiWidget->kdeKeySequence->setKeySequence(toggleAction->globalShortcut().primary()); + actionCollection->loadLayoutShortcuts(keyboardConfig->layouts, rules); + layoutsTableModel->refresh(); +} + +void KCMKeyboardWidget::updateXkbOptionsUI() +{ + uiWidget->configureKeyboardOptionsChk->setChecked(keyboardConfig->resetOldXkbOptions); +} + +void KCMKeyboardWidget::updateLayoutsUI() { + uiWidget->layoutsGroupBox->setChecked(keyboardConfig->configureLayouts); + uiWidget->showIndicatorChk->setChecked(keyboardConfig->showIndicator); + uiWidget->showSingleChk->setChecked(keyboardConfig->showSingle); + uiWidget->showFlagRadioBtn->setChecked(keyboardConfig->indicatorType == KeyboardConfig::SHOW_FLAG); + uiWidget->showLabelRadioBtn->setChecked(keyboardConfig->indicatorType == KeyboardConfig::SHOW_LABEL); + uiWidget->showLabelOnFlagRadioBtn->setChecked(keyboardConfig->indicatorType == KeyboardConfig::SHOW_LABEL_ON_FLAG); + + bool loopingOn = keyboardConfig->configureLayouts && keyboardConfig->layoutLoopCount + != KeyboardConfig::NO_LOOPING; + uiWidget->layoutLoopingCheckBox->setChecked(loopingOn); + uiWidget->layoutLoopingGroupBox->setEnabled(loopingOn); + if( loopingOn ) { + uiWidget->layoutLoopCountSpinBox->setValue(keyboardConfig->layoutLoopCount); + } + else { + uiWidget->layoutLoopCountSpinBox->clear(); + } +} + +void KCMKeyboardWidget::updateHardwareUI() +{ + int idx = uiWidget->keyboardModelComboBox->findData(keyboardConfig->keyboardModel); + if( idx != -1 ) { + uiWidget->keyboardModelComboBox->setCurrentIndex(idx); + } +} + +void KCMKeyboardWidget::populateWithCurrentLayouts() +{ + QList layouts = X11Helper::getLayoutsList(); + foreach(LayoutUnit layoutUnit, layouts) { + keyboardConfig->layouts.append(layoutUnit); + } +} + +void KCMKeyboardWidget::populateWithCurrentXkbOptions() +{ + XkbConfig xkbConfig; + if( X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::ALL) ) { + foreach(QString xkbOption, xkbConfig.options) { + keyboardConfig->xkbOptions.append(xkbOption); + } + } +} diff --git a/kcontrol/keyboard/kcm_keyboard_widget.h b/kcontrol/keyboard/kcm_keyboard_widget.h new file mode 100644 index 00000000..58256dfe --- /dev/null +++ b/kcontrol/keyboard/kcm_keyboard_widget.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KCM_KEYBOARD_WIDGET_H_ +#define KCM_KEYBOARD_WIDGET_H_ + +#include "ui_kcm_keyboard.h" + +#include +#include + +class QWidget; +class KeyboardConfig; +class Rules; +class Flags; +class KComponentData; +class QString; +class QPushButton; +class LayoutsTableModel; +class KCMiscKeyboardWidget; +class KeyboardLayoutActionCollection; + +class KCMKeyboardWidget: public QTabWidget +{ + Q_OBJECT + +public: + KCMKeyboardWidget(Rules* rules, KeyboardConfig* keyboardConfig, + const KComponentData componentData, const QVariantList &args, QWidget* parent=0); + virtual ~KCMKeyboardWidget(); + + void updateUI(); + void save(); + + //temp hack + KCMiscKeyboardWidget* getKcmMiscWidget() const { return kcmMiscWidget; } + +Q_SIGNALS: + void changed(bool state); + +private Q_SLOTS: + void addLayout(); + void removeLayout(); + void layoutSelectionChanged(); + void uiChanged(); + void scrollToGroupShortcut(); + void scrollTo3rdLevelShortcut(); + void clearGroupShortcuts(); + void clear3rdLevelShortcuts(); + void updateXkbShortcutsButtons(); + void moveUp(); + void moveDown(); + void configureLayoutsChanged(); + void configureXkbOptionsChanged(); + void previewLayout(); + +private: + Rules *rules; + Flags *flags; + Ui::TabWidget *uiWidget; + KeyboardConfig *keyboardConfig; + const KComponentData componentData; + KeyboardLayoutActionCollection* actionCollection; + LayoutsTableModel* layoutsTableModel; + KCMiscKeyboardWidget* kcmMiscWidget; + bool uiUpdating; + + void initializeLayoutsUI(); + void initializeXkbOptionsUI(); + void initializeKeyboardModelUI(); + void updateHardwareUI(); + void updateLayoutsUI(); + void updateShortcutsUI(); + void updateXkbOptionsUI(); + void updateSwitcingPolicyUI(); + void updateXkbShortcutButton(const QString& groupName, QPushButton* button); + void clearXkbGroup(const QString& groupName); + void moveSelectedLayouts(int shift); + void populateWithCurrentLayouts(); + void populateWithCurrentXkbOptions(); + void updateLoopCount(); + void handleParameters(const QVariantList &args); +}; + + +#endif /* KCM_KEYBOARD_WIDGET_H_ */ diff --git a/kcontrol/keyboard/kcm_view_models.cpp b/kcontrol/keyboard/kcm_view_models.cpp new file mode 100644 index 00000000..c2241940 --- /dev/null +++ b/kcontrol/keyboard/kcm_view_models.cpp @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "kcm_view_models.h" + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef DRAG_ENABLED +#include +#endif + +#include "keyboard_config.h" +#include "xkb_rules.h" +#include "flags.h" +#include "x11_helper.h" +#include "bindings.h" + +const int LayoutsTableModel::MAP_COLUMN = 0; +const int LayoutsTableModel::LAYOUT_COLUMN = 1; +const int LayoutsTableModel::VARIANT_COLUMN = 2; +const int LayoutsTableModel::DISPLAY_NAME_COLUMN = 3; +const int LayoutsTableModel::SHORTCUT_COLUMN = 4; +static const int COLUMN_COUNT = 5; + +LayoutsTableModel::LayoutsTableModel(Rules* rules_, Flags *flags_, KeyboardConfig* keyboardConfig_, QObject* parent): + QAbstractTableModel(parent), + keyboardConfig(keyboardConfig_), + rules(rules_), + countryFlags(flags_) +{ +} + +void LayoutsTableModel::refresh() +{ + beginResetModel(); + endResetModel(); +} + +int LayoutsTableModel::rowCount(const QModelIndex &/*parent*/) const +{ + return keyboardConfig->layouts.count(); +} + +int LayoutsTableModel::columnCount(const QModelIndex&) const +{ + return COLUMN_COUNT; +} + +Qt::ItemFlags LayoutsTableModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + Qt::ItemFlags flags = QAbstractTableModel::flags(index); + + if( index.column() == DISPLAY_NAME_COLUMN + || index.column() == VARIANT_COLUMN + || index.column() == SHORTCUT_COLUMN ) { + flags |= Qt::ItemIsEditable; + } + +#ifdef DRAG_ENABLED + flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; +#endif + + return flags; +} + +#ifdef DRAG_ENABLED +QStringList LayoutsTableModel::mimeTypes() const +{ + QStringList types; + types << "application/keyboard-layout-item"; + return types; +} + +QMimeData *LayoutsTableModel::mimeData(const QModelIndexList &indexes) const + { + QMimeData *mimeData = new QMimeData(); + QByteArray encodedData; + + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + QSet rows; + foreach (const QModelIndex& index, indexes) { + if (index.isValid()) { + rows << index.row(); + } + } + foreach (int row, rows) { + stream << row; + } + + mimeData->setData("application/keyboard-layout-item", encodedData); + return mimeData; +} +#endif + +QVariant LayoutsTableModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= keyboardConfig->layouts.size()) + return QVariant(); + + const LayoutUnit& layoutUnit = keyboardConfig->layouts.at(index.row()); + + if (role == Qt::DecorationRole) { + switch( index.column() ) { + case DISPLAY_NAME_COLUMN: { +// if( keyboardConfig->isFlagShown() ) { + QIcon icon = countryFlags->getIconWithText(layoutUnit, *keyboardConfig); + return icon.isNull() ? countryFlags->getTransparentPixmap() : icon; +// } + } +//TODO: show the cells are editable +// case VARIANT_COLUMN: { +// case DISPLAY_NAME_COLUMN: { +// int sz = 5; +// QPixmap pm = QPixmap(sz, sz+5); +// pm.fill(Qt::transparent); +// QPainter p(&pm); +// QPoint points[] = { QPoint(0, 0), QPoint(0, sz), QPoint(sz, 0) }; +// p.drawPolygon(points, 3); +// return pm; +// } + break; + } + } + else + if( role == Qt::BackgroundRole ) { + if( keyboardConfig->layoutLoopCount != KeyboardConfig::NO_LOOPING + && index.row() >= keyboardConfig->layoutLoopCount ) { + return QBrush(Qt::lightGray); + } + } + else + if (role == Qt::DisplayRole) { + switch( index.column() ) { + case MAP_COLUMN: + return layoutUnit.layout; + break; + case LAYOUT_COLUMN: { + const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); + return layoutInfo != NULL ? layoutInfo->description : layoutUnit.layout; + } + case VARIANT_COLUMN: { + if( layoutUnit.variant.isEmpty() ) + return QVariant(); + const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); + if( layoutInfo == NULL ) + return QVariant(); + const VariantInfo* variantInfo = layoutInfo->getVariantInfo(layoutUnit.variant); + return variantInfo != NULL ? variantInfo->description : layoutUnit.variant; + } + break; + case DISPLAY_NAME_COLUMN: +// if( keyboardConfig->indicatorType == KeyboardConfig::SHOW_LABEL ) { +// return layoutUnit.getDisplayName(); +// } + break; + case SHORTCUT_COLUMN: { + return layoutUnit.getShortcut().toString(); + } + break; + } + } + else if (role==Qt::EditRole ) { + switch( index.column() ) { + case DISPLAY_NAME_COLUMN: + return layoutUnit.getDisplayName(); + break; + case VARIANT_COLUMN: + return layoutUnit.variant; + break; + case SHORTCUT_COLUMN: + return layoutUnit.getShortcut().toString(); + break; + default:; + } + } + else if( role == Qt::TextAlignmentRole ) { + switch( index.column() ) { + case MAP_COLUMN: + case DISPLAY_NAME_COLUMN: + case SHORTCUT_COLUMN: + return Qt::AlignCenter; + break; + default:; + } + } + return QVariant(); +} + +QVariant LayoutsTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) { + const QString headers[] = {i18nc("layout map name", "Map"), i18n("Layout"), i18n("Variant"), i18n("Label"), i18n("Shortcut")}; + return headers[section]; + } + + return QVariant(); +} + +bool LayoutsTableModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (role != Qt::EditRole + || (index.column() != DISPLAY_NAME_COLUMN && index.column() != VARIANT_COLUMN && index.column() != SHORTCUT_COLUMN) ) + return false; + + if (index.row() >= keyboardConfig->layouts.size()) + return false; + + LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; + + switch( index.column() ) { + case DISPLAY_NAME_COLUMN: { + QString displayText = value.toString().left(3); + layoutUnit.setDisplayName(displayText); + countryFlags->clearCache(); // regenerate the label + } + break; + case VARIANT_COLUMN: { + QString variant = value.toString(); + layoutUnit.variant = variant; + } + break; + case SHORTCUT_COLUMN: { + QString shortcut = value.toString(); + layoutUnit.setShortcut(QKeySequence(shortcut)); + } + break; + } + emit dataChanged(index, index); + + return true; +} + +// +// LabelEditDelegate +// +LabelEditDelegate::LabelEditDelegate(const KeyboardConfig* keyboardConfig_, QObject *parent): + QStyledItemDelegate(parent), + keyboardConfig(keyboardConfig_) +{} + +QWidget *LabelEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option , + const QModelIndex & index ) const +{ + if( keyboardConfig->indicatorType == KeyboardConfig::SHOW_FLAG ) + return NULL; + + QWidget* widget = QStyledItemDelegate::createEditor(parent, option, index); + QLineEdit* lineEdit = static_cast(widget); + if( lineEdit != NULL ) { + lineEdit->setMaxLength(LayoutUnit::MAX_LABEL_LENGTH); + } + return widget; +} + +//void LabelEditDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const +//{ +// QStyleOptionViewItem option2(option); +//// option2.decorationPosition = QStyleOptionViewItem::Right; +// option2.decorationAlignment = Qt::AlignHCenter | Qt::AlignVCenter; +// QStyledItemDelegate::paint(painter, option2, index); +//} + + +// +// VariantComboDelegate +// +//TODO: reuse this function in kcm_add_layout_dialog.cpp +static void populateComboWithVariants(QComboBox* combo, const QString& layout, const Rules* rules) +{ + combo->clear(); + const LayoutInfo* layoutInfo = rules->getLayoutInfo(layout); + foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { + combo->addItem(variantInfo->description, variantInfo->name); + } + combo->model()->sort(0); + combo->insertItem(0, i18nc("variant", "Default"), ""); + combo->setCurrentIndex(0); +} + +VariantComboDelegate::VariantComboDelegate(const KeyboardConfig* keyboardConfig_, const Rules* rules_, QObject *parent): + QStyledItemDelegate(parent), + keyboardConfig(keyboardConfig_), + rules(rules_) +{} + +QWidget *VariantComboDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, + const QModelIndex & index ) const +{ + QComboBox *editor = new QComboBox(parent); + const LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; + populateComboWithVariants(editor, layoutUnit.layout, rules); + return editor; +} + +void VariantComboDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + QComboBox *combo = static_cast(editor); + QString variant = index.model()->data(index, Qt::EditRole).toString(); + int itemIndex = combo->findData(variant); + if( itemIndex == -1 ) { + itemIndex = 0; + } + combo->setCurrentIndex(itemIndex); +} + +void VariantComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const +{ + QComboBox *combo = static_cast(editor); + QString variant = combo->itemData(combo->currentIndex()).toString(); + model->setData(index, variant, Qt::EditRole); +} + +void VariantComboDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, const QModelIndex &/* index */) const +{ + editor->setGeometry(option.rect); +} + +// +// KKeySequenceWidgetDelegate +// +KKeySequenceWidgetDelegate::KKeySequenceWidgetDelegate(const KeyboardConfig* keyboardConfig_, QObject *parent): + QStyledItemDelegate(parent), + keyboardConfig(keyboardConfig_) +{} + +QWidget *KKeySequenceWidgetDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, + const QModelIndex & index ) const +{ + itemsBeingEdited.insert(index); + + KKeySequenceWidget *editor = new KKeySequenceWidget(parent); + editor->setFocusPolicy(Qt::StrongFocus); + editor->setModifierlessAllowed(false); + + const LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; + editor->setKeySequence(layoutUnit.getShortcut()); + + editor->captureKeySequence(); + + return editor; +} + +//void KKeySequenceWidgetDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +//{ +// KKeySequenceWidget *kkeysequencewidget = static_cast(editor); +// QString shortcut = index.model()->data(index, Qt::EditRole).toString(); +// kkeysequencewidget->setKeySequence(QKeySequence(shortcut)); +// kkeysequencewidget->captureKeySequence(); +//// kDebug() << "set editor data"; +//} + +void KKeySequenceWidgetDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const +{ + KKeySequenceWidget *kkeysequencewidget = static_cast(editor); + QString shortcut = kkeysequencewidget->keySequence().toString(); + model->setData(index, shortcut, Qt::EditRole); + itemsBeingEdited.remove(index); +} + +void KKeySequenceWidgetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + if (itemsBeingEdited.contains(index)) { +// StyledBackgroundPainter::drawBackground(painter,option,index); + } + else { + QStyledItemDelegate::paint(painter,option,index); + } +} +// +// Xkb Options Tree View +// + +int XkbOptionsTreeModel::rowCount(const QModelIndex& parent) const { + if( ! parent.isValid() ) + return rules->optionGroupInfos.count(); + if( ! parent.parent().isValid() ) + return rules->optionGroupInfos[parent.row()]->optionInfos.count(); + return 0; +} + +QVariant XkbOptionsTreeModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + int row = index.row(); + + if (role == Qt::DisplayRole) { + if( ! index.parent().isValid() ) { + return rules->optionGroupInfos[row]->description; + } + else { + int groupRow = index.parent().row(); + const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; + return xkbGroup->optionInfos[row]->description; + } + } + else if (role==Qt::CheckStateRole ) { + if( index.parent().isValid() ) { + int groupRow = index.parent().row(); + const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; + const QString& xkbOptionName = xkbGroup->optionInfos[row]->name; + return keyboardConfig->xkbOptions.indexOf(xkbOptionName) == -1 + ? Qt::Unchecked : Qt::Checked; + } + else { + int groupRow = index.row(); + const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; + foreach(const OptionInfo* optionInfo, xkbGroup->optionInfos) { + if( keyboardConfig->xkbOptions.indexOf(optionInfo->name) != -1 ) + return Qt::PartiallyChecked; + } + return Qt::Unchecked; + } + } + return QVariant(); +} + +bool XkbOptionsTreeModel::setData(const QModelIndex & index, const QVariant & value, int role) { + int groupRow = index.parent().row(); + if( groupRow < 0 ) return false; + + const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; + const OptionInfo* option = xkbGroup->optionInfos[index.row()]; + + if( value.toInt() == Qt::Checked ) { + if( xkbGroup->exclusive ) { + // clear if exclusive (TODO: radiobutton) + int idx = keyboardConfig->xkbOptions.indexOf(QRegExp(xkbGroup->name + ".*")); + if( idx >= 0 ) { + for(int i=0; ioptionInfos.count(); i++) + if( xkbGroup->optionInfos[i]->name == keyboardConfig->xkbOptions[idx] ) { + setData(createIndex(i, index.column(), (quint32)index.internalId()-index.row()+i), Qt::Unchecked, role); + break; + } + // m_kxkbConfig->m_options.removeAt(idx); + // idx = m_kxkbConfig->m_options.indexOf(QRegExp(xkbGroupNm+".*")); + } + } + if( keyboardConfig->xkbOptions.indexOf(option->name) < 0 ) { + keyboardConfig->xkbOptions.append(option->name); + } + } + else { + keyboardConfig->xkbOptions.removeAll(option->name); + } + + emit dataChanged(index, index); + emit dataChanged(index.parent(), index.parent()); + return true; +} + +void XkbOptionsTreeModel::gotoGroup(const QString& groupName, QTreeView* view) { + const OptionGroupInfo* optionGroupInfo = rules->getOptionGroupInfo(groupName); + int index = rules->optionGroupInfos.indexOf((OptionGroupInfo*)optionGroupInfo); + if( index != -1 ) { + QModelIndex modelIdx = createIndex(index,0); +// view->selectionModel()->setCurrentIndex(createIndex(index,0), QItemSelectionModel::NoUpdate); + view->setExpanded(modelIdx, true); + view->scrollTo(modelIdx, QAbstractItemView::PositionAtTop); + view->selectionModel()->setCurrentIndex(modelIdx, QItemSelectionModel::Current); + view->setFocus(Qt::OtherFocusReason); + } +// else { +// kDebug() << "can't scroll to group" << group; +// } +} + diff --git a/kcontrol/keyboard/kcm_view_models.h b/kcontrol/keyboard/kcm_view_models.h new file mode 100644 index 00000000..001d3a5a --- /dev/null +++ b/kcontrol/keyboard/kcm_view_models.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KCM_VIEW_MODELS_H_ +#define KCM_VIEW_MODELS_H_ + +#include +#include +#include +#include + +class QTreeView; +class KeyboardConfig; +class Rules; +class Flags; +class KeyboardLayoutActionCollection; + +class LayoutsTableModel : public QAbstractTableModel +{ + Q_OBJECT + + public: + LayoutsTableModel(Rules* rules, Flags *flags, KeyboardConfig* keyboardConfig, QObject *parent = 0); + + int columnCount(const QModelIndex&) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); +#ifdef DRAG_ENABLED + Qt::DropActions supportedDropActions() const { + return Qt::MoveAction; + } + QStringList mimeTypes() const; + QMimeData *mimeData(const QModelIndexList &indexes) const; +#endif + void refresh(); + + static const int MAP_COLUMN; + static const int LAYOUT_COLUMN; + static const int VARIANT_COLUMN; + static const int DISPLAY_NAME_COLUMN; + static const int SHORTCUT_COLUMN; + + private: + KeyboardConfig* keyboardConfig; + const Rules *rules; + Flags *countryFlags; +}; + +class LabelEditDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit LabelEditDelegate(const KeyboardConfig* keyboardConfig, QObject *parent = 0); + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + +// void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + +private: + const KeyboardConfig* keyboardConfig; +}; + +class VariantComboDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + VariantComboDelegate(const KeyboardConfig* keyboardConfig, const Rules* rules, QObject *parent = 0); + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + void setEditorData(QWidget *editor, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; + + void updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, const QModelIndex &index) const; + +private: + const KeyboardConfig* keyboardConfig; + const Rules* rules; +}; + +class KKeySequenceWidgetDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + KKeySequenceWidgetDelegate(const KeyboardConfig* keyboardConfig_, QObject *parent = 0); + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; +// void setEditorData(QWidget *editor, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + +private: + const KeyboardConfig* keyboardConfig; + mutable QSet itemsBeingEdited; +}; + + +class XkbOptionsTreeModel: public QAbstractItemModel +{ +public: + XkbOptionsTreeModel(Rules* rules_, KeyboardConfig* keyboardConfig_, QObject *parent) + : QAbstractItemModel(parent), + keyboardConfig(keyboardConfig_), + rules(rules_) { } + + int columnCount(const QModelIndex& /*parent*/) const { return 1; } + int rowCount(const QModelIndex& parent) const; + QModelIndex parent(const QModelIndex& index) const { + if (!index.isValid() ) + return QModelIndex(); + if( index.internalId() < 100 ) + return QModelIndex(); + return createIndex(((index.internalId() - index.row())/100) - 1, index.column()); + } + QModelIndex index(int row, int column, const QModelIndex& parent) const { + if(!parent.isValid()) return createIndex(row, column); + return createIndex(row, column, (100 * (parent.row()+1)) + row); + } + Qt::ItemFlags flags ( const QModelIndex & index ) const { + if( ! index.isValid() ) + return 0; + + if( !index.parent().isValid() ) + return Qt::ItemIsEnabled; + + return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; + } + + bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); + QVariant data(const QModelIndex& index, int role) const; + void reset() { QAbstractItemModel::reset(); } + void gotoGroup(const QString& group, QTreeView* view); + +private: + KeyboardConfig* keyboardConfig; + Rules *rules; +}; + +#endif /* KCM_VIEW_MODELS_H_ */ diff --git a/kcontrol/keyboard/kcmmisc.cpp b/kcontrol/keyboard/kcmmisc.cpp new file mode 100644 index 00000000..382f026f --- /dev/null +++ b/kcontrol/keyboard/kcmmisc.cpp @@ -0,0 +1,237 @@ +/* + * kcmmisc.cpp + * + * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * + * Layout management, cleanups: + * Copyright (c) 1999 Dirk A. Mueller + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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 "kcmmisc.h" +#include "ui_kcmmiscwidget.h" + +#include + +#include +#include +#include + +#include +#include +#include + +#include + + +KCMiscKeyboardWidget::KCMiscKeyboardWidget(QWidget *parent) + : QWidget(parent), + ui(*new Ui_KeyboardConfigWidget) +{ + ui.setupUi(this); + + ui.delay->setRange(100, 5000, 50); + ui.delay->setSliderEnabled(false); + ui.rate->setRange(0.2, 50, 5, false); + + sliderMax = (int)floor (0.5 + 2*(log(5000.0L)-log(100.0L)) / (log(5000.0L)-log(4999.0L))); + ui.delaySlider->setRange(0, sliderMax); + ui.delaySlider->setSingleStep(sliderMax/100); + ui.delaySlider->setPageStep(sliderMax/10); + ui.delaySlider->setTickInterval(sliderMax/10); + + ui.rateSlider->setRange(20, 5000); + ui.rateSlider->setSingleStep(30); + ui.rateSlider->setPageStep(500); + ui.rateSlider->setTickInterval(498); + + connect(ui.keyboardRepeatButtonGroup, SIGNAL(clicked()), this, SLOT(changed())); + connect(ui.keyboardRepeatButtonGroup, SIGNAL(changed(int)), this, SLOT(keyboardRepeatStateChanged(int))); + connect(ui.delay, SIGNAL(valueChanged(int)), this, SLOT(delaySpinboxChanged(int))); + connect(ui.delaySlider, SIGNAL(valueChanged(int)), this, SLOT(delaySliderChanged(int))); + connect(ui.rate, SIGNAL(valueChanged(double)), this, SLOT(rateSpinboxChanged(double))); + connect(ui.rateSlider, SIGNAL(valueChanged(int)), this, SLOT(rateSliderChanged(int))); + + connect(ui.click, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(ui.numlockButtonGroup, SIGNAL(released(int)), this, SLOT(changed())); + +// Not sure why we need this - if XKB is not found the whole keyboard module won't be compiled +//#if !defined(HAVE_XTEST) && !defined(HAVE_XKB) +// ui.numlockButtonGroup->setDisabled( true ); +//#endif +//#if !defined(HAVE_XKB) && !defined(HAVE_XF86MISC) +// ui.delay->setDisabled( true ); +// ui.rate->setDisabled( true ); +//#endif +} + +KCMiscKeyboardWidget::~KCMiscKeyboardWidget() +{ + delete &ui; +} + +int KCMiscKeyboardWidget::getClick() +{ + return ui.click->value(); +} + +// set the slider and LCD values +void KCMiscKeyboardWidget::setRepeat(TriState keyboardRepeat, int delay_, double rate_) +{ + TriStateHelper::setTriState( ui.keyboardRepeatButtonGroup, keyboardRepeat ); +// ui.repeatBox->setChecked(r == AutoRepeatModeOn); + ui.delay->setValue(delay_); + ui.rate->setValue(rate_); + delaySpinboxChanged(delay_); + rateSpinboxChanged(rate_); +} + +void KCMiscKeyboardWidget::setClickVolume(int v) +{ + ui.click->setValue(v); +} + +TriState TriStateHelper::getTriState(const KButtonGroup* group) +{ + int selected = group->selected(); + return selected < 0 ? STATE_UNCHANGED : getTriState(selected); +} + +void TriStateHelper::setTriState(KButtonGroup* group, TriState state) +{ + group->setSelected( getInt(state) ); +} + +void KCMiscKeyboardWidget::load() +{ + KConfigGroup config(KSharedConfig::openConfig("kcminputrc", KConfig::NoGlobals), "Keyboard"); + + ui.delay->blockSignals(true); + ui.rate->blockSignals(true); + ui.click->blockSignals(true); + + // need to read as string to support old "true/false" parameter + QString key = config.readEntry("KeyboardRepeating", TriStateHelper::getString(STATE_ON)); + if( key == "true" || key == TriStateHelper::getString(STATE_ON)) { + keyboardRepeat = STATE_ON; + } + else if( key == "false" || key == TriStateHelper::getString(STATE_OFF)) { + keyboardRepeat = STATE_OFF; + } + else { + keyboardRepeat = STATE_UNCHANGED; + } + +// keyboardRepeat = (key ? AutoRepeatModeOn : AutoRepeatModeOff); + float delay = config.readEntry( "RepeatDelay", 660 ); + float rate = config.readEntry( "RepeatRate", 25. ); + setRepeat(keyboardRepeat, delay, rate); + + XKeyboardState kbd; + XGetKeyboardControl(QX11Info::display(), &kbd); + + clickVolume = config.readEntry("ClickVolume", kbd.key_click_percent); + setClickVolume(clickVolume); + // setRepeat(kbd.global_auto_repeat, ui.delay->value(), ui.rate->value()); + + numlockState = TriStateHelper::getTriState(config.readEntry( "NumLock", TriStateHelper::getInt(STATE_UNCHANGED) )); + TriStateHelper::setTriState( ui.numlockButtonGroup, numlockState ); + + ui.delay->blockSignals(false); + ui.rate->blockSignals(false); + ui.click->blockSignals(false); +} + +void KCMiscKeyboardWidget::save() +{ + KConfigGroup config(KSharedConfig::openConfig("kcminputrc", KConfig::NoGlobals), "Keyboard"); + + clickVolume = getClick(); + keyboardRepeat = TriStateHelper::getTriState(ui.keyboardRepeatButtonGroup); + numlockState = TriStateHelper::getTriState(ui.numlockButtonGroup); + + config.writeEntry("ClickVolume",clickVolume); + config.writeEntry("KeyboardRepeating", TriStateHelper::getInt(keyboardRepeat)); + config.writeEntry("RepeatRate", ui.rate->value() ); + config.writeEntry("RepeatDelay", ui.delay->value() ); + config.writeEntry("NumLock", TriStateHelper::getInt(numlockState) ); + config.sync(); +} + +void KCMiscKeyboardWidget::defaults() +{ + setClickVolume(50); + setRepeat(STATE_ON, 660, 25); + TriStateHelper::setTriState( ui.numlockButtonGroup, STATE_UNCHANGED ); + emit changed(true); +} + +QString KCMiscKeyboardWidget::quickHelp() const +{ + return QString(); + + /* "

Keyboard

This module allows you to choose options" + " for the way in which your keyboard works. The actual effect of" + " setting these options depends upon the features provided by your" + " keyboard hardware and the X server on which KDE is running.

" + " For example, you may find that changing the key click volume" + " has no effect because this feature is not available on your system." */ +} + +void KCMiscKeyboardWidget::delaySliderChanged (int value) { + double alpha = sliderMax / (log(5000.0L) - log(100.0L)); + double linearValue = exp (value/alpha + log(100.0L)); + + ui.delay->setValue((int)floor(0.5 + linearValue)); + + emit changed(true); +} + +void KCMiscKeyboardWidget::delaySpinboxChanged (int value) { + double alpha = sliderMax / (log(5000.0L) - log(100.0L)); + double logVal = alpha * (log((double)value)-log(100.0L)); + + ui.delaySlider->setValue ((int)floor (0.5 + logVal)); + + emit changed(true); +} + +void KCMiscKeyboardWidget::rateSliderChanged (int value) { + ui.rate->setValue(value/100.0); + + emit changed(true); +} + +void KCMiscKeyboardWidget::rateSpinboxChanged (double value) { + ui.rateSlider->setValue ((int)(value*100)); + + emit changed(true); +} + +void KCMiscKeyboardWidget::changed() +{ + emit changed(true); +} + +void KCMiscKeyboardWidget::keyboardRepeatStateChanged(int selection) +{ + bool enabled = selection == TriStateHelper::getInt(STATE_ON); + ui.keyboardRepeatParamsGroupBox->setEnabled(enabled); + changed(); +} diff --git a/kcontrol/keyboard/kcmmisc.h b/kcontrol/keyboard/kcmmisc.h new file mode 100644 index 00000000..b1c0a535 --- /dev/null +++ b/kcontrol/keyboard/kcmmisc.h @@ -0,0 +1,91 @@ +/* + * keyboard.h + * + * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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 __KCMMISC_H__ +#define __KCMMISC_H__ + +#include +#include + +class Ui_KeyboardConfigWidget; + +enum TriState { + STATE_ON = 0, STATE_OFF = 1, STATE_UNCHANGED = 2 +}; + +class KButtonGroup; +class TriStateHelper { +public: + static void setTriState(KButtonGroup* group, TriState state); + static TriState getTriState(const KButtonGroup* group); + + static TriState getTriState(int state) { return static_cast(state); } + static int getInt(TriState state) { return static_cast(state); } + static const char* getString(TriState state) { + return state == STATE_ON ? "0" : state == STATE_OFF ? "1" : "2"; + } +}; + +class KCMiscKeyboardWidget : public QWidget +{ + Q_OBJECT +public: + KCMiscKeyboardWidget(QWidget *parent); + ~KCMiscKeyboardWidget(); + + void save(); + void load(); + void defaults(); + + QString quickHelp() const; + +private slots: + void changed(); + + void delaySliderChanged (int value); + void delaySpinboxChanged (int value); + void rateSliderChanged (int value); + void rateSpinboxChanged (double value); + void keyboardRepeatStateChanged(int selection); + +Q_SIGNALS: + void changed(bool state); + +private: + void setClickVolume( int ); + void setRepeat( TriState flag, int delay, double rate); + void setRepeatRate( int ); + + int getClick(); + int getRepeatRate(); + + int sliderMax; + int clickVolume; + enum TriState keyboardRepeat; + enum TriState numlockState; + + Ui_KeyboardConfigWidget& ui; +}; + +#endif + diff --git a/kcontrol/keyboard/kcmmiscwidget.ui b/kcontrol/keyboard/kcmmiscwidget.ui new file mode 100644 index 00000000..37fbaf4b --- /dev/null +++ b/kcontrol/keyboard/kcmmiscwidget.ui @@ -0,0 +1,335 @@ + + + KeyboardConfigWidget + + + + 0 + 0 + 577 + 361 + + + + + + + If supported, this option allows you to setup the state of NumLock after KDE startup.<p>You can configure NumLock to be turned on or off, or configure KDE not to set NumLock state. + + + NumLock on KDE Startup + + + + + + true + + + + + + T&urn on + + + + + + + Turn o&ff + + + + + + + Leave unchan&ged + + + + + + + + + + + + + Keyboard Repeat + + + + + + true + + + + + + T&urn on + + + + + + + Turn o&ff + + + + + + + Leave unchan&ged + + + + + + + + + + Qt::Horizontal + + + + 159 + 20 + + + + + + + + + + + false + + + + + + + 0 + 0 + + + + &Delay: + + + delay + + + + + + + If supported, this option allows you to set the delay after which a pressed key will start generating keycodes. The 'Repeat rate' option controls the frequency of these keycodes. + + + 0 + + + 10000 + + + 1000 + + + 1000 + + + 5000 + + + Qt::Horizontal + + + 1000 + + + + + + + If supported, this option allows you to set the delay after which a pressed key will start generating keycodes. The 'Repeat rate' option controls the frequency of these keycodes. + + + ms + + + + + + + + 0 + 0 + + + + &Rate: + + + rate + + + + + + + If supported, this option allows you to set the rate at which keycodes are generated while a key is pressed. + + + 0 + + + 10000 + + + 1000 + + + 1000 + + + 5000 + + + Qt::Horizontal + + + 1000 + + + + + + + If supported, this option allows you to set the rate at which keycodes are generated while a key is pressed. + + + repeats/s + + + + + + + + + + + + + + + + + + Test area: + + + + + + + Allows to test keyboard repeat and click volume (just don't forget to apply the changes). + + + + + + + + + Key Click + + + + + + + + If supported, this option allows you to hear audible clicks from your computer's speakers when you press the keys on your keyboard. This might be useful if your keyboard does not have mechanical keys, or if the sound that the keys make is very soft.<p>You can change the loudness of the key click feedback by dragging the slider button or by clicking the up/down arrows on the spin box. Setting the volume to 0% turns off the key click. + + + Key click &volume: + + + click + + + + + + + 100 + + + 10 + + + Qt::Horizontal + + + QSlider::NoTicks + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Horizontal + + + + + + + + KDoubleNumInput + QWidget +

knuminput.h
+ 1 + + + KButtonGroup + QGroupBox +
kbuttongroup.h
+ 1 +
+ + KIntNumInput + QWidget +
knuminput.h
+ 1 +
+ + + + diff --git a/kcontrol/keyboard/keyboard.desktop b/kcontrol/keyboard/keyboard.desktop new file mode 100644 index 00000000..a2a4654c --- /dev/null +++ b/kcontrol/keyboard/keyboard.desktop @@ -0,0 +1,75 @@ +[Desktop Entry] +Type=Service +Icon=preferences-desktop-keyboard +X-KDE-ServiceTypes=KDEDModule +X-KDE-Library=keyboard +X-KDE-DBus-ModuleName=keyboard +X-KDE-Kded-autoload=true +X-KDE-Kded-load-on-demand=false +X-KDE-Kded-phase=1 +OnlyShowIn=KDE; + +Name=Keyboard Daemon +Name[ar]=مراقب لوحة المفاتيح +Name[ast]=Degorriu de tecláu +Name[bg]=Демон на клавиатурата +Name[bn]=কীবোর্ড ডীমন +Name[bs]=Demon tastature +Name[ca]=Dimoni del teclat +Name[ca@valencia]=Dimoni del teclat +Name[cs]=Démon klávesnice +Name[da]=Tastatur-dæmon +Name[de]=Tastatur-Dienst +Name[el]=Δαίμονας Πληκτρολογίου +Name[en_GB]=Keyboard Dæmon +Name[es]=Demonio de teclado +Name[et]=Klaviatuurideemon +Name[eu]=Teklatuaren daimona +Name[fi]=Näppäimistötaustaprosessi +Name[fr]=Démon du clavier +Name[ga]=Deamhan Méarchláir +Name[gl]=Daemon do teclado +Name[gu]=કીબોર્ડ ડિમન +Name[he]=תהליך רקע של המקלדת +Name[hi]=कुंजीपट डेमन +Name[hr]=Tipkovnički servis +Name[hu]=Billentyűzetszolgáltatás +Name[ia]=Demone de claviero +Name[id]=Jurik Papan Ketik +Name[is]=Lyklaborðspúki +Name[it]=Demone della tastiera +Name[ja]=キーボードデーモン +Name[kk]=Перенетақта қызметі +Name[km]=ដេមិន​​ក្ដារចុច +Name[kn]=ಕೀಲಿಮಣೆ ನೇಪಥಿಕ +Name[ko]=키보드 데몬 +Name[lt]=Klaviatūros tarnyba +Name[lv]=Tastatūras dēmons +Name[mr]=कळफलक डीमन +Name[nb]=Tastatur-daemon +Name[nds]=Tastatuur-Dämoon +Name[nl]=Toetsenbord-daemon +Name[nn]=Tastaturteneste +Name[pa]=ਕੀ-ਬੋਰਡ ਡੈਮਨ +Name[pl]=Demon klawiatury +Name[pt]=Servidor do Teclado +Name[pt_BR]=Daemon de teclado +Name[ro]=Demon de tastatură +Name[ru]=Фоновая служба клавиатуры +Name[si]=යතුරුපුවරු ඩීමනය +Name[sk]=Démon klávesnice +Name[sl]=Ozadnji program za tipkovnico +Name[sr]=Демон тастатуре +Name[sr@ijekavian]=Демон тастатуре +Name[sr@ijekavianlatin]=Demon tastature +Name[sr@latin]=Demon tastature +Name[sv]=Tangentbordsdemon +Name[th]=ดีมอนแป้นพิมพ์ +Name[tr]=Klavye Servisi +Name[ug]=ھەرپتاختا نازارەتچى +Name[uk]=Фонова служба клавіатури +Name[vi]=Trình nền bàn phím +Name[wa]=Démon del taprece +Name[x-test]=xxKeyboard Daemonxx +Name[zh_CN]=键盘守护进程 +Name[zh_TW]=鍵盤伺服程式 diff --git a/kcontrol/keyboard/keyboard_applet.cpp b/kcontrol/keyboard/keyboard_applet.cpp new file mode 100644 index 00000000..85422d8b --- /dev/null +++ b/kcontrol/keyboard/keyboard_applet.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "keyboard_applet.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "x11_helper.h" +#include "xkb_rules.h" +#include "keyboard_config.h" +#include "keyboard_dbus.h" +#include "layouts_menu.h" +//#include "utils.h" + + +K_EXPORT_PLASMA_APPLET(keyboard, KeyboardApplet) + +KeyboardApplet::KeyboardApplet(QObject *parent, const QVariantList &args): + Plasma::Applet(parent, args), + xEventNotifier(), + rules(Rules::readRules(Rules::READ_EXTRAS)), + keyboardConfig(new KeyboardConfig()), + layoutsMenu(new LayoutsMenu(*keyboardConfig, *rules, flags)) +{ + if( ! X11Helper::xkbSupported(NULL) ) { + setFailedToLaunch(true, i18n("XKB extension failed to initialize")); + return; + } + + m_svg = new Plasma::Svg(this); + m_svg->setImagePath("widgets/labeltexture"); + m_svg->setContainsMultipleImages(true); + resize(48,48); + + setHasConfigurationInterface(false); + + setAspectRatioMode(Plasma::KeepAspectRatio); + //setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); + setBackgroundHints(DefaultBackground); + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeChanged())); + + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.connect(QString(), KEYBOARD_DBUS_OBJECT_PATH, KEYBOARD_DBUS_SERVICE_NAME, KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE, this, SLOT(configChanged())); +} + +KeyboardApplet::~KeyboardApplet() +{ + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.disconnect(QString(), KEYBOARD_DBUS_OBJECT_PATH, KEYBOARD_DBUS_SERVICE_NAME, KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE, this, SLOT(configChanged())); + + delete layoutsMenu; + delete rules; +} + +void KeyboardApplet::keyboardConfigChanged() +{ + readConfig(); + update(); +} + +void KeyboardApplet::readConfig() +{ +// KConfigGroup config = Plasma::Applet::config("KeyboardLayout"); + keyboardConfig->load(); +// drawFlag = keyboardConfig->readEntry("ShowFlag", true); +} + +void KeyboardApplet::configChanged() +{ + Applet::configChanged(); + readConfig(); +} + +void KeyboardApplet::init() +{ + Applet::init(); + + readConfig(); + connect(&xEventNotifier, SIGNAL(layoutChanged()), this, SLOT(layoutChanged())); + connect(&xEventNotifier, SIGNAL(layoutMapChanged()), this, SLOT(layoutChanged())); + xEventNotifier.start(); + + layoutChanged(); +} + +void KeyboardApplet::destroy() +{ + xEventNotifier.stop(); + disconnect(&xEventNotifier, SIGNAL(layoutMapChanged()), this, SLOT(layoutChanged())); + disconnect(&xEventNotifier, SIGNAL(layoutChanged()), this, SLOT(layoutChanged())); + Applet::destroy(); +} + +void KeyboardApplet::layoutChanged() +{ + generatePixmap(); + updateTooltip(); + update(); +} + +void KeyboardApplet::updateTooltip() +{ + LayoutUnit layoutUnit = X11Helper::getCurrentLayout(); + if( layoutUnit.isEmpty() ) + return; + + const QIcon icon(getFlag(layoutUnit.layout)); + Plasma::ToolTipContent data(name(), flags.getLongText(layoutUnit, rules), icon); + Plasma::ToolTipManager::self()->setContent(this, data); +} + +const QIcon KeyboardApplet::getFlag(const QString& layout) +{ + return keyboardConfig->isFlagShown() ? flags.getIcon(layout) : QIcon(); +} + +void KeyboardApplet::paintInterface(QPainter *p, const QStyleOptionGraphicsItem */*option*/, const QRect &contentsRect) +{ + LayoutUnit layoutUnit = X11Helper::getCurrentLayout(); + if( layoutUnit.isEmpty() ) + return; + + const QIcon icon(getFlag(layoutUnit.layout)); + if( ! icon.isNull() ) { + p->save(); + p->setRenderHint(QPainter::SmoothPixmapTransform); + p->setRenderHint(QPainter::Antialiasing); + QPixmap pixmap = icon.pixmap(contentsRect.size()); + p->drawPixmap(contentsRect, pixmap); + p->restore(); + } + if( icon.isNull() || keyboardConfig->isLabelShown() ) { + QRect finalRect(m_pixmap.rect()); + finalRect.moveCenter(contentsRect.center()); + p->drawPixmap(finalRect, m_pixmap); + } +} + +void KeyboardApplet::mousePressEvent ( QGraphicsSceneMouseEvent * event ) +{ + if( event->button() == Qt::LeftButton ) { + X11Helper::switchToNextLayout(); + } + event->ignore(); +} + +void KeyboardApplet::constraintsEvent(Plasma::Constraints constraints) +{ + if (constraints & Plasma::FormFactorConstraint) { + int iconSize; + if (formFactor() == Plasma::Planar || + formFactor() == Plasma::MediaCenter) { + iconSize = IconSize(KIconLoader::Desktop); + } else { + iconSize = IconSize(KIconLoader::Small); + } + setMinimumSize(iconSize, iconSize); + } + if (constraints & Plasma::SizeConstraint) { + generatePixmap(); + } +} + +void KeyboardApplet::generatePixmap() +{ + LayoutUnit layoutUnit = X11Helper::getCurrentLayout(); + QRect contentsRect = KeyboardApplet::contentsRect().toRect(); + QString shortText = Flags::getShortText(layoutUnit, *keyboardConfig); + + QPixmap pixmap(contentsRect.size()); + pixmap.fill(Qt::transparent); + + QFont font = Plasma::Theme::defaultTheme()->font(Plasma::Theme::DesktopFont); + int height = qMin(contentsRect.height(), contentsRect.width()); + int fontSize = shortText.length() == 2 + ? height * 13 / 15 + : height * 5 / 15; + + int smallestReadableSize = KGlobalSettings::smallestReadableFont().pixelSize(); + if( fontSize < smallestReadableSize ) { + fontSize = smallestReadableSize; + } + font.setPixelSize(fontSize); + if( keyboardConfig->isFlagShown() ) { + m_pixmap = Plasma::PaintUtils::shadowText(shortText, font, Qt::black, Qt::white, QPoint(), 3); + } + else { + m_pixmap = Plasma::PaintUtils::texturedText(shortText, font, m_svg); + } +} + +QList KeyboardApplet::contextualActions() +{ + return layoutsMenu->contextualActions(); +} diff --git a/kcontrol/keyboard/keyboard_applet.h b/kcontrol/keyboard/keyboard_applet.h new file mode 100644 index 00000000..2fb9c98f --- /dev/null +++ b/kcontrol/keyboard/keyboard_applet.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KEYBOARD_APPLET_H_ +#define KEYBOARD_APPLET_H_ + +#include + +#include + +#include "x11_helper.h" +#include "flags.h" + +class QGraphicsSceneMouseEvent; +class QAction; +class KConfigDialog; +class QActionGroup; +class Rules; +class KeyboardConfig; +class LayoutsMenu; + +class KeyboardApplet : public Plasma::Applet +{ + Q_OBJECT + +public Q_SLOTS: + void init(); + void destroy(); + +private Q_SLOTS: + void configChanged(); + void layoutChanged(); + +public: + KeyboardApplet(QObject *parent, const QVariantList &args); + virtual ~KeyboardApplet(); + + void constraintsEvent(Plasma::Constraints constraints); + void paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect); + +protected: + void mousePressEvent ( QGraphicsSceneMouseEvent *event ); + QList contextualActions(); + void generatePixmap(); +// void createConfigurationInterface(KConfigDialog *parent); + +private Q_SLOTS: + void keyboardConfigChanged(); + +private: + void readConfig(); + const QIcon getFlag(const QString& layout); + void updateTooltip(); + +// bool drawFlag; + Flags flags; + XEventNotifier xEventNotifier; + const Rules* rules; + KeyboardConfig* keyboardConfig; + LayoutsMenu* layoutsMenu; + Plasma::Svg *m_svg; + QPixmap m_pixmap; +}; + +#endif /* KEYBOARD_APPLET_H_ */ diff --git a/kcontrol/keyboard/keyboard_config.cpp b/kcontrol/keyboard/keyboard_config.cpp new file mode 100644 index 00000000..f3ff97ca --- /dev/null +++ b/kcontrol/keyboard/keyboard_config.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "keyboard_config.h" + +#include +#include +#include + + +static const char* SWITCHING_POLICIES[] = {"Global", "Desktop", "WinClass", "Window", NULL }; +static const char* LIST_SEPARATOR = ","; +//static const char* DEFAULT_LAYOUT = "us"; +static const char* DEFAULT_MODEL = "pc104"; + +static const QString CONFIG_FILENAME("kxkbrc"); +static const QString CONFIG_GROUPNAME("Layout"); + +const int KeyboardConfig::NO_LOOPING = -1; + +KeyboardConfig::KeyboardConfig() +{ + setDefaults(); +} + +QString KeyboardConfig::getSwitchingPolicyString(SwitchingPolicy switchingPolicy) { + return SWITCHING_POLICIES[switchingPolicy]; +} + +static int findStringIndex(const char* strings[], const QString& toFind, int defaultIndex) +{ + for(int i=0; strings[i] != NULL; i++) { + if( toFind == strings[i] ) { + return i; + } + } + return defaultIndex; +} + +void KeyboardConfig::setDefaults() +{ + keyboardModel = DEFAULT_MODEL; + resetOldXkbOptions = false; + xkbOptions.clear(); + + // init layouts options + configureLayouts = false; + layouts.clear(); +// layouts.append(LayoutUnit(DEFAULT_LAYOUT)); + layoutLoopCount = NO_LOOPING; + + // switch cotrol options + switchingPolicy = SWITCH_POLICY_GLOBAL; +// stickySwitching = false; +// stickySwitchingDepth = 2; + + // display options + showIndicator = true; + indicatorType = SHOW_LABEL; + showSingle = false; +} + +static +KeyboardConfig::IndicatorType getIndicatorType(bool showFlag, bool showLabel) +{ + if( showFlag ) { + if( showLabel ) + return KeyboardConfig::SHOW_LABEL_ON_FLAG; + else + return KeyboardConfig::SHOW_FLAG; + } + else { + return KeyboardConfig::SHOW_LABEL; + } +} + + +void KeyboardConfig::load() +{ + KConfigGroup config(KSharedConfig::openConfig( CONFIG_FILENAME, KConfig::NoGlobals ), CONFIG_GROUPNAME); + + keyboardModel = config.readEntry("Model", ""); + + resetOldXkbOptions = config.readEntry("ResetOldOptions", false); + QString options = config.readEntry("Options", ""); + xkbOptions = options.split(LIST_SEPARATOR, QString::SkipEmptyParts); + + configureLayouts = config.readEntry("Use", false); + QString layoutsString = config.readEntry("LayoutList", ""); + QStringList layoutStrings = layoutsString.split(LIST_SEPARATOR, QString::SkipEmptyParts); +// if( layoutStrings.isEmpty() ) { +// layoutStrings.append(DEFAULT_LAYOUT); +// } + layouts.clear(); + foreach(const QString& layoutString, layoutStrings) { + layouts.append(LayoutUnit(layoutString)); + } + if( layouts.isEmpty() ) { + configureLayouts = false; + } + + layoutLoopCount = config.readEntry("LayoutLoopCount", NO_LOOPING); + + QString layoutMode = config.readEntry("SwitchMode", "Global"); + switchingPolicy = static_cast(findStringIndex(SWITCHING_POLICIES, layoutMode, SWITCH_POLICY_GLOBAL)); + + showIndicator = config.readEntry("ShowLayoutIndicator", true); + + bool showFlag = config.readEntry("ShowFlag", false); + bool showLabel = config.readEntry("ShowLabel", true); + indicatorType = getIndicatorType(showFlag, showLabel); + + showSingle = config.readEntry("ShowSingle", false); + + QString labelsStr = config.readEntry("DisplayNames", ""); + QStringList labels = labelsStr.split(LIST_SEPARATOR, QString::KeepEmptyParts); + for(int i=0; i KeyboardConfig::getDefaultLayouts() const +{ + QList defaultLayoutList; + int i = 0; + foreach(const LayoutUnit& layoutUnit, layouts) { + defaultLayoutList.append(layoutUnit); + if( layoutLoopCount != KeyboardConfig::NO_LOOPING && i >= layoutLoopCount-1 ) + break; + i++; + } + return defaultLayoutList; +} + +QList KeyboardConfig::getExtraLayouts() const +{ + if( layoutLoopCount == KeyboardConfig::NO_LOOPING ) + return QList(); + + return layouts.mid(layoutLoopCount, layouts.size()); +} diff --git a/kcontrol/keyboard/keyboard_config.h b/kcontrol/keyboard/keyboard_config.h new file mode 100644 index 00000000..b86418de --- /dev/null +++ b/kcontrol/keyboard/keyboard_config.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KEYBOARD_CONFIG_H_ +#define KEYBOARD_CONFIG_H_ + +#include "x11_helper.h" + +#include +#include +#include +#include +#include + +/** + * This class provides configuration options for keyboard module + */ +class KeyboardConfig +{ +public: + static const int MAX_LABEL_LEN = 3; + static const int NO_LOOPING; // = -1; + + enum SwitchingPolicy { + SWITCH_POLICY_GLOBAL = 0, + SWITCH_POLICY_DESKTOP = 1, + SWITCH_POLICY_APPLICATION = 2, + SWITCH_POLICY_WINDOW = 3 + }; + + enum IndicatorType { + SHOW_LABEL = 0, + SHOW_FLAG = 1, + SHOW_LABEL_ON_FLAG = 2 + }; + + QString keyboardModel; + // resetOldXkbOptions is now also "set xkb options" + bool resetOldXkbOptions; + QStringList xkbOptions; + + // init layouts options + bool configureLayouts; + QList layouts; + int layoutLoopCount; + + // switch cotrol options + SwitchingPolicy switchingPolicy; +// bool stickySwitching; +// int stickySwitchingDepth; + + // display options + bool showIndicator; + IndicatorType indicatorType; + bool showSingle; + + KeyboardConfig(); + bool isSpareLayoutsEnabled() const { + return layoutLoopCount != KeyboardConfig::NO_LOOPING; + } + QList getDefaultLayouts() const; + QList getExtraLayouts() const; + bool isFlagShown() const { + return indicatorType == SHOW_FLAG || indicatorType == SHOW_LABEL_ON_FLAG; + } + bool isLabelShown() const { + return indicatorType == SHOW_LABEL || indicatorType == SHOW_LABEL_ON_FLAG; + } + + void setDefaults(); + void load(); + void save(); + + static QString getSwitchingPolicyString(SwitchingPolicy switchingPolicy); +}; + +#endif /* KEYBOARD_CONFIG_H_ */ diff --git a/kcontrol/keyboard/keyboard_daemon.cpp b/kcontrol/keyboard/keyboard_daemon.cpp new file mode 100644 index 00000000..eb9061f3 --- /dev/null +++ b/kcontrol/keyboard/keyboard_daemon.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "keyboard_daemon.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "x11_helper.h" +#include "xinput_helper.h" +#include "xkb_helper.h" +#include "keyboard_dbus.h" +#include "xkb_rules.h" +#include "bindings.h" +#include "keyboard_hardware.h" +#include "layout_tray_icon.h" +#include "layout_memory_persister.h" +#include "layouts_menu.h" + + +K_PLUGIN_FACTORY(KeyboardFactory, registerPlugin();) +K_EXPORT_PLUGIN(KeyboardFactory("keyboard", "kxkb")) + +KeyboardDaemon::KeyboardDaemon(QObject *parent, const QList&) + : KDEDModule(parent), + actionCollection(NULL), + xEventNotifier(NULL), + layoutTrayIcon(NULL), + layoutMemory(keyboardConfig), + rules(Rules::readRules(Rules::READ_EXTRAS)) +{ + if( ! X11Helper::xkbSupported(NULL) ) + return; //TODO: shut down the daemon? + + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerService(KEYBOARD_DBUS_SERVICE_NAME); + dbus.registerObject(KEYBOARD_DBUS_OBJECT_PATH, this, QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportScriptableSignals); + dbus.connect(QString(), KEYBOARD_DBUS_OBJECT_PATH, KEYBOARD_DBUS_SERVICE_NAME, KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE, this, SLOT(configureKeyboard())); + + configureKeyboard(); + registerListeners(); + + LayoutMemoryPersister layoutMemoryPersister(layoutMemory); + if( layoutMemoryPersister.restore(KGlobal::mainComponent().componentName()) ) { + if( layoutMemoryPersister.getGlobalLayout().isValid() ) { + X11Helper::setLayout(layoutMemoryPersister.getGlobalLayout()); + } + } +} + +KeyboardDaemon::~KeyboardDaemon() +{ + LayoutMemoryPersister layoutMemoryPersister(layoutMemory); + layoutMemoryPersister.setGlobalLayout(X11Helper::getCurrentLayout()); + layoutMemoryPersister.save(KGlobal::mainComponent().componentName()); + + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.disconnect(QString(), KEYBOARD_DBUS_OBJECT_PATH, KEYBOARD_DBUS_SERVICE_NAME, KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE, this, SLOT(configureKeyboard())); + dbus.unregisterObject(KEYBOARD_DBUS_OBJECT_PATH); + dbus.unregisterService(KEYBOARD_DBUS_SERVICE_NAME); + + unregisterListeners(); + unregisterShortcut(); + + delete xEventNotifier; + delete layoutTrayIcon; + delete rules; +} + +void KeyboardDaemon::configureKeyboard() +{ + kDebug() << "Configuring keyboard"; + init_keyboard_hardware(); + + keyboardConfig.load(); + XkbHelper::initializeKeyboardLayouts(keyboardConfig); + layoutMemory.configChanged(); + + setupTrayIcon(); + + unregisterShortcut(); + registerShortcut(); +} + +void KeyboardDaemon::configureMouse() +{ + QStringList modules; + modules << "mouse"; + QProcess::startDetached("kcminit", modules); +} + +void KeyboardDaemon::setupTrayIcon() +{ + bool show = keyboardConfig.showIndicator + && ( keyboardConfig.showSingle || X11Helper::getLayoutsList().size() > 1 ); + + if( show && ! layoutTrayIcon ) { + layoutTrayIcon = new LayoutTrayIcon(rules, keyboardConfig); + } + else if( ! show && layoutTrayIcon ) { + delete layoutTrayIcon; + layoutTrayIcon = NULL; + } +} + +void KeyboardDaemon::registerShortcut() +{ + if( actionCollection == NULL ) { + actionCollection = new KeyboardLayoutActionCollection(this, false); + + KAction* toggleLayoutAction = actionCollection->getToggeAction(); + connect(toggleLayoutAction, SIGNAL(triggered()), this, SLOT(switchToNextLayout())); + actionCollection->loadLayoutShortcuts(keyboardConfig.layouts, rules); + connect(actionCollection, SIGNAL(actionTriggered(QAction*)), this, SLOT(setLayout(QAction*))); + + connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(globalSettingsChanged(int))); + } +} + +void KeyboardDaemon::unregisterShortcut() +{ + // register KDE keyboard shortcut for switching layouts + if( actionCollection != NULL ) { + disconnect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(globalSettingsChanged(int))); + + disconnect(actionCollection, SIGNAL(actionTriggered(QAction*)), this, SLOT(setLayout(QAction*))); + disconnect(actionCollection->getToggeAction(), SIGNAL(triggered()), this, SLOT(switchToNextLayout())); + + delete actionCollection; + actionCollection = NULL; + } +} + +void KeyboardDaemon::registerListeners() +{ + if( xEventNotifier == NULL ) { + xEventNotifier = new XInputEventNotifier(); + } + connect(xEventNotifier, SIGNAL(newPointerDevice()), this, SLOT(configureMouse())); + connect(xEventNotifier, SIGNAL(newKeyboardDevice()), this, SLOT(configureKeyboard())); + connect(xEventNotifier, SIGNAL(layoutMapChanged()), this, SLOT(layoutMapChanged())); + connect(xEventNotifier, SIGNAL(layoutChanged()), this, SLOT(layoutChanged())); + xEventNotifier->start(); +} + +void KeyboardDaemon::unregisterListeners() +{ + if( xEventNotifier != NULL ) { + xEventNotifier->stop(); + disconnect(xEventNotifier, SIGNAL(newPointerDevice()), this, SLOT(configureMouse())); + disconnect(xEventNotifier, SIGNAL(newKeyboardDevice()), this, SLOT(configureKeyboard())); + disconnect(xEventNotifier, SIGNAL(layoutChanged()), this, SLOT(layoutChanged())); + disconnect(xEventNotifier, SIGNAL(layoutMapChanged()), this, SLOT(layoutMapChanged())); + } +} + +void KeyboardDaemon::globalSettingsChanged(int category) +{ + if ( category == KGlobalSettings::SETTINGS_SHORTCUTS) { +//TODO: optimize this? seems like we'll get configReload and globalShortcuts from kcm so we'll reconfigure twice + unregisterShortcut(); + registerShortcut(); + } +} + +void KeyboardDaemon::layoutChanged() +{ + //TODO: pass newLayout into layoutTrayIcon? + LayoutUnit newLayout = X11Helper::getCurrentLayout(); + + layoutMemory.layoutChanged(); + if( layoutTrayIcon != NULL ) { + layoutTrayIcon->layoutChanged(); + } + + if( newLayout != currentLayout ) { + currentLayout = newLayout; + emit currentLayoutChanged(newLayout.toString()); + } +} + +void KeyboardDaemon::layoutMapChanged() +{ + keyboardConfig.load(); + layoutMemory.layoutMapChanged(); + emit layoutListChanged(); + if( layoutTrayIcon != NULL ) { + layoutTrayIcon->layoutMapChanged(); + } +} + +void KeyboardDaemon::switchToNextLayout() +{ + kDebug() << "Toggling layout"; + X11Helper::switchToNextLayout(); +} + +bool KeyboardDaemon::setLayout(QAction* action) +{ + if( action == actionCollection->getToggeAction() ) + return false; + + LayoutUnit layoutUnit(action->data().toString()); + return LayoutsMenu::switchToLayout(layoutUnit, keyboardConfig); // need this to be able to switch to spare layouts +// return X11Helper::setLayout(LayoutUnit(action->data().toString())); +} + +bool KeyboardDaemon::setLayout(const QString& layout) +{ + return X11Helper::setLayout(LayoutUnit(layout)); +} + +QString KeyboardDaemon::getCurrentLayout() +{ + return X11Helper::getCurrentLayout().toString(); +} + +QStringList KeyboardDaemon::getLayoutsList() +{ + return X11Helper::getLayoutsListAsString( X11Helper::getLayoutsList() ); +} diff --git a/kcontrol/keyboard/keyboard_daemon.h b/kcontrol/keyboard/keyboard_daemon.h new file mode 100644 index 00000000..5b778663 --- /dev/null +++ b/kcontrol/keyboard/keyboard_daemon.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KEYBOARD_DAEMON_H_ +#define KEYBOARD_DAEMON_H_ + +#include +#include + +#include "layout_memory.h" +#include "keyboard_dbus.h" +#include "bindings.h" + + +class KActionCollection; +class XInputEventNotifier; +class LayoutTrayIcon; +class KeyboardConfig; +class KAction; +class Rules; + +class KDE_EXPORT KeyboardDaemon : public KDEDModule +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.KeyboardLayouts") + + KeyboardConfig keyboardConfig; + KeyboardLayoutActionCollection *actionCollection; + XInputEventNotifier* xEventNotifier; + LayoutTrayIcon* layoutTrayIcon; + LayoutMemory layoutMemory; + LayoutUnit currentLayout; + const Rules* rules; + + void registerListeners(); + void registerShortcut(); + void unregisterListeners(); + void unregisterShortcut(); + void setupTrayIcon(); + +private Q_SLOTS: + void switchToNextLayout(); + void globalSettingsChanged(int category); + void configureKeyboard(); + void configureMouse(); + void layoutChanged(); + void layoutMapChanged(); + bool setLayout(QAction* action); + +public Q_SLOTS: + Q_SCRIPTABLE bool setLayout(const QString& layout); + Q_SCRIPTABLE QString getCurrentLayout(); + Q_SCRIPTABLE QStringList getLayoutsList(); + +Q_SIGNALS: + Q_SCRIPTABLE void currentLayoutChanged(QString layout); + Q_SCRIPTABLE void layoutListChanged(); + +public: + KeyboardDaemon(QObject *parent, const QList&); + virtual ~KeyboardDaemon(); +}; + +#endif /* KEYBOARD_DAEMON_H_ */ diff --git a/kcontrol/keyboard/keyboard_dbus.h b/kcontrol/keyboard/keyboard_dbus.h new file mode 100644 index 00000000..4ea39668 --- /dev/null +++ b/kcontrol/keyboard/keyboard_dbus.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KEYBOARD_DBUS_H_ +#define KEYBOARD_DBUS_H_ + +#define KEYBOARD_DBUS_SERVICE_NAME "org.kde.keyboard" +#define KEYBOARD_DBUS_OBJECT_PATH "/Layouts" +#define KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE "reloadConfig" + +#endif /* KEYBOARD_DBUS_H_ */ diff --git a/kcontrol/keyboard/keyboard_hardware.cpp b/kcontrol/keyboard/keyboard_hardware.cpp new file mode 100644 index 00000000..d116eb2a --- /dev/null +++ b/kcontrol/keyboard/keyboard_hardware.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 +#include // WTF? - otherwise compiler complains + +#include + +#include + +#include "x11_helper.h" +#include "kcmmisc.h" + +// from numlockx.c +extern "C" void numlockx_change_numlock_state(Display* dpy, int state); + +#include +#include + + +// This code is taken from xset utility from XFree 4.3 (http://www.xfree86.org/) + +static +void set_repeatrate(int delay, double rate) +{ + if( !X11Helper::xkbSupported(NULL) ) { + kError() << "Failed to set keyboard repeat rate: xkb is not supported"; + return; + } + + XkbDescPtr xkb = XkbAllocKeyboard(); + if (xkb) { + Display* dpy = QX11Info::display(); + int res = XkbGetControls(dpy, XkbRepeatKeysMask, xkb); + xkb->ctrls->repeat_delay = delay; + xkb->ctrls->repeat_interval = (int)floor(1000/rate + 0.5); + res = XkbSetControls(dpy, XkbRepeatKeysMask, xkb); + XkbFreeKeyboard(xkb, 0, true); + return; + } +} + +static +int set_volume(int clickVolumePercent, TriState keyboardRepeatMode) +{ + XKeyboardState kbd; + XKeyboardControl kbdc; + + XGetKeyboardControl(QX11Info::display(), &kbd); + + int flags = 0; + if( clickVolumePercent != -1 ) { + flags |= KBKeyClickPercent; + kbdc.key_click_percent = clickVolumePercent; + } + if( keyboardRepeatMode != STATE_UNCHANGED ) { + flags |= KBAutoRepeatMode; + kbdc.auto_repeat_mode = (keyboardRepeatMode==STATE_ON ? AutoRepeatModeOn : AutoRepeatModeOff); + } + + return XChangeKeyboardControl(QX11Info::display(), flags, &kbdc); +} + +void init_keyboard_hardware() +{ + KConfigGroup config(KSharedConfig::openConfig( "kcminputrc" ), "Keyboard"); + + QString keyRepeatStr = config.readEntry("KeyboardRepeating", TriStateHelper::getString(STATE_ON)); + TriState keyRepeat = STATE_UNCHANGED; + if( keyRepeatStr == "true" || keyRepeatStr == TriStateHelper::getString(STATE_ON) ) { + keyRepeat = STATE_ON; + } + else if( keyRepeatStr == "false" || keyRepeatStr == TriStateHelper::getString(STATE_OFF) ) { + keyRepeat = STATE_OFF; + } + + int clickVolumePercent = config.readEntry("ClickVolume", -1); + if( clickVolumePercent != -1 && keyRepeat != STATE_UNCHANGED ) { + set_volume(clickVolumePercent, keyRepeat); + } + + if( keyRepeat == STATE_ON ) { + int delay_ = config.readEntry("RepeatDelay", 250); + double rate_ = config.readEntry("RepeatRate", 30.); + set_repeatrate(delay_, rate_); + } + + + TriState numlockState = TriStateHelper::getTriState( config.readEntry( "NumLock", TriStateHelper::getInt(STATE_UNCHANGED) ) ); + if( numlockState != STATE_UNCHANGED ) { + numlockx_change_numlock_state(QX11Info::display(), numlockState == STATE_ON ); + } +} diff --git a/kcontrol/keyboard/keyboard_hardware.h b/kcontrol/keyboard/keyboard_hardware.h new file mode 100644 index 00000000..e3daa80b --- /dev/null +++ b/kcontrol/keyboard/keyboard_hardware.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 KEYBOARD_HARDWARE_H_ +#define KEYBOARD_HARDWARE_H_ + +void init_keyboard_hardware(); + +#endif /* KEYBOARD_HARDWARE_H_ */ diff --git a/kcontrol/keyboard/layout_memory.cpp b/kcontrol/keyboard/layout_memory.cpp new file mode 100644 index 00000000..6940245a --- /dev/null +++ b/kcontrol/keyboard/layout_memory.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "layout_memory.h" + +#include +#include + +#include +#include + +#include "x11_helper.h" +#include "xkb_helper.h" + + +LayoutMemory::LayoutMemory(const KeyboardConfig& keyboardConfig_): + prevLayoutList(X11Helper::getLayoutsList()), + keyboardConfig(keyboardConfig_) +{ + registerListeners(); +} + +LayoutMemory::~LayoutMemory() +{ + unregisterListeners(); +} + +void LayoutMemory::configChanged() +{ +// this->layoutMap.clear(); // if needed this will be done on layoutMapChanged event + unregisterListeners(); + registerListeners(); +} + +void LayoutMemory::registerListeners() +{ + if( keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_WINDOW + || keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_APPLICATION ) { + connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(windowChanged(WId))); +// connect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)), this, SLOT(windowRemoved(WId))); + } + if( keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_DESKTOP ) { + connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(desktopChanged(int))); + } +} + +void LayoutMemory::unregisterListeners() +{ + disconnect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(windowChanged(WId))); + disconnect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(desktopChanged(int))); +// disconnect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)), this, SLOT(windowRemoved(WId))); +} + +QString LayoutMemory::getCurrentMapKey() { + switch(keyboardConfig.switchingPolicy) { + case KeyboardConfig::SWITCH_POLICY_WINDOW: { + WId wid = KWindowSystem::self()->activeWindow(); + KWindowInfo winInfo = KWindowSystem::windowInfo(wid, NET::WMWindowType); + NET::WindowType windowType = winInfo.windowType( NET::NormalMask | NET::DesktopMask | NET::DialogMask ); + kDebug() << "window type" << windowType; + + // we ignore desktop type so that our keybaord layout applet on desktop could change layout properly + if( windowType == NET::Desktop ) + return previousLayoutMapKey; + if( windowType != NET::Unknown && windowType != NET::Normal && windowType != NET::Dialog ) + return QString(); + + return QString::number(wid); + } + case KeyboardConfig::SWITCH_POLICY_APPLICATION: { + WId wid = KWindowSystem::self()->activeWindow(); + KWindowInfo winInfo = KWindowSystem::windowInfo(wid, NET::WMWindowType, NET::WM2WindowClass); + NET::WindowType windowType = winInfo.windowType( NET::NormalMask | NET::DesktopMask | NET::DialogMask ); + kDebug() << "window type" << windowType; + + // we ignore desktop type so that our keybaord layout applet on desktop could change layout properly + if( windowType == NET::Desktop ) + return previousLayoutMapKey; + if( windowType != NET::Unknown && windowType != NET::Normal && windowType != NET::Dialog ) + return QString(); + + // shall we use pid or window class ??? - class seems better (see e.g. https://bugs.kde.org/show_bug.cgi?id=245507) + // for window class shall we use class.class or class.name? (seem class.class is a bit better - more app-oriented) + kDebug() << "New active window with class.class: " << winInfo.windowClassClass(); + return QString(winInfo.windowClassClass()); +// NETWinInfo winInfoForPid( QX11Info::display(), wid, QX11Info::appRootWindow(), NET::WMPid); +// return QString::number(winInfoForPid.pid()); + } + case KeyboardConfig::SWITCH_POLICY_DESKTOP: + return QString::number(KWindowSystem::self()->currentDesktop()); + default: + return QString(); + } +} + +static +bool isExtraSubset(const QList& allLayouts, const QList& newList) +{ + if( allLayouts.first() != newList.first() ) + return false; + foreach(const LayoutUnit& layoutUnit, newList) { + if( ! allLayouts.contains(layoutUnit) ) + return false; + } + return true; +} + +void LayoutMemory::layoutMapChanged() +{ + QList newLayoutList(X11Helper::getLayoutsList()); + + if( prevLayoutList == newLayoutList ) + return; + + kDebug() << "Layout map change: " << LayoutSet::toString(prevLayoutList) << "-->" << LayoutSet::toString(newLayoutList); + prevLayoutList = newLayoutList; + + //TODO: need more thinking here on how to support external map resetting + if( keyboardConfig.configureLayouts + && keyboardConfig.isSpareLayoutsEnabled() + && isExtraSubset(keyboardConfig.layouts, newLayoutList) ) { + kDebug() << "Layout map change for extra layout"; + layoutChanged(); // to remember new map for active "window" + } + else { +// if( newLayoutList != keyboardConfig.getDefaultLayouts() ) { + // layoutList = newLayoutList; + kDebug() << "Layout map change from external source: clearing layout memory"; + layoutMap.clear(); +// } + } +} + +void LayoutMemory::layoutChanged() +{ + QString layoutMapKey = getCurrentMapKey(); + if( layoutMapKey.isEmpty() ) + return; + + layoutMap[ layoutMapKey ] = X11Helper::getCurrentLayouts(); +} + +void LayoutMemory::setCurrentLayoutFromMap() +{ + QString layoutMapKey = getCurrentMapKey(); + if( layoutMapKey.isEmpty() ) + return; + + if( ! layoutMap.contains(layoutMapKey) ) { +// kDebug() << "new key for layout map" << layoutMapKey; + + if( ! X11Helper::isDefaultLayout() ) { +// kDebug() << "setting default layout for container key" << layoutMapKey; + if( keyboardConfig.configureLayouts && keyboardConfig.isSpareLayoutsEnabled() + && X11Helper::getLayoutsList() != keyboardConfig.getDefaultLayouts() ) { + XkbHelper::initializeKeyboardLayouts(keyboardConfig.getDefaultLayouts()); + } + X11Helper::setDefaultLayout(); + } + } + else { + LayoutSet layoutFromMap = layoutMap[layoutMapKey]; + kDebug() << "Setting layout map item" << layoutFromMap.currentLayout.toString() + << "for container key" << layoutMapKey; + + LayoutSet currentLayouts = X11Helper::getCurrentLayouts(); + if( layoutFromMap.layouts != currentLayouts.layouts ) { + if( keyboardConfig.configureLayouts && keyboardConfig.isSpareLayoutsEnabled() ) { + XkbHelper::initializeKeyboardLayouts(layoutFromMap.layouts); + } + X11Helper::setLayout( layoutFromMap.currentLayout ); + } + else if( layoutFromMap.currentLayout != currentLayouts.currentLayout ) { + X11Helper::setLayout( layoutFromMap.currentLayout ); + } + } + + previousLayoutMapKey = layoutMapKey; +} + +//#include +//#include + +void LayoutMemory::windowChanged(WId /*wId*/) +{ +// KPluginInfo::List plugins = Plasma::Containment::listContainments(); +// foreach(KPluginInfo info, plugins) { +// kDebug() << "applets" << info.name(); +// } + setCurrentLayoutFromMap(); +} + +void LayoutMemory::desktopChanged(int /*desktop*/) +{ + setCurrentLayoutFromMap(); +} diff --git a/kcontrol/keyboard/layout_memory.h b/kcontrol/keyboard/layout_memory.h new file mode 100644 index 00000000..df8568c2 --- /dev/null +++ b/kcontrol/keyboard/layout_memory.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 LAYOUT_MEMORY_H_ +#define LAYOUT_MEMORY_H_ + +#include +#include +#include //For WId + +#include "x11_helper.h" +#include "keyboard_config.h" + +class LayoutMemoryPersister; + +class LayoutMemory : public QObject +{ + Q_OBJECT + + // if there's some transient windows coming up we'll need to either ignore it + // or in case of layout switcher popup menu to apply new layout to previous key + QString previousLayoutMapKey; + QList prevLayoutList; + const KeyboardConfig& keyboardConfig; + + void registerListeners(); + void unregisterListeners(); + QString getCurrentMapKey(); + void setCurrentLayoutFromMap(); + +public Q_SLOTS: + void layoutMapChanged(); + void layoutChanged(); + void windowChanged(WId wId); + void desktopChanged(int desktop); + +public: + LayoutMemory(const KeyboardConfig& keyboardConfig); + virtual ~LayoutMemory(); + + void configChanged(); + +protected: + //QVariant does not support long for WId so we'll use QString for key instead + QMap layoutMap; + + friend class LayoutMemoryPersister; +}; + +#endif /* LAYOUT_MEMORY_H_ */ diff --git a/kcontrol/keyboard/layout_memory_persister.cpp b/kcontrol/keyboard/layout_memory_persister.cpp new file mode 100644 index 00000000..8a6118aa --- /dev/null +++ b/kcontrol/keyboard/layout_memory_persister.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2011 Andriy Rysin (rysin@kde.org) + * + * 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 "layout_memory_persister.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "keyboard_config.h" +#include "layout_memory.h" + + +static const char* VERSION = "1.0"; +static const char* DOC_NAME = "LayoutMap"; +static const char* ROOT_NODE = "LayoutMap"; +static const char* VERSION_ATTRIBUTE = "version"; +static const char* SWITCH_MODE_ATTRIBUTE = "SwitchMode"; +static const char* ITEM_NODE = "item"; +static const QString CURRENT_LAYOUT_ATTRIBUTE("currentLayout"); +static const char* OWNER_KEY_ATTRIBUTE = "ownerKey"; +static const char* LAYOUTS_ATTRIBUTE = "layouts"; + +static const char* LIST_SEPARATOR_LM = ","; + +static const char* REL_SESSION_FILE_PATH = "/session/keyboard/layout_memory.xml"; + +QString LayoutMemoryPersister::getLayoutMapAsString() +{ + if( ! canPersist() ) + return ""; + + QDomDocument doc(DOC_NAME); + QDomElement root = doc.createElement(ROOT_NODE); + root.setAttribute(VERSION_ATTRIBUTE, VERSION); + root.setAttribute(SWITCH_MODE_ATTRIBUTE, KeyboardConfig::getSwitchingPolicyString(layoutMemory.keyboardConfig.switchingPolicy)); + doc.appendChild(root); + + if( layoutMemory.keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_GLOBAL ) { + if( ! globalLayout.isValid() ) + return ""; + + QDomElement item = doc.createElement(ITEM_NODE); + item.setAttribute(CURRENT_LAYOUT_ATTRIBUTE, globalLayout.toString()); + root.appendChild(item); + } + else { + foreach(const QString& key , layoutMemory.layoutMap.keys()) { + QDomElement item = doc.createElement(ITEM_NODE); + item.setAttribute(OWNER_KEY_ATTRIBUTE, key); + item.setAttribute(CURRENT_LAYOUT_ATTRIBUTE, layoutMemory.layoutMap[key].currentLayout.toString()); + + QString layoutSetString; + foreach(const LayoutUnit& layoutUnit, layoutMemory.layoutMap[key].layouts) { + if( ! layoutSetString.isEmpty() ) { + layoutSetString += LIST_SEPARATOR_LM; + } + layoutSetString += layoutUnit.toString(); + } + item.setAttribute(LAYOUTS_ATTRIBUTE, layoutSetString); + root.appendChild(item); + } + } + + return doc.toString(); +} + +static bool isRestoreSession() +{ + KConfigGroup c(KSharedConfig::openConfig("ksmserverrc", KConfig::NoGlobals), "General"); + kDebug() << "loginMode:" << c.readEntry("loginMode"); + QString loginMode = c.readEntry("loginMode"); + return loginMode != "default" && loginMode != "restoreSavedSession"; // we don't know how to restore saved session - only previous one +} + +bool LayoutMemoryPersister::save(const QString& moduleName) +{ + if( isRestoreSession() ) { + QString relPath = moduleName + REL_SESSION_FILE_PATH; + QFile file(KStandardDirs::locateLocal("data", relPath)); + return saveToFile(file); + } + return false; +} + +bool LayoutMemoryPersister::restore(const QString& moduleName) +{ + if( isRestoreSession() ) { + QString relPath = moduleName + REL_SESSION_FILE_PATH; + QFile file(KStandardDirs::locateLocal("data", relPath)); + return restoreFromFile(file); + } + return false; +} + + +bool LayoutMemoryPersister::saveToFile(const QFile& file_) +{ + QString xml = getLayoutMapAsString(); + if( xml.isEmpty() ) + return false; + + QFile file(file_.fileName()); // so we don't expose the file we open/close to the caller + if( ! file.open( QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) ) { + kWarning() << "Failed to open layout memory xml file for writing" << file.fileName(); + return false; + } + + QTextStream out(&file); + out << xml; + out.flush(); + + if( file.error() != QFile::NoError ) { + kWarning() << "Failed to store keyboard layout memory, error" << file.error(); + file.close(); + file.remove(); + return false; + } + else { + kDebug() << "Keyboard layout memory stored into" << file.fileName() << "written" << file.pos(); + return true; + } +} + + +class MapHandler : public QXmlDefaultHandler +{ +public: + MapHandler(const KeyboardConfig::SwitchingPolicy& switchingPolicy_): + verified(false), + switchingPolicy(switchingPolicy_) {} + + bool startElement(const QString &/*namespaceURI*/, const QString &/*localName*/, + const QString &qName, const QXmlAttributes &attributes) { + + if( qName == ROOT_NODE ) { + if( attributes.value(VERSION_ATTRIBUTE) != VERSION ) + return false; + if( attributes.value(SWITCH_MODE_ATTRIBUTE) != KeyboardConfig::getSwitchingPolicyString(switchingPolicy) ) + return false; + + verified = true; + } + if( qName == ITEM_NODE ) { + if( ! verified ) + return false; + + if( switchingPolicy == KeyboardConfig::SWITCH_POLICY_GLOBAL ) { + globalLayout = LayoutUnit(attributes.value(CURRENT_LAYOUT_ATTRIBUTE)); + } + else { + QStringList layoutStrings = attributes.value(LAYOUTS_ATTRIBUTE).split(LIST_SEPARATOR_LM); + LayoutSet layoutSet; + foreach(const QString& layoutString, layoutStrings) { + layoutSet.layouts.append(LayoutUnit(layoutString)); + } + layoutSet.currentLayout = LayoutUnit(attributes.value(CURRENT_LAYOUT_ATTRIBUTE)); + QString ownerKey = attributes.value(OWNER_KEY_ATTRIBUTE); + + if( ownerKey.trimmed().isEmpty() || ! layoutSet.isValid() ) + return false; + + layoutMap[ownerKey] = layoutSet; + } + } + return verified; + } + + bool verified; + QMap layoutMap; + LayoutUnit globalLayout; + +private: + const KeyboardConfig::SwitchingPolicy& switchingPolicy; +}; + +template +static +bool containsAll(QList set1, QList set2) +{ + foreach(const T& t, set2) { + if( ! set1.contains(t) ) + return false; + } + return true; +} + +bool LayoutMemoryPersister::restoreFromFile(const QFile& file_) +{ + globalLayout = LayoutUnit(); + + if( ! canPersist() ) + return false; + + QFile file(file_.fileName()); // so we don't expose the file we open/close to the caller + if( ! file.open( QIODevice::ReadOnly | QIODevice::Text ) ) { + kWarning() << "Failed to open layout memory xml file for reading" << file.fileName() << "error:" << file.error(); + return false; + } + + MapHandler mapHandler(layoutMemory.keyboardConfig.switchingPolicy); + + QXmlSimpleReader reader; + reader.setContentHandler(&mapHandler); + reader.setErrorHandler(&mapHandler); + + QXmlInputSource xmlInputSource(&file); + kDebug() << "Restoring keyboard layout map from" << file.fileName(); + + if( ! reader.parse(xmlInputSource) ) { + kWarning() << "Failed to parse the layout memory file" << file.fileName(); + return false; + } + + if( layoutMemory.keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_GLOBAL ) { + if( mapHandler.globalLayout.isValid() && layoutMemory.keyboardConfig.layouts.contains(mapHandler.globalLayout)) { + globalLayout = mapHandler.globalLayout; + kDebug() << "Restored global layout" << globalLayout.toString(); + } + } + else { + layoutMemory.layoutMap.clear(); + foreach(const QString& key, mapHandler.layoutMap.keys()) { + if( containsAll(layoutMemory.keyboardConfig.layouts, mapHandler.layoutMap[key].layouts) ) { + layoutMemory.layoutMap.insert(key, mapHandler.layoutMap[key]); + } + } + kDebug() << "Restored layouts for" << layoutMemory.layoutMap.size() << "containers"; + } + return true; +} + +bool LayoutMemoryPersister::canPersist() { + // we can't persist per window - as we're using window id which is not preserved between sessions + bool windowMode = layoutMemory.keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_WINDOW; + if( windowMode ) { + kDebug() << "Not saving session for window mode"; + } + return !windowMode; +} diff --git a/kcontrol/keyboard/layout_memory_persister.h b/kcontrol/keyboard/layout_memory_persister.h new file mode 100644 index 00000000..8c4b3c5f --- /dev/null +++ b/kcontrol/keyboard/layout_memory_persister.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 Andriy Rysin (rysin@kde.org) + * + * 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 LAYOUT_MEMORY_PERSISTER_H_ +#define LAYOUT_MEMORY_PERSISTER_H_ + +#include + +#include "x11_helper.h" + +class LayoutMemory; +class QFile; + +class LayoutMemoryPersister { +public: + LayoutMemoryPersister(LayoutMemory& layoutMemory_): + layoutMemory(layoutMemory_) {} + + bool saveToFile(const QFile& file); + bool restoreFromFile(const QFile& file); + + bool save(const QString& moduleName); + bool restore(const QString& moduleName); + + LayoutUnit getGlobalLayout() const { return globalLayout; } + void setGlobalLayout(const LayoutUnit& layout) { globalLayout = layout; } + +private: + LayoutMemory& layoutMemory; + LayoutUnit globalLayout; + + QString getLayoutMapAsString(); + + bool canPersist(); +}; + +#endif /* LAYOUT_MEMORY_PERSISTER_H_ */ diff --git a/kcontrol/keyboard/layout_tray_icon.cpp b/kcontrol/keyboard/layout_tray_icon.cpp new file mode 100644 index 00000000..85eac9e4 --- /dev/null +++ b/kcontrol/keyboard/layout_tray_icon.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "layout_tray_icon.h" + +//#include +#include +#include +#include + +#include "xkb_rules.h" +#include "x11_helper.h" +#include "xkb_helper.h" +#include "keyboard_config.h" +#include "flags.h" +#include "layouts_menu.h" + + +// +// Layout Tray Icon +// +LayoutTrayIcon::LayoutTrayIcon(const Rules* rules_, const KeyboardConfig& keyboardConfig_): + keyboardConfig(keyboardConfig_), + rules(rules_), + flags(new Flags()), + layoutsMenu(new LayoutsMenu(keyboardConfig_, *rules, *flags)) +{ + m_notifierItem = new KStatusNotifierItem(this); + m_notifierItem->setCategory(KStatusNotifierItem::SystemServices); + m_notifierItem->setStatus(KStatusNotifierItem::Active); + m_notifierItem->setToolTipTitle(i18nc("tooltip title", "Keyboard Layout")); + m_notifierItem->setTitle(i18nc("tooltip title", "Keyboard Layout")); + + KMenu* menu = new KMenu(""); + m_notifierItem->setContextMenu(menu); + m_notifierItem->setStandardActionsEnabled(false); + + layoutMapChanged(); + + m_notifierItem->setStatus(KStatusNotifierItem::Active); + + init(); +} + +LayoutTrayIcon::~LayoutTrayIcon() +{ + destroy(); + delete flags; + delete layoutsMenu; +} + +void LayoutTrayIcon::init() +{ + connect(m_notifierItem, SIGNAL(activateRequested(bool,QPoint)), this, SLOT(toggleLayout())); + connect(m_notifierItem, SIGNAL(scrollRequested(int,Qt::Orientation)), this, SLOT(scrollRequested(int,Qt::Orientation))); + connect(flags, SIGNAL(pixmapChanged()), this, SLOT(layoutChanged())); +} + +void LayoutTrayIcon::destroy() +{ + disconnect(flags, SIGNAL(pixmapChanged()), this, SLOT(layoutChanged())); + disconnect(m_notifierItem, SIGNAL(scrollRequested(int,Qt::Orientation)), this, SLOT(scrollRequested(int,Qt::Orientation))); + disconnect(m_notifierItem, SIGNAL(activateRequested(bool,QPoint)), this, SLOT(toggleLayout())); +} + +void LayoutTrayIcon::layoutMapChanged() +{ + flags->clearCache(); + + KMenu* menu = m_notifierItem->contextMenu(); + menu->clear(); + QList actions = layoutsMenu->contextualActions(); + menu->addActions(actions); + + layoutChanged(); +} + +void LayoutTrayIcon::layoutChanged() +{ + LayoutUnit layoutUnit = X11Helper::getCurrentLayout(); + if( layoutUnit.isEmpty() ) + return; + +// QString shortText = Flags::getShortText(layoutUnit, *keyboardConfig); +// kDebug() << "systray: LayoutChanged" << layoutUnit.toString() << shortText; + QString longText = Flags::getLongText(layoutUnit, rules); + + m_notifierItem->setToolTipSubTitle(longText); + + const QIcon icon(getFlag(layoutUnit.layout)); + m_notifierItem->setToolTipIconByPixmap(icon); + + QIcon textOrIcon = flags->getIconWithText(layoutUnit, keyboardConfig); + m_notifierItem->setIconByPixmap( textOrIcon ); +} + +void LayoutTrayIcon::toggleLayout() +{ + X11Helper::switchToNextLayout(); +} + +void LayoutTrayIcon::scrollRequested(int delta, Qt::Orientation /*orientation*/) +{ + X11Helper::scrollLayouts(delta > 0 ? 1 : -1); +} + +const QIcon LayoutTrayIcon::getFlag(const QString& layout) const +{ + return keyboardConfig.isFlagShown() ? flags->getIcon(layout) : QIcon(); +} diff --git a/kcontrol/keyboard/layout_tray_icon.h b/kcontrol/keyboard/layout_tray_icon.h new file mode 100644 index 00000000..1ed4dda6 --- /dev/null +++ b/kcontrol/keyboard/layout_tray_icon.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 LAYOUT_TRAY_ICON_H_ +#define LAYOUT_TRAY_ICON_H_ + +#include +#include + +#include "flags.h" +#include "x11_helper.h" + +class KeyboardConfig; +class LayoutsMenu; + +/** + * System tray icon to show layouts + */ +class KStatusNotifierItem; +class QActionGroup; +class Rules; +class Flags; +class LayoutTrayIcon : public QObject +{ + Q_OBJECT + +public: + LayoutTrayIcon(const Rules* rules, const KeyboardConfig& keyboardConfig); + ~LayoutTrayIcon(); + + void layoutMapChanged(); + +public Q_SLOTS: + void layoutChanged(); + +private Q_SLOTS: + void toggleLayout(); + void scrollRequested(int, Qt::Orientation); + +private: + void init(); + void destroy(); + const QIcon getFlag(const QString& layout) const; + + const KeyboardConfig& keyboardConfig; + const Rules* rules; + Flags* flags; + KStatusNotifierItem *m_notifierItem; + LayoutsMenu* layoutsMenu; +}; + + +#endif /* LAYOUT_WIDGET_H_ */ diff --git a/kcontrol/keyboard/layout_widget.cpp b/kcontrol/keyboard/layout_widget.cpp new file mode 100644 index 00000000..07ef0a56 --- /dev/null +++ b/kcontrol/keyboard/layout_widget.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "layout_widget.h" + +//#include +#include + +#include + +#include "xkb_rules.h" +#include "x11_helper.h" +#include "xkb_helper.h" +#include "keyboard_config.h" +#include "flags.h" + + +K_PLUGIN_FACTORY(LayoutWidgetFactory, registerPlugin();) +K_EXPORT_PLUGIN(LayoutWidgetFactory("keyboard_layout_widget")) + + +LayoutWidget::LayoutWidget(QWidget* parent, const QList& /*args*/): + QWidget(parent), + xEventNotifier(), + keyboardConfig(new KeyboardConfig()), + flags(new Flags()) +{ + if( ! X11Helper::xkbSupported(NULL) ) { +// setFailedToLaunch(true, "XKB extension failed to initialize"); + hide(); + return; + } + + keyboardConfig->load(); + bool show = // keyboardConfig->showIndicator && + ( keyboardConfig->showSingle || X11Helper::getLayoutsList().size() > 1 ); + if( ! show ) { + hide(); + return; + } + + widget = new QPushButton(this); + widget->setFlat(true); + + layoutChanged(); + init(); +} + +LayoutWidget::~LayoutWidget() +{ + destroy(); +} + +void LayoutWidget::init() +{ + connect(widget, SIGNAL(clicked(bool)), this, SLOT(toggleLayout())); + connect(&xEventNotifier, SIGNAL(layoutChanged()), this, SLOT(layoutChanged())); + connect(&xEventNotifier, SIGNAL(layoutMapChanged()), this, SLOT(layoutChanged())); + xEventNotifier.start(); +} + +void LayoutWidget::destroy() +{ + xEventNotifier.stop(); + disconnect(&xEventNotifier, SIGNAL(layoutMapChanged()), this, SLOT(layoutChanged())); + disconnect(&xEventNotifier, SIGNAL(layoutChanged()), this, SLOT(layoutChanged())); +} + +void LayoutWidget::toggleLayout() +{ + X11Helper::switchToNextLayout(); +} + +void LayoutWidget::layoutChanged() +{ + LayoutUnit layoutUnit = X11Helper::getCurrentLayout(); + if( layoutUnit.isEmpty() ) + return; + + QIcon icon; + if( keyboardConfig->isFlagShown() ) { + icon = flags->getIcon(layoutUnit.layout); + } + + QString longText = Flags::getLongText(layoutUnit, NULL); + if( ! icon.isNull() ) { + widget->setIcon(icon); + widget->setText(""); + widget->setToolTip(longText); + } + else { + QString shortText = Flags::getShortText(layoutUnit, *keyboardConfig); + widget->setIcon(icon); + widget->setText(shortText); + widget->setToolTip(longText); +// widget->setShortcut(QKeySequence()); + } +} + diff --git a/kcontrol/keyboard/layout_widget.h b/kcontrol/keyboard/layout_widget.h new file mode 100644 index 00000000..77d50a20 --- /dev/null +++ b/kcontrol/keyboard/layout_widget.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 LAYOUT_WIDGET_H_ +#define LAYOUT_WIDGET_H_ + +#include +#include + +#include "flags.h" +#include "x11_helper.h" + +class QPushButton; +class KeyboardConfig; +class LayoutsMenu; + +/** + * Note: does not listen to configuration changes as currently we only use it in screen lock dialog + */ +class LayoutWidget : public QWidget +{ + Q_OBJECT + +public: + explicit LayoutWidget(QWidget* parent = 0, const QList& args = QList()); + virtual ~LayoutWidget(); + +private Q_SLOTS: + void toggleLayout(); + void layoutChanged(); + // void configChanged(); + +private: + void init(); + void destroy(); + + XEventNotifier xEventNotifier; + QPushButton* widget; + KeyboardConfig* keyboardConfig; + Flags* flags; +}; + +#endif /* LAYOUT_WIDGET_H_ */ diff --git a/kcontrol/keyboard/layouts_menu.cpp b/kcontrol/keyboard/layouts_menu.cpp new file mode 100644 index 00000000..5b9a62e5 --- /dev/null +++ b/kcontrol/keyboard/layouts_menu.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "layouts_menu.h" + +#include +#include +#include +#include + +#include +#include + +#include "keyboard_config.h" +#include "x11_helper.h" +#include "xkb_helper.h" +#include "flags.h" + + +LayoutsMenu::LayoutsMenu(const KeyboardConfig& keyboardConfig_, const Rules& rules_, Flags& flags_): + keyboardConfig(keyboardConfig_), + rules(rules_), + flags(flags_), + actionGroup(NULL) +{ +} + +LayoutsMenu::~LayoutsMenu() +{ + delete actionGroup; +} + +const QIcon LayoutsMenu::getFlag(const QString& layout) const +{ + return keyboardConfig.isFlagShown() ? flags.getIcon(layout) : QIcon(); +} + +void LayoutsMenu::actionTriggered(QAction* action) +{ + QString data = action->data().toString(); + if( data == "config" ) { + QStringList args; + args << "--args=--tab=layouts"; + args << "kcm_keyboard"; + KToolInvocation::kdeinitExec("kcmshell4", args); + } + else { + LayoutUnit layoutUnit(LayoutUnit(action->data().toString())); + switchToLayout(layoutUnit, keyboardConfig); + } +} + +int LayoutsMenu::switchToLayout(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) +{ + QList layouts = X11Helper::getCurrentLayouts().layouts; + + bool res; + if( layouts.contains(layoutUnit) ) { + res = X11Helper::setLayout(layoutUnit); + } + else if ( keyboardConfig.isSpareLayoutsEnabled() && keyboardConfig.layouts.contains(layoutUnit) ) { + QList layouts(keyboardConfig.getDefaultLayouts()); + layouts.removeLast(); + layouts.append(layoutUnit); + XkbHelper::initializeKeyboardLayouts(layouts); + res = X11Helper::setLayout(layoutUnit); + } + else { + kWarning() << "switchToLayout with unknown layout" << layoutUnit.toString(); + res = -1; + } + return res; +} + +QAction* LayoutsMenu::createAction(const LayoutUnit& layoutUnit) const +{ + QString menuText = Flags::getFullText(layoutUnit, keyboardConfig, &rules); + QAction* action = new QAction(getFlag(layoutUnit.layout), menuText, actionGroup); + action->setData(layoutUnit.toString()); + //FIXME: tooltips don't work on dbusmenus??? +// if( ! layoutUnit.getShortcut().isEmpty() ) { +// action->setToolTip(layoutUnit.getShortcut().toString()); +// } + return action; +} + +QList LayoutsMenu::contextualActions() +{ + if( actionGroup ) { + disconnect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(actionTriggered(QAction*))); + delete actionGroup; + } + actionGroup = new QActionGroup(this); + + X11Helper::getLayoutsList(); //UGLY: seems to be more reliable with extra call + QList currentLayouts = X11Helper::getLayoutsList(); + foreach(const LayoutUnit& layoutUnit, currentLayouts) { + QAction* action = createAction(layoutUnit); + actionGroup->addAction(action); + } + + if( keyboardConfig.configureLayouts ) { + QList extraLayouts = keyboardConfig.layouts; + foreach(const LayoutUnit& layoutUnit, currentLayouts) { + extraLayouts.removeOne(layoutUnit); + } + if( extraLayouts.size() > 0 ) { + QAction* separator = new QAction(actionGroup); + separator->setSeparator(true); + actionGroup->addAction(separator); + + foreach(const LayoutUnit& layoutUnit, extraLayouts) { + QAction* action = createAction(layoutUnit); + actionGroup->addAction(action); + } + } + } + + QAction* separator = new QAction(actionGroup); + separator->setSeparator(true); + actionGroup->addAction(separator); + QAction* configAction = new QAction(i18n("Configure..."), actionGroup); + actionGroup->addAction(configAction); + configAction->setData("config"); + connect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(actionTriggered(QAction*))); + return actionGroup->actions(); +} diff --git a/kcontrol/keyboard/layouts_menu.h b/kcontrol/keyboard/layouts_menu.h new file mode 100644 index 00000000..db2f3ff5 --- /dev/null +++ b/kcontrol/keyboard/layouts_menu.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 LAYOUTS_MENU_H_ +#define LAYOUTS_MENU_H_ + +#include +#include + +class QAction; +class KeyboardConfig; +class Flags; +class Rules; +class QActionGroup; +class LayoutUnit; + +class LayoutsMenu : public QObject +{ + Q_OBJECT + +public: + LayoutsMenu(const KeyboardConfig& keyboardConfig, const Rules& rules, Flags& flags); + virtual ~LayoutsMenu(); + + QList contextualActions(); + static int switchToLayout(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig); + +private Q_SLOTS: + void actionTriggered(QAction* action); + +private: + const QIcon getFlag(const QString& layout) const; + QAction* createAction(const LayoutUnit& layoutUnit) const; + + const KeyboardConfig& keyboardConfig; + const Rules& rules; + Flags& flags; + QActionGroup* actionGroup; +}; + +#endif /* LAYOUTS_MENU_H_ */ diff --git a/kcontrol/keyboard/numlockx.c b/kcontrol/keyboard/numlockx.c new file mode 100644 index 00000000..0ac7cfbd --- /dev/null +++ b/kcontrol/keyboard/numlockx.c @@ -0,0 +1,305 @@ +/**************************************************************************** + + NumLockX + + $Id: main.c,v 1.10 2001/04/30 20:55:20 seli Exp $ + + Copyright (C) 2000-2001 Lubos Lunak + Copyright (C) 2001 Oswald Buddenhagen + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +****************************************************************************/ + +#include + +#include + +#include + +#ifdef HAVE_XTEST +#include +#endif + +#ifdef HAVE_XKB +#include +#endif + +#include + +static +Display* dpy; + +/* the XKB stuff is based on code created by Oswald Buddenhagen */ +#ifdef HAVE_XKB +static +int xkb_init() + { + int xkb_opcode, xkb_event, xkb_error; + int xkb_lmaj = XkbMajorVersion; + int xkb_lmin = XkbMinorVersion; + return XkbLibraryVersion( &xkb_lmaj, &xkb_lmin ) + && XkbQueryExtension( dpy, &xkb_opcode, &xkb_event, &xkb_error, + &xkb_lmaj, &xkb_lmin ); + } + +static +unsigned int xkb_mask_modifier( XkbDescPtr xkb, const char *name ) + { + int i; + if( !xkb || !xkb->names ) + return 0; + for( i = 0; + i < XkbNumVirtualMods; + i++ ) + { + char* modStr = XGetAtomName( xkb->dpy, xkb->names->vmods[i] ); + if( modStr != NULL && strcmp(name, modStr) == 0 ) + { + unsigned int mask; + XkbVirtualModsToReal( xkb, 1 << i, &mask ); + return mask; + } + } + return 0; + } + +static +unsigned int xkb_numlock_mask() + { + XkbDescPtr xkb; + if(( xkb = XkbGetKeyboard( dpy, XkbAllComponentsMask, XkbUseCoreKbd )) != NULL ) + { + unsigned int mask = xkb_mask_modifier( xkb, "NumLock" ); + XkbFreeKeyboard( xkb, 0, True ); + return mask; + } + return 0; + } + +static +int xkb_set_on() + { + unsigned int mask; + if( !xkb_init()) + return 0; + mask = xkb_numlock_mask(); + if( mask == 0 ) + return 0; + XkbLockModifiers ( dpy, XkbUseCoreKbd, mask, mask); + return 1; + } + +static +int xkb_set_off() + { + unsigned int mask; + if( !xkb_init()) + return 0; + mask = xkb_numlock_mask(); + if( mask == 0 ) + return 0; + XkbLockModifiers ( dpy, XkbUseCoreKbd, mask, 0); + return 1; + } + +#ifdef NUMLOCKX_STANDALONE +static +int xkb_toggle() + { + unsigned int mask; + unsigned int numlockState; + XkbStateRec xkbState; + if( !xkb_init()) + return 0; + mask = xkb_numlock_mask(); + if( mask == 0 ) + return 0; + XkbGetState( dpy, XkbUseCoreKbd, &xkbState); + numlockState = xkbState.locked_mods & mask; + if (numlockState) + XkbLockModifiers ( dpy, XkbUseCoreKbd, mask, 0); + else + XkbLockModifiers ( dpy, XkbUseCoreKbd, mask, mask); + return 1; + } +#endif + +#endif + +#ifdef HAVE_XTEST +static +int xtest_get_numlock_state() + { + int i; + int numlock_mask = 0; + Window dummy1, dummy2; + int dummy3, dummy4, dummy5, dummy6; + unsigned int mask; + XModifierKeymap* map = XGetModifierMapping( dpy ); + KeyCode numlock_keycode = XKeysymToKeycode( dpy, XK_Num_Lock ); + if( numlock_keycode == NoSymbol ) + return 0; + for( i = 0; + i < 8; + ++i ) + { + if( map->modifiermap[ map->max_keypermod * i ] == numlock_keycode ) + numlock_mask = 1 << i; + } + XQueryPointer( dpy, DefaultRootWindow( dpy ), &dummy1, &dummy2, + &dummy3, &dummy4, &dummy5, &dummy6, &mask ); + XFreeModifiermap( map ); + return mask & numlock_mask; + } + +static +void xtest_change_numlock() + { + XTestFakeKeyEvent( dpy, XKeysymToKeycode( dpy, XK_Num_Lock ), True, CurrentTime ); + XTestFakeKeyEvent( dpy, XKeysymToKeycode( dpy, XK_Num_Lock ), False, CurrentTime ); + } + +static +void xtest_set_on() + { + if( !xtest_get_numlock_state()) + xtest_change_numlock(); + } + +static +void xtest_set_off() + { + if( xtest_get_numlock_state()) + xtest_change_numlock(); + } + +#ifdef NUMLOCKX_STANDALONE +static +void xtest_toggle() + { + xtest_change_numlock(); + } +#endif + +#endif + +static +void numlock_set_on() + { +#ifdef HAVE_XKB + if( xkb_set_on()) + return; +#endif +#ifdef HAVE_XTEST + xtest_set_on(); +#endif + } + +static +void numlock_set_off() + { +#ifdef HAVE_XKB + if( xkb_set_off()) + return; +#endif +#ifdef HAVE_XTEST + xtest_set_off(); +#endif + } + + +#ifndef NUMLOCKX_STANDALONE + +void numlockx_change_numlock_state(Display* dpy_, int state) +{ +#ifndef HAVE_XTEST +#ifdef __GNUC__ + #warning "XTEST extension not found - numlock setting may not work reliably" +#endif +#endif + + dpy = dpy_; + if( state ) { + numlock_set_on(); + } + else { + numlock_set_off(); + } +} + +#else + +static +void numlock_toggle() + { +#ifdef HAVE_XKB + if( xkb_toggle()) + return; +#endif +#ifdef HAVE_XTEST + xtest_toggle(); +#endif + } + +void usage( const char* argv0 ) + { + printf( "NumLockX " VERSION "\n" + "(C) 2000-2001 Lubos Lunak \n" + "(C) 2001 Oswald Buddenhagen \n\n" + "Usage : %s [on|off]\n" + "on - turns NumLock on in X ( default )\n" + "off - turns NumLock off in X\n" + "toggle - toggles the NumLock on and off in X\n" + "\n" + , argv0 ); + } + +int main( int argc, char* argv[] ) + { + if( argc > 2 ) + { + usage( argv[ 0 ] ); + return 1; + } + dpy = XOpenDisplay( NULL ); + if( dpy == NULL ) + { + fprintf( stderr, "Error opening display!\n" ); + return 1; + } + if( argc == 1 ) + numlock_set_on(); + else if( strcmp( argv[ 1 ], "on" ) == 0 ) + numlock_set_on(); + else if( strcmp( argv[ 1 ], "off" ) == 0 ) + numlock_set_off(); + else if( strcmp( argv[ 1 ], "toggle" ) == 0 ) + numlock_toggle(); + else + { + usage( argv[ 0 ] ); + XCloseDisplay( dpy ); + return 2; + } + XCloseDisplay( dpy ); + return 0; + } + +#endif diff --git a/kcontrol/keyboard/pics/CMakeLists.txt b/kcontrol/keyboard/pics/CMakeLists.txt new file mode 100644 index 00000000..6d5b7cae --- /dev/null +++ b/kcontrol/keyboard/pics/CMakeLists.txt @@ -0,0 +1 @@ +install( FILES epo.png DESTINATION ${DATA_INSTALL_DIR}/kcmkeyboard/pics ) diff --git a/kcontrol/keyboard/pics/epo.png b/kcontrol/keyboard/pics/epo.png new file mode 100644 index 00000000..a8ed2943 Binary files /dev/null and b/kcontrol/keyboard/pics/epo.png differ diff --git a/kcontrol/keyboard/plasma_applet_keyboard.desktop b/kcontrol/keyboard/plasma_applet_keyboard.desktop new file mode 100644 index 00000000..711c977f --- /dev/null +++ b/kcontrol/keyboard/plasma_applet_keyboard.desktop @@ -0,0 +1,161 @@ +[Desktop Entry] +Name=Keyboard Layout +Name[af]=Sleutelbord Uitleg +Name[ar]=تخطيط لوحة المفاتيح +Name[ast]=Disposición del tecláu +Name[be]=Раскладка клавіятуры +Name[be@latin]=Vykład klavijatury +Name[bg]=Клавиатурни подредби +Name[bn]=কীবোর্ড বিন্যাস +Name[bn_IN]=কি-বোর্ড বিন্যাস +Name[br]=Reizhadur ar stokellaoueg +Name[bs]=Raspored tastera +Name[ca]=Disposició del teclat +Name[ca@valencia]=Disposició del teclat +Name[cs]=Rozvržení klávesnice +Name[csb]=Ùstôw klawiaturë +Name[cy]=Cynllun Bysellfwrdd +Name[da]=Tastaturlayout +Name[de]=Tastaturbelegung +Name[el]=Διάταξη πληκτρολογίου +Name[en_GB]=Keyboard Layout +Name[eo]=Klavararanĝo +Name[es]=Disposición del teclado +Name[et]=Klaviatuuri paigutus +Name[eu]=Teklatu-diseinua +Name[fa]=طرح‌بندی صفحه کلید +Name[fi]=Näppäimistöasettelu +Name[fy]=Toetseboerdyndieling +Name[ga]=Leagan Amach Méarchláir +Name[gl]=Disposición do teclado +Name[gu]=કીબોર્ડ દેખાવ +Name[he]=פריסת מקלדת +Name[hi]=कुंजीपट ख़ाका +Name[hne]=कुंजीपट खाका +Name[hr]=Raspored tipkovnice +Name[hsb]=Tastaturowy layout +Name[hu]=Billentyűzetkiosztás +Name[ia]=Disposition de claviero +Name[id]=Tata Letak Papan Ketik +Name[is]=Lyklaborð +Name[ja]=キーボード配列 +Name[ka]=კლავიატურის განლაგება +Name[kk]=Перенетақта сәйкестігі +Name[km]=ប្លង់​ក្ដារចុច +Name[kn]=ಕೀಲಿಮಣೆ ವಿನ್ಯಾಸ +Name[ko]=키보드 레이아웃 +Name[ku]=Rengê Klavyeyê +Name[lt]=Klaviatūros išdėstymas +Name[lv]=Tastatūras izkārtojums +Name[mai]=कीबोर्ड लेआउट +Name[mk]=Распоред на тастатура +Name[ml]=കീബോര്‍ഡ് വിന്യാസം +Name[mr]=कळफलक रचना +Name[nb]=Tastaturutforming +Name[nds]=Tasttoornen +Name[ne]=कुञ्जीपाटी सजावट +Name[nl]=Toetsenbordindeling +Name[nn]=Taste­oppsett +Name[oc]=Disposicion del clavièr +Name[or]=କିବୋର୍ଡ଼ ବିନ୍ୟାସ +Name[pa]=ਕੀ-ਬੋਰਡ ਲੇਆਉਟ +Name[pl]=Układ klawiatury +Name[pt]=Disposição do Teclado +Name[pt_BR]=Leiaute do teclado +Name[ro]=Aranjament de tastatură +Name[ru]=Раскладка клавиатуры +Name[se]=Boallobeavdehápmi +Name[si]=යතුරුපුවරු ආකෘතිය +Name[sk]=Rozloženie klávesnice +Name[sl]=Razporeditev tipk +Name[sr]=Распоред тастатуре +Name[sr@ijekavian]=Распоред тастатуре +Name[sr@ijekavianlatin]=Raspored tastature +Name[sr@latin]=Raspored tastature +Name[sv]=Tangentbordslayout +Name[ta]=விசைப்பலகை உருவரை +Name[te]=కీబోర్డ్ కూర్పు +Name[tg]=Тугмабандии клавиатура +Name[th]=ผังแป้นพิมพ์ +Name[tr]=Klavye Düzeni +Name[ug]=ھەرپتاختا جايلاشتۇرۇلۇشى +Name[uk]=Розкладка клавіатури +Name[uz]=Tugmalar tartibi +Name[uz@cyrillic]=Тугмалар тартиби +Name[vi]=Bố trí bàn phím +Name[wa]=Adjinçmint del taprece +Name[xh]=Ubeko Lwebhodi yezitshixo +Name[x-test]=xxKeyboard Layoutxx +Name[zh_CN]=键盘布局 +Name[zh_TW]=鍵盤配置 +Comment=View and switch between active keyboard layouts +Comment[ar]=إعرض وبدل بين مخططات لوحة المفاتيح +Comment[ast]=Ver y camudar ente les distribuciones de tecláu actives +Comment[bg]=Преглед и превключване на клавиатурната подредба +Comment[bn]=সক্রিয় কীবোর্ড বিন্যাসগুলি দেখুন এবং অদলবদল করুন +Comment[bs]=Prikaz i prebacivanje između aktivnih rasporeda tastature +Comment[ca]=Vista i commutació entre disposicions actives de teclat +Comment[ca@valencia]=Vista i commutació entre disposicions actives de teclat +Comment[cs]=Zobrazí a přepne mezi aktivními rozloženími klávesnice +Comment[da]=Vis og skift mellem aktive tastaturlayouts +Comment[de]=Aktive Tastaturbelegungen anzeigen und zwischen ihnen umschalten +Comment[el]=Εμφάνιση και εναλλαγή μεταξύ των ενεργών διατάξεων πληκτρολογίου +Comment[en_GB]=View and switch between active keyboard layouts +Comment[es]=Ver y cambiar entre las distribuciones de teclado activas +Comment[et]=Aktiivsete klaviatuuripaigutuste näitamine ja nende vahel lülitamine +Comment[eu]=Ikusi eta aldatu teklatu-diseinu aktibo batetik bestera +Comment[fi]=Katsele ja vaihda aktiivisten näppäinasetteluiden välillä +Comment[gl]=Mostra e troca a disposición de teclado activa +Comment[he]=משמש להצגת והחלפה בין פריסות מקלדת +Comment[hr]=Prikaži i prebaci između aktivnih tipkovničkih rasporeda +Comment[hu]=Aktív billentyűzetkiosztások megjelenítése és váltás köztük +Comment[ia]=Monstra e commuta inter dispositiones de claviero active +Comment[is]=Skoða og skipta á milli virkra lyklaborðsframsetninga +Comment[ja]=アクティブキーボードレイアウトを表示して切り替える +Comment[kk]=Белсенді пернетақталарды көру және біріне ауысу +Comment[km]=មើល ហើយ​ប្ដូរ​ប្លង់​ក្ដារចុច​សកម្ម +Comment[ko]=활성 키보드 레이아웃을 보고 바꾸기 +Comment[lt]=Peržiūrėti ir persijungti tarp aktyvių klaviatūros maketų +Comment[lv]=Skatīt un pārslēgties starp aktīvajiem tastatūras izkārtojumumiem +Comment[mr]=चालू कळफलक रचना बघा व बदला +Comment[nb]=Vis aktive tastaturutforminger og bytt mellom dem +Comment[nds]=Aktiv Tasttoornen ankieken un wesseln +Comment[nl]=Bekijk en schakel tussen actieve toetsenbordindelingen +Comment[nn]=Vis og byt mellom aktive tastaturoppsett +Comment[pa]=ਸਰਗਰਮ ਕੀਬੋਰਡ ਲੇਆਉਟ ਵੇਖੋ ਅਤੇ ਬਦਲੋ +Comment[pl]=Przeglądanie i przełączanie między aktywnymi układami klawiatury +Comment[pt]=Ver e mudar a disposição de teclado activa +Comment[pt_BR]=Visualiza e troca o leiaute de teclado ativo +Comment[ro]=Vizualizează și schimbă între aranjamentele de tastatură active +Comment[ru]=Просмотр и переключение между активными раскладками клавиатуры +Comment[sk]=Zobrazenie a prepínanie medzi aktívnymi rozloženiami klávesnice +Comment[sl]=Oglejte si in preklopite med dejavnimi razporeditvami tipk +Comment[sr]=Приказ и мењање активних распореда тастатуре +Comment[sr@ijekavian]=Приказ и мењање активних распореда тастатуре +Comment[sr@ijekavianlatin]=Prikaz i menjanje aktivnih rasporeda tastature +Comment[sr@latin]=Prikaz i menjanje aktivnih rasporeda tastature +Comment[sv]=Visa och byt mellan aktiva tangentbordslayouter +Comment[th]=ดูและสลับการจัดวางแป้นพิมพ์ที่ใช้งานอยู่ +Comment[tr]=Etkin klavye düzenlerini görüntüle ve geçiş yap +Comment[ug]=ئاكتىپ ھەرپتاختا جايلاشتۇرۇشى ئارىسىدا ئالماشتۇر ۋە كۆرسەت +Comment[uk]=Перегляд і перемикання між активними розкладками клавіатури +Comment[wa]=Vey eyet discandjî etur les adjinçmints del taprece ovrants +Comment[x-test]=xxView and switch between active keyboard layoutsxx +Comment[zh_CN]=查看和切换键盘布局 +Comment[zh_TW]=檢視並在可用的鍵盤佈局中切換 + +Icon=preferences-desktop-keyboard +Type=Service + +X-KDE-ServiceTypes=Plasma/Applet +X-KDE-Library=plasma_applet_keyboard +X-KDE-PluginInfo-Author=Andriy Rysin +X-KDE-PluginInfo-Email=rysin@kde.org +X-KDE-PluginInfo-Name=keyboard_applet +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-NotificationArea=true diff --git a/kcontrol/keyboard/preview/TODO b/kcontrol/keyboard/preview/TODO new file mode 100644 index 00000000..784924fe --- /dev/null +++ b/kcontrol/keyboard/preview/TODO @@ -0,0 +1,10 @@ +Important: +* display tooltip for each key with key description from symbol file + +Good to have: +* read keyboard geometry and show it properly instead of default keyboard +* use some common parser to parse symbol and geometry descriptions +* replace symkey2ucs with something more reliable (e.g. XLookupString?) + +Cleanup: +* clean up the code (especially kbpreviewframe.cpp) diff --git a/kcontrol/keyboard/preview/kbpreviewframe.cpp b/kcontrol/keyboard/preview/kbpreviewframe.cpp new file mode 100644 index 00000000..8ecc4f24 --- /dev/null +++ b/kcontrol/keyboard/preview/kbpreviewframe.cpp @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 "kbpreviewframe.h" + +#include +#include + +#include +#include + + +static const QColor keyBorderColor("#d4d4d4"); +static const QColor lev12color("#d4d4d4"); +static const QColor lev34color("#FF3300"); +static const int sz=20, kszx=70, kszy=70; + +static const int xOffset[] = {15, 15, 40, 40 }; +static const int yOffset[] = {10, 40, 10, 40 }; +static const QColor color[] = { lev12color, lev12color, lev34color, lev34color }; + + +// TODO: parse geometry files and display keyboard according to current keyboard model + +KbPreviewFrame::KbPreviewFrame(QWidget *parent) : + QFrame(parent) +{ + setFrameStyle( QFrame::Box ); + setFrameShadow(QFrame::Sunken); +} + +void KbPreviewFrame::paintTLDE(QPainter &painter,int &x,int &y) +{ + painter.setPen(keyBorderColor); + painter.drawRect(x, y, kszx, kszy); + + const QList symbols = keyboardLayout.TLDE.symbols; + + for(int level=0; level symbols = keyboardLayout.AE[i].symbols; + + for(int level=0; level")); + x+=tabszx; + + + for(int i=0; i symbols = keyboardLayout.AD[i].symbols; + + painter.setPen(keyBorderColor); + painter.drawRect(x, y,kszx,kszy); + + for(int level=0; level symbols = keyboardLayout.BKSL.symbols; + + for(int level=0; level symbols = keyboardLayout.AC[i].symbols; + + for(int level=0; level symbols = keyboardLayout.AB[i].symbols; + + for(int level=0; level symstr = content.split("xkb_symbols "); + + if( layoutVariant.isEmpty() ) { + keyboardLayout.generateLayout(symstr.at(1), layout); + } + else { + for(int i=1;i +#include + +class KbPreviewFrame : public QFrame +{ + Q_OBJECT + +private: + void paintTLDE(QPainter &painter, int &x, int &y); + void paintAERow(QPainter &painter, int &x, int &y); + void paintADRow(QPainter &painter, int &x, int &y); + void paintACRow(QPainter &painter, int &x, int &y); + void paintABRow(QPainter &painter, int &x, int &y); + void paintBottomRow(QPainter &painter, int &x, int &y); + void paintFnKeys(QPainter &painter, int &x, int &y); + + KeySymHelper symbol; + Aliases alias; + KeyboardLayout keyboardLayout; + +public: + explicit KbPreviewFrame(QWidget *parent = 0); + + void paintEvent(QPaintEvent * event); + void generateKeyboardLayout(const QString &country, const QString &layoutVariant); + QString getLayoutName() const { + return keyboardLayout.getLayoutName(); + } +}; + +#endif // KBPREVIEWFRAME_H diff --git a/kcontrol/keyboard/preview/keyaliases.cpp b/kcontrol/keyboard/preview/keyaliases.cpp new file mode 100644 index 00000000..3eb45ec4 --- /dev/null +++ b/kcontrol/keyboard/preview/keyaliases.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 "keyaliases.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +Aliases::Aliases() +{ + QString filename=findaliasdir(); + QFile file(filename); + file.open(QIODevice::ReadOnly | QIODevice::Text); + QString content = file.readAll(); + file.close(); + QListals; + als=content.split("xkb_keycodes"); + for(int i=1;i"); + temp=temp.remove("<"); + temp=temp.remove(";"); + temp=temp.remove("}"); + temp=temp.remove("{"); + QListalskeys; + alskeys=temp.split("alias"); + if(temp.startsWith("qwerty")){ + for(int k=1;k= 3 ) { + // .../usr/lib/X11 -> /usr/share/X11/xkb vs .../usr/X11/lib -> /usr/X11/share/X11/xkb + QString delta = base.endsWith("X11") ? "/../../share/X11" : "/../share/X11"; + QDir baseDir(base + delta); + if( baseDir.exists() ) { + xkbParentDir = baseDir.absolutePath(); + } + else { + QDir baseDir(base + "/X11"); // .../usr/X11/lib/X11/xkb (old XFree) + if( baseDir.exists() ) { + xkbParentDir = baseDir.absolutePath(); + } + } + } + + if( xkbParentDir.isEmpty() ) { + xkbParentDir = "/usr/share/X11"; + } + aliasdir=QString("%1/xkb/keycodes/aliases").arg(xkbParentDir); + return(aliasdir); +} diff --git a/kcontrol/keyboard/preview/keyaliases.h b/kcontrol/keyboard/preview/keyaliases.h new file mode 100644 index 00000000..3769e4eb --- /dev/null +++ b/kcontrol/keyboard/preview/keyaliases.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 ALIASES_H +#define ALIASES_H + +#include + +class Aliases +{ +private: + QMapqwerty; + QMapazerty; + QMapqwertz; + QString findaliasdir(); +public: + Aliases(); + QString getAlias(const QString &type, const QString &name); +}; + +#endif // ALIASES_H diff --git a/kcontrol/keyboard/preview/keyboardlayout.cpp b/kcontrol/keyboard/preview/keyboardlayout.cpp new file mode 100644 index 00000000..6ac2f3f7 --- /dev/null +++ b/kcontrol/keyboard/preview/keyboardlayout.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 "keyboardlayout.h" +#include "keysymbols.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +//TODO: replace this with grammar parser (e.g. antlr) + + +KeyboardLayout::KeyboardLayout() +{ +} + +void KeyboardLayout::generateLayout(QString a,const QString& cname) +{ + includeSymbol(a,cname); + int i=a.indexOf("name[Group1]="); + i+=13; + + QString n=a.mid(i); + n=n.simplified(); + i=n.indexOf("\"",1); + layoutName=n.left(i); + layoutName.remove("\""); + layoutName.simplified(); + i=n.indexOf("key"); + n=n.mid(i); + + QList st; + st=n.split("key"); + + KeySymbols dum; + QString r,y; + + for(int k=0;ktobeinclude; + tobeinclude=a.split("include"); + + QString r; + for(int o=1;o incfile; + incfile=incsym.split("("); + for(int i=0;i symstrlist; + + symstrlist=content.split("xkb_symbols "); + for(int u=1;u= 3 ) { + // .../usr/lib/X11 -> /usr/share/X11/xkb vs .../usr/X11/lib -> /usr/X11/share/X11/xkb + QString delta = base.endsWith("X11") ? "/../../share/X11" : "/../share/X11"; + QDir baseDir(base + delta); + if( baseDir.exists() ) { + xkbParentDir = baseDir.absolutePath(); + } + else { + QDir baseDir(base + "/X11"); // .../usr/X11/lib/X11/xkb (old XFree) + if( baseDir.exists() ) { + xkbParentDir = baseDir.absolutePath(); + } + } + } + + if( xkbParentDir.isEmpty() ) { + xkbParentDir = "/usr/share/X11"; + } + + return QString("%1/xkb/symbols/").arg(xkbParentDir); +} diff --git a/kcontrol/keyboard/preview/keyboardlayout.h b/kcontrol/keyboard/preview/keyboardlayout.h new file mode 100644 index 00000000..4844382e --- /dev/null +++ b/kcontrol/keyboard/preview/keyboardlayout.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 KEYBOARDLAYOUT_H +#define KEYBOARDLAYOUT_H + +#include "keysymbols.h" +#include "keyaliases.h" + +#include + +class KeyboardLayout +{ + QString layoutName; + Aliases alias; + +public: + KeyboardLayout(); + + KeySymbols TLDE; + KeySymbols BKSL; + KeySymbols AE[12]; + KeySymbols AD[12]; + KeySymbols AC[11]; + KeySymbols AB[11]; + + void generateLayout(QString a, const QString &cname); + QString findSymbolBaseDir(); + void includeSymbol(QString a, const QString &cname); + QString getLayoutName() const { + return layoutName; + } +}; + +#endif // KEYBOARDLAYOUT_H diff --git a/kcontrol/keyboard/preview/keyboardpainter.cpp b/kcontrol/keyboard/preview/keyboardpainter.cpp new file mode 100644 index 00000000..b9fbf242 --- /dev/null +++ b/kcontrol/keyboard/preview/keyboardpainter.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 "keyboardpainter.h" + +#include +#include +#include + +#include + + +KeyboardPainter::KeyboardPainter(): + kbframe(new KbPreviewFrame(this)), + exitButton(new QPushButton(i18n("Close"),this)) +{ + kbframe->setFixedSize( 1030, 490 ); + exitButton->setFixedSize(120, 30); + + QVBoxLayout* vLayout = new QVBoxLayout( this ); + vLayout->addWidget(kbframe); + vLayout->addWidget(exitButton); + + connect(exitButton, SIGNAL(clicked()), this, SLOT(close())); + + setWindowTitle(kbframe->getLayoutName()); +} + +void KeyboardPainter::generateKeyboardLayout(const QString& layout, const QString& variant) +{ + kbframe->generateKeyboardLayout(layout, variant); +} + +KeyboardPainter::~KeyboardPainter() +{ + delete kbframe; + delete exitButton; +} diff --git a/kcontrol/keyboard/preview/keyboardpainter.h b/kcontrol/keyboard/preview/keyboardpainter.h new file mode 100644 index 00000000..39382be7 --- /dev/null +++ b/kcontrol/keyboard/preview/keyboardpainter.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 KEYBOARDPAINTER_H +#define KEYBOARDPAINTER_H + +#include "kbpreviewframe.h" + +#include + +class QPushButton; + +class KeyboardPainter : public QDialog +{ + Q_OBJECT + +public: + explicit KeyboardPainter(); + ~KeyboardPainter(); + + void generateKeyboardLayout(const QString& layout, const QString& variant); + +private: + KbPreviewFrame *kbframe; + QPushButton *exitButton; +}; + +#endif // KEYBOARDPAINTER_H diff --git a/kcontrol/keyboard/preview/keysym2ucs.cpp b/kcontrol/keyboard/preview/keysym2ucs.cpp new file mode 100644 index 00000000..37afb082 --- /dev/null +++ b/kcontrol/keyboard/preview/keysym2ucs.cpp @@ -0,0 +1,899 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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. + */ + +/* $XFree86$ + * This module converts keysym values into the corresponding ISO 10646-1 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * keysym2ucs() maps a keysym onto a Unicode value using a binary search, + * therefore keysymtab[] must remain SORTED by keysym value. + * + * The keysym -> UTF-8 conversion will hopefully one day be provided + * by Xlib via XmbLookupString() and should ideally not have to be + * done in X applications. But we are not there yet. + * + * We allow to represent any UCS character in the range U+00000000 to + * U+00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U+10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x1000abcd. + * + * NOTE: The comments in the table below contain the actual character + * encoded in UTF-8, so for viewing and editing best use an editor in + * UTF-8 mode. + * + * Author: Markus G. Kuhn , University of Cambridge, June 1999 + * + * Special thanks to Richard Verhoeven for preparing + * an initial draft of the mapping table. + */ + +#include + +struct codepair { + unsigned short keysym; + unsigned short ucs; +} keysymtab[] = { + { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ + { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ + { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ + { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ + { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ + { 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ + { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ + { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ + { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ + { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ + { 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ + { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ + { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ + { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ + { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ + { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ + { 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */ + { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ + { 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ + { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ + { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ + { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ + { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ + { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ + { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ + { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ + { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ + { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ + { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ + { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ + { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ + { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ + { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ + { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ + { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ + { 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ + { 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + { 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ + { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ + { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ + { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ + { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ + { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ + { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ + { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ + { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ + { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ + { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ + { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ + { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ + { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ + { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + { 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ + { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ + { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ + { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + { 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ + { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ + { 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ + { 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ + { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ + { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ + { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ + { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ + { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + { 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ + { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ + { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ + { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ + { 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ + { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ + { 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ + { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ + { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ + { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ + { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ + { 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ + { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ + { 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ + { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ + { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + { 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ + { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ + { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ + { 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ + { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ + { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ + { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ + { 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ + { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ + { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ + { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ + { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ + { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ + { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ + { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ + { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ + { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ + { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ + { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ + { 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ + { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ + { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ + { 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ + { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ + { 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ + { 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ + { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ + { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ + { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ + { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ + { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ + { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ + { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ + { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ + { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ + { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ + { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ + { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ + { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ + { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ + { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ + { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ + { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ + { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ + { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ + { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ + { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ + { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ + { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ + { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ + { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ + { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ + { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ + { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ + { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ + { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ + { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ + { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ + { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ + { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ + { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ + { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ + { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ + { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ + { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ + { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ + { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ + { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ + { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ + { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ + { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ + { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ + { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ + { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ + { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ + { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ + { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ + { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ + { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ + { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ + { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ + { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ + { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ + { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ + { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ + { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ + { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ + { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ + { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ + { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ + { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ + { 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */ + { 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ + { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ + { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ + { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ + { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ + { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ + { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ + { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ + { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ + { 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */ + { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ + { 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */ + { 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */ + { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ + { 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */ + { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ + { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ + { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ + { 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */ + { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ + { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ + { 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */ + { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ + { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ + { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ + { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ + { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ + { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ + { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ + { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ + { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ + { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ + { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ + { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ + { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ + { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ + { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ + { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ + { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ + { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ + { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ + { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ + { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ + { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ + { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ + { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ + { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ + { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ + { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ + { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ + { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ + { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ + { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ + { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ + { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ + { 0x06ad, 0x0491 }, /* Ukrainian_ghe_with_upturn ґ CYRILLIC SMALL LETTER GHE WITH UPTURN */ + { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ + { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ + { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ + { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ + { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ + { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ + { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ + { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ + { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ + { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ + { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ + { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ + { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ + { 0x06bd, 0x0490 }, /* Ukrainian_GHE_WITH_UPTURN Ґ CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ + { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ + { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ + { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ + { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ + { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ + { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ + { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ + { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ + { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ + { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ + { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ + { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ + { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ + { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ + { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ + { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ + { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ + { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ + { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ + { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ + { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ + { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ + { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ + { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ + { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ + { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ + { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ + { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ + { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ + { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ + { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ + { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ + { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ + { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ + { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ + { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ + { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ + { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ + { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ + { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ + { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ + { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ + { 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ + { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ + { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ + { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ + { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ + { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ + { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ + { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ + { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ + { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ + { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ + { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ + { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ + { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ + { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ + { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ + { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ + { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ + { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ + { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ + { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ + { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ + { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ + { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ + { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ + { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ + { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ + { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ + { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ + { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ + { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ + { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ + { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ + { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ + { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ + { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ + { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ + { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ + { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ + { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ + { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ + { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ + { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ + { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ + { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ + { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ + { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ + { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ + { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ + { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ + { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ + { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ + { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ + { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ + { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ + { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ + { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ + { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ + { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ + { 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ + { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ + { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ + { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ + { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ + { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ + { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ + { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ + { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ + { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ + { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ + { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ + { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ + { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ + { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ + { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ + { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ + { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ + { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ + { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ + { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ + { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ + { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ + { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ + { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ + { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ + { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ + { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ + { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ + { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ + { 0x08a1, 0x23b7 }, /* leftradical ⎷ RADICAL SYMBOL BOTTOM */ + { 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + { 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */ + { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ + { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ + { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ LEFT SQUARE BRACKET UPPER CORNER */ + { 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ LEFT SQUARE BRACKET LOWER CORNER */ + { 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ RIGHT SQUARE BRACKET UPPER CORNER */ + { 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ RIGHT SQUARE BRACKET LOWER CORNER */ + { 0x08ab, 0x239b }, /* topleftparens ⎛ LEFT PARENTHESIS UPPER HOOK */ + { 0x08ac, 0x239d }, /* botleftparens ⎝ LEFT PARENTHESIS LOWER HOOK */ + { 0x08ad, 0x239e }, /* toprightparens ⎞ RIGHT PARENTHESIS UPPER HOOK */ + { 0x08ae, 0x23a0 }, /* botrightparens ⎠ RIGHT PARENTHESIS LOWER HOOK */ + { 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ LEFT CURLY BRACKET MIDDLE PIECE */ + { 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ RIGHT CURLY BRACKET MIDDLE PIECE */ +/* 0x08b1 topleftsummation ? ??? */ +/* 0x08b2 botleftsummation ? ??? */ +/* 0x08b3 topvertsummationconnector ? ??? */ +/* 0x08b4 botvertsummationconnector ? ??? */ +/* 0x08b5 toprightsummation ? ??? */ +/* 0x08b6 botrightsummation ? ??? */ +/* 0x08b7 rightmiddlesummation ? ??? */ + { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ + { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ + { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ + { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ + { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ + { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ + { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ + { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ + { 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */ + { 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */ + { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ + { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ + { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ + { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ + { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ + { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ + { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ + { 0x08dd, 0x222a }, /* union ∪ UNION */ + { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ + { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ + { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ + { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ + { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ + { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ + { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ + { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ + { 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */ + { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ + { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ + { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ + { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ + { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ + { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ + { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ + { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ + { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ + { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ + { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ + { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + { 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 */ + { 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 */ + { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ + { 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 */ + { 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 */ + { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ + { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ + { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ + { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ + { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */ + { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ + { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */ + { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */ + { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ + { 0x0aaa, 0x2013 }, /* endash – EN DASH */ + { 0x0aac, 0x2423 }, /* signifblank ␣ OPEN BOX */ + { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ + { 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */ + { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ + { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ + { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ + { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ + { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ + { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ + { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ + { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ + { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ + { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ + { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ + { 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */ + { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ +/* 0x0abf marker ? ??? */ + { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ + { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ + { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ + { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ + { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ + { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ +/* 0x0acb trademarkincircle ? ??? */ + { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ + { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ + { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ + { 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */ + { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ + { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ + { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ + { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ + { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ +/* 0x0ad5 permille ? ??? */ + { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ + { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ + { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ +/* 0x0ada hexagram ? ??? */ + { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ + { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ + { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ + { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ + { 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */ + { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ + { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ + { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ + { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ + { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ + { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ + { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ + { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ + { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ + { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ + { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ + { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ + { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ + { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ + { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ + { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ + { 0x0af1, 0x2020 }, /* dagger † DAGGER */ + { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ + { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ + { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ + { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ + { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ + { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ + { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ + { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ + { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ + { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ + { 0x0afc, 0x2038 }, /* caret ‸ CARET */ + { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ + { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ +/* 0x0aff cursor ? ??? */ + { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ + { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ + { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ + { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ + { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ + { 0x0bc2, 0x22a5 }, /* downtack ⊥ UP TACK */ + { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ + { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ + { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ + { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ + { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */ + { 0x0bce, 0x22a4 }, /* uptack ⊤ DOWN TACK */ + { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ + { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ + { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ + { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ + { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ + { 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */ + { 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */ + { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ + { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ + { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ + { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ + { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ + { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ + { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ + { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ + { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ + { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ + { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ + { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ + { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ + { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ + { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ + { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ + { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ + { 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */ + { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ + { 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */ + { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ + { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ + { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ + { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ + { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ + { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ + { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ + { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ + { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ + { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ + { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ + { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ + { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ + { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ + { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ + { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ + { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ + { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ + { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ + { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ + { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ + { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ + { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ + { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ + { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ + { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ + { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ + { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ + { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ + { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ + { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ + { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ + { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ + { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ + { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ + { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ + { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ + { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ + { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ + { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ + { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ + { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ + { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ + { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ + { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ + { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ + { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ + { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ + { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ + { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ + { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ + { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ + { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ + { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ + { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ + { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ + { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ + { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ + { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ + { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ + { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ + { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ + { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ + { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ + { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ + { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ + { 0x0dde, 0x0e3e }, /* Thai_maihanakat_maitho ฾ ??? */ + { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ + { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ + { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ + { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ + { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ + { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ + { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ + { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ + { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ + { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ + { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ + { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ + { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ + { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ + { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ + { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ + { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ + { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ + { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ + { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ + { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ + { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ + { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ + { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ + { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ + { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ + { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ + { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ + { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ + { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ + { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ + { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ + { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ + { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ + { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ + { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ + { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ + { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ + { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ + { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ + { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ + { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ + { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ + { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ + { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ + { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ + { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ + { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ + { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ + { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ + { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ + { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ + { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ + { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ + { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ + { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ + { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ + { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ + { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ + { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ + { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ + { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ + { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ + { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ + { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ + { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ + { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ + { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ + { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ + { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ + { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ + { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ + { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ + { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ + { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ + { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ + { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ + { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ + { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ + { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ + { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ + { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ + { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ + { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ + { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ + { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ + { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ + { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ + { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ + { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ + { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ + { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ + { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ + { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ + { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ + { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ + { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ + { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ + { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ + { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ + { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ + { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ + { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ + { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ + { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ + { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ + { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ + { 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */ + { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ + { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ + { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ + { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ + { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ + { 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */ + { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ + { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ + { 0x13a4, 0x20ac }, /* Euro € EURO SIGN */ + { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ + { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ + { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ + { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ + + /* Combining symbols */ + { 0xfe50, 0x0300 }, /* dead_grave */ + { 0xfe51, 0x0301 }, /* dead_acute" */ + { 0xfe52, 0x0302 }, /* dead_circumflex" */ + { 0xfe53, 0x0303 }, /* dead_tilde" */ + { 0xfe54, 0x0304 }, /* dead_macron" */ + { 0xfe55, 0x0306 }, /* dead_breve" */ + { 0xfe56, 0x0307 }, /* dead_abovedot" */ + { 0xfe57, 0x0308 }, /* dead_diaeresis" */ + { 0xfe58, 0x030A }, /* dead_abovering" */ + { 0xfe59, 0x030B }, /* dead_doubleacute" */ + { 0xfe5a, 0x030C }, /* dead_caron" */ + { 0xfe5b, 0x0327 }, /* dead_cedilla" */ + { 0xfe5c, 0x0328 }, /* dead_ogonek" */ + { 0xfe60, 0x0323 }, /* dead_belowdot */ + + /* Special function keys. */ + + { 0xff08, 0x0008 }, /* XK_BackSpace */ + { 0xff09, 0x0009 }, /* XK_Tab */ + { 0xff0a, 0x000a }, /* XK_Linefeed */ + { 0xff0d, 0x000d }, /* XK_Return */ + { 0xff13, 0x0013 }, /* XK_Pause */ + { 0xff1b, 0x001b }, /* XK_Escape */ + { 0xff50, 0x0001 }, /* XK_Home */ + { 0xff51, 0x001c }, /* XK_Left */ + { 0xff52, 0x001e }, /* XK_Up */ + { 0xff53, 0x001d }, /* XK_Right */ + { 0xff54, 0x001f }, /* XK_Down */ + { 0xff55, 0x000b }, /* XK_Prior */ + { 0xff56, 0x000c }, /* XK_Next */ + { 0xff57, 0x0004 }, /* XK_End */ + { 0xff6a, 0x0005 }, /* XK_Help */ + { 0xffff, 0x007f }, /* XK_Delete */ +}; + +long keysym2ucs(KeySym keysym) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + /* first check for Latin-1 characters (1:1 mapping) */ + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + return keysym; + + /* also check for directly encoded 24-bit UCS characters */ + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + /* binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (keysymtab[mid].keysym < keysym) + min = mid + 1; + else if (keysymtab[mid].keysym > keysym) + max = mid - 1; + else { + /* found it */ + return keysymtab[mid].ucs; + } + } + + /* no matching Unicode value found */ + return -1; +} diff --git a/kcontrol/keyboard/preview/keysym2ucs.h b/kcontrol/keyboard/preview/keysym2ucs.h new file mode 100644 index 00000000..6e50c764 --- /dev/null +++ b/kcontrol/keyboard/preview/keysym2ucs.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2012 Andriy Rysin (arysin@gmail.com) + * + * 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 KEYSYM2UCS_H +#define KEYSYM2UCS_H + +#include +#include + +extern long keysym2ucs(KeySym keysym); + +#endif diff --git a/kcontrol/keyboard/preview/keysymbols.cpp b/kcontrol/keyboard/preview/keysymbols.cpp new file mode 100644 index 00000000..af43f621 --- /dev/null +++ b/kcontrol/keyboard/preview/keysymbols.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 "keysymbols.h" + +#include +#include + + +static const int MAX_GROUPS_SUPPORTED = 4; + +KeySymbols::KeySymbols() +{ +} + +void KeySymbols::setKey(const QString& a) +{ + int i=a.indexOf("<"); + i++; + keyname=a.mid(i,4); + keyname.remove(" "); + i=a.indexOf("["); + i++; + + QString str=a.mid(i); + i=str.indexOf("]"); + + QString st=str.left(i); + st=st.remove(" "); + //QStringList klst; + symbols=st.split(","); + + if( symbols.size() > MAX_GROUPS_SUPPORTED ) { + symbols = symbols.mid(0, MAX_GROUPS_SUPPORTED); + } + + for(int k=0;k +#include + +class KeySymbols +{ +public: + KeySymbols(); + + QString keyname; + QList symbols; + + void setKey(const QString& opton); +}; + +#endif // KEYSYMBOLS_H diff --git a/kcontrol/keyboard/preview/keysymhelper.cpp b/kcontrol/keyboard/preview/keysymhelper.cpp new file mode 100644 index 00000000..67beb80d --- /dev/null +++ b/kcontrol/keyboard/preview/keysymhelper.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 "keysymhelper.h" +#include "keysym2ucs.h" + +#include +#include + +#include + +#include + + +KeySymHelper::KeySymHelper() +{ + nill = 0; +} + +QString KeySymHelper::getKeySymbol(const QString& opton) +{ + if( keySymbolMap.contains(opton) ) + return keySymbolMap[opton]; + + const char* str = opton.toAscii().data(); + +#if 0 + //TODO: figure out how to use this so we don't need our own symkey2ucs mapping + int res = Xutf8LookupString(XIC ic, XKeyPressedEvent *event, char *buffer_return, int bytes_buffer, KeySym *keysym_return, Status *status_return); + +#else + + KeySym keysym = XStringToKeysym(str); + long ucs = keysym2ucs(keysym); + +// if( ucs == -1 && (keysym >= 0xFE50 && keysym <= 0xFE5F) ) { +// ucs = 0x0300 + (keysym & 0x000F); +// kWarning() << "Got dead symbol" << QString("0x%1").arg(keysym, 0, 16) << "named" << opton << "will use" << QString("0x%1").arg(ucs, 0, 16) << "as UCS"; +// } + + if( ucs == -1 ) { + nill++; + kWarning() << "No mapping from keysym:" << QString("0x%1").arg(keysym, 0, 16) << "named:" << opton << "to UCS"; + } + + QString ucsStr = QString(QChar((int)ucs)); + + // Combining Diacritical Marks + if( ucs >= 0x0300 && ucs <= 0x036F ) { + ucsStr = " " + ucsStr + " "; + } + +// kWarning() << "--" << opton << "keysym: " << keysym << QString("0x%1").arg(keysym, 0, 16) << "keysym2string" << XKeysymToString(keysym) +// << "---" << QString("0x%1").arg(ucs, 0, 16) << ucsStr; + + keySymbolMap[opton] = ucsStr; + + return ucsStr; + +#endif + +} + diff --git a/kcontrol/keyboard/preview/keysymhelper.h b/kcontrol/keyboard/preview/keysymhelper.h new file mode 100644 index 00000000..763e872e --- /dev/null +++ b/kcontrol/keyboard/preview/keysymhelper.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) + * + * 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 KEYSYMHELPER_H +#define KEYSYMHELPER_H + +#include +#include + +class KeySymHelper +{ +public: + KeySymHelper(); + + QString getKeySymbol(const QString &opton); + bool isFailed() const { + return nill >= 120; + } + +private: + QMap keySymbolMap; + int nill; +}; + +#endif // KEYSYMHELPER_H diff --git a/kcontrol/keyboard/tests/CMakeLists.txt b/kcontrol/keyboard/tests/CMakeLists.txt new file mode 100644 index 00000000..b2bbedc5 --- /dev/null +++ b/kcontrol/keyboard/tests/CMakeLists.txt @@ -0,0 +1,30 @@ +set ( text_paint_LIB ${KDE4_PLASMA_LIBS} ) + +MACRO(KEYBOARD_DAEMON_UNIT_TESTS _testname) + kde4_add_unit_test(${_testname}_test TESTNAME kcm-keyboard-${_testname} NOGUI ${_testname}_test.cpp ../${_testname}.cpp) + target_link_libraries(${_testname}_test ${KDE4_KDEUI_LIBS} ${QT_QTXML_LIBRARY} ${QT_QTTEST_LIBRARY} ${X11_Xkbfile_LIB} ${X11_LIBRARIES}) +ENDMACRO(KEYBOARD_DAEMON_UNIT_TESTS) + +MACRO(KEYBOARD_DAEMON_UNIT_TESTS2 _testname _src1 _src2 _src3) + kde4_add_unit_test(${_testname}_test TESTNAME kcm-keyboard-${_testname} NOGUI ${_testname}_test.cpp ../${_testname}.cpp ../${_src1} ../${_src2} ../${_src3}) + target_link_libraries(${_testname}_test ${KDE4_KDEUI_LIBS} ${QT_QTXML_LIBRARY} ${QT_QTTEST_LIBRARY} ${X11_Xkbfile_LIB}) +ENDMACRO(KEYBOARD_DAEMON_UNIT_TESTS2) + + +KEYBOARD_DAEMON_UNIT_TESTS(xkb_rules) +KEYBOARD_DAEMON_UNIT_TESTS(iso_codes) + +kde4_add_unit_test(flags_test TESTNAME kcm-keyboard-flags_test NOGUI flags_test.cpp ../flags.cpp ../x11_helper.cpp ../keyboard_config.cpp ../xkb_rules.cpp) +target_link_libraries(flags_test ${KDE4_KDEUI_LIBS} ${QT_QTXML_LIBRARY} ${QT_QTTEST_LIBRARY} ${X11_Xkbfile_LIB} ${X11_LIBRARIES} ${text_paint_LIB}) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config/base.1.1.xml ${CMAKE_CURRENT_BINARY_DIR}/config/base.1.1.xml COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config/base.bad.xml ${CMAKE_CURRENT_BINARY_DIR}/config/base.bad.xml COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config/base.xml ${CMAKE_CURRENT_BINARY_DIR}/config/base.xml COPYONLY) + +if( X11_XTest_FOUND ) + kde4_add_unit_test(keyboard_daemon_test TESTNAME kcm-keyboard-keyboard_daemon_test NOGUI keyboard_daemon_test.cpp ../keyboard_daemon.cpp ../layout_memory.cpp ../layout_memory_persister.cpp ../flags.cpp ../x11_helper.cpp ../xkb_helper.cpp ../xinput_helper.cpp ../layout_tray_icon.cpp ../keyboard_config.cpp ../xkb_rules.cpp ../keyboard_hardware.cpp ../bindings.cpp ../layouts_menu.cpp ../numlockx.c) + target_link_libraries(keyboard_daemon_test ${KDE4_KDEUI_LIBS} ${QT_QTXML_LIBRARY} ${QT_QTTEST_LIBRARY} ${X11_Xkbfile_LIB} ${X11_XTest_LIB} ${X11_LIBRARIES} ${text_paint_LIB}) + if(XiGetDevicePresence_FOUND) + target_link_libraries(keyboard_daemon_test ${X11_Xinput_LIB}) + endif(XiGetDevicePresence_FOUND) +endif( X11_XTest_FOUND ) diff --git a/kcontrol/keyboard/tests/config/base.1.1.xml b/kcontrol/keyboard/tests/config/base.1.1.xml new file mode 100644 index 00000000..97206a0b --- /dev/null +++ b/kcontrol/keyboard/tests/config/base.1.1.xml @@ -0,0 +1,68 @@ + + + + + + + pc101 + Generic 101-key PC + Generic + + + + + + + us + USA + USA + eng + + + + + chr + Cherokee + chr + + + chr + Cherokee2 + + + + bad + Bad Variant Missing configItem tag + chr + + + + + + tw + + zh + Taiwanese + + fox + + + + + + + + + grp + Key(s) to change layout + + + + + + \ No newline at end of file diff --git a/kcontrol/keyboard/tests/config/base.bad.xml b/kcontrol/keyboard/tests/config/base.bad.xml new file mode 100644 index 00000000..75bacdd2 --- /dev/null +++ b/kcontrol/keyboard/tests/config/base.bad.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/kcontrol/keyboard/tests/config/base.xml b/kcontrol/keyboard/tests/config/base.xml new file mode 100644 index 00000000..ddab0561 --- /dev/null +++ b/kcontrol/keyboard/tests/config/base.xml @@ -0,0 +1,48 @@ + + + + + + + pc101 + Generic 101-key PC + Generic + + + + + + + us + USA + USA + eng + + + + + chr + Cherokee + chr + + + + + + + + + + grp + Key(s) to change layout + + + + + + \ No newline at end of file diff --git a/kcontrol/keyboard/tests/flags_test.cpp b/kcontrol/keyboard/tests/flags_test.cpp new file mode 100644 index 00000000..59f73716 --- /dev/null +++ b/kcontrol/keyboard/tests/flags_test.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2011 Andriy Rysin (rysin@kde.org) + * + * 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 "../flags.h" +#include "../xkb_rules.h" +#include "../keyboard_config.h" + + +static QImage image(const QIcon& icon) { + return icon.pixmap(QSize(16,16), QIcon::Normal, QIcon::On).toImage(); +} + +class FlagsTest : public QObject +{ + Q_OBJECT + + Flags* flags; + const Rules* rules; + +private Q_SLOTS: + void initTestCase() { + flags = new Flags(); + rules = NULL; + } + + void cleanupTestCase() { + delete flags; + delete rules; + } + + void testRules() { + QVERIFY( flags != NULL ); + + QVERIFY( ! flags->getTransparentPixmap().isNull() ); + + const QIcon iconUs(flags->getIcon("us")); + QVERIFY( ! iconUs.isNull() ); + QVERIFY( flags->getIcon("--").isNull() ); + + KeyboardConfig keyboardConfig; + LayoutUnit layoutUnit("us"); + LayoutUnit layoutUnit1("us", "intl"); + layoutUnit1.setDisplayName("usi"); + LayoutUnit layoutUnit2("us", "other"); + + keyboardConfig.indicatorType = KeyboardConfig::SHOW_FLAG; + const QIcon iconUsFlag = flags->getIconWithText(layoutUnit, keyboardConfig); + QVERIFY( ! iconUsFlag.isNull() ); + QCOMPARE( image(iconUsFlag), image(iconUs) ); + + keyboardConfig.indicatorType = KeyboardConfig::SHOW_LABEL; + const QIcon iconUsText = flags->getIconWithText(layoutUnit, keyboardConfig); + QVERIFY( ! iconUsText.isNull() ); + QVERIFY( image(iconUsText) != image(iconUs) ); + + keyboardConfig.layouts.append(layoutUnit1); + QCOMPARE( flags->getShortText(layoutUnit, keyboardConfig), QString("us") ); + QCOMPARE( flags->getShortText(layoutUnit1, keyboardConfig), QString("usi") ); + QCOMPARE( flags->getShortText(layoutUnit2, keyboardConfig), QString("us") ); + + const Rules* rules = Rules::readRules(Rules::NO_EXTRAS); + QCOMPARE( flags->getLongText(layoutUnit, rules), QString("English (US)") ); + QVERIFY( flags->getLongText(layoutUnit1, rules).startsWith("English (US, international with dead keys)") ); + QCOMPARE( flags->getLongText(layoutUnit2, rules), QString("other") ); + + rules = NULL; // when no rules found + QCOMPARE( flags->getLongText(layoutUnit1, rules), QString("us - intl") ); + + flags->clearCache(); + } + +// void loadRulesBenchmark() { +// QBENCHMARK { +// Flags* flags = new Flags(); +// delete flags; +// } +// } + +}; + +// need GUI for xkb protocol in xkb_rules.cpp +QTEST_KDEMAIN( FlagsTest, GUI ) + +#include "flags_test.moc" diff --git a/kcontrol/keyboard/tests/iso_codes_test.cpp b/kcontrol/keyboard/tests/iso_codes_test.cpp new file mode 100644 index 00000000..14f16be8 --- /dev/null +++ b/kcontrol/keyboard/tests/iso_codes_test.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 Andriy Rysin (rysin@kde.org) + * + * 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 "../iso_codes.h" + + +class IsoCodesTest : public QObject +{ + Q_OBJECT + + IsoCodes* isoCodes; + +private Q_SLOTS: + void initTestCase() { +// isoCodes = new IsoCodes(IsoCodes::iso_639); + isoCodes = new IsoCodes(IsoCodes::iso_639_3); + } + + void cleanupTestCase() { + delete isoCodes; + } + + void testIsoCodes() { + QVERIFY( isoCodes != NULL ); + QVERIFY( ! isoCodes->getEntryList().isEmpty() ); +// const IsoCodeEntry* isoEntry = isoCodes->getEntry(IsoCodes::attr_iso_639_2T_code, "eng"); + const IsoCodeEntry* isoEntry = isoCodes->getEntry(IsoCodes::attr_iso_639_3_id, "eng"); + QVERIFY( isoEntry != NULL ); + QVERIFY( ! isoEntry->empty() ); +// QCOMPARE( isoEntry->value(IsoCodes::attr_iso_639_2T_code), QString("eng") ); +// QCOMPARE( isoEntry->value(IsoCodes::attr_iso_639_2B_code), QString("eng") ); +// QCOMPARE( isoEntry->value(IsoCodes::attr_iso_639_1_code), QString("en") ); + QCOMPARE( isoEntry->value("name"), QString("English") ); +// QCOMPARE( isoEntry->value("status"), QString("Active") ); + } + + void testIso639_3_Codes() { + QVERIFY( isoCodes != NULL ); + QVERIFY( ! isoCodes->getEntryList().isEmpty() ); + const IsoCodeEntry* isoEntry = isoCodes->getEntry(IsoCodes::attr_iso_639_3_id, "ant"); + QVERIFY( isoEntry != NULL ); + QVERIFY( ! isoEntry->empty() ); + QVERIFY( isoEntry->value("name") != QString("ant") ); + QCOMPARE( isoEntry->value("name"), QString("Antakarinya") ); + } + + void loadIsoCodesBenchmark() { + QBENCHMARK { + IsoCodes* isoCodes = new IsoCodes(IsoCodes::iso_639_3); + delete isoCodes; + } + } + +}; + +//TODO: something lighter than KDEMAIN ? +QTEST_KDEMAIN( IsoCodesTest, NoGUI ) + +#include "iso_codes_test.moc" diff --git a/kcontrol/keyboard/tests/keyboard_daemon_test.cpp b/kcontrol/keyboard/tests/keyboard_daemon_test.cpp new file mode 100644 index 00000000..8879daf9 --- /dev/null +++ b/kcontrol/keyboard/tests/keyboard_daemon_test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2011 Andriy Rysin (rysin@kde.org) + * + * 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 + +#include "../flags.h" +#include "../xkb_rules.h" +#include "../keyboard_config.h" +#include "../keyboard_daemon.h" + + +class KeyboardDaemonTest : public QObject +{ + Q_OBJECT + + KeyboardDaemon* keyboardDaemon; +// KApplication* kapplication; + +private Q_SLOTS: + void initTestCase() { +// kapplication = new KApplication(); +// const KAboutData* kAboutData = new KAboutData(i18n("a").toAscii(), i18n("a").toAscii(), KLocalizedString(), i18n("a").toAscii()); +// KCmdLineArgs::init(kAboutData); + keyboardDaemon = new KeyboardDaemon(this, QList()); + } + + void cleanupTestCase() { + delete keyboardDaemon; +// delete kapplication; + } + + void testDaemon() { + QVERIFY( keyboardDaemon != NULL ); + +// QVERIFY( ! flags->getTransparentPixmap().isNull() ); +// +// const QIcon iconUs(flags->getIcon("us")); +// QVERIFY( ! iconUs.isNull() ); +// QVERIFY( flags->getIcon("--").isNull() ); +// +// KeyboardConfig keyboardConfig; +// LayoutUnit layoutUnit("us"); +// LayoutUnit layoutUnit1("us", "intl"); +// layoutUnit1.setDisplayName("usi"); +// LayoutUnit layoutUnit2("us", "other"); +// +// keyboardConfig.showFlag = true; +// const QIcon iconUsFlag = flags->getIconWithText(layoutUnit, keyboardConfig); +// QVERIFY( ! iconUsFlag.isNull() ); +// QCOMPARE( image(iconUsFlag), image(iconUs) ); +// +// keyboardConfig.showFlag = false; +// const QIcon iconUsText = flags->getIconWithText(layoutUnit, keyboardConfig); +// QVERIFY( ! iconUsText.isNull() ); +// QVERIFY( image(iconUsText) != image(iconUs) ); +// +// keyboardConfig.layouts.append(layoutUnit1); +// QCOMPARE( flags->getShortText(layoutUnit, keyboardConfig), QString("us") ); +// QCOMPARE( flags->getShortText(layoutUnit1, keyboardConfig), QString("usi") ); +// QCOMPARE( flags->getShortText(layoutUnit2, keyboardConfig), QString("us") ); +// +// const Rules* rules = Rules::readRules(); +// QCOMPARE( flags->getLongText(layoutUnit, rules), QString("USA") ); +// QVERIFY( flags->getLongText(layoutUnit1, rules).startsWith("USA - International") ); +// QCOMPARE( flags->getLongText(layoutUnit2, rules), QString("USA - other") ); +// +// flags->clearCache(); + } + +// void loadRulesBenchmark() { +// QBENCHMARK { +// Flags* flags = new Flags(); +// delete flags; +// } +// } + +}; + +// need GUI for xkb protocol in xkb_rules.cpp +QTEST_KDEMAIN( KeyboardDaemonTest, GUI ) + +#include "keyboard_daemon_test.moc" diff --git a/kcontrol/keyboard/tests/layout_memory_persister_test.cpp b/kcontrol/keyboard/tests/layout_memory_persister_test.cpp new file mode 100644 index 00000000..0dd0c74c --- /dev/null +++ b/kcontrol/keyboard/tests/layout_memory_persister_test.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2011 Andriy Rysin (rysin@kde.org) + * + * 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 "../layout_memory_persister.h" +#include "../layout_memory.h" +#include "../keyboard_config.h" + + +class TestLayoutMemory: public LayoutMemory { +public: + TestLayoutMemory(const KeyboardConfig& keyboardConfig): + LayoutMemory(keyboardConfig) {} + QMap& getLayoutMap() { return layoutMap; } +}; + +class LayoutMemoryPersisterTest : public QObject +{ + Q_OBJECT + + QString path; + KeyboardConfig keyboardConfig; + TestLayoutMemory* layoutMemory; + LayoutMemoryPersister* layoutMemoryPersister; + + const LayoutUnit layoutUnit1; + const LayoutUnit layoutUnit2; + const LayoutUnit layoutUnit3; + + +public: + LayoutMemoryPersisterTest(): + layoutUnit1("xx"), + layoutUnit2("yy", "var1"), + layoutUnit3("zz", "var2") + {} + +private Q_SLOTS: + void initTestCase() { + path = "keyboard_memory_test.xml"; + QFile(path).remove(); + + layoutMemory = new TestLayoutMemory(keyboardConfig); + layoutMemoryPersister = new LayoutMemoryPersister(*layoutMemory); + +// QFile(path).remove(); + } + + void cleanupTestCase() { + delete layoutMemoryPersister; + delete layoutMemory; + } + + void testSaveNA() { + QFile file(path); + + keyboardConfig.switchingPolicy = KeyboardConfig::SWITCH_POLICY_WINDOW; + QVERIFY( ! layoutMemoryPersister->saveToFile(file) ); + QVERIFY(QFile(path).size() == 0); + + QVERIFY( ! layoutMemoryPersister->restoreFromFile(file) ); + } + + void testSaveGlobal() { + QFile file(path); + + keyboardConfig.switchingPolicy = KeyboardConfig::SWITCH_POLICY_GLOBAL; + layoutMemoryPersister->setGlobalLayout(layoutUnit1); + QVERIFY( layoutMemoryPersister->saveToFile(file) ); + QVERIFY(QFile(path).size() > 0); +// file.close(); + + keyboardConfig.layouts.clear(); + + QVERIFY( layoutMemoryPersister->restoreFromFile(file) ); + QVERIFY( !layoutMemoryPersister->getGlobalLayout().isValid() ); + +// file.close(); + keyboardConfig.layouts << layoutUnit1; + QVERIFY( layoutMemoryPersister->restoreFromFile(file) ); + QVERIFY( layoutUnit1.isValid() ); + QVERIFY( layoutMemoryPersister->getGlobalLayout().isValid() ); + QCOMPARE( layoutMemoryPersister->getGlobalLayout(), layoutUnit1); + } + + void testSaveByApp() { + QFile file(path); + + keyboardConfig.switchingPolicy = KeyboardConfig::SWITCH_POLICY_APPLICATION; + + layoutMemoryPersister->setGlobalLayout(LayoutUnit()); + layoutMemory->getLayoutMap().clear(); + + keyboardConfig.layouts.clear(); + keyboardConfig.layouts << layoutUnit1 << layoutUnit2; + + LayoutSet layoutSet1; + layoutSet1.layouts << layoutUnit1 << layoutUnit2; + layoutSet1.currentLayout = layoutUnit1; + layoutMemory->getLayoutMap().insert(QString("app1"), layoutSet1); + + LayoutSet layoutSet2; + layoutSet2.layouts << layoutUnit2 << layoutUnit1 << layoutUnit3; + layoutSet2.currentLayout = layoutUnit2; + layoutMemory->getLayoutMap().insert(QString("app2"), layoutSet2); + + QVERIFY( layoutMemoryPersister->saveToFile(file) ); + QVERIFY(QFile(path).size() > 0); + file.close(); + + layoutMemory->getLayoutMap().clear(); + QVERIFY( ! layoutMemory->getLayoutMap().value("app1").isValid() ); + QVERIFY( ! layoutMemory->getLayoutMap().value("app2").isValid() ); + + QVERIFY( layoutMemoryPersister->restoreFromFile(file) ); + QVERIFY( ! layoutMemoryPersister->getGlobalLayout().isValid() ); + QCOMPARE( layoutMemory->getLayoutMap().value("app1"), layoutSet1 ); + QVERIFY( ! layoutMemory->getLayoutMap().value("app2").isValid() ); + + keyboardConfig.layouts << layoutUnit3; + + file.close(); + QVERIFY( layoutMemoryPersister->restoreFromFile(file) ); + QVERIFY( ! layoutMemoryPersister->getGlobalLayout().isValid() ); + QCOMPARE( layoutMemory->getLayoutMap().value("app1"), layoutSet1 ); + QCOMPARE( layoutMemory->getLayoutMap().value("app2"), layoutSet2 ); + } + +// void layoutMemroyPersisterBenchmark() { +// QBENCHMARK { +// //TODO: generate big map +// layoutMemoryPersister->save(); +// layoutMemoryPersister->restore(); +// } +// } + +}; + +// need GUI for xkb protocol +QTEST_KDEMAIN( LayoutMemoryPersisterTest, GUI ) + +#include "layout_memory_persister_test.moc" diff --git a/kcontrol/keyboard/tests/xkb_rules_test.cpp b/kcontrol/keyboard/tests/xkb_rules_test.cpp new file mode 100644 index 00000000..9cee188d --- /dev/null +++ b/kcontrol/keyboard/tests/xkb_rules_test.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2011 Andriy Rysin (rysin@kde.org) + * + * 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 "../xkb_rules.h" + +#include +#include + +static const Rules::ExtrasFlag readExtras = Rules::NO_EXTRAS; + +class RulesTest : public QObject +{ + Q_OBJECT + + Rules* rules; + +private Q_SLOTS: + void initTestCase() { + rules = Rules::readRules(readExtras); + } + + void cleanupTestCase() { + delete rules; + } + + void testRules() { + QVERIFY( rules != NULL ); + QVERIFY( rules->modelInfos.size() > 0 ); + QVERIFY( rules->layoutInfos.size() > 0 ); + QVERIFY( rules->optionGroupInfos.size() > 0 ); + } + + void testModel() { + foreach(const ModelInfo* modelInfo, rules->modelInfos) { + QVERIFY( modelInfo != NULL); + QVERIFY( modelInfo->name.length() > 0 ); + QVERIFY( modelInfo->description.length() > 0 ); +// QVERIFY( ! modelInfo->vendor.isEmpty() ); + } + } + + void testLayouts() { + foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { + QVERIFY( layoutInfo != NULL); + QVERIFY( ! layoutInfo->name.isEmpty() ); +// const char* desc = layoutInfo->name.toUtf8() ; +// qDebug() << layoutInfo->name; + QVERIFY( ! layoutInfo->description.isEmpty() ); + + foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { + QVERIFY( variantInfo != NULL ); + QVERIFY( ! variantInfo->name.isEmpty() ); + QVERIFY( ! variantInfo->description.isEmpty() ); + } + foreach(const QString& language, layoutInfo->languages) { + QVERIFY( ! language.isEmpty() ); + } + } + } + + void testOptionGroups() { + foreach(const OptionGroupInfo* optionGroupInfo, rules->optionGroupInfos) { + QVERIFY( optionGroupInfo != NULL); + QVERIFY( ! optionGroupInfo->name.isEmpty() ); + QVERIFY( ! optionGroupInfo->description.isEmpty() ); + // optionGroupInfo->exclusive + + foreach(const OptionInfo* optionInfo, optionGroupInfo->optionInfos) { + QVERIFY( optionInfo != NULL ); + QVERIFY( ! optionInfo->name.isEmpty() ); + QVERIFY( ! optionInfo->description.isEmpty() ); + } + } + } + + void testExtras() { + Rules* rulesWithExtras = Rules::readRules(Rules::READ_EXTRAS); + QVERIFY2(rulesWithExtras->layoutInfos.size() > rules->layoutInfos.size(), "Rules with extras should have more layouts"); + + foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { + QVERIFY( ! layoutInfo->fromExtras ); + } + + bool foundFromExtras = false, foundNonExtras = false; + foreach(const LayoutInfo* layoutInfo, rulesWithExtras->layoutInfos) { + if( layoutInfo->fromExtras ) foundFromExtras = true; + if( ! layoutInfo->fromExtras ) foundNonExtras = true; + layoutInfo->languages.size(); // make sure we can access all merged objects + layoutInfo->variantInfos.size(); // make sure we can access all merged objects + } + QVERIFY( foundNonExtras ); + QVERIFY( foundFromExtras ); + } + + void testWriteNewXml() { + QDomDocument doc("xkbConfigRegistry"); + QDomElement root = doc.createElement("xkbConfigRegistry"); + root.setAttribute("version", "2.0"); + doc.appendChild(root); + + QDomElement modelList = doc.createElement("modelList"); + root.appendChild(modelList); + foreach(const ModelInfo* modelInfo, rules->modelInfos) { + QDomElement model = doc.createElement("model"); + model.setAttribute("name", modelInfo->name); + model.setAttribute("description", modelInfo->description); + model.setAttribute("vendor", modelInfo->vendor); + modelList.appendChild(model); + } + + QDomElement layoutList = doc.createElement("layoutList"); + foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { + QDomElement layout = doc.createElement("layout"); + layout.setAttribute("name", layoutInfo->name); + layout.setAttribute("description", layoutInfo->description); + + QDomElement langList = doc.createElement("languageList"); + foreach(const QString& lang, layoutInfo->languages) { + QDomElement langNode = doc.createElement("lang"); + langNode.setAttribute("iso639Id", lang); + langList.appendChild(langNode); + } + if( langList.hasChildNodes() ) { + layout.appendChild(langList); + } + + QDomElement variantList = doc.createElement("variantList"); + foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { + QDomElement variant = doc.createElement("variant"); + variant.setAttribute("name", variantInfo->name); + variant.setAttribute("description", variantInfo->description); + + QDomElement langList = doc.createElement("languageList"); + foreach(const QString& lang, variantInfo->languages) { + QDomElement langNode = doc.createElement("lang"); + langNode.setAttribute("iso639Id", lang); + langList.appendChild(langNode); + } + if( langList.hasChildNodes() ) { + variant.appendChild(langList); + } + + variantList.appendChild(variant); + } + if( variantList.hasChildNodes() ) { + layout.appendChild(variantList); + } + + layoutList.appendChild(layout); + } + root.appendChild(layoutList); + + QDomElement optionGroupList = doc.createElement("optionList"); + foreach(const OptionGroupInfo* optionGroupInfo, rules->optionGroupInfos) { + QDomElement optionGroup = doc.createElement("optionGroup"); + optionGroup.setAttribute("name", optionGroupInfo->name); + optionGroup.setAttribute("description", optionGroupInfo->description); + optionGroup.setAttribute("exclusive", optionGroupInfo->exclusive); + + foreach(const OptionInfo* optionGroupInfo, optionGroupInfo->optionInfos) { + QDomElement option = doc.createElement("option"); + option.setAttribute("name", optionGroupInfo->name); + option.setAttribute("description", optionGroupInfo->description); + optionGroup.appendChild(option); + } + + optionGroupList.appendChild(optionGroup); + } + root.appendChild(optionGroupList); + + QFile file("base2.xml"); + if( ! file.open( QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) ) { + kWarning() << "Failed to open layout memory xml file for writing" << file.fileName(); + QFAIL("failed"); + } + + QTextStream out(&file); + out << doc.toString(); + } + + void testRulesVersion() { + QVERIFY(!rules->version.isEmpty()); + + Rules* rules10 = new Rules(); + Rules::readRules(rules10, QString("config/base.xml"), false); + QCOMPARE(rules10->version, QString("1.0")); + delete rules10; + + Rules* rules11 = new Rules(); + Rules::readRules(rules11, QString("config/base.1.1.xml"), false); + QCOMPARE(rules11->version, QString("1.1")); + + foreach(const LayoutInfo* layoutInfo, rules11->layoutInfos) { + QVERIFY( layoutInfo != NULL); + QVERIFY( ! layoutInfo->name.isEmpty() ); + QVERIFY( ! layoutInfo->description.isEmpty() ); + + foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { + QVERIFY( variantInfo != NULL ); + QVERIFY( ! variantInfo->name.isEmpty() ); + QVERIFY( ! variantInfo->description.isEmpty() ); + } + } + + delete rules11; + } + + void loadRulesBenchmark() { + QBENCHMARK { + Rules* rules = Rules::readRules(readExtras); + delete rules; + } + } + +}; + +// need kde libs for config-workspace.h used in xkb_rules.cpp +// need GUI for xkb protocol +QTEST_KDEMAIN( RulesTest, GUI ) + +#include "xkb_rules_test.moc" diff --git a/kcontrol/keyboard/x11_helper.cpp b/kcontrol/keyboard/x11_helper.cpp new file mode 100644 index 00000000..f8060fb2 --- /dev/null +++ b/kcontrol/keyboard/x11_helper.cpp @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "x11_helper.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + + +// more information about the limit https://bugs.freedesktop.org/show_bug.cgi?id=19501 +int X11Helper::MAX_GROUP_COUNT = 4; +int X11Helper::ARTIFICIAL_GROUP_LIMIT_COUNT = 8; + +const char* X11Helper::LEFT_VARIANT_STR = "("; +const char* X11Helper::RIGHT_VARIANT_STR = ")"; + +bool X11Helper::xkbSupported(int* xkbOpcode) +{ + // Verify the Xlib has matching XKB extension. + + int major = XkbMajorVersion; + int minor = XkbMinorVersion; + + if (!XkbLibraryVersion(&major, &minor)) + { + kWarning() << "Xlib XKB extension " << major << '.' << minor << + " != " << XkbMajorVersion << '.' << XkbMinorVersion; + return false; + } + + // Verify the X server has matching XKB extension. + + int opcode_rtrn; + int error_rtrn; + int xkb_opcode; + if( ! XkbQueryExtension(QX11Info::display(), &opcode_rtrn, &xkb_opcode, &error_rtrn, &major, &minor)) { + kWarning() << "X server XKB extension " << major << '.' << minor << + " != " << XkbMajorVersion << '.' << XkbMinorVersion; + return false; + } + + if( xkbOpcode != NULL ) { + *xkbOpcode = xkb_opcode; + } + + return true; +} + +void X11Helper::switchToNextLayout() +{ + int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count + int group = (X11Helper::getGroup() + 1) % size; + X11Helper::setGroup(group); +} + +void X11Helper::scrollLayouts(int delta) +{ + int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count + int group = X11Helper::getGroup() + delta; + group = group < 0 ? size - ((-group) % size) : group % size; + + X11Helper::setGroup(group); +} + +QStringList X11Helper::getLayoutsListAsString(const QList& layoutsList) +{ + QStringList stringList; + foreach(const LayoutUnit& layoutUnit, layoutsList) { + stringList << layoutUnit.toString(); + } + return stringList; +} + +bool X11Helper::setLayout(const LayoutUnit& layout) +{ + QList currentLayouts = getLayoutsList(); + int idx = currentLayouts.indexOf(layout); + if( idx == -1 || idx >= X11Helper::MAX_GROUP_COUNT ) { + kWarning() << "Layout" << layout.toString() << "is not found in current layout list" + << getLayoutsListAsString(currentLayouts); + return false; + } + + return X11Helper::setGroup((unsigned int)idx); +} + +bool X11Helper::setDefaultLayout() { + return X11Helper::setGroup(0); +} + +bool X11Helper::isDefaultLayout() { + return X11Helper::getGroup() == 0; +} + +LayoutUnit X11Helper::getCurrentLayout() +{ + QList currentLayouts = getLayoutsList(); + unsigned int group = X11Helper::getGroup(); + if( group < (unsigned int)currentLayouts.size() ) + return currentLayouts[group]; + + kWarning() << "Current group number" << group << "is outside of current layout list" << + getLayoutsListAsString(currentLayouts); + return LayoutUnit(); +} + +LayoutSet X11Helper::getCurrentLayouts() +{ + LayoutSet layoutSet; + + QList currentLayouts = getLayoutsList(); + layoutSet.layouts = currentLayouts; + + unsigned int group = X11Helper::getGroup(); + if( group < (unsigned int)currentLayouts.size() ) { + layoutSet.currentLayout = currentLayouts[group]; + } + else { + kWarning() << "Current group number" << group << "is outside of current layout list" << getLayoutsListAsString(currentLayouts); + layoutSet.currentLayout = LayoutUnit(); + } + + return layoutSet; +} + + +//static QString addNum(const QString& str, int n) +//{ +// QString format("%1%2"); +// if( str.length() >= 3 ) return format.arg(str.left(2)).arg(n); +// return format.arg(str).arg(n); +//} + +QList X11Helper::getLayoutsList() +{ + XkbConfig xkbConfig; + QList layouts; + if( X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::LAYOUTS_ONLY) ) { + for(int i=0; i 0) || (real_prop_type != XA_STRING) || (fmt != 8)) { + if (prop_data) + XFree(prop_data); + kWarning() << "Failed to fetch layouts from server:" << "Wrong property format"; + return false; + } + +// qDebug() << "prop_data:" << nitems << prop_data; + QStringList names; + for(char* p=prop_data; p-prop_data < (long)nitems && p != NULL; p += strlen(p)+1) { + names.append( p ); +// kDebug() << " " << p; + } + + if( names.count() < 4 ) { //{ rules, model, layouts, variants, options } + XFree(prop_data); + return false; + } + + if( fetchType == ALL || fetchType == LAYOUTS_ONLY ) { + QStringList layouts = names[2].split(OPTIONS_SEPARATOR); + QStringList variants = names[3].split(OPTIONS_SEPARATOR); + + for(int ii=0; iilayouts << (layouts[ii] != NULL ? layouts[ii] : ""); + xkbConfig->variants << (ii < variants.count() && variants[ii] != NULL ? variants[ii] : ""); + } + kDebug() << "Fetched layout groups from X server:" + << "\tlayouts:" << xkbConfig->layouts + << "\tvariants:" << xkbConfig->variants; + } + + if( fetchType == ALL || fetchType == MODEL_ONLY ) { + xkbConfig->keyboardModel = (names[1] != NULL ? names[1] : ""); + kDebug() << "Fetched keyboard model from X server:" << xkbConfig->keyboardModel; + } + + if( fetchType == ALL ) { + if( names.count() >= 5 ) { + QString options = (names[4] != NULL ? names[4] : ""); + xkbConfig->options = options.split(OPTIONS_SEPARATOR); + kDebug() << "Fetched xkbOptions from X server:" << options; + } + } + + XFree(prop_data); + return true; +} + +XEventNotifier::XEventNotifier(QWidget* parent): + QWidget(parent), + xkbOpcode(-1) +{ + if( KApplication::kApplication() == NULL ) { + kWarning() << "Layout Widget won't work properly without KApplication instance"; + } +} + +void XEventNotifier::start() +{ + if( KApplication::kApplication() != NULL && X11Helper::xkbSupported(&xkbOpcode) ) { + registerForXkbEvents(QX11Info::display()); + + // start the event loop + KApplication::kApplication()->installX11EventFilter(this); + } +} + +void XEventNotifier::stop() +{ + if( KApplication::kApplication() != NULL ) { + //TODO: unregister + // XEventNotifier::unregisterForXkbEvents(QX11Info::display()); + + // stop the event loop + KApplication::kApplication()->removeX11EventFilter(this); + } +} + +bool XEventNotifier::isXkbEvent(XEvent* event) +{ + return event->type == xkbOpcode; +} + +bool XEventNotifier::processOtherEvents(XEvent* /*event*/) +{ + return true; +} + +bool XEventNotifier::processXkbEvents(XEvent* event) +{ + if( XEventNotifier::isGroupSwitchEvent(event) ) { + emit(layoutChanged()); + } + else if( XEventNotifier::isLayoutSwitchEvent(event) ) { + emit(layoutMapChanged()); + } + return true; +} + +bool XEventNotifier::x11Event(XEvent * event) +{ + // qApp->x11ProcessEvent ( event ); + if( isXkbEvent(event) ) { + processXkbEvents(event); + } + else { + processOtherEvents(event); + } + return QWidget::x11Event(event); +} + +bool XEventNotifier::isGroupSwitchEvent(XEvent* event) +{ + XkbEvent *xkbEvent = (XkbEvent*) event; +#define GROUP_CHANGE_MASK \ + ( XkbGroupStateMask | XkbGroupBaseMask | XkbGroupLatchMask | XkbGroupLockMask ) + + return xkbEvent->any.xkb_type == XkbStateNotify && (xkbEvent->state.changed & GROUP_CHANGE_MASK); +} + +bool XEventNotifier::isLayoutSwitchEvent(XEvent* event) +{ + XkbEvent *xkbEvent = (XkbEvent*) event; + + return //( (xkbEvent->any.xkb_type == XkbMapNotify) && (xkbEvent->map.changed & XkbKeySymsMask) ) || +/* || ( (xkbEvent->any.xkb_type == XkbNamesNotify) && (xkbEvent->names.changed & XkbGroupNamesMask) || )*/ + (xkbEvent->any.xkb_type == XkbNewKeyboardNotify); +} + +int XEventNotifier::registerForXkbEvents(Display* display) +{ + int eventMask = XkbNewKeyboardNotifyMask | XkbStateNotifyMask; + if( ! XkbSelectEvents(display, XkbUseCoreKbd, eventMask, eventMask) ) { + kWarning() << "Couldn't select desired XKB events"; + return false; + } + return true; +} + + +static const char* LAYOUT_VARIANT_SEPARATOR_PREFIX = "("; +static const char* LAYOUT_VARIANT_SEPARATOR_SUFFIX = ")"; + +static QString& stripVariantName(QString& variant) +{ + if( variant.endsWith(LAYOUT_VARIANT_SEPARATOR_SUFFIX) ) { + int suffixLen = strlen(LAYOUT_VARIANT_SEPARATOR_SUFFIX); + return variant.remove(variant.length()-suffixLen, suffixLen); + } + return variant; +} + +LayoutUnit::LayoutUnit(const QString& fullLayoutName) +{ + QStringList lv = fullLayoutName.split(LAYOUT_VARIANT_SEPARATOR_PREFIX); + layout = lv[0]; + variant = lv.size() > 1 ? stripVariantName(lv[1]) : ""; +} + +QString LayoutUnit::toString() const +{ + if( variant.isEmpty() ) + return layout; + + return layout + LAYOUT_VARIANT_SEPARATOR_PREFIX+variant+LAYOUT_VARIANT_SEPARATOR_SUFFIX; +} + +const int LayoutUnit::MAX_LABEL_LENGTH = 3; diff --git a/kcontrol/keyboard/x11_helper.h b/kcontrol/keyboard/x11_helper.h new file mode 100644 index 00000000..69490d64 --- /dev/null +++ b/kcontrol/keyboard/x11_helper.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 X11_HELPER_H_ +#define X11_HELPER_H_ + +#include +#include +#include +#include + + +class XEventNotifier : public QWidget { + Q_OBJECT + +Q_SIGNALS: + void layoutChanged(); + void layoutMapChanged(); + +public: + XEventNotifier(QWidget* parent=NULL); + virtual ~XEventNotifier() {} + + virtual void start(); + virtual void stop(); + +protected: + bool x11Event(XEvent * e); + virtual bool processOtherEvents(XEvent* e); + virtual bool processXkbEvents(XEvent* e); + +private: + int registerForXkbEvents(Display* display); + bool isXkbEvent(XEvent* event); + bool isGroupSwitchEvent(XEvent* event); + bool isLayoutSwitchEvent(XEvent* event); + + int xkbOpcode; +}; + +struct XkbConfig { + QString keyboardModel; + QStringList layouts; + QStringList variants; + QStringList options; + + bool isValid() { return ! layouts.empty(); } +}; + + +struct LayoutUnit { + static const int MAX_LABEL_LENGTH; + + //TODO: move these to private? + QString layout; + QString variant; + + LayoutUnit() {} + explicit LayoutUnit(const QString& fullLayoutName); + LayoutUnit(const QString& layout_, const QString& variant_) { + layout = layout_; + variant = variant_; + } + /*explicit*/ LayoutUnit(const LayoutUnit& layoutUnit) { + layout = layoutUnit.layout; + variant = layoutUnit.variant; + displayName = layoutUnit.displayName; + shortcut = layoutUnit.shortcut; + } + + QString getRawDisplayName() const { return displayName; } + QString getDisplayName() const { return !displayName.isEmpty() ? displayName : layout; } + void setDisplayName(const QString& name) { displayName = name; } + + void setShortcut(const QKeySequence& shortcut) { this->shortcut = shortcut; } + QKeySequence getShortcut() const { return shortcut; } + + bool isEmpty() const { return layout.isEmpty(); } + bool isValid() const { return ! isEmpty(); } + bool operator==(const LayoutUnit& layoutItem) const { + return layout==layoutItem.layout && variant==layoutItem.variant; + } + bool operator!=(const LayoutUnit& layoutItem) const { + return ! (*this == layoutItem); + } + QString toString() const; + +private: + QString displayName; + QKeySequence shortcut; +}; + +struct LayoutSet { + QList layouts; + LayoutUnit currentLayout; + + LayoutSet() {} + + LayoutSet(const LayoutSet& currentLayouts) { + this->layouts = currentLayouts.layouts; + this->currentLayout = currentLayouts.currentLayout; + } + + bool isValid() const { + return currentLayout.isValid() && layouts.contains(currentLayout); + } + + bool operator == (const LayoutSet& currentLayouts) const { + return this->layouts == currentLayouts.layouts + && this->currentLayout == currentLayouts.currentLayout; + } + + LayoutSet& operator = (const LayoutSet& currentLayouts) { + this->layouts = currentLayouts.layouts; + this->currentLayout = currentLayouts.currentLayout; + return *this; + } + + QString toString() const { + QString str(currentLayout.toString()); + str += ": "; + foreach(const LayoutUnit& layoutUnit, layouts) { + str += layoutUnit.toString() + " "; + } + return str; + } + + static QString toString(const QList& layoutUnits) { + QString str; + foreach(const LayoutUnit& layoutUnit, layoutUnits) { + str += layoutUnit.toString() + ","; + } + return str; + } +}; + +class X11Helper +{ +public: + static int MAX_GROUP_COUNT; + static int ARTIFICIAL_GROUP_LIMIT_COUNT; + + static const char* LEFT_VARIANT_STR; + static const char* RIGHT_VARIANT_STR; + + static bool xkbSupported(int* xkbOpcode); + + static void switchToNextLayout(); + static void scrollLayouts(int delta); + static bool isDefaultLayout(); + static bool setDefaultLayout(); + static bool setLayout(const LayoutUnit& layout); + static LayoutUnit getCurrentLayout(); + static LayoutSet getCurrentLayouts(); + static QList getLayoutsList(); + static QStringList getLayoutsListAsString(const QList& layoutsList); + + enum FetchType { ALL, LAYOUTS_ONLY, MODEL_ONLY }; + static bool getGroupNames(Display* dpy, XkbConfig* xkbConfig, FetchType fetchType); + +private: + static unsigned int getGroup(); + static bool setGroup(unsigned int group); +}; + +#endif /* X11_HELPER_H_ */ diff --git a/kcontrol/keyboard/xinput_helper.cpp b/kcontrol/keyboard/xinput_helper.cpp new file mode 100644 index 00000000..2a10f340 --- /dev/null +++ b/kcontrol/keyboard/xinput_helper.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "xinput_helper.h" + +#include +#include + +#include + +#include +#include +#include + +#ifdef HAVE_XINPUT_AND_DEVICE_NOTIFY +#include +#endif + +#include + +#include "x11_helper.h" + +#include + +static int DEVICE_NONE = 0; +static int DEVICE_KEYBOARD = 1; +static int DEVICE_POINTER = 2; + +XInputEventNotifier::XInputEventNotifier(QWidget* parent): + XEventNotifier(parent), + xinputEventType(-1) +{ +} + +void XInputEventNotifier::start() +{ + if( KApplication::kApplication() != NULL ) { + registerForNewDeviceEvent(QX11Info::display()); + } + + XEventNotifier::start(); +} + +void XInputEventNotifier::stop() +{ + XEventNotifier::stop(); + + if( KApplication::kApplication() != NULL ) { + // XEventNotifier::unregisterForNewDeviceEvent(QX11Info::display()); + } +} + +bool XInputEventNotifier::processOtherEvents(XEvent* event) +{ + int newDeviceType = getNewDeviceEventType(event); + if( newDeviceType == DEVICE_KEYBOARD ) { + emit(newKeyboardDevice()); + } + else if( newDeviceType == DEVICE_POINTER ) { + emit(newPointerDevice()); + emit(newKeyboardDevice()); // arghhh, looks like X resets xkb map even when only pointer device is connected + } + return true; +} + + +#ifdef HAVE_XINPUT_AND_DEVICE_NOTIFY + +extern "C" { + extern int _XiGetDevicePresenceNotifyEvent(Display *); +} + +// This is ugly but allows to skip multiple execution of setxkbmap +// for all keyboard devices that don't care about layouts +static bool isRealKeyboard(const char* deviceName) +{ + return strstr(deviceName, "Video Bus") == NULL + && strstr(deviceName, "Sleep Button") == NULL + && strstr(deviceName, "Power Button") == NULL + && strstr(deviceName, "WMI hotkeys") == NULL; +} + +int XInputEventNotifier::getNewDeviceEventType(XEvent* event) +{ + int newDeviceType = DEVICE_NONE; + + if( xinputEventType != -1 && event->type == xinputEventType ) { + XDevicePresenceNotifyEvent *xdpne = (XDevicePresenceNotifyEvent*) event; + if( xdpne->devchange == DeviceEnabled ) { + int ndevices; + XDeviceInfo *devices = XListInputDevices(xdpne->display, &ndevices); + if( devices != NULL ) { +// kDebug() << "New device id:" << xdpne->deviceid; + for(int i=0; ideviceid ) { + if( devices[i].use == IsXKeyboard || devices[i].use == IsXExtensionKeyboard ) { + if( isRealKeyboard(devices[i].name) ) { + newDeviceType = DEVICE_KEYBOARD; + kDebug() << "new keyboard device, id:" << devices[i].id << "name:" << devices[i].name << "used as:" << devices[i].use; + break; + } + } + if( devices[i].use == IsXPointer || devices[i].use == IsXExtensionPointer ) { + newDeviceType = DEVICE_POINTER; + kDebug() << "new pointer device, id:" << devices[i].id << "name:" << devices[i].name << "used as:" << devices[i].use; + break; + } + } + } + XFreeDeviceList(devices); + } + } + } + return newDeviceType; +} + +int XInputEventNotifier::registerForNewDeviceEvent(Display* display) +{ + int xitype; + XEventClass xiclass; + + DevicePresence(display, xitype, xiclass); + XSelectExtensionEvent(display, DefaultRootWindow(display), &xiclass, 1); + kDebug() << "Registered for new device events from XInput, class" << xitype; + xinputEventType = xitype; + return xitype; +} + +#else + +#ifdef __GNUC__ +#warning "Keyboard daemon is compiled without XInput, keyboard settings will be reset when new keyboard device is plugged in!" +#endif + +int XInputEventNotifier::registerForNewDeviceEvent(Display* /*display*/) +{ + kWarning() << "Keyboard kded daemon is compiled without XInput, xkb configuration will be reset when new keyboard device is plugged in!"; + return -1; +} + +int XInputEventNotifier::getNewDeviceEventType(XEvent* /*event*/) +{ + return DEVICE_NONE; +} + +#endif diff --git a/kcontrol/keyboard/xinput_helper.h b/kcontrol/keyboard/xinput_helper.h new file mode 100644 index 00000000..92f1eb65 --- /dev/null +++ b/kcontrol/keyboard/xinput_helper.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 XINPUT_HELPER_H_ +#define XINPUT_HELPER_H_ + +#include "x11_helper.h" + + +class XInputEventNotifier: public XEventNotifier { + Q_OBJECT + +public: + XInputEventNotifier(QWidget* parent=NULL); + + void start(); + void stop(); + + int registerForNewDeviceEvent(Display* dpy); + +Q_SIGNALS: + void newKeyboardDevice(); + void newPointerDevice(); + +protected: + bool processOtherEvents(XEvent* event); + +private: + int getNewDeviceEventType(XEvent* event); + + int xinputEventType; +}; + +#endif /* XINPUT_HELPER_H_ */ diff --git a/kcontrol/keyboard/xkb_helper.cpp b/kcontrol/keyboard/xkb_helper.cpp new file mode 100644 index 00000000..60bf5a8f --- /dev/null +++ b/kcontrol/keyboard/xkb_helper.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "xkb_helper.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "keyboard_config.h" + + +static const char* SETXKBMAP_EXEC = "setxkbmap"; +static const char* XMODMAP_EXEC = "xmodmap"; + +static bool setxkbmapNotFound = false; +static QString setxkbmapExe; + +static bool xmodmapNotFound = false; +static QString xmodmapExe; + +static const QString COMMAND_OPTIONS_SEPARATOR(","); + +static +QString getSetxkbmapExe() +{ + if( setxkbmapNotFound ) + return ""; + + if( setxkbmapExe.isEmpty() ) { + setxkbmapExe = KGlobal::dirs()->findExe(SETXKBMAP_EXEC); + if( setxkbmapExe.isEmpty() ) { + setxkbmapNotFound = true; + kError() << "Can't find" << SETXKBMAP_EXEC << "- keyboard layouts won't be configured"; + return ""; + } + } + return setxkbmapExe; +} + +static +void executeXmodmap(const QString& configFileName) +{ + if( xmodmapNotFound ) + return; + + if( QFile(configFileName).exists() ) { + if( xmodmapExe.isEmpty() ) { + xmodmapExe = KGlobal::dirs()->findExe(XMODMAP_EXEC); + if( xmodmapExe.isEmpty() ) { + xmodmapNotFound = true; + kError() << "Can't find" << XMODMAP_EXEC << "- xmodmap files won't be run"; + return; + } + } + + KProcess xmodmapProcess; + xmodmapProcess << xmodmapExe; + xmodmapProcess << configFileName; + kDebug() << "Executing" << xmodmapProcess.program().join(" "); + if( xmodmapProcess.execute() != 0 ) { + kError() << "Failed to execute " << xmodmapProcess.program(); + } + } +} + +static +void restoreXmodmap() +{ + // TODO: is just home .Xmodmap enough or should system be involved too? + // QString configFileName = QDir("/etc/X11/xinit").filePath(".Xmodmap"); + // executeXmodmap(configFileName); + QString configFileName = QDir::home().filePath(".Xmodmap"); + executeXmodmap(configFileName); +} + +//TODO: make private +bool XkbHelper::runConfigLayoutCommand(const QStringList& setxkbmapCommandArguments) +{ + QTime timer; + timer.start(); + + KProcess setxkbmapProcess; + setxkbmapProcess << getSetxkbmapExe() << setxkbmapCommandArguments; + int res = setxkbmapProcess.execute(); + + if( res == 0 ) { // restore Xmodmap mapping reset by setxkbmap + kDebug() << "Executed successfully in " << timer.elapsed() << "ms" << setxkbmapProcess.program().join(" "); + restoreXmodmap(); + kDebug() << "\t and with xmodmap" << timer.elapsed() << "ms"; + return true; + } + else { + kError() << "Failed to run" << setxkbmapProcess.program().join(" ") << "return code:" << res; + } + return false; +} + +bool XkbHelper::initializeKeyboardLayouts(const QList& layoutUnits) +{ + QStringList layouts; + QStringList variants; + foreach (const LayoutUnit& layoutUnit, layoutUnits) { + layouts.append(layoutUnit.layout); + variants.append(layoutUnit.variant); + } + + QStringList setxkbmapCommandArguments; + setxkbmapCommandArguments.append("-layout"); + setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); + if( ! variants.join("").isEmpty() ) { + setxkbmapCommandArguments.append("-variant"); + setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); + } + + return runConfigLayoutCommand(setxkbmapCommandArguments); +} + +bool XkbHelper::initializeKeyboardLayouts(KeyboardConfig& config) +{ + QStringList setxkbmapCommandArguments; + if( ! config.keyboardModel.isEmpty() ) { + XkbConfig xkbConfig; + X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::MODEL_ONLY); + if( xkbConfig.keyboardModel != config.keyboardModel ) { + setxkbmapCommandArguments.append("-model"); + setxkbmapCommandArguments.append(config.keyboardModel); + } + } + if( config.configureLayouts ) { + QStringList layouts; + QStringList variants; + QList defaultLayouts = config.getDefaultLayouts(); + foreach (const LayoutUnit& layoutUnit, defaultLayouts) { + layouts.append(layoutUnit.layout); + variants.append(layoutUnit.variant); + } + + setxkbmapCommandArguments.append("-layout"); + setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); + if( ! variants.join("").isEmpty() ) { + setxkbmapCommandArguments.append("-variant"); + setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); + } + } + if( config.resetOldXkbOptions ) { + setxkbmapCommandArguments.append("-option"); + } + if( ! config.xkbOptions.isEmpty() ) { + setxkbmapCommandArguments.append("-option"); + setxkbmapCommandArguments.append(config.xkbOptions.join(COMMAND_OPTIONS_SEPARATOR)); + } + + if( ! setxkbmapCommandArguments.isEmpty() ) { + return runConfigLayoutCommand(setxkbmapCommandArguments); + if( config.configureLayouts ) { + X11Helper::setDefaultLayout(); + } + } + return false; +} diff --git a/kcontrol/keyboard/xkb_helper.h b/kcontrol/keyboard/xkb_helper.h new file mode 100644 index 00000000..5e4f94d2 --- /dev/null +++ b/kcontrol/keyboard/xkb_helper.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 XKB_HELPER_H_ +#define XKB_HELPER_H_ + +template class QList; +class LayoutUnit; +class QStringList; +class KeyboardConfig; + +class XkbHelper { +public: + static bool initializeKeyboardLayouts(KeyboardConfig& config); + static bool initializeKeyboardLayouts(const QList& layouts); + static bool runConfigLayoutCommand(const QStringList& setxkbmapCommandArguments); +}; + +#endif /* XKB_HELPER_H_ */ diff --git a/kcontrol/keyboard/xkb_rules.cpp b/kcontrol/keyboard/xkb_rules.cpp new file mode 100644 index 00000000..616e7b84 --- /dev/null +++ b/kcontrol/keyboard/xkb_rules.cpp @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 "xkb_rules.h" + +#include +#include +#include + +#include +#include +#include // for Qt::escape +#include +#include + +//#include +//#include + +#include "x11_helper.h" + +// for findXkbRuleFile +#include +#include +#include +#include +#include +#include +#include + + +class RulesHandler : public QXmlDefaultHandler +{ +public: + RulesHandler(Rules* rules_, bool fromExtras_): + rules(rules_), + fromExtras(fromExtras_){} + + bool startElement(const QString &namespaceURI, const QString &localName, + const QString &qName, const QXmlAttributes &attributes); + bool endElement(const QString &namespaceURI, const QString &localName, + const QString &qName); + bool characters(const QString &str); +// bool fatalError(const QXmlParseException &exception); +// QString errorString() const; + +private: +// QString getString(const QString& text); + + QStringList path; + Rules* rules; + const bool fromExtras; +}; + +static QString translate_xml_item(const QString& itemText) +{ + return i18n(Qt::escape(itemText).toUtf8()); + // return QString::fromUtf8(dgettext("xkeyboard-config", itemText.toAscii())); +} + +static QString translate_description(ConfigItem* item) +{ + return item->description.isEmpty() + ? item->name : translate_xml_item(item->description); +} + +static bool notEmpty(const ConfigItem* item) +{ + return ! item->name.isEmpty(); +} + +template +void removeEmptyItems(QList& list) +{ + QtConcurrent::blockingFilter(list, notEmpty); +} + +static +void postProcess(Rules* rules) +{ + //TODO remove elements with empty names to safeguard us + removeEmptyItems(rules->layoutInfos); + removeEmptyItems(rules->modelInfos); + removeEmptyItems(rules->optionGroupInfos); + + KGlobal::locale()->insertCatalog("xkeyboard-config"); +// setlocale(LC_ALL, ""); +// bindtextdomain("xkeyboard-config", LOCALE_DIR); + foreach(ModelInfo* modelInfo, rules->modelInfos) { + modelInfo->vendor = translate_xml_item(modelInfo->vendor); + modelInfo->description = translate_description(modelInfo); + } + + foreach(LayoutInfo* layoutInfo, rules->layoutInfos) { + layoutInfo->description = translate_description(layoutInfo); + + removeEmptyItems(layoutInfo->variantInfos); + foreach(VariantInfo* variantInfo, layoutInfo->variantInfos) { + variantInfo->description = translate_description(variantInfo); + } + } + foreach(OptionGroupInfo* optionGroupInfo, rules->optionGroupInfos) { + optionGroupInfo->description = translate_description(optionGroupInfo); + + removeEmptyItems(optionGroupInfo->optionInfos); + foreach(OptionInfo* optionInfo, optionGroupInfo->optionInfos) { + optionInfo->description = translate_description(optionInfo); + } + } + KGlobal::locale()->removeCatalog("xkeyboard-config"); +} + + +Rules::Rules(): + version("1.0") +{ +} + +QString Rules::getRulesName() +{ + XkbRF_VarDefsRec vd; + char *tmp = NULL; + + if (XkbRF_GetNamesProp(QX11Info::display(), &tmp, &vd) && tmp != NULL ) { + // qDebug() << "namesprop" << tmp ; + const QString name(tmp); + XFree(tmp); + return name; + } + + return QString::null; +} + +static QString findXkbRulesFile() +{ + QString rulesFile; + QString rulesName = Rules::getRulesName(); + + if ( ! rulesName.isNull() ) { + QString xkbParentDir; + + QString base(XLIBDIR); + if( base.count('/') >= 3 ) { + // .../usr/lib/X11 -> /usr/share/X11/xkb vs .../usr/X11/lib -> /usr/X11/share/X11/xkb + QString delta = base.endsWith("X11") ? "/../../share/X11" : "/../share/X11"; + QDir baseDir(base + delta); + if( baseDir.exists() ) { + xkbParentDir = baseDir.absolutePath(); + } + else { + QDir baseDir(base + "/X11"); // .../usr/X11/lib/X11/xkb (old XFree) + if( baseDir.exists() ) { + xkbParentDir = baseDir.absolutePath(); + } + } + } + + if( xkbParentDir.isEmpty() ) { + xkbParentDir = "/usr/share/X11"; + } + + rulesFile = QString("%1/xkb/rules/%2.xml").arg(xkbParentDir, rulesName); + } + + return rulesFile; +} + +static +void mergeRules(Rules* rules, Rules* extraRules) +{ + rules->modelInfos.append( extraRules->modelInfos ); + rules->optionGroupInfos.append( extraRules->optionGroupInfos ); // need to iterate and merge? + + QList layoutsToAdd; + foreach(LayoutInfo* extraLayoutInfo, extraRules->layoutInfos) { + LayoutInfo* layoutInfo = findByName(rules->layoutInfos, extraLayoutInfo->name); + if( layoutInfo != NULL ) { + layoutInfo->variantInfos.append( extraLayoutInfo->variantInfos ); + layoutInfo->languages.append( extraLayoutInfo->languages ); + } + else { + layoutsToAdd.append(extraLayoutInfo); + } + } + rules->layoutInfos.append(layoutsToAdd); + kDebug() << "Merged from extra rules:" << extraRules->layoutInfos.size() << "layouts," << extraRules->modelInfos.size() << "models," << extraRules->optionGroupInfos.size() << "option groups"; + + // base rules now own the objects - remove them from extra rules so that it does not try to delete them + extraRules->layoutInfos.clear(); + extraRules->modelInfos.clear(); + extraRules->optionGroupInfos.clear(); +} + + +const char Rules::XKB_OPTION_GROUP_SEPARATOR = ':'; + +Rules* Rules::readRules(ExtrasFlag extrasFlag) +{ + Rules* rules = new Rules(); + QString rulesFile = findXkbRulesFile(); + if( ! readRules(rules, rulesFile, false) ) { + delete rules; + return NULL; + } + if( extrasFlag == Rules::READ_EXTRAS ) { + QRegExp regex("\\.xml$"); + Rules* rulesExtra = new Rules(); + QString extraRulesFile = rulesFile.replace(regex, ".extras.xml"); + if( readRules(rulesExtra, extraRulesFile, true) ) { // not fatal if it fails + mergeRules(rules, rulesExtra); + } + delete rulesExtra; + } + return rules; +} + + +Rules* Rules::readRules(Rules* rules, const QString& filename, bool fromExtras) +{ + QFile file(filename); + if( !file.open(QFile::ReadOnly | QFile::Text) ) { + kError() << "Cannot open the rules file" << file.fileName(); + return NULL; + } + + RulesHandler rulesHandler(rules, fromExtras); + + QXmlSimpleReader reader; + reader.setContentHandler(&rulesHandler); + reader.setErrorHandler(&rulesHandler); + + QXmlInputSource xmlInputSource(&file); + + kDebug() << "Parsing xkb rules from" << file.fileName(); + + if( ! reader.parse(xmlInputSource) ) { + kError() << "Failed to parse the rules file" << file.fileName(); + delete rules; + return NULL; + } + + postProcess(rules); + + return rules; +} + +bool RulesHandler::startElement(const QString &/*namespaceURI*/, const QString &/*localName*/, + const QString &qName, const QXmlAttributes &attributes) +{ + path << QString(qName); + + QString strPath = path.join("/"); + if( strPath.endsWith("layoutList/layout/configItem") ) { + rules->layoutInfos << new LayoutInfo(fromExtras); + } + else if( strPath.endsWith("layoutList/layout/variantList/variant") ) { + rules->layoutInfos.last()->variantInfos << new VariantInfo(fromExtras); + } + else if( strPath.endsWith("modelList/model") ) { + rules->modelInfos << new ModelInfo(); + } + else if( strPath.endsWith("optionList/group") ) { + rules->optionGroupInfos << new OptionGroupInfo(); + rules->optionGroupInfos.last()->exclusive = (attributes.value("allowMultipleSelection") != "true"); + } + else if( strPath.endsWith("optionList/group/option") ) { + rules->optionGroupInfos.last()->optionInfos << new OptionInfo(); + } + else if( strPath == ("xkbConfigRegistry") && ! attributes.value("version").isEmpty() ) { + rules->version = attributes.value("version"); + kDebug() << "xkbConfigRegistry version" << rules->version; + } + return true; +} + +bool RulesHandler::endElement(const QString &/*namespaceURI*/, const QString &/*localName*/, const QString &/*qName*/) +{ + path.removeLast(); + return true; +} + +bool RulesHandler::characters(const QString &str) +{ + if( !str.trimmed().isEmpty() ) { + QString strPath = path.join("/"); + if( strPath.endsWith("layoutList/layout/configItem/name") ) { + if( rules->layoutInfos.last() != NULL ) { + rules->layoutInfos.last()->name = str.trimmed(); +// qDebug() << "name:" << str; + } + // skipping invalid entry + } + else if( strPath.endsWith("layoutList/layout/configItem/description") ) { + rules->layoutInfos.last()->description = str.trimmed(); +// qDebug() << "descr:" << str; + } + else if( strPath.endsWith("layoutList/layout/configItem/languageList/iso639Id") ) { + rules->layoutInfos.last()->languages << str.trimmed(); +// qDebug() << "\tlang:" << str; + } + else if( strPath.endsWith("layoutList/layout/variantList/variant/configItem/name") ) { + rules->layoutInfos.last()->variantInfos.last()->name = str.trimmed(); +// qDebug() << "\tvariant name:" << str; + } + else if( strPath.endsWith("layoutList/layout/variantList/variant/configItem/description") ) { + rules->layoutInfos.last()->variantInfos.last()->description = str.trimmed(); +// qDebug() << "\tvariant descr:" << str; + } + else if( strPath.endsWith("layoutList/layout/variantList/variant/configItem/languageList/iso639Id") ) { + rules->layoutInfos.last()->variantInfos.last()->languages << str.trimmed(); +// qDebug() << "\tvlang:" << str; + } + else if( strPath.endsWith("modelList/model/configItem/name") ) { + rules->modelInfos.last()->name = str.trimmed(); +// qDebug() << "name:" << str; + } + else if( strPath.endsWith("modelList/model/configItem/description") ) { + rules->modelInfos.last()->description = str.trimmed(); +// qDebug() << "\tdescr:" << str; + } + else if( strPath.endsWith("modelList/model/configItem/vendor") ) { + rules->modelInfos.last()->vendor = str.trimmed(); +// qDebug() << "\tvendor:" << str; + } + else if( strPath.endsWith("optionList/group/configItem/name") ) { + rules->optionGroupInfos.last()->name = str.trimmed(); +// qDebug() << "name:" << str; + } + else if( strPath.endsWith("optionList/group/configItem/description") ) { + rules->optionGroupInfos.last()->description = str.trimmed(); +// qDebug() << "\tdescr:" << str; + } + else if( strPath.endsWith("optionList/group/option/configItem/name") ) { + rules->optionGroupInfos.last()->optionInfos.last()->name = str.trimmed(); +// qDebug() << "name:" << str; + } + else if( strPath.endsWith("optionList/group/option/configItem/description") ) { + rules->optionGroupInfos.last()->optionInfos.last()->description = str.trimmed(); +// qDebug() << "\tdescr:" << str; + } + } + return true; +} + +bool LayoutInfo::isLanguageSupportedByLayout(const QString& lang) const +{ + if( languages.contains(lang) || isLanguageSupportedByVariants(lang) ) + return true; + +// // return yes if no languages found in layout or its variants +// if( languages.empty() ) { +// foreach(const VariantInfo* info, variantInfos) { +// if( ! info->languages.empty() ) +// return false; +// } +// return true; +// } + + return false; +} + +bool LayoutInfo::isLanguageSupportedByVariants(const QString& lang) const +{ + foreach(const VariantInfo* info, variantInfos) { + if( info->languages.contains(lang) ) + return true; + } + return false; +} + +bool LayoutInfo::isLanguageSupportedByDefaultVariant(const QString& lang) const +{ + if( languages.contains(lang) ) + return true; + + if( languages.empty() && isLanguageSupportedByVariants(lang) ) + return true; + + return false; +} + +bool LayoutInfo::isLanguageSupportedByVariant(const VariantInfo* variantInfo, const QString& lang) const +{ + if( variantInfo->languages.contains(lang) ) + return true; + + // if variant has no languages try to "inherit" them from layout + if( variantInfo->languages.empty() && languages.contains(lang) ) + return true; + + return false; +} diff --git a/kcontrol/keyboard/xkb_rules.h b/kcontrol/keyboard/xkb_rules.h new file mode 100644 index 00000000..2be85624 --- /dev/null +++ b/kcontrol/keyboard/xkb_rules.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) + * + * 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 XKB_RULES_H_ +#define XKB_RULES_H_ + +#include +#include +#include + + +struct ConfigItem { + QString name; + QString description; +}; + +template +inline T* findByName(QList list, QString name) { + foreach(T* info, list) { + if( info->name == name ) + return info; + } + return NULL; +} + +struct VariantInfo: public ConfigItem { + QList languages; + const bool fromExtras; + + VariantInfo(bool fromExtras_): + fromExtras(fromExtras_) {} +}; + +struct LayoutInfo: public ConfigItem { + QList variantInfos; + QList languages; + const bool fromExtras; + +// LayoutInfo() {} + LayoutInfo(bool fromExtras_): + fromExtras(fromExtras_) {} + ~LayoutInfo() { foreach(VariantInfo* variantInfo, variantInfos) delete variantInfo; } + + VariantInfo* getVariantInfo(const QString& variantName) const { + return findByName(variantInfos, variantName); + } + + bool isLanguageSupportedByLayout(const QString& lang) const; + bool isLanguageSupportedByDefaultVariant(const QString& lang) const; + bool isLanguageSupportedByVariants(const QString& lang) const; + bool isLanguageSupportedByVariant(const VariantInfo* variantInfo, const QString& lang) const; +}; + +struct ModelInfo: public ConfigItem { + QString vendor; +}; + +struct OptionInfo: public ConfigItem { +}; + +struct OptionGroupInfo: public ConfigItem { + QList optionInfos; + bool exclusive; + + ~OptionGroupInfo() { foreach(OptionInfo* opt, optionInfos) delete opt; } + + const OptionInfo* getOptionInfo(const QString& optionName) const { + return findByName(optionInfos, optionName); + } +}; + +struct Rules { + enum ExtrasFlag { NO_EXTRAS, READ_EXTRAS }; + + static const char XKB_OPTION_GROUP_SEPARATOR; + + QList layoutInfos; + QList modelInfos; + QList optionGroupInfos; + QString version; + + Rules(); + + ~Rules() { + foreach(LayoutInfo* layoutInfo, layoutInfos) delete layoutInfo; + foreach(ModelInfo* modelInfo, modelInfos) delete modelInfo; + foreach(OptionGroupInfo* optionGroupInfo, optionGroupInfos) delete optionGroupInfo; + } + + const LayoutInfo* getLayoutInfo(const QString& layoutName) const { + return findByName(layoutInfos, layoutName); + } + + const OptionGroupInfo* getOptionGroupInfo(const QString& optionGroupName) const { + return findByName(optionGroupInfos, optionGroupName); + } + + static Rules* readRules(ExtrasFlag extrasFlag); + static Rules* readRules(Rules* rules, const QString& filename, bool fromExtras); + static QString getRulesName(); +}; + +#endif /* XKB_RULES_H_ */ diff --git a/kcontrol/keys/CMakeLists.txt b/kcontrol/keys/CMakeLists.txt new file mode 100644 index 00000000..f0eb42c4 --- /dev/null +++ b/kcontrol/keys/CMakeLists.txt @@ -0,0 +1,46 @@ +kde4_no_enable_final(keys) + +########### next target ############### + +set(kcm_keys_PART_SRCS + kglobalshortcutseditor.cpp + globalshortcuts.cpp + select_scheme_dialog.cpp + kglobalaccel_interface.cpp + kglobalaccel_component_interface.cpp + export_scheme_dialog.cpp + ) + +kde4_add_ui_files( kcm_keys_PART_SRCS + export_scheme_dialog.ui + kglobalshortcutseditor.ui + select_scheme_dialog.ui ) + +set(kglobalaccel_xml ${KDE4_DBUS_INTERFACES_DIR}/org.kde.KGlobalAccel.xml) +set_source_files_properties(${kglobalaccel_xml} PROPERTIES INCLUDE "kglobalshortcutinfo_p.h") +qt4_add_dbus_interface(kdeui_LIB_SRCS ${kglobalaccel_xml} kglobalaccel_interface ) + +set(kglobalaccel_component_xml ${KDE4_DBUS_INTERFACES_DIR}/org.kde.kglobalaccel.Component.xml) +set_source_files_properties(${kglobalaccel_component_xml} PROPERTIES INCLUDE "kglobalshortcutinfo_p.h") +qt4_add_dbus_interface(kdeui_LIB_SRCS ${kglobalaccel_component_xml} kglobalaccel_component_interface ) + +kde4_add_plugin(kcm_keys ${kcm_keys_PART_SRCS}) +target_link_libraries(kcm_keys ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${X11_X11_LIB}) + +install(TARGETS kcm_keys DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install( FILES keys.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES + schemes/kde3.kksrc + schemes/kde4.kksrc + schemes/mac4.kksrc + schemes/unix3.kksrc + schemes/win3.kksrc + schemes/win4.kksrc + schemes/wm3.kksrc + DESTINATION ${DATA_INSTALL_DIR}/kcmkeys ) + + diff --git a/kcontrol/keys/ChangeLog b/kcontrol/keys/ChangeLog new file mode 100644 index 00000000..67c21160 --- /dev/null +++ b/kcontrol/keys/ChangeLog @@ -0,0 +1,29 @@ +2005-09-30 Benjamin Meyer + * Removed Command Shortcuts, it is already in kmenuedit + +1999-08-19 Duncan Haldane + * removed left-over commented out code from change + decribed below, and adjusted help doc names to + index-1.html + +1999-02-28 Duncan Haldane + * commented out those unnecessary debug calls. + in keyconfig.cpp + +1998-12-19 Duncan Haldane + * Converted global.cpp, global.h to keyconfig.cpp, + keyconfig.h, that can now be used to configure both + the standard keys and the global keys + in the same sophisticated manner as + global.cpp did for just the global keys. + * converted main.cpp to use keyconfig.cpp rather than + global.cpp and standard.cpp for standard and globall + key configuration. KGlobalConfig and KStdConfig disappear. + (KGlobalConfig is renamed to KKeyConfig) + * appropriate changes to Makefile.am. + * standard key binding are now #include'd from + stdbindings.cpp + * standard.cpp, standard.h are left here for now. + The entries that used to use them in main.cpp and + Makefile.am are just commented out for now. + diff --git a/kcontrol/keys/Messages.sh b/kcontrol/keys/Messages.sh new file mode 100644 index 00000000..78a9c48f --- /dev/null +++ b/kcontrol/keys/Messages.sh @@ -0,0 +1,7 @@ +#! /usr/bin/env bash +# customkeys=`grep "^.include .\.\." keyconfig.cpp | sed -e "s#.*\"\(.*\)\"#\1#"` +# $XGETTEXT *.cpp $customkeys -o $podir/kcmkeys.pot +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/kcmkeys.pot +rm -f rc.cpp + diff --git a/kcontrol/keys/README b/kcontrol/keys/README new file mode 100644 index 00000000..14e09f73 --- /dev/null +++ b/kcontrol/keys/README @@ -0,0 +1,7 @@ +CHANGES V0.2 +- Global keys stored by default in ~/.kde/share/config/kdeglobals + [Global Keys] group +- KKeyDialog checks new key choices against exising bindings for the widget +and against entries in .kderc [Global Keys] +- kcmkeys now has two standard kcontrol pages - one for standard desktop +accelerators and one for global keybindings. diff --git a/kcontrol/keys/export_scheme_dialog.cpp b/kcontrol/keys/export_scheme_dialog.cpp new file mode 100644 index 00000000..49ca7f3d --- /dev/null +++ b/kcontrol/keys/export_scheme_dialog.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2009 Michael Jansen + * + * 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 "export_scheme_dialog.h" + +#include + +#include + + +ExportSchemeDialog::ExportSchemeDialog(QStringList components, QWidget *parent) + : KDialog(parent), + ui(), + mComponents(components) + { + QWidget *w = new QWidget(this); + ui.setupUi(w); + setMainWidget(w); + + // We allow to check more than one button + mButtons.setExclusive(false); + + // A grid layout for the buttons + QGridLayout *vb = new QGridLayout(this); + + int item=0; + Q_FOREACH(QString component, mComponents) + { + QCheckBox *cb = new QCheckBox(component); + vb->addWidget(cb, item / 2, item % 2); + mButtons.addButton(cb, item); + ++item; + } + + ui.components->setLayout(vb); + } + + +ExportSchemeDialog::~ExportSchemeDialog() + {} + + +QStringList ExportSchemeDialog::selectedComponents() const + { + QStringList rc; + Q_FOREACH(QAbstractButton const *button, mButtons.buttons()) + { + if (button->isChecked()) + { + // Remove the '&' added by KAcceleratorManager magically + rc.append(KGlobal::locale()->removeAcceleratorMarker(button->text())); + } + } + return rc; + } + + +#include "moc_export_scheme_dialog.cpp" diff --git a/kcontrol/keys/export_scheme_dialog.h b/kcontrol/keys/export_scheme_dialog.h new file mode 100644 index 00000000..ab27fa19 --- /dev/null +++ b/kcontrol/keys/export_scheme_dialog.h @@ -0,0 +1,58 @@ +#ifndef EXPORT_SCHEME_DIALOG_H +#define EXPORT_SCHEME_DIALOG_H +/** + * Copyright (C) 2009 Michael Jansen + * + * 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 "ui_export_scheme_dialog.h" + +#include + +/** + * @author Michael Jansen + */ +class ExportSchemeDialog : public KDialog + { + Q_OBJECT + +public: + + ExportSchemeDialog (QStringList components, QWidget *parent=NULL); + + virtual ~ExportSchemeDialog(); + + // Get the list of currently selected components + QStringList selectedComponents() const; + +private: + + Ui::ExportSchemeDialog ui; + + // list of components to choose from + QStringList mComponents; + + // list of buttons for the components + QButtonGroup mButtons; + + }; // ExportSchemeDialog + + + + +#endif /* EXPORT_SCHEME_DIALOG_H */ + diff --git a/kcontrol/keys/export_scheme_dialog.ui b/kcontrol/keys/export_scheme_dialog.ui new file mode 100644 index 00000000..4e8651ee --- /dev/null +++ b/kcontrol/keys/export_scheme_dialog.ui @@ -0,0 +1,35 @@ + + + ExportSchemeDialog + + + + 0 + 0 + 400 + 300 + + + + + + + Select the Components to Export + + + Qt::AlignCenter + + + + + + + Components + + + + + + + + diff --git a/kcontrol/keys/globalshortcuts.cpp b/kcontrol/keys/globalshortcuts.cpp new file mode 100644 index 00000000..88220593 --- /dev/null +++ b/kcontrol/keys/globalshortcuts.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2007 Andreas Pakulat + * Copyright 2008 Michael Jansen + * + * 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 "globalshortcuts.h" + +#include "kglobalshortcutseditor.h" + +#include +#include +#include + + +#include + + +K_PLUGIN_FACTORY(GlobalShortcutsModuleFactory, registerPlugin();) +K_EXPORT_PLUGIN(GlobalShortcutsModuleFactory("kcmkeys")) + + +GlobalShortcutsModule::GlobalShortcutsModule(QWidget *parent, const QVariantList &args) + : KCModule(GlobalShortcutsModuleFactory::componentData(), parent, args), + editor(0) +{ + KCModule::setButtons(KCModule::Buttons(KCModule::Default | KCModule::Apply | KCModule::Help)); + + + // Create the kglobaleditor + editor = new KGlobalShortcutsEditor(this, KShortcutsEditor::GlobalAction); + connect(editor, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); + + // Layout the hole bunch + QVBoxLayout *global = new QVBoxLayout; + global->addWidget(editor); + setLayout(global); +} + +GlobalShortcutsModule::~GlobalShortcutsModule() +{} + + +void GlobalShortcutsModule::load() +{ + editor->load(); +} + + +void GlobalShortcutsModule::defaults() +{ + switch (KMessageBox::questionYesNoCancel( + this, + i18n("You are about to reset all shortcuts to their default values."), + i18n("Reset to defaults"), + KGuiItem(i18n("Current Component")), + KGuiItem(i18n("All Components")))) + { + case KMessageBox::Yes: + editor->defaults(KGlobalShortcutsEditor::CurrentComponent); + break; + + case KMessageBox::No: + editor->defaults(KGlobalShortcutsEditor::AllComponents); + break; + + default: + return; + } +} + + +void GlobalShortcutsModule::save() +{ + editor->save(); +} + + +#include "globalshortcuts.moc" diff --git a/kcontrol/keys/globalshortcuts.h b/kcontrol/keys/globalshortcuts.h new file mode 100644 index 00000000..428c0335 --- /dev/null +++ b/kcontrol/keys/globalshortcuts.h @@ -0,0 +1,44 @@ +/* + * Copyright 2007 Andreas Pakulat + * Copyright 2008 Michael Jansen + * + * 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 SHORTCUTS_MODULE_H +#define SHORTCUTS_MODULE_H + +#include +#include + +class KGlobalShortcutsEditor; + +class GlobalShortcutsModule : public KCModule +{ + Q_OBJECT +public: + GlobalShortcutsModule(QWidget *parent, const QVariantList &args); + ~GlobalShortcutsModule(); + + virtual void save(); + virtual void load(); + virtual void defaults(); + +private: + KGlobalShortcutsEditor *editor; +}; + + +#endif diff --git a/kcontrol/keys/keys.desktop b/kcontrol/keys/keys.desktop new file mode 100644 index 00000000..0db464f6 --- /dev/null +++ b/kcontrol/keys/keys.desktop @@ -0,0 +1,227 @@ +[Desktop Entry] +Exec=kcmshell4 keys +Icon=preferences-desktop-keyboard-shortcut +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/keys/index.html + +X-KDE-Library=kcm_keys +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=shortcuts-and-gestures +X-KDE-Weight=160 + +Name=Global Keyboard Shortcuts +Name[ar]=اختصارات لوحة المفاتيح العمومية +Name[ast]=Accesos rápidos de tecláu globales +Name[be@latin]=Paŭsiudnyja klavijaturnyja skaroty +Name[bg]=Общи бързи клавиши +Name[bn]=গ্লোবাল কীবোর্ড শর্টকাট +Name[bn_IN]=কি-বোর্ডের সার্বজনীন শর্ট-কাট +Name[bs]=Globalne prečice sa tastature +Name[ca]=Dreceres de teclat globals +Name[ca@valencia]=Dreceres de teclat globals +Name[cs]=Globální klávesové zkratky +Name[csb]=Globalné klawiszowé skrodzënë +Name[da]=Globale tastaturgenveje +Name[de]=Globale Kurzbefehle +Name[el]=Καθολικές συντομεύσεις πληκτρολογίου +Name[en_GB]=Global Keyboard Shortcuts +Name[eo]=Ĝeneralaj Klavkombinoj +Name[es]=Accesos rápidos de teclado globales +Name[et]=Globaalsed kiirklahvid +Name[eu]=Laster-tekla orokorrak +Name[fa]=میان‌برهای صفحه‌ کلید سراسری +Name[fi]=Työpöydänlaajuiset pikanäppäimet +Name[fr]=Raccourcis globaux de clavier +Name[fy]=Globale fluchkeppelings +Name[ga]=Aicearraí Comhchoiteanna Méarchláir +Name[gl]=Atallos de teclado globais +Name[gu]=વૈશ્વીક કીબોર્ડ ટૂંકાણો +Name[he]=קיצורי מקשים גלובליים +Name[hi]=वैश्विक कुंजीपट शॉर्टकट +Name[hne]=वैस्विक कुंजीपट सार्टकट +Name[hr]=Globalni prečaci tipkovnice +Name[hsb]=Globalne tastaturowe skrótšenki +Name[hu]=Globális billentyűparancsok +Name[ia]=Vias breve global de claviero +Name[id]=Jalan Pintas Papan Ketik Global +Name[is]=Víðværir flýtilyklar +Name[it]=Scorciatoie globali della tastiera +Name[ja]=グローバルキーボードショートカット +Name[kk]=Жалпы жүйелік перне тіркесімдер +Name[km]=ផ្លូវកាត់​ក្ដារចុច​​សកល +Name[kn]=ಸಾರ್ವತ್ರಿಕ ಕೀಲಿಮಣೆ ಶೀಘ್ರಮಾರ್ಗಗಳು (ಶಾರ್ಟ್ ಕಟ್) +Name[ko]=전역 키보드 단축키 +Name[ku]=Kurteriyên Klavyeyê yên Giştî +Name[lt]=Globalieji spartieji klavišai +Name[lv]=Globālie tastatūras īsceļi +Name[mai]=वैश्विक कुंजीपटल शार्टकट +Name[mk]=Глобални кратенки на тастатурата +Name[ml]=ആഗോളമായ കീബോര്‍ഡിലെ കുറക്കുവഴികള്‍ +Name[mr]=जागतिक कळफलक शॉर्टकट +Name[nb]=Globale hurtigtaster +Name[nds]=Globaal Tastkombinatschonen +Name[nl]=Globale sneltoetsen +Name[nn]=Globale snøgg­tastar +Name[or]=ଜାଗତିକ କିବୋର୍ଡ଼ ସଂକ୍ଷିପ୍ତ ପଥ +Name[pa]=ਗਲੋਬਲ ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ +Name[pl]=Globalne skróty klawiszowe +Name[pt]=Atalhos Globais do Teclado +Name[pt_BR]=Atalhos de teclado globais +Name[ro]=Acceleratori de tastatură globali +Name[ru]=Глобальные комбинации клавиш +Name[si]=ගෝලීය යතුරුපුවරු කෙටිමං +Name[sk]=Globálne klávesové skratky +Name[sl]=Splošne tipkovne bližnjice +Name[sr]=Глобалне пречице са тастатуре +Name[sr@ijekavian]=Глобалне пречице са тастатуре +Name[sr@ijekavianlatin]=Globalne prečice sa tastature +Name[sr@latin]=Globalne prečice sa tastature +Name[sv]=Globala snabbtangenter +Name[ta]=பொது விசைப்பலகை குறுக்குவழிகள் +Name[te]=గ్లౌబల్ కీబోర్‍డ్ లఘువులు +Name[tg]=Глобальные комбинации клавиш +Name[th]=ปุ่มพิมพ์ลัดใช้งานส่วนรวม +Name[tr]=Genel Klavye Kısayolları +Name[ug]=ئومۇمىيەت ھەرپتاختا تېزلەتمىسى +Name[uk]=Загальні клавіатурні скорочення +Name[vi]=Phím tắt toàn hệ thống +Name[wa]=Rascourtis del taprece po ttavå +Name[x-test]=xxGlobal Keyboard Shortcutsxx +Name[zh_CN]=全局键盘快捷键 +Name[zh_TW]=全域鍵盤捷徑 + +Comment=Configuration of keybindings +Comment[af]=Opstelling van sleutel bindinge +Comment[ar]=إعداد ارتباطات المفاتيح +Comment[ast]=Configuración de les asociaciones de les tecles +Comment[be]=Настаўленні клавішных скаротаў +Comment[be@latin]=Nałady dla poviaziaŭ klavišaŭ z roznymi aperacyjami +Comment[bg]=Настройки на бързи клавиши +Comment[bn]=কী-বাইন্ডিং কনফিগারেশন +Comment[bn_IN]=কি-বাইন্ডিং কনফিগারেশন +Comment[br]=Kefluniañ ereoù stokell +Comment[bs]=Postava prečica sa tastature +Comment[ca]=Configuració dels lligams de tecles +Comment[ca@valencia]=Configuració dels lligams de tecles +Comment[cs]=Nastavení klávesových zkratek +Comment[csb]=Nastôw klawiszowëch skrodzënów +Comment[cy]=Furfweddiad o rwymiadau bysell +Comment[da]=Indstilling af tastebindinger +Comment[de]=Einrichtung von Tastenzuordnungen +Comment[el]=Διαμόρφωση συνδυασμών πλήκτρων +Comment[en_GB]=Configuration of keybindings +Comment[eo]=Agordo de klavkombinoj +Comment[es]=Configuración de las asociaciones de las teclas +Comment[et]=Kiirklahvide seadistamine +Comment[eu]=Laster-teklen konfigurazioa +Comment[fa]=پیکربندی مقیدسازیهای کلید +Comment[fi]=Näppäinsidosten asetukset +Comment[fy]=Ynstellings foar fluchtoetsen +Comment[ga]=Cumraíocht ceangal eochracha +Comment[gl]=Configuración dos atallos de teclado +Comment[gu]=કીજોડાણોનું રૂપરેખાંકન +Comment[he]=הגדרות מיפוי מקשים +Comment[hi]=की-बाइंडिंग का कॉन्फ़िगरेशन +Comment[hne]=की-बाइंडिंग के कान्फिगरेसन +Comment[hr]=Konfiguriranje prečaca tipkovnice +Comment[hsb]=Připrawjenje přirjadowanjow tastow +Comment[hu]=A billentyűparancsok beállításai +Comment[ia]=Configuration de keybindings (ligamines de claves) +Comment[id]=Konfigurasi pengikat tombol +Comment[is]=Stillingar altækra flýtihnappa +Comment[ka]=კლავიშთა წყვილების კონფიგურაცია +Comment[kk]=Перне тіркесімдерді баптау +Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ការ​ចង​គ្រាប់ចុច +Comment[kn]=ಕೀಲಿ ನಿಬಂಧಗಳ (ಬೈಂಡಿಂಗ್ಸ್) ಸಂರಚನೆ +Comment[ko]=키 바인딩 설정 +Comment[ku]=Veavakirina bicîkirina bişkojkan +Comment[lt]=Klavišų siečių derinimas +Comment[lv]=Taustiņsasaistes konfigurēšana +Comment[mai]=की-बाइंडिंग क' कान्फिगरेशन +Comment[mk]=Конфигурација на врски меѓу копчиња и акции +Comment[ml]=കീബൈന്‍ഡിങ്സിനുള്ള ക്രമീകരണം +Comment[mr]=कीबाइंडिंगची संयोजना +Comment[ms]=Konfigurasi untuk pengikatan kekunci +Comment[nb]=Oppsett av hurtigtaster +Comment[nds]=Instellen vun Tastkombinatschonen +Comment[ne]=कुञ्जी बाइन्डिङहरूको कन्फिगरेसन +Comment[nl]=Instellingen voor sneltoetsen +Comment[nn]=Oppsett av snøggtastar +Comment[or]=କିବନ୍ଧନଗୁଡ଼ିକର ସଂରଚନା +Comment[pa]=ਕੀ-ਬਾਇਡਿੰਗ ਦੀ ਸੰਰਚਨਾ +Comment[pl]=Ustawienia powiązań klawiszowych +Comment[pt]=Configuração das teclas +Comment[pt_BR]=Configuração dos atalhos de teclado +Comment[ro]=Configurează asocierile de taste +Comment[ru]=Настройка глобальных комбинаций клавиш +Comment[se]=Jođánisboaluid heiveheapmi +Comment[si]=යතුරු බැඳුම් වල සැකසුම +Comment[sk]=Nastavenie globálnych klávesových skratiek +Comment[sl]=Nastavitve tipkovnih bližnjic +Comment[sr]=Поставке пречица са тастатуре +Comment[sr@ijekavian]=Поставке пречица са тастатуре +Comment[sr@ijekavianlatin]=Postavke prečica sa tastature +Comment[sr@latin]=Postavke prečica sa tastature +Comment[sv]=Anpassa kortkommandon +Comment[ta]=விசைசேர்வுகளுக்கான வடிவமைப்பு +Comment[te]=కీ భందనముల యొక్క ఆకృతీకరణ +Comment[tg]=Танзимоти тугмаҳои якҷояшуда +Comment[th]=ปรับแต่งปุ่มพิมพ์ลัดต่าง ๆ +Comment[tr]=Tuş bağıntılarının yapılandırılması +Comment[ug]=كۇنۇپكا باغلاش سەپلىمە +Comment[uk]=Налаштування прив'язок клавіш +Comment[uz]=Tugmalar birikmasini moslash +Comment[uz@cyrillic]=Тугмалар бирикмасини мослаш +Comment[vi]=Cấu hình các tổ hợp phím +Comment[wa]=Apontiaedje des rascourtis di tapes +Comment[xh]=Uqwalaselo lwezibopheleo zesitshixo +Comment[x-test]=xxConfiguration of keybindingsxx +Comment[zh_CN]=键绑定配置 +Comment[zh_TW]=按鍵關聯設定 + +X-KDE-Keywords=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts +X-KDE-Keywords[bs]=Tipke, Globalni vezovi tipki, Šema tipki, Veze tipki, Prečice, Prečice za aplikacije, globalne Prečice +X-KDE-Keywords[ca]=Tecles,Assignació de tecles globals,Esquema de tecles,Assignació de tecles,dreceres,dreceres d'aplicació,dreceres globals +X-KDE-Keywords[ca@valencia]=Tecles,Assignació de tecles globals,Esquema de tecles,Assignació de tecles,dreceres,dreceres d'aplicació,dreceres globals +X-KDE-Keywords[da]=Taster,globale tastebindinger,tasteskema,tastebindinger,genveje,programgenveje,globale genveje +X-KDE-Keywords[de]=Tasten,Tastenzuordnung,Tastenkürzel,Kurzbefehle,Tastenschema,Tastaturlayout +X-KDE-Keywords[el]=Πλήκτρα,δεσμεύσεις καθολικών πλήκτρων, σχήμα πλήκτρων, δεσμεύσεις πλήκτρων,συντομεύσεις,συντομεύσεις εφαρμογών,καθολικές συντομεύσεις +X-KDE-Keywords[en_GB]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts +X-KDE-Keywords[es]=Teclas,Asociaciones globales de teclas,Esquema de teclas,Asociaciones de teclas,accesos rápidos,accesos rápidos de aplicaciones,accesos rápidos globales +X-KDE-Keywords[et]=klahvid,globaalsed kiirklahvid,klaviatuuriskeem,klahviseosed,kiirklahvid,rakenduse kiirklahvid,globaalsed kiirklahvid +X-KDE-Keywords[eu]=tekla,laster-tekla orokor,tekla-eskema,laster-tekla,lasterbide,aplikazioen laster-teklak +X-KDE-Keywords[fi]=näppäimet,globaalit näppäinsidokset,yleiset näppäinsidokset,työpöydänlaajuiset näppäinsidokset,globaalit pikanäppäimet,työpöydänlaajuiset pikanäppäimet,globaalit näppäinyhdistelmät,työpöydänlaajuiset näppäinyhdistelmät,näppäimistön yleispikavalinnat,näppäimistön globaalit pikavalinnat,näppäinsidokset,pikanäppäimet,näppäimistön pikavalinnat, näppäinyhdistelmät,näppäinoikotiet,sovellusten pikanäppäimet,sovellusten näppäinyhdistelmät,sovellusten näppäinoikotiet +X-KDE-Keywords[fr]=Touches, Association globale des touches, Schéma des touches, Association de touches, Raccourci des applications, Raccourcis globaux +X-KDE-Keywords[ga]=Eochracha,Ceangail chomhchoiteanna eochracha,Scéim eochracha,Ceangail eochracha,aicearraí,aicearraí feidhmchláir,aicearraí comhchoiteanna +X-KDE-Keywords[gl]=tecla, atallo, asociación, esquema de teclas, atallo de teclado, asociación de teclas, atallo a programa, atallos globais +X-KDE-Keywords[hu]=Billentyűk,Globális gyorsbillentyűk,Billentyűséma,Gyorsbillentyűk,alkalmazás gyorsbillentyűk,globális gyorsbillentyűk +X-KDE-Keywords[ia]=Claves,ligamines de clave global,schema de clave,ligamines de clave,vias breve,vias breve de application,vias breve global +X-KDE-Keywords[it]=tasti,scorciatoie globali di tastiera,schema di tasti,scorciatoie,scorciatoie delle applicazioni,scorciatoie globali +X-KDE-Keywords[kk]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts +X-KDE-Keywords[km]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts +X-KDE-Keywords[ko]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,키,전역 키 바인딩,키 바인딩,단축키,프로그램 단축키 +X-KDE-Keywords[mr]=कीज, ग्लोबल की बाईंडिंगज, की स्कीम, की बाईंडिंगज, शॉर्टकटस, अप्लिकेशन शॉर्टकटस, ग्लोबल शॉर्टकटस +X-KDE-Keywords[nb]=Taster,Globale tastebindinger,Tastaturutforming,Tastebindinger,snarveier,programsnarveier,globale snarveier +X-KDE-Keywords[nds]=Tasten,Globaal Tasttowiesen,Tasttowiesen,Tastkombinatschonen,Programm-Tastkombinatschonen,Globaal Tastkombinatschonen +X-KDE-Keywords[nl]=toetsen,globale toetsbindingen,toetsenschema,toetsbindingen,sneltoetsen,sneltoetsen van toepassing,globale sneltoetsen +X-KDE-Keywords[pl]=Klawisze,Globalne powiązania klawiszy,Motyw klawiszy,Powiązania klawiszy,skróty,skróty programów,globalne skróty +X-KDE-Keywords[pt]=Teclas,combinações de teclas,global,esquema de teclas,atalhos de teclado,atalhos,atalhos das aplicações +X-KDE-Keywords[pt_BR]=Teclas,combinações de teclas global,esquema de teclas,atalhos de teclado,atalhos,atalhos dos aplicativos, atalhos globais +X-KDE-Keywords[ru]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts,клавиши,глобальные привязки клавиш,схема,привязки клавиш,комбинации клавиш,комбинации клавиш в приложениях,глобальные привязки клавиш +X-KDE-Keywords[sk]=Klávesy,Globálne klávesové skratky,Klávesová schéma,Klávesové skratky,skratky,skratky aplikácie,globálne skratky +X-KDE-Keywords[sl]=tipke,splošne tipkovne bližnjice,tipkovna shema,shema tipk,tipkovne bližnjice,vezave tipk,bližnjice,programske bližnjice,splošne bližnjice +X-KDE-Keywords[sr]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts,тастери,глобалне свезе тастера,шема тастера,свезе тастера,пречице,пречице програма,глобалне пречице +X-KDE-Keywords[sr@ijekavian]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts,тастери,глобалне свезе тастера,шема тастера,свезе тастера,пречице,пречице програма,глобалне пречице +X-KDE-Keywords[sr@ijekavianlatin]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts,tasteri,globalne sveze tastera,šema tastera,sveze tastera,prečice,prečice programa,globalne prečice +X-KDE-Keywords[sr@latin]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts,tasteri,globalne sveze tastera,šema tastera,sveze tastera,prečice,prečice programa,globalne prečice +X-KDE-Keywords[sv]=Tangenter,Globala tangentbindingar,Tangentschema,Tangentbindingar,genvägar,programgenvägar,globala genvägar +X-KDE-Keywords[tr]=Tuşlar,Genel kısayollar,Klavye şeması,Klavye Kısayolları,kısayollar,uygulama kısayolları,genel kısayollar, kısayol tuşları +X-KDE-Keywords[uk]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts,клавіатура,скорочення,клавіатурні скорочення,схема,загальні клавіатурні скорочення,клавіатурні скорочення програми,загальні скорочення +X-KDE-Keywords[vi]=Phím,tổ hợp phím toàn cục,phối hợp phím,tổ hợp phím,gõ tắt,gõ tắt cho ứng dụng +X-KDE-Keywords[x-test]=xxKeys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcutsxx +X-KDE-Keywords[zh_CN]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts,按键,全局键绑定,按键方案,按键绑定,快捷键,应用程序,全局快捷键 +X-KDE-Keywords[zh_TW]=Keys,Global key bindings,Key scheme,Key bindings,shortcuts,application shortcuts,global shortcuts + +Categories=Qt;KDE;X-KDE-settings-accessibility; diff --git a/kcontrol/keys/kglobalshortcutseditor.cpp b/kcontrol/keys/kglobalshortcutseditor.cpp new file mode 100644 index 00000000..50f3796a --- /dev/null +++ b/kcontrol/keys/kglobalshortcutseditor.cpp @@ -0,0 +1,676 @@ +/* + * Copyright 2008 Michael Jansen + * + * 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 "kglobalshortcutseditor.h" + +#include "ui_kglobalshortcutseditor.h" +#include "export_scheme_dialog.h" +#include "select_scheme_dialog.h" +#include "globalshortcuts.h" +#include "kglobalaccel_interface.h" +#include "kglobalaccel_component_interface.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* + * README + * + * This class was created because the kshortcutseditor class has some shortcomings. That class uses + * QTreeWidget and therefore makes it impossible for an outsider to switch the models. But the + * global shortcuts editor did that. Each global component ( kded, krunner, kopete ... ) was + * destined to be separately edited. If you selected another component the kshortcutseditor was + * cleared and refilled. But the items take care of undoing. Therefore when switching the component + * you lost the undo history. + * + * To solve that problem this class keeps one kshortcuteditor for each component. That is easier + * than rewrite that dialog to a model/view framework. + * + * It perfectly covers a bug of KExtedableItemDelegate when clearing and refilling the associated + * model. + */ + +class ComponentData + { + +public: + + ComponentData( + const QString &uniqueName, + const QDBusObjectPath &path, + KShortcutsEditor *_editor); + + ~ComponentData(); + + QString uniqueName() const; + KShortcutsEditor *editor(); + QDBusObjectPath dbusPath(); + +private: + + QString _uniqueName; + QDBusObjectPath _path; + QPointer _editor; + }; + + +ComponentData::ComponentData( + const QString &uniqueName, + const QDBusObjectPath &path, + KShortcutsEditor *editor) + : _uniqueName(uniqueName), + _path(path), + _editor(editor) + {} + + +ComponentData::~ComponentData() + { + delete _editor; _editor = 0; + } + + +QString ComponentData::uniqueName() const + { + return _uniqueName; + } + + +QDBusObjectPath ComponentData::dbusPath() + { + return _path; + } + + +KShortcutsEditor *ComponentData::editor() + { + return _editor; + } + + +class KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate +{ +public: + + KGlobalShortcutsEditorPrivate(KGlobalShortcutsEditor *q) + : q(q), + stack(0), + bus(QDBusConnection::sessionBus()) + {} + + //! Setup the gui + void initGUI(); + + //! Delete the currently selected component + void removeComponent(); + + //! Load the component at @a componentPath + bool loadComponent(const QDBusObjectPath &componentPath); + + //! Return the componentPath for component + QDBusObjectPath componentPath(const QString &componentUnique); + + //! Remove the component + void removeComponent(const QString &componentUnique); + + KGlobalShortcutsEditor *q; + Ui::KGlobalShortcutsEditor ui; + QStackedWidget *stack; + KShortcutsEditor::ActionTypes actionTypes; + QHash components; + QDBusConnection bus; +}; + + +void KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::initGUI() +{ + ui.setupUi(q); + // Create a stacked widget. + stack = new QStackedWidget(q); + q->layout()->addWidget(stack); + + // Connect our components + connect(ui.components, SIGNAL(activated(QString)), + q, SLOT(activateComponent(QString))); + + // Build the menu + QMenu *menu = new QMenu(q); + menu->addAction( KIcon("document-import"), i18n("Import Scheme..."), q, SLOT(importScheme())); + menu->addAction( KIcon("document-export"), i18n("Export Scheme..."), q, SLOT(exportScheme())); + menu->addAction( i18n("Set All Shortcuts to None"), q, SLOT(clearConfiguration())); + menu->addAction( KIcon("edit-delete"), i18n("Remove Component"), q, SLOT(removeComponent())); + + ui.menu_button->setMenu(menu); + + QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(q); + proxyModel->setSourceModel(new QStandardItemModel(0, 1, proxyModel)); + proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + ui.components->setModel(proxyModel); +} + + +KGlobalShortcutsEditor::KGlobalShortcutsEditor(QWidget *parent, KShortcutsEditor::ActionTypes actionTypes) + : QWidget(parent), + d(new KGlobalShortcutsEditorPrivate(this)) +{ + d->actionTypes = actionTypes; + // Setup the ui + d->initGUI(); +} + + +KGlobalShortcutsEditor::~KGlobalShortcutsEditor() +{ + // Before closing the door, undo all changes + undo(); + qDeleteAll(d->components); + delete d; +} + + +void KGlobalShortcutsEditor::activateComponent(const QString &component) +{ + QHash::Iterator iter = d->components.find(component); + if (iter == d->components.end()) { + Q_ASSERT(iter != d->components.end()); + return; + } else { + int index = d->ui.components->findText(component); + Q_ASSERT(index != -1); + if (index > -1) { + // Known component. Get it. + d->ui.components->setCurrentIndex(index); + d->stack->setCurrentWidget((*iter)->editor()); + } + } +} + + +void KGlobalShortcutsEditor::addCollection( + KActionCollection *collection, + const QDBusObjectPath &objectPath, + const QString &id, + const QString &friendlyName) +{ + KShortcutsEditor *editor; + // Check if this component is known + QHash::Iterator iter = d->components.find(friendlyName); + if (iter == d->components.end()) { + // Unknown component. Create an editor. + editor = new KShortcutsEditor(this, d->actionTypes); + d->stack->addWidget(editor); + + // try to find one appropriate icon ( allowing NULL pixmap to be returned) + QPixmap pixmap = KIconLoader::global()->loadIcon(id, KIconLoader::Small, 0, + KIconLoader::DefaultState, QStringList(), 0, true); + // if NULL pixmap is returned, use the F.D.O "system-run" icon + if (pixmap.isNull()) { + pixmap = KIconLoader::global()->loadIcon("system-run", KIconLoader::Small); + } + + // Add to the component combobox + d->ui.components->addItem(pixmap, friendlyName); + d->ui.components->model()->sort(0); + + // Add to our component registry + ComponentData *cd = new ComponentData(id, objectPath, editor); + d->components.insert(friendlyName, cd); + + connect(editor, SIGNAL(keyChange()), this, SLOT(_k_key_changed())); + } else { + // Known component. + editor = (*iter)->editor(); + } + + // Add the collection to the editor of the component + editor->addCollection(collection, friendlyName); + + if (d->ui.components->count() > -1) { + d->ui.components->setCurrentIndex(0); + activateComponent(d->ui.components->itemText(0)); + } +} + + +void KGlobalShortcutsEditor::clearConfiguration() +{ + QString name = d->ui.components->currentText(); + d->components[name]->editor()->clearConfiguration(); +} + + +void KGlobalShortcutsEditor::defaults(ComponentScope scope) +{ + switch (scope) + { + case AllComponents: + Q_FOREACH (ComponentData *cd, d->components) { + // The editors are responsible for the reset + cd->editor()->allDefault(); + } + break; + + case CurrentComponent: { + QString name = d->ui.components->currentText(); + // The editors are responsible for the reset + d->components[name]->editor()->allDefault(); + } + break; + + default: + Q_ASSERT(false); + }; +} + + +void KGlobalShortcutsEditor::clear() +{ + // Remove all components and their associated editors + qDeleteAll(d->components); + d->components.clear(); + d->ui.components->clear(); +} + + +static bool compare(const QString &a, const QString &b) + { + return a.toLower().localeAwareCompare(b.toLower()) < 0; + } + + +void KGlobalShortcutsEditor::exportScheme() +{ + QStringList keys = d->components.keys(); + qSort(keys.begin(), keys.end(), compare); + ExportSchemeDialog dia(keys); + + if (dia.exec() != KMessageBox::Ok) { + return; + } + + KUrl url = KFileDialog::getSaveFileName(KUrl(), "*.kksrc", this); + if (!url.isEmpty()) { + KConfig config(url.path(), KConfig::SimpleConfig); + // TODO: Bug ossi to provide a method for this + Q_FOREACH(const QString &group, config.groupList()) + { + // do not overwrite the Settings group. That makes it possible to + // update the standard scheme kksrc file with the editor. + if (group == "Settings") continue; + config.deleteGroup(group); + } + exportConfiguration(dia.selectedComponents(), &config); + } +} + + +void KGlobalShortcutsEditor::importScheme() +{ + // Check for unsaved modifications + if (isModified()) { + int choice = KMessageBox::warningContinueCancel( + this, + i18n("Your current changes will be lost if you load another scheme before saving this one"), + i18n("Load Shortcut Scheme"), + KGuiItem(i18n("Load"))); + if (choice != KMessageBox::Continue) { + return; + } + } + + SelectSchemeDialog dialog(this); + if (dialog.exec() != KDialog::Accepted) { + return; + } + + KUrl url = dialog.selectedScheme(); + if (!url.isLocalFile()) { + KMessageBox::sorry(this, i18n("This file (%1) does not exist. You can only select local files.", + url.url())); + return; + } + KConfig config(url.path(), KConfig::SimpleConfig); + importConfiguration(&config); +} + + +void KGlobalShortcutsEditor::load() +{ + // Connect to kglobalaccel. If that fails there is no need to continue. + qRegisterMetaType >(); + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >(); + qDBusRegisterMetaType(); + + org::kde::KGlobalAccel kglobalaccel( + "org.kde.kglobalaccel", + "/kglobalaccel", + d->bus); + + if (!kglobalaccel.isValid()) { + QString errorString; + QDBusError error = kglobalaccel.lastError(); + // The global shortcuts DBus service manages all global shortcuts and we + // can't do anything useful without it. + if (error.isValid()) { + errorString = i18n("Message: %1\nError: %2", error.message(), error.name()); + } + + KMessageBox::sorry( + this, + i18n("Failed to contact the KDE global shortcuts daemon\n") + + errorString ); + return; + } + + // Undo all changes not yet applied + undo(); + clear(); + + QDBusReply< QList > componentsRc = kglobalaccel.allComponents(); + if (!componentsRc.isValid()) + { + // Sometimes error pop up only after the first real call. + QString errorString; + QDBusError error = componentsRc.error(); + // The global shortcuts DBus service manages all global shortcuts and we + // can't do anything useful without it. + if (error.isValid()) { + errorString = i18n("Message: %1\nError: %2", error.message(), error.name()); + } + + KMessageBox::sorry( + this, + i18n("Failed to contact the KDE global shortcuts daemon\n") + + errorString ); + return; + } + QList components = componentsRc; + + Q_FOREACH(const QDBusObjectPath &componentPath, components) { + d->loadComponent(componentPath); + } // Q_FOREACH(component) +} + + +void KGlobalShortcutsEditor::save() +{ + // The editors are responsible for the saving + kDebug() << "Save the changes"; + Q_FOREACH (ComponentData *cd, d->components) { + cd->editor()->commit(); + } +} + + +void KGlobalShortcutsEditor::importConfiguration(KConfigBase *config) +{ + kDebug() << config->groupList(); + + // In a first step clean out the current configurations. We do this + // because we want to minimize the chance of conflicts. + Q_FOREACH (ComponentData *cd, d->components) { + KConfigGroup group(config, cd->uniqueName()); + kDebug() << cd->uniqueName() << group.name(); + if (group.exists()) { + kDebug() << "Removing" << cd->uniqueName(); + cd->editor()->clearConfiguration(); + } + } + + // Now import the new configurations. + Q_FOREACH (ComponentData *cd, d->components) { + KConfigGroup group(config, cd->uniqueName()); + if (group.exists()) { + kDebug() << "Importing" << cd->uniqueName(); + cd->editor()->importConfiguration(&group); + } + } +} + +void KGlobalShortcutsEditor::exportConfiguration(QStringList components, KConfig *config) const + { + Q_FOREACH (const QString &componentFriendly, components) + { + QHash::Iterator iter = d->components.find(componentFriendly); + if (iter == d->components.end()) + { + Q_ASSERT(iter != d->components.end()); + continue; + } + else + { + KConfigGroup group(config, (*iter)->uniqueName()); + (*iter)->editor()->exportConfiguration(&group); + } + } + } + + +void KGlobalShortcutsEditor::undo() +{ + // The editors are responsible for the undo + kDebug() << "Undo the changes"; + Q_FOREACH (ComponentData *cd, d->components) { + cd->editor()->undoChanges(); + } +} + + +bool KGlobalShortcutsEditor::isModified() const +{ + Q_FOREACH (ComponentData *cd, d->components) { + if (cd->editor()->isModified()) { + return true; + } + } + return false; +} + + +void KGlobalShortcutsEditor::_k_key_changed() +{ + emit changed(isModified()); +} + + +QDBusObjectPath KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::componentPath(const QString &componentUnique) +{ + return QDBusObjectPath(QLatin1String("/component/") + componentUnique); +} + + +void KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::removeComponent() +{ + QString name = ui.components->currentText(); + QString componentUnique = components.value(name)->uniqueName(); + + // The confirmation text is different when the component is active + if (KGlobalAccel::isComponentActive(componentUnique)) { + if (KMessageBox::questionYesNo( + q, + i18n("Component '%1' is currently active. Only global shortcuts currently not active will be removed from the list.\n" + "All global shortcuts will reregister themselves with their defaults when they are next started.", componentUnique), + i18n("Remove component")) != KMessageBox::Yes) { + return; + } + } else { + if (KMessageBox::questionYesNo( + q, + i18n("Are you sure you want to remove the registered shortcuts for component '%1'? " + "The component and shortcuts will reregister themselves with their default settings" + " when they are next started.", + componentUnique), + i18n("Remove component")) != KMessageBox::Yes) { + return; + } + } + + // Initiate the removing of the component. + if (KGlobalAccel::cleanComponent(componentUnique)) { + + // Get the objectPath BEFORE we delete the source of it + QDBusObjectPath oPath = components.value(name)->dbusPath(); + // Remove the component from the gui + removeComponent(componentUnique); + + // Load it again + // ############# + if (loadComponent(oPath)) { + // Active it + q->activateComponent(name); + } + } +} + + +bool KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::loadComponent(const QDBusObjectPath &componentPath) +{ + // Get the component + org::kde::kglobalaccel::Component component( + "org.kde.kglobalaccel", + componentPath.path(), + bus); + if (!component.isValid()) { + kDebug() << "Component " << componentPath.path() << "not valid! Skipping!"; + return false; + } + + // Get the shortcut contexts. + QDBusReply shortcutContextsRc = component.getShortcutContexts(); + if (!shortcutContextsRc.isValid()) { + kDebug() << "Failed to get contexts for component " + << componentPath.path() <<"! Skipping!"; + kDebug() << shortcutContextsRc.error(); + return false; + } + QStringList shortcutContexts = shortcutContextsRc; + + // We add the shortcuts for all shortcut contexts to the editor. This + // way the user keeps full control of it's shortcuts. + Q_FOREACH (const QString &shortcutContext, shortcutContexts) { + + QDBusReply< QList > shortcutsRc = + component.allShortcutInfos(shortcutContext); + if (!shortcutsRc.isValid()) + { + kDebug() << "allShortcutInfos() failed for " << componentPath.path() << shortcutContext; + continue; + } + QList shortcuts = shortcutsRc; + // Shouldn't happen. But you never know + if (shortcuts.isEmpty()) { + kDebug() << "Got shortcut context" << shortcutContext << "without shortcuts for" + << componentPath.path(); + continue; + } + + // It's safe now + const QString componentUnique = shortcuts[0].componentUniqueName(); + QString componentContextId = componentUnique; + // kglobalaccel knows that '|' is our separator between + // component and context + if (shortcutContext != "default") { + componentContextId += QString("|") + shortcutContext; + } + + // Create a action collection for our current component:context + KActionCollection* col = new KActionCollection( + q, + KComponentData(componentContextId.toAscii())); + + // Now add the shortcuts. + Q_FOREACH (const KGlobalShortcutInfo &shortcut, shortcuts) { + + const QString &objectName = shortcut.uniqueName(); + KAction *action = col->addAction(objectName); + action->setProperty("isConfigurationAction", QVariant(true)); // see KAction::~KAction + action->setText(shortcut.friendlyName()); + + // Always call this to enable global shortcuts for the action. The editor widget + // checks it. + // Also actually loads the shortcut using the KAction::Autoloading mechanism. + // Avoid setting the default shortcut; it would just be written to the global + // configuration so we would not get the real one below. + action->setGlobalShortcut(KShortcut(), KAction::ActiveShortcut); + + // The default shortcut will never be loaded because it's pointless in a real + // application. There are no scarce resources [i.e. physical keys] to manage + // so applications can set them at will and there's no autoloading. + QList sc = shortcut.defaultKeys(); + if (sc.count()>0) { + action->setGlobalShortcut(KShortcut(sc[0]), KAction::DefaultShortcut); + } + } // Q_FOREACH(shortcut) + + QString componentFriendlyName = shortcuts[0].componentFriendlyName(); + + if (shortcuts[0].contextUniqueName() != "default") + { + componentFriendlyName += + QString('[') + shortcuts[0].contextFriendlyName() + QString(']'); + } + + q->addCollection(col, componentPath, componentContextId, componentFriendlyName ); + + } // Q_FOREACH(context) + + return true; +} + + +void KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::removeComponent( + const QString &componentUnique ) + { + // TODO: Remove contexts too. + + Q_FOREACH (const QString &text, components.keys()) + { + if (components.value(text)->uniqueName() == componentUnique) + { + // Remove from QComboBox + int index = ui.components->findText(text); + Q_ASSERT(index != -1); + ui.components->removeItem(index); + + // Remove from QStackedWidget + stack->removeWidget(components[text]->editor()); + + // Remove the componentData + delete components.take(text); + } + } + } + + +#include "kglobalshortcutseditor.moc" diff --git a/kcontrol/keys/kglobalshortcutseditor.h b/kcontrol/keys/kglobalshortcutseditor.h new file mode 100644 index 00000000..26781862 --- /dev/null +++ b/kcontrol/keys/kglobalshortcutseditor.h @@ -0,0 +1,156 @@ +/* + * Copyright 2008 Michael Jansen + * + * 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 KGLOBALSHORTCUTSEDITOR_H +#define KGLOBALSHORTCUTSEDITOR_H + +#include + +#include "kshortcutseditor.h" + +class KActionCollection; +class KShortcut; +class KConfig; +class QDBusObjectPath; + +/** + * Combine a KShortcutsEditor with a KComboBox. + * + * @see KShortcutsEditor + * @author Michael Jansen + */ +class KGlobalShortcutsEditor : public QWidget +{ + Q_OBJECT + +public: + + /** + * Constructor + * + * @param parent parent widget + */ + KGlobalShortcutsEditor(QWidget *parent, + KShortcutsEditor::ActionTypes actionTypes = KShortcutsEditor::AllActions); + ~KGlobalShortcutsEditor(); + + /** + * Insert an action collection, i.e. add all it's actions to the ones already associated + * with the KShortcutsEditor object. + * + * @param collection the collection to add + * @param component title for the component + * @param title title for the subtree in the component + */ + void addCollection(KActionCollection *, const QDBusObjectPath &path, const QString &id, const QString &name); + + /** + * Clear all collections were currently hosting. Current changes are not + * undone? Do that before calling this method. + */ + void clear(); + + + /** + * Revert all changes made since the last save. + */ + void undo(); + + + /** + * Load the shortcuts from the configuration. + */ + void importConfiguration(KConfigBase *config); + + + /** + * Save the shortcuts to the configuration. + */ + void exportConfiguration(QStringList componentsFriendly, KConfig *config) const; + + + /** + * Are the unsaved changes? + */ + bool isModified() const; + + enum ComponentScope + { + AllComponents, + CurrentComponent + }; + +Q_SIGNALS: + + /** + * Indicate that state of the modules contents has changed. + * + * @param state changed or not + */ + void changed(bool); + + +public Q_SLOTS: + + /** + * Activate the component \a component. + * + * @param component the component + */ + void activateComponent(const QString &component); + + /** + * Set all shortcuts to none. + */ + void clearConfiguration(); + + /** + * Load/Reload the global shortcuts + */ + void load(); + + /** + * Make the changes persistent. + * + * That's function is not really saving. Global shortcuts are saved immediately. This + * prevent the undo on deleting the editor. + */ + void save(); + + /** + * Set shortcuts to their default value; + */ + void defaults(ComponentScope scope); + + virtual void importScheme(); + virtual void exportScheme(); + +private Q_SLOTS: + void _k_key_changed(); + +private: + + friend class KGlobalShortcutsEditorPrivate; + class KGlobalShortcutsEditorPrivate; + KGlobalShortcutsEditorPrivate *const d; + + Q_DISABLE_COPY(KGlobalShortcutsEditor) + + Q_PRIVATE_SLOT(d, void removeComponent()) +}; // class KGlobalShortcutsEditor + +#endif // KGLOBALSHORTCUTSEDITOR_H diff --git a/kcontrol/keys/kglobalshortcutseditor.ui b/kcontrol/keys/kglobalshortcutseditor.ui new file mode 100644 index 00000000..444103e2 --- /dev/null +++ b/kcontrol/keys/kglobalshortcutseditor.ui @@ -0,0 +1,57 @@ + + + KGlobalShortcutsEditor + + + + 0 + 0 + 612 + 516 + + + + + + + + + KDE component: + + + + + + + + 0 + 0 + + + + + + + + File + + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+
+ + components + menu_button + + + +
diff --git a/kcontrol/keys/schemes/kde3.kksrc b/kcontrol/keys/schemes/kde3.kksrc new file mode 100644 index 00000000..336757d3 --- /dev/null +++ b/kcontrol/keys/schemes/kde3.kksrc @@ -0,0 +1,166 @@ +[Settings] +Name=KDE Default for 3 Modifier Keys +Name[af]=Standaard KDE vir 3 verandering sleutels +Name[ar]=مبدئي كدي لـ3 مفاتيح مغيرة +Name[ast]=Predetermináu de KDE de 3 modificadores de tecláu +Name[be]=Стандартны для KDE з трыма клавішамі мадыфікацыі +Name[be@latin]=Zmoŭčanaja schiema „KDE” dla 3 klavišnych madyfikataraŭ +Name[bg]=KDE (с 3 модификационни клавиша) +Name[ca]=Omissió del KDE per a 3 tecles modificadores +Name[ca@valencia]=Omissió del KDE per a 3 tecles modificadores +Name[cs]=Výchozí pro KDE (3 modifikátory) +Name[csb]=Domëslny nastôw KDE dlô 3 klawiszów zjinaczi +Name[cy]=Rhagosodion KDE i 3 Bysell Addasu +Name[da]=KDE-standard med 3 modifikatortaster +Name[de]=KDE-Standard für 3 Sondertasten +Name[el]=Προκαθορισμένο του KDE για 3 τροποποιητές +Name[en_GB]=KDE Default for 3 Modifier Keys +Name[eo]=KDE-defaŭlto por 3 modifoklavoj +Name[es]=Predeterminado de KDE de 3 modificadores de teclado +Name[et]=KDE vaikeskeem 3 muuteklahviga +Name[eu]=KDE lehenetsia 3 tekla modifikatzailekin +Name[fa]=پیش‌فرض KDE برای ۳ کلید تغییردهنده +Name[fi]=KDE oletus 3:lle muokkausnäppäimelle +Name[fr]=KDE par défaut pour 3 touches de modifications +Name[fy]=KDE-standert foar 3 modifikaasjetoetsen +Name[ga]=Réamhshocrú KDE le haghaidh trí eochair mhionathraithe +Name[gl]=Predeterminado de KDE para 3 teclas modificadoras +Name[gu]=૩ બદલેલ કળો માટે KDE મૂળભૂત +Name[he]=ברירת המחדל של KDE עבור 3 כפתורים משני מצב +Name[hi]=3 मॉडीफ़ायर कुंजियों के लिए केडीई डिफ़ॉल्ट +Name[hne]=3 माडीफायर कुंजी मन बर केडीई डिफाल्ट +Name[hr]=KDE zadano za 3 modifikatorske tipke +Name[hsb]=KDE-standard za tři modifikowace tasty +Name[hu]=KDE-s alapértelmezés (3 módosító billentyűvel) +Name[ia]=KDE predefinite pro 3 claves modificator +Name[id]=Standar KDE untuk 3 Tombol Pengubah +Name[is]=Sjálfgefið KDE fyrir 3 breytilykla +Name[it]=Predefinito di KDE per 3 tasti modificatori +Name[ja]=KDE 標準 (修飾キー 3 個) +Name[kk]=3 түрлендіру пернелі KDE-нің әдетті баптауы +Name[km]=លំនាំដើម​របស់ KDE សម្រាប់​សោ​កែប្រែ ៣ +Name[kn]=೩ ಪರಿವರ್ತಕ ಕೀಲಿಗಳಿಗೆ ಕೆಡಿಇ ಪೂರ್ವನಿಯೋಜನೆ +Name[ko]=세 개의 수정자 키를 사용하는 KDE 기본값 +Name[ku]=KDE Standard ji bo 3 Bişkojkên Guherker +Name[lt]=KDE numatytoji 3 lygio klavišams – modifikatoriams +Name[lv]=KDE noklusējums ar 3 modifikācijas taustiņiem +Name[mai]=3 माडीफायर कुंजीसभ क' लेल केडीई पूर्वनिर्धारित +Name[mk]=KDE-стандардно за 3 копчиња-модификатори +Name[ml]=3 മോഡിഫയര്‍ കീകള്‍ക്കു് കെഡിഇയുടെ സഹജമായതു് +Name[mr]=3 संपादन की करीता KDE मुलभूत +Name[ms]=Piawai KDE untuk 3 Kekunci Pengubah Suai +Name[nb]=KDE-standard for tre valgtaster +Name[nds]=KDE-Standard för 3 Sünnertasten +Name[ne]=३ परिमार्जक कुञ्जीका लागि पूर्वनिर्धारित केडीई +Name[nl]=KDE-standaard voor 3 modificatietoetsen +Name[nn]=KDE-standard med tre valtastar +Name[or]=3ଟି ପରିବର୍ତ୍ତକ କି ପାଇଁ KDE ପୂର୍ବନିର୍ଦ୍ଧାରିତ +Name[pa]=3 ਮੋਡੀਫਾਇਰ ਸਵਿੱਚਾਂ ਲਈ KDE ਡਿਫਾਲਟ +Name[pl]=Ustawienia domyślne KDE dla 3 klawiszy modyfikatorów +Name[pt]=Predefinição do KDE para 3 Teclas Modificadoras +Name[pt_BR]=Padrão do KDE para 3 teclas modificadoras +Name[ro]=Implicit KDE pentru 3 modificatori +Name[ru]=KDE с тремя клавишами-модификаторами +Name[se]=KDE-standárda mas leat golbma válljeboalu +Name[si]=3 වෙනස් යතුරු සඳහා KDE පෙරනිමියන් +Name[sk]=KDE štandardné (3 modifikačné klávesy) +Name[sl]=Privzeto za 3 spremenilne tipke +Name[sr]=КДЕ‑ово подразумевано за три модификаторска тастера +Name[sr@ijekavian]=КДЕ‑ово подразумијевано за три модификаторска тастера +Name[sr@ijekavianlatin]=KDE‑ovo podrazumijevano za tri modifikatorska tastera +Name[sr@latin]=KDE‑ovo podrazumevano za tri modifikatorska tastera +Name[sv]=KDE-förinställt med 3 väljartangenter +Name[ta]=KDE Default for 3 Modifier Keys +Name[te]=3 సవరింపు కీలకొరకు KDE అప్రమేయం +Name[tg]=KDE с тремя клавишами-модификаторами +Name[th]=ค่าปริยายของ KDE สำหรับปุ่มเปลี่ยนหน้าที่ 3 ปุ่ม +Name[tr]=3 Değiştirici Anahtar için KDE Varsayılan +Name[uk]=Типова для KDE з 3 клавішами-модифікаторами +Name[vi]=Mặc định KDE cho 3 Phím Bổ trợ +Name[wa]=Prémetou KDE (3 tapes modifieueses) +Name[xh]=KDE Engagqibekanga ye 3 Izitsixo Mofifier +Name[x-test]=xxKDE Default for 3 Modifier Keysxx +Name[zh_CN]=三个修饰键的 KDE 默认值 +Name[zh_TW]=KDE 預設 3 個變更鍵 +Uses Win Modifier=false + +[klipper][Global Shortcuts] +clipboard_action=Ctrl+Alt+X +repeat_action=Ctrl+Alt+R +show_klipper_popup=Ctrl+Alt+V + +[krunner][Global Shortcuts] +Halt Without Confirmation=none +Lock Session=Ctrl+Alt+L +Log Out Without Confirmation=none +Log Out=Ctrl+Alt+Del +Reboot Without Confirmation=none +Run Command=Alt+F2 +Show System Activity=Ctrl+Esc + +[kwin][Global Shortcuts] +Desktop Screenshot to Clipboard=Ctrl+Print +Kill Window=Ctrl+Alt+Esc +Mouse Emulation=Alt+F12 +Switch One Desktop Down=none +Switch One Desktop Up=none +Switch One Desktop to the Left=none +Switch One Desktop to the Right=none +Switch to Desktop 10=Ctrl+F10 +Switch to Desktop 11=Ctrl+F11 +Switch to Desktop 12=Ctrl+F12 +Switch to Desktop 13=Ctrl+Shift+F1 +Switch to Desktop 14=Ctrl+Shift+F2 +Switch to Desktop 15=Ctrl+Shift+F3 +Switch to Desktop 16=Ctrl+Shift+F4 +Switch to Desktop 1=Ctrl+F1 +Switch to Desktop 2=Ctrl+F2 +Switch to Desktop 3=Ctrl+F3 +Switch to Desktop 4=Ctrl+F4 +Switch to Desktop 5=Ctrl+F5 +Switch to Desktop 6=Ctrl+F6 +Switch to Desktop 7=Ctrl+F7 +Switch to Desktop 8=Ctrl+F8 +Switch to Desktop 9=Ctrl+F9 +Switch to Next Desktop=none +Switch to Previous Desktop=none +Toggle Window Raise/Lower=none +Walk Through Desktop List (Reverse)=Ctrl+Shift+Tab +Walk Through Desktop List=Ctrl+Tab +Walk Through Desktops (Reverse)=none +Walk Through Desktops=none +Walk Through Windows (Reverse)=Alt+Shift+Tab +Walk Through Windows=Alt+Tab +Window Close=Alt+F4 +Window Lower=none +Window Maximize Horizontal=none +Window Maximize Vertical=none +Window Maximize=none +Window Minimize=none +Window Move=none +Window Operations Menu=Alt+F3 +Window Raise=none +Window Resize=none +Window Screenshot to Clipboard=Alt+Print +Window Shade=none +Window to Desktop 10=none +Window to Desktop 11=none +Window to Desktop 12=none +Window to Desktop 13=none +Window to Desktop 14=none +Window to Desktop 15=none +Window to Desktop 16=none +Window to Desktop 1=none +Window to Desktop 2=none +Window to Desktop 3=none +Window to Desktop 4=none +Window to Desktop 5=none +Window to Desktop 6=none +Window to Desktop 7=none +Window to Desktop 8=none +Window to Desktop 9=none +Window to Next Desktop=none +Window to Previous Desktop=none + +[kxkb][Global Shortcuts] +Switch to Next Keyboard Layout=Ctrl+Alt+K diff --git a/kcontrol/keys/schemes/kde4.kksrc b/kcontrol/keys/schemes/kde4.kksrc new file mode 100644 index 00000000..2ea1432b --- /dev/null +++ b/kcontrol/keys/schemes/kde4.kksrc @@ -0,0 +1,166 @@ +[Settings] +Name=KDE Default for 4 Modifier Keys +Name[af]=Standaard KDE vir 4 verandering sleutels +Name[ar]=مبدئي كدي لـ4 مفاتيح مغيرة +Name[ast]=Predetermináu de KDE de 4 modificadores de tecláu +Name[be]=Стандартны для KDE з чатырма клавішамі мадыфікацыі +Name[be@latin]=Zmoŭčanaja schiema „KDE” dla 4 klavišnych madyfikataraŭ +Name[bg]=KDE (с 4 модификационни клавиша) +Name[ca]=Omissió del KDE per a 4 tecles modificadores +Name[ca@valencia]=Omissió del KDE per a 4 tecles modificadores +Name[cs]=Výchozí pro KDE (4 modifikátory) +Name[csb]=Domëslny nastôw KDE dlô 4 klawiszów zjinaczi +Name[cy]=Rhagosodion KDE i 4 Bysell Addasu +Name[da]=KDE-standard med 4 modifikatortaster +Name[de]=KDE-Standard für 4 Sondertasten +Name[el]=Προκαθορισμένο του KDE για 4 τροποποιητές +Name[en_GB]=KDE Default for 4 Modifier Keys +Name[eo]=KDE-defaŭlto por 4 modifoklavoj +Name[es]=Predeterminado de KDE de 4 modificadores de teclado +Name[et]=KDE vaikeskeem 4 muuteklahviga +Name[eu]=KDE lehenetsia 4 tekla modifikatzailekin +Name[fa]=پیش‌فرض KDE برای ۴ کلید تغییردهنده +Name[fi]=KDE oletus 4:lle muokkausnäppäimelle +Name[fr]=KDE par défaut pour 4 touches de modifications +Name[fy]=KDE-standert foar 4 modifikaasjetoetsen +Name[ga]=Réamhshocrú KDE le haghaidh ceithre eochair mhionathraithe +Name[gl]=Predeterminado de KDE para 4 teclas modificadoras +Name[gu]=૪ બદલેલ કળો માટે KDE મૂળભૂત +Name[he]=ברירת המחדל של KDE עבור 4 כפתורים משני מצב +Name[hi]=4 मॉडीफ़ायर कुंजियों के लिए केडीई डिफ़ॉल्ट +Name[hne]=4 माडीफायर कुंजी मन बर केडीई डिफाल्ट +Name[hr]=KDE zadano za 4 modifikatorske tipke +Name[hsb]=KDE-standard za štyri modifikowace tasty +Name[hu]=KDE-s alapértelmezés (4 módosító billentyűvel) +Name[ia]=KDE predefinite pro 4 claves modificator +Name[id]=Standar KDE untuk 4 Tombol Pengubah +Name[is]=Sjálfgefið KDE fyrir 4 breytilykla +Name[it]=Predefinito di KDE per 4 tasti modificatori +Name[ja]=KDE 標準 (修飾キー 4 個) +Name[kk]=4 түрлендіру пернелі KDE-нің әдетті баптауы +Name[km]=លំនាំដើម​របស់ KDE សម្រាប់​សោ​កែប្រែ ៤ +Name[kn]=೪ ಪರಿವರ್ತಕ ಕೀಲಿಗಳಿಗೆ ಕೆಡಿಇ ಪೂರ್ವನಿಯೋಜನೆ +Name[ko]=네 개의 수정자 키를 사용하는 KDE 기본값 +Name[ku]=KDE Standard ji bo 4 Bişkojkên Guherker +Name[lt]=KDE numatytoji 4 lygio klavišams – modifikatoriams +Name[lv]=KDE noklusējums ar 4 modifikācijas taustiņiem +Name[mai]=4 माडीफायर कुंजियों क' लेल केडीई पूर्वनिर्धारित +Name[mk]=KDE-стандардно за 4 копчиња-модификатори +Name[ml]=4 മോഡിഫയര്‍ കീകള്‍ക്കു് കെഡിഇയുടെ സഹജമായതു് +Name[mr]=4 संपादन की करीता KDE मुलभूत +Name[ms]=Piawai KDE untuk 4 Kekunci Pengubah Suai +Name[nb]=KDE-standard for fire valgtaster +Name[nds]=KDE-Standard för 4 Sünnertasten +Name[ne]=४ परिमार्जक कुञ्जीका लागि पूर्वनिर्धारित केडीई +Name[nl]=KDE-standaard voor 4 modificatietoetsen +Name[nn]=KDE-standard med fire valtastar +Name[or]=4ଟି ପରିବର୍ତ୍ତକ କି ପାଇଁ KDE ପୂର୍ବନିର୍ଦ୍ଧାରିତ +Name[pa]=4 ਮੋਡੀਫਾਇਰ ਸਵਿੱਚਾਂ ਲਈ KDE ਡਿਫਾਲਟ +Name[pl]=Ustawienia domyślne KDE dla 4 klawiszy modyfikatorów +Name[pt]=Predefinição do KDE para 4 Teclas Modificadoras +Name[pt_BR]=Padrão do KDE para 4 teclas modificadoras +Name[ro]=Implicit KDE pentru 4 modificatori +Name[ru]=KDE с четырьмя клавишами-модификаторами +Name[se]=KDE-standárda mas leat njeallje válljenboalu +Name[si]=4 වෙනස් යතුරු සඳහා KDE පෙරනිමියන් +Name[sk]=KDE štandardné (4 modifikačné klávesy) +Name[sl]=Privzeto za 4 spremenilne tipke +Name[sr]=КДЕ‑ово подразумевано за четири модификаторска тастера +Name[sr@ijekavian]=КДЕ‑ово подразумијевано за четири модификаторска тастера +Name[sr@ijekavianlatin]=KDE‑ovo podrazumijevano za četiri modifikatorska tastera +Name[sr@latin]=KDE‑ovo podrazumevano za četiri modifikatorska tastera +Name[sv]=KDE-förinställt med 4 väljartangenter +Name[ta]=KDE Default for 4 Modifier Keys +Name[te]=4 సవరింపు కీలకొరకు KDE అప్రమేయం +Name[tg]=KDE с четырьмя клавишами-модификаторами +Name[th]=ค่าปริยายของ KDE สำหรับปุ่มเปลี่ยนหน้าที่ 4 ปุ่ม +Name[tr]=4 Değiştirici Anahtar için KDE Varsayılan +Name[uk]=Типова для KDE з 4 клавішами-модифікаторами +Name[vi]=Mặc định KDE cho 4 Phím Bổ trợ +Name[wa]=Prémetou KDE (4 tapes modifieueses) +Name[xh]=KDE Engagqibekanga ye 4 Izitsixo Mofifier +Name[x-test]=xxKDE Default for 4 Modifier Keysxx +Name[zh_CN]=四个修饰键的 KDE 默认值 +Name[zh_TW]=KDE 預設 4 個變更鍵 +Uses Win Modifier=true + +[klipper][Global Shortcuts] +clipboard_action=Meta+Ctrl+X +repeat_action=Meta+Ctrl+R +show_klipper_popup=Meta+Ctrl+V + +[krunner][Global Shortcuts] +Halt Without Confirmation=none +Lock Session=Meta+ScrollLock +Log Out Without Confirmation=none +Log Out=Meta+Esc +Reboot Without Confirmation=none +Run Command=Meta+Return; Alt+F2 +Show System Activity=Meta+Ctrl+Pause + +[kwin][Global Shortcuts] +Desktop Screenshot to Clipboard=Meta+Print +Kill Window=Meta+Ctrl+Del +Mouse Emulation=none +Switch One Desktop Down=none +Switch One Desktop Up=none +Switch One Desktop to the Left=none +Switch One Desktop to the Right=none +Switch to Desktop 10=Meta+F10 +Switch to Desktop 11=none +Switch to Desktop 12=none +Switch to Desktop 13=none +Switch to Desktop 14=none +Switch to Desktop 15=none +Switch to Desktop 16=none +Switch to Desktop 1=Meta+F1 +Switch to Desktop 2=Meta+F2 +Switch to Desktop 3=Meta+F3 +Switch to Desktop 4=Meta+F4 +Switch to Desktop 5=Meta+F5 +Switch to Desktop 6=Meta+F6 +Switch to Desktop 7=Meta+F7 +Switch to Desktop 8=Meta+F8 +Switch to Desktop 9=Meta+F9 +Switch to Next Desktop=none +Switch to Previous Desktop=none +Toggle Window Raise/Lower=none +Walk Through Desktop List (Reverse)=none +Walk Through Desktop List=none +Walk Through Desktops (Reverse)=Meta+Shift+Tab +Walk Through Desktops=Meta+Tab +Walk Through Windows (Reverse)=Alt+Shift+Tab +Walk Through Windows=Alt+Tab +Window Close=Alt+Esc; Alt+F4 +Window Lower=none +Window Maximize Horizontal=Meta+= +Window Maximize Vertical=Meta+| +Window Maximize=Meta++ +Window Minimize=Meta+- +Window Move=none +Window Operations Menu=Alt+Menu +Window Raise=none +Window Resize=none +Window Screenshot to Clipboard=Alt+Print +Window Shade=Meta+_ +Window to Desktop 10=Meta+Alt+F10 +Window to Desktop 11=none +Window to Desktop 12=none +Window to Desktop 13=none +Window to Desktop 14=none +Window to Desktop 15=none +Window to Desktop 16=none +Window to Desktop 1=Meta+Alt+F1 +Window to Desktop 2=Meta+Alt+F2 +Window to Desktop 3=Meta+Alt+F3 +Window to Desktop 4=Meta+Alt+F4 +Window to Desktop 5=Meta+Alt+F5 +Window to Desktop 6=Meta+Alt+F6 +Window to Desktop 7=Meta+Alt+F7 +Window to Desktop 8=Meta+Alt+F8 +Window to Desktop 9=Meta+Alt+F9 +Window to Next Desktop=none +Window to Previous Desktop=none + +[kxkb][Global Shortcuts] +Switch to Next Keyboard Layout=Meta+Ctrl+K diff --git a/kcontrol/keys/schemes/mac4.kksrc b/kcontrol/keys/schemes/mac4.kksrc new file mode 100644 index 00000000..0ecde007 --- /dev/null +++ b/kcontrol/keys/schemes/mac4.kksrc @@ -0,0 +1,171 @@ +[Settings] +Name=Mac Scheme +Name[af]=Mac Tema +Name[ar]=مخطط الماك +Name[ast]=Tema Mac +Name[be]=Схема Mac +Name[be@latin]=Schiema „Mac” +Name[bg]=Mac +Name[bn]=ম্যাক্ স্কীম +Name[bn_IN]=Mac স্কিম +Name[br]=Steuñv Mac +Name[ca]=Esquema Mac +Name[ca@valencia]=Esquema Mac +Name[cs]=Mac schéma +Name[csb]=Mòtiw Mac-a +Name[cy]=Cynllun Mac +Name[da]=Mac-system +Name[de]=Mac-Design +Name[el]=Σχήμα Mac +Name[en_GB]=Mac Scheme +Name[eo]=Makintoŝa aranĝo +Name[es]=Tema Mac +Name[et]=Maci skeem +Name[eu]=Mac eskema +Name[fa]=طرحواره مکینتاش +Name[fi]=Mac-skeema +Name[fr]=Agencement Mac +Name[fy]=Mac-skema +Name[ga]=Scéim Mac +Name[gl]=Esquema de Mac +Name[gu]=મેક પધ્ધતિ +Name[he]=ערכת Mac +Name[hi]=मॅक प्रसंग +Name[hne]=मॅक प्रसंग +Name[hr]=Mac shema +Name[hsb]=Mac-šema +Name[hu]=Mac +Name[ia]=Schema Mac +Name[id]=Skema Mac +Name[is]=Mac þema +Name[it]=Schema Mac +Name[ja]=Macintosh スキーマ +Name[ka]=Mac სქემა +Name[kk]=Mac сұлбасы +Name[km]=គ្រោងការណ៍ Mac +Name[kn]=ಮ್ಯಾಕ್ ಪದ್ಧತಿ (ಸ್ಕೀಮ್) +Name[ko]=Mac 배열 +Name[ku]=Dirbê Mac +Name[lt]=Mac schema +Name[lv]=Mac shēma +Name[mai]=मैक प्रसंग +Name[mk]=Mac-шема +Name[ml]=മാക് പദ്ധതി +Name[mr]=मॅक सुत्रयोजना +Name[nb]=Mac-oppsett +Name[nds]=Mac-Vörbild +Name[ne]=म्याक योजना +Name[nl]=Mac-schema +Name[nn]=Mac-oppsett +Name[or]=Mac ଯୋଜନା +Name[pa]=Mac ਸਕੀਮ +Name[pl]=Motyw Mac-a +Name[pt]=Esquema do Mac +Name[pt_BR]=Esquema do Mac +Name[ro]=Schemă Mac +Name[ru]=Mac +Name[se]=Mac-coakkáldat +Name[si]=Mac ක්‍රමය +Name[sk]=Mac schéma +Name[sl]=Shema Mac +Name[sr]=Мекинтошева шема +Name[sr@ijekavian]=Мекинтошева шема +Name[sr@ijekavianlatin]=Macintosheva šema +Name[sr@latin]=Macintosheva šema +Name[sv]=Mac schema +Name[ta]=Mac முறைமை +Name[te]=Mac స్కీమ్ +Name[tg]=Нақшаи Mac +Name[th]=ใช้แบบของ MAC +Name[tr]=Mac Şeması +Name[uk]=Схема Mac +Name[uz]=Mac mavzusi +Name[uz@cyrillic]=Mac мавзуси +Name[vi]=Phối hợp của Mac +Name[wa]=Djeu d' rascourtis Mac +Name[xh]=Udweliso lwe Mac +Name[x-test]=xxMac Schemexx +Name[zh_CN]=Mac 方案 +Name[zh_TW]=Mac 機制 +Uses Win Modifier=true + +[klipper][Global Shortcuts] +clipboard_action=Ctrl+Alt+X +repeat_action=Ctrl+Alt+R +show_klipper_popup=Ctrl+Alt+V + +[krunner][Global Shortcuts] +Halt Without Confirmation=none +Lock Session=Ctrl+Alt+L +Log Out Without Confirmation=none +Log Out=Ctrl+Alt+Del +Reboot Without Confirmation=none +Run Command=Alt+F2 +Show System Activity=Ctrl+Esc + +[kwin][Global Shortcuts] +Desktop Screenshot to Clipboard=Ctrl+Shift+3 +Kill Window=Ctrl+Alt+Esc +Mouse Emulation=none +Switch One Desktop Down=none +Switch One Desktop Up=none +Switch One Desktop to the Left=none +Switch One Desktop to the Right=none +Switch to Desktop 10=Ctrl+F10 +Switch to Desktop 11=Ctrl+F11 +Switch to Desktop 12=Ctrl+F12 +Switch to Desktop 13=Ctrl+Shift+F1 +Switch to Desktop 14=Ctrl+Shift+F2 +Switch to Desktop 15=Ctrl+Shift+F3 +Switch to Desktop 16=Ctrl+Shift+F4 +Switch to Desktop 1=Ctrl+F1 +Switch to Desktop 2=Ctrl+F2 +Switch to Desktop 3=Ctrl+F3 +Switch to Desktop 4=Ctrl+F4 +Switch to Desktop 5=Ctrl+F5 +Switch to Desktop 6=Ctrl+F6 +Switch to Desktop 7=Ctrl+F7 +Switch to Desktop 8=Ctrl+F8 +Switch to Desktop 9=Ctrl+F9 +Switch to Next Desktop=none +Switch to Previous Desktop=none +Toggle Window Raise/Lower=Ctrl+E +Walk Through Desktop List (Reverse)=none +Walk Through Desktop List=none +Walk Through Desktops (Reverse)=Alt+Shift+Tab +Walk Through Desktops=Alt+Tab +Walk Through Windows (Reverse)=Ctrl+Shift+Tab +Walk Through Windows=Ctrl+Tab +Window Close=Alt+F4 +Window Lower=none +Window Maximize Horizontal=none +Window Maximize Vertical=none +Window Maximize=none +Window Minimize=none +Window Move=none +Window Operations Menu=Alt+F3 +Window Raise=none +Window Resize=none +Window Screenshot to Clipboard=Ctrl+Shift+4 +Window Shade=none +Window to Desktop 10=none +Window to Desktop 11=none +Window to Desktop 12=none +Window to Desktop 13=none +Window to Desktop 14=none +Window to Desktop 15=none +Window to Desktop 16=none +Window to Desktop 1=none +Window to Desktop 2=none +Window to Desktop 3=none +Window to Desktop 4=none +Window to Desktop 5=none +Window to Desktop 6=none +Window to Desktop 7=none +Window to Desktop 8=none +Window to Desktop 9=none +Window to Next Desktop=none +Window to Previous Desktop=none + +[kxkb][Global Shortcuts] +Switch to Next Keyboard Layout=Ctrl+Alt+K diff --git a/kcontrol/keys/schemes/old_kde3.kksrc b/kcontrol/keys/schemes/old_kde3.kksrc new file mode 100644 index 00000000..561ff99f --- /dev/null +++ b/kcontrol/keys/schemes/old_kde3.kksrc @@ -0,0 +1,51 @@ + +[Global Shortcuts] +Halt Computer=none +Popup Launch Menu=Alt+F1 +Reboot Computer=none +Show Window List=Alt+F5 +Toggle Showing Desktop=Ctrl+Alt+D + +[Shortcuts] +AddBookmark=Ctrl+B +Back=Alt+Left +Close=Ctrl+W +Copy=Ctrl+C; Ctrl+Insert +Cut=Ctrl+X; Shift+Del +DeleteWordBack=Ctrl+Backspace +DeleteWordForward=Ctrl+Del +Deselect=Ctrl+Shift+A +End=Ctrl+End +Find=Ctrl+F +FindNext=F3 +FindPrev=Shift+F3 +Forward=Alt+Right +GotoLine=Ctrl+G +Help=F1 +Home=Ctrl+Home +Insert=Ctrl+Insert +New=Ctrl+N +Next=Next +NextCompletion=Ctrl+Down +Open=Ctrl+O +Paste=Ctrl+V; Shift+Insert +PopupMenuContext=Menu +PrevCompletion=Ctrl+Up +Print=Ctrl+P +Prior=Prior +Quit=Ctrl+Q +Redo=Ctrl+Shift+Z +Reload=F5 +Replace=Ctrl+R +RotateDown=Down +RotateUp=Up +Save=Ctrl+S +SelectAll=Ctrl+A +ShowMenubar=Ctrl+M +SubstringCompletion=Ctrl+T +TextCompletion=Ctrl+E +Undo=Ctrl+Z +Up=Alt+Up +WhatsThis=Shift+F1 +ZoomIn=Ctrl++ +ZoomOut=Ctrl+- diff --git a/kcontrol/keys/schemes/old_kde4.kksrc b/kcontrol/keys/schemes/old_kde4.kksrc new file mode 100644 index 00000000..64dfd8da --- /dev/null +++ b/kcontrol/keys/schemes/old_kde4.kksrc @@ -0,0 +1,51 @@ + +[Global Shortcuts] +Halt Computer=none +Popup Launch Menu=Meta+Menu +Reboot Computer=none +Show Window List=Meta+0 +Toggle Showing Desktop=Meta+Ctrl+D + +[Shortcuts] +AddBookmark=Ctrl+B +Back=Alt+Left +Close=Ctrl+Esc; Ctrl+W +Copy=Ctrl+C; Ctrl+Insert +Cut=Ctrl+X; Shift+Del +DeleteWordBack=Ctrl+Backspace +DeleteWordForward=Ctrl+Del +Deselect=Ctrl+Shift+A +End=Ctrl+End +Find=Ctrl+F +FindNext=F3 +FindPrev=Shift+F3 +Forward=Alt+Right +GotoLine=Ctrl+G +Help=F1 +Home=Ctrl+Home +Insert=Ctrl+Insert +New=Ctrl+N +Next=Next +NextCompletion=Ctrl+Down +Open=Ctrl+O +Paste=Ctrl+V; Shift+Insert +PopupMenuContext=Menu +PrevCompletion=Ctrl+Up +Print=Ctrl+P +Prior=Prior +Quit=Ctrl+Q +Redo=Ctrl+Shift+Z +Reload=F5 +Replace=Ctrl+R +RotateDown=Down +RotateUp=Up +Save=Ctrl+S +SelectAll=Ctrl+A +ShowMenubar=Ctrl+M +SubstringCompletion=Ctrl+T +TextCompletion=Ctrl+E +Undo=Ctrl+Z +Up=Alt+Up +WhatsThis=Shift+F1 +ZoomIn=Ctrl++ +ZoomOut=Ctrl+- diff --git a/kcontrol/keys/schemes/old_mac4.kksrc b/kcontrol/keys/schemes/old_mac4.kksrc new file mode 100644 index 00000000..f0da90de --- /dev/null +++ b/kcontrol/keys/schemes/old_mac4.kksrc @@ -0,0 +1,51 @@ + +[Global Shortcuts] +Halt Computer=none +Popup Launch Menu=Alt+F1 +Reboot Computer=none +Show Window List=Alt+F5 +Toggle Showing Desktop=Ctrl+Alt+D + +[Shortcuts] +AddBookmark=Ctrl+B +Back=Alt+Left +Close=Ctrl+W +Copy=Ctrl+C +Cut=Ctrl+X +DeleteWordBack=Ctrl+Backspace +DeleteWordForward=Ctrl+Del +Deselect=Ctrl+Shift+A +End=Ctrl+End +Find=Ctrl+F +FindNext=Ctrl+G +FindPrev=Ctrl+Shift+G +Forward=Alt+Right +GotoLine=none +Help=F1 +Home=Ctrl+Home +Insert=Ctrl+Insert +New=Ctrl+N +Next=Next +NextCompletion=Ctrl+Down +Open=Ctrl+O +Paste=Ctrl+V +PopupMenuContext=Menu +PrevCompletion=Ctrl+Up +Print=Ctrl+P +Prior=Prior +Quit=Ctrl+Q +Redo=Ctrl+Shift+Z +Reload=F5 +Replace=Ctrl+R +RotateDown=Down +RotateUp=Up +Save=Ctrl+S +SelectAll=Ctrl+A +ShowMenubar=Ctrl+M +SubstringCompletion=Ctrl+T +TextCompletion=Ctrl+E +Undo=Ctrl+Z +Up=Alt+Up +WhatsThis=Shift+F1 +ZoomIn=Ctrl++ +ZoomOut=Ctrl+- diff --git a/kcontrol/keys/schemes/old_unix3.kksrc b/kcontrol/keys/schemes/old_unix3.kksrc new file mode 100644 index 00000000..6e724007 --- /dev/null +++ b/kcontrol/keys/schemes/old_unix3.kksrc @@ -0,0 +1,51 @@ + +[Global Shortcuts] +Halt Computer=none +Popup Launch Menu=Alt+F1 +Reboot Computer=none +Show Window List=none +Toggle Showing Desktop=Ctrl+Alt+D + +[Shortcuts] +AddBookmark=Ctrl+B +Back=Alt+Left +Close=Ctrl+W +Copy=Ctrl+C +Cut=Ctrl+X +DeleteWordBack=Ctrl+Backspace +DeleteWordForward=Ctrl+Del +Deselect=Ctrl+Shift+A +End=Ctrl+End +Find=Ctrl+S +FindNext=F3 +FindPrev=Shift+F3 +Forward=Alt+Right +GotoLine=Ctrl+G +Help=F1 +Home=Ctrl+Home +Insert=Ctrl+Insert +New=Ctrl+N +Next=Next +NextCompletion=Ctrl+Down +Open=Ctrl+O +Paste=Ctrl+V +PopupMenuContext=Menu +PrevCompletion=Ctrl+Up +Print=Ctrl+P +Prior=Prior +Quit=Ctrl+Q +Redo=Ctrl+Shift+Z +Reload=F5 +Replace=Ctrl+R +RotateDown=Down +RotateUp=Up +Save=Ctrl+S +SelectAll= +ShowMenubar=Ctrl+M +SubstringCompletion=Ctrl+T +TextCompletion=Ctrl+E +Undo=Ctrl+Z +Up=Alt+Up +WhatsThis=Shift+F1 +ZoomIn=Ctrl++ +ZoomOut=Ctrl+- diff --git a/kcontrol/keys/schemes/old_win3.kksrc b/kcontrol/keys/schemes/old_win3.kksrc new file mode 100644 index 00000000..410d6877 --- /dev/null +++ b/kcontrol/keys/schemes/old_win3.kksrc @@ -0,0 +1,51 @@ + +[Global Shortcuts] +Halt Computer=none +Popup Launch Menu=Ctrl+Esc +Reboot Computer=none +Show Window List=none +Toggle Showing Desktop=Ctrl+Alt+D + +[Shortcuts] +AddBookmark=Ctrl+D +Back=Alt+Left +Close=Ctrl+F4; Ctrl+W +Copy=Ctrl+C; Ctrl+Insert +Cut=Ctrl+X; Shift+Del +DeleteWordBack=Ctrl+Backspace +DeleteWordForward=Ctrl+Del +Deselect=Ctrl+Shift+A +End=Ctrl+End +Find=Ctrl+F +FindNext=F3 +FindPrev=Shift+F3 +Forward=Alt+Right +GotoLine=Ctrl+G +Help=F1 +Home=Ctrl+Home +Insert=Ctrl+Insert +New=Ctrl+N +Next=Next +NextCompletion=Ctrl+Down +Open=Ctrl+O +Paste=Ctrl+V; Shift+Insert +PopupMenuContext=F10 +PrevCompletion=Ctrl+Up +Print=Ctrl+P +Prior=Prior +Quit= +Redo=Ctrl+Shift+Z +Reload=F5 +Replace=Ctrl+R +RotateDown=Down +RotateUp=Up +Save=Ctrl+S +SelectAll=Ctrl+A +ShowMenubar=Ctrl+M +SubstringCompletion=Ctrl+T +TextCompletion=Ctrl+E +Undo=Ctrl+Z +Up=Alt+Up +WhatsThis=Shift+F1 +ZoomIn=Ctrl++ +ZoomOut=Ctrl+- diff --git a/kcontrol/keys/schemes/old_win4.kksrc b/kcontrol/keys/schemes/old_win4.kksrc new file mode 100644 index 00000000..3859eb68 --- /dev/null +++ b/kcontrol/keys/schemes/old_win4.kksrc @@ -0,0 +1,51 @@ + +[Global Shortcuts] +Halt Computer=none +Popup Launch Menu=Ctrl+Esc +Reboot Computer=none +Show Window List=none +Toggle Showing Desktop=Meta+D; Win+M + +[Shortcuts] +AddBookmark=Ctrl+D +Back=Alt+Left +Close=Ctrl+F4; Ctrl+W +Copy=Ctrl+C; Ctrl+Insert +Cut=Ctrl+X; Shift+Del +DeleteWordBack=Ctrl+Backspace +DeleteWordForward=Ctrl+Del +Deselect=Ctrl+Shift+A +End=Ctrl+End +Find=Ctrl+F +FindNext=F3 +FindPrev=Shift+F3 +Forward=Alt+Right +GotoLine=Ctrl+G +Help=F1 +Home=Ctrl+Home +Insert=Ctrl+Insert +New=Ctrl+N +Next=Next +NextCompletion=Ctrl+Down +Open=Ctrl+O +Paste=Ctrl+V; Shift+Insert +PopupMenuContext=F10 +PrevCompletion=Ctrl+Up +Print=Ctrl+P +Prior=Prior +Quit= +Redo=Ctrl+Shift+Z +Reload=F5 +Replace=Ctrl+R +RotateDown=Down +RotateUp=Up +Save=Ctrl+S +SelectAll=Ctrl+A +ShowMenubar=Ctrl+M +SubstringCompletion=Ctrl+T +TextCompletion=Ctrl+E +Undo=Ctrl+Z +Up=Alt+Up +WhatsThis=Shift+F1 +ZoomIn=Ctrl++ +ZoomOut=Ctrl+- diff --git a/kcontrol/keys/schemes/old_wm3.kksrc b/kcontrol/keys/schemes/old_wm3.kksrc new file mode 100644 index 00000000..561ff99f --- /dev/null +++ b/kcontrol/keys/schemes/old_wm3.kksrc @@ -0,0 +1,51 @@ + +[Global Shortcuts] +Halt Computer=none +Popup Launch Menu=Alt+F1 +Reboot Computer=none +Show Window List=Alt+F5 +Toggle Showing Desktop=Ctrl+Alt+D + +[Shortcuts] +AddBookmark=Ctrl+B +Back=Alt+Left +Close=Ctrl+W +Copy=Ctrl+C; Ctrl+Insert +Cut=Ctrl+X; Shift+Del +DeleteWordBack=Ctrl+Backspace +DeleteWordForward=Ctrl+Del +Deselect=Ctrl+Shift+A +End=Ctrl+End +Find=Ctrl+F +FindNext=F3 +FindPrev=Shift+F3 +Forward=Alt+Right +GotoLine=Ctrl+G +Help=F1 +Home=Ctrl+Home +Insert=Ctrl+Insert +New=Ctrl+N +Next=Next +NextCompletion=Ctrl+Down +Open=Ctrl+O +Paste=Ctrl+V; Shift+Insert +PopupMenuContext=Menu +PrevCompletion=Ctrl+Up +Print=Ctrl+P +Prior=Prior +Quit=Ctrl+Q +Redo=Ctrl+Shift+Z +Reload=F5 +Replace=Ctrl+R +RotateDown=Down +RotateUp=Up +Save=Ctrl+S +SelectAll=Ctrl+A +ShowMenubar=Ctrl+M +SubstringCompletion=Ctrl+T +TextCompletion=Ctrl+E +Undo=Ctrl+Z +Up=Alt+Up +WhatsThis=Shift+F1 +ZoomIn=Ctrl++ +ZoomOut=Ctrl+- diff --git a/kcontrol/keys/schemes/split_kksrc b/kcontrol/keys/schemes/split_kksrc new file mode 100755 index 00000000..9fab61e4 --- /dev/null +++ b/kcontrol/keys/schemes/split_kksrc @@ -0,0 +1,111 @@ +#!/usr/bin/perl + +use strict; +use warnings; + + +foreach my $file( @ARGV ) + { + print STDERR "Working on $file\n"; + + open(my $FILEHD, $file) or do + { + print STDERR "Failed to open $file : $!"; + next; + }; + + open(my $NEWHD, ">new_$file") or do + { + print STDERR "Failed to open new_$file : $!"; + next; + }; + + open(my $OLDHD, ">old_$file") or do + { + print STDERR "Failed to open old_$file : $!"; + next; + }; + + my $process = 0; + my @kwin; + my @krunner; + my @klipper; + my @kxkb; + for( <$FILEHD> ) + { + /\[Settings\]/ and do { print $NEWHD $_; next; }; + /Name(\[[a-zA-Z_@]*\])?/ and do { print $NEWHD $_; next; }; + /Name\[x-test\]/ and do { print $NEWHD $_; next; }; + /Uses Win Modifier/ and do { print $NEWHD $_; next; }; + + /\[Global Shortcuts\]/ and do { print $OLDHD $_; $process = 1; next; }; + /\[Shortcuts\]/ and do { print $OLDHD $_; $process = 0; next; }; + + s/Alt\+Ctrl/Ctrl+Alt/; + s/Delete/Del/; + s/Escape/Esc/; + s/Win/Meta/; + + if ($process) + { + /Desktop Screenshot=/ and do { s/Desktop Screenshot=/Desktop Screenshot to Clipboard=/; push @kwin, $_; next; }; + /Kill Window=/ and do { push @kwin, $_; next; }; + /Mouse Emulation/ and do { push @kwin, $_; next; }; + /Switch to Desktop [0-9]+/ and do { push @kwin, $_; next; }; + /Switch to (Next|Previous) Desktop=/ and do { push @kwin, $_; next; }; + /Switch One Desktop / and do { push @kwin, $_; next; }; + /Toggle Window Raise\/Lower=/ and do { push @kwin, $_; next; }; + /Walk Through Desktop/ and do { push @kwin, $_; next; }; + /Walk Through Windows/ and do { push @kwin, $_; next; }; + /Window to (Next |Previous )?Desktop/ and do { push @kwin, $_; next; }; + /Window (Close|Minimize|Lower|Move|Raise|Resize|Shade)/ and do { push @kwin, $_; next; }; + /Window Maximize/ and do { push @kwin, $_; next; }; + /Window Operations Menu=/ and do { s/Window Screenshot=/Window Screenshot to Clipboard=/; push @kwin, $_; next; }; + /Window Screenshot=/ and do { s/Window Screenshot=/Window Screenshot to Clipboard=/; push @kwin, $_; next; }; + + /Switch to Next Keyboard Layout/ and do { push @kxkb, $_; next; }; + + /clipboard_action/ and do { push @klipper, $_; next; }; + /repeat_action/ and do { push @klipper, $_; next; }; + /show_klipper_popup/ and do { push @klipper, $_; next; }; + + /Halt without Confirmation/ and do { s/Halt without Confirmation/Halt Without Confirmation/; push @krunner, $_; next; }; + /Lock Session/ and do { push @krunner, $_; next; }; + /Log Out/ and do { push @krunner, $_; next; }; + /Log Out Without Confirmation/ and do { push @krunner, $_; next; }; + /Lock Session/ and do { push @krunner, $_; next; }; + /Reboot without Confirmation/ and do { s/Reboot without Confirmation/Reboot Without Confirmation/; push @krunner, $_; next; }; + /Run Command/ and do { push @krunner, $_; next; }; + /Show Taskmanager/ and do { s/Show Taskmanager/Show System Activity/; push @krunner, $_; next; }; + } + + print $OLDHD $_; + } + + print $NEWHD "\n[klipper][Global Shortcuts]\n"; + print $NEWHD sort @klipper; + print $NEWHD "\n[krunner][Global Shortcuts]\n"; + print $NEWHD sort @krunner; + print $NEWHD "\n[kwin][Global Shortcuts]\n"; + print $NEWHD sort @kwin; + print $NEWHD "\n[kxkb][Global Shortcuts]\n"; + print $NEWHD sort @kxkb; + + close($FILEHD) or do + { + print STDERR "Failed to close $file : $!"; + next; + }; + + close($NEWHD) or do + { + print STDERR "Failed to close new_$file : $!"; + next; + }; + + close($OLDHD) or do + { + print STDERR "Failed to close old_$file : $!"; + next; + }; + } diff --git a/kcontrol/keys/schemes/unix3.kksrc b/kcontrol/keys/schemes/unix3.kksrc new file mode 100644 index 00000000..1845cde7 --- /dev/null +++ b/kcontrol/keys/schemes/unix3.kksrc @@ -0,0 +1,171 @@ +[Settings] +Name=UNIX Scheme +Name[af]=UNIX Tema +Name[ar]=مخطط يونِكس +Name[ast]=Esquema UNIX +Name[be]=Схема UNIX +Name[be@latin]=Schiema „UNIX” +Name[bg]=UNIX +Name[bn]=ইউনিক্স স্কীম +Name[bn_IN]=UNIX স্কিম +Name[br]=Steuñv UNIX +Name[ca]=Esquema UNIX +Name[ca@valencia]=Esquema UNIX +Name[cs]=Unixové schéma +Name[csb]=Mòtiw Uniksa +Name[cy]=Cynllun UNIX +Name[da]=UNIX-system +Name[de]=UNIX-Design +Name[el]=Σχήμα UNIX +Name[en_GB]=UNIX Scheme +Name[eo]=Uniksa aranĝo +Name[es]=Esquema UNIX +Name[et]=UNIX-i skeem +Name[eu]=UNIX eskema +Name[fa]=طرحواره یونیکس +Name[fi]=UNIX-skeema +Name[fr]=Agencement UNIX +Name[fy]=UNIX-skema +Name[ga]=Scéim UNIX +Name[gl]=Esquema de UNIX +Name[gu]=UNIX પધ્ધતિ +Name[he]=ערכת UNIX +Name[hi]=यूनिक्स प्रसंग +Name[hne]=यूनिक्स प्रसंग +Name[hr]=UNIX shema +Name[hsb]=UNIX-šema +Name[hu]=UNIX +Name[ia]=Schema UNIX +Name[id]=Skema UNIX +Name[is]=UNIX þema +Name[it]=Schema UNIX +Name[ja]=UNIX スキーマ +Name[ka]=UNIX სქემა +Name[kk]=UNIX сұлбасы +Name[km]=គ្រោងការណ៍​យូនីក +Name[kn]=ಯುನೀಕ್ಸ್ ಪದ್ಧತಿ (ಸ್ಕೀಮ್) +Name[ko]=UNIX 배열 +Name[ku]=Şemaya UNIX'ê +Name[lt]=UNIX schema +Name[lv]=UNIX shēma +Name[mai]=यूनिक्स प्रसंग +Name[mk]=UNIX-шема +Name[ml]=യൂണിക്സ് പദ്ധതി +Name[mr]=UNIX सुत्रयोजना +Name[nb]=UNIX-oppsett +Name[nds]=UNIX-Vörbild +Name[ne]=यूनिक्स योजना +Name[nl]=UNIX-schema +Name[nn]=UNIX-oppsett +Name[or]=UNIX ଯୋଜନା +Name[pa]=UNIX ਸਕੀਮ +Name[pl]=Motyw Uniksa +Name[pt]=Esquema do UNIX +Name[pt_BR]=Esquema do UNIX +Name[ro]=Schemă UNIX +Name[ru]=UNIX +Name[se]=UNIX-čoahkkáldat +Name[si]=UNIX ක්‍රමය +Name[sk]=UNIX schéma +Name[sl]=Shema UNIX +Name[sr]=Уникс шема +Name[sr@ijekavian]=Уникс шема +Name[sr@ijekavianlatin]=Unix šema +Name[sr@latin]=Unix šema +Name[sv]=Unix schema +Name[ta]=UNIX முறைமை +Name[te]=UNIX స్కీమ్ +Name[tg]=Нақшаи UNIX +Name[th]=ใช้แบบของ UNIX +Name[tr]=UNIX Şeması +Name[uk]=Схема UNIX +Name[uz]=UNIX mavzusi +Name[uz@cyrillic]=UNIX мавзуси +Name[vi]=Phối hợp của Unix +Name[wa]=Djeu d' rascourtis Unix +Name[xh]=Udweliso lwe UNIX +Name[x-test]=xxUNIX Schemexx +Name[zh_CN]=Unix 方案 +Name[zh_TW]=UNIX 機制 +Uses Win Modifier=false + +[klipper][Global Shortcuts] +clipboard_action=none +repeat_action=Ctrl+Alt+R +show_klipper_popup=none + +[krunner][Global Shortcuts] +Halt Without Confirmation=none +Lock Session=Ctrl+Alt+L +Log Out Without Confirmation=none +Log Out=Ctrl+Alt+Del +Reboot Without Confirmation=none +Run Command=Alt+F2 +Show System Activity=Ctrl+Esc + +[kwin][Global Shortcuts] +Desktop Screenshot to Clipboard=none +Kill Window=Alt+F9 +Mouse Emulation=Alt+F12 +Switch One Desktop Down=none +Switch One Desktop Up=none +Switch One Desktop to the Left=none +Switch One Desktop to the Right=none +Switch to Desktop 10=Ctrl+F10 +Switch to Desktop 11=Ctrl+F11 +Switch to Desktop 12=Ctrl+F12 +Switch to Desktop 13=Ctrl+Shift+F1 +Switch to Desktop 14=Ctrl+Shift+F2 +Switch to Desktop 15=Ctrl+Shift+F3 +Switch to Desktop 16=Ctrl+Shift+F4 +Switch to Desktop 1=Ctrl+F1 +Switch to Desktop 2=Ctrl+F2 +Switch to Desktop 3=Ctrl+F3 +Switch to Desktop 4=Ctrl+F4 +Switch to Desktop 5=Ctrl+F5 +Switch to Desktop 6=Ctrl+F6 +Switch to Desktop 7=Ctrl+F7 +Switch to Desktop 8=Ctrl+F8 +Switch to Desktop 9=Ctrl+F9 +Switch to Next Desktop=none +Switch to Previous Desktop=none +Toggle Window Raise/Lower=none +Walk Through Desktop List (Reverse)=Ctrl+Shift+Tab +Walk Through Desktop List=none +Walk Through Desktops (Reverse)=none +Walk Through Desktops=Ctrl+Tab +Walk Through Windows (Reverse)=Alt+Shift+Tab +Walk Through Windows=Alt+F11 +Window Close=none +Window Lower=none +Window Maximize Horizontal=none +Window Maximize Vertical=none +Window Maximize=Alt+Shift+F3 +Window Minimize=Alt+F4 +Window Move=Alt+F5 +Window Operations Menu=none +Window Raise=none +Window Resize=Alt+F6 +Window Screenshot to Clipboard=none +Window Shade=none +Window to Desktop 10=none +Window to Desktop 11=none +Window to Desktop 12=none +Window to Desktop 13=none +Window to Desktop 14=none +Window to Desktop 15=none +Window to Desktop 16=none +Window to Desktop 1=none +Window to Desktop 2=none +Window to Desktop 3=none +Window to Desktop 4=none +Window to Desktop 5=none +Window to Desktop 6=none +Window to Desktop 7=none +Window to Desktop 8=none +Window to Desktop 9=none +Window to Next Desktop=none +Window to Previous Desktop=none + +[kxkb][Global Shortcuts] +Switch to Next Keyboard Layout=Ctrl+Alt+K diff --git a/kcontrol/keys/schemes/win3.kksrc b/kcontrol/keys/schemes/win3.kksrc new file mode 100644 index 00000000..e1929fb7 --- /dev/null +++ b/kcontrol/keys/schemes/win3.kksrc @@ -0,0 +1,170 @@ +[Settings] +Name=Windows Scheme (Without Win Key) +Name[af]=Venster Skema (Sonder Win Sleutel) +Name[ar]=مخطط ويندوز (بدون مفتاح Win) +Name[ast]=Esquema Windows (Ensin tecla Win) +Name[be]=Схема Windows (без клавішы "Win") +Name[be@latin]=Schiema „Windows” (biaz klavišy „Win”) +Name[bg]=Windows (без клавиша Win) +Name[bn]=উইণ্ডোস্ স্কীম (উইন্ কী ব্যতীত) +Name[br]=Steuñv Windows (hep stokell Win) +Name[ca]=Esquema Windows (sense la tecla Win) +Name[ca@valencia]=Esquema Windows (sense la tecla Win) +Name[cs]=Schéma Windows (bez klávesy Win) +Name[csb]=Mòtiw Windows (bez klawiszë Win) +Name[cy]=Cynllun Windows (Heb Allwedd Win) +Name[da]=Windows-system (uden Win-tast) +Name[de]=Windows-Design (ohne Windows-Taste) +Name[el]=Σχήμα Windows (Χωρίς πλήκτρο Win) +Name[en_GB]=Windows Scheme (Without Win Key) +Name[eo]=Vindoza aranĝo (sen Vindozoklavo) +Name[es]=Esquema Windows (Sin tecla Win) +Name[et]=Windowsi skeem (ilma Win-klahvita) +Name[eu]=Windows eskema (Win teklarik gabe) +Name[fa]=طرحواره ویندوز( بدون کلید پنجره) +Name[fi]=Windows-skeema (ilman Win-näppäintä) +Name[fr]=Agencement Windows (sans la touche « Win ») +Name[fy]=Windows-skema (sûnder Win-toets) +Name[ga]=Scéim Windows (Gan Eochair Win) +Name[gl]=Esquema de Windows (sen tecla de Windows) +Name[gu]=વિન્ડોઝ પધ્ધતિ (વિન કળ વગર) +Name[he]=ערכת חלונות (בלי מקש Win) +Name[hi]=विंडोज़ प्रसंग (विन कुंजी के बगैर) +Name[hne]=विंडोज प्रसंग (विन कुंजी के बिना) +Name[hr]=Windows shema (bez Windows tipki) +Name[hsb]=Windows-šema (bjez Win-tasty) +Name[hu]=Windows (Win billentyű nélkül) +Name[ia]=Schema Windows (Sin clave Win) +Name[id]=Skema Windows (Tanpa Tombol Win) +Name[is]=Windowsþema (án Win lykils) +Name[it]=Schema Windows (senza tasto Win) +Name[ja]=Windows スキーマ (Win キーなし) +Name[kk]=Windows сұлбасы (Win пернесіз) +Name[km]=គ្រោងការណ៍ វីនដូ (គ្មាន​គ្រាប់ចុច Win) +Name[kn]=ವಿಂಡೋಸ್ ಪದ್ಧತಿ (ವಿನ್ ಕೀಲಿ ರಹಿತ) +Name[ko]=윈도 배열 (윈도 키 사용 안함) +Name[ku]=Şemaya Windowsê (Bêyê Bişkojka Winê) +Name[lt]=Windows schema (be Win klavišo) +Name[lv]=Windows shēma (bez Win taustiņa) +Name[mai]=विंडोज प्रसंग (विन कुँजी केर बगैर) +Name[mk]=Windows-шема (без копчето Win) +Name[ml]=വിന്‍ഡോസ് പദ്ധതി (വിന്‍ കീ ഇല്ലാതെ) +Name[mr]=Windows सुत्रयोजना (विना Win किल्ली) +Name[ms]=Skim Tetingkap (Tanpa Kekunci Win) +Name[nb]=Windows-oppsett (uten Windows-tast) +Name[nds]=Windows-Schema (ahn Windows-Tast) +Name[ne]=विण्डोज योजना (विन कुञ्जी बाहेक) +Name[nl]=Windows-schema (zonder Win-toets) +Name[nn]=Windows-oppsett (utan Windows-tast) +Name[or]=ୱିଣ୍ଡୋ ଯୋଜନା (ୱିନ କି ବିନା) +Name[pa]=Windows ਸਕੀਮ (ਬਿਨਾਂ Win ਸਵਿੱਚ) +Name[pl]=Motyw Windows (bez klawisza Win) +Name[pt]=Esquema do Windows (Sem a Tecla Win) +Name[pt_BR]=Esquema do Windows (sem a tecla Win) +Name[ro]=Schemă Windows (fără tasta Win) +Name[ru]=Windows (без клавиши Win) +Name[se]=Windows-čoakkáldat (Windows-boalu haga) +Name[si]=Windows ක්‍රමය (Win යතුර නොමැතිව) +Name[sk]=Windows schéma (bez klávesu Win) +Name[sl]=Shema Windows (brez tipke Win) +Name[sr]=Виндоузова шема (без тастера Win) +Name[sr@ijekavian]=Виндоузова шема (без тастера Win) +Name[sr@ijekavianlatin]=Windowsova šema (bez tastera Win) +Name[sr@latin]=Windowsova šema (bez tastera Win) +Name[sv]=Windows schema (utan Win-tangent) +Name[ta]=சாளர முறைமை (விண் விசை இல்லாமல்) +Name[te]=Windows స్కీమ్ (విన్ కీ లేకుండా) +Name[tg]=Нақшаи Windows (Бе тугмаи Win) +Name[th]=ใช้แบบของวินโดวส์ (โดยไม่ใช้ปุ่ม Win) +Name[tr]=Windows Şeması (Win Key'siz) +Name[uk]=Схема Windows (без клавіші Win) +Name[uz]=Windows qolipi (Win tugmasi bilan) +Name[uz@cyrillic]=Windows қолипи (Win тугмаси билан) +Name[vi]=Phối hợp của Windows (không có phím Cửa sổ) +Name[wa]=Djeu Windows (sins tape Win) +Name[xh]=Window Yodweliso (Ngaphandle kwe Win key) +Name[x-test]=xxWindows Scheme (Without Win Key)xx +Name[zh_CN]=Windows 方案(无 Win 键) +Name[zh_TW]=Windows 機制(沒有 Win 鍵) +Uses Win Modifier=false + +[klipper][Global Shortcuts] +clipboard_action=none +repeat_action=none +show_klipper_popup=none + +[krunner][Global Shortcuts] +Halt Without Confirmation=none +Lock Session=none +Log Out Without Confirmation=none +Log Out=none +Reboot Without Confirmation=none +Run Command=none +Show System Activity=Ctrl+Alt+Del + +[kwin][Global Shortcuts] +Desktop Screenshot to Clipboard=Ctrl+Print +Kill Window=none +Mouse Emulation=none +Switch One Desktop Down=none +Switch One Desktop Up=none +Switch One Desktop to the Left=none +Switch One Desktop to the Right=none +Switch to Desktop 10=none +Switch to Desktop 11=none +Switch to Desktop 12=none +Switch to Desktop 13=none +Switch to Desktop 14=none +Switch to Desktop 15=none +Switch to Desktop 16=none +Switch to Desktop 1=none +Switch to Desktop 2=none +Switch to Desktop 3=none +Switch to Desktop 4=none +Switch to Desktop 5=none +Switch to Desktop 6=none +Switch to Desktop 7=none +Switch to Desktop 8=none +Switch to Desktop 9=none +Switch to Next Desktop=Alt+Shift+Tab +Switch to Previous Desktop=none +Toggle Window Raise/Lower=none +Walk Through Desktop List (Reverse)=none +Walk Through Desktop List=none +Walk Through Desktops (Reverse)=Ctrl+Alt+Shift+Tab +Walk Through Desktops=Ctrl+Alt+Tab +Walk Through Windows (Reverse)=Alt+Shift+Tab +Walk Through Windows=Alt+Tab +Window Close=Alt+F4 +Window Lower=none +Window Maximize Horizontal=none +Window Maximize Vertical=none +Window Maximize=none +Window Minimize=none +Window Move=none +Window Operations Menu=Alt+Space +Window Raise=none +Window Resize=none +Window Screenshot to Clipboard=Alt+Print +Window Shade=none +Window to Desktop 10=none +Window to Desktop 11=none +Window to Desktop 12=none +Window to Desktop 13=none +Window to Desktop 14=none +Window to Desktop 15=none +Window to Desktop 16=none +Window to Desktop 1=none +Window to Desktop 2=none +Window to Desktop 3=none +Window to Desktop 4=none +Window to Desktop 5=none +Window to Desktop 6=none +Window to Desktop 7=none +Window to Desktop 8=none +Window to Desktop 9=none +Window to Next Desktop=none +Window to Previous Desktop=none + +[kxkb][Global Shortcuts] +Switch to Next Keyboard Layout=Ctrl+Alt+K diff --git a/kcontrol/keys/schemes/win4.kksrc b/kcontrol/keys/schemes/win4.kksrc new file mode 100644 index 00000000..b28e8499 --- /dev/null +++ b/kcontrol/keys/schemes/win4.kksrc @@ -0,0 +1,170 @@ +[Settings] +Name=Windows Scheme (With Win Key) +Name[af]=Windows Skema (Met Win Sleutel) +Name[ar]=مخطط ويندوز (مع مفتاح Win) +Name[ast]=Esquema Windows (Con tecla Win) +Name[be]=Схема Windows (з клавішай "Win") +Name[be@latin]=Schiema „Windows” (z klavišaj „Win”) +Name[bg]=Windows (с клавиша Win) +Name[bn]=উইণ্ডোস্ স্কীম (উইন্ কী সমেত) +Name[br]=Steuñv Windows (gant stokell Win) +Name[ca]=Esquema Windows (amb la tecla Win) +Name[ca@valencia]=Esquema Windows (amb la tecla Win) +Name[cs]=Schéma Windows (s klávesou Win) +Name[csb]=Mòtiw Windows (z klawiszą Win) +Name[cy]=Cynllun Windows (Gyda'r Allwedd Win) +Name[da]=Windows-system (med Win-tast) +Name[de]=Windows-Design (mit Windows-Taste) +Name[el]=Σχήμα Windows (με πλήκτρο Win) +Name[en_GB]=Windows Scheme (With Win Key) +Name[eo]=Vindoza aranĝo (kun Vindozoklavo) +Name[es]=Esquema Windows (Con tecla Win) +Name[et]=Windowsi skeem (Win-klahviga) +Name[eu]=Windows eskema (Win teklarekin) +Name[fa]=طرحواره پنجره( با کلید پنجره) +Name[fi]=Windows-skeema (Win-näppäimellä) +Name[fr]=Agencement Windows (avec la touche « Win ») +Name[fy]=Windows-skema (mei Win-toets) +Name[ga]=Scéim Windows (Le hEochair Win) +Name[gl]=Esquema de Windows (con tecla de Windows) +Name[gu]=વિન્ડોઝ પધ્ધતિ (વિન કળ સાથે) +Name[he]=ערכת חלונות (עם מקש Win) +Name[hi]=विंडोज प्रसंग (विन कुंजी समेत) +Name[hne]=विंडोज प्रसंग (विन कुंजी समेत) +Name[hr]=Windows shema (s Windows tipkama) +Name[hsb]=Windows-šema (z Win-tastu) +Name[hu]=Windows (Win billentyűvel) +Name[ia]=Schema Windows (con clave Win) +Name[id]=Skema Windows (Dengan Tombol Win) +Name[is]=Windowsþema (með Win lykli) +Name[it]=Schema Windows (con tasto Win) +Name[ja]=Windows スキーマ (Win キーあり) +Name[ka]=Windows სქემა (Win კლავიშით) +Name[kk]=Windows сұлбасы (Win пернемен) +Name[km]=គ្រោងការណ៍ វីនដូ (មាន​គ្រាប់ចុច Win) +Name[kn]=ವಿಂಡೋಸ್ ಪದ್ಧತಿ (ವಿನ್ ಕೀಲಿ ಸಹಿತ) +Name[ko]=윈도 배열 (윈도 키 사용) +Name[ku]=Şemaya Windowsê (Digel Bişkojka Winê) +Name[lt]=Windows schema (su Win klavišu) +Name[lv]=Windows shēma (ar Win taustiņu) +Name[mai]=विंडोज प्रसंग (विन कुँजी समेत) +Name[mk]=Windows-шема (со копчето Win) +Name[ml]=വിന്‍ഡോസ് പദ്ധതി (വിന്‍ കീയോടൊപ്പം) +Name[mr]=Windows सुत्रयोजना (विन किल्ली सह) +Name[nb]=Windows-oppsett (med Windows-tast) +Name[nds]=Windows-Schema (mit Windows-Tast) +Name[ne]=विण्डोज योजना (विन कुञ्जीसँग) +Name[nl]=Windows-schema (met Win-toets) +Name[nn]=Windows-oppsett (med Windows-tast) +Name[or]=ୱିଣ୍ଡୋ ଯୋଜନା (ୱିନ କି ବିନା) +Name[pa]=Windows ਸਕੀਮ (Win ਸਵਿੱਚ ਨਾਲ) +Name[pl]=Motyw Windows (z klawiszem Win) +Name[pt]=Esquema do Windows (Com a Tecla Win) +Name[pt_BR]=Esquema do Windows (com a tecla Win) +Name[ro]=Schemă Windows (cu tasta Win) +Name[ru]=Windows (поддержка клавиши Win) +Name[se]=Windows-čoakkáldat (Windows-boaluin) +Name[si]=Windows ක්‍රමය (Win යතුර සමඟ) +Name[sk]=Windows schéma (s klávesom Win) +Name[sl]=Shema Windows (s tipko Win) +Name[sr]=Виндоузова шема (са тастером Win) +Name[sr@ijekavian]=Виндоузова шема (са тастером Win) +Name[sr@ijekavianlatin]=Windowsova šema (sa tasterom Win) +Name[sr@latin]=Windowsova šema (sa tasterom Win) +Name[sv]=Windows schema (med Win-tangent) +Name[ta]=சாளர முறைமை (விண் விசையுடன்) +Name[te]=విండోస్ పధకం (విన్ కీ తో) +Name[tg]=Нақшаи Windows (Бо тугмаи Win) +Name[th]=ใช้แบบของวินโดวส์ (ใช้ปุ่ม Win) +Name[tr]=Windows Şeması (Win Key İle) +Name[uk]=Схема Windows (з клавішею Win) +Name[uz]=Windows qolipi (Win tugmasiz) +Name[uz@cyrillic]=Windows қолипи (Win тугмасиз) +Name[vi]=Phối hợp của Windows (có phím Cửa sổ) +Name[wa]=Djeu Windows (avou tape Win) +Name[xh]=Windows Ezingagqibekanga (Nge Win-key) +Name[x-test]=xxWindows Scheme (With Win Key)xx +Name[zh_CN]=Windows 方案(有 Win 键) +Name[zh_TW]=Windows 機制(有 Win 鍵) +Uses Win Modifier=true + +[klipper][Global Shortcuts] +clipboard_action=none +repeat_action=none +show_klipper_popup=none + +[krunner][Global Shortcuts] +Halt Without Confirmation=none +Lock Session=none +Log Out Without Confirmation=none +Log Out=none +Reboot Without Confirmation=none +Run Command=Meta+R +Show System Activity=Ctrl+Alt+Del + +[kwin][Global Shortcuts] +Desktop Screenshot to Clipboard=Print +Kill Window=none +Mouse Emulation=none +Switch One Desktop Down=none +Switch One Desktop Up=none +Switch One Desktop to the Left=none +Switch One Desktop to the Right=none +Switch to Desktop 10=Meta+F10 +Switch to Desktop 11=none +Switch to Desktop 12=none +Switch to Desktop 13=none +Switch to Desktop 14=none +Switch to Desktop 15=none +Switch to Desktop 16=none +Switch to Desktop 1=Meta+F1 +Switch to Desktop 2=Meta+F2 +Switch to Desktop 3=Meta+F3 +Switch to Desktop 4=Meta+F4 +Switch to Desktop 5=Meta+F5 +Switch to Desktop 6=Meta+F6 +Switch to Desktop 7=Meta+F7 +Switch to Desktop 8=Meta+F8 +Switch to Desktop 9=Meta+F9 +Switch to Next Desktop=none +Switch to Previous Desktop=none +Toggle Window Raise/Lower=none +Walk Through Desktop List (Reverse)=none +Walk Through Desktop List=none +Walk Through Desktops (Reverse)=Meta+Shift+Tab +Walk Through Desktops=Meta+Tab +Walk Through Windows (Reverse)=Alt+Shift+Tab +Walk Through Windows=Alt+Tab +Window Close=Alt+F4 +Window Lower=none +Window Maximize Horizontal=none +Window Maximize Vertical=none +Window Maximize=none +Window Minimize=none +Window Move=none +Window Operations Menu=Alt+Space +Window Raise=none +Window Resize=none +Window Screenshot to Clipboard=Alt+Print +Window Shade=none +Window to Desktop 10=none +Window to Desktop 11=none +Window to Desktop 12=none +Window to Desktop 13=none +Window to Desktop 14=none +Window to Desktop 15=none +Window to Desktop 16=none +Window to Desktop 1=none +Window to Desktop 2=none +Window to Desktop 3=none +Window to Desktop 4=none +Window to Desktop 5=none +Window to Desktop 6=none +Window to Desktop 7=none +Window to Desktop 8=none +Window to Desktop 9=none +Window to Next Desktop=none +Window to Previous Desktop=none + +[kxkb][Global Shortcuts] +Switch to Next Keyboard Layout=Ctrl+Alt+K diff --git a/kcontrol/keys/schemes/wm3.kksrc b/kcontrol/keys/schemes/wm3.kksrc new file mode 100644 index 00000000..e57093fd --- /dev/null +++ b/kcontrol/keys/schemes/wm3.kksrc @@ -0,0 +1,165 @@ +[Settings] +Name=WindowMaker (3 Modifier Keys) +Name[af]=WindowMaker (3 verandering sleutels) +Name[ar]=صانع النوافذ (3 مفاتيح مغيرة) +Name[ast]=WindowMaker (3 tecles de modificación) +Name[be]=WindowMaker (тры клавішы мадыфікацыі) +Name[be@latin]=Schiema „WindowMaker” (z 3 madyfikacyjnymi klavišami) +Name[bg]=WindowMaker (с 3 модификационни клавиша) +Name[bn]=উইণ্ডো-মেকার (৩-টি মডিফায়ার কী) +Name[ca]=WindowMaker (3 tecles modificadores) +Name[ca@valencia]=WindowMaker (3 tecles modificadores) +Name[cs]=WindowMaker (3 modifikátory) +Name[csb]=WindowMaker (3 klawisze zjinaczi) +Name[cy]=WindowMaker (3 Bysell Addasu) +Name[da]=Windowmaker (3 modifikatortaster) +Name[de]=WindowMaker (3 Sondertasten) +Name[el]=WindowMaker (3 τροποποιητές) +Name[en_GB]=WindowMaker (3 Modifier Keys) +Name[eo]=WindowMaker (3 modifoklavoj) +Name[es]=WindowMaker (3 teclas de modificación) +Name[et]=WindowMaker (3 muuteklahviga) +Name[eu]=WindowMaker (3 tekla modifikatzailekin) +Name[fa]=WindowMaker (۳کلید تغییردهنده) +Name[fi]=WindowMaker (3 muokkausnäppäintä) +Name[fr]=WindowMaker (3 touches de modifications) +Name[fy]=WindowMaker (3 modifikaasjetoetsen) +Name[ga]=WindowMaker (3 Eochair Mhionathraithe) +Name[gl]=WindowMaker (3 teclas modificadoras) +Name[gu]=વિન્ડોમેકર (૩ બદલનાર કળો) +Name[he]=‏WindowMaker (עם 3 מקשים משני מצב) +Name[hi]=विंडोमेकर (3 मॉडीफ़ॉयर कुंजियाँ) +Name[hne]=विंडोमेकर (3 माडीफायर कुंजियाँ) +Name[hr]=WindowMaker (3 modifikatorske tipke) +Name[hsb]=WindowMaker (3 modifikowace tasty) +Name[hu]=WindowMaker (3 módosító billentyű) +Name[ia]=Windowmaker (3 Claves Modificator) +Name[id]=WindowMaker (3 Tombol Pengubah) +Name[is]=WindowMaker (3 breytilyklar) +Name[it]=WindowMaker (3 tasti modificatori) +Name[ja]=WindowMaker (修飾キー 3 個) +Name[ka]=WindowMaker (3 ცვლადი კლავიში) +Name[kk]=WindowMaker (3 түрлендіру перне) +Name[km]=WindowMaker (សោ​​កែប្រែ ៣) +Name[kn]=ವಿಂಡೋಮೇಕರ್ (೩ ಪರಿವರ್ತಕ ಕೀಲಿಗಳು) +Name[ko]=WindowMaker (수정자 키 세 개) +Name[ku]=WindowMaker(3 Bişkojkên Guherker) +Name[lt]=WindowMaker (3 lygio klavišai – modifikatoriai) +Name[lv]=WindowMaker (3 modifikācijas taustiņi) +Name[mai]=विंडोमेकर (3 माडीफायर कुंजीसभ) +Name[mk]=WindowMaker (3 копчиња-модификатори) +Name[ml]=വിന്‍ഡോമേക്കര്‍ (3 മോഡിഫയര്‍ കീകള്‍) +Name[mr]=चौकटमेकर (3 संपादन की) +Name[nb]=WindowMaker (tre valgtaster) +Name[nds]=WindowMaker (3 Sünnertasten) +Name[ne]=विण्डोज निर्माता (३ परिमार्जक कुञ्जी) +Name[nl]=WindowMaker (3 modificatietoetsen) +Name[nn]=WindowMaker (tre valtastar) +Name[or]=WindowMaker (3ଟି ପରିବର୍ତ୍ତକ କି) +Name[pa]=WindowMaker (3 ਸੋਧ ਸਵਿੱਚਾਂ) +Name[pl]=WindowMaker (3 klawisze modyfikatorów) +Name[pt]=WindowMaker (3 Teclas Modificadoras) +Name[pt_BR]=WindowMaker (3 teclas modificadoras) +Name[ro]=WindowMaker (3 modificatori) +Name[ru]=WindowMaker (3 клавиши-модификатора) +Name[se]=WindowMaker (golbma válljenboaluiguin) +Name[si]=කවුළු සැකසීම (3 වෙනස්කම් යතුරු) +Name[sk]=WindowMaker (3 modifikačné klávesy) +Name[sl]=WindowMaker (3 spremenilne tipke) +Name[sr]=Виндоумејкер (три модификаторска тастера) +Name[sr@ijekavian]=Виндоумејкер (три модификаторска тастера) +Name[sr@ijekavianlatin]=WindowMaker (tri modifikatorska tastera) +Name[sr@latin]=WindowMaker (tri modifikatorska tastera) +Name[sv]=Windowmaker (3 väljartangenter) +Name[ta]=WindowMaker (3 Modifier Keys) +Name[te]=విండోమేకర్ (3 సవరణి కీలు) +Name[tg]=WindowMaker (3 тугмаи якҷояшуда) +Name[th]=วินโดว์เมกเกอร์ (ใช้ปุ่มเปลี่ยนหน้าที่ 3ปุ่ม) +Name[tr]=WindowMaker (3 Değiştirici Anahtar) +Name[uk]=WindowMaker (3 клавіші-модифікатори) +Name[vi]=WindowMaker (3 Phím Bổ trợ) +Name[wa]=Djeu WindowMaker (3 tapes modifieuses) +Name[x-test]=xxWindowMaker (3 Modifier Keys)xx +Name[zh_CN]=WindowMaker (三个修饰键) +Name[zh_TW]=WindowMaker(3 個變更鍵) + +[klipper][Global Shortcuts] +clipboard_action=Ctrl+Alt+X +repeat_action=Ctrl+Alt+R +show_klipper_popup=Ctrl+Alt+V + +[krunner][Global Shortcuts] +Halt Without Confirmation=none +Lock Session=Ctrl+Alt+L +Log Out Without Confirmation=none +Log Out=Ctrl+Alt+Del +Reboot Without Confirmation=none +Run Command=Alt+F2 +Show System Activity=Ctrl+Esc + +[kwin][Global Shortcuts] +Desktop Screenshot to Clipboard=Ctrl+Print +Kill Window=Ctrl+Alt+Esc +Mouse Emulation=Alt+F12 +Switch One Desktop Down=none +Switch One Desktop Up=none +Switch One Desktop to the Left=none +Switch One Desktop to the Right=none +Switch to Desktop 10=Alt+Shift+1 +Switch to Desktop 11=Alt+Shift+2 +Switch to Desktop 12=Alt+Shift+3 +Switch to Desktop 13=Alt+Shift+4 +Switch to Desktop 14=Alt+Shift+5 +Switch to Desktop 15=Alt+Shift+6 +Switch to Desktop 16=Alt+Shift+7 +Switch to Desktop 1=Alt+1 +Switch to Desktop 2=Alt+2 +Switch to Desktop 3=Alt+3 +Switch to Desktop 4=Alt+4 +Switch to Desktop 5=Alt+5 +Switch to Desktop 6=Alt+6 +Switch to Desktop 7=Alt+7 +Switch to Desktop 8=Alt+8 +Switch to Desktop 9=Alt+9 +Switch to Next Desktop=none +Switch to Previous Desktop=none +Toggle Window Raise/Lower=none +Walk Through Desktop List (Reverse)=Ctrl+Shift+Tab +Walk Through Desktop List=Ctrl+Tab +Walk Through Desktops (Reverse)=none +Walk Through Desktops=none +Walk Through Windows (Reverse)=Alt+Shift+Tab +Walk Through Windows=Alt+Tab +Window Close=Alt+Esc +Window Lower=none +Window Maximize Horizontal=none +Window Maximize Vertical=none +Window Maximize=none +Window Minimize=none +Window Move=none +Window Operations Menu=Alt+F3 +Window Raise=none +Window Resize=none +Window Screenshot to Clipboard=Alt+Print +Window Shade=none +Window to Desktop 10=Ctrl+Alt+Shift+1 +Window to Desktop 11=Ctrl+Alt+Shift+2 +Window to Desktop 12=Ctrl+Alt+Shift+3 +Window to Desktop 13=Ctrl+Alt+Shift+4 +Window to Desktop 14=Ctrl+Alt+Shift+5 +Window to Desktop 15=Ctrl+Alt+Shift+6 +Window to Desktop 16=Ctrl+Alt+Shift+7 +Window to Desktop 1=Ctrl+Alt+1 +Window to Desktop 2=Ctrl+Alt+2 +Window to Desktop 3=Ctrl+Alt+3 +Window to Desktop 4=Ctrl+Alt+4 +Window to Desktop 5=Ctrl+Alt+5 +Window to Desktop 6=Ctrl+Alt+6 +Window to Desktop 7=Ctrl+Alt+7 +Window to Desktop 8=Ctrl+Alt+8 +Window to Desktop 9=Ctrl+Alt+9 +Window to Next Desktop=none +Window to Previous Desktop=none + +[kxkb][Global Shortcuts] +Switch to Next Keyboard Layout=Ctrl+Alt+K diff --git a/kcontrol/keys/select_scheme_dialog.cpp b/kcontrol/keys/select_scheme_dialog.cpp new file mode 100644 index 00000000..e3720716 --- /dev/null +++ b/kcontrol/keys/select_scheme_dialog.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2008 Michael Jansen + * + * 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 "select_scheme_dialog.h" +#include "ui_select_scheme_dialog.h" + + +#include "KDialog" +#include "KStandardDirs" +#include + +SelectSchemeDialog::SelectSchemeDialog(QWidget *parent) + : KDialog(parent), + ui(new Ui::SelectSchemeDialog) +{ + m_schemes = KGlobal::dirs()->findAllResources("data", "kcmkeys/*.kksrc"); + + ui->setupUi(this); + setMainWidget(ui->layoutWidget); + + foreach (const QString &res, m_schemes) { + KConfig config(res, KConfig::SimpleConfig); + KConfigGroup group(&config, "Settings"); + QString name = group.readEntry("Name"); + + if (name.isEmpty()) { + name = res; + } + ui->m_schemes->addItem(name); + } + + ui->m_schemes->setCurrentIndex(-1); + + ui->m_url->setMode(KFile::LocalOnly | KFile::ExistingOnly); + + connect(ui->m_schemes, SIGNAL(activated(int)), + this, SLOT(schemeActivated(int))); + connect(ui->m_url->lineEdit(), SIGNAL(textChanged(QString)), + this, SLOT(slotUrlChanged(QString))); + enableButtonOk(false); +} + + +SelectSchemeDialog::~SelectSchemeDialog() +{ + delete ui; +} + +void SelectSchemeDialog::schemeActivated(int index) +{ + ui->m_url->setUrl(m_schemes[index]); +} + + +KUrl SelectSchemeDialog::selectedScheme() const +{ + return ui->m_url->url(); +} + +void SelectSchemeDialog::slotUrlChanged(const QString &_text) +{ + enableButtonOk(!_text.isEmpty()); +} + +#include "moc_select_scheme_dialog.cpp" diff --git a/kcontrol/keys/select_scheme_dialog.h b/kcontrol/keys/select_scheme_dialog.h new file mode 100644 index 00000000..9d96a842 --- /dev/null +++ b/kcontrol/keys/select_scheme_dialog.h @@ -0,0 +1,48 @@ +/* + * Copyright 2008 Michael Jansen + * + * 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 SELECT_SCHEME_DIALOG_H +#define SELECT_SCHEME_DIALOG_H + +#include "KDialog" + +namespace Ui +{ +class SelectSchemeDialog; +} + +class SelectSchemeDialog : public KDialog +{ + Q_OBJECT +public: + SelectSchemeDialog(QWidget *parent = 0); + ~SelectSchemeDialog(); + + KUrl selectedScheme() const; + +private slots: + void schemeActivated(int index); + void slotUrlChanged(const QString &); + +private: + Ui::SelectSchemeDialog *ui; + QStringList m_schemes; +}; // SelectSchemeDialog + + + +#endif diff --git a/kcontrol/keys/select_scheme_dialog.ui b/kcontrol/keys/select_scheme_dialog.ui new file mode 100644 index 00000000..0803ad5d --- /dev/null +++ b/kcontrol/keys/select_scheme_dialog.ui @@ -0,0 +1,150 @@ + + + Michael Jansen + SelectSchemeDialog + + + + 0 + 0 + 717 + 224 + + + + Select Shortcut Scheme + + + true + + + + + 32 + 12 + 671 + 71 + + + + + + + + 0 + 50 + + + + Select one of the standard KDE shortcut schemes + + + &Standard scheme: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_schemes + + + + + + + + 0 + 0 + + + + + 0 + 50 + + + + true + + + + + + + + 150 + 0 + + + + + 1 + 0 + + + + + 0 + 50 + + + + Select a shortcut scheme file + + + &Path: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_url + + + + + + + + 3 + 0 + + + + + 0 + 50 + + + + *.kksrc + + + Select Shortcut Scheme + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KDialog + QDialog +
kdialog.h
+ 1 +
+ + KUrlRequester + QFrame +
kurlrequester.h
+
+
+ + +
diff --git a/kcontrol/kfontinst/AUTHORS b/kcontrol/kfontinst/AUTHORS new file mode 100644 index 00000000..afabc4a8 --- /dev/null +++ b/kcontrol/kfontinst/AUTHORS @@ -0,0 +1 @@ +Craig Drummond diff --git a/kcontrol/kfontinst/CMakeLists.txt b/kcontrol/kfontinst/CMakeLists.txt new file mode 100644 index 00000000..1ba461cf --- /dev/null +++ b/kcontrol/kfontinst/CMakeLists.txt @@ -0,0 +1,51 @@ +if (KFI_BUILD_STANDALONE) + cmake_minimum_required(VERSION 2.6.4) + find_package(KDE4 "4.6.0" REQUIRED) + find_package(Qt4 REQUIRED) + find_package(Freetype REQUIRED) + find_package(Fontconfig REQUIRED) + find_package(Strigi REQUIRED) + find_package(X11 REQUIRED) + macro_log_feature(X11_Xft_FOUND "libxft" "X FreeType interface library" "http://www.x.org" FALSE "" "Font installer and font previews") + include(KDE4Defaults) +endif (KFI_BUILD_STANDALONE) + +if (X11_Xft_FOUND) + check_include_files(locale.h HAVE_LOCALE_H) + configure_file(config-fontinst.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-fontinst.h) + include_directories( + ${KDE4_INCLUDES} + ${FREETYPE_INCLUDE_DIRS} + ${FONTCONFIG_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/lib + ${CMAKE_CURRENT_BINARY_DIR}/lib + ${CMAKE_CURRENT_SOURCE_DIR}/dbus + ${CMAKE_CURRENT_BINARY_DIR}/dbus + ${CMAKE_CURRENT_SOURCE_DIR}/viewpart + ${CMAKE_CURRENT_SOURCE_DIR}/kcmfontinst + ${CMAKE_CURRENT_BINARY_DIR}/kcmfontinst) + add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) + + set(libkfontinstdbusiface_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/dbus/FontinstIface.cpp) + set(libkfontinstview_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/viewpart/FontPreview.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/viewpart/PreviewSelectAction.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/viewpart/CharTip.cpp ) + set(libkfontinstactionlabel_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/kcmfontinst/ActionLabel.cpp) + set(libkfontinstjobrunner_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/kcmfontinst/JobRunner.cpp + ${libkfontinstactionlabel_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/kcmfontinst/FontsPackage.cpp) + + add_subdirectory( lib ) + add_subdirectory( dbus ) + add_subdirectory( kcmfontinst ) + add_subdirectory( strigi-analyzer ) + add_subdirectory( apps ) + add_subdirectory( kio ) + add_subdirectory( thumbnail ) + add_subdirectory( viewpart ) + + kde4_install_icons( ${ICON_INSTALL_DIR} ) + +endif (X11_Xft_FOUND) diff --git a/kcontrol/kfontinst/ChangeLog b/kcontrol/kfontinst/ChangeLog new file mode 100644 index 00000000..fe87b58a --- /dev/null +++ b/kcontrol/kfontinst/ChangeLog @@ -0,0 +1,562 @@ +KDE4.4 +====== +1. Create a dbus daemon for handling font installtion, and have the kcm and ioslave + use this. +2. Use policykit to control installation of system-wide fonts. +3. Merged progress, skip, cancel, and error dialogs used when installing, etc., into + 1 dialog. +4. Simplify layout. +5. Remove simple mode - always use font management mode. +6. When multiple fonts are selected, use a list style preview of all selected fonts. +7. Because of the above, remove the in-line previews from the font list. + +KDE4.3 +====== +1. Dont cache previews to disk. + +KDE4.2 +====== +1. Added zoom controls to font preview. +2. Made viewer application a KUniqueApplication + +KDE3.5 -> KDE4.0 +================ + 1. Enabling/disabling of fonts. + 2. Creation of "Font Groups" + 3. Fonts are now grouped via family name, i.e. shown as: + + Courier [4] + - Times [2] + Regular + Italic + ...where the number in brackets indicates the number of styles. Clicking + on the expand icon (+) will then show the list of styles. + 4. Add ability in font view part to show unicode tables. + 5. Remove all references to Speedo fonts - haven't been supported since + KDE3.3! + 6. Only one view - list view. However, each item now has a small preview. + 7. Xft is now required. + 8. Remove Fontmap creation. + 9. Creation of fonts.dir & fonts.scale will be done via mkfontscale and + mkfontdir. +10. Legacy X is only configured for a folder if it already contains a fonts.dir + file. +11. Font installtion is *much* faster - as config files are now updated after + all fonts are installed, as opposed to every 50 fonts. +12. Folders are no longer added to X's config files - because of 10 above. + The only system config file that will be altered is either + /etc/fonts/local.conf or /etc/fonts/conf.d/00kde.conf (dependant upon + your fontconfig version) +13. When installing font files, install into a sub folder named after the 1st + character. e.g. + wibble.ttf -> ~/.fonts/w/wibble.ttf +14. Better unique names when creating font packages. +15. Use zip and not tar.gz for font packages. +16. Allow import of fonts/package. +17. Allow fonts/package to be installed via konqueror service menu. +18. Better TTC handling. +19. When installing to fonts:/, as non-root, automatically install to fonts:/Personal. + To install to fonts:/System need to explicity copy to fonts:/System. +20. Hide kfontview from KMenu - its only required by kcm, and when cliking on a font. +21. Renamed kcmfontinst to just fontinst. +22. When printing, use external kfontprint app - that way newly installed fonts can + also be printed. +23. When run as non-root, the kcontrol module will have a combo box allowing the user + to select Personal or System fonts. +24. Better bitmap font previews - list of sizes obtained via fontconfig. +25. Regular fonts listed as fonts:/, Regular - e.g. fonts:/Times, Regular +26. Use a kio_font_helper app when accesing fonts:/System - much faster, as kdesu is + not required to be called for each action. +27. Add a "Find Duplicates" tool, that looks for multiple installtions of the same font. + i.e. different locations, or the same location but different filename case + (e.g. times.ttf / times.TTF) + +KDE3.4 -> KDE3.5 +================ +1. When copying a file out of fonts sub-system, copy as filename, or .fonts.tar.gz + in the case of multiple font files mapped to the same font name. + + e.g. Times New Roman -> times.ttf + Helvetica, Bold Oblique-> Hevetica, Bold Oblique.fonts.tar.gz + Which contains: + 75dpi_helvBO10.pcf.gz + 75dpi_helvBO12.pcf.gz + 100dpi_helvBO10.pcf.gz + 100dpi_helvBO12.pcf.gz + ...etc + +2. New mimetype: fonts/package - to cater for the above. +3. Add settings to enable/disable configuring fonts for legacy X, and Ghostscript + (X defaults to true, and Ghostscript defaults to false) +4. Show mime-type in detailed view. +5. Simple font sample printing - but only of installed fonts! +6. Add toggle button to control display of bitmap fonts. + +KDE3.3 -> KDE3.4 +================ +1. Font listing comes from fontconfig. This means that fonts will be grouped, i.e. + previously each size of a bitmap font was shown seperately, now only 1 font + will be displayed which represents all sizes. +2. Only fonts, and not folders (except System and Personal), are now shown. +3. Creation of afms from pfa/pfb and a pfm file. +4. Previews are drawn via Xft - previously FreeType was called directly. +5. New font preview look. +6. No longer dependant upon file extension. +7. Check for FPE of "fontconfig" -> if set, then no need to configure X core fonts. + +KDE3.2 -> KDE3.3 +================ +1. List fonts as "Full Name" -> i.e. "Times New Roman". +2. Preview of bitmap fonts. +3. No fontname-title in thumbnails - as fonts:/ lists the fontnames! +4. When copying to fonts:/ (as non-root) only ask for destination if more than 5 seconds + since previously asked. +5. Add a konqueror service menu "Install" +6. Use FreeType2 for reading Type1 - instead of parsing the pfa/pfb header. +7. FamilyName is now the fonts *real* family name - no adding of style information. +8. Add extra style information (which was previously added to FamilyName) into the XLFD. +9. Consider regular weight to be medium (same as mkfontscale). +10. Default to width=normal, weight=medium if not set. +11. Allow change of preview string. +12. Allow zooming in/out of preview. +13. Waterfall font preview. +14. Use font preview part in the KControl module - less code duplication. +15. Include simple fontviwer app - basically just an application wrapper for the viewpart. + +KDE3.1 -> KDE3.2 +================ +1. Re-designed (yet again...) to be a kio slave. As a user, starting fonts:/ will display + + Personal Lists contents of $HOME/.fonts and $KDEHOME/share/fonts (where previous installer installed to) + Fonts are installed to $HOME/.fonts + + System Lists contents of /usr/local/share/fonts, /usr/share/fonts, and /usr/X11R6/lib/X11/fonts + Fonts are installed to /usr/local/share/fonts (as per FHS) + + To install fonts system wide, just drop onto "System" and root's password will be asked + for. + + As root, fonts:/ will show the same as fonts:/System (but without the System part...) + +2. New kcontrol module that uses fonts:/ +3. Removed: + AFM creation -- only really required (TTF wise) for SO <6.0 + StarOffice configuration (S0 6.0 / OO.o is *much* better anyway) +4. X font server (xfs) - if used - is refreshed by sending a SIGUSR1 instead of + relying on a /etc/init.d/xfs script. This is much more portable. +5. Simple FontView part for konqueror - this is basically a big re-sizable preview of the font. +6. Speed up creation of fonts.dir and fonts.scale - by reading in any existing files, and using the + entries from these instead of loading and testing the font (if listed). +7. Better font preview and thumbnails. +8. Only add a dir to fontpath if fonts.dir has greater than 0 entries! +9. Use /etc/fonts/local.conf as root fontconfig file. +10. Only add dirs to fontconfig if *not* a sub-dir of an existing dir. +11. Ensure that top-level fonts dir is always in fontpath. +12. A Fontmap file is created in each sub dir, which is then combined into 1 top level Fontmap file. + ~/.fonts/Fontmap for normal users, and /etc/fonts/Fontmap for root. +13. Modify /Fontmap to contain: + (/etc/fonts/Fontmap) .runlibfile + ...as this is the system-wide Fontmap file created. As for the per-user, one, hmmm... +14. When a folder is configured, ensure fonts.dir/fonts.scale/Fontmap/.fonts-config-timestamp (SuSE + specific) all have the same timestamp (if they exist). Helps to discover if a folder has been + modified - in which case it needs to be reconfigured (and should happen automatically). +15. Add support for TrueType Collections (.ttc), and OpenType (.otf) fonts. Currently TTC's are only + configured for X - need to also configure GS to see other faces. +16. CID fonts are *not* handled - therefore don't list the X11 CID directory, and don't let users + try to create this. +17. Don't list "encodings" in fonts:/System - and don't allow users to create this. +18. Use XFree86's libfontenc (if found) to read font-encodings. +19. Handle 1bpp glyphs in thumbnail code. +20. Ensure X fontpaths *never* end in "/" - i.e. when write XF86Config, xfs/config, + or fontpaths remove any trailing "/" +21. When adding/removing an unscaled dir from X font path, ensure ":unscaled" is + part of the path! +22. Call fc-cache on top-level dir, not on each dir. +23. Use "~" in Xft config and user X config files -> e.g. /home/user/.fonts -> ~/.fonts +24. Remove top-level dir spec from top-level fontmap, e.g. + + TimesNewRomanPSMT (/home/user/.fonts/wibble/times.ttf); + + ...becomes... + + TimesNewRomanPSMT (wibble/times.ttf); + +25. Add meta-data for AFM files to KFile plugin. + +0.11-> KDE3.1 +============= +1. Re-design of UI - removed "Install From" view. +2. Created a KIO/thumbnail font preview class. +3. Fonts are installed/uninstalled on "Apply". +4. Settings are saved on "Apply". +5. Settings tab simplified - some uneccesary settings removed. +6. Removal of Anti-Alias tab - relevant settings moved to kcmfonts. +7. Add kfile-plugin to display Meta data for fonts. +8. Remove settings wizard. +9. Drop use of internal version numbering - not tagging CVS anyway, so whats the point? +10. DCOP interface. +11. Remember size of main window when run via kcmshell. + +0.10->0.11 (KDE3.0) +=================== +1. Port to KDE3/Qt3. +2. Add support for CUPS's Fontmap. +3. Create backups of system files. +4. When install symbol encoding fonts, set encoding to "glyphs-fontspecific" in XftConfig. +5. When install monospaced fonts, set spacing to mono in XftConfig. +6. When first run (as root) - checks XFree86 config file to see if a font server is being used, if + so then fs/config is used as the config file, and "/etc/rc.d/init.d/xfs restart" is selected as + as the X refresh command. +7. Only install fonts that are useable. +8. Add checkbox to enable overwriting of existing AFMs. +9. Remember open directories in advanced mode. +10. Add support for .Z compressed Bitmap fonts. +11. Read Type1 encodings from .afm files if listed as "array" in pfa/pfb. + +0.10b11->0.10 +============= +1. Version added to KDE CVS. +2. Modified some keyboard shortcuts to remove conflicts. +3. Disable "Touch" and "Delete" folder if top-level X fonts dir is selected. + +0.10b10->0.10b11 (Test version...) +================ +1. Removed "root"/"Modify" and "Help" buttons - this gives more space to font lists, plus when using "root"/"Modify" root's + config files are not being saved. +2. "IsFixedPitch" flag in AFMs produced incorrectly - was outputing "false" for monospaced fonts! +3. Added rounding to AFM metric scaling. +4. When creating AFMs, check that each characters' BBox is within the main BBox - this is a quick fix for wingdings.afm, + which seems to be giving incorrect results. +5. StarOffice 6 / OpenOffice only need AFM files for Type1 fonts - plus no config files need to be altered. Therefore, added the ability to + select which font types AFMs should be created for. +6. Output *all* characters from a font into the AFM file. +7. Fixed a bug with Full/Family name in Speedo fonts. +8. For TrueType, Type1, and Speedo fonts - family name is obtained by using the fonts' FullName, remove FamilyName (read from file), remove + any weight, width, or italic designation, and re-add FamilyName. (This is because some fonts are named + , and was previously being lost). +9. When adding encodings to lists, check that they aren't alredy inserted. + +0.10b9->0.10b10 (Test version...) +=============== +1. Fixed a problem with non-enabled install button in basic mode - again, thanks to Hardy Griech for spotting this. + +0.10b8->0.10b9 (Test version...) +============== + +*** NOTE +*** Please remove any Kfontinst generated StarOffice psstd.fonts and Ghostscript Fontmap output before using this version + +1. StarOffice psstd.fonts generated output is no longer marked line-by line, instead it is marked as a section, e.g. + + # kfontinst /usr/X11R6/lib/X11/fonts/TrueType + + # kfontinst /usr/X11R6/lib/X11/fonts/TrueType + + ...Likewise for Ghostscript's Fontmap + +2. Limited generated StarOffice psstd.fonts lines to 126 characters, and lines longher than this will not be output. It appears + as if this is the max line len StarOffice will accept - thanks to Hardy Griech for discovering this. +3. Fixed a bug where a static pointer was not reset to NULL when module was unloaded. +4. When chekcing ps-fonts, I was looking for the string "%!PS-Adbobe", however the hershey fonts just has "%!FontType" - therefore + I've change the code to just look for "%!" +5. For pcf fonts, look for FAMILY as well as FAMILY_NAME +6. Construct name from xlfd for bitmap fonts where can't get seperate components + +0.10b7->0.10b8 (Test version...) +============== + +*** NOTE +*** Please remove any Kfontinst generated Ghostscript and/or StarOffice output before using this version + +1. Forgot to extract foundry from bitmap fonts - however, changed bitmap Xlfd creation, see below. +2. Extract Xlfd from Bitmap fonts directly - not all fonts have each seperate component available. Thanks to Claudio Bandaloukas + for helping me discover the various bugs with Bitmap output. +3. When displaying bitmap details, if individual entries (family, point size, etc) can't be read, then the + Xlfd will be displayed. +4. Ghostscript & StarOffice include guards changed from "kfontinst" to "kfi" -- this will *require" removing of any previous output! +5. Shortened generated TrueType foundry fields - to help with StarOffice + +0.10b6->0.10b7 (Test version...) +============== +1. Fixed a bug with string-to-width conversion for Type1 and bitmap fonts +2. Fixed some compile bugs if no Xft.h found +3. Remove any fonts.alias when deleting a dir +4. When try to open Type1 or Speedo fonts, check magic numbers - for Speedo check char[0]=='D' or 'd', char[1]==num, char[2]=='.', and char[3]==num + +0.10b5->0.10b6 (Test version...) +============== +1. Fonts with "Normal" weight now installed as "Medium" +2. Added support for "Oblique" in xlfd +3. Check is performed to see if destination is writeable before enabling "Install" button, likewise for the "Remove" button. + +0.10b4->0.10b5 (Test version...) +============== +1. Forgot to reset the made-changes state of XftConfig when saved! +2. Add a validator to math & edit line-edits to disallow usage of double-quotes & tabs +3. Select correct default entries for field-name combos when adding an XftRule. +4. Removed check for number of items in match list, as these are not always required (such as for the sub-pixel hinting + rule.) +5. When setting rgba - use symbolic name - previously always setting to 0! +6. Modified help a little +7. Reduced Advanced mode list-view treeStepSize to 10 pixels (from default of 20), this makes it easier for browsing + /usr/X11R6/lib/X11/fonts/etc... +8. Fixed bug where could not remove Xft exclude range! +9. Fixed a bug where uninstalled items could cause duplicates in "Install from" list. +10. Renamed the "Configure System" button to "Apply" - this should make the neccessity of the option more obvious. +11. Fixed display of uninstall folder. +12. Added "include" and "includeif" directives from XftConfig to editor. + +0.10b3->0.10b4 (Test version...) +============== + +*** NOTE +*** Please delete your existing ~/.kde/share/config/kfontinstrc -or- ~/.kde2/share/config/kfontinstrc file +*** before using this version + +1. Added support for X font server config files. +2. Show "unscaled" directories in italic. +3. Abilty to set directories as scaled/unscaled. +4. Modified GUI slightly so that it works beter with Liquid style. +5. Added chack to make sure XftConfig file exists before trying to parse. +6. Advanced editing of XftConfig. +7. Added help on XftConfig - from Danny Tholen (obiwan@mailmij.org) +8. Removed some memory leaks +10. Default folders changed for non-root users. KFontinst will now (upon initial start-up) select the following: + + X fonts dir: $KDEHOME/share/fonts + XConfig file: $KDEHOME/share/fonts/fontpaths + XftConfig file: $HOME/.xftconfig + Fontmap file: $KDEHOME/share/fonts/Fontmap + + ...This should make it possible for users to install fonts without being root. However, problems may arrise when + configuring StarOffice - as this requires some other files to be modified, which won't be possible if SO has been installed + by root. + + ...Also to accomplish this, some changes are needed to 'startkde' - see file README.startkde + +11. Because of the above, when started as non-root, KFontinst will create Type1 and TrueType sub-folders in + $KDEHOME/share/fonts - if they do not already exist. +12. Moved XftConfig stuff from a sub-page of settings tab into its own tab. +13. Added question dialog if module is unloaded before system has been configured. +14. Added ability to "touch" a X font folder - marking it as being modified, so that a re-configure of the that folder + can be done in order to create AFMs, modify encoding, etc. + +0.10b2->0.10b3 (Test version...) +============== +1. When locating Ghostscript's Fontmap file, sub-directories (up to a level of 4) are searched - this allows + for the possiblity of users using a different version of Ghostscript. +2. Create a fonts.scale as well as fonts.dir - just incase another program runs mkfontdir. +3. Fixed an error when creating AFMs for some symbol-encoded fonts. +4. Re-worded SettingsWizard "Folders/Files" tab. +5. Added a checkbox to Ghostscript configuration. +6. Added support for XftConfig. +7. Added/fixed support of Type1 fonts with no FullName or FamilyName fields - such as the hershey fonts. +8. Fixed some bugs when configuring with --enable-final. +9. Basic html help added. + +0.10b1->0.10b2 (Test version...) +============== +1. Minor compile error (struct declared as private, but used elsewhere!) + +0.9.2->0.10b1 (Test version...) +============= +1. Almost a complete re-write, +2. Handles Speedo, and Bitmap fonts +3. fonts.dir & encodings.dir are now created internally - no need for ttmkfdir +4. Re-design of GUI. +5. Advanced mode where X11 folder structure is displayed and all font types may be installed - and a Basic + mode where the X11 folder structure is hidden, and only TrueType and Type1 fonts may be installed. +6. Settings wizard. +7. Application is now a kcontrol module. +8. Complete X11 fonts directory structure is now managed - no need for seperate 'Managed' directory. +9. X11.PS is no longer created, instead the StarOffice printer file (*.PS) is now modified. +10. Ported to FreeType2. +11. Support more encodings - encodings combos now list standard encodings as well as those read from + .enc(.gz) files. +12. Internal AMF creator for Type1 and TrueType fonts - ttf2pt1 and pf2afm.ps are no longer used/supplied. +13. Removed the 'Process AFMs' & 'Delete AFMs' options - all AFMs are created be KFontinst, therefore they + should be OK for StarOffice and AbiWord. +14. If a writable XF86Config file is found - then complete folders may be installed, and folders in the X11 + directory may be uninstalled or disabled (i.e. the folder is not deleted, but it's entry is removed from + the XF86Config file). +15. No longer supply .enc files with KFontinst - they should be provided by the distro. + +0.9.1->0.9.2 +============ +1. Removed a bug where the "Configure System" menu entry was always disabled! +2. Spelling error in Settings dialog. +3. t1lib has problems with some of the fonts supplied with Adobe acrobat - therefore, if t1lib fails to load the + font, then KFontinst itself will try to read the header information (although no preview will be available, + everything else should still work). +4. Fixed multiple installing of programs in other/ directory. For instance KFontinst's version of ttmkfdir + was being installed into $(PREFIX) (usually /usr/bin) as well as $(KDE_DATADIR)/kfontinst - this was incorrect + as KFontinst will only use the version in $(KDE_DATADIR)/kfontinst, and it was possible that a previous version + of ttmkfdir (such as that supplied with XFree86) would have been overwritten. +5. Fixed bug where the user was allowed to select (and subsequently install) fonts which could not be loaded correctly. +6. Added the ability to enter a custom preview string. + +0.9->0.9.1 +========== +1. Fixed a few compile errors. +2. Fix to html formatting error. +3. Fixed a ./configure error if t1lib was not found (the string NO was being used as the + librarary name, instead of an empty string!) +4. Modified the reading of Type1 header information. + +0.8.3->0.9 +========== +1. Converted to KDE2. +2. Rearranged this file! +3. Removed command line interface - KDE2's command line stuff is way different! +4. Re-created dialogs with Qt designer. +5. Removed ProgressDialog, and replaced with a progress bar on a new statusbar. +6. Modified configure script to check for FreeType & t1lib. +7. If an encoding (not unicode) is selected, then the .enc file is copied to the X11 fonts directory. +8. As with the .enc files, the StarOffice .xpp files are also copied, and no longer just sym linked. +9. Removed enabling/disabing of Configure System button. +10. Fontmap.X11 is no longer created, instead the real Fontmap file itself is modified. + +0.8.2->0.8.3 +============ +1. Modified 'kfontinst.kdelnk' so that kdesu is now used - so that a user will automatically be prompted + for the root password. +2. Modified dialogs to use the KDE caption ("Font Installer") instead of the app name ("kfontinst") +3. Corrected size of Configure dialog. +4. Fixed a minor bug where if all fonts were uninstalled, the 'Configure System' button was disabled - therefore not + allowing you to activate the changes! +5. Added a command line interface. (type 'kfontinst --help' for details) +6. Added option to automatically fix TTF postscript names upon install. + +0.8.1->0.8.2 +============ +1. Fixed a bug which always had SO configuration disabled! +2. Fixed a bug when selecting Unicode encoding. +3. Changed "Fonts/Uninstalled" menu entry to "Fonts/Disk" +4. Added keyboard short-cuts to dialogs + +0.8->0.8.1 +========== +1. Fixed a bug where X configuration would fail if no TT fonts present. +2. If no fonts are installed, then the system configuration button/menu-entry is now disabled. +3. Changed menu structure to add 'Fonts' menu. + +0.7.4->0.8 +========== +1. Changed location of StarOffice stuf from /xp3 to just + -- As StarOffice 5.2 has 'xp3' within a 'share' sub-dir. +2. Changed structure of config file to be more modular. +3. Modified internal code structure to allow easier additon of extra apps to be configured. (NOTE: If any + apps need to be configured, then I'll also [later on] modify the Settings & Configure dialogs to + accomodate these.) +4. Because of 3, added a 'StarOffice' check to the settings dialog. If this is not seleted, then no check + is performed to make sure the SO dir is OK - and the option to config SO is diabled on the config dialog. +5. Added check when installing font to make sure that it's not already installed. + +0.7.3->0.7.4 +============ +1. Changed location of Fontmap.X11 -- from /lib/Fontmap.X11 to + /Fontmap.X11. As it seems some ghostscript installations don't + have the 'lib' sub directory. +2. Improved the documentation a little - added a FAQ section + +0.7.2->0.7.3 +============ +1. Very minor bug fix. + +0.7.1->0.7.2 +============ +1. Added more detailed error messages when system configuration fails. + +0.7->0.7.1 +========== +1. Removed lots of debug info from ttf2pt1, and afm.pl -- this should drastically speed up afm creation. +2. Modified ttf2pt1 to accept a parameter to just create .afm files +3. Added option to modify a .afm file when installing. +4. Added "Unicode" to list of encodings that can be used. +5. Removed kfontinst-cp1252.enc, kfontinst-cp1252.xpp -- these were hacks anyway, and seing as Qt2 is going to + support cp1252 by a hard-coded codec, there's no real point... +6. Rearranged the Configure System dialog - so that Force AFM regeneration is grouped next to the Generate AFMs option. +7. Encoding files now stored in /share/apps/kfontinst/Encodings + +0.6.1->0.7 +========== +1. Modified ttmkfdir & ttf2pt1 to allow usage of X11 style font re-encoding files. +2. Because .enc files are now used by kfontinst, removed the possibility of using gzipped encodings. +3. Added the ability to delete an installed font's .afm file. +4. Fixed a bug in the TtfPsNameFixer class - this would cause ttf2pt1 to creash when accessing a modified font! +5. Font encodings are now stored in /share/x11encodings +6. Removed the reencode shell script, as the encodng is all done by ttmkfdir. +7. Removed xfinst shell script - handled internally. +8. Supplied a kfontinst-cp1252 encoding - with the ugly single-quotes normaly found in .ttf files remapped to + the nice looking ones. +9. Added functionality, when configuring StarOffice, to select an appropriate xprinter.prolog for the selected + encoding (if one exists)... + +0.6->0.6.1 +========== +1. Fixed a display bug in the 'Un/Exclude from StarOffice" options. + +0.5->0.6 +======== +1. Added the ability to 'fix' the postscript names in a ttf file. +2. Fixed some missing changes to help files. + +0.4->0.5 +======== +1. Discovered a patch that modifies StarOffice's xprinter.prolog so that font's don't need to be modified + to use the microsoft cp1252 enocding scheme. (Previosuly the PS output from StarOffice would not print + OK with ghostscript - when using extra characters - unless the .ttf file was modified.) +2. Because of 1, removed the abilty to modify a TrueType font's internal charactermap - this was a hack anyway. +3. xfinst now uses mkfontdir to create encodings.dir - instead of kfontinst's install procedure copying a standard + one in (this didn't actually work...) +4. As kfontinst no longer reads the .enc files themselves, added the ability to use .enc.gz files as well + when selecting an encoding for X. +5. Re-wrote xfinst & reencode to be plain 'sh' scripts, as opposed to 'tcsh' scripts. + +0.3->0.4 +======== +1. All X fonts will now be placed with in a directory - "Managed" - this makes things easier for + AbiWord, and maybe others. +2. encodings.dir & Encodings/ will now be placed within this new "Managed" dir. +3. Only 1 StarOffice .PS file will be created - X11.PS +4. Only 1 Fontmap will be created - Fontmap.X11 - and this will be placed within + /lib +5. Because of 4, an option has been added to the Settings dialog to specify the location of + Ghostscript. +6. Because of 1, removed the font option from the Configure dialog. +7. Fixed an error with getting PS name from TT font - PS names are not allowed to have spaces, but in + fences.ttf it does. FontEngine.cpp will now check for, and fix, this - using the same 'algorithm' as that + of ttf2pt1 (which means the names will tie up with those in the .afm files). +8. Added some improvements to control of dialogs. + +0.2.1->0.3 +========== +1. Reverted back to naming .afm files .afm - and renaming any conflicting fonts. +2. Speeded up copying of files - by copying preview bitmap as opposed to regenerating it! +3. Removed need for FontMetrics directory - .afm files now placed within TrueType or Type1 dir, + and sym links are produced for StarOffice. + + 1. & 3. should now make things easier for AbiWord. + +4. Fixed output of Fontmap so that "URW Gothic" will be aliased as "UrwGothic-Roman" (etc.) as + this is what Qt will output. +5. Added more processing of .afm files - this makes them OK for AbiWord. + +0.2->0.2.1 +========== +1. Modified start-up progress dailog, and added progress dialogs to main window when scanning + fonts. These will only appear if numTTfonts>X || numT1fonts>Y + +0.1->0.2 +======== +1. Combined views of installed TrueType and Type1 fonts into 1 list. +2. When uninstalling a font, can now move the font to another directory - or delete. +3. Used t1lib so that Type1 fonts can also be previewed. +4. Changed Fontmap creator to dynamically allocate memory for each font-category. +5. .afm files are now named as ..afm - this removes the need + for renaming the .afm file if there exists Type1 and TrueType fonts with the same + fontname. +6. Removed the re-scanning of the install directories whenever a font is added. +7. Added support for extra Type1 font weights. +8. Added a start-up screen to inform the user that the installed/disk fonts are being scanned. +9. When exiting, confirmation is now only asked if the system has been changed and not + reconfigured. diff --git a/kcontrol/kfontinst/Messages.sh b/kcontrol/kfontinst/Messages.sh new file mode 100644 index 00000000..0634d49b --- /dev/null +++ b/kcontrol/kfontinst/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC `find . -name \*.rc` >> rc.cpp +$XGETTEXT rc.cpp */*.cpp */*.h -o $podir/kfontinst.pot +rm -f rc.cpp diff --git a/kcontrol/kfontinst/apps/CMakeLists.txt b/kcontrol/kfontinst/apps/CMakeLists.txt new file mode 100644 index 00000000..975a187f --- /dev/null +++ b/kcontrol/kfontinst/apps/CMakeLists.txt @@ -0,0 +1,33 @@ +include_directories( + ${KDEBASE_WORKSPACE_SOURCE_DIR}/kcontrol/kfontinst/kcmfontinst/ + ${KDEBASE_WORKSPACE_SOURCE_DIR}/kcontrol/kfontinst/viewpart/ + ${CMAKE_CURRENT_BINARY_DIR} + ) + +set(kfontinst_bin_SRCS ${libkfontinstjobrunner_SRCS} ${libkfontinstdbusiface_SRCS} Installer.cpp ) +# qt4_add_dbus_interface(kfontinst_bin_SRCS ../dbus/org.kde.fontinst.xml FontInstInterfaceBase) + +set(kfontprint_bin_SRCS ${libkfontinstactionlabel_SRCS} Printer.cpp ) +set(kfontview_bin_SRCS Viewer.cpp ) + +kde4_add_executable(kfontinst_bin ${kfontinst_bin_SRCS}) +kde4_add_executable(kfontprint_bin ${kfontprint_bin_SRCS}) +kde4_add_executable(kfontview_bin ${kfontview_bin_SRCS}) + +set_target_properties(kfontinst_bin PROPERTIES OUTPUT_NAME kfontinst) +set_target_properties(kfontprint_bin PROPERTIES OUTPUT_NAME kfontprint) +set_target_properties(kfontview_bin PROPERTIES OUTPUT_NAME kfontview) + +target_link_libraries(kfontinst_bin ${KDE4_KIO_LIBS} ${KDE4_KDESU_LIBS} ${X11_X11_LIB} kfontinst) +target_link_libraries(kfontprint_bin ${X11_X11_LIB} ${KDE4_KDEUI_LIBS} ${FREETYPE_LIBRARIES} kfontinstui kfontinst) +target_link_libraries(kfontview_bin ${KDE4_KPARTS_LIBS} kfontinstui kfontinst ) + +install(TARGETS kfontinst_bin ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install(TARGETS kfontprint_bin DESTINATION ${LIBEXEC_INSTALL_DIR} ) +install(TARGETS kfontview_bin ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install(FILES kfontviewui.rc DESTINATION ${DATA_INSTALL_DIR}/kfontview ) +install(PROGRAMS kfontview.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) +install(FILES installfont.desktop DESTINATION +${SERVICES_INSTALL_DIR}/ServiceMenus ) + +kde4_install_icons( ${ICON_INSTALL_DIR} ) diff --git a/kcontrol/kfontinst/apps/CreateParent.h b/kcontrol/kfontinst/apps/CreateParent.h new file mode 100644 index 00000000..5a3dc381 --- /dev/null +++ b/kcontrol/kfontinst/apps/CreateParent.h @@ -0,0 +1,73 @@ +#ifndef __CREATE_PARENT_H__ +#define __CREATE_PARENT_H__ + +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2007 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +// +// *Very* hacky way to get some KDE dialogs to appear to be transient +// for 'xid' +// +// Create's a QWidget with size 0/0 and no border, makes this transient +// for xid, and all other widgets can use this as their parent... +static QWidget * createParent(int xid) +{ + if(!xid) + return NULL; + + QWidget *parent=new QWidget(NULL, Qt::FramelessWindowHint); + + parent->resize(1, 1); + parent->show(); + + XWindowAttributes attr; + int rx, ry; + Window junkwin; + + XSetTransientForHint(QX11Info::display(), parent->winId(), xid); + if(XGetWindowAttributes(QX11Info::display(), xid, &attr)) + { + XTranslateCoordinates(QX11Info::display(), xid, attr.root, + -attr.border_width, -16, + &rx, &ry, &junkwin); + + rx=(rx+(attr.width/2)); + if(rx<0) + rx=0; + ry=(ry+(attr.height/2)); + if(ry<0) + ry=0; + parent->move(rx, ry); + } + parent->setWindowOpacity(0); + parent->setWindowTitle(QLatin1String("KFI")); + + return parent; +} + +#endif diff --git a/kcontrol/kfontinst/apps/Installer.cpp b/kcontrol/kfontinst/apps/Installer.cpp new file mode 100644 index 00000000..9747fe3f --- /dev/null +++ b/kcontrol/kfontinst/apps/Installer.cpp @@ -0,0 +1,154 @@ +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2007 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "Installer.h" +#include "Misc.h" +#include "FontsPackage.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "JobRunner.h" +#include "CreateParent.h" + +namespace KFI +{ + +int CInstaller::install(const QSet &urls) +{ + QSet::ConstIterator it(urls.begin()), + end(urls.end()); + bool sysInstall(false); + CJobRunner *jobRunner=new CJobRunner(itsParent); + + CJobRunner::startDbusService(); + + if(!Misc::root()) + { + switch(KMessageBox::questionYesNoCancel(itsParent, + i18n("Do you wish to install the font(s) for personal use " + "(only available to you), or " + "system-wide (available to all users)?"), + i18n("Where to Install"), KGuiItem(i18n(KFI_KIO_FONTS_USER)), + KGuiItem(i18n(KFI_KIO_FONTS_SYS)))) + { + case KMessageBox::No: + sysInstall=true; + break; + case KMessageBox::Cancel: + return -1; + default: + break; + } + } + + QSet instUrls; + + for(; it!=end; ++it) + { + KUrl local(KIO::NetAccess::mostLocalUrl(*it, NULL)); + bool package(false); + + if(local.isLocalFile()) + { + QString localFile(local.toLocalFile()); + + if(Misc::isPackage(localFile)) + { + instUrls+=FontsPackage::extract(localFile, &itsTempDir); + package=true; + } + } + if(!package) + { + KUrl::List associatedUrls; + + CJobRunner::getAssociatedUrls(*it, associatedUrls, false, itsParent); + instUrls.insert(*it); + + KUrl::List::Iterator aIt(associatedUrls.begin()), + aEnd(associatedUrls.end()); + + for(; aIt!=aEnd; ++aIt) + instUrls.insert(*aIt); + } + } + + if(instUrls.count()) + { + CJobRunner::ItemList list; + QSet::ConstIterator it(instUrls.begin()), + end(instUrls.end()); + + for(; it!=end; ++it) + list.append(*it); + + return jobRunner->exec(CJobRunner::CMD_INSTALL, list, Misc::root() || sysInstall); + } + else + return -1; +} + +CInstaller::~CInstaller() +{ + delete itsTempDir; +} + +} + +static KAboutData aboutData("kfontinst", KFI_CATALOGUE, ki18n("Font Installer"), "1.0", ki18n("Simple font installer"), + KAboutData::License_GPL, ki18n("(C) Craig Drummond, 2007")); + +int main(int argc, char **argv) +{ + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("embed ", ki18n("Makes the dialog transient for an X app specified by winid")); + options.add("+[URL]", ki18n("URL to install")); + KCmdLineArgs::addCmdLineOptions(options); + + QSet urls; + KCmdLineArgs *args(KCmdLineArgs::parsedArgs()); + + for(int i=0; i < args->count(); i++) + urls.insert(args->url(i)); + + if(urls.count()) + { + KLocale::setMainCatalog(KFI_CATALOGUE); + + KApplication app; + QString opt(args->getOption("embed")); + KFI::CInstaller inst(createParent(opt.size() ? opt.toInt(0, 16) : 0)); + + return inst.install(urls); + } + + return -1; +} diff --git a/kcontrol/kfontinst/apps/Installer.h b/kcontrol/kfontinst/apps/Installer.h new file mode 100644 index 00000000..29237e58 --- /dev/null +++ b/kcontrol/kfontinst/apps/Installer.h @@ -0,0 +1,53 @@ +#ifndef __INSTALLER_H__ +#define __INSTALLER_H__ + +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2007 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +class QWidget; +class KTempDir; + +namespace KFI +{ +class CInstaller +{ + public: + + CInstaller(QWidget *p) + : itsParent(p), itsTempDir(NULL) { } + ~CInstaller(); + + int install(const QSet &urls); + + private: + + QWidget *itsParent; + KTempDir *itsTempDir; +}; + +} + +#endif diff --git a/kcontrol/kfontinst/apps/Printer.cpp b/kcontrol/kfontinst/apps/Printer.cpp new file mode 100644 index 00000000..60393156 --- /dev/null +++ b/kcontrol/kfontinst/apps/Printer.cpp @@ -0,0 +1,496 @@ +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2007 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config-fontinst.h" +#include "Printer.h" +#include "FcEngine.h" +#include "ActionLabel.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(Q_WS_X11) || defined(Q_WS_QWS) +#include +#include +#include FT_FREETYPE_H +#endif + +#ifdef HAVE_LOCALE_H +#include +#endif +#include "CreateParent.h" + +// Enable the following to allow printing of non-installed fonts. Does not seem to work :-( +//#define KFI_PRINT_APP_FONTS + +using namespace KFI; + +static const int constMarginLineBefore=1; +static const int constMarginLineAfter=2; +static const int constMarginFont=4; + +inline bool sufficientSpace(int y, int pageHeight, const QFontMetrics &fm) +{ + return (y+constMarginFont+fm.height())fontMetrics().height(), + required=titleFontHeight+constMarginLineBefore+constMarginLineAfter; + + for(unsigned int s=0; sizes[s]; ++s) + { + font.setPointSize(sizes[s]); + required+=QFontMetrics(font, painter->device()).height(); + if(sizes[s+1]) + required+=constMarginFont; + } + + if(0==size) + { + font.setPointSize(CFcEngine::constDefaultAlphaSize); + int fontHeight=QFontMetrics(font, painter->device()).height(); + + required+=(3*(constMarginFont+fontHeight))+ + constMarginLineBefore+constMarginLineAfter; + } + return (y+required)num_charmaps; ++cmap) + if(face->charmaps[cmap] && FT_ENCODING_ADOBE_CUSTOM==face->charmaps[cmap]->encoding) + { + FT_Select_Charmap(face, FT_ENCODING_ADOBE_CUSTOM); + break; + } + + for(unsigned int i=1; i<65535; ++i) + if(FT_Get_Char_Index(face, i)) + { + newStr+=QChar(i); + if(newStr.length()>255) + break; + } + + return newStr; +} + +static QString usableStr(FT_Face face, const QString &str) +{ + unsigned int slen=str.length(), + ch; + QString newStr; + + for(ch=0; ch &items, int size, QObject *parent) + : QThread(parent) + , itsPrinter(printer) + , itsItems(items) + , itsSize(size) + , itsCancelled(false) +{ +} + +CPrintThread::~CPrintThread() +{ +} + +void CPrintThread::cancel() +{ + itsCancelled=true; +} + +void CPrintThread::run() +{ + QPainter painter; + QFont sans("sans", 12, QFont::Bold); + bool changedFontEmbeddingSetting(false); + QString str(CFcEngine(false).getPreviewString()); + + if(!itsPrinter->fontEmbeddingEnabled()) + { + itsPrinter->setFontEmbeddingEnabled(true); + changedFontEmbeddingSetting=true; + } + + itsPrinter->setResolution(72); + painter.begin(itsPrinter); + + int pageWidth=painter.device()->width(), + pageHeight=painter.device()->height(), + y=0, + oneSize[2]={itsSize, 0}; + const int *sizes=oneSize; + bool firstFont(true); + + if(0==itsSize) + sizes=CFcEngine::constScalableSizes; + + painter.setClipping(true); + painter.setClipRect(0, 0, pageWidth, pageHeight); + + QList::ConstIterator it(itsItems.constBegin()), + end(itsItems.constEnd()); + + for(int i=0; it!=end && !itsCancelled; ++it, ++i) + { + QString name(FC::createName((*it).family, (*it).styleInfo)); + emit progress(i, name); + + unsigned int s=0; + QFont font; + +#ifdef KFI_PRINT_APP_FONTS + QString family; + + if(-1!=appFont[(*it).family]) + { + family=QFontDatabase::applicationFontFamilies(appFont[(*it).family]).first(); + font=QFont(family); + } +#else + font=CFcEngine::getQFont((*it).family, (*it).styleInfo, CFcEngine::constDefaultAlphaSize); +#endif + painter.setFont(sans); + + if(!firstFont && !sufficientSpace(y, &painter, font, sizes, pageHeight, itsSize)) + { + itsPrinter->newPage(); + y=0; + } + painter.setFont(sans); + y+=painter.fontMetrics().height(); + painter.drawText(0, y, name); + + y+=constMarginLineBefore; + painter.drawLine(0, y, pageWidth, y); + y+=constMarginLineAfter; + + bool onlyDrawChars=false; + Qt::TextElideMode em=Qt::LeftToRight==QApplication::layoutDirection() ? Qt::ElideRight : Qt::ElideLeft; + + if(0==itsSize) + { + font.setPointSize(CFcEngine::constDefaultAlphaSize); + painter.setFont(font); + + QFontMetrics fm(font, painter.device()); + bool lc=hasStr(font, CFcEngine::getLowercaseLetters()), + uc=hasStr(font, CFcEngine::getUppercaseLetters()); + + onlyDrawChars=!lc && !uc; + + if(lc || uc) + y+=CFcEngine::constDefaultAlphaSize; + + if(lc) + { + painter.drawText(0, y, fm.elidedText(CFcEngine::getLowercaseLetters(), em, pageWidth)); + y+=constMarginFont+CFcEngine::constDefaultAlphaSize; + } + + if(uc) + { + painter.drawText(0, y, fm.elidedText(CFcEngine::getUppercaseLetters(), em, pageWidth)); + y+=constMarginFont+CFcEngine::constDefaultAlphaSize; + } + + if(lc || uc) + { + QString validPunc(usableStr(font, CFcEngine::getPunctuation())); + if(validPunc.length()>=(CFcEngine::getPunctuation().length()/2)) + { + painter.drawText(0, y, fm.elidedText(CFcEngine::getPunctuation(), em, pageWidth)); + y+=constMarginFont+constMarginLineBefore; + } + painter.drawLine(0, y, pageWidth, y); + y+=constMarginLineAfter; + } + } + + for(; sizes[s]; ++s) + { + y+=sizes[s]; + font.setPointSize(sizes[s]); + painter.setFont(font); + + QFontMetrics fm(font, painter.device()); + + if(sufficientSpace(y, pageHeight, fm)) + { + painter.drawText(0, y, fm.elidedText(previewString(font, str, onlyDrawChars), em, pageWidth)); + if(sizes[s+1]) + y+=constMarginFont; + } + else + break; + } + y+=(s<1 || sizes[s-1]<25 ? 14 : 28); + firstFont=false; + } + emit progress(itsItems.count(), QString()); + painter.end(); + + // + // Did we change the users font settings? If so, reset to their previous values... + if(changedFontEmbeddingSetting) + itsPrinter->setFontEmbeddingEnabled(false); +} + +CPrinter::CPrinter(QWidget *parent) + : KDialog(parent) +{ + setCaption(i18n("Print")); + setButtons(Cancel); + + QFrame *page = new QFrame(this); + QGridLayout *layout=new QGridLayout(page); + layout->setMargin(KDialog::marginHint()); + layout->setSpacing(KDialog::spacingHint()); + itsStatusLabel=new QLabel(page); + itsProgress=new QProgressBar(page); + layout->addWidget(itsActionLabel = new CActionLabel(this), 0, 0, 2, 1); + layout->addWidget(itsStatusLabel, 0, 1); + layout->addWidget(itsProgress, 1, 1); + itsProgress->setRange(0, 100); + layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 0); + setMainWidget(page); + setMinimumSize(420, 80); +} + +CPrinter::~CPrinter() +{ +} + +void CPrinter::print(const QList &items, int size) +{ + #ifdef HAVE_LOCALE_H + char *oldLocale=setlocale(LC_NUMERIC, "C"); + #endif + + QPrinter printer; + QPrintDialog *dialog = KdePrint::createPrintDialog(&printer, parentWidget()); + + if(dialog->exec()) + { + CPrintThread *thread = new CPrintThread(&printer, items, size, this); + + itsProgress->setRange(0, items.count()); + itsProgress->setValue(0); + progress(0, QString()); + connect(thread, SIGNAL(progress(int,QString)), SLOT(progress(int,QString))); + connect(thread, SIGNAL(finished()), SLOT(accept())); + connect(this, SIGNAL(cancelled()), thread, SLOT(cancel())); + itsActionLabel->startAnimation(); + thread->start(); + exec(); + delete thread; + } + + delete dialog; + + #ifdef HAVE_LOCALE_H + if(oldLocale) + setlocale(LC_NUMERIC, oldLocale); + #endif +} + +void CPrinter::progress(int p, const QString &label) +{ + if(!label.isEmpty()) + itsStatusLabel->setText(label); + itsProgress->setValue(p); +} + +void CPrinter::slotButtonClicked(int button) +{ + Q_UNUSED(button) + itsStatusLabel->setText(i18n("Canceling...")); + emit cancelled(); +} + +void CPrinter::closeEvent(QCloseEvent *e) +{ + Q_UNUSED(e) + e->ignore(); + slotButtonClicked(0); +} + +static KAboutData aboutData("kfontprint", KFI_CATALOGUE, ki18n("Font Printer"), "1.1", ki18n("Simple font printer"), + KAboutData::License_GPL, ki18n("(C) Craig Drummond, 2007")); + +int main(int argc, char **argv) +{ + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("embed ", ki18n("Makes the dialog transient for an X app specified by winid")); + options.add("size ", ki18n("Size index to print fonts")); + options.add("pfont ", ki18n("Font to print, specified as \"Family,Style\" where Style is a 24-bit decimal number composed as: ")); //krazy:exclude=i18ncheckarg + options.add("listfile ", ki18n("File containing list of fonts to print")); + options.add("deletefile", ki18n("Remove file containing list of fonts to print")); + KCmdLineArgs::addCmdLineOptions(options); + + KApplication app; + KCmdLineArgs *args(KCmdLineArgs::parsedArgs()); + QList fonts; + int size(args->getOption("size").toInt()); + + if(size>-1 && size<256) + { + QString listFile(args->getOption("listfile")); + + if(listFile.size()) + { + QFile f(listFile); + + if(f.open(QIODevice::ReadOnly)) + { + QTextStream str(&f); + + while (!str.atEnd()) + { + QString family(str.readLine()), + style(str.readLine()); + + if(!family.isEmpty() && !style.isEmpty()) + fonts.append(Misc::TFont(family, style.toUInt())); + else + break; + } + f.close(); + } + + if(args->isSet("deletefile")) + ::unlink(listFile.toLocal8Bit().constData()); + } + else + { + QStringList fl(args->getOptionList("pfont")); + QStringList::ConstIterator it(fl.begin()), + end(fl.end()); + + for(; it!=end; ++it) + { + QString f(*it); + + int commaPos=f.lastIndexOf(','); + + if(-1!=commaPos) + fonts.append(Misc::TFont(f.left(commaPos), f.mid(commaPos+1).toUInt())); + } + } + + if(fonts.count()) + { + KLocale::setMainCatalog(KFI_CATALOGUE); + CPrinter(createParent(args->getOption("embed").toInt(0, 16))).print(fonts, size); + + return 0; + } + } + + return -1; +} + +#include "Printer.moc" diff --git a/kcontrol/kfontinst/apps/Printer.h b/kcontrol/kfontinst/apps/Printer.h new file mode 100644 index 00000000..910e3285 --- /dev/null +++ b/kcontrol/kfontinst/apps/Printer.h @@ -0,0 +1,103 @@ +/* + * KFontInst - KDE Font Installer + * + * Copyright 2011 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PRINTER_H__ +#define __PRINTER_H__ + +#include +#include +#include +#include +#include "Misc.h" + +class QLabel; +class QProgressBar; +class QStackedWidget; +class QPrinter; + +namespace KFI +{ + +class CActionLabel; + +class CPrintThread : public QThread +{ + Q_OBJECT + + public: + + CPrintThread(QPrinter *printer, const QList &items, int size, QObject *parent); + ~CPrintThread(); + + void run(); + + Q_SIGNALS: + + void progress(int p, const QString &f); + + public Q_SLOTS: + + void cancel(); + + private: + + QPrinter *itsPrinter; + QList itsItems; + int itsSize; + bool itsCancelled; +}; + +class CPrinter : public KDialog +{ + Q_OBJECT + + public: + + explicit CPrinter(QWidget *parent); + ~CPrinter(); + + void print(const QList &items, int size); + + Q_SIGNALS: + + void cancelled(); + + public Q_SLOTS: + + void progress(int p, const QString &label); + void slotButtonClicked(int button); + + private: + + void closeEvent(QCloseEvent *e); + + private: + + QLabel *itsStatusLabel; + QProgressBar *itsProgress; + CActionLabel *itsActionLabel; +}; + +} + +#endif diff --git a/kcontrol/kfontinst/apps/Viewer.cpp b/kcontrol/kfontinst/apps/Viewer.cpp new file mode 100644 index 00000000..f8408c57 --- /dev/null +++ b/kcontrol/kfontinst/apps/Viewer.cpp @@ -0,0 +1,166 @@ +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2007 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "Viewer.h" +#include "KfiConstants.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace KFI +{ + +CViewer::CViewer() +{ + KPluginFactory *factory=KPluginLoader("kfontviewpart").factory(); + + if(factory) + { + itsPreview=factory->create(this); + + actionCollection()->addAction(KStandardAction::Open, this, SLOT(fileOpen())); + actionCollection()->addAction(KStandardAction::Quit, this, SLOT(close())); + actionCollection()->addAction(KStandardAction::KeyBindings, this, SLOT(configureKeys())); + itsPrintAct=actionCollection()->addAction(KStandardAction::Print, itsPreview, SLOT(print())); + + itsPrintAct->setEnabled(false); + + if(itsPreview->browserExtension()) + connect(itsPreview->browserExtension(), SIGNAL(enableAction(const char*,bool)), + this, SLOT(enableAction(const char*,bool))); + + setCentralWidget(itsPreview->widget()); + createGUI(itsPreview); + + setAutoSaveSettings(); + applyMainWindowSettings(KGlobal::config()->group("MainWindow")); + } + else + exit(0); +} + +void CViewer::fileOpen() +{ + KUrl url(KFileDialog::getOpenUrl(KUrl(), "application/x-font-ttf application/x-font-otf " + "application/x-font-type1 " + "application/x-font-bdf application/x-font-pcf ", + this, i18n("Select Font to View"))); + showUrl(url); +} + +void CViewer::showUrl(const KUrl &url) +{ + if(url.isValid()) + itsPreview->openUrl(url); +} + +void CViewer::configureKeys() +{ + KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this); + + dlg.addCollection(actionCollection()); + dlg.configure(); +} + +void CViewer::enableAction(const char *name, bool enable) +{ + if(0==qstrcmp("print", name)) + itsPrintAct->setEnabled(enable); +} + + + + +class ViewerApplication : public KUniqueApplication +{ + public: + +#ifdef Q_WS_X11 + ViewerApplication(Display *display, Qt::HANDLE visual, Qt::HANDLE colormap) + : KUniqueApplication(display,visual,colormap) + { + } +#endif + + ViewerApplication() : KUniqueApplication() + { + } + + int newInstance() + { + KCmdLineArgs *args(KCmdLineArgs::parsedArgs()); + KFI::CViewer *viewer=new KFI::CViewer; + + viewer->show(); + if(args->count() > 0) + { + for (int i = 0; i < args->count(); ++i) + { + KUrl url(args->url(i)); + + if (i != 0) + { + viewer=new KFI::CViewer; + viewer->show(); + } + viewer->showUrl(url); + } + } + + return 0; + } +}; + +} + +static KAboutData aboutData("kfontview", KFI_CATALOGUE, ki18n("Font Viewer"), "1.1", ki18n("Simple font viewer"), + KAboutData::License_GPL, ki18n("(C) Craig Drummond, 2004-2007")); + +int main(int argc, char **argv) +{ + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addTempFileOption(); + + KCmdLineOptions options; + options.add("+[URL]", ki18n("URL to open")); + KCmdLineArgs::addCmdLineOptions(options); + + if (!KUniqueApplication::start()) + exit(0); + + KFI::ViewerApplication app; + + return app.exec(); +} + +#include "Viewer.moc" diff --git a/kcontrol/kfontinst/apps/Viewer.h b/kcontrol/kfontinst/apps/Viewer.h new file mode 100644 index 00000000..b0fafe52 --- /dev/null +++ b/kcontrol/kfontinst/apps/Viewer.h @@ -0,0 +1,59 @@ +#ifndef __VIEWER_H__ +#define __VIEWER_H__ + +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2007 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +class QAction; + +namespace KFI +{ + +class CViewer : public KParts::MainWindow +{ + Q_OBJECT + + public: + + CViewer(); + virtual ~CViewer() { } + void showUrl(const KUrl &url); + + public Q_SLOTS: + + void fileOpen(); + void configureKeys(); + void enableAction(const char *name, bool enable); + + private: + + KParts::ReadOnlyPart *itsPreview; + QAction *itsPrintAct; +}; + +} + +#endif diff --git a/kcontrol/kfontinst/apps/installfont.desktop b/kcontrol/kfontinst/apps/installfont.desktop new file mode 100644 index 00000000..a83e4198 --- /dev/null +++ b/kcontrol/kfontinst/apps/installfont.desktop @@ -0,0 +1,96 @@ +[Desktop Entry] +X-KDE-ServiceTypes=KonqPopupMenu/Plugin,application/x-font-ttf,application/x-font-type1,application/x-font-bdf,application/x-font-pcf,application/x-font-otf,application/x-font-afm,fonts/package +Actions=installFont; +Type=Service + +[Desktop Action installFont] +Name=Install... +Name[af]=Installeer... +Name[ar]=ثبّت... +Name[as]=সংস্থাপন কৰক... +Name[ast]=Instalar... +Name[be]=Устанавіць... +Name[be@latin]=Zainstaluj... +Name[bg]=Инсталиране... +Name[bn]=ইনস্টল... +Name[bn_IN]=ইনস্টল করুন... +Name[bs]=Instaliraj... +Name[ca]=Instal·la... +Name[ca@valencia]=Instal·la... +Name[cs]=Instalovat... +Name[csb]=Instalëjë... +Name[da]=Installér... +Name[de]=Installieren ... +Name[el]=Εγκατάσταση... +Name[en_GB]=Install... +Name[eo]=Instali... +Name[es]=Instalar... +Name[et]=Paigalda... +Name[eu]=Instalatu... +Name[fa]=نصب... +Name[fi]=Asenna… +Name[fr]=Installer... +Name[fy]=Ynstallearje... +Name[ga]=Suiteáil... +Name[gl]=Instalar... +Name[gu]=સ્થાપન... +Name[he]=התקנה... +Name[hi]=संस्थापित करें... +Name[hne]=इंस्टाल करव... +Name[hr]=Instaliraj… +Name[hsb]=instalować... +Name[hu]=Telepítés... +Name[ia]=Installa ... +Name[id]=Instal... +Name[is]=Setja upp... +Name[it]=Installa... +Name[ja]=インストール... +Name[kk]=Орнату... +Name[km]=ដំឡើង... +Name[kn]=ಅನುಸ್ಢಾಪಿಸು... +Name[ko]=설치... +Name[ku]=Sazkirin... +Name[lt]=Įdiegti... +Name[lv]=Instalēt... +Name[mai]=संस्थापित करू... +Name[mk]=Инсталирање... +Name[ml]=ഇന്‍‌സ്റ്റോള്‍ ചെയ്യുക... +Name[mr]=प्रतिष्ठापन... +Name[nb]=Installer … +Name[nds]=Installeren... +Name[ne]=स्थापना गर्नुहोस् +Name[nl]=Installeren... +Name[nn]=Installer … +Name[oc]=Installar... +Name[or]=ସ୍ଥାପନ କରନ୍ତୁ... +Name[pa]=ਇੰਸਟਾਲ... +Name[pl]=Instaluj... +Name[pt]=Instalar... +Name[pt_BR]=Instalar... +Name[ro]=Instalare... +Name[ru]=Установить... +Name[se]=Sajáiduhte … +Name[si]=ස්ථාපනය... +Name[sk]=Inštalovať... +Name[sl]=Namesti ... +Name[sr]=Инсталирај... +Name[sr@ijekavian]=Инсталирај... +Name[sr@ijekavianlatin]=Instaliraj... +Name[sr@latin]=Instaliraj... +Name[sv]=Installera... +Name[ta]=நிறுவுக... +Name[te]=సంస్థాపించు... +Name[tg]=Коргузорӣ... +Name[th]=ติดตั้ง... +Name[tr]=Yükle... +Name[ug]=ئورنات… +Name[uk]=Встановити... +Name[uz]=Oʻrnatish... +Name[uz@cyrillic]=Ўрнатиш... +Name[vi]=Cài đặt... +Name[wa]=Astaler... +Name[x-test]=xxInstall...xx +Name[zh_CN]=安装... +Name[zh_TW]=安裝... +Icon=preferences-desktop-font-installer +Exec=kfontinst --icon preferences-desktop-font-installer %U diff --git a/kcontrol/kfontinst/apps/kfontview.desktop b/kcontrol/kfontinst/apps/kfontview.desktop new file mode 100755 index 00000000..20c0042e --- /dev/null +++ b/kcontrol/kfontinst/apps/kfontview.desktop @@ -0,0 +1,192 @@ +[Desktop Entry] +Name=KFontView +Name[af]=KFontView +Name[ar]=عارض خطوط كيدي +Name[ast]=KFontView +Name[be]=Прагляд шрыфтоў +Name[be@latin]=KFontView +Name[bg]=KFontView +Name[bn]=কে-ফন্ট-ভিউ +Name[bn_IN]=KFontView +Name[br]=KFontView +Name[bs]=K‑prikazivač-fontova +Name[ca]=KFontView +Name[ca@valencia]=KFontView +Name[cs]=Prohlížeč písem +Name[csb]=KFontView +Name[cy]=KFontView +Name[da]=KFontView +Name[de]=KFontView +Name[el]=KFontView +Name[en_GB]=KFontView +Name[eo]=KFontView +Name[es]=KFontView +Name[et]=KFontView +Name[eu]=KFontWiew +Name[fi]=KFontView +Name[fr]=KFontView +Name[fy]=KFontView +Name[ga]=KFontView +Name[gl]=KFontView +Name[gu]=KFontView +Name[he]=KFontView +Name[hi]=के-फ़ॉन्ट-व्यू +Name[hne]=के-फोंट-व्यू +Name[hr]=KFontView +Name[hsb]=KFontView +Name[hu]=KFontView +Name[ia]=KFontView +Name[id]=KFontView +Name[is]=KFontView +Name[it]=KFontView +Name[ja]=KFontView +Name[ka]=KFontView +Name[kk]=KFontView +Name[km]=KFontView +Name[kn]=ಕೆಫಾಂಟ್ ವ್ಯೂ +Name[ko]=KFontView +Name[ku]=KFontView +Name[lt]=KFontView +Name[lv]=KFontView +Name[mai]=के-फान्ट-व्यू +Name[mk]=КФонтПреглед +Name[ml]=കെഫോണ്ട്‌വ്യൂ +Name[mr]=केफॉन्टव्यू +Name[ms]=KFontView +Name[nb]=KFontView +Name[nds]=KFontView +Name[ne]=केडीई फन्ट दृश्य +Name[nl]=KFontView +Name[nn]=Skriftvisar +Name[oc]=KFontView +Name[or]=KFontView +Name[pa]=KFontView +Name[pl]=KFontView +Name[pt]=KFontView +Name[pt_BR]=KFontView +Name[ro]=KFontView +Name[ru]=KFontView +Name[se]=Fontačájeheaddji +Name[si]=KFontView +Name[sk]=KFontView +Name[sl]=KFontView +Name[sr]=К‑приказивач-фонтова +Name[sr@ijekavian]=К‑приказивач-фонтова +Name[sr@ijekavianlatin]=K‑prikazivač-fontova +Name[sr@latin]=K‑prikazivač-fontova +Name[sv]=Kfontview +Name[ta]=KFontView +Name[te]=KFontView +Name[tg]=Намоиши ҳарф +Name[th]=ดูแบบอักษร-K +Name[tr]=KFontView +Name[ug]=KFontView +Name[uk]=KFontView +Name[uz]=KFontView +Name[uz@cyrillic]=KFontView +Name[vi]=KFonView +Name[wa]=Håyneu d' fontes +Name[x-test]=xxKFontViewxx +Name[zh_CN]=KFontView +Name[zh_TW]=KFontView +Exec=kfontview %U +Icon=kfontview +X-KDE-StartupNotify=true +Type=Application +MimeType=application/x-font-ttf;application/x-font-type1;application/x-font-otf;application/x-font-pcf;application/x-font-bdf;application/vnd.kde.fontspackage; +GenericName=Font Viewer +GenericName[af]=Skriftipe Besigter +GenericName[ar]=عارض الخطوط +GenericName[ast]=Visor del triba de lletra +GenericName[be]=Прагляд шрыфта +GenericName[be@latin]=Prahladnik šryftoŭ +GenericName[bg]=Преглед на шрифтове +GenericName[bn]=ফন্ট প্রদর্শক +GenericName[bn_IN]=ফন্ট প্রদর্শক +GenericName[br]=Gweler Nodrezhoù +GenericName[bs]=Prikazivač fontova +GenericName[ca]=Visor de tipus de lletra +GenericName[ca@valencia]=Visor de tipus de lletra +GenericName[cs]=Prohlížeč písem +GenericName[csb]=Przezérnik fòntów +GenericName[cy]=Gwelydd Wynebfathau +GenericName[da]=Skrifttype-fremviser +GenericName[de]=Schriftartenbetrachter +GenericName[el]=Προβολέας γραμματοσειρών +GenericName[en_GB]=Font Viewer +GenericName[eo]=Tipara rigardilo +GenericName[es]=Visor del tipo de letra +GenericName[et]=Fontide näitaja +GenericName[eu]=Letra-tipoen ikustailea +GenericName[fa]=مشاهده‌گر قلم +GenericName[fi]=Fonttikatselin +GenericName[fr]=Afficheur de polices de caractères +GenericName[fy]=Lettertypewerjefte +GenericName[ga]=Amharcán Clónna +GenericName[gl]=Visor de tipos de letra +GenericName[gu]=ફોન્ટ દર્શક +GenericName[he]=מציג גופנים +GenericName[hi]=फ़ॉन्ट प्रदर्शक +GenericName[hne]=फोंट प्रदर्सक +GenericName[hr]=Preglednik fontova +GenericName[hsb]=Přehladowar za pisma +GenericName[hu]=Betűtípusböngésző +GenericName[ia]=Visor de fronte +GenericName[id]=Penampil Fonta +GenericName[is]=Leturskoðari +GenericName[it]=Visore di caratteri +GenericName[ja]=フォントビューア +GenericName[ka]=პროგრამა ფონტების სანახავად +GenericName[kk]=Қаріпті қарау құралы +GenericName[km]=កម្មវិធី​មើល​ពុម្ពអក្សរ +GenericName[kn]=ಅಕ್ಷರಶೈಲಿ ವೀಕ್ಷಕ +GenericName[ko]=글꼴 뷰어 +GenericName[ku]=Nîşandêra Curetîpan +GenericName[lt]=Šriftų žiūryklė +GenericName[lv]=Fontu skatītājs +GenericName[mai]=फान्ट प्रदर्शक +GenericName[mk]=Прегледувач на фонтови +GenericName[ml]=അക്ഷരസഞ്ചയദര്‍ശിനി +GenericName[mr]=फॉन्ट प्रदर्शक +GenericName[ms]=Pemapar Fon +GenericName[nb]=Skriftviser +GenericName[nds]=Schriftoortkieker +GenericName[ne]=फन्ट दर्शक +GenericName[nl]=Lettertypeweergave +GenericName[nn]=Skriftvisar +GenericName[or]=ଅକ୍ଷରରୂପ ପ୍ରଦର୍ଶକ +GenericName[pa]=ਫੋਂਟ ਦਰਸ਼ਕ +GenericName[pl]=Przeglądarka czcionek +GenericName[pt]=Visualizador do Tipo de Letra +GenericName[pt_BR]=Visualizador de fontes +GenericName[ro]=Vizualizator de fonturi +GenericName[ru]=Просмотр шрифтов +GenericName[se]=Fontačájeheaddji +GenericName[si]=අකුරු දසුන +GenericName[sk]=Prehliadač písiem +GenericName[sl]=Pregledovalnik pisav +GenericName[sr]=Приказивач фонтова +GenericName[sr@ijekavian]=Приказивач фонтова +GenericName[sr@ijekavianlatin]=Prikazivač fontova +GenericName[sr@latin]=Prikazivač fontova +GenericName[sv]=Teckensnittsvisning +GenericName[ta]=Font Viewer +GenericName[te]=ఫాంట్ వీక్షణి +GenericName[tg]=Намоишгари ҳарфҳо +GenericName[th]=ดูตัวอย่างแบบอักษร +GenericName[tr]=Yazı Tipi Görüntüleyici +GenericName[ug]=خەت نۇسخا كۆرگۈچ +GenericName[uk]=Переглядач шрифтів +GenericName[uz]=Shrift koʻruvchi +GenericName[uz@cyrillic]=Шрифт кўрувчи +GenericName[vi]=Trình xem phông chữ +GenericName[wa]=Håyneu d' fontes +GenericName[x-test]=xxFont Viewerxx +GenericName[zh_CN]=字体查看器 +GenericName[zh_TW]=字型檢視器 +Terminal=false +InitialPreference=1 +NoDisplay=true +Categories=Qt;KDE;Utility; +X-DBUS-StartupType=Unique +X-KDE-HasTempFileOption=true diff --git a/kcontrol/kfontinst/apps/kfontviewui.rc b/kcontrol/kfontinst/apps/kfontviewui.rc new file mode 100644 index 00000000..f2e4a86f --- /dev/null +++ b/kcontrol/kfontinst/apps/kfontviewui.rc @@ -0,0 +1,4 @@ + + + + diff --git a/kcontrol/kfontinst/apps/ox16-app-kfontview.png b/kcontrol/kfontinst/apps/ox16-app-kfontview.png new file mode 100644 index 00000000..3691f906 Binary files /dev/null and b/kcontrol/kfontinst/apps/ox16-app-kfontview.png differ diff --git a/kcontrol/kfontinst/apps/ox22-app-kfontview.png b/kcontrol/kfontinst/apps/ox22-app-kfontview.png new file mode 100644 index 00000000..5a24803e Binary files /dev/null and b/kcontrol/kfontinst/apps/ox22-app-kfontview.png differ diff --git a/kcontrol/kfontinst/apps/ox32-app-kfontview.png b/kcontrol/kfontinst/apps/ox32-app-kfontview.png new file mode 100644 index 00000000..c3063f15 Binary files /dev/null and b/kcontrol/kfontinst/apps/ox32-app-kfontview.png differ diff --git a/kcontrol/kfontinst/apps/ox48-app-kfontview.png b/kcontrol/kfontinst/apps/ox48-app-kfontview.png new file mode 100644 index 00000000..0a340707 Binary files /dev/null and b/kcontrol/kfontinst/apps/ox48-app-kfontview.png differ diff --git a/kcontrol/kfontinst/apps/ox64-app-kfontview.png b/kcontrol/kfontinst/apps/ox64-app-kfontview.png new file mode 100644 index 00000000..38902990 Binary files /dev/null and b/kcontrol/kfontinst/apps/ox64-app-kfontview.png differ diff --git a/kcontrol/kfontinst/apps/oxsc-app-kfontview.svgz b/kcontrol/kfontinst/apps/oxsc-app-kfontview.svgz new file mode 100644 index 00000000..6a6a4f8d Binary files /dev/null and b/kcontrol/kfontinst/apps/oxsc-app-kfontview.svgz differ diff --git a/kcontrol/kfontinst/config-fontinst.h.cmake b/kcontrol/kfontinst/config-fontinst.h.cmake new file mode 100644 index 00000000..98966d3b --- /dev/null +++ b/kcontrol/kfontinst/config-fontinst.h.cmake @@ -0,0 +1,9 @@ +#ifndef __CONFIG_FONTINST_H__ +#define __CONFIG_FONTINST_H__ + +#define KFONTINST_LIB_EXEC_DIR "@LIBEXEC_INSTALL_DIR@" + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LOCALE_H 1 + +#endif diff --git a/kcontrol/kfontinst/dbus/CMakeLists.txt b/kcontrol/kfontinst/dbus/CMakeLists.txt new file mode 100644 index 00000000..e983796b --- /dev/null +++ b/kcontrol/kfontinst/dbus/CMakeLists.txt @@ -0,0 +1,32 @@ +include_directories(${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} + ${KDEBASE_WORKSPACE_SOURCE_DIR}/kcontrol/fonts) +add_definitions(${QT_DEFINITIONS}) + +set(fontinst_bin_SRCS FcConfig.cpp FontInst.cpp Folder.cpp Main.cpp Utils.cpp ${libkfontinstdbusiface_SRCS} ) +set(fontinst_helper_SRCS FcConfig.cpp Helper.cpp Folder.cpp Utils.cpp ${libkfontinstdbusiface_SRCS} ) + +# qt4_generate_dbus_interface(FontInst.h org.kde.fontinst.xml) +qt4_add_dbus_adaptor(fontinst_bin_SRCS org.kde.fontinst.xml FontInst.h KFI::FontInst) +# qt4_add_dbus_interface(fontinst_bin_SRCS org.kde.fontinst.xml FontinstIface) + +kde4_add_executable(fontinst_bin ${fontinst_bin_SRCS}) +kde4_add_executable(fontinst_helper ${fontinst_helper_SRCS}) + +set_target_properties(fontinst_bin PROPERTIES OUTPUT_NAME fontinst) +target_link_libraries(fontinst_bin ${KDE4_KDECORE_LIBS} + ${QT_QTDBUS_LIBRARY} ${QT_QTXML_LIBRARY} ${FONTCONFIG_LIBRARIES} kfontinst) + +set_target_properties(fontinst_helper PROPERTIES OUTPUT_NAME fontinst_helper) +target_link_libraries(fontinst_helper ${KDE4_KDECORE_LIBS} + ${QT_QTDBUS_LIBRARY} ${QT_QTXML_LIBRARY} ${FONTCONFIG_LIBRARIES} kfontinst) + +install(TARGETS fontinst_bin DESTINATION ${LIBEXEC_INSTALL_DIR} ) +install(TARGETS fontinst_helper DESTINATION ${LIBEXEC_INSTALL_DIR} ) +install(PROGRAMS fontinst_x11 DESTINATION ${LIBEXEC_INSTALL_DIR}) + +configure_file(org.kde.fontinst.service.cmake ${CMAKE_CURRENT_BINARY_DIR}/session/org.kde.fontinst.service) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/session/org.kde.fontinst.service DESTINATION ${DBUS_SERVICES_INSTALL_DIR} ) + +kde4_install_auth_helper_files(fontinst_helper org.kde.fontinst root) +kde4_install_auth_actions(org.kde.fontinst fontinst.actions) diff --git a/kcontrol/kfontinst/dbus/FcConfig.cpp b/kcontrol/kfontinst/dbus/FcConfig.cpp new file mode 100644 index 00000000..2213a5ef --- /dev/null +++ b/kcontrol/kfontinst/dbus/FcConfig.cpp @@ -0,0 +1,194 @@ +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2009 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "FcConfig.h" +#include "Misc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KFI_DBUG kDebug() << time(0L) + +namespace KFI +{ + +namespace FcConfig +{ + +inline QString xDirSyntax(const QString &d) { return Misc::fileSyntax(d); } + +// +// Obtain location of config file to use. +// +// For system, prefer the following: +// +// <...>/config.d/00kde.conf = preferred method from FCConfig >= 2.3 +// <...>/local.conf +// +// Non-system, prefer: +// +// $HOME/<...>/.fonts.conf +// $HOME/<...>/fonts.conf +// +QString getConfigFile(bool system) +{ +#if (FC_VERSION>=20300) + static const char constKdeRootFcFile[] = "00kde.conf"; +#endif + + FcStrList *list=FcConfigGetConfigFiles(FcConfigGetCurrent()); + QStringList files; + FcChar8 *file; + QString home(Misc::dirSyntax(QDir::homePath())); + + while((file=FcStrListNext(list))) + { + QString f((const char *)file); + + if(Misc::fExists(f)) + { + // For nonsystem, only consider file within $HOME + if(system || 0==Misc::fileSyntax(f).indexOf(home)) + files.append(f); + } +#if (FC_VERSION>=20300) + if(system && Misc::dExists(f) && (f.contains(QRegExp("/conf\\.d/?$")) || + f.contains(QRegExp("/conf\\.d?$"))) ) + return Misc::dirSyntax(f)+constKdeRootFcFile; // This ones good enough for me! +#endif + } + + // + // Go through list of files, looking for the preferred one... + if(files.count()) + { + QStringList::const_iterator it(files.begin()), + end(files.end()); + + for(; it!=end; ++it) + if(-1!=(*it).indexOf(QRegExp(system ? "/local\\.conf$" : "/\\.?fonts\\.conf$"))) + return *it; + return files.front(); // Just return the 1st one... + } + else // Hmmm... no known files? + return system ? "/etc/fonts/local.conf" : Misc::fileSyntax(home+"/.fonts.conf"); +} + +void addDir(const QString &dir, bool system) +{ + QDomDocument doc("fontconfig"); + QString fileName=getConfigFile(system); + QFile f(fileName); + bool hasDir(false); + + KFI_DBUG << "Using fontconfig file:" << fileName; + + // Load existing file - and check to see whether it has the dir... + if(f.open(QIODevice::ReadOnly)) + { + doc.clear(); + + if(doc.setContent(&f)) + { + QDomNode n = doc.documentElement().firstChild(); + + while(!n.isNull() && !hasDir) + { + QDomElement e = n.toElement(); + + if(!e.isNull() && "dir"==e.tagName()) + if(0==Misc::expandHome(Misc::dirSyntax(e.text())).indexOf(dir)) + hasDir=true; + n=n.nextSibling(); + } + } + f.close(); + } + + // Add dir, and save, if config does not already have this dir. + if(!hasDir) + { + if(doc.documentElement().isNull()) + doc.appendChild(doc.createElement("fontconfig")); + + QDomElement newNode = doc.createElement("dir"); + QDomText text = doc.createTextNode(Misc::contractHome(xDirSyntax(dir))); + + newNode.appendChild(text); + doc.documentElement().appendChild(newNode); + + FcAtomic *atomic=FcAtomicCreate((const unsigned char *)(QFile::encodeName(fileName).data())); + + if(atomic) + { + if(FcAtomicLock(atomic)) + { + FILE *f=fopen((char *)FcAtomicNewFile(atomic), "w"); + + if(f) + { + // + // Check document syntax... + static const char qtXmlHeader[] = ""; + static const char xmlHeader[] = ""; + static const char qtDocTypeLine[] = ""; + static const char docTypeLine[] = ""; + + QString str(doc.toString()); + int idx; + + if(0!=str.indexOf(" + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +class QString; + +namespace KFI +{ + +namespace FcConfig +{ + void addDir(const QString &dir, bool system); +} + +} + +#endif diff --git a/kcontrol/kfontinst/dbus/Folder.cpp b/kcontrol/kfontinst/dbus/Folder.cpp new file mode 100644 index 00000000..328dfad0 --- /dev/null +++ b/kcontrol/kfontinst/dbus/Folder.cpp @@ -0,0 +1,417 @@ +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2009 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Folder.h" +#include "FcConfig.h" +#include "Misc.h" +#include "KfiConstants.h" +#include "XmlStrings.h" +#include "Style.h" +#include "File.h" +#include "config-fontinst.h" + +#define DISABLED_FONTS "disabledfonts" +#define KFI_DBUG kDebug() << time(0L) + +namespace KFI +{ + +bool Folder::CfgFile::modified() +{ + return timestamp!=Misc::getTimeStamp(name); +} + +void Folder::CfgFile::updateTimeStamp() +{ + timestamp=Misc::getTimeStamp(name); +} + +Folder::~Folder() +{ + saveDisabled(); +} + +void Folder::init(bool system, bool systemBus) +{ + itsIsSystem=system; + if(!system) + { + FcStrList *list=FcConfigGetFontDirs(FcInitLoadConfigAndFonts()); + QStringList dirs; + FcChar8 *fcDir; + + while((fcDir=FcStrListNext(list))) + dirs.append(Misc::dirSyntax((const char *)fcDir)); + + itsLocation=Misc::getFolder(Misc::dirSyntax(QDir::homePath()+"/.fonts/"), Misc::dirSyntax(QDir::homePath()), dirs); + } + else + itsLocation=KFI_DEFAULT_SYS_FONTS_FOLDER; + + if((!system && !systemBus) || (system && systemBus)) + FcConfig::addDir(itsLocation, system); + + itsDisabledCfg.dirty=false; + if(itsDisabledCfg.name.isEmpty()) + { + QString fileName("/"DISABLED_FONTS".xml"); + + if(system) + itsDisabledCfg.name=QString::fromLatin1(KFI_ROOT_CFG_DIR)+fileName; + else + { + QString path=KGlobal::dirs()->localxdgconfdir(); + + if(!Misc::dExists(path)) + Misc::createDir(path); + itsDisabledCfg.name=path+fileName; + } + itsDisabledCfg.timestamp=0; + } +} + +bool Folder::allowToggling() const +{ + return Misc::fExists(itsDisabledCfg.name) + ? Misc::fWritable(itsDisabledCfg.name) + : Misc::dWritable(Misc::getDir(itsDisabledCfg.name)); +} + +void Folder::loadDisabled() +{ + if(itsDisabledCfg.dirty) + saveDisabled(); + + QFile f(itsDisabledCfg.name); + + KFI_DBUG << itsDisabledCfg.name; + itsDisabledCfg.dirty=false; + if(f.open(QIODevice::ReadOnly)) + { + QDomDocument doc; + + if(doc.setContent(&f)) + for(QDomNode n=doc.documentElement().firstChild(); !n.isNull(); n=n.nextSibling()) + { + QDomElement e=n.toElement(); + + if(FONT_TAG==e.tagName()) + { + Family fam(e, false); + + if(!fam.name().isEmpty()) + { + Style style(e, false); + + if(KFI_NO_STYLE_INFO!=style.value()) + { + QList files; + + if(e.hasAttribute(PATH_ATTR)) + { + File file(e, true); + + if(!file.path().isEmpty()) + files.append(file); + else + itsDisabledCfg.dirty=true; + } + else + { + for(QDomNode n=e.firstChild(); !n.isNull(); n=n.nextSibling()) + { + QDomElement ent=n.toElement(); + + if(FILE_TAG==ent.tagName()) + { + File file(ent, true); + + if(!file.path().isEmpty()) + files.append(file); + else + { + KFI_DBUG << "Set dirty from load"; + itsDisabledCfg.dirty=true; + } + } + } + } + + if(files.count()>0) + { + QList::ConstIterator it(files.begin()), + end(files.end()); + + FamilyCont::ConstIterator f(itsFonts.insert(fam)); + StyleCont::ConstIterator s((*f).add(style)); + + for(; it!=end; ++it) + (*s).add(*it); + } + } + } + } + } + + f.close(); + itsDisabledCfg.updateTimeStamp(); + } + + saveDisabled(); +} + +void Folder::saveDisabled() +{ + if(itsDisabledCfg.dirty) + { + if(!itsIsSystem || Misc::root()) + { + KFI_DBUG << itsDisabledCfg.name; + + KSaveFile file; + + file.setFileName(itsDisabledCfg.name); + + if(!file.open()) + { + KFI_DBUG << "Exit - cant open save file"; + qApp->exit(0); + } + + QTextStream str(&file); + + str << "<"DISABLED_FONTS">" << endl; + + FamilyCont::ConstIterator it(itsFonts.begin()), + end(itsFonts.end()); + + for(; it!=end; ++it) + (*it).toXml(true, str); + str << "" << endl; + str.flush(); + + if(!file.finalize()) + { + KFI_DBUG << "Exit - cant finalize save file"; + qApp->exit(0); + } + } + itsDisabledCfg.updateTimeStamp(); + itsDisabledCfg.dirty=false; + } +} + +QStringList Folder::toXml(int max) +{ + QStringList rv; + FamilyCont::ConstIterator it(itsFonts.begin()), + end(itsFonts.end()); + QString string; + QTextStream str(&string); + + for(int i=0; it!=end; ++it, ++i) + { + if(0==(i%max)) + { + if(i) + { + str << "" << endl; + rv.append(string); + string=QString(); + } + str << "<"FONTLIST_TAG" " << SYSTEM_ATTR"=\"" << (itsIsSystem ? "true" : "false") << "\">" << endl; + } + + (*it).toXml(false, str); + } + + if(!string.isEmpty()) + { + str << "" << endl; + rv.append(string); + } + return rv; +} + +Families Folder::list() +{ + Families fam(itsIsSystem); + FamilyCont::ConstIterator it(itsFonts.begin()), + end(itsFonts.end()); + + for(int i=0; it!=end; ++it, ++i) + fam.items.insert(*it); + + return fam; +} + +bool Folder::contains(const QString &family, quint32 style) +{ + FamilyCont::ConstIterator fam=itsFonts.find(Family(family)); + + if(fam==itsFonts.end()) + return false; + + StyleCont::ConstIterator st=(*fam).styles().find(Style(style)); + + return st!=(*fam).styles().end(); +} + +void Folder::add(const Family &family) +{ + FamilyCont::ConstIterator existingFamily=itsFonts.find(family); + + if(existingFamily==itsFonts.end()) + itsFonts.insert(family); + else + { + StyleCont::ConstIterator it(family.styles().begin()), + end(family.styles().end()); + + for(; it!=end; ++it) + { + StyleCont::ConstIterator existingStyle=(*existingFamily).styles().find(*it); + + if(existingStyle==(*existingFamily).styles().end()) + (*existingFamily).add(*it); + else + { + FileCont::ConstIterator fit((*it).files().begin()), + fend((*it).files().end()); + + for(; fit!=fend; ++fit) + { + FileCont::ConstIterator f=(*existingStyle).files().find(*fit); + + if(f==(*existingStyle).files().end()) + (*existingStyle).add(*fit); + } + + (*existingStyle).setWritingSystems((*existingStyle).writingSystems()|(*it).writingSystems()); + if(!(*existingStyle).scalable() && (*it).scalable()) + (*existingStyle).setScalable(true); + } + } + } +} + +void Folder::configure(bool force) +{ +KFI_DBUG << "EMPTY MODIFIED " << itsModifiedDirs.isEmpty(); + + if(force || !itsModifiedDirs.isEmpty()) + { + saveDisabled(); + + QSet::ConstIterator it(itsModifiedDirs.constBegin()), + end(itsModifiedDirs.constEnd()); + QSet dirs; + + for(; it!=end; ++it) + if(Misc::fExists((*it)+"fonts.dir")) + dirs.insert(KShell::quoteArg(*it)); + + if(!dirs.isEmpty()) + QProcess::startDetached(QLatin1String(KFONTINST_LIB_EXEC_DIR"/fontinst_x11"), dirs.toList()); + + itsModifiedDirs.clear(); + +KFI_DBUG << "RUN FC"; + Misc::doCmd("fc-cache"); +KFI_DBUG << "DONE"; + } +} + +Folder::Flat Folder::flatten() const +{ + FamilyCont::ConstIterator fam=itsFonts.begin(), + famEnd=itsFonts.end(); + Flat rv; + + for(; fam!=famEnd; ++fam) + { + StyleCont::ConstIterator style((*fam).styles().begin()), + styleEnd((*fam).styles().end()); + + for(; style!=styleEnd; ++style) + { + FileCont::ConstIterator file((*style).files().begin()), + fileEnd((*style).files().end()); + + for(; file!=fileEnd; ++file) + rv.insert(FlatFont(*fam, *style, *file)); + } + } + + return rv; +} + +Families Folder::Flat::build(bool system) const +{ + ConstIterator it(begin()), + e(end()); + Families families(system); + + for(; it!=e; ++it) + { + Family f((*it).family); + Style s((*it).styleInfo, (*it).scalable, (*it).writingSystems); + FamilyCont::ConstIterator fam=families.items.constFind(f); + + if(families.items.constEnd()==fam) + { + s.add((*it).file); + f.add(s); + families.items.insert(f); + } + else + { + StyleCont::ConstIterator st=(*fam).styles().constFind(s); + + if((*fam).styles().constEnd()==st) + { + s.add((*it).file); + (*fam).add(s); + } + else + (*st).add((*it).file); + } + } + + return families; +} + +} diff --git a/kcontrol/kfontinst/dbus/Folder.h b/kcontrol/kfontinst/dbus/Folder.h new file mode 100644 index 00000000..63725d16 --- /dev/null +++ b/kcontrol/kfontinst/dbus/Folder.h @@ -0,0 +1,114 @@ +#ifndef FOLDER_H +#define FOLDER_H + +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2009 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include "Family.h" +#include "Style.h" +#include "File.h" +#include "Misc.h" + +namespace KFI +{ + +class Folder +{ + struct CfgFile + { + bool modified(); + void updateTimeStamp(); + + bool dirty; + QString name; + time_t timestamp; + }; + + public: + + struct FlatFont : Misc::TFont + { + FlatFont(const Family &fam, const Style &style, const File &f) + : Misc::TFont(fam.name(), style.value()), + writingSystems(style.writingSystems()), + scalable(style.scalable()), + file(f) + { + } + bool operator==(const FlatFont &o) const { return file.path()==o.file.path(); } + + qulonglong writingSystems; + bool scalable; + File file; + }; + + struct Flat : public QSet + { + Families build(bool system) const; + }; + + Folder() { } + ~Folder(); + + void init(bool system, bool systemBus); + const QString & location() const { return itsLocation; } + bool allowToggling() const; + void loadDisabled(); + void saveDisabled(); + void setDisabledDirty() { itsDisabledCfg.dirty=true; } + bool disabledDirty() const { return itsDisabledCfg.dirty; } + QStringList toXml(int max=0); + Families list(); + bool contains(const QString &family, quint32 style); + void add(const Family &family); + void addModifiedDir(const QString &dir) { itsModifiedDirs.insert(dir); } + void addModifiedDirs(const QSet &dirs) { itsModifiedDirs+=dirs; } + bool isModified() const { return !itsModifiedDirs.isEmpty(); } + void clearModified() { itsModifiedDirs.clear(); } + void configure(bool force=false); + Flat flatten() const; + const FamilyCont & fonts() const { return itsFonts; } + FamilyCont::ConstIterator addFont(const Family &fam) { return itsFonts.insert(fam); } + void removeFont(const Family &fam) { itsFonts.remove(fam); } + void clearFonts() { itsFonts.clear(); } + + private: + + bool itsIsSystem; + FamilyCont itsFonts; + CfgFile itsDisabledCfg; + QString itsLocation; + QSet itsModifiedDirs; +}; + +inline KDE_EXPORT uint qHash(const Folder::FlatFont &key) +{ + return qHash(key.file); // +qHash(key.index()); +} + +} + +#endif diff --git a/kcontrol/kfontinst/dbus/FontInst.cpp b/kcontrol/kfontinst/dbus/FontInst.cpp new file mode 100644 index 00000000..ef6c5b8d --- /dev/null +++ b/kcontrol/kfontinst/dbus/FontInst.cpp @@ -0,0 +1,971 @@ +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2009 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "FontInst.h" +#include "fontinstadaptor.h" +#include "Misc.h" +#include "Fc.h" +#include "WritingSystems.h" +#include "Utils.h" +#include "FontinstIface.h" + +#define KFI_DBUG kDebug() << time(0L) + +namespace KFI +{ + +static void decompose(const QString &name, QString &family, QString &style) +{ + int commaPos=name.lastIndexOf(','); + + family=-1==commaPos ? name : name.left(commaPos); + style=-1==commaPos ? KFI_WEIGHT_REGULAR : name.mid(commaPos+2); +} + +static bool isSystem=false; +static Folder theFolders[FontInst::FOLDER_COUNT]; +static const int constSystemReconfigured=-1; +static const int constConnectionsTimeout = 30 * 1000; +static const int constFontListTimeout = 10 * 1000; + +typedef void (*SignalHandler)(int); + +static void registerSignalHandler(SignalHandler handler) +{ + if (!handler) + handler = SIG_DFL; + + sigset_t mask; + sigemptyset(&mask); + +#ifdef SIGSEGV + signal(SIGSEGV, handler); + sigaddset(&mask, SIGSEGV); +#endif +#ifdef SIGFPE + signal(SIGFPE, handler); + sigaddset(&mask, SIGFPE); +#endif +#ifdef SIGILL + signal(SIGILL, handler); + sigaddset(&mask, SIGILL); +#endif +#ifdef SIGABRT + signal(SIGABRT, handler); + sigaddset(&mask, SIGABRT); +#endif + + sigprocmask(SIG_UNBLOCK, &mask, 0); +} + +void signalHander(int) +{ + static bool inHandler=false; + + if(!inHandler) + { + inHandler=true; + theFolders[isSystem ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER].saveDisabled(); + inHandler=false; + } +} + +FontInst::FontInst() +{ + isSystem=Misc::root(); + registerTypes(); + + new FontinstAdaptor(this); + QDBusConnection bus=QDBusConnection::sessionBus(); + + KFI_DBUG << "Connecting to session bus"; + if(!bus.registerService(OrgKdeFontinstInterface::staticInterfaceName())) + { + KFI_DBUG << "Failed to register service!"; + ::exit(-1); + } + if(!bus.registerObject(FONTINST_PATH, this)) + { + KFI_DBUG << "Failed to register object!"; + ::exit(-1); + } + + registerSignalHandler(signalHander); + itsConnectionsTimer=new QTimer(this); + itsFontListTimer=new QTimer(this); + connect(itsConnectionsTimer, SIGNAL(timeout()), SLOT(connectionsTimeout())); + connect(itsFontListTimer, SIGNAL(timeout()), SLOT(fontListTimeout())); + itsConnectionsTimer->start(constConnectionsTimeout); + itsFontListTimer->start(constFontListTimeout); + + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) + theFolders[i].init(FOLDER_SYS==i, isSystem); + + updateFontList(false); +} + +FontInst::~FontInst() +{ + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) + theFolders[i].saveDisabled(); +} + +void FontInst::list(int folders, int pid) +{ + KFI_DBUG << folders << pid; + + itsConnections.insert(pid); + updateFontList(false); + QList fonts; + + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) + if(0==folders || folders&(1<start(constConnectionsTimeout); + itsFontListTimer->start(constFontListTimeout); + emit fontList(pid, fonts); +} + +void FontInst::stat(const QString &name, int folders, int pid) +{ + KFI_DBUG << name << folders << pid; + + bool checkSystem=0==folders || folders&SYS_MASK || isSystem, + checkUser=0==folders || (folders&USR_MASK && !isSystem); + FamilyCont::ConstIterator fam; + StyleCont::ConstIterator st; + + itsConnections.insert(pid); + if( (checkSystem && findFont(name, FOLDER_SYS, fam, st)) || + (checkUser && findFont(name, FOLDER_USER, fam, st, !checkSystem)) ) + { + Family rv((*fam).name()); + rv.add(*st); + KFI_DBUG << "Found font, emit details..."; + emit fontStat(pid, rv); + } + else + { + KFI_DBUG << "Font not found, emit empty details..."; + emit fontStat(pid, Family(name)); + } +} + +void FontInst::install(const QString &file, bool createAfm, bool toSystem, int pid, bool checkConfig) +{ + KFI_DBUG << file << createAfm << toSystem << pid << checkConfig; + + itsConnections.insert(pid); + + if(checkConfig) + updateFontList(); + + EFolder folder=isSystem || toSystem ? FOLDER_SYS : FOLDER_USER; + Family font; + Utils::EFileType type=Utils::check(file, font); + + int result=Utils::FILE_BITMAP==type && !FC::bitmapsEnabled() + ? STATUS_BITMAPS_DISABLED + : Utils::FILE_INVALID==type + ? STATUS_NOT_FONT_FILE + : STATUS_OK; + + if(STATUS_OK==result) + { + if(Utils::FILE_AFM!=type && Utils::FILE_PFM!=type) + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT) && STATUS_OK==result; ++i) + if(theFolders[i].contains(font.name(), (*font.styles().begin()).value())) + result=STATUS_ALREADY_INSTALLED; + + if(STATUS_OK==result) + { + QString name(Misc::modifyName(Misc::getFile(file))), + destFolder(Misc::getDestFolder(theFolders[folder].location(), name)); + + result=Utils::FILE_AFM!=type && Utils::FILE_PFM!=type && Misc::fExists(destFolder+name) ? (int)KIO::ERR_FILE_ALREADY_EXIST : (int)STATUS_OK; + if(STATUS_OK==result) + { + if(toSystem && !isSystem) + { + KFI_DBUG << "Send request to system helper" << file << destFolder << name; + QVariantMap args; + args["method"] = "install"; + args["file"] = file; + args["name"] = name; + args["destFolder"] = destFolder; + args["createAfm"] = createAfm; + args["type"] = (int)type; + result=performAction(args); + } + else + { + if(!Misc::dExists(destFolder)) + result=Misc::createDir(destFolder) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; + + if(STATUS_OK==result) + result=QFile::copy(file, destFolder+name) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; + + if(STATUS_OK==result) + { + Misc::setFilePerms(QFile::encodeName(destFolder+name)); + if((Utils::FILE_SCALABLE==type || Utils::FILE_PFM==type) && createAfm) + Utils::createAfm(destFolder+name, type); + } + } + + if(STATUS_OK==result && Utils::FILE_AFM!=type && Utils::FILE_PFM!=type) + { + StyleCont::ConstIterator st(font.styles().begin()); + FileCont::ConstIterator f((*st).files().begin()); + File df(destFolder+name, (*f).foundry(), (*f).index()); + + (*st).clearFiles(); + (*st).add(df); + theFolders[folder].add(font); + theFolders[folder].addModifiedDir(destFolder); + emit fontsAdded(Families(font, FOLDER_SYS==folder)); + } + } + } + } + + emit status(pid, result); + itsConnectionsTimer->start(constConnectionsTimeout); + itsFontListTimer->start(constFontListTimeout); +} + +void FontInst::uninstall(const QString &family, quint32 style, bool fromSystem, int pid, bool checkConfig) +{ + KFI_DBUG << family << style << fromSystem << pid << checkConfig; + + itsConnections.insert(pid); + + if(checkConfig) + updateFontList(); + + EFolder folder=isSystem || fromSystem ? FOLDER_SYS : FOLDER_USER; + FamilyCont::ConstIterator fam; + StyleCont::ConstIterator st; + int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST; + + if(STATUS_OK==result) + { + Family del((*fam).name()); + Style s((*st).value(), (*st).scalable(), (*st).writingSystems()); + FileCont files((*st).files()); + FileCont::ConstIterator it(files.begin()), + end(files.end()); + + if(fromSystem && !isSystem) + { + QStringList fileList; + bool wasDisabled(false); + + for(; it!=end; ++it) + { + fileList.append((*it).path()); + theFolders[FOLDER_SYS].addModifiedDir(Misc::getDir((*it).path())); + if(!wasDisabled && Misc::isHidden(Misc::getFile((*it).path()))) + wasDisabled=true; + } + QVariantMap args; + args["method"] = "uninstall"; + args["files"] = fileList; + result=performAction(args); + + if(STATUS_OK==result) + { + FileCont empty; + s.setFiles(files); + (*st).setFiles(empty); + if(wasDisabled) + theFolders[FOLDER_SYS].setDisabledDirty(); + } + } + else + { + for(; it!=end; ++it) + if(!Misc::fExists((*it).path()) || QFile::remove((*it).path())) + { + // Also remove any AFM or PFM files... + QStringList other; + Misc::getAssociatedFiles((*it).path(), other); + QStringList::ConstIterator oit(other.constBegin()), + oend(other.constEnd()); + for(; oit!=oend; ++oit) + QFile::remove(*oit); + + theFolders[folder].addModifiedDir(Misc::getDir((*it).path())); + (*st).remove(*it); + s.add(*it); + if(!theFolders[folder].disabledDirty() && Misc::isHidden(Misc::getFile((*it).path()))) + theFolders[folder].setDisabledDirty(); + } + } + + if(STATUS_OK==result) + { + if((*st).files().isEmpty()) + { + (*fam).remove(*st); + if((*fam).styles().isEmpty()) + theFolders[folder].removeFont(*fam); + } + else + result=STATUS_PARTIAL_DELETE; + del.add(s); + } + emit fontsRemoved(Families(del, FOLDER_SYS==folder)); + + } + KFI_DBUG << "status" << result; + emit status(pid, result); + + itsConnectionsTimer->start(constConnectionsTimeout); + itsFontListTimer->start(constFontListTimeout); +} + +void FontInst::uninstall(const QString &name, bool fromSystem, int pid, bool checkConfig) +{ + KFI_DBUG << name << fromSystem << pid << checkConfig; + + FamilyCont::ConstIterator fam; + StyleCont::ConstIterator st; + if(findFont(name, fromSystem || isSystem ? FOLDER_SYS : FOLDER_USER, fam, st)) + uninstall((*fam).name(), (*st).value(), fromSystem, pid, checkConfig); + else + emit status(pid, KIO::ERR_DOES_NOT_EXIST); +} + +void FontInst::move(const QString &family, quint32 style, bool toSystem, int pid, bool checkConfig) +{ + KFI_DBUG << family << style << toSystem << pid << checkConfig; + + itsConnections.insert(pid); + if(checkConfig) + updateFontList(); + + if(isSystem) + emit status(pid, KIO::ERR_UNSUPPORTED_ACTION); + else + { + FamilyCont::ConstIterator fam; + StyleCont::ConstIterator st; + EFolder from=toSystem ? FOLDER_USER : FOLDER_SYS, + to=toSystem ? FOLDER_SYS : FOLDER_USER; + + if(findFont(family, style, from, fam, st)) + { + FileCont::ConstIterator it((*st).files().begin()), + end((*st).files().end()); + QStringList files; + + for(; it!=end; ++it) + { + files.append((*it).path()); + theFolders[from].addModifiedDir(Misc::getDir((*it).path())); + // Actual 'to' folder does not really matter, as we only want to call fc-cache + // ...actual folders only matter for xreating fonts.dir, etc, and we wont be doing this... + theFolders[to].addModifiedDir(theFolders[to].location()); + } + + QVariantMap args; + args["method"] = "move"; + args["files"] = files; + args["toSystem"] = toSystem; + args["dest"] = theFolders[to].location(); + args["uid"] = getuid(); + args["gid"] = getgid(); + int result=performAction(args); + + if(STATUS_OK==result) + updateFontList(); + emit status(pid, result); + } + else + { + KFI_DBUG << "does not exist"; + emit status(pid, KIO::ERR_DOES_NOT_EXIST); + } + } + + itsConnectionsTimer->start(constConnectionsTimeout); + itsFontListTimer->start(constFontListTimeout); +} + +static bool renameFontFile(const QString &from, const QString &to, int uid=-1, int gid=-1) +{ + QByteArray src(QFile::encodeName(from)), + dest(QFile::encodeName(to)); + + if(KDE_rename(src.data(), dest.data())) + return false; + + Misc::setFilePerms(dest); + if(-1!=uid && -1!=gid) + ::chown(dest.data(), uid, gid); + return true; +} + +void FontInst::enable(const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig) +{ + KFI_DBUG << family << style << inSystem << pid << checkConfig; + toggle(true, family, style, inSystem, pid, checkConfig); +} + +void FontInst::disable(const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig) +{ + KFI_DBUG << family << style << inSystem << pid << checkConfig; + toggle(false, family, style, inSystem, pid, checkConfig); +} + +void FontInst::removeFile(const QString &family, quint32 style, const QString &file, bool fromSystem, int pid, + bool checkConfig) +{ + KFI_DBUG << family << style << file << fromSystem << pid << checkConfig; + + itsConnections.insert(pid); + + if(checkConfig) + updateFontList(); + + // First find the family/style + EFolder folder=isSystem || fromSystem ? FOLDER_SYS : FOLDER_USER; + FamilyCont::ConstIterator fam; + StyleCont::ConstIterator st; + int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST; + + if(STATUS_OK==result) + { + // Family/style found - now check that the requested file is *within* the same folder as one + // of the files linked to this font... + FileCont files((*st).files()); + FileCont::ConstIterator it(files.begin()), + end(files.end()); + QString dir(Misc::getDir(file)); + + result=KIO::ERR_DOES_NOT_EXIST; + for(; it!=end && STATUS_OK!=result; ++it) + if(Misc::getDir((*it).path())==dir) + result=STATUS_OK; + + if(STATUS_OK==result) + { + // OK, found folder - so can now proceed to delete the file... + if(fromSystem && !isSystem) + { + QVariantMap args; + args["method"] = "removeFile"; + args["file"] = file; + result=performAction(args); + } + else + { + result=Misc::fExists(file) + ? QFile::remove(file) + ? (int)STATUS_OK + : (int)KIO::ERR_WRITE_ACCESS_DENIED + : (int)KIO::ERR_DOES_NOT_EXIST; + } + + if(STATUS_OK==result) + theFolders[folder].addModifiedDir(dir); + } + } + + emit status(pid, result); +} + +void FontInst::reconfigure(int pid, bool force) +{ + KFI_DBUG << pid << force; + bool sysModified(theFolders[FOLDER_SYS].isModified()); + + saveDisabled(); + + KFI_DBUG << theFolders[FOLDER_USER].isModified() << sysModified; + if(!isSystem && (force || theFolders[FOLDER_USER].isModified())) + theFolders[FOLDER_USER].configure(force); + + if(sysModified) + { + if(isSystem) + { + theFolders[FOLDER_SYS].configure(); + } + else + { + QVariantMap args; + args["method"] = "reconfigure"; + performAction(args); + theFolders[FOLDER_SYS].clearModified(); + } + } + + itsConnectionsTimer->start(constConnectionsTimeout); + itsFontListTimer->start(constFontListTimeout); + + updateFontList(); + emit status(pid, isSystem ? constSystemReconfigured : STATUS_OK); +} + +QString FontInst::folderName(bool sys) +{ + return theFolders[sys || isSystem ? FOLDER_SYS : FOLDER_USER].location(); +} + +void FontInst::saveDisabled() +{ + if(isSystem) + theFolders[FOLDER_SYS].saveDisabled(); + else + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) + if(FOLDER_SYS==i && !isSystem) + { + if(theFolders[i].disabledDirty()) + { + QVariantMap args; + args["method"] = "saveDisabled"; + performAction(args); + theFolders[i].saveDisabled(); + } + } + else + theFolders[i].saveDisabled(); +} + +void FontInst::connectionsTimeout() +{ + bool canExit(true); + + KFI_DBUG << "exiting"; + checkConnections(); + + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) + { + if(theFolders[i].disabledDirty()) + canExit=false; + theFolders[i].saveDisabled(); + } + + if(0==itsConnections.count()) + { + if(canExit) + qApp->exit(0); + else // Try again later... + itsConnectionsTimer->start(constConnectionsTimeout); + } +} + +void FontInst::fontListTimeout() +{ + updateFontList(true); + itsFontListTimer->start(constFontListTimeout); +} + +void FontInst::updateFontList(bool emitChanges) +{ + // For some reason just the "!FcConfigUptoDate(0)" check does not always work :-( + FcBool fcModified=!FcConfigUptoDate(0); + + if(fcModified || + theFolders[FOLDER_SYS].fonts().isEmpty() || + (!isSystem && theFolders[FOLDER_USER].fonts().isEmpty()) || + theFolders[FOLDER_SYS].disabledDirty() || + (!isSystem && theFolders[FOLDER_USER].disabledDirty())) + { + KFI_DBUG << "Need to refresh font lists"; + if(fcModified) + { + KFI_DBUG << "Re-init FC"; + if(!FcInitReinitialize()) + KFI_DBUG << "Re-init failed????"; + } + + Folder::Flat old[FOLDER_COUNT]; + + if(emitChanges) + { + KFI_DBUG << "Flatten existing font lists"; + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) + old[i]=theFolders[i].flatten(); + } + + saveDisabled(); + + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) + theFolders[i].clearFonts(); + + KFI_DBUG << "update list of fonts"; + + FcPattern *pat = FcPatternCreate(); + FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_FAMILY, FC_FAMILYLANG, + FC_WEIGHT, FC_LANG, FC_CHARSET, FC_SCALABLE, +#ifndef KFI_FC_NO_WIDTHS + FC_WIDTH, +#endif + FC_SLANT, FC_INDEX, FC_FOUNDRY, (void*)0); + + FcFontSet *list=FcFontList(0, pat, os); + + FcPatternDestroy(pat); + FcObjectSetDestroy(os); + + theFolders[FOLDER_SYS].loadDisabled(); + if(!isSystem) + theFolders[FOLDER_USER].loadDisabled(); + + if(list) + { + QString home(Misc::dirSyntax(QDir::homePath())); + + for (int i = 0; i < list->nfont; i++) + { + QString fileName(Misc::fileSyntax(FC::getFcString(list->fonts[i], FC_FILE))); + + if(!fileName.isEmpty() && Misc::fExists(fileName)) // && 0!=fileName.indexOf(constDefomaLocation)) + { + QString family, + foundry; + quint32 styleVal; + int index; + qulonglong writingSystems(WritingSystems::instance()->get(list->fonts[i])); + FcBool scalable=FcFalse; + + if(FcResultMatch!=FcPatternGetBool(list->fonts[i], FC_SCALABLE, 0, &scalable)) + scalable=FcFalse; + + FC::getDetails(list->fonts[i], family, styleVal, index, foundry); + FamilyCont::ConstIterator fam=theFolders[isSystem || 0!=fileName.indexOf(home) + ? FOLDER_SYS : FOLDER_USER].addFont(Family(family)); + StyleCont::ConstIterator style=(*fam).add(Style(styleVal)); + FileCont::ConstIterator file=(*style).add(File(fileName, foundry, index)); + + (*style).setWritingSystems((*style).writingSystems()|writingSystems); + if(scalable) + (*style).setScalable(); + } + } + + FcFontSetDestroy(list); + } + + if(emitChanges) + { + KFI_DBUG << "Look for differences"; + for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) + { + KFI_DBUG << "Flatten, and take copies..."; + Folder::Flat newList=theFolders[i].flatten(), + onlyNew=newList; + + KFI_DBUG << "Determine differences..."; + onlyNew.subtract(old[i]); + old[i].subtract(newList); + + KFI_DBUG << "Emit changes..."; + Families families=onlyNew.build(isSystem || i==FOLDER_SYS); + + if(!families.items.isEmpty()) + emit fontsAdded(families); + + families=old[i].build(isSystem || i==FOLDER_SYS); + if(!families.items.isEmpty()) + emit fontsRemoved(families); + } + } + KFI_DBUG << "updated list of fonts"; + } +} + +void FontInst::toggle(bool enable, const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig) +{ + KFI_DBUG; + itsConnections.insert(pid); + + if(checkConfig) + updateFontList(); + + EFolder folder=isSystem || inSystem ? FOLDER_SYS : FOLDER_USER; + FamilyCont::ConstIterator fam; + StyleCont::ConstIterator st; + int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST; + + if(STATUS_OK==result) + { + FileCont files((*st).files()), + toggledFiles; + FileCont::ConstIterator it(files.begin()), + end(files.end()); + QHash movedFonts; + QHash movedAssoc; + QSet modifiedDirs; + + for(; it!=end && STATUS_OK==result; ++it) + { + QString to=Misc::getDir((*it).path())+ + QString(enable ? Misc::unhide(Misc::getFile((*it).path())) + : Misc::hide(Misc::getFile((*it).path()))); + if(to!=(*it).path()) + { + KFI_DBUG << "MOVE:" << (*it).path() << " to " << to; + // If the font is a system font, and we're not root, then just go through the actions here - so + // that we can build the list of changes that would happen... + if((inSystem && !isSystem) || renameFontFile((*it).path(), to)) + { + modifiedDirs.insert(Misc::getDir(enable ? to : (*it).path())); + toggledFiles.insert(File(to, (*it).foundry(), (*it).index())); + // Now try to move an associated AFM or PFM files... + QStringList assoc; + + movedFonts[*it]=to; + Misc::getAssociatedFiles((*it).path(), assoc); + + QStringList::ConstIterator ait(assoc.constBegin()), + aend(assoc.constEnd()); + + for(; ait!=aend && STATUS_OK==result; ++ait) + { + to=Misc::getDir(*ait)+ + QString(enable ? Misc::unhide(Misc::getFile(*ait)) + : Misc::hide(Misc::getFile(*ait))); + + if(to!=*ait) + { + if((inSystem && !isSystem) || renameFontFile(*ait, to)) + { + movedAssoc[*ait]=to; + } + else + { + result=KIO::ERR_WRITE_ACCESS_DENIED; + } + } + } + } + else + { + result=KIO::ERR_WRITE_ACCESS_DENIED; + } + } + } + + if(inSystem && !isSystem) + { + Family toggleFam((*fam).name()); + + toggleFam.add(*st); + QVariantMap args; + args["method"] = "toggle"; + QString xml; + QTextStream str(&xml); + toggleFam.toXml(false, str); + args["xml"] = xml; + args["enable"] = enable; + result=performAction(args); + } + + if(STATUS_OK==result) + { + Family addFam((*fam).name()), + delFam((*fam).name()); + Style addStyle((*st).value(), (*st).scalable(), (*st).writingSystems()), + delStyle((*st).value(), (*st).scalable(), (*st).writingSystems()); + + addStyle.setFiles(toggledFiles); + addFam.add(addStyle); + delStyle.setFiles(files); + delFam.add(delStyle); + (*st).setFiles(toggledFiles); + + theFolders[folder].addModifiedDirs(modifiedDirs); + emit fontsAdded(Families(addFam, FOLDER_SYS==folder)); + emit fontsRemoved(Families(delFam, FOLDER_SYS==folder)); + + theFolders[folder].setDisabledDirty(); + } + else // un-move fonts! + { + QHash::ConstIterator fit(movedFonts.constBegin()), + fend(movedFonts.constEnd()); + QHash::ConstIterator ait(movedAssoc.constBegin()), + aend(movedAssoc.constEnd()); + + for(; fit!=fend; ++fit) + renameFontFile(fit.value(), fit.key().path()); + for(; ait!=aend; ++ait) + renameFontFile(ait.value(), ait.key()); + } + } + emit status(pid, result); + + itsConnectionsTimer->start(constConnectionsTimeout); + itsFontListTimer->start(constFontListTimeout); +} + +void FontInst::addModifedSysFolders(const Family &family) +{ + StyleCont::ConstIterator style(family.styles().begin()), + styleEnd(family.styles().end()); + + for(; style!=styleEnd; ++style) + { + FileCont::ConstIterator file((*style).files().begin()), + fileEnd((*style).files().end()); + + for(; file!=fileEnd; ++file) + theFolders[FOLDER_SYS].addModifiedDir(Misc::getDir((*file).path())); + } +} + +void FontInst::checkConnections() +{ + KFI_DBUG; + QSet::ConstIterator it(itsConnections.begin()), + end(itsConnections.end()); + QSet remove; + + for(; it!=end; ++it) + if(0!=kill(*it, 0)) + remove.insert(*it); + itsConnections.subtract(remove); +} + +bool FontInst::findFontReal(const QString &family, const QString &style, EFolder folder, + FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st) +{ + KFI_DBUG; + Family f(family); + fam=theFolders[folder].fonts().find(f); + if(theFolders[folder].fonts().end()==fam) + return false; + + StyleCont::ConstIterator end((*fam).styles().end()); + for(st=(*fam).styles().begin(); st!=end; ++st) + if(FC::createStyleName((*st).value())==style) + return true; + + return false; +} + +bool FontInst::findFont(const QString &font, EFolder folder, + FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st, + bool updateList) +{ + KFI_DBUG; + QString family, + style; + + decompose(font, family, style); + + if(!findFontReal(family, style, folder, fam, st)) + { + if(updateList) + { + // Not found, so refresh font list and try again... + updateFontList(); + return findFontReal(family, style, folder, fam, st); + } + else + { + return false; + } + } + + return true; +} + +bool FontInst::findFontReal(const QString &family, quint32 style, EFolder folder, + FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st) +{ + KFI_DBUG; + fam=theFolders[folder].fonts().find(Family(family)); + + if(theFolders[folder].fonts().end()==fam) + return false; + else + { + st=(*fam).styles().find(style); + + return (*fam).styles().end()!=st; + } +} + +bool FontInst::findFont(const QString &family, quint32 style, EFolder folder, + FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st, + bool updateList) +{ + KFI_DBUG; + if(!findFontReal(family, style, folder, fam, st)) + { + if(updateList) + { + // Not found, so refresh font list and try again... + updateFontList(); + return findFontReal(family, style, folder, fam, st); + } + else + { + return false; + } + } + return true; +} + +int FontInst::performAction(const QVariantMap &args) +{ + KAuth::Action action("org.kde.fontinst.manage"); + + action.setHelperID("org.kde.fontinst"); + action.setArguments(args); + KFI_DBUG << "Call " << args["method"].toString() << " on helper"; + itsFontListTimer->stop(); + itsConnectionsTimer->stop(); + KAuth::ActionReply reply = action.execute(); + + switch(reply.type()) + { + case KAuth::ActionReply::KAuthError: + KFI_DBUG << "KAuth failed - error code:" << reply.errorCode(); + return KIO::ERR_COULD_NOT_AUTHENTICATE; + case KAuth::ActionReply::HelperError: + KFI_DBUG << "Helper failed - error code:" << reply.errorCode(); + return (int)reply.errorCode(); + } + + KFI_DBUG << "Success!"; + return STATUS_OK; +} + +} diff --git a/kcontrol/kfontinst/dbus/FontInst.h b/kcontrol/kfontinst/dbus/FontInst.h new file mode 100644 index 00000000..e53ee6aa --- /dev/null +++ b/kcontrol/kfontinst/dbus/FontInst.h @@ -0,0 +1,162 @@ +#ifndef FONTINST_H +#define FONTINST_H + +/* + * KFontInst - KDE Font Installer + * + * Copyright 2003-2009 Craig Drummond + * + * ---- + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include "Family.h" +#include "Folder.h" +#include "FontinstIface.h" +#include "kfontinst_export.h" + +#define FONTINST_PATH "/FontInst" + +class QTimer; + +namespace KFI +{ + +class KFONTINST_EXPORT FontInst : public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.fontinst") + + public: + + enum EStatus + { + STATUS_OK=0, + STATUS_SERVICE_DIED = KJob::UserDefinedError+500, + STATUS_BITMAPS_DISABLED, + STATUS_ALREADY_INSTALLED, + STATUS_NOT_FONT_FILE, + STATUS_PARTIAL_DELETE, + STATUS_NO_SYS_CONNECTION + }; + + enum EFolder + { + FOLDER_SYS, + FOLDER_USER, + + FOLDER_COUNT + }; + + enum + { + SYS_MASK=0x01, + USR_MASK=0x02 + }; + + static void registerTypes() + { + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType" +#define START_BASIC "" +#define START_TABLE "" +#define INFO_ROW "" +#define END_TABLE "
%1:%2
" +#define END "" + +HWInfo::HWInfo(QObject *parent, const QVariantList &args) + : SM::Applet(parent, args), m_info(0), m_icon(0) +{ + resize(234 + 20 + 23, 135 + 20 + 25); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(updateHtml())); +} + +HWInfo::~HWInfo() +{ +} + +void HWInfo::init() +{ + KGlobal::locale()->insertCatalog("plasma_applet_system-monitor"); + setTitle(i18n("Hardware Info")); + setEngine(dataEngine("soliddevice")); + setSources(); + connectToEngine(); +} + +bool HWInfo::addVisualization(const QString& source) +{ + if (mode() != SM::Applet::Panel) { + if (!m_info) { + m_info = new Plasma::TextBrowser(this); + m_info->nativeWidget()->setHtml(QString(START + i18n("Getting hardware information...") + END)); + appendVisualization(source, m_info); + //m_info->nativeWidget()->document()->setTextWidth(contentsRect().width()); + //setPreferredItemHeight(m_info->nativeWidget()->document()->size().height()); + setPreferredItemHeight(135); + } + } else { + if (!m_icon) { + m_icon = new Plasma::IconWidget(KIcon(icon()), "", this); + appendVisualization(source, m_icon); + } + } + return true; +} + +void HWInfo::deleteVisualizations() +{ + SM::Applet::deleteVisualizations(); + m_icon = 0; + m_info = 0; +} + +void HWInfo::setSources() +{ + m_cpus = engine()->query("IS Processor")["IS Processor"].toStringList(); + foreach (const QString& id, m_cpus) { + appendSource(id); + } + m_networks = engine()->query("IS NetworkInterface")["IS NetworkInterface"].toStringList(); + foreach (const QString& id, m_networks) { + appendSource(id); + } + m_audios = engine()->query("IS AudioInterface")["IS AudioInterface"].toStringList(); + foreach (const QString& id, m_audios) { + appendSource(id); + } + // TODO: get this from soliddevice + Plasma::DataEngine* engine = dataEngine("executable"); + QString path = QString::fromLocal8Bit(qgetenv("PATH")) + + QString::fromLatin1(":/usr/sbin:/sbin/"); + QString exe = KStandardDirs::findExe( "lspci", path ); + if (exe.isEmpty()) { + kError() << "lspci not found in " << path << endl; + } else { + QString tmp = exe + " | grep VGA | sed 's/.*: //g'"; + engine->connectSource(tmp, this); + } +} + +void HWInfo::dataUpdated(const QString& source, + const Plasma::DataEngine::Data &data) +{ + if (m_audios.contains(source) && !m_audioNames.contains(data["Name"].toString()) && + !data["Name"].toString().isEmpty()) { + m_audioNames.append(data["Name"].toString()); + } else if (m_networks.contains(source) && !m_networkNames.contains(data["Product"].toString()) && + !data["Product"].toString().isEmpty()) { + m_networkNames.append(data["Product"].toString()); + } else if (m_cpus.contains(source) && !m_cpuNames.contains(data["Product"].toString()) && + !data["Product"].toString().isEmpty()) { + m_cpuNames.append(data["Product"].toString().trimmed()); + } else if (source.indexOf("VGA") > -1) { + m_gpu = data["stdout"].toString().trimmed(); + } + updateHtml(); +} + +void HWInfo::updateHtml() +{ + QString html; + foreach(const QString& cpu, m_cpuNames) { + html += QString(INFO_ROW).arg(i18n("CPU")).arg(cpu); + } + html += QString(INFO_ROW).arg(i18n("GPU")).arg(m_gpu); + foreach(const QString& audio, m_audioNames) { + html += QString(INFO_ROW).arg(i18n("Audio")).arg(audio); + } + foreach(const QString& network, m_networkNames) { + html += QString(INFO_ROW).arg(i18n("Network")).arg(network); + } + html += END_TABLE END; + if (m_info) { + Plasma::Theme* theme = Plasma::Theme::defaultTheme(); + html = QString(START START_TABLE) + .arg(theme->color(Plasma::Theme::TextColor).name()) + html; + m_info->nativeWidget()->setHtml(html); + } else if (m_icon) { + html = START_BASIC START_TABLE + html; + Plasma::ToolTipContent data(i18n("Hardware Info"), html); + Plasma::ToolTipManager::self()->setContent(m_icon, data); + } +} + +#include "hwinfo.moc" diff --git a/plasma/generic/applets/system-monitor/hwinfo.h b/plasma/generic/applets/system-monitor/hwinfo.h new file mode 100644 index 00000000..e9fa4821 --- /dev/null +++ b/plasma/generic/applets/system-monitor/hwinfo.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 Petri Damsten + * Copyright (C) 2010 Michel Lafon-Puyo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef HWINFO_HEADER +#define HWINFO_HEADER + +#include +#include + +namespace Plasma { + class TextBrowser; + class IconWidget; +} + +class HWInfo : public SM::Applet +{ + Q_OBJECT + public: + HWInfo(QObject *parent, const QVariantList &args); + ~HWInfo(); + + virtual void init(); + virtual bool addVisualization(const QString&); + + public slots: + void dataUpdated(const QString &name, + const Plasma::DataEngine::Data &data); + + private slots: + void updateHtml(); + + protected: + virtual void deleteVisualizations(); + + private: + void setSources(); + + Plasma::TextBrowser *m_info; + Plasma::IconWidget *m_icon; + QString m_gpu; + QStringList m_cpus; + QStringList m_cpuNames; + QStringList m_networks; + QStringList m_networkNames; + QStringList m_audios; + QStringList m_audioNames; +}; + +K_EXPORT_PLASMA_APPLET(sm_hwinfo, HWInfo) + +#endif diff --git a/plasma/generic/applets/system-monitor/monitorbutton.cpp b/plasma/generic/applets/system-monitor/monitorbutton.cpp new file mode 100644 index 00000000..ee5e5d87 --- /dev/null +++ b/plasma/generic/applets/system-monitor/monitorbutton.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "monitorbutton.h" + +#include +#include +#include + +#include +#include +#include + +#include + +#define MARGIN 2 + +class MonitorButton::Private +{ +public: + Private() : imageSize(32, 32) + { + } + + QSize imageSize; + QString image; + KIcon icon; + QTimeLine highlighter; +}; + +MonitorButton::MonitorButton(QGraphicsWidget *parent) : + Plasma::PushButton(parent), + d(new Private) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + setPreferredSize(d->imageSize.width() + 2 * MARGIN, d->imageSize.height() + 2 * MARGIN); + + d->highlighter.setDuration(100); + d->highlighter.setFrameRange(0, 10); + d->highlighter.setCurveShape(QTimeLine::EaseInCurve); + connect(&d->highlighter, SIGNAL(valueChanged(qreal)), this, SLOT(highlight())); +} + +MonitorButton::~MonitorButton() +{ + delete d; +} + +QString MonitorButton::image() const +{ + return d->image; +} + +void MonitorButton::setImage(const QString &image) +{ + d->image = image; + d->icon = KIcon(image); + update(); +} + +void MonitorButton::highlight() +{ + update(); +} + +void MonitorButton::hoverEnterEvent(QGraphicsSceneHoverEvent * event) +{ + Q_UNUSED(event) + + d->highlighter.setDirection(QTimeLine::Forward); + if (d->highlighter.currentValue() < 1 && + d->highlighter.state() == QTimeLine::NotRunning) { + d->highlighter.start(); + } +} + +void MonitorButton::hoverLeaveEvent(QGraphicsSceneHoverEvent * event) +{ + Q_UNUSED(event) + + d->highlighter.setDirection(QTimeLine::Backward); + + if (d->highlighter.currentValue() > 0 && + d->highlighter.state() == QTimeLine::NotRunning) { + d->highlighter.start(); + } +} + +void MonitorButton::paint(QPainter *p, + const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + Q_UNUSED(option) + Q_UNUSED(widget) + + QIcon::Mode mode = QIcon::Disabled; + if (isChecked()) { + mode = QIcon::Normal; + } + + QPixmap icon = Plasma::PaintUtils::transition(d->icon.pixmap(d->imageSize, QIcon::Disabled), + d->icon.pixmap(d->imageSize, QIcon::Normal), + isChecked() ? 1 : d->highlighter.currentValue()); + p->drawPixmap(QPointF((size().width() - d->imageSize.width()) / 2, + (size().height() - d->imageSize.height()) / 2), + icon); +} + +#include "monitorbutton.moc" diff --git a/plasma/generic/applets/system-monitor/monitorbutton.h b/plasma/generic/applets/system-monitor/monitorbutton.h new file mode 100644 index 00000000..fba0fb90 --- /dev/null +++ b/plasma/generic/applets/system-monitor/monitorbutton.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MONITORBUTTON_HEADER +#define MONITORBUTTON_HEADER + +#include +#include "sm_export.h" + +class SM_EXPORT MonitorButton : public Plasma::PushButton +{ + Q_OBJECT + Q_PROPERTY(QString image READ image WRITE setImage) + +public: + explicit MonitorButton(QGraphicsWidget *parent = 0); + virtual ~MonitorButton(); + + QString image() const; + void setImage(const QString &image); + +protected: + void hoverEnterEvent(QGraphicsSceneHoverEvent * event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent * event); + virtual void paint(QPainter *p, + const QStyleOptionGraphicsItem *option, + QWidget *widget = 0); + +private slots: + void highlight(); + +private: + class Private; + Private * const d; +}; + +#endif diff --git a/plasma/generic/applets/system-monitor/monitoricon.cpp b/plasma/generic/applets/system-monitor/monitoricon.cpp new file mode 100644 index 00000000..2d604efa --- /dev/null +++ b/plasma/generic/applets/system-monitor/monitoricon.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2007 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "monitoricon.h" +#include +#include +#include +#include + +#define MARGIN 5 + +class MonitorIcon::Private +{ + public: + Private() : imageSize(22, 22) { } + + QSizeF imageSize; + QString image; + QStringList overlays; +}; + +MonitorIcon::MonitorIcon(QGraphicsItem *parent) : + QGraphicsWidget(parent), + d(new Private) +{ + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + setPreferredSize(d->imageSize.width() + 2 * MARGIN, d->imageSize.height() + 2 * MARGIN); +} + +MonitorIcon::~MonitorIcon() +{ + delete d; +} + +QString MonitorIcon::image() const +{ + return d->image; +} + +void MonitorIcon::setImage(const QString &image) +{ + d->image = image; + update(); +} + +QStringList MonitorIcon::overlays() const +{ + return d->overlays; +} + +void MonitorIcon::setOverlays( const QStringList & overlays ) +{ + d->overlays = overlays; + update(); +} + +void MonitorIcon::paint(QPainter *p, + const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + Q_UNUSED(option) + Q_UNUSED(widget) + + p->drawPixmap(QPointF((size().width() - d->imageSize.width()) / 2, + (size().height() - d->imageSize.height()) / 2), + KIcon(d->image, KIconLoader::global(), + d->overlays).pixmap(d->imageSize.toSize())); +} + +#include "monitoricon.moc" diff --git a/plasma/generic/applets/system-monitor/monitoricon.h b/plasma/generic/applets/system-monitor/monitoricon.h new file mode 100644 index 00000000..e94f5462 --- /dev/null +++ b/plasma/generic/applets/system-monitor/monitoricon.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MONITORICON_HEADER +#define MONITORICON_HEADER + +#include +#include "sm_export.h" + +class SM_EXPORT MonitorIcon : public QGraphicsWidget +{ + Q_OBJECT + Q_PROPERTY(QString image READ image WRITE setImage) + +public: + explicit MonitorIcon(QGraphicsItem *parent = 0); + virtual ~MonitorIcon(); + + QString image() const; + void setImage(const QString &image); + + QStringList overlays() const; + void setOverlays( const QStringList & overlays ); +protected: + virtual void paint(QPainter *p, + const QStyleOptionGraphicsItem *option, + QWidget *widget = 0); +private: + class Private; + Private * const d; +}; + +#endif diff --git a/plasma/generic/applets/system-monitor/net-config.ui b/plasma/generic/applets/system-monitor/net-config.ui new file mode 100644 index 00000000..f3011b8e --- /dev/null +++ b/plasma/generic/applets/system-monitor/net-config.ui @@ -0,0 +1,93 @@ + + + config + + + + 0 + 0 + 382 + 263 + + + + + + + + 0 + + + + + &Network interfaces: + + + treeView + + + + + + + false + + + true + + + true + + + + + + + + + Update &interval: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + intervalSpinBox + + + + + + + 1 + + + 0.100000000000000 + + + 525600.000000000000000 + + + 2.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/plasma/generic/applets/system-monitor/net.cpp b/plasma/generic/applets/system-monitor/net.cpp new file mode 100644 index 00000000..99955f32 --- /dev/null +++ b/plasma/generic/applets/system-monitor/net.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2008 Petri Damsten + * Copyright (C) 2010 Michel Lafon-Puyo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "net.h" +#include +#include +#include +#include +#include + +SM::Net::Net(QObject *parent, const QVariantList &args) + : SM::Applet(parent, args) + , m_rx("^network/interfaces/(\\w+)/transmitter/data$") +{ + setHasConfigurationInterface(true); + resize(234 + 20 + 23, 135 + 20 + 25); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_sourceTimer.setSingleShot(true); + connect(&m_sourceTimer, SIGNAL(timeout()), this, SLOT(sourcesAdded())); +} + +SM::Net::~Net() +{ +} + +void SM::Net::init() +{ + KGlobal::locale()->insertCatalog("plasma_applet_system-monitor"); + setEngine(dataEngine("systemmonitor")); + setTitle(i18n("Network")); + + connect(engine(), SIGNAL(sourceAdded(QString)), this, SLOT(sourceAdded(QString))); + connect(engine(), SIGNAL(sourceRemoved(QString)), + this, SLOT(sourceRemoved(QString))); + foreach (const QString& source, engine()->sources()) { + sourceAdded(source); + } +} + +void SM::Net::configChanged() +{ + KConfigGroup cg = config(); + setInterval(cg.readEntry("interval", 2.0) * 1000); + setSources(cg.readEntry("interfaces", m_interfaces)); + connectToEngine(); +} + +void SM::Net::sourceAdded(const QString& name) +{ + if (m_rx.indexIn(name) != -1) { + //kDebug() << m_rx.cap(1); + if (m_rx.cap(1) != "lo") { + m_interfaces << name; + if (!m_sourceTimer.isActive()) { + m_sourceTimer.start(0); + } + } + } +} + +void SM::Net::sourcesAdded() +{ + configChanged(); +} + +void SM::Net::sourceRemoved(const QString& name) +{ + m_interfaces.removeAll(name); +} + +bool SM::Net::addVisualization(const QString& source) +{ + QStringList l = source.split('/'); + if (l.count() < 3) { + return false; + } + QString interface = l[2]; + SM::Plotter *plotter = new SM::Plotter(this); + plotter->setTitle(interface); + plotter->setUnit("KiB/s"); + plotter->setCustomPlots(QList() << QColor("#0099ff") << QColor("#91ff00")); + //plotter->setStackPlots(false); + appendVisualization(interface, plotter); + connectSource("network/interfaces/" + interface + "/receiver/data"); + setPreferredItemHeight(80); + return true; +} + +void SM::Net::dataUpdated(const QString& source, + const Plasma::DataEngine::Data &data) +{ + QStringList splitted = source.split('/'); + + if (splitted.length() < 4) { + return; + } + + QString interface = splitted[2]; + int index = (splitted[3] == "receiver") ? 0 : 1; + + if (!m_data.contains(interface)) { + m_data[interface] = QList() << -1 << -1; + } + + m_data[interface][index] = qMax(0.0, data["value"].toDouble()); + + if (!m_data[interface].contains(-1)) { + + SM::Plotter *plotter = qobject_cast(visualization(interface)); + if (plotter) { + plotter->addSample(m_data[interface]); + + if (mode() == SM::Applet::Panel) { + const double downstream = m_data[interface][0]; + const double upstream = m_data[interface][1]; + + + QString tooltip = QString::fromUtf8("%1
⇧   %2
⇩   %3
"); + + setToolTip(interface, tooltip.arg(plotter->title()) + .arg(KGlobal::locale()->formatByteSize(upstream*1024)) + .arg(KGlobal::locale()->formatByteSize(downstream*1024))); + } + } + m_data[interface] = QList() << -1 << -1; + } +} + +void SM::Net::createConfigurationInterface(KConfigDialog *parent) +{ + QWidget *widget = new QWidget(); + ui.setupUi(widget); + m_model.clear(); + m_model.setHorizontalHeaderLabels(QStringList() << i18n("Network Interface")); + QStandardItem *parentItem = m_model.invisibleRootItem(); + + foreach (const QString& interface, m_interfaces) { + QString ifname = interface.split('/')[2]; + QStandardItem *item1 = new QStandardItem(ifname); + item1->setEditable(false); + item1->setCheckable(true); + item1->setData(interface); + if (sources().contains(interface)) { + item1->setCheckState(Qt::Checked); + } + parentItem->appendRow(QList() << item1); + } + ui.treeView->setModel(&m_model); + ui.treeView->resizeColumnToContents(0); + ui.intervalSpinBox->setValue(interval() / 1000.0); + ui.intervalSpinBox->setSuffix(i18nc("second", " s")); + parent->addPage(widget, i18n("Interfaces"), "network-workgroup"); + + connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); + connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); + connect(ui.treeView, SIGNAL(clicked(QModelIndex)), parent, SLOT(settingsModified())); + connect(ui.intervalSpinBox, SIGNAL(valueChanged(QString)), parent, SLOT(settingsModified())); +} + +void SM::Net::configAccepted() +{ + KConfigGroup cg = config(); + QStandardItem *parentItem = m_model.invisibleRootItem(); + + clear(); + + for (int i = 0; i < parentItem->rowCount(); ++i) { + QStandardItem *item = parentItem->child(i, 0); + if (item) { + if (item->checkState() == Qt::Checked) { + appendSource(item->data().toString()); + } + } + } + cg.writeEntry("interfaces", sources()); + + double interval = ui.intervalSpinBox->value(); + cg.writeEntry("interval", interval); + + emit configNeedsSaving(); +} + +#include "net.moc" diff --git a/plasma/generic/applets/system-monitor/net.h b/plasma/generic/applets/system-monitor/net.h new file mode 100644 index 00000000..c3707310 --- /dev/null +++ b/plasma/generic/applets/system-monitor/net.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Petri Damsten + * Copyright (C) 2010 Michel Lafon-Puyo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NET_HEADER +#define NET_HEADER + +#include +#include "applet.h" +#include +#include +#include +#include + +class QStandardItemModel; + +namespace SM { + +class Net : public Applet +{ + Q_OBJECT + public: + Net(QObject *parent, const QVariantList &args); + ~Net(); + + virtual void init(); + virtual bool addVisualization(const QString&); + virtual void createConfigurationInterface(KConfigDialog *parent); + + public slots: + void configAccepted(); + void configChanged(); + void dataUpdated(const QString &name, + const Plasma::DataEngine::Data &data); + void sourceAdded(const QString &name); + void sourcesAdded(); + void sourceRemoved(const QString &name); + + private: + Ui::config ui; + QStandardItemModel m_model; + QStringList m_interfaces; + QMap > m_data; + QTimer m_sourceTimer; + QRegExp m_rx; +}; +} + +K_EXPORT_PLASMA_APPLET(sm_net, SM::Net) + +#endif diff --git a/plasma/generic/applets/system-monitor/plasma-applet-sm_cpu.desktop b/plasma/generic/applets/system-monitor/plasma-applet-sm_cpu.desktop new file mode 100644 index 00000000..86588d91 --- /dev/null +++ b/plasma/generic/applets/system-monitor/plasma-applet-sm_cpu.desktop @@ -0,0 +1,156 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=CPU Monitor +Name[ar]=مراقب استعمال المعالج +Name[ast]=Monitor de CPU +Name[bg]=Наблюдение на процесора +Name[bs]=nadzor procesora +Name[ca]=Controlador de la CPU +Name[ca@valencia]=Controlador de la CPU +Name[cs]=Monitor CPU +Name[da]=CPU-overvågning +Name[de]=Überwachungsmonitor für Prozessoren +Name[el]=Επόπτης ΚΜΕ +Name[en_GB]=CPU Monitor +Name[es]=Monitor de CPU +Name[et]=Protsessori jälgija +Name[eu]=PUZaren monitorea +Name[fi]=Suoritinkäyttö +Name[fr]=Surveillance du processeur +Name[ga]=Monatóir an LAP +Name[gl]=Vixilante da CPU +Name[gu]=CPU મોનિટર +Name[he]=מוניטור המעבד +Name[hi]=सीपीयू नीरीक्षक +Name[hr]=Nadzornik CPU-a +Name[hu]=Processzorfigyelő +Name[ia]=Monitor de CPU +Name[id]=Monitor CPU +Name[is]=Eftirlit með notkun örgjörva +Name[it]=Monitor del processore +Name[ja]=CPU モニタ +Name[kk]=Процссорды бақылау +Name[km]=ត្រួតពិនិត្យ​ស៊ីភីយូ +Name[kn]=CPU ಮೇಲ್ವಿಚಾರಕ +Name[ko]=CPU 모니터 +Name[lt]=CPU apkrovos stebėtojas +Name[lv]=Procesora novērotājs +Name[mr]=CPU नियंत्रक +Name[nb]=prosessor-overvåker +Name[nds]=CPU-Kieker +Name[nl]=Monitor voor CPU-gebruik +Name[pa]=CPU ਨਿਗਰਾਨ +Name[pl]=Monitor procesora +Name[pt]=Monitor do CPU +Name[pt_BR]=Monitor da CPU +Name[ro]=Monitor de procesor +Name[ru]=Использование процессора +Name[si]=CPU මොනිටරය +Name[sk]=Monitor CPU +Name[sl]=Nadzornik procesorja +Name[sr]=надзор процесора +Name[sr@ijekavian]=надзор процесора +Name[sr@ijekavianlatin]=nadzor procesora +Name[sr@latin]=nadzor procesora +Name[sv]=Övervakning av processoranvändning +Name[tg]=Монитори CPU +Name[th]=ติดตามการใช้งานตัวประมวลผลกลาง +Name[tr]=İşlemci İzleyici +Name[ug]=CPU كۆزەتكۈچ +Name[uk]=Використання процесора +Name[vi]=Trình quản lý CPU +Name[wa]=Corwaitoe CPU +Name[x-test]=xxCPU Monitorxx +Name[zh_CN]=CPU 监视器 +Name[zh_TW]=CPU 監視器 +Comment=A CPU usage monitor +Comment[ar]=مراقب استعمال المعالج +Comment[ast]=Monitor d'usu de la CPU +Comment[be@latin]=Nazirańnik zaniataści „CPU” +Comment[bg]=Наблюдение натоварването на процесора +Comment[bs]=Nadgledanje upotrebe procesora +Comment[ca]=Un controlador d'ús de la CPU +Comment[ca@valencia]=Un controlador d'ús de la CPU +Comment[cs]=Monitor vytížení CPU +Comment[csb]=Mònitór brëkùnkù CPU +Comment[da]=Overvågning af CPU-forbrug +Comment[de]=Ein Überwachungsmonitor für Prozessoren +Comment[el]=Ένας επόπτης χρήσης ΚΜΕ +Comment[en_GB]=A CPU usage monitor +Comment[eo]=Monitoro de procezila uzo +Comment[es]=Monitor de uso de la CPU +Comment[et]=Protsessori kasutuse jälgija +Comment[eu]=PUZaren erabilera-monitorea +Comment[fi]=Näyttää suoritinten käytön +Comment[fr]=Une surveillance de l'usage du processeur +Comment[fy]=In CPU brûkme monitor +Comment[ga]=Monatóir úsáid an LAP +Comment[gl]=Un vixilante da utilización da CPU +Comment[gu]=CPU વપરાશ દેખરેખ +Comment[he]=מנטר שימוש במעבד +Comment[hi]=सीपीयू उपयो मॉनीटर +Comment[hne]=सीपीयू उपयोग देखइया +Comment[hr]=Nadzor korištenja procesora +Comment[hsb]=Monitor, kiž pokazuje wućeženosć procesora +Comment[hu]=Kijelzi a CPU állapotát +Comment[ia]=Un monitor del usage de CPU +Comment[id]=Monitor penggunaan CPU +Comment[is]=Eftirlit með notkun örgjörva +Comment[it]=Indica l'uso della CPU +Comment[ja]=CPU 使用率を監視します +Comment[kk]=Процессордың жүктелісін бақылау +Comment[km]=កម្មវិធី​ត្រួតពិនិត្យ​ការ​ប្រើប្រាស់​ស៊ីភីយូ +Comment[kn]=ಒಂದು CPU ಬಳಕೆಯ ಮೇಲ್ವಿಚಾರಕ +Comment[ko]=CPU 사용량 모니터 +Comment[lt]=CPU apkrovos stebėtojas +Comment[lv]=Procesora noslogojuma novērotājs +Comment[mk]=Монитор на користењето на процесорот +Comment[ml]=സിപിയു ഉപയോഗ നിരീക്ഷകന്‍ +Comment[mr]=CPU वापरणी नियंत्रक +Comment[nb]=En overvåker for prosessorbruk +Comment[nds]=En Kieker för den CPU-Bruuk +Comment[nl]=Volgt het CPU-gebruik +Comment[nn]=Overvaking av prosessorbruk +Comment[or]=ଗୋଟିଏ CPU ବ୍ୟବହାର ବିଧି ନିରିକ୍ଷକ +Comment[pa]=ਇੱਕ CPU ਵਰਤੋਂ ਮਾਨੀਟਰ +Comment[pl]=Monitor użycia procesora +Comment[pt]=Um monitor da utilização do CPU +Comment[pt_BR]=Um monitor de utilização da CPU +Comment[ro]=Monitor de utilizare a procesorului +Comment[ru]=Монитор использования процессора +Comment[si]=CPU භාවිතය නිරික්‍ෂකය +Comment[sk]=Monitor využitia CPU +Comment[sl]=Nadzornik obremenjenosti procesorja +Comment[sr]=Надгледање употребе процесора +Comment[sr@ijekavian]=Надгледање употребе процесора +Comment[sr@ijekavianlatin]=Nadgledanje upotrebe procesora +Comment[sr@latin]=Nadgledanje upotrebe procesora +Comment[sv]=Övervakning av processoranvändning +Comment[ta]=A CPU usage monitor +Comment[tg]=Монитори истифодабарии манбаъи система +Comment[th]=ตัวติดตามการใช้งานตัวประมวลผลกลาง +Comment[tr]=Bir işlemci kullanımı izleyici +Comment[ug]=CPU ئىشلىتىشنى كۆزەتكۈچ +Comment[uk]=Монітор використання процесора +Comment[wa]=On corwaitoe di l' eployaedje del CPU +Comment[x-test]=xxA CPU usage monitorxx +Comment[zh_CN]=CPU 利用率监视器 +Comment[zh_TW]=CPU 使用量監視器 +Type=Service +Icon=cpu +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_sm_cpu +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=sm_cpu +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/generic/applets/system-monitor/plasma-applet-sm_hdd.desktop b/plasma/generic/applets/system-monitor/plasma-applet-sm_hdd.desktop new file mode 100644 index 00000000..37d0de45 --- /dev/null +++ b/plasma/generic/applets/system-monitor/plasma-applet-sm_hdd.desktop @@ -0,0 +1,111 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Hard Disk Space Usage +Name[bs]=Iskorisenost Hard diska +Name[ca]=Ús d'espai de disc dur +Name[ca@valencia]=Ús d'espai de disc dur +Name[cs]=Využití místa na pevném disku +Name[da]=Brug af harddiskplads +Name[de]=Festplattenbelegung +Name[el]=Χρήση χώρου σκληρού δίσκου +Name[en_GB]=Hard Disk Space Usage +Name[es]=Espacio usado en el disco duro +Name[et]=Kõvaketta ruumikasutus +Name[eu]=Disko gogorreko lekuaren erabilera +Name[fi]=Kiintolevyjen tilankäyttö +Name[fr]=Utilisation de l'espace des disques dur +Name[gl]=Uso do espazo do disco duro +Name[he]=השימוש בדיסק +Name[hu]=Lemezterület használat +Name[ia]=Usage de spatio del disco dur +Name[it]=Spazio del disco fisso +Name[kk]=Қатқыл дискідегі пайдаланған орын +Name[km]=ការ​ប្រើ​ប្រាស់​ទំហំ​ថាសរឹង +Name[ko]=하드디스크 공간 사용량 +Name[lt]=Kietojo disko panaudojimas +Name[mr]=हार्ड डिस्क वापर +Name[nb]=Plassbruk for harddisk +Name[nds]=Fastplaat-Bruuk +Name[nl]=Ruimtegebruik van de harde schijf +Name[pa]=ਹਾਰਡ ਡਿਸਕ ਥਾਂ ਵਰਤੋਂ +Name[pl]=Wykorzystanie przestrzeni dysku twardego +Name[pt]=Utilização do Disco Rígido +Name[pt_BR]=Uso do espaço do disco rígido +Name[ro]=Utilizarea spațiului pe discul dur +Name[ru]=Использование места на диске +Name[sk]=Využitie miesta na pevnom disku +Name[sl]=Uporaba prostora na trdem disku +Name[sr]=заузеће хард диска +Name[sr@ijekavian]=заузеће хард диска +Name[sr@ijekavianlatin]=zauzeće hard diska +Name[sr@latin]=zauzeće hard diska +Name[sv]=Utrymmesanvändning för hårddisk +Name[tr]=Sabit Disk Alanı Kullanımı +Name[uk]=Використання місця на диску +Name[vi]=Sử dụng không gian đĩa +Name[x-test]=xxHard Disk Space Usagexx +Name[zh_CN]=硬盘空间使用 +Name[zh_TW]=硬碟空間使用量 +Comment=An applet that monitors hard disk space usage and percentage +Comment[bs]=Aplet koji prati hard korištenje prostora na disku i postotak +Comment[ca]=Una miniaplicació que controla l'ús d'espai del disc dur i el tant per cent +Comment[ca@valencia]=Una miniaplicació que controla l'ús d'espai del disc dur i el tant per cent +Comment[cs]=Aplet, jenž monitoruje zaplnění místa na disku +Comment[da]=En applet som overvåger brug af harddiskplads og procent ledig plads +Comment[de]=Ein Miniprogramm, das die Festplattenbelegung absolut und in Prozent überwacht +Comment[el]=Μικροεφαρμογή που εποπτεύει την ποσοτική και ποσοστιαία χρήση χώρου του σκληρού δίσκου +Comment[en_GB]=An applet that monitors hard disk space usage and percentage +Comment[es]=Una miniaplicación que monitoriza el uso y porcentaje del espacio en disco duro +Comment[et]=Kõvaketta ruumikasutust ja protsenti jälgiv aplett +Comment[eu]=Disko gogorreko lekuaren erabilera eta ehunekoa kontrolatzen dituen miniaplikazio bat +Comment[fi]=Sovelma, joka näyttää kiintolevyjen tilankäytön ja sen prosenttiosuuden +Comment[fr]=Une applet surveillant l'utilisation de l'espace des disques durs et donnant des pourcentages +Comment[gl]=Unha applet que vixía o espazo usado do disco duro e a porcentaxe +Comment[hu]=Egy kisalkalmazás, amely figyeli a merevlemez használatot és százalékot +Comment[ia]=Un applet que monitora usage e percentage de spatio de disco dur +Comment[it]=Un'applet che controlla l'uso dello spazio su disco fisso +Comment[kk]=Қатқыл дискідегі пайдаланған орын және пайызын бақылау аплеті +Comment[km]=អាប់ភ្លេត​ដែល​ត្រួតពិនិត្យ​​ការ​ប្រើប្រាស់​ និង​ភាគរយ​ទំហំ​ថាសរឹង +Comment[ko]=하드디스크 공간 사용량 및 비율을 보여 주는 애플릿 +Comment[lt]=Programėlė, kuri stebi disko vietos panaudojimą ir procentinį santykį +Comment[mr]=हार्ड डिस्क वापर व टक्केवारी दर्शविणारे एप्लेट +Comment[nb]=Et miniprogram som overvåker bruk av plass på harddisk, og prosentvis +Comment[nds]=En Lüttprogramm, dat den Fastplaat-Bruuk afsluuts un in Perzent beluert +Comment[nl]=Een applet die het ruimtegebruik van de harde schijf volgt +Comment[pa]=ਐਪਲਿਟ, ਜੋ ਕਿ ਹਾਰਡ ਡਿਸਕ ਵਲੋਂ ਵਰਤੀ ਥਾਂ ਅਤੇ ਫੀਸਦੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ +Comment[pl]=Aplet, który monitoruje wykorzystaną przestrzeń i procent wykorzystania dysku twardego +Comment[pt]=Uma 'applet' que vigia a utilização e percentagem do disco +Comment[pt_BR]=Monitora o uso do espaço do disco rígido e a porcentagem +Comment[ro]=Miniaplicație ce monitorizează gradul de utilizare a discului dur +Comment[ru]=Мониторинг используемого дискового пространства +Comment[sk]=Applet, ktorý monitoruje použitie miesta na pevnom disku a percentá +Comment[sl]=Aplet, ki nadzoruje uporabo prostora na trdem disku +Comment[sr]=Аплет за надгледање заузећа хард диска +Comment[sr@ijekavian]=Аплет за надгледање заузећа хард диска +Comment[sr@ijekavianlatin]=Aplet za nadgledanje zauzeća hard diska +Comment[sr@latin]=Aplet za nadgledanje zauzeća hard diska +Comment[sv]=Ett miniprogram som övervakar hårddiskutrymme och procent +Comment[tr]=Sabit disk kullanımını izleyen ve yüzde olarak gösteren bir programcık +Comment[uk]=Аплет, який стежить за використанням місця на диску +Comment[vi]=Một ứng dụng nhỏ quản lý phần trăm sử dụng không gian đĩa +Comment[x-test]=xxAn applet that monitors hard disk space usage and percentagexx +Comment[zh_CN]=监视硬盘空间使用率的小程序 +Comment[zh_TW]=監視硬碟空間使用量百分比的小程式 +Type=Service +Icon=drive-harddisk +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_sm_hdd +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=sm_hdd +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/generic/applets/system-monitor/plasma-applet-sm_hdd_activity.desktop b/plasma/generic/applets/system-monitor/plasma-applet-sm_hdd_activity.desktop new file mode 100644 index 00000000..78f6ca06 --- /dev/null +++ b/plasma/generic/applets/system-monitor/plasma-applet-sm_hdd_activity.desktop @@ -0,0 +1,114 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Hard Disk I/O Monitor +Name[bs]=Hard Disk I/O Monitor +Name[ca]=Controlador d'E/S de disc dur +Name[ca@valencia]=Controlador d'E/S de disc dur +Name[cs]=Monitor I/O pevného disku +Name[da]=Overvågning af harddisk-I/O +Name[de]=Überwachungsmonitor für Festplattenein- und ausgabe +Name[el]=Επόπτης χρήσης του σκληρού δίσκου +Name[en_GB]=Hard Disk I/O Monitor +Name[es]=Monitor de E/S del disco duro +Name[et]=Kõvaketta sisendi/väljundi jälgija +Name[eu]=Disko gogorreko S/I monitorea +Name[fi]=Kiintolevyjen käyttöilmaisin +Name[fr]=Une surveillance des entrées / sorties des disques durs +Name[ga]=Monatóir I/A Diosca Crua +Name[gl]=Vixilante da E/S do disco duro +Name[he]=מנטר שימוש בכונן הקשיח +Name[hu]=Merevlemez I/O monitor +Name[ia]=Monitor de I/E del disco dur +Name[it]=Uso del disco fisso +Name[kk]=Қатқыл дискінің Е/Ш бақылауы +Name[km]=ត្រួតពិនិត្យ I/O ថាសរឹង +Name[ko]=하드디스크 I/O 모니터 +Name[lt]=Kietojo disko I/O stebėtojas +Name[mr]=हार्ड डिस्क I/O नियंत्रक +Name[nb]=En overvåker for disk-I/U +Name[nds]=Fastplaat-I/O-Beluern +Name[nl]=Volgt de activiteit van de harde schijf +Name[pa]=ਹਾਰਡ ਡਿਸਕ I/O ਮਾਨੀਟਰ +Name[pl]=Monitor WE/WY dysku twardego +Name[pt]=Monitor de E/S do Disco +Name[pt_BR]=Monitor de E/S do disco rígido +Name[ro]=Monitor pentru utilizarea discului dur +Name[ru]=Монитор ввода-вывода жестких дисков +Name[sk]=Monitor I/O pevného disku +Name[sl]=Nadzornik V/I trdega diska +Name[sr]=Надгледање У/И‑ја хард‑диска +Name[sr@ijekavian]=Надгледање У/И‑ја хард‑диска +Name[sr@ijekavianlatin]=Nadgledanje U/I‑ja hard‑diska +Name[sr@latin]=Nadgledanje U/I‑ja hard‑diska +Name[sv]=Övervakning av in- och utmatning för hårddisk +Name[tr]=Sabit Disk G/Ç İzleyici +Name[uk]=Монітор роботи жорсткого диска +Name[vi]=Trình quản lý I/O đĩa cứng +Name[x-test]=xxHard Disk I/O Monitorxx +Name[zh_CN]=硬盘 I/O 监视器 +Name[zh_TW]=硬碟使用量 I/O 監視器 + +Comment=An applet that monitors hard disk throughput and input/output +Comment[bs]=Aplet koji prati hard disk protok ulaz / izlaz +Comment[ca]=Una miniaplicació que controla la velocitat de transferència de dades del disc dur i l'entrada/sortida +Comment[ca@valencia]=Una miniaplicació que controla la velocitat de transferència de dades del disc dur i l'entrada/eixida +Comment[cs]=Aplet, jenž monitoruje propustnost disku a vstup/výstup +Comment[da]=En applet som overvåger gennemgang og input/output for harddisken +Comment[de]=Ein Miniprogramm, das den Festplattendurchsatz und die Festplattenein- und -ausgabe überwacht +Comment[el]=Μικροεφαρμογή που εποπτεύει τη ρυθμοαπόδοση και την είσοδο/έξοδο του σκληρού δίσκου +Comment[en_GB]=An applet that monitors hard disk throughput and input/output +Comment[es]=Una miniaplicación que monitoriza el rendimiento y la entrada/salida del disco duro +Comment[et]=Kõvaketta läbilaset ja sisendit/väljundit jälgiv aplett +Comment[eu]=Disko gogorraren errendimendua eta sarrera/irteera kontrolatzen dituen miniaplikazio bat +Comment[fi]=Sovelma joka tarkkailee kiintolevyjen suoritustehoa ja siirtomäärää +Comment[fr]=Une applet surveillant l'activité des disques durs et de leurs entrées / sorties +Comment[gl]=Unha applet que vixía o rendemento e a entrada/saída +Comment[hu]=Egy kisalkalmazás, amely figyeli a merevlemez átvitelét és a bemenetet/kimenetet +Comment[ia]=Un applet que que monitora le prestation (throughput) e ingresso/egresso de disco dur +Comment[it]=Un'applet che controlla le prestazioni e l'uso del disco fisso +Comment[kk]=Дискінің белсендігі және енгізу/шығаруды бақылау апплеті +Comment[km]=អាប់ភ្លេត​ដែល​ត្រួតពិនិត្យ​ថាសរឹង​ និង​ឧបករណ៍​ចេញ/ចូល +Comment[ko]=하드디스크 대역폭 및 I/O 상태를 보여 주는 애플릿 +Comment[lt]=Programėlė, kuri stebi disko apkrovimą ir įvestį/išvestį +Comment[mr]=हार्ड डिस्क इनपुट व आउटपुट दर्शविणारे एप्लेट +Comment[nb]=Et miniprogram som overvåker dataflyt til og fra harddisk +Comment[nds]=En Lüttprogramm, dat den Fastplaat-Dörsatz un de In- un Utgaven beluert +Comment[nl]=Een applet die de activiteit van de harde schijf volgt +Comment[pa]=ਹਾਰਡ ਡਿਸਕ ਥਰੂਪੁੱਟ ਅਤੇ ਇੰਪੁੱਟ/ਆਉਟਪੁੱਟ ਦੀ ਨਿਗਰਾਨੀ ਲਈ ਐਪਲਿਟ +Comment[pl]=Aplet, który monitoruje przepustowość wejścia/wyjścia dysku twardego +Comment[pt]=Uma 'applet' que vigia o rendimento e o fluxo de entrada-saída do disco +Comment[pt_BR]=Monitora a taxa de transferência e entrada/saída do disco rígido +Comment[ro]=Miniaplicație ce monitorizează traficul de intrare și cel de ieșire pentru discul dur +Comment[ru]=Мониторинг пропускной способности и процессов ввода/вывода жестких дисков +Comment[sk]=Applet, ktorý monitoruje priepustnosť pevného disku a vstup/výstup +Comment[sl]=Aplet, ki nadzoruje prepustnost in vhod/izhod trdega diska +Comment[sr]=Аплет за надгледање пропусности и улаза/излаза хард‑диска +Comment[sr@ijekavian]=Аплет за надгледање пропусности и улаза/излаза хард‑диска +Comment[sr@ijekavianlatin]=Aplet za nadgledanje propusnosti i ulaza/izlaza hard‑diska +Comment[sr@latin]=Aplet za nadgledanje propusnosti i ulaza/izlaza hard‑diska +Comment[sv]=Ett miniprogram som övervakar hårddiskprestanda samt in- och utmatning +Comment[tr]=Sabit diski girdi/çıktı olarak izleyen bir programcık +Comment[uk]=Аплет, який стежить за даними, які записуються на жорсткий диск та читаються з жорсткого диска +Comment[vi]=Một ứng dụng nhỏ quản lý dữ liệu vào/ra trên đĩa cứng +Comment[x-test]=xxAn applet that monitors hard disk throughput and input/outputxx +Comment[zh_CN]=监视硬盘输入输出的小程序 +Comment[zh_TW]=監視硬碟效能與 I/O 的小程式 + +Type=Service +Icon=drive-harddisk +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_sm_hdd_activity +X-KDE-PluginInfo-Author=Shaun Reich +X-KDE-PluginInfo-Email=shaun.reich@kdemail.net +X-KDE-PluginInfo-Name=sm_hdd_activity +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/generic/applets/system-monitor/plasma-applet-sm_hwinfo.desktop b/plasma/generic/applets/system-monitor/plasma-applet-sm_hwinfo.desktop new file mode 100644 index 00000000..2010f2a4 --- /dev/null +++ b/plasma/generic/applets/system-monitor/plasma-applet-sm_hwinfo.desktop @@ -0,0 +1,158 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Hardware Info +Name[ar]=معلومات العتاد +Name[ast]=Información del hardware +Name[bg]=Хардуерни данни +Name[bs]=podaci o hardveru +Name[ca]=Informació del maquinari +Name[ca@valencia]=Informació del maquinari +Name[cs]=Informace o hardware +Name[da]=Hardwareinfo +Name[de]=Hardwareinformationen +Name[el]=Πληροφορίες υλικού +Name[en_GB]=Hardware Info +Name[es]=Información del hardware +Name[et]=Riistvara teave +Name[eu]=Hardwareari buruzko informazioa +Name[fi]=Laitteistotiedot +Name[fr]=Informations sur le matériel +Name[ga]=Faisnéis Crua-Earraí +Name[gl]=Información do hardware +Name[gu]=હાર્ડવેર જાણકારી +Name[he]=מידע אודות חומרה +Name[hi]=हार्डवेयर जानकारी +Name[hr]=Informacije o hardveru +Name[hu]=Hardverjellemzők +Name[ia]=Info de hardware +Name[id]=Info Peranti Keras +Name[is]=Vélbúnaðarupplýsingar +Name[it]=Informazioni sull'hardware +Name[ja]=ハードウェア情報 +Name[kk]=Жабдық мәліметі +Name[km]=ព័ត៌មាន​ផ្នែក​រឹង +Name[kn]=ಯಂತ್ರಾಂಶ ಮಾಹಿತಿ +Name[ko]=하드웨어 정보 +Name[lt]=Aparatinės įrangos informacija +Name[lv]=Aparatūras informācija +Name[mr]=हार्डवेअर माहिती +Name[nb]=Maskinvareinformasjon +Name[nds]=Reedschap-Informatschonen +Name[nl]=Hardware-informatie +Name[pa]=ਹਾਰਡਵੇਅਰ ਜਾਣਕਾਰੀ +Name[pl]=Informacje o sprzęcie +Name[pt]=Informação do 'Hardware' +Name[pt_BR]=Informações do hardware +Name[ro]=Informații echipament +Name[ru]=Оборудование компьютера +Name[si]=දෘඩාංග තොරතුරු +Name[sk]=Informácie o hardvéri +Name[sl]=Podatki o strojni opremi +Name[sr]=подаци о хардверу +Name[sr@ijekavian]=подаци о хардверу +Name[sr@ijekavianlatin]=podaci o hardveru +Name[sr@latin]=podaci o hardveru +Name[sv]=Hårdvaruinformation +Name[tg]=Иттилооти сахтафзор +Name[th]=ข้อมูลของฮาร์ดแวร์ +Name[tr]=Donanım Bilgileri +Name[ug]=قاتتىق دېتال ئۇچۇرى +Name[uk]=Відомості про обладнання +Name[vi]=Thông tin phần cứng +Name[wa]=Info so l' éndjolreye +Name[x-test]=xxHardware Infoxx +Name[zh_CN]=硬件信息 +Name[zh_TW]=硬體資訊 +Comment=Show hardware info +Comment[ar]=يظهر معلومات العتاد +Comment[ast]=Amosar información d'hardware +Comment[be@latin]=Pakazvaje źviestki pra aparaturu +Comment[bg]=Показване на данни за хардуера +Comment[bn]=হার্ডওয়্যার তথ্য দেখাও +Comment[bs]=Podaci o hardveru +Comment[ca]=Mostra la informació del maquinari +Comment[ca@valencia]=Mostra la informació del maquinari +Comment[cs]=Zobrazit informace o hardwaru +Comment[csb]=Wëskrzëniô wëdowiédzã ò hardwôrze +Comment[da]=Vis hardwareinformation +Comment[de]=Zeigt Informationen zu bestimmten Geräten an. +Comment[el]=Εμφάνιση πληροφοριών υλικού +Comment[en_GB]=Show hardware info +Comment[eo]=Montri aparatajn informojn +Comment[es]=Mostrar información de hardware +Comment[et]=Riistvarainfo näitamine +Comment[eu]=Erakutsi hardwareari buruzko informazioa +Comment[fi]=Näyttää laitteistotiedot +Comment[fr]=Affiche des informations sur le matériel +Comment[fy]=Hardware ynfo sjen litte +Comment[ga]=Taispeáin eolas faoi na crua-earraí +Comment[gl]=Mostra información acerca do hardware +Comment[gu]=હાર્ડવેર માહિતી બતાવો +Comment[he]=משמש להצגת מידע אודות חומרה +Comment[hi]=हार्डवेयर जानकारी दिखाएँ +Comment[hne]=हार्डवेयर जानकारी देखाव +Comment[hr]=Prikaz informacija o hardveru +Comment[hsb]=Pokazuje informaciju wo hardware +Comment[hu]=Hardverjellemzők +Comment[ia]=Monstra info del hardware +Comment[id]=Tampilkan info peranti keras +Comment[is]=Sýna upplýsingar um vélbúnað +Comment[it]=Mostra informazioni sull'hardware +Comment[ja]=ハードウェアの情報を表示します +Comment[kk]=Жабдықтар мәліметін қарау +Comment[km]=បង្ហាញ​ព័ត៌មាន​ផ្នែក​រឹង +Comment[kn]=ಯಂತ್ರಾಂಶ ಮಾಹಿತಿಯನ್ನು ತೋರಿಸು +Comment[ko]=하드웨어 정보를 표시합니다 +Comment[lt]=Rodyti aparatinės įrangos informaciją +Comment[lv]=Rāda aparatūras informāciju +Comment[mk]=Прикажува информации за хардверот +Comment[ml]=ഹാര്‍ഡ്വെവര്‍ വിവരം കാണിക്കുക +Comment[mr]=हार्डवेअर माहिती दर्शवा +Comment[nb]=Vis maskinvareinformasjon +Comment[nds]=Hardware-Infos wiesen +Comment[nl]=Geeft informatie over uw hardware +Comment[nn]=Vis maskinvareinfo +Comment[or]=ହାର୍ଡ଼ୱେର ସୂଚନା ଦର୍ଶାନ୍ତୁ +Comment[pa]=ਹਾਰਡਵੇਅਰ ਜਾਣਕਾਰੀ ਵੇਖੋ +Comment[pl]=Pokazywanie informacji o sprzęcie +Comment[pt]=Mostrar informações sobre o 'hardware' +Comment[pt_BR]=Mostra informações do hardware +Comment[ro]=Afișează informații despre echipamentul fizic +Comment[ru]=Показ сведений об оборудовании +Comment[si]=දෘඩාංග තොරතුරු පෙන්වන්න +Comment[sk]=Zobrazenie informácií o hardvéri +Comment[sl]=Prikaz podatkov o strojni opremi +Comment[sr]=Подаци о хардверу +Comment[sr@ijekavian]=Подаци о хардверу +Comment[sr@ijekavianlatin]=Podaci o hardveru +Comment[sr@latin]=Podaci o hardveru +Comment[sv]=Visa hårdvaruinformation +Comment[ta]=Show hardware info +Comment[te]=హార్డువేర్ సమాచారమును చూపుము +Comment[tg]=Намоиши иттилооти сахтафзор +Comment[th]=แสดงข้อมูลของฮาร์ดแวร์ +Comment[tr]=Donanım bilgilerini göster +Comment[ug]=قاتتىق دېتال ئۇچۇرىنى كۆرسەت +Comment[uk]=Показати інформацію про обладнання +Comment[wa]=Mostrer les pondants et les djondants di l' éndjolreye +Comment[x-test]=xxShow hardware infoxx +Comment[zh_CN]=显示硬件信息 +Comment[zh_TW]=顯示硬體資訊 +Type=Service +Icon=hwinfo +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_sm_hwinfo +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=sm_hwinfo +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/generic/applets/system-monitor/plasma-applet-sm_net.desktop b/plasma/generic/applets/system-monitor/plasma-applet-sm_net.desktop new file mode 100644 index 00000000..782ab2ad --- /dev/null +++ b/plasma/generic/applets/system-monitor/plasma-applet-sm_net.desktop @@ -0,0 +1,157 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Network Monitor +Name[ar]=مراقب الشبكة +Name[ast]=Monitor de rede +Name[bg]=Наблюдение на мрежата +Name[bs]=nadzor mreže +Name[ca]=Controlador de la xarxa +Name[ca@valencia]=Controlador de la xarxa +Name[cs]=Monitor sítě +Name[da]=Netværksovervågning +Name[de]=Netzwerküberwachung +Name[el]=Επίβλεψη δικτύου +Name[en_GB]=Network Monitor +Name[es]=Monitor de red +Name[et]=Võrgujälgija +Name[eu]=Sareko monitorea +Name[fi]=Verkon käyttö +Name[fr]=Surveillance du réseau +Name[ga]=Monatóir an Líonra +Name[gl]=Vixilante da rede +Name[gu]=નેટવર્ક મોનિટર +Name[he]=מוניטור רשת +Name[hi]=नेटवर्क नरीक्षण +Name[hr]=Nadzornik mreže +Name[hu]=Hálózatfigyelő +Name[ia]=Monitor de Rete +Name[id]=Monitor Jaringan +Name[is]=Netkerfisvaktari +Name[it]=Monitor di rete +Name[ja]=ネットワークモニタ +Name[kk]=Желіні бақылау +Name[km]=ត្រួតពិនិត្យ​បណ្ដាញ +Name[kn]=ಜಾಲಬಂಧ ಮೇಲ್ವಿಚಾರಕ +Name[ko]=네트워크 모니터 +Name[lt]=Tinklo stebėjimo priemonė +Name[lv]=Tīkla monitors +Name[mr]=संजाळ नियंत्रक +Name[nb]=Nettverksovervåker +Name[nds]=Nettwark-Kieker +Name[nl]=Netwerkmonitor +Name[nn]=Nettverksovervaking +Name[pa]=ਨੈੱਟਵਰਕ ਨਿਗਰਾਨ +Name[pl]=Monitor sieci +Name[pt]=Monitor da Rede +Name[pt_BR]=Monitor da rede +Name[ro]=Monitor de rețea +Name[ru]=Сетевой монитор +Name[se]=Fierbmi +Name[si]=ජාල මොනිටරය +Name[sk]=Monitor siete +Name[sl]=Nadzornik omrežja +Name[sr]=надзор мреже +Name[sr@ijekavian]=надзор мреже +Name[sr@ijekavianlatin]=nadzor mreže +Name[sr@latin]=nadzor mreže +Name[sv]=Nätverksövervakning +Name[tg]=Монитори шабака +Name[th]=ติดตามการใช้งานเครือข่าย +Name[tr]=Ağ İzleyici +Name[ug]=تور كۆزەتكۈچ +Name[uk]=Монітор мережі +Name[wa]=Corwaitoe del rantoele +Name[x-test]=xxNetwork Monitorxx +Name[zh_CN]=网络监视器 +Name[zh_TW]=網路監控 +Comment=A network usage monitor +Comment[ar]=يراقب استعمال الشبكة +Comment[ast]=Monitor d'usu de la rede +Comment[be@latin]=Nazirańnik zaniataści sietki +Comment[bg]=Наблюдение на изпозлването на мрежата +Comment[bs]=Nadgledanje upotrebe mreže +Comment[ca]=Un controlador d'ús de la xarxa +Comment[ca@valencia]=Un controlador d'ús de la xarxa +Comment[cs]=Monitor využití sítě +Comment[csb]=Mònitór brëkòwaniô sécë +Comment[da]=Overvågning af netværkstrafik +Comment[de]=Ein Überwachungsmonitor für Netzwerke +Comment[el]=Ένας επόπτης χρήσης του δικτύου +Comment[en_GB]=A network usage monitor +Comment[es]=Monitor de uso de la red +Comment[et]=Võrgukasutuse jälgija +Comment[eu]=Sarearen erabileraren monitorea +Comment[fi]=Näyttää verkon käytön +Comment[fr]=Surveillance de l'usage réseau +Comment[fy]=In netwurk brûkme monitor +Comment[ga]=Monatóir úsáide an líonra +Comment[gl]=Un vixilante do estado da rede +Comment[gu]=નેટવર્ક સ્થિતિ દેખરેખ +Comment[he]=משמש לניטור השימוש ברשת +Comment[hi]=नेटवर्क उपयोग मॉनीटर +Comment[hne]=नेटवर्क उपयोग देखइया +Comment[hr]=Nadzor korištenja mreže +Comment[hsb]=Monitor, kiž pokazuje wućeženosć syće +Comment[hu]=Kijelzi a hálózat állapotát +Comment[ia]=Un monitor de usage de rete +Comment[id]=Monitor penggunaan jaringan +Comment[is]=Eftirlit með notkun netsins +Comment[it]=Indica l'uso della rete +Comment[ja]=ネットワークの活動を監視します +Comment[kk]=Желі пайдалануын бақылау +Comment[km]=កម្មវិធី​ត្រួតពិនិត្យ​ការ​ប្រើ​បណ្ដាញ +Comment[kn]=ಜಾಲಬಂಧ ಬಳಕೆಯ ಮೇಲ್ವಿಚಾರಕ +Comment[ko]=네트워크 사용량 모니터 +Comment[ku]=Temaşekerê rewşa torê +Comment[lt]=Tinklo naudojimo stebėtojas +Comment[lv]=Tīkla noslogojuma novērotājs +Comment[mk]=Монитор на користењето на мрежата +Comment[ml]= ശ്രംഖല ഉപയോഗം നിരീക്ഷകന്‍ +Comment[mr]=संजाळ वापरणी नियंत्रक +Comment[nb]=En overvåker for nettverksbruk +Comment[nds]=En Kieker för den Nettwark-Bruuk +Comment[nl]=Toont het netwerkgebruik +Comment[nn]=Overvaking av nettverksbruk +Comment[or]=ଗୋଟିଏ ନେଟୱର୍କ ବ୍ୟବହାର ବିଧି ନିରିକ୍ଷକ +Comment[pa]=ਇੱਕ ਨੈੱਟਵਰਕ ਵਰਤੋਂ ਮਾਨੀਟਰ +Comment[pl]=Monitor wykorzystania sieci +Comment[pt]=Um monitor da utilização da rede +Comment[pt_BR]=Um monitor de utilização da rede +Comment[ro]=Monitor de utilizare a rețelei +Comment[ru]=Монитор сетевой активности +Comment[si]=ජාල භාවිතය නිරික්‍ෂකය +Comment[sk]=Monitor využitia siete +Comment[sl]=Nadzornik uporabe omrežja +Comment[sr]=Надгледање употребе мреже +Comment[sr@ijekavian]=Надгледање употребе мреже +Comment[sr@ijekavianlatin]=Nadgledanje upotrebe mreže +Comment[sr@latin]=Nadgledanje upotrebe mreže +Comment[sv]=Övervakning av nätverksanvändning +Comment[ta]=பிணைய பயன்பாடு நோட்டம் +Comment[tg]=Состояние сервера Samba +Comment[th]=ตัวติดตามดูการใช้งานเครือข่าย +Comment[tr]=Bir ağ kullanımı izleyici +Comment[ug]=تور ئىشلىتىشنى كۆزەتكۈچ +Comment[uk]=Монітор використання мережі +Comment[wa]=On corwaitoe di l' eployaedje del rantoele +Comment[x-test]=xxA network usage monitorxx +Comment[zh_CN]=网络利用率监视器 +Comment[zh_TW]=網路使用量監視器 +Type=Service +Icon=network-workgroup +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_sm_net +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=sm_net +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/generic/applets/system-monitor/plasma-applet-sm_ram.desktop b/plasma/generic/applets/system-monitor/plasma-applet-sm_ram.desktop new file mode 100644 index 00000000..b433cba8 --- /dev/null +++ b/plasma/generic/applets/system-monitor/plasma-applet-sm_ram.desktop @@ -0,0 +1,151 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Memory Status +Name[ar]=حالة الذاكرة +Name[ast]=Estáu de la memoria +Name[bg]=Състояние на паметта +Name[bs]=stanje memorije +Name[ca]=Estat de la memòria +Name[ca@valencia]=Estat de la memòria +Name[cs]=Stav paměti +Name[da]=Hukommelsesstatus +Name[de]=Speicherstatus +Name[el]=Κατάσταση μνήμης +Name[en_GB]=Memory Status +Name[es]=Estado de la memoria +Name[et]=Mälu olek +Name[eu]=Memoria-egoera +Name[fi]=Muistin käyttö +Name[fr]=État de la mémoire +Name[ga]=Stádas Cuimhne +Name[gl]=Estado da memoria +Name[gu]=મેમરી પરિસ્થિતિ +Name[he]=מצב הזיכרון +Name[hi]=मेमोरी स्थिति +Name[hr]=Stanje memorije +Name[hu]=Memóriaállapot +Name[ia]=Stato de memoria +Name[id]=Memori Status +Name[is]=Staða minnis +Name[it]=Stato della memoria +Name[ja]=メモリの状態 +Name[kk]=Жад күй-жайы +Name[km]=ស្ថានភាព​សតិ +Name[kn]=ಸ್ಮೃತಿ (ಮೆಮೊರಿ) ಸ್ಥಿತಿ +Name[ko]=메모리 상태 +Name[lt]=Atminties būsena +Name[lv]=Atmiņas statuss +Name[mr]=स्मृति स्थिति +Name[nb]=Minnestatus +Name[nds]=Spieker-Status +Name[nl]=Geheugen-status +Name[pa]=ਮੈਮੋਰੀ ਹਾਲਤ +Name[pl]=Stan pamięci +Name[pt]=Estado da Memória +Name[pt_BR]=Status da memória +Name[ro]=Stare memorie +Name[ru]=Использование памяти +Name[si]=මතක තත්ත්වය +Name[sk]=Stav pamäte +Name[sl]=Stanje pomnilnika +Name[sr]=стање меморије +Name[sr@ijekavian]=стање меморије +Name[sr@ijekavianlatin]=stanje memorije +Name[sr@latin]=stanje memorije +Name[sv]=Minnesstatus +Name[tg]=Ҳолати хотира +Name[th]=สถานะหน่วยความจำ +Name[tr]=Bellek Durumu +Name[ug]=ئەسلەك ھالىتى +Name[uk]=Стан пам’яті +Name[wa]=Estat del memwere +Name[x-test]=xxMemory Statusxx +Name[zh_CN]=内存状态 +Name[zh_TW]=記憶體狀態 +Comment=A RAM usage monitor +Comment[ar]=مراقب استعمال الذاكرة العشوائية +Comment[ast]=Monitor d'usu de la RAM +Comment[bg]=Изпозлване на оперативната памет (RAM) +Comment[bs]=Nadgledanje upotrebe RAM‑a +Comment[ca]=Un controlador d'ús de la RAM +Comment[ca@valencia]=Un controlador d'ús de la RAM +Comment[cs]=Monitor využití RAM +Comment[csb]=Mònitór brëkòwaniô pamiãcë RAM +Comment[da]=Overvågning af ram-forbrug +Comment[de]=Ein Überwachungsmonitor für den Arbeitsspeicher +Comment[el]=Ένας επόπτης χρήσης μνήμης RAM +Comment[en_GB]=A RAM usage monitor +Comment[eo]=RAM uzada rigardilo +Comment[es]=Monitor de uso de la RAM +Comment[et]=RAM-i kasutuse jälgija +Comment[eu]=RAMaen erabileraren monitorea +Comment[fi]=Näyttää muistin käytön +Comment[fr]=Une surveillance de l'usage de la mémoire vive +Comment[fy]=In RAM brûkme monitor +Comment[ga]=Monatóir úsáid RAM +Comment[gl]=Un vixilante do utilización da memoria RAM +Comment[gu]=રેમ વપરાશ દેખરેખ +Comment[he]=משמש לניטור השימוש בזיכרון ה־RAM +Comment[hi]=रेम उपयोग मॉनीटर +Comment[hr]=Nadzor korištenja RAM memorije +Comment[hu]=Memóriahasználat-figyelő +Comment[ia]=Un monitor del usage de RAM +Comment[id]=Monitor penggunaan RAM +Comment[is]=Eftirlit með notkun vinnsluminnis +Comment[it]=Indica l'uso della RAM +Comment[ja]=RAM 使用率を監視します +Comment[kk]=Жадыны пайдалануын бақылау +Comment[km]=កម្មវិធី​ត្រួតពិនិត្យ​ការ​ប្រើ​សតិ +Comment[kn]=RAM ಬಳಕೆಯ ಮೇಲ್ವಿಚಾರಕ +Comment[ko]=RAM 사용량 모니터 +Comment[lt]=RAM naudojimo stebėtojas +Comment[lv]=Atmiņas izmantotāja novērotājs +Comment[mai]=रैम उपयोग मानीटर +Comment[mk]=Монитор на користењето на меморијата +Comment[ml]=റാം ഉപയോഗ നിരീക്ഷകന്‍ +Comment[mr]=RAM वापरणी नियंत्रक +Comment[nb]=En overvåker for RAM-bruk +Comment[nds]=En Kieker för den RAM-Bruuk +Comment[nl]=Volgt het RAM-gebruik +Comment[nn]=Overvaking av minnebruk +Comment[pa]=ਇੱਕ RAM ਵਰਤੋਂ ਮਾਨੀਟਰ +Comment[pl]=Monitor wykorzystania pamięci RAM +Comment[pt]=Um monitor da utilização da RAM +Comment[pt_BR]=Um monitor de utilização da RAM +Comment[ro]=Monitor pentru utilizarea memoriei +Comment[ru]=Монитор использования оперативной памяти +Comment[si]=RAM භාවිතය නිරික්‍ෂකය +Comment[sk]=Monitor využitia RAM +Comment[sl]=Nadzornik porabe pomnilnika +Comment[sr]=Надгледање употребе РАМ‑а +Comment[sr@ijekavian]=Надгледање употребе РАМ‑а +Comment[sr@ijekavianlatin]=Nadgledanje upotrebe RAM‑a +Comment[sr@latin]=Nadgledanje upotrebe RAM‑a +Comment[sv]=Övervakning av minnesanvändning +Comment[tg]=Монитори истифодабарии манбаъи система +Comment[th]=ตัวติดตามการใช้งานหน่วยความจำ +Comment[tr]=Bir bellek kullanımı izleyici +Comment[ug]=RAM ئىشلىتىشنى كۆزەتكۈچ +Comment[uk]=Монітор використання пам’яті +Comment[wa]=On corwaitoe di l' eployaedje del RAM +Comment[x-test]=xxA RAM usage monitorxx +Comment[zh_CN]=RAM 利用率监视器 +Comment[zh_TW]=記憶體使用量監視器 +Type=Service +Icon=media-flash +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_sm_ram +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=sm_ram +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/generic/applets/system-monitor/plasma-applet-sm_temperature.desktop b/plasma/generic/applets/system-monitor/plasma-applet-sm_temperature.desktop new file mode 100644 index 00000000..2179384c --- /dev/null +++ b/plasma/generic/applets/system-monitor/plasma-applet-sm_temperature.desktop @@ -0,0 +1,156 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Hardware Temperature +Name[ar]=حرارة العتاد +Name[ast]=Temperatura del hardware +Name[bg]=Температура на хардуера +Name[bs]=temperatura hardvera +Name[ca]=Temperatura del maquinari +Name[ca@valencia]=Temperatura del maquinari +Name[cs]=Teplota hardwaru +Name[da]=Hardwaretemperatur +Name[de]=Hardwaretemperatur +Name[el]=Θερμοκρασία Υλικού +Name[en_GB]=Hardware Temperature +Name[es]=Temperatura del hardware +Name[et]=Riistvara temperatuur +Name[eu]=Hardwarearen tenperatura +Name[fi]=Laitteiston lämpötilat +Name[fr]=Température du matériel +Name[ga]=Teocht na gCrua-Earraí +Name[gl]=Temperatura do hardware +Name[he]=טמפרטורת חומרה +Name[hi]=हार्डवेयर तापमान +Name[hr]=Temperatura hardvera +Name[hu]=Hardverhőmérséklet +Name[ia]=Temperatura Hardware +Name[id]=Temperatur Peranti Keras +Name[is]=Hitastig vélbúnaðar +Name[it]=Temperatura dell'hardware +Name[ja]=ハードウェアの温度 +Name[kk]=Жабдықтың температурасы +Name[km]=សីតុណ្ហភាព​ផ្នែក​រឹង +Name[kn]=ಯಂತ್ರಾಂಶ ತಾಪಮಾನ +Name[ko]=하드웨어 온도 +Name[lt]=Techninės įrangos temperatūra +Name[lv]=Aparatūras temperatūra +Name[mr]=हार्डवेअर तापमान +Name[nb]=Maskintemperatur +Name[nds]=Reedschap-Temperatuur +Name[nl]=Hardware temperatuur +Name[pa]=ਹਾਰਡਵੇਅਰ ਤਾਪਮਾਨ +Name[pl]=Temperatura sprzętu +Name[pt]=Temperatura do 'Hardware' +Name[pt_BR]=Temperatura do hardware +Name[ro]=Temperatură echipament +Name[ru]=Температурные датчики +Name[si]=දෘඩාංග උෂ්ණත්වය +Name[sk]=Teplota hardvéru +Name[sl]=Temperatura strojne opreme +Name[sr]=температура хардвера +Name[sr@ijekavian]=температура хардвера +Name[sr@ijekavianlatin]=temperatura hardvera +Name[sr@latin]=temperatura hardvera +Name[sv]=Hårdvarutemperatur +Name[tg]=Ҳарорати сахтафзор +Name[th]=อุณหภูมิของฮาร์ดแวร์ +Name[tr]=Donanım Sıcaklığı +Name[ug]=قاتتىق دېتال تېمپېراتۇرىسى +Name[uk]=Температура обладнання +Name[vi]=Nhiệt độ phần cứng +Name[wa]=Tchåleur di l' éndjolreye +Name[x-test]=xxHardware Temperaturexx +Name[zh_CN]=硬件温度计 +Name[zh_TW]=硬體溫度 +Comment=A system temperature monitor +Comment[ar]=يراقب حرارة النظام +Comment[ast]=Monitor de la temperatura del sistema +Comment[be@latin]=Nazirańnik za temperaturaju systemy +Comment[bg]=Наблюдение на температурата на компютъра +Comment[bs]=Nadgledanje temperature sistema +Comment[ca]=Un controlador de la temperatura del sistema +Comment[ca@valencia]=Un controlador de la temperatura del sistema +Comment[cs]=Monitor teploty systému +Comment[csb]=Mònitór temperaturë systemë +Comment[da]=Overvågning af systemtemperatur +Comment[de]=Ein Überwachungsmonitor für Temperatursensoren +Comment[el]=Ένας επόπτης θερμοκρασίας του συστήματος +Comment[en_GB]=A system temperature monitor +Comment[eo]=Systema temperatura rigardilo +Comment[es]=Monitor de la temperatura del sistema +Comment[et]=Süsteemi temperatuuri jälgija +Comment[eu]=Sistemaren tenperaturaren monitorea +Comment[fi]=Näyttää järjestelmän lämpötilat +Comment[fr]=Une surveillance de la température du système +Comment[fy]=In systeemtempratuer monitor +Comment[ga]=Monatóir theocht an chórais +Comment[gl]=Un vixilante da temperatura do sistema +Comment[gu]=સિસ્ટમ તાપમાન દેખરેખ +Comment[he]=משמש לניטור טמפרטורת המערכת +Comment[hi]=तंत्र तापक्रम मॉनीटर +Comment[hne]=तंत्र तापमान देखइया +Comment[hr]=Nadzor temperature sustava +Comment[hsb]=Monitor za systemowu temparaturu +Comment[hu]=Kijelzi a rendszer jellemző hőmérsékleteit +Comment[ia]=Un monitor de temperatura de systema +Comment[id]=Monitor temperatur sistem +Comment[is]=Eftirlit með hitastigi í kerfinu +Comment[it]=Indica la temperatura del sistema +Comment[ja]=システムの温度を監視します +Comment[kk]=Жүйек температурасын бақылау +Comment[km]=កម្មវិធី​ត្រួតពិនិត្យ​សីតុណ្ហភាព​របស់​ប្រព័ន្ធ +Comment[kn]=ವ್ಯವಸ್ಥೆಯ ಉಷ್ಣತೆಯ ಮೇಲ್ವಿಚಾರಕ +Comment[ko]=시스템 온도 모니터 +Comment[lt]=Sistemos temperatūros stebėtojas +Comment[lv]=Sistēmas temperatūras novērotājs +Comment[mk]=Монитор на температурата на системот +Comment[ml]=സിസ്റ്റം താപനില നിരീക്ഷകന്‍ +Comment[mr]=प्रणाली तापमान नियंत्रक +Comment[nb]=En overvåker for systemtemperaturen +Comment[nds]=En Wachter för de Systeemtemperatuur +Comment[nl]=Volgt de systeemtemperatuur +Comment[nn]=Overvaking av systemtemperaturen +Comment[or]=ତନ୍ତ୍ର ଉତ୍ତାପ ନିରିକ୍ଷକ +Comment[pa]=ਇੱਕ ਸਿਸਟਮ ਤਾਪਮਾਨ ਮਾਨੀਟਰ +Comment[pl]=Monitor temperatury komputera +Comment[pt]=Um monitor da temperatura do sistema +Comment[pt_BR]=Um monitor da temperatura do sistema +Comment[ro]=Monitor de temperatură a sistemului +Comment[ru]=Монитор температуры разных узлов компьютера +Comment[si]=පද්ධති උෂ්ණත්ව නිරික්‍ෂකය +Comment[sk]=Monitor teploty systému +Comment[sl]=Nadzornik temperature v sistemu +Comment[sr]=Надгледање температуре система +Comment[sr@ijekavian]=Надгледање температуре система +Comment[sr@ijekavianlatin]=Nadgledanje temperature sistema +Comment[sr@latin]=Nadgledanje temperature sistema +Comment[sv]=Övervakning av systemtemperatur +Comment[ta]=A system temperature monitor +Comment[tg]=Системный монитор KDE +Comment[th]=ตัวติดตามสถานะของอุณหภูมิ +Comment[tr]=Bir sistem sıcaklığı izleyici +Comment[ug]=سىستېما تېمپېراتۇرىسىنى كۆزەتكۈچ +Comment[uk]=Монітор системної температури +Comment[vi]=Một trình quản lý nhiệt độ hệ thống +Comment[wa]=On corwaitoe del tchåleur do sistinme +Comment[x-test]=xxA system temperature monitorxx +Comment[zh_CN]=系统温度监视器 +Comment[zh_TW]=系統溫度監視器 +Type=Service +Icon=view-statistics +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_sm_temperature +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=sm_temperature +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/generic/applets/system-monitor/plasma-applet-system-monitor.desktop b/plasma/generic/applets/system-monitor/plasma-applet-system-monitor.desktop new file mode 100644 index 00000000..81c394df --- /dev/null +++ b/plasma/generic/applets/system-monitor/plasma-applet-system-monitor.desktop @@ -0,0 +1,178 @@ +[Desktop Entry] +Name=System Monitor +Name[af]=Stelsel Monitor +Name[ar]=مراقب النظام +Name[ast]=Monitor del sistema +Name[be]=Сістэмны назіральнік +Name[be@latin]=Systemny nazirańnik +Name[bg]=Наблюдение на системата +Name[bn]=সিস্টেম মনিটর +Name[bn_IN]=সিস্টেম নিরীক্ষণ ব্যবস্থা +Name[bs]=Monitor sistema +Name[ca]=Monitor del sistema +Name[ca@valencia]=Monitor del sistema +Name[cs]=Monitor systému +Name[csb]=Mònitór systemë +Name[da]=Systemovervågning +Name[de]=Systemmonitor +Name[el]=Επόπτης συστήματος +Name[en_GB]=System Monitor +Name[eo]=Sistemstato-programo +Name[es]=Monitor del sistema +Name[et]=Süsteemi jälgija +Name[eu]=Sistema-monitorea +Name[fa]=نمایشگر سیستم +Name[fi]=Järjestelmän valvonta +Name[fr]=Surveillance du système +Name[fy]=Systeemmonitor +Name[ga]=Monatóir an Chórais +Name[gl]=Vixilante do sistema +Name[gu]=સિસ્ટમ દેખરેખ +Name[he]=מוניטור המערכת +Name[hi]=तंत्र मॉनीटर +Name[hne]=तंत्र मानीटर +Name[hr]=Nadzor sustava +Name[hsb]=Systemowy monitor +Name[hu]=Rendszermonitor +Name[ia]=Monitor de systema +Name[id]=Monitor Sistem +Name[is]=Kerfiseftirlit +Name[it]=Monitor di sistema +Name[ja]=システムモニタ +Name[kk]=Жүйе мониторы +Name[km]=កម្មវិធី​ត្រួត​​ពិនិត្យ​ប្រព័ន្ធ +Name[kn]=ವ್ಯವಸ್ಥೆಯ ಪ್ರದರ್ಶಕ +Name[ko]=시스템 모니터 +Name[ku]=Temaşekerê Pergalê +Name[lt]=Sistemos stebėtojas +Name[lv]=Sistēmas monitors +Name[mai]=सिस्टम मानीटर +Name[mk]=Системски монитор +Name[ml]=സിസ്റ്റം നിരീക്ഷകന്‍ +Name[mr]=प्रणाली मॉनिटर +Name[nb]=Systemovervåker +Name[nds]=Systeemkieker +Name[ne]=प्रणाली मनिटर +Name[nl]=Systeemmonitor +Name[nn]=Systemovervaking +Name[oc]=Monitor sistèma +Name[pa]=ਸਿਸਟਮ ਮਾਨੀਟਰ +Name[pl]=Monitor systemu +Name[pt]=Monitor do Sistema +Name[pt_BR]=Monitor do sistema +Name[ro]=Monitor de sistem +Name[ru]=Системный монитор +Name[se]=Vuogádatgoziheaddji +Name[si]=පද්ධති නිරීක්‍ෂකය +Name[sk]=Monitor systému +Name[sl]=Sistemski nadzornik +Name[sr]=надзорник система +Name[sr@ijekavian]=надзорник система +Name[sr@ijekavianlatin]=nadzornik sistema +Name[sr@latin]=nadzornik sistema +Name[sv]=Systemövervakare +Name[ta]=கணினி நோட்டம் +Name[te]=సిస్టమ్ మానిటర్ +Name[tg]=Назорати система +Name[th]=ติดตามการทำงานของระบบ +Name[tr]=Sistem İzleyici +Name[ug]=سىستېما كۆزەتكۈچ +Name[uk]=Монітор системи +Name[vi]=Bộ theo dõi hệ thống +Name[wa]=Corwaitoe do sistinme +Name[x-test]=xxSystem Monitorxx +Name[zh_CN]=系统监视器 +Name[zh_TW]=系統監視器 +Comment=System monitoring applet +Comment[ar]=بريمج مراقب النظام +Comment[ast]=Miniaplicación de monitorización del sistema +Comment[be@latin]=Aplet nazirańnia za systemaju +Comment[bg]=Аплет за наблюдение на системата +Comment[bn]=সিস্টেম মনিটর অ্যাপলেট +Comment[bn_IN]=সিস্টেম নিরীক্ষণের অ্যাপ্লেট +Comment[bs]=Aplet za nadgledanje sistema +Comment[ca]=Miniaplicació controladora del sistema +Comment[ca@valencia]=Miniaplicació controladora del sistema +Comment[cs]=Applet pro monitorování systému +Comment[csb]=Aplet mònitorowaniô systemë +Comment[da]=Applet til systemovervågning +Comment[de]=Allgemeiner Systemmonitor +Comment[el]=Μικροεφαρμογή εποπτείας συστήματος +Comment[en_GB]=System monitoring applet +Comment[es]=Miniaplicación de monitorización del sistema +Comment[et]=Süsteemi jälgimise aplett +Comment[eu]=Sistema kontrolatzeko miniaplikazioa +Comment[fi]=Järjestelmänvalvontasovelma +Comment[fr]=Applet de surveillance du système +Comment[fy]=systeemtempratuer applet +Comment[ga]=Feidhmchláirín mhonatóireacht an chórais +Comment[gl]=Applet de vixilancia do sistema +Comment[gu]=સિસ્ટમ દેખરેખ એપ્લેટ +Comment[he]=יישומון לניטור המערכת +Comment[hi]=तंत्र मॉनिटरिंग एप्लेट +Comment[hne]=तंत्र मानीटर एपलेट +Comment[hr]=Nadzor sustava +Comment[hsb]=Applet za systemowy monitor +Comment[hu]=Rendszermonitor kisalkalmazás +Comment[ia]=Applet per monitorar le systema +Comment[id]=Applet monitor sistem +Comment[is]=Eftirlitsforritlingur í kerfisbakka +Comment[it]=Programma di monitoraggio del sistema +Comment[ja]=システムの状態を監視するアプレット +Comment[kk]=Жүйені бақылау апплеті +Comment[km]=អាប់ភ្លេត​​ត្រួតពិនិត្យ​ប្រព័ន្ធ +Comment[kn]=ವ್ಯವಸ್ಥೆಯ ಮೇಲ್ವಿಚಾರಕ ಆಪ್ಲೆಟ್ +Comment[ko]=시스템 모니터 애플릿 +Comment[ku]=Sepanoka temaşe kirina pergalê +Comment[lt]=Sistemos stebėjimo įskiepis +Comment[lv]=Sistēmas novērošanas sīkrīks +Comment[mk]=Аплет за следење на системот +Comment[ml]=സിസ്റ്റം നിരീക്ഷണി ലഘുപ്രയോഗം +Comment[mr]=प्रणाली नियंत्रण ऍपलेट +Comment[nb]=Systemovervåker miniprogram +Comment[nds]=Systeemwachter-Lüttprogramm +Comment[nl]=Systeemmonitorapplet +Comment[nn]=Overvaking av systemet +Comment[or]=ତନ୍ତ୍ର ନିରିକ୍ଷଣ ଆପଲେଟ +Comment[pa]=ਸਿਸਟਮ ਮਾਨੀਟਰ ਐਪਲਿਟ +Comment[pl]=Aplet monitora systemu +Comment[pt]='Applet' de monitorização do sistema +Comment[pt_BR]=Miniaplicativo de monitoramento do sistema +Comment[ro]=Miniaplicație de monitorizare a sistemului +Comment[ru]=Системный монитор +Comment[si]=පද්ධති නිරික්‍ෂණ යෙදුම්පත +Comment[sk]=Aplet pre monitorovanie systému +Comment[sl]=Sistemski nadzornik +Comment[sr]=Аплет за надгледање система +Comment[sr@ijekavian]=Аплет за надгледање система +Comment[sr@ijekavianlatin]=Aplet za nadgledanje sistema +Comment[sr@latin]=Aplet za nadgledanje sistema +Comment[sv]=Miniprogram för systemövervakning +Comment[ta]=கணினி நோட்ட சிறுபயன்பாடு +Comment[tg]=Барномаи мониторинги система +Comment[th]=แอพเพล็ตติดตามการทำงานของระบบ +Comment[tr]=Sistem izleme programcığı +Comment[ug]=سىستېما كۆزىتىش قوللانچىقى +Comment[uk]=Аплет моніторингу системи +Comment[wa]=Aplikete di corwaitaedje do sistinme +Comment[x-test]=xxSystem monitoring appletxx +Comment[zh_CN]=系统监视器小程序 +Comment[zh_TW]=系統監控小程式 +Type=Service +Icon=utilities-system-monitor +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_system-monitor +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=system-monitor_applet +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/generic/applets/system-monitor/plotter.cpp b/plasma/generic/applets/system-monitor/plotter.cpp new file mode 100644 index 00000000..231a4423 --- /dev/null +++ b/plasma/generic/applets/system-monitor/plotter.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2010 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "plotter.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace SM { + +Plotter::Plotter(QGraphicsItem* parent, Qt::WindowFlags wFlags) + : QGraphicsWidget(parent, wFlags) + , m_layout(0) + , m_plotter(0) + , m_meter(0) + , m_plotCount(1) + , m_min(0.0) + , m_max(0.0) + , m_overlayFrame(0) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + createWidgets(); + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeChanged())); +} + +Plotter::~Plotter() +{ +} + +void Plotter::setAnalog(bool analog) +{ + if (analog && m_layout->count() < 2) { + m_meter = new Plasma::Meter(this); + m_meter->setMeterType(Plasma::Meter::AnalogMeter); + m_meter->setLabelAlignment(1, Qt::AlignCenter); + m_layout->insertItem(0, m_meter); + m_meter->setMinimum(m_min); + m_meter->setMaximum(m_max); + m_meter->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + themeChanged(); + } else if (m_layout->count() > 1) { + m_layout->removeAt(0); + delete m_meter; + m_meter = 0; + } +} + +void Plotter::setMinMax(double min, double max) +{ + if (m_meter) { + m_meter->setMinimum(min); + m_meter->setMaximum(max); + } + m_plotter->setUseAutoRange(false); + m_plotter->setVerticalRange(min, max); + m_min = min; + m_max = max; +} + +const QString& Plotter::title() +{ + return m_title; +} + +void Plotter::setTitle(const QString& title) +{ + m_plotter->setTitle(title); + if (m_meter) { + m_meter->setLabel(0, title); + } + m_title = title; +} + +void Plotter::setUnit(const QString& unit) +{ + m_plotter->setUnit(unit); + m_unit = unit; +} + +void Plotter::setScale(qreal scale) +{ + m_plotter->scale(scale); +} + +void Plotter::setStackPlots(bool stack) +{ + m_plotter->setStackPlots(stack); +} + +void Plotter::setPlotCount(int count) +{ + for (int i = 0; i < m_plotCount; ++i) { + m_plotter->removePlot(0); + } + m_plotCount = count; + Plasma::Theme* theme = Plasma::Theme::defaultTheme(); + QColor text = theme->color(Plasma::Theme::TextColor); + QColor bg = theme->color(Plasma::Theme::BackgroundColor); + for (int i = 0; i < m_plotCount; ++i) { + QColor color = KColorUtils::tint(text, bg, 0.4 + ((double)i / 2.5)); + m_plotter->addPlot(color); + } +} + +void Plotter::setCustomPlots(const QList& colors) +{ + for (int i = 0; i < m_plotCount; ++i) { + m_plotter->removePlot(0); + } + m_plotCount = colors.count(); + foreach (const QColor& color, colors) { + m_plotter->addPlot(color); + } +} + +void Plotter::createWidgets() +{ + m_layout = new QGraphicsLinearLayout(Qt::Horizontal); + m_layout->setContentsMargins(0, 0, 0, 0); + m_layout->setSpacing(5); + setLayout(m_layout); + + m_plotter = new Plasma::SignalPlotter(this); + m_plotter->setThinFrame(false); + m_plotter->setShowLabels(false); + m_plotter->setShowTopBar(true); + m_plotter->setShowVerticalLines(false); + m_plotter->setShowHorizontalLines(false); + m_plotter->setUseAutoRange(true); + m_plotter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_layout->addItem(m_plotter); + themeChanged(); + setPlotCount(m_plotCount); +} + +void Plotter::themeChanged() +{ + Plasma::Theme* theme = Plasma::Theme::defaultTheme(); + if (m_meter) { + m_meter->setLabelColor(0, theme->color(Plasma::Theme::TextColor)); + m_meter->setLabelColor(0, theme->color(Plasma::Theme::TextColor)); + m_meter->setLabelColor(1, QColor("#000")); + } + m_plotter->setFontColor(theme->color(Plasma::Theme::TextColor)); + m_plotter->setSvgBackground("widgets/plot-background"); + QColor linesColor = theme->color(Plasma::Theme::TextColor); + linesColor.setAlphaF(0.4); + m_plotter->setHorizontalLinesColor(linesColor); + m_plotter->setVerticalLinesColor(linesColor); + resizeEvent(0); +} + +void Plotter::addSample(const QList& values) +{ + m_plotter->addSample(values); + QStringList list; + foreach (double value, values) { + double v = value / m_plotter->scaledBy(); + list << QString("%1 %2").arg(v, 0, 'f', (v > 1000.0) ? 0 : 1).arg(m_unit); + } + setOverlayText(list.join(" / ")); + if (m_meter) { + m_meter->setValue(values[0]); + } +} + +void Plotter::setOverlayText(const QString& text) +{ + if (!m_overlayFrame) { + QGraphicsLinearLayout* layout = new QGraphicsLinearLayout(Qt::Vertical, m_plotter); + m_plotter->setLayout(layout); + m_overlayFrame = new Plasma::Frame(m_plotter); + m_overlayFrame->setZValue(10); + m_overlayFrame->resize(m_overlayFrame->size().height() * 2.5, + m_overlayFrame->size().height()); + layout->addStretch(); + QGraphicsLinearLayout* layout2 = new QGraphicsLinearLayout(Qt::Horizontal, layout); + layout2->addStretch(); + layout2->addItem(m_overlayFrame); + layout2->addStretch(); + layout->addItem(layout2); + resizeEvent(0); + } + m_overlayFrame->setText(text); + if (m_meter) { + if (m_showAnalogValue) { + m_meter->setLabel(1, text); + } else { + m_meter->setLabel(1, QString()); + } + } +} + +void Plotter::resizeEvent(QGraphicsSceneResizeEvent* event) +{ + Q_UNUSED(event) + qreal h = size().height(); + qreal fontHeight = h / (7.0 * 1.5); // Seven rows + Plasma::Theme* theme = Plasma::Theme::defaultTheme(); + QFont font = theme->font(Plasma::Theme::DefaultFont); + QFont smallest = KGlobalSettings::smallestReadableFont(); + bool show = false; + QFontMetrics metrics(font); + QStringList list; + for (int i = 0; i < m_plotCount; ++i) { + list << QString("888.0 %2").arg(m_unit); + } + QString valueText = list.join(" / "); + + font.setPointSizeF(smallest.pointSizeF()); + forever { + metrics = QFontMetrics(font); + if (metrics.height() > fontHeight) { + break; + } + font.setPointSizeF(font.pointSizeF() + 0.5); + show = true; + } + m_plotter->setFont(font); + m_plotter->setShowTopBar(metrics.height() < h / 6); + m_plotter->setShowLabels(show); + m_plotter->setShowHorizontalLines(show); + if (m_overlayFrame) { + m_overlayFrame->setVisible(metrics.height() < h / 3 && + metrics.width(valueText) < size().width() * 0.8); + m_overlayFrame->setFont(font); + } + + if (m_meter) { + m_meter->setLabelFont(0, font); + m_meter->setLabelFont(1, font); + // Make analog meter square + m_meter->setMinimumSize(h, 8); + m_showAnalogValue = (m_meter->size().width() * 0.7 > metrics.width(valueText)); + if (m_meter->size().width() * 0.9 > metrics.width(m_title)) { + m_meter->setLabel(0, m_title); + } else { + m_meter->setLabel(0, QString()); + } + m_meter->setLabel(1, QString()); + } +} + +} // namespace + +#include "plotter.moc" diff --git a/plasma/generic/applets/system-monitor/plotter.h b/plasma/generic/applets/system-monitor/plotter.h new file mode 100644 index 00000000..b40a855b --- /dev/null +++ b/plasma/generic/applets/system-monitor/plotter.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SM_PLOTTER_HEADER +#define SM_PLOTTER_HEADER + +#include + +#include "sm_export.h" + +class QGraphicsLinearLayout; + +namespace Plasma { + class Meter; + class SignalPlotter; + class Frame; +} + +namespace SM { + +class SM_EXPORT Plotter : public QGraphicsWidget +{ + Q_OBJECT + public: + Plotter(QGraphicsItem* parent = 0, Qt::WindowFlags wFlags = 0); + ~Plotter(); + + void addSample(const QList& values); + void setAnalog(bool analog); + void setMinMax(double min, double max); + const QString& title(); + void setTitle(const QString& title); + void setUnit(const QString& unit); + void setPlotCount(int count); + void setCustomPlots(const QList& colors); + void setScale(qreal scale); + void setStackPlots(bool stack); + + protected slots: + void themeChanged(); + + protected: + void createWidgets(); + void setOverlayText(const QString& text); + virtual void resizeEvent(QGraphicsSceneResizeEvent* event); + + private: + QGraphicsLinearLayout *m_layout; + Plasma::SignalPlotter *m_plotter; + Plasma::Meter *m_meter; + int m_plotCount; + QString m_title; + QString m_unit; + double m_min; + double m_max; + Plasma::Frame* m_overlayFrame; + bool m_showAnalogValue; +}; + +} + +#endif diff --git a/plasma/generic/applets/system-monitor/ram-config.ui b/plasma/generic/applets/system-monitor/ram-config.ui new file mode 100644 index 00000000..0a0c2344 --- /dev/null +++ b/plasma/generic/applets/system-monitor/ram-config.ui @@ -0,0 +1,93 @@ + + + config + + + + 0 + 0 + 382 + 263 + + + + + + + + 0 + + + + + &Memory: + + + treeView + + + + + + + false + + + true + + + true + + + + + + + + + Update &interval: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + intervalSpinBox + + + + + + + 1 + + + 0.100000000000000 + + + 525600.000000000000000 + + + 2.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/plasma/generic/applets/system-monitor/ram.cpp b/plasma/generic/applets/system-monitor/ram.cpp new file mode 100644 index 00000000..ee88eb90 --- /dev/null +++ b/plasma/generic/applets/system-monitor/ram.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2008 Petri Damsten + * Copyright (C) 2010 Michel Lafon-Puyo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "ram.h" +#include +#include +#include +#include +#include +#include "plotter.h" + +/* All sources we are interested in. */ +static const char phys_source[] = "mem/physical/application"; +static const char swap_source[] = "mem/swap/used"; + +SM::Ram::Ram(QObject *parent, const QVariantList &args) + : SM::Applet(parent, args) +{ + setHasConfigurationInterface(true); + resize(234 + 20 + 23, 135 + 20 + 25); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +SM::Ram::~Ram() +{ +} + +void SM::Ram::init() +{ + KGlobal::locale()->insertCatalog("plasma_applet_system-monitor"); + setEngine(dataEngine("systemmonitor")); + setTitle(i18n("RAM")); + + /* At the time this method is running, not all source may be connected. */ + connect(engine(), SIGNAL(sourceAdded(QString)), this, SLOT(sourceAdded(QString))); + foreach (const QString& source, engine()->sources()) { + sourceAdded(source); + } +} + +void SM::Ram::configChanged() +{ + KConfigGroup cg = config(); + setInterval(cg.readEntry("interval", 2.0) * 1000.0); + // sanity check + QStringList memories = cg.readEntry("memories", m_memories); + foreach (QString source, memories) { + if (source != phys_source && source != swap_source) + memories.removeAt(memories.indexOf(source)); + } + setSources(memories); + m_max.clear(); + connectToEngine(); +} + +void SM::Ram::sourceAdded(const QString& name) +{ + if ((name == phys_source || name == swap_source) && !m_memories.contains(name)) { + m_memories << name; + if (m_memories.count() == 2) { + // all sources are ready + QTimer::singleShot(0, this, SLOT(sourcesAdded())); + } + } +} + +void SM::Ram::sourcesAdded() +{ + configChanged(); +} + +bool SM::Ram::addVisualization(const QString& source) +{ + QStringList l = source.split('/'); + if (l.count() < 3) { + return false; + } + QString ram = l[1]; + + SM::Plotter *plotter = new SM::Plotter(this); + + // 'ram' should be "physical" or "swap". I'm not aware of other values + // for it, but who knows. + if (ram == "physical") { + ram = i18nc("noun, hardware, physical RAM/memory", "physical"); + } else if (ram == "swap") { + ram = i18nc("noun, hardware, swap file/partition", "swap"); + } + + plotter->setTitle(ram); + plotter->setUnit("B"); + + appendVisualization(source, plotter); + setPreferredItemHeight(80); + + return true; +} + +double SM::Ram::preferredBinaryUnit() +{ + KLocale::BinaryUnitDialect binaryUnit = KGlobal::locale()->binaryUnitDialect(); + + // this makes me feel all dirty inside. but it's the only way I could find + // which will let us know what we should be scaling our graph by, independent + // of how locale settings are configured. + switch (binaryUnit) { + case KLocale::IECBinaryDialect: + //fallthrough + case KLocale::JEDECBinaryDialect: + return 1024; + break; + case KLocale::MetricBinaryDialect: + return 1000; + break; + + default: + // being careful..I'm sure some genius will invent a new byte unit system ;-) + Q_ASSERT_X(0, "preferredBinaryUnit", "invalid binary preference enum returned"); + return 0; + } +} + +QStringList SM::Ram::preferredUnitsList() +{ + QStringList units; + KLocale::BinaryUnitDialect binaryUnit = KGlobal::locale()->binaryUnitDialect(); + switch (binaryUnit) { + case KLocale::IECBinaryDialect: + units << "B" << "KiB" << "MiB" << "GiB" << "TiB"; + break; + case KLocale::JEDECBinaryDialect: + units << "B" << "KB" << "MB" << "GB" << "TB"; + break; + case KLocale::MetricBinaryDialect: + units << "B" << "kB" << "MB" << "GB" << "TB"; + break; + default: + Q_ASSERT_X(0, "preferredBinaryUnit", "invalid binary preference enum returned"); + } + + return units; +} + +void SM::Ram::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data) +{ + SM::Plotter *plotter = qobject_cast(visualization(source)); + if (plotter) { + /* A factor to convert from default units to bytes. + * If units is not "KB", assume it is bytes. + * NOTE: the dataengine refers to KB == 1024. so it's KiB as well. + * Though keep in mind, KB does not imply 1024 and can be KB == 1000 as well. + */ + const double preferredUnit = preferredBinaryUnit(); + const double factor = (data["units"].toString() == "KB") ? preferredUnit : 1.0; + const double value_b = data["value"].toDouble() * factor; + const double max_b = data["max"].toDouble() * factor; + const QStringList units = preferredUnitsList(); + + if (value_b > m_max[source]) { + m_max[source] = max_b; + plotter->setMinMax(0.0, max_b); + qreal scale = 1.0; + int i = 0; + while (max_b / scale > factor && i < units.size()) { + scale *= factor; + ++i; + } + + plotter->setUnit(units[i]); + plotter->setScale(scale); + } + + plotter->addSample(QList() << value_b); + QString temp = KGlobal::locale()->formatByteSize(value_b); + + if (mode() == SM::Applet::Panel) { + setToolTip(source, QString("%1%2of%3") + .arg(plotter->title()) + .arg(temp) + .arg(KGlobal::locale()->formatByteSize(m_max[source]))); + } + } +} + +void SM::Ram::createConfigurationInterface(KConfigDialog *parent) +{ + QWidget *widget = new QWidget(); + ui.setupUi(widget); + m_model.clear(); + m_model.setHorizontalHeaderLabels(QStringList() << i18n("RAM")); + QStandardItem *parentItem = m_model.invisibleRootItem(); + QRegExp rx("mem/(\\w+)/.*"); + QString ramName; + + foreach (const QString& ram, m_memories) { + if (rx.indexIn(ram) != -1) { + ramName = rx.cap(1); + + // 'ram' should be "physical" or "swap". I'm not aware of other values + // for it, but who knows. (see also addVisualization) + if (ramName == "physical") { + ramName = i18nc("noun, hardware, physical RAM/memory", "physical"); + } else if (ramName == "swap") { + ramName = i18nc("noun, hardware, swap file/partition", "swap"); + } + + QStandardItem *ramItem = new QStandardItem(ramName); + ramItem->setEditable(false); + ramItem->setCheckable(true); + ramItem->setData(ram); + + if (sources().contains(ram)) { + ramItem->setCheckState(Qt::Checked); + } + + parentItem->appendRow(ramItem); + } + } + + ui.treeView->setModel(&m_model); + ui.treeView->resizeColumnToContents(0); + ui.intervalSpinBox->setValue(interval() / 1000.0); + ui.intervalSpinBox->setSuffix(i18nc("second", " s")); + parent->addPage(widget, i18n("RAM"), "media-flash"); + + connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); + connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); + connect(ui.treeView, SIGNAL(clicked(QModelIndex)), parent, SLOT(settingsModified())); + connect(ui.intervalSpinBox, SIGNAL(valueChanged(QString)), parent, SLOT(settingsModified())); +} + +void SM::Ram::configAccepted() +{ + KConfigGroup cg = config(); + QStandardItem *parentItem = m_model.invisibleRootItem(); + + clear(); + + for (int i = 0; i < parentItem->rowCount(); ++i) { + QStandardItem *item = parentItem->child(i, 0); + if (item) { + if (item->checkState() == Qt::Checked) { + // data() is the untranslated string + // for use with sources + appendSource(item->data().toString()); + } + } + } + + // note we write and read non-translated + // version to config file. + cg.writeEntry("memories", sources()); + + double interval = ui.intervalSpinBox->value(); + cg.writeEntry("interval", interval); + + emit configNeedsSaving(); +} + +#include "ram.moc" diff --git a/plasma/generic/applets/system-monitor/ram.h b/plasma/generic/applets/system-monitor/ram.h new file mode 100644 index 00000000..c9edde9b --- /dev/null +++ b/plasma/generic/applets/system-monitor/ram.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2008 Petri Damsten + * Copyright (C) 2010 Michel Lafon-Puyo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef RAM_HEADER +#define RAM_HEADER + +#include +#include "applet.h" +#include +#include + +class QStandardItemModel; + +namespace SM { + +class Ram : public Applet +{ + Q_OBJECT + public: + Ram(QObject *parent, const QVariantList &args); + ~Ram(); + + virtual void init(); + virtual bool addVisualization(const QString&); + virtual void createConfigurationInterface(KConfigDialog *parent); + + public slots: + void dataUpdated(const QString &name, + const Plasma::DataEngine::Data &data); + void sourceAdded(const QString &name); + void sourcesAdded(); + void configAccepted(); + void configChanged(); + + private: + // below methods exist because KLocale has no nice + // way of getting this info :( + // thought about adding it to the api, but perhaps this + // code is the only one that uses it? + /** + * The preferred binary unit byte value + * e.g. KiB, kiB, KIB, etc. + * @return double 1024 or 1000 + */ + double preferredBinaryUnit(); + + /** + * The preferred binary unit abbreviations. + * @return QStringList B, KiB, MiB, GiB, TiB.\ + * or whatever is best fit for current binary unit + * settings via klocale. + */ + QStringList preferredUnitsList(); + + Ui::config ui; + QStandardItemModel m_model; + QStringList m_memories; + QHash m_max; +}; +} + +K_EXPORT_PLASMA_APPLET(sm_ram, SM::Ram) + +#endif diff --git a/plasma/generic/applets/system-monitor/sm_export.h b/plasma/generic/applets/system-monitor/sm_export.h new file mode 100644 index 00000000..a802a7dd --- /dev/null +++ b/plasma/generic/applets/system-monitor/sm_export.h @@ -0,0 +1,40 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + + 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 SM_EXPORT_H +#define SM_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include + +#ifndef SM_EXPORT +# if defined(MAKE_PLASMA_APPLET_SYSTEM_MONITOR_LIB) + /* We are building this library */ +# define SM_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define SM_EXPORT KDE_IMPORT +# endif +#endif + +# ifndef SM_EXPORT_DEPRECATED +# define SM_EXPORT_DEPRECATED KDE_DEPRECATED SM_EXPORT +# endif + +#endif diff --git a/plasma/generic/applets/system-monitor/system-monitor.cpp b/plasma/generic/applets/system-monitor/system-monitor.cpp new file mode 100644 index 00000000..fc771b89 --- /dev/null +++ b/plasma/generic/applets/system-monitor/system-monitor.cpp @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2007 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "system-monitor.h" +#include "monitorbutton.h" +#include "applet.h" +#include +#include +#include +#include +#include +#include + +SystemMonitor::SystemMonitor(QObject *parent, const QVariantList &args) + : Plasma::PopupApplet(parent, args), m_layout(0), m_buttons(0), m_widget(0) +{ + setAspectRatioMode(Plasma::IgnoreAspectRatio); +} + +SystemMonitor::~SystemMonitor() +{ +} + +void SystemMonitor::saveState(KConfigGroup &group) const +{ + QStringList appletNames; + foreach (SM::Applet *applet, m_applets) { + applet->saveConfig(group); + appletNames << applet->objectName(); + } + + group.writeEntry("applets", appletNames); +} + +void SystemMonitor::createConfigurationInterface(KConfigDialog *parent) +{ + foreach (Plasma::Applet *applet, m_applets) { + applet->createConfigurationInterface(parent); + } +} + +void SystemMonitor::init() +{ + KConfigGroup cg = config(); + QStringList appletNames = cg.readEntry("applets", QStringList()); + + m_widget = new QGraphicsWidget(this); + m_layout = new QGraphicsLinearLayout(Qt::Vertical); + m_layout->setContentsMargins(0, 0, 0, 0); + m_buttons = new QGraphicsLinearLayout(Qt::Horizontal); + m_buttons->setContentsMargins(0, 0, 0, 0); + m_buttons->setSpacing(5); + + QMap appletsFound; + KPluginInfo::List appletList = listAppletInfo("System Information"); + foreach (const KPluginInfo &pluginInfo, appletList) { + if (pluginInfo.pluginName().startsWith("sm_") && !pluginInfo.isHidden()) { + appletsFound.insert(pluginInfo.pluginName(), pluginInfo); + } + } + + foreach (const KPluginInfo &pluginInfo, appletsFound) { + MonitorButton *button = new MonitorButton(m_widget); + button->setObjectName(pluginInfo.pluginName()); + Plasma::ToolTipContent data; + data.setMainText(pluginInfo.name()); + data.setImage(KIcon(pluginInfo.icon()).pixmap(IconSize(KIconLoader::Desktop))); + Plasma::ToolTipManager::self()->setContent(button, data); + button->setCheckable(true); + button->setImage(pluginInfo.icon()); + if (appletNames.contains(pluginInfo.pluginName())) { + button->setChecked(true); + } + connect(button, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + m_buttons->addItem(button); + m_monitorButtons << button; + // this does not work + KGlobal::locale()->insertCatalog(pluginInfo.pluginName()); + } + + m_layout->addItem(m_buttons); + foreach (const QString& appletName, appletNames) { + if (appletsFound.contains(appletName)) { + Applet * applet = addApplet(appletName); + + if (applet) { + Plasma::Constraints constraints(Plasma::ImmutableConstraint | + Plasma::StartupCompletedConstraint); + applet->updateConstraints(constraints); + applet->flushPendingConstraintsEvents(); + } + } + } + + m_widget->setLayout(m_layout); + checkGeometry(); + + setPopupIcon("utilities-system-monitor"); +} + +void SystemMonitor::toggled(bool toggled) +{ + removeApplet(sender()->objectName()); + + if (toggled) { + SM::Applet * applet = addApplet(sender()->objectName()); + + if (applet) { + Plasma::Constraints constraints(Plasma::ImmutableConstraint | + Plasma::StartupCompletedConstraint); + applet->updateConstraints(constraints); + applet->flushPendingConstraintsEvents(); + } + } +} + +void SystemMonitor::configChanged() +{ + KConfigGroup cg = config(); + QStringList appletNames = cg.readEntry("applets", QStringList()); + + QStringList oldAppletNames; + foreach (SM::Applet *applet, m_applets) { + oldAppletNames << applet->objectName(); + } + + if (appletNames == oldAppletNames) { + foreach (SM::Applet *applet, m_applets) + applet->configChanged(); + } else { + QMap appletsFound; + KPluginInfo::List appletList = listAppletInfo("System Information"); + foreach (const KPluginInfo &pluginInfo, appletList) { + if (pluginInfo.pluginName().startsWith("sm_") && !pluginInfo.isHidden()) { + appletsFound.insert(pluginInfo.pluginName(), pluginInfo); + } + } + + foreach (MonitorButton *button, m_monitorButtons) { + button->setChecked(false); + } + + foreach (const QString& appletName, appletNames) { + if (appletsFound.contains(appletName)) { + foreach (MonitorButton* button, m_monitorButtons) { + if (button->objectName() == appletName) + button->setChecked(true); + } + } + } + checkGeometry(); + } +} + +SM::Applet *SystemMonitor::addApplet(const QString &name) +{ + if (name.isEmpty()) { + return 0; + } + + Plasma::Applet* plasmaApplet = Plasma::Applet::load(name, 0, QVariantList() << "SM"); + SM::Applet* applet = qobject_cast(plasmaApplet); + if (applet) { + applet->setParentItem(m_widget); + m_applets.append(applet); + connect(applet, SIGNAL(geometryChecked()), this, SLOT(checkGeometry())); + connect(applet, SIGNAL(destroyed(QObject*)), this, SLOT(appletRemoved(QObject*))); + applet->setFlag(QGraphicsItem::ItemIsMovable, false); + applet->setBackgroundHints(Plasma::Applet::NoBackground); + applet->setObjectName(name); + connect(applet, SIGNAL(configNeedsSaving()), this, SIGNAL(configNeedsSaving())); + m_layout->addItem(applet); + applet->init(); + + KConfigGroup cg = config(); + saveState(cg); + emit configNeedsSaving(); + } else if (plasmaApplet) { + delete plasmaApplet; + } + + return applet; +} + +void SystemMonitor::removeApplet(const QString &name) +{ + foreach (SM::Applet *applet, m_applets) { + if (applet->objectName() == name) { + applet->destroy(); + } + } +} + +void SystemMonitor::appletRemoved(QObject *object) +{ + SM::Applet *applet = static_cast(object); + + foreach (SM::Applet *a, m_applets) { + if (a == applet) { + m_layout->removeItem(applet); + m_applets.removeAll(applet); + checkGeometry(); + + KConfigGroup cg = config(); + saveState(cg); + emit configNeedsSaving(); + } + } + + // sanity check the buttons + QSet running; + foreach (SM::Applet *a, m_applets) { + running << a->objectName(); + } + + foreach (MonitorButton* button, m_monitorButtons) { + if (!running.contains(button->objectName())) { + kDebug() << "unchecking" << button->objectName(); + button->setChecked(false); + } + } +} + +void SystemMonitor::checkGeometry() +{ + QSizeF margins = size() - contentsRect().size(); + qreal minHeight = m_buttons->minimumHeight(); + //kDebug() << minHeight; + + foreach (SM::Applet *applet, m_applets) { + //kDebug() << applet->minSize() << applet->minimumSize() + // << applet->metaObject()->className() << applet->size() - applet->contentsRect().size(); + minHeight += applet->preferredSize().height() + m_layout->spacing(); + } + + + update(); + /* + kDebug() << m_widget->size().height() << m_layout->geometry().height(); + foreach (SM::Applet *applet, m_applets) { + kDebug() << applet->metaObject()->className() << applet->size().height(); + } + for (int i = 0; i < m_layout->count(); ++i) { + kDebug() << m_layout->itemAt(i)->geometry().top() << m_layout->itemAt(i)->geometry().height(); + } + */ +} + +QGraphicsWidget *SystemMonitor::graphicsWidget() +{ + return m_widget; +} + +void SystemMonitor::constraintsEvent(Plasma::Constraints constraints) +{ + Plasma::Constraints passOn = Plasma::NoConstraint; + + if (constraints & Plasma::ImmutableConstraint) { + foreach (MonitorButton* button, m_monitorButtons) { + button->setEnabled(immutability() == Plasma::Mutable); + } + + passOn |= Plasma::ImmutableConstraint; + } + + if (constraints & Plasma::StartupCompletedConstraint) { + passOn |= Plasma::StartupCompletedConstraint; + } + + if (passOn != Plasma::NoConstraint) { + foreach (Plasma::Applet *applet, m_applets) { + applet->updateConstraints(passOn); + if (passOn & Plasma::StartupCompletedConstraint) { + applet->flushPendingConstraintsEvents(); + } + } + } + + PopupApplet::constraintsEvent(constraints); +} + +#include "system-monitor.moc" diff --git a/plasma/generic/applets/system-monitor/system-monitor.h b/plasma/generic/applets/system-monitor/system-monitor.h new file mode 100644 index 00000000..dc889021 --- /dev/null +++ b/plasma/generic/applets/system-monitor/system-monitor.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SYSTEM_MONITOR_HEADER +#define SYSTEM_MONITOR_HEADER + +#include +#include + +namespace SM { + class Applet; +} +class MonitorButton; + +class QGraphicsLinearLayout; + +class SystemMonitor : public Plasma::PopupApplet +{ + Q_OBJECT + public: + SystemMonitor(QObject *parent, const QVariantList &args); + virtual ~SystemMonitor(); + + void init(); + virtual QGraphicsWidget *graphicsWidget(); + virtual void constraintsEvent(Plasma::Constraints constraints); + + public slots: + void checkGeometry(); + + protected slots: + void toggled(bool toggled); + void appletRemoved(QObject *object); + void configChanged(); + + protected: + SM::Applet *addApplet(const QString &name); + void removeApplet(const QString &name); + void saveState(KConfigGroup &group) const; + void createConfigurationInterface(KConfigDialog *parent); + + private: + QGraphicsLinearLayout *m_layout; + QGraphicsLinearLayout *m_buttons; + QList m_applets; + QList m_monitorButtons; + QGraphicsWidget *m_widget; +}; + +K_EXPORT_PLASMA_APPLET(system-monitor_applet, SystemMonitor) + +#endif diff --git a/plasma/generic/applets/system-monitor/temperature-config.ui b/plasma/generic/applets/system-monitor/temperature-config.ui new file mode 100644 index 00000000..6bec6103 --- /dev/null +++ b/plasma/generic/applets/system-monitor/temperature-config.ui @@ -0,0 +1,90 @@ + + + config + + + + 0 + 0 + 383 + 323 + + + + + + + + + + &Available temperatures: + + + treeView + + + + + + + false + + + true + + + true + + + + + + + + + Update &interval: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + intervalSpinBox + + + + + + + 1 + + + 0.100000000000000 + + + 525600.000000000000000 + + + 2.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/plasma/generic/applets/system-monitor/temperature-offset-delegate.cpp b/plasma/generic/applets/system-monitor/temperature-offset-delegate.cpp new file mode 100644 index 00000000..2ed90d03 --- /dev/null +++ b/plasma/generic/applets/system-monitor/temperature-offset-delegate.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 Elvis Stansvik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "temperature-offset-delegate.h" + +#include + +TemperatureOffsetDelegate::TemperatureOffsetDelegate(QObject *parent) : QItemDelegate(parent) +{ +} + +QWidget *TemperatureOffsetDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + Q_UNUSED(option); + Q_UNUSED(index); + + KDoubleNumInput *input = new KDoubleNumInput(parent); + input->setMinimum(-1000); + input->setMaximum(1000); + input->setDecimals(1); + input->setSingleStep(0.1); + input->setSliderEnabled(false); + + return input; +} + +void TemperatureOffsetDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + KDoubleNumInput *input = static_cast(editor); + input->setValue(index.model()->data(index, Qt::EditRole).toDouble()); +} + +void TemperatureOffsetDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const +{ + KDoubleNumInput *input = static_cast(editor); + model->setData(index, input->value(), Qt::EditRole); +} + +void TemperatureOffsetDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + Q_UNUSED(index); + editor->setGeometry(option.rect); +} diff --git a/plasma/generic/applets/system-monitor/temperature-offset-delegate.h b/plasma/generic/applets/system-monitor/temperature-offset-delegate.h new file mode 100644 index 00000000..8b7c1855 --- /dev/null +++ b/plasma/generic/applets/system-monitor/temperature-offset-delegate.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Elvis Stansvik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TEMPERATURE_OFFSET_DELEGATE_H +#define TEMPERATURE_OFFSET_DELEGATE_H + +#include + +/** + * Item delegate that uses a spinbox to edit real numbers. + */ +class TemperatureOffsetDelegate : public QItemDelegate +{ + Q_OBJECT + +public: + TemperatureOffsetDelegate(QObject *parent = 0); + + /// reimplemented from QItemDelegate. + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + /// reimplemented from QItemDelegate. + void setEditorData(QWidget *editor, const QModelIndex &index) const; + /// reimplemented from QItemDelegate. + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; + /// reimplemented from QItemDelegate. + void updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, const QModelIndex &index) const; +}; + +#endif // TEMPERATURE_OFFSET_DELEGATE_H diff --git a/plasma/generic/applets/system-monitor/temperature.cpp b/plasma/generic/applets/system-monitor/temperature.cpp new file mode 100644 index 00000000..a1ec715a --- /dev/null +++ b/plasma/generic/applets/system-monitor/temperature.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2007 Petri Damsten + * Copyright (C) 2008 Marco Martin + * Copyright (C) 2010 Michel Lafon-Puyo + * Copyright (C) 2011 Elvis Stansvik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "temperature.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "plotter.h" +#include "temperature-offset-delegate.h" + +using namespace KUnitConversion; + +Temperature::Temperature(QObject *parent, const QVariantList &args) + : SM::Applet(parent, args) + , m_tempModel(0) + , m_rx(".*temp.*", Qt::CaseInsensitive) +{ + setHasConfigurationInterface(true); + resize(215 + 20 + 23, 109 + 20 + 25); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + m_sourceTimer.setSingleShot(true); + connect(&m_sourceTimer, SIGNAL(timeout()), this, SLOT(sourcesAdded())); +} + +Temperature::~Temperature() +{ +} + +void Temperature::init() +{ + KGlobal::locale()->insertCatalog("plasma_applet_system-monitor"); + setEngine(dataEngine("systemmonitor")); + setTitle(i18n("Temperature")); + + /* At the time this method is running, not all source may be connected. */ + connect(engine(), SIGNAL(sourceAdded(QString)), this, SLOT(sourceAdded(QString))); + foreach (const QString& source, engine()->sources()) { + sourceAdded(source); + } +} + +void Temperature::configChanged() +{ + KConfigGroup cg = config(); + setInterval(cg.readEntry("interval", 2.0) * 1000.0); + setSources(cg.readEntry("temps", m_sources.mid(0, 5))); + connectToEngine(); +} + +void Temperature::sourceAdded(const QString& name) +{ + if (m_rx.indexIn(name) != -1) { + //kDebug() << m_rx.cap(1); + m_sources << name; + if (!m_sourceTimer.isActive()) { + m_sourceTimer.start(0); + } + } +} + +void Temperature::sourcesAdded() +{ + configChanged(); +} + +void Temperature::createConfigurationInterface(KConfigDialog *parent) +{ + QWidget *widget = new QWidget(); + ui.setupUi(widget); + m_tempModel.clear(); + m_tempModel.setHorizontalHeaderLabels(QStringList() << i18n("Sensor") + << i18n("Name") + << i18n("Offset")); + + QStandardItem *parentItem = m_tempModel.invisibleRootItem(); + foreach (const QString& temp, m_sources) { + QStandardItem *item1 = new QStandardItem(temp); + item1->setEditable(false); + item1->setCheckable(true); + if (sources().contains(temp)) { + item1->setCheckState(Qt::Checked); + } + QStandardItem *item2 = new QStandardItem(temperatureTitle(temp)); + item2->setEditable(true); + QStandardItem *item3 = new QStandardItem( + KGlobal::locale()->formatNumber(temperatureOffset(temp), 1)); + item3->setEditable(true); + parentItem->appendRow(QList() << item1 << item2 << item3); + } + ui.treeView->setModel(&m_tempModel); + ui.treeView->resizeColumnToContents(0); + ui.treeView->setItemDelegateForColumn(2, new TemperatureOffsetDelegate()); + + ui.intervalSpinBox->setValue(interval() / 1000.0); + ui.intervalSpinBox->setSuffix(i18nc("second", " s")); + parent->setButtons(KDialog::Ok | KDialog::Cancel | KDialog::Apply); + parent->addPage(widget, i18n("Temperature"), "view-statistics"); + + connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); + connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); + connect(ui.treeView, SIGNAL(clicked(QModelIndex)), parent, SLOT(settingsModified())); + connect(ui.intervalSpinBox, SIGNAL(valueChanged(QString)), parent, SLOT(settingsModified())); +} + +void Temperature::configAccepted() +{ + KConfigGroup cg = config(); + KConfigGroup cgGlobal = globalConfig(); + QStandardItem *parentItem = m_tempModel.invisibleRootItem(); + + clear(); + + for (int i = 0; i < parentItem->rowCount(); ++i) { + QStandardItem *item = parentItem->child(i, 0); + if (item) { + cgGlobal.writeEntry(item->text(), + parentItem->child(i, 1)->text()); + cgGlobal.writeEntry(item->text() + "_offset", QString::number( + parentItem->child(i, 2)->data(Qt::EditRole).toDouble(), 'f', 1)); + if (item->checkState() == Qt::Checked) { + appendSource(item->text()); + } + } + } + cg.writeEntry("temps", sources()); + uint interval = ui.intervalSpinBox->value(); + cg.writeEntry("interval", interval); + + emit configNeedsSaving(); +} + +QString Temperature::temperatureTitle(const QString& source) +{ + KConfigGroup cg = globalConfig(); + return cg.readEntry(source, source.mid(source.lastIndexOf('/') + 1).replace('_',' ')); +} + +double Temperature::temperatureOffset(const QString& source) +{ + KConfigGroup cg = globalConfig(); + return cg.readEntry(source + "_offset", 0.0); +} + +bool Temperature::addVisualization(const QString& source) +{ + Plasma::DataEngine *engine = dataEngine("systemmonitor"); + + if (!engine) { + return false; + } + + SM::Plotter *plotter = new SM::Plotter(this); + plotter->setTitle(temperatureTitle(source)); + plotter->setAnalog(mode() != SM::Applet::Panel); + + if (KGlobal::locale()->measureSystem() == KLocale::Metric) { + plotter->setMinMax(0, 110); + plotter->setUnit(QString::fromUtf8("°C")); + } else { + plotter->setMinMax(32, 230); + plotter->setUnit(QString::fromUtf8("°F")); + } + appendVisualization(source, plotter); + + Plasma::DataEngine::Data data = engine->query(source); + dataUpdated(source, data); + setPreferredItemHeight(80); + return true; +} + +void Temperature::dataUpdated(const QString& source, + const Plasma::DataEngine::Data &data) +{ + if (!sources().contains(source)) { + return; + } + SM::Plotter *plotter = qobject_cast(visualization(source)); + QString temp; + QString unit = data["units"].toString(); + double doubleValue = data["value"].toDouble() + temperatureOffset(source); + Value value = Value(doubleValue, unit); + + if (KGlobal::locale()->measureSystem() == KLocale::Metric) { + value = value.convertTo(Celsius); + } else { + value = value.convertTo(Fahrenheit); + } + + value.round(1); + if (plotter) { + plotter->addSample(QList() << value.number()); + } + + temp = value.toSymbolString(); + + if (mode() == SM::Applet::Panel) { + setToolTip(source, + QString("%1%2").arg(temperatureTitle(source)).arg(temp)); + } +} + +#include "temperature.moc" diff --git a/plasma/generic/applets/system-monitor/temperature.h b/plasma/generic/applets/system-monitor/temperature.h new file mode 100644 index 00000000..f340204f --- /dev/null +++ b/plasma/generic/applets/system-monitor/temperature.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 Petri Damsten + * Copyright (C) 2010 Michel Lafon-Puyo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TEMPERATURE_HEADER +#define TEMPERATURE_HEADER + +#include +#include "ui_temperature-config.h" +#include +#include +#include + +namespace Plasma { + class Meter; +} + +class Temperature : public SM::Applet +{ + Q_OBJECT + public: + Temperature(QObject *parent, const QVariantList &args); + ~Temperature(); + + virtual void init(); + + public slots: + void configChanged(); + void dataUpdated(const QString &name, const Plasma::DataEngine::Data &data); + void createConfigurationInterface(KConfigDialog *parent); + + private slots: + void configAccepted(); + void sourceAdded(const QString& name); + void sourcesAdded(); + + private: + Ui::config ui; + QStandardItemModel m_tempModel; + QStringList m_sources; + QTimer m_sourceTimer; + QRegExp m_rx; + + QString temperatureTitle(const QString& source); + double temperatureOffset(const QString& source); + bool addVisualization(const QString& source); + bool isValidDevice(const QString& uuid, Plasma::DataEngine::Data* data); +}; + +K_EXPORT_PLASMA_APPLET(sm_temperature, Temperature) + +#endif diff --git a/plasma/generic/applets/systemtray/CMakeLists.txt b/plasma/generic/applets/systemtray/CMakeLists.txt new file mode 100644 index 00000000..caca7006 --- /dev/null +++ b/plasma/generic/applets/systemtray/CMakeLists.txt @@ -0,0 +1,66 @@ +project(plasma-systemtray) +#TODO: see if is still the case +# 'engineName' causes error +kde4_no_enable_final(plasma-systemtray) + +find_package(Qt4 4.8 COMPONENTS QtCore QtGui QtDeclarative REQUIRED) + +set(data_install_dir "plasma/packages/org.kde.systemtray") + +set(systemtray_SRCS + + core/manager.cpp + core/protocol.cpp + core/task.cpp + + protocols/fdo/fdoprotocol.cpp + protocols/fdo/fdotask.cpp + #FIXME: we should find another way to achieve that + #protocols/fdo/fdonotification.cpp + protocols/fdo/fdographicswidget.cpp + protocols/fdo/fdoselectionmanager.cpp + protocols/fdo/x11embedcontainer.cpp + protocols/fdo/x11embeddelegate.cpp + protocols/fdo/x11embedpainter.cpp + + protocols/plasmoid/plasmoidtaskprotocol.cpp + protocols/plasmoid/plasmoidtask.cpp + + protocols/dbussystemtray/dbussystemtraytask.cpp + protocols/dbussystemtray/dbussystemtrayprotocol.cpp + + ui/applet.cpp + ui/widgetitem.cpp + ui/mouseredirectarea.cpp + ) + +kde4_add_ui_files(systemtray_SRCS + ui/autohide.ui + ui/visibleitems.ui) + +include(${QT_USE_FILE}) +include (CheckLibraryExists) +check_library_exists (Xss XScreenSaverQueryInfo "" HAVE_LIBXSS) +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) +IF (HAVE_LIBXSS) + SET (IDLE_DETECTION_LIB "Xss") +ENDIF (HAVE_LIBXSS) + +kde4_add_plugin(plasma_applet_systemtray ${systemtray_SRCS}) +include_directories(${CMAKE_SOURCE_DIR}) +target_link_libraries(plasma_applet_systemtray + ${QT_LIBRARIES} + ${KDE4_KDEUI_LIBS} + ${KDE4_PLASMA_LIBS} + ${X11_LIBRARIES} + ${X11_Xrender_LIB} + ${X11_Xfixes_LIB} + ${X11_Xdamage_LIB} + ${X11_Xcomposite_LIB} + ${KDE4_SOLID_LIBS} + ${IDLE_DETECTION_LIB} +) + +install(TARGETS plasma_applet_systemtray DESTINATION ${PLUGIN_INSTALL_DIR}) +install(DIRECTORY "package/" DESTINATION "${DATA_INSTALL_DIR}/${data_install_dir}") +install(FILES plasma-applet-systemtray.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/applets/systemtray/Messages.sh b/plasma/generic/applets/systemtray/Messages.sh new file mode 100755 index 00000000..e761c32b --- /dev/null +++ b/plasma/generic/applets/systemtray/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp +$XGETTEXT `find . -name \*.js -o -name \*.qml -o -name \*.cpp` -o $podir/plasma_applet_systemtray.pot +rm rc.cpp diff --git a/plasma/generic/applets/systemtray/TODO b/plasma/generic/applets/systemtray/TODO new file mode 100644 index 00000000..4a41987b --- /dev/null +++ b/plasma/generic/applets/systemtray/TODO @@ -0,0 +1,17 @@ +* Fix sizing on the desktop + +* Try overriding QPaintDevice to obtain the background pixmap + - Will get rid of the double painting + - Will possibly allow calling XSetBackgroundPixmap without having to call XClearWindow() + - Might allow paints that result in an identical background pixmap to be discarded + +* Remove X11EmbedContainer's dependency on SelectionManager + - X11EmbedContainer needs to be a self-contained QX11EmbedContainer implementation + +* Add checks for XRender presence and fail nicely if necessary +* Don't do all the extra QX11EmbedContainer hacks if the client window is of the same depth +* Handle taskId clashes better + +* Misbehavior of certain applets within the plasmoid protocol or vice-versa. (Still needs investigating) + +* Qt5: Remove WheelArea implementation, use Qt implementation instead \ No newline at end of file diff --git a/plasma/generic/applets/systemtray/config.h.in b/plasma/generic/applets/systemtray/config.h.in new file mode 100644 index 00000000..2b38ffb9 --- /dev/null +++ b/plasma/generic/applets/systemtray/config.h.in @@ -0,0 +1,4 @@ +#cmakedefine HAVE_LIBXSS + +// Path to directory containing qml stuff for systemtray +#define SYSTEMTRAY_DATA_INSTALL_DIR "${data_install_dir}" diff --git a/plasma/generic/applets/systemtray/core/manager.cpp b/plasma/generic/applets/systemtray/core/manager.cpp new file mode 100644 index 00000000..fc6f6a02 --- /dev/null +++ b/plasma/generic/applets/systemtray/core/manager.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * manager.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * Copyright (C) 2010 Marco Martin * + * * + * 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 "manager.h" + +#include +#include + +#include + +#include "protocol.h" +#include "task.h" + +#include "../protocols/fdo/fdoprotocol.h" +#include "../protocols/plasmoid/plasmoidtaskprotocol.h" +#include "../protocols/dbussystemtray/dbussystemtrayprotocol.h" + +#include + +namespace SystemTray +{ + +class Manager::Private +{ +public: + Private(Manager *manager) + : q(manager), + plasmoidProtocol(0) + { + } + + void setupProtocol(Protocol *protocol); + + Manager *q; + QList tasks; + PlasmoidProtocol *plasmoidProtocol; +}; + + +Manager::Manager() + : d(new Private(this)) +{ + d->plasmoidProtocol = new PlasmoidProtocol(this); + d->setupProtocol(d->plasmoidProtocol); + d->setupProtocol(new SystemTray::FdoProtocol(this)); + d->setupProtocol(new SystemTray::DBusSystemTrayProtocol(this)); +} + +Manager::~Manager() +{ + delete d; +} + + +QList Manager::tasks() const +{ + return d->tasks; +} + +void Manager::addTask(Task *task) +{ + connect(task, SIGNAL(destroyed(SystemTray::Task*)), this, SLOT(removeTask(SystemTray::Task*))); + connect(task, SIGNAL(changedStatus()), this, SIGNAL(taskStatusChanged())); + + kDebug() << task->name() << "(" << task->taskId() << ")"; + + d->tasks.append(task); + emit taskAdded(task); +} + +void Manager::removeTask(Task *task) +{ + d->tasks.removeAll(task); + disconnect(task, 0, this, 0); + emit taskRemoved(task); +} + +void Manager::forwardConstraintsEvent(Plasma::Constraints constraints, Plasma::Applet *host) +{ + d->plasmoidProtocol->forwardConstraintsEvent(constraints, host); +} + +void Manager::loadApplets(Plasma::Applet *parent) +{ + d->plasmoidProtocol->loadFromConfig(parent); +} + +void Manager::addApplet(const QString appletName, Plasma::Applet *parent) +{ + d->plasmoidProtocol->addApplet(appletName, 0, parent); +} + +void Manager::removeApplet(const QString appletName, Plasma::Applet *parent) +{ + d->plasmoidProtocol->removeApplet(appletName, parent); +} + +QStringList Manager::applets(Plasma::Applet *parent) const +{ + return d->plasmoidProtocol->applets(parent); +} + + +void Manager::Private::setupProtocol(Protocol *protocol) +{ + connect(protocol, SIGNAL(taskCreated(SystemTray::Task*)), q, SLOT(addTask(SystemTray::Task*))); + protocol->init(); +} + +} + + +#include "manager.moc" diff --git a/plasma/generic/applets/systemtray/core/manager.h b/plasma/generic/applets/systemtray/core/manager.h new file mode 100644 index 00000000..599a3fd9 --- /dev/null +++ b/plasma/generic/applets/systemtray/core/manager.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * manager.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * Copyright (C) 2010 Marco Martin * + * * + * 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 SYSTEMTRAYMANAGER_H +#define SYSTEMTRAYMANAGER_H + +#include + +#include + +#include + +namespace Plasma +{ +class Applet; +} + +namespace SystemTray +{ + +class Applet; +class Notification; +class Task; +class Job; + +/** + * w + * @short Creator and amalgamator of the supported system tray specifications + **/ +class Manager : public QObject +{ + Q_OBJECT + +public: + Manager(); + ~Manager(); + + /** + * @return a list of all known Task instances + **/ + QList tasks() const; + + void forwardConstraintsEvent(Plasma::Constraints constraints, Plasma::Applet *host); + + void loadApplets(Plasma::Applet *parent); + + void addApplet(const QString appletName, Plasma::Applet *parent); + + void removeApplet(const QString appletName, Plasma::Applet *parent); + + QStringList applets(Plasma::Applet *parent) const; + +signals: + /** + * Emitted when a new task has been added + **/ + void taskAdded(SystemTray::Task *task); + + /** + * Emitted when status of task changes (such as it changing from + * Passive to NeedsAttention) + **/ + void taskStatusChanged(); + + /** + * Emitted when a task has been removed + **/ + void taskRemoved(SystemTray::Task *task); + +private slots: + void addTask(SystemTray::Task *task); + void removeTask(SystemTray::Task *task); + +private: + class Private; + Private* const d; + + friend class Applet; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/core/protocol.cpp b/plasma/generic/applets/systemtray/core/protocol.cpp new file mode 100644 index 00000000..a6af0c25 --- /dev/null +++ b/plasma/generic/applets/systemtray/core/protocol.cpp @@ -0,0 +1,35 @@ +/*************************************************************************** + * taskprotocol.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "protocol.h" + + +namespace SystemTray +{ + +Protocol::Protocol(QObject *parent) + : QObject(parent) +{ +} + +} + +#include "protocol.moc" diff --git a/plasma/generic/applets/systemtray/core/protocol.h b/plasma/generic/applets/systemtray/core/protocol.h new file mode 100644 index 00000000..a6a56b53 --- /dev/null +++ b/plasma/generic/applets/systemtray/core/protocol.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * taskprotocol.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 SYSTEMTRAYPROTOCOL_H +#define SYSTEMTRAYPROTOCOL_H + +#include + +namespace SystemTray +{ + class Job; + class Notification; + class Task; +} + + +namespace SystemTray +{ + +/** + * @short System tray protocol base class + * + * To support a new system tray protocol, this class and Task should be + * subclassed and the subclass of this class registered with the global + * Manager. The Protocol subclass should emit taskCreated() for each new + * task created. + **/ +class Protocol : public QObject +{ + Q_OBJECT +public: + explicit Protocol(QObject *parent); + + virtual void init() = 0; + +signals: + /** + * Signals that a new task has been created + **/ + void taskCreated(SystemTray::Task *task); + + /** + * Signals that a new notification has been created + **/ + void jobCreated(SystemTray::Job *job); + + /** + * Signals that a new notification has been created + **/ + void notificationCreated(SystemTray::Notification *notification); +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/core/task.cpp b/plasma/generic/applets/systemtray/core/task.cpp new file mode 100644 index 00000000..6e344ab7 --- /dev/null +++ b/plasma/generic/applets/systemtray/core/task.cpp @@ -0,0 +1,198 @@ +/*************************************************************************** + * task.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "task.h" + +#include +#include + +#include "../ui/applet.h" + +namespace SystemTray +{ + + +class Task::Private +{ +public: + Private() + : status(Task::UnknownStatus), + category(Task::UnknownCategory) + { + } + + QHash widgetsByHost; + Task::Status status; + Task::Category category; + QString name; +}; + + +Task::Task(QObject *parent) + : QObject(parent), + d(new Private) +{ +} + +Task::~Task() +{ + emit destroyed(this); + foreach (QGraphicsWidget * widget, d->widgetsByHost) { + disconnect(widget, 0, this, 0); + // sometimes it appears that the widget will get scheduled for a repaint + // then it gets deleted here and QGraphicsScene doesn't get that straight + // in its bookkeeping and crashes occur; work around this by giving it a + // chance to schedule after the next paintfun + widget->deleteLater(); + } + delete d; +} + +QGraphicsWidget *Task::widget(Plasma::Applet *host, bool createIfNecessary) +{ + Q_ASSERT(host); + + QGraphicsWidget *widget = d->widgetsByHost.value(host); + + if (!widget && createIfNecessary) { + widget = createWidget(host); + + if (widget) { + d->widgetsByHost.insert(host, widget); + connect(widget, SIGNAL(destroyed()), this, SLOT(widgetDeleted())); + } + } + + return widget; +} + +bool Task::isEmbeddable(SystemTray::Applet *host) +{ + if (!host) { + return false; + } + + return (d->widgetsByHost.value(host) || isEmbeddable()) && host->shownCategories().contains(category()); +} + +QHash Task::widgetsByHost() const +{ + return d->widgetsByHost; +} + +void Task::abandon(Plasma::Applet *host) +{ + QGraphicsWidget *widget = d->widgetsByHost.take(host); + if (widget) { + widget->deleteLater(); + } +} + +QGraphicsWidget *Task::forget(Plasma::Applet *host) +{ + return d->widgetsByHost.take(host); +} + +void Task::widgetDeleted() +{ + bool wasEmbeddable = isEmbeddable(); + + QGraphicsWidget *w = static_cast(sender()); + QMutableHashIterator it(d->widgetsByHost); + while (it.hasNext()) { + it.next(); + if (it.value() == w) { + it.remove(); + } + } + + if (!wasEmbeddable && isEmbeddable()) { + // we have to delay this call because some Task subclasses have a single widget that + // becomes embedabble at this point (e.g. FdoTaskWidget). if the signal is emitted + // immediately, another system tray will attempt to immediately embed it, and + // part of that process involves removing the item from any previous layouts. now, + // if that happens because a system tray is being deleted (removed, app exit, logout, etcS) + // then the previous parent layout will be a dangling pointer at this point and + // that will not get fixed up until everything is finished... so.. we delay the signal + QTimer::singleShot(0, this, SLOT(emitChanged())); + } +} + +void Task::emitChanged() +{ + emit changed(this); +} + +bool Task::isUsed() const +{ + return !d->widgetsByHost.isEmpty(); +} + +void Task::setCategory(Category category) +{ + if (d->category == category) { + return; + } + + d->category = category; + emit changedCategory(); + emit changed(this); +} + +Task::Category Task::category() const +{ + return d->category; +} + +void Task::setStatus(Status status) +{ + if (d->status == status) { + return; + } + + d->status = status; + emit changedStatus(); + emit changed(this); +} + +Task::Status Task::status() const +{ + return d->status; +} + +QString Task::name() const +{ + return d->name; +} + + +void Task::setName(QString name) +{ + if (d->name != name) { + d->name = name; + emit changedName(); + } +} + + +} + +#include "task.moc" diff --git a/plasma/generic/applets/systemtray/core/task.h b/plasma/generic/applets/systemtray/core/task.h new file mode 100644 index 00000000..6ae4ac99 --- /dev/null +++ b/plasma/generic/applets/systemtray/core/task.h @@ -0,0 +1,237 @@ +/*************************************************************************** + * task.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 SYSTEMTRAYTASK_H +#define SYSTEMTRAYTASK_H + +#include + +#include + +class QGraphicsWidget; + +namespace Plasma +{ + class Applet; +} // namespace Plasma + +namespace SystemTray +{ + + class Applet; + +/** + * @short System tray task base class + * + * To support a new system tray protocol, Protocol and this class should + * be subclassed. + **/ +class Task : public QObject +{ + Q_OBJECT + + Q_PROPERTY(TaskType type READ type CONSTANT) + Q_PROPERTY(QString taskId READ taskId CONSTANT) + Q_PROPERTY(Status status READ status NOTIFY changedStatus) + Q_PROPERTY(QString name READ name NOTIFY changedName) + Q_PROPERTY(Category category READ category NOTIFY changedCategory) + +public: + enum Status { + UnknownStatus = 0, + Passive = 1, + Active = 2, + NeedsAttention = 3 + }; + Q_ENUMS(Status) + + enum Category { + UnknownCategory = 0, + ApplicationStatus = 1, + Communications = 2, + SystemServices = 3, + Hardware = 4 + }; + Q_ENUMS(Category) + + /** + * Derived classes should provide its type. We assume that number of different types of tasks is + * a limited value. So, it's easier to provide constants for each type of tasks than always + * try to cast classes. Moreover, these contants are used in QML code. + */ + enum TaskType { + TypePlasmoid, + TypeX11Task, + TypeStatusItem, + TypeUserDefined + }; + Q_ENUMS(TaskType) + + + virtual ~Task(); + + /** + * Creates a new graphics widget for this task + * + * isEmbeddable() should be checked before creating a new widget. + **/ + QGraphicsWidget* widget(Plasma::Applet *host, bool createIfNecessary = true); + + /** + * @return whether this task is embeddable; true if there is already a widget + * for this host. + */ + bool isEmbeddable(SystemTray::Applet *host); + + /** + * Returns whether this task can be embeddable + * + * Depending on the protocol, there may be circumstances under which + * a new widget can not be created. isEmbeddable() will return false + * under these circumstances. + **/ + virtual bool isEmbeddable() const = 0; + + /** + * Returns whether this task is represented as widget or it provides only information (icon, name, state, etc) + * @return true if task is represented as widget. + */ + virtual bool isWidget() const = 0; + + /** + * Returns the name of this task that should be presented to the user + **/ + QString name() const; + + void setName(QString name); + + /** + * Returns a unique identifier for this task + * + * The identifier is valid between restarts and so is safe to save + **/ + virtual QString taskId() const = 0; + + /** + * Returns an icon that can be associated with this task + * + * The icon returned is not necessarily the same icon that appears + * in the tray icon itself. + **/ + virtual QIcon icon() const = 0; + + /** + * @return true if this task is current being used, e.g. it has created + * widgets for one or more hosts + */ + bool isUsed() const; + + /** + * Sets the category of the task, UnknownCategory by default + * @arg category the category for this task + */ + void setCategory(Category category); + + /** + * @return the category of this task + */ + Category category() const; + + /** + * Sets the status of the task, UnknownStatus by default. + * @arg status the status for this task + */ + void setStatus(Status status); + + /** + * @return the status for this task + */ + Status status() const; + + /** + * This function must always return type of task (an integer value). This value must always be + * the same for each call of function. + * @return a type of task. + */ + virtual TaskType type() const = 0; + + + /** + * Can be used by the hostwhen they no longer wish to use the widget associated + * with the host. + */ + virtual void abandon(Plasma::Applet *host); + +Q_SIGNALS: + /** + * Emitted when something about the task has changed + **/ + //TODO: this should also state _what_ was changed so we can react more + // precisely (and therefore with greater efficiency) + void changed(SystemTray::Task *task); + + /** + * Special signal for changed status + */ + void changedStatus(); + + // if a category of task has been changed + void changedCategory(); + + // If a name of task has been changed + void changedName(); + + /// if visibility preference of task is changed + void changedVisibilityPreference(); + + /** + * Emitted when the task is about to be destroyed + **/ + void destroyed(SystemTray::Task *task); + +protected: + Task(QObject *parent = 0); + QHash widgetsByHost() const; + QGraphicsWidget *forget(Plasma::Applet *host); + + /** + * Called when a new widget is required + * + * Subclasses should implement this to return a graphics widget that + * handles all user interaction with the task. Ownership of the + * created widget is handled automatically so subclasses should not + * delete the created widget. + **/ + virtual QGraphicsWidget* createWidget(Plasma::Applet *host) = 0; + +private slots: + void widgetDeleted(); + void emitChanged(); + +private: + class Private; + Private* const d; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/package/contents/code/IconsList.js b/plasma/generic/applets/systemtray/package/contents/code/IconsList.js new file mode 100644 index 00000000..db77b46b --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/code/IconsList.js @@ -0,0 +1,34 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ +// This JS file is intended for IconsList.qml only as a stuff + +var tasks = {} + +function findMax() { + var max = 0 + for (var i in tasks) { + if (max < tasks[i]) + max = tasks[i] + } + return max +} diff --git a/plasma/generic/applets/systemtray/package/contents/code/TasksSet.js b/plasma/generic/applets/systemtray/package/contents/code/TasksSet.js new file mode 100644 index 00000000..12fd6513 --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/code/TasksSet.js @@ -0,0 +1,130 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ + +// This is stateless library, it may be shared between several qml files +.pragma library + + +// Represents task +var Task = function(id, index, category, data) +{ + this.id = id + this.index = index + this.category = category + this.data = data +} + + +/** + * Creates new set of tasks + * @param categories_list a list of categories, this list gives order of categories + */ +var TasksSet = function(categories_list) +{ + var _categories = categories_list + var _tasks = {} // internal set of tasks + var _tasks_as_array = [] // array of tasks + + // number of tasks in each location with the same category + var _cat_sizes = {} + for (var i = 0, s = _categories.length; i < s; ++i) { + _cat_sizes[_categories[i]] = 0 + } + + // Finds correct model index for new task + function _findIndex(category) + { + var index = 0 // index is a sum of numbers of tasks groupped by category + for (var c = 0, l = _categories.length; c < l && _categories[c] !== category; ++c) + index += _cat_sizes[_categories[c]] + return index + } + + // Increments model indexes for tasks + function _incIndexes(index) + { + for (var i = 0, len = _tasks_as_array.length; i < len; ++i) { + var t = _tasks_as_array[i] + if (t.index >= index) + t.index++ + } + } + + // Decrement indexes of tasks + function _decIndexes(index) + { + for (var i = 0, len = _tasks_as_array.length; i < len; ++i) { + var t = _tasks_as_array[i] + if (t.index >= index) + t.index-- + } + } + + // Returns object representing properties of task + function _get(id) { + return _tasks[id] + } + this.get = _get + + /** + * Adds new task to set + * @param id unique id of task + * @param category a category of task + * @param data an additional data to accociate with task + * @return a new task object + */ + function _add(id, category, data) + { + var index = _findIndex(category) // first of all, find correct model index to insert task + _incIndexes(index) + var t = new Task(id, index, category, data) + _tasks[id] = t + _cat_sizes[category]++ + _tasks_as_array.push(t) + return t + } + this.add = _add + + /** + * Removes tasks from set + * @param id an unique ID of task + * @return an object containing properties of old task + */ + function _remove(id) + { + var t = _tasks[id] //find task using ID + // remove task from array, we remove last item and move it to new place + var arr_index = 0 + var len = _tasks_as_array.length + for (; _tasks_as_array[arr_index] !== t; ++arr_index); + if (arr_index < len-1) + _tasks_as_array[arr_index] = _tasks_as_array[len-1] // move item + _tasks_as_array.pop() + // remove task from internal set & decrement indexes + _cat_sizes[t.category]-- + delete _tasks[id] + _decIndexes(t.index) + return t + } + this.remove = _remove +} diff --git a/plasma/generic/applets/systemtray/package/contents/code/main.js b/plasma/generic/applets/systemtray/package/contents/code/main.js new file mode 100644 index 00000000..f5885e9c --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/code/main.js @@ -0,0 +1,74 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ + +// This isn't a stateless library, it is intended only as a stuff for main.qml + +// Constants +var ICONS_SIZE = 24 // Size of icons, icons are square i.e. width == height +var MINIMUM_SIZE = 8 // minimum size of widget +var ARROW_MARGINS = 5 // margins for an arrow +var BLINK_INTERVAL = 750 // time interval of blinking +var TASK_NOTIFICATIONS_TYPEID = "org.kde.notifications" +var USE_GRID_IN_POPUP = false // true if in popup icons should be placed like a grid without names + + +// [const] Location of item (model for icon) +var LOCATION_TRAY = 0 +var LOCATION_POPUP = LOCATION_TRAY + 1 +var LOCATION_NOTIFICATION = LOCATION_POPUP + 1 + + +// [const] List of possible locations +var LOCATIONS = [ + LOCATION_TRAY, + LOCATION_POPUP, + LOCATION_NOTIFICATION +] + +// [const] Number of locations +var LOCATIONS_NUMBER = LOCATIONS.length + +// This list determines order of categories of tasks +var CATEGORIES = [ + UnknownCategory, + ApplicationStatus, + Communications, + SystemServices, + Hardware +] + +// all available tasks by their id +var allTasks = {} + +// Set of tasks sets, each set for one location (area) +var tasks = new Array(LOCATIONS_NUMBER) + + +// Returns location of task by ID of task +function findLocation(id) +{ + for (var i = 0; i < LOCATIONS_NUMBER; ++i) { + if (tasks[i].get(id)) + return LOCATIONS[i] + } +} diff --git a/plasma/generic/applets/systemtray/package/contents/ui/ArrowArea.qml b/plasma/generic/applets/systemtray/package/contents/ui/ArrowArea.qml new file mode 100644 index 00000000..fd074694 --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/ui/ArrowArea.qml @@ -0,0 +1,135 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ + +import QtQuick 1.1 +import org.kde.plasma.core 0.1 as PlasmaCore +import org.kde.plasma.extras 0.1 as PlasmaExtras + +Item { + id: arrow_area + + property variant content; ///< content of popup dialog + property int arrow_size: 12 // size of an icon + + MouseArea { + anchors.fill: parent + onClicked: togglePopup() + onPressed: PlasmaExtras.PressedAnimation { targetItem: arrow_widget } + onReleased: PlasmaExtras.ReleasedAnimation { targetItem: arrow_widget } + } + + PlasmaCore.SvgItem { + + id: arrow_widget + + anchors.centerIn: parent + width: arrow_size + height: width + + svg: PlasmaCore.Svg { imagePath: "widgets/arrows" } + elementId: "left-arrow" + } + + // Tooltip for arrow ----------------------------------------------------------------------------------------------- + PlasmaCore.ToolTip { + id: arrow_tooltip + target: arrow_widget + subText: dialog.visible ? i18n("Hide icons") : i18n("Show hidden icons") + } + + // Popup dialog (window) ------------------------------------------------------------------------------------------- + PlasmaCore.Dialog { + id: dialog + visible: false + mainItem: content + location: plasmoid.location + windowFlags: Qt.WindowStaysOnTopHint + + onActiveWindowChanged: dialog.visible = activeWindow // hide window if it deactivates + + + // We have to move dialog if its size is changed + onHeightChanged: updatePosition() + onWidthChanged: updatePosition() + + onVisibleChanged: { + if (visible) { + if (dialog.windowId) + plasmoid.hideFromTaskbar(dialog.windowId) + updatePosition() + } + } + + function updatePosition() { + var pos = dialog.popupPosition(arrow_area, Qt.AlignCenter) + x = pos.x + y = pos.y + } + } + + + function togglePopup() { + if (dialog.visible) { + dialog.visible = false + return + } + dialog.visible = true + dialog.activateWindow() + } + + + states: [ + State { + name: "LEFT_EDGE" + PropertyChanges { + target: arrow_widget + elementId: dialog.visible ? "left-arrow" : "right-arrow" + } + }, + + State { + name: "RIGHT_EDGE" + PropertyChanges { + target: arrow_widget + elementId: dialog.visible ? "right-arrow" : "left-arrow" + } + }, + + State { + name: "TOP_EDGE" + PropertyChanges { + target: arrow_widget + elementId: dialog.visible ? "up-arrow" : "down-arrow" + } + }, + + State { + name: "BOTTOM_EDGE" + PropertyChanges { + target: arrow_widget + elementId: dialog.visible ? "down-arrow" : "up-arrow" + } + } + ] + +} diff --git a/plasma/generic/applets/systemtray/package/contents/ui/IconsGrid.qml b/plasma/generic/applets/systemtray/package/contents/ui/IconsGrid.qml new file mode 100644 index 00000000..8448f304 --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/ui/IconsGrid.qml @@ -0,0 +1,128 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ + +import QtQuick 1.1 + +Item { + id: root_item + + property int icons_size: 24 ///< Size of icons, icons are square i.e. width == height + property int icons_margins: 2 ///< Margins for icons + property alias icons_number: grid.count ///< [readonly] Number of icons + property alias model: grid.model; ///< Model for grid + property int cols_num: 0 ///< [readonly] Number of columns + property int rows_num: 0 ///< [readonly] Number of rows + property int min_width: cols_num*cell_size ///< [readonly] minimum width of component required to show whole grid + property int min_height: rows_num*cell_size ///< [readonly] minimum height of compontn required to show whole grid + property int cell_size: icons_size + 2*icons_margins ///< [readonly] size of grid cell + + property int _sqrt: 0 + property int _sqrt2: _sqrt*_sqrt + + GridView { + id: grid + anchors.centerIn: parent + width: min_width + height: min_height + + cellWidth: cell_size + cellHeight: cellWidth + interactive: false + delegate: TrayIcon { width: grid.cellWidth; height: grid.cellHeight } + } + + states: [ + /// Base state for square states (for internal use only) + State { + name: "__SQR" + + PropertyChanges { + target: root_item + _sqrt: Math.floor(Math.sqrt(grid.count)) + } + }, + + /// Vertical layout of grid + State { + name: "VERT" + + PropertyChanges { + target: root_item + _sqrt: 0 + cols_num: grid.count*cell_size <= width ? grid.count : Math.max(1, Math.floor(width / cell_size)) + rows_num: cols_num > 0 ? (Math.max(1, Math.floor(grid.count / cols_num)) + (grid.count % cols_num ? 1 : 0)) : 0 + } + PropertyChanges { + target: grid + flow: GridView.LeftToRight + } + }, + + /// Horizontal layout of grid + State { + name: "HORZ" + + PropertyChanges { + target: root_item + _sqrt: 0 + rows_num: grid.count*cell_size <= height ? grid.count : Math.max(1, Math.floor(height / cell_size)) + cols_num: rows_num > 0 ? (Math.max(1, Math.floor(grid.count / rows_num)) + (grid.count % rows_num ? 1 : 0)) : 0 + } + PropertyChanges { + target: grid + flow: GridView.TopToBottom + } + }, + + /// Square layout of grid with horizontal flow + State { + name: "SQR_H" + extend: "__SQR" + + PropertyChanges { + target: root_item + cols_num: ( grid.count > _sqrt2 ? _sqrt + 1 : _sqrt ) + rows_num: ( grid.count > _sqrt2 + _sqrt ? _sqrt + 1 : _sqrt ) + } + PropertyChanges { + target: grid + flow: GridView.LeftToRight + } + }, + + /// Square layout of grid with vertical flow + State { + name: "SQR_V" + extend: "__SQR" + PropertyChanges { + target: root_item + rows_num: ( grid.count > _sqrt2 ? _sqrt + 1 : _sqrt ) + cols_num: ( grid.count > _sqrt2 + _sqrt ? _sqrt + 1 : _sqrt ) + } + PropertyChanges { + target: grid + flow: GridView.TopToBottom + } + } + ] +} diff --git a/plasma/generic/applets/systemtray/package/contents/ui/IconsList.qml b/plasma/generic/applets/systemtray/package/contents/ui/IconsList.qml new file mode 100644 index 00000000..d72733c1 --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/ui/IconsList.qml @@ -0,0 +1,149 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ + +import QtQuick 1.1 +import org.kde.plasma.graphicswidgets 0.1 as PlasmaWidgets +import org.kde.plasma.components 0.1 as PlasmaComponents +import org.kde.plasma.extras 0.1 as PlasmaExtras +import Private 0.1 + +import "../code/IconsList.js" as IconsListJS + +MouseArea { + id: root_item + + property int icons_size: 24 ///< Size of icons, icons are square i.e. width == height + property int icons_margins: icons_size/6 ///< Margins for icons + property alias icons_number: repeater.count ///< [readonly] Number of icons + property alias model: repeater.model; ///< Model for grid + property int cell_size: icons_size + 2*icons_margins ///< [readonly] size of grid cell + + //Those properties are used by PlasmaCore.Dialog for size hints + property int extraHorizMargins: delegate_highlight.marginHints.right + property int minimumWidth: extraHorizMargins + layoutColumn.childrenRect.width ///< [readonly] minimum width of component required to show whole grid + property int minimumHeight:layoutColumn.childrenRect.height ///< [readonly] minimum height of compontn required to show whole grid + property int maximumWidth: minimumWidth + property int maximumHeight: minimumHeight + + hoverEnabled: true + + Component { + id: delegate_task + + MouseRedirectArea { + id: delegate_root_item + width: Math.max(minimumWidth - extraHorizMargins, childrenRect.width) + height: childrenRect.height + + // we redirect some events to IconWidget or applet + target: task.type == TypeStatusItem ? ui_item.getMouseArea() : task + applet: plasmoid + + // Next events we process manually + onClickMiddle: ui_item.click(Qt.MiddleButton) + onClickRight: ui_item.click(Qt.RightButton) + onScrollVert: ui_item.scrollVert(delta) + onScrollHorz: ui_item.scrollHorz(delta) + onEntered: { + delegate_highlight.y = delegate_root_item.y + } + + Row { + Item { + id: tray_icon + + width: cell_size + height: width + + TrayIcon { + anchors.centerIn: parent + width: icons_size + height: width + } + } + + PlasmaComponents.Label { + id: name_item + anchors.verticalCenter: tray_icon.verticalCenter + wrapMode: Text.NoWrap + text: task.name + } + } + + + Component.onCompleted: { + var text_width = name_item.width + IconsListJS.tasks[delegate_root_item] = text_width + } + + Component.onDestruction: { + delete IconsListJS.tasks[delegate_root_item] + } + + Connections { + target: task + onChangedName: { + // if name is changed => we should recalculate width of popup + IconsListJS.tasks[delegate_root_item] = name_item.width + } + } + + } + + } + + PlasmaComponents.Highlight { + id: delegate_highlight + height: cell_size + width: minimumWidth + opacity: root_item.containsMouse + + Behavior on opacity { + NumberAnimation { + duration: 150 + easing: Easing.InOutQuad + } + } + Behavior on y { + NumberAnimation { + duration: 250 + easing: Easing.InOutQuad + } + } + } + + + Column { + id: layoutColumn + spacing: 0 + Repeater { + id: repeater + delegate: delegate_task + } + + } + + Component.onCompleted: { + console.log("========================> " + " " + minimumWidth + " " + layoutColumn.childrenRect.width); + } +} diff --git a/plasma/generic/applets/systemtray/package/contents/ui/StatusNotifierItem.qml b/plasma/generic/applets/systemtray/package/contents/ui/StatusNotifierItem.qml new file mode 100644 index 00000000..8e06b5e8 --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/ui/StatusNotifierItem.qml @@ -0,0 +1,276 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ + +import QtQuick 1.1 +import Private 0.1 +import org.kde.plasma.core 0.1 as PlasmaCore +import org.kde.qtextracomponents 0.1 as QtExtraComponents + + +Item { + id: root_item + + property int blink_interval: 1000 // interval of blinking (if status of task is NeedsAttention) + property variant task: null // task that provides information for item + + property bool __has_task: task ? true : false + property string __icon_name: __has_task ? task.iconName : "" + property string __att_icon_name: __has_task ? task.attIconName : "" + property variant __icon: __has_task ? task.icon : QIcon("default") + property variant __att_icon: __has_task ? task.attIcon : __getDefaultIcon() + property string __overlay_icon_name: __has_task ? task.overlayIconName : "" + property string __movie_path: __has_task ? task.moviePath : "" + property int __status: __has_task ? task.status : UnknownStatus + //Hack for activating only items that has been clicked by ourselves + property variant __clickTime: 0; + + // Public functions ================================================================================================ + function click(buttons) { + __processClick(buttons, mouse_area) + } + + function scrollHorz(delta) { + task.activateHorzScroll(delta) + } + + function scrollVert(delta) { + task.activateVertScroll(delta) + } + + function getMouseArea() { + return mouse_area + } + + Connections { + target: task + + onChangedShortcut: { + // update shortcut for icon widget + if (!icon_widget.action) + return + plasmoid.updateShortcutAction(icon_widget.action, task.shortcut) + icon_widget.action.triggered.disconnect(__onActivatedShortcut) // disconnect old signals + icon_widget.action.triggered.connect(__onActivatedShortcut) + } + + onShowContextMenu: { + //refuse events for elapsed times < 1 second + var time = new Date().getTime(); + if (time - __clickTime < 1000) { + plasmoid.showMenu(menu, x, y, root_item) + } + } + } + + function __onActivatedShortcut() { + __processClick(Qt.LeftButton, icon_widget) + } + + + // Timer for blink effect ========================================================================================== + Timer { + id: timer_blink + running: false + repeat: true + interval: blink_interval + + property bool is_att_icon: false + + onTriggered: { + icon_widget.source = is_att_icon ? __getAttentionIcon() : __getDefaultIcon() + is_att_icon = !is_att_icon + } + } + + + // TODO: remove wheel area in QtQuick 2.0 + QtExtraComponents.MouseEventListener { + id: wheel_area + anchors.fill: parent + enabled: __has_task + visible: __has_task + z: -2 + + // Mouse events handlers =========================================================================================== + MouseArea { + id: mouse_area + anchors.fill: parent + hoverEnabled: true + // if no task passed we don't accept any buttons, if icon_widget is visible we pass left button to it + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + enabled: __has_task + visible: __has_task + + onClicked: __processClick(mouse.button, mouse_area) + + // Widget for icon if no animation is requested + PlasmaCore.IconItem { + id: icon_widget + + anchors.fill: parent + + property QtObject action: __has_task ? plasmoid.createShortcutAction(task.objectName + "-" + plasmoid.id) : null + + visible: false + active: mouse_area.containsMouse + + // Overlay icon + Image { + width: 10 // we fix size of an overlay icon + height: width + anchors { right: parent.right; bottom: parent.bottom } + + sourceSize.width: width + sourceSize.height: width + fillMode: Image.PreserveAspectFit + smooth: true + source: "image://icon/" + __overlay_icon_name + visible: __overlay_icon_name + } + + Component.onDestruction: { + var act = icon_widget.action + icon_widget.action = null + plasmoid.destroyShortcutAction(act) + } + } + + // Animation (Movie icon) + AnimatedImage { + id: animation + + anchors.fill: parent + + playing: false + visible: false + smooth: true + source: __movie_path + } + } + onWheelMoved: { + if (wheel.orientation === Qt.Horizontal) + task.activateHorzScroll(wheel.delta) + else + task.activateVertScroll(wheel.delta) + } + // Tooltip ========================================================================================================= + PlasmaCore.ToolTip { + id: tooltip + target: wheel_area + mainText: __has_task ? task.tooltipTitle : "" + subText: __has_task ? task.tooltipText : "" + image: __has_task ? task.tooltipIcon : "" + } + } + + // Functions ======================================================================================================= + function __getDefaultIcon() { + return task.customIcon(__icon_name != "" ? __icon_name : __icon) + } + + function __getAttentionIcon() { + return task.customIcon(__att_icon_name != "" ? __att_icon_name : __att_icon) + } + + function __processClick(buttons, item) { + __clickTime = (new Date()).getTime(); + var pos = plasmoid.popupPosition(item) + switch (buttons) { + case Qt.LeftButton: task.activate1(pos.x, pos.y); break + case Qt.RightButton: task.activateContextMenu(pos.x, pos.y); break + case Qt.MiddleButton: task.activate2(pos.x, pos.y); break + } + } + + // States ========================================================================================================== + states: [ + // Static icon + State { + name: "__STATIC" + when: __status !== NeedsAttention + PropertyChanges { + target: timer_blink + running: false + } + PropertyChanges { + target: icon_widget + source: __getDefaultIcon() + visible: true + } + PropertyChanges { + target: animation + visible: false + playing: false + } + StateChangeScript { + script: tooltip.target = icon_widget // binding to property doesn't work + } + }, + // Attention icon + State { + name: "__BLINK" + when: __status === NeedsAttention && !__movie_path + PropertyChanges { + target: icon_widget + source: __getAttentionIcon() + visible: true + } + PropertyChanges { + target: timer_blink + running: true + is_att_icon: false + } + PropertyChanges { + target: animation + visible: false + playing: false + } + StateChangeScript { + script: tooltip.target = icon_widget + } + }, + // Animation icon + State { + name: "__ANIM" + when: __status === NeedsAttention && __movie_path + PropertyChanges { + target: timer_blink + running: false + } + PropertyChanges { + target: icon_widget + source: __getDefaultIcon() + visible: false + } + PropertyChanges { + target: animation + visible: true + playing: true + } + StateChangeScript { + script: tooltip.target = animation + } + } + ] + +} diff --git a/plasma/generic/applets/systemtray/package/contents/ui/TrayIcon.qml b/plasma/generic/applets/systemtray/package/contents/ui/TrayIcon.qml new file mode 100644 index 00000000..7b69ebea --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/ui/TrayIcon.qml @@ -0,0 +1,31 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ +import QtQuick 1.1 + +Item { + id: root_item + + Component.onCompleted: { + ui_item.parent = root_item + } +} diff --git a/plasma/generic/applets/systemtray/package/contents/ui/main.qml b/plasma/generic/applets/systemtray/package/contents/ui/main.qml new file mode 100644 index 00000000..209091b0 --- /dev/null +++ b/plasma/generic/applets/systemtray/package/contents/ui/main.qml @@ -0,0 +1,347 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: LGPLv2+ + * Authors: Dmitry Ashkadov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **********************************************************************************************************************/ + +import QtQuick 1.1 +import Private 0.1 + +import "../code/TasksSet.js" as TasksSet +import "../code/main.js" as JS // stuff & JS additions + +Item { + id: root_item // represents available space on screen + + // This 2 properties must be defined because we use states to set their values + property int minimumWidth: JS.MINIMUM_SIZE + property int minimumHeight: JS.MINIMUM_SIZE + + property int iconSize: Math.min(root_item.width, Math.min(root_item.height, theme.defaultFont.mSize.height < 20 ? 24 : theme.largeIconSize)) //Math.min(root_item.width, Math.min(root_item.height, JS.ICONS_SIZE)) + + // Data Models + property list models: [ + ListModel {id: model_tray}, + ListModel {id: model_popup}, + ListModel {id: model_notifications} + ] + + Connections { + target: plasmoid + + onNewTask: { + // create declarative item + var component = (task.type === TypeStatusItem ? component_status_item : component_widget) + var props = {"task": task} + var item = component.createObject(null, props) + if (item) { + var loc = getLocationForTask(task) + var task_id = plasmoid.getUniqueId(task) + JS.allTasks[task_id] = task + var t = JS.tasks[loc].add(task_id, task.category, item) + models[loc].insert(t.index, {"task": task, "ui_item": item}) + } + } + + onDeletedTask: { + var task_id = plasmoid.getUniqueId(task) + var loc = JS.findLocation(task_id) + var t = JS.tasks[loc].remove(task_id) + models[loc].remove(t.index) + t.data.destroy() // destroy item / we have to destroy it manually because we don't provide parent at initialization + delete JS.allTasks[task_id] + } + + onVisibilityPreferenceChanged: { + // move all tasks to their new location + for (var task_id in JS.allTasks) { + var task = JS.allTasks[task_id] + moveTaskToLocation(task, getLocationForTask(task)) + } + } + + onActivate: arrow_area.togglePopup() + } + + + Component.onCompleted: { + // create sets for tasks + for (var i = 0; i < JS.LOCATIONS_NUMBER; ++i) + JS.tasks[JS.LOCATIONS[i]] = new TasksSet.TasksSet(JS.CATEGORIES) + } + + Item { + id: content_item // represents rectangle containing all visual elements on panel + anchors.centerIn: parent + + // Notifications area in panel part of tray + IconsGrid { + id: notifications_area + icons_size: root_item.iconSize + model: model_notifications + } + + // Tray area that is in panel + IconsGrid { + id: tray_area + icons_size: root_item.iconSize + model: model_tray + } + + // An area that contains arrow + ArrowArea { + id: arrow_area + visible: model_popup.count > 0 + + content: IconsList { + id: popup_area + icons_size: root_item.iconSize + model: model_popup + } + } + } + + // Delegates for views ============================================================================================= + Component { + id: component_status_item + + StatusNotifierItem { + id: status_item + + blink_interval: JS.BLINK_INTERVAL + visible: task !== null + width: root_item.iconSize + height: width + anchors.centerIn: parent + + Connections { + target: task + onChangedStatus: moveTaskToLocation(task, getLocationForTask(task)) + onChangedVisibilityPreference: moveTaskToLocation(task, getLocationForTask(task)) + } + } + } + + Component { + id: component_widget + + WidgetItem { + id: widget_item + + applet: plasmoid + visible: task !== null + width: root_item.iconSize + height: width + anchors.centerIn: parent + + Connections { + target: task + onChangedStatus: moveTaskToLocation(task, getLocationForTask(task)) + onChangedVisibilityPreference: moveTaskToLocation(task, getLocationForTask(task)) + } + } + } + + // Funtions ======================================================================================================== + function getLocationForTask(task) { + var loc = getDefaultLocationForTask(task); + if (loc === JS.LOCATION_TRAY && task.taskId == JS.TASK_NOTIFICATIONS_TYPEID) { + // redefine location for notifications applet + return JS.LOCATION_NOTIFICATION; + } + return loc; + } + + /// Returns location depending on status and hide state of task + function getDefaultLocationForTask(task) { + var vis_pref = plasmoid.getVisibilityPreference(task); + + if (task.status === NeedsAttention || vis_pref === AlwaysShown) { + return JS.LOCATION_TRAY; + } + + if (vis_pref === AlwaysHidden || (task.status !== Active && task.status !== UnknownStatus)) { + return JS.LOCATION_POPUP; + } + + return JS.LOCATION_TRAY; + } + + /// Moves task to specified location + function moveTaskToLocation(task, loc) { + var task_id = plasmoid.getUniqueId(task); + var old_loc = JS.findLocation(task_id); + + if (old_loc === loc) { + return + } + + // remove from old location + var t = JS.tasks[old_loc].remove(task_id); + models[old_loc].remove(t.index); + + // add to new model + t = JS.tasks[loc].add(task_id, t.category, t.data); + models[loc].insert(t.index, {"task": task, "ui_item": t.data}); + } + + + // States ========================================================================================================== + states: [ + State { + name: "_HORZ" // it is shared state for HORZ and FLOAT + AnchorChanges { + target: arrow_area + anchors { left: tray_area.right; top: content_item.top; bottom: content_item.bottom } + } + PropertyChanges { + target: arrow_area + // it's strange but if width of arrow area is set to 0 then this may cause crashing of plasma during resising of panel (somewhere in QtDeclarative) + width: arrow_area.visible ? arrow_area.arrow_size + 2*JS.ARROW_MARGINS : 1 + state: plasmoid.location === TopEdge ? "TOP_EDGE" : "BOTTOM_EDGE" + } + PropertyChanges { + target: popup_area + state: JS.USE_GRID_IN_POPUP ? "SQR_H" : "" + } + }, + + State { + name: "HORZ" + extend: "_HORZ" + when: (plasmoid.formFactor === Horizontal) + + AnchorChanges { + target: notifications_area + anchors { top: content_item.top; bottom: content_item.bottom; left: content_item.left } + } + PropertyChanges { + target: notifications_area + state: "HORZ" + width: notifications_area.min_width + } + AnchorChanges { + target: tray_area + anchors { left: notifications_area.right; top: content_item.top; bottom: content_item.bottom } + } + PropertyChanges { + target: tray_area + state: "HORZ" + width: tray_area.min_width + } + PropertyChanges { + target: content_item + width: notifications_area.width + tray_area.width + arrow_area.width + height: root_item.height + } + PropertyChanges { + target: root_item + minimumWidth: content_item.width + minimumHeight: JS.MINIMUM_SIZE + } + }, + + State { + name: "VERT" + when: (plasmoid.formFactor === Vertical) + + AnchorChanges { + target: notifications_area + anchors { left: content_item.left; right: content_item.right; top: content_item.top } + } + PropertyChanges { + target: notifications_area + state: "VERT" + height: notifications_area.min_height + } + AnchorChanges { + target: tray_area + anchors { left: content_item.left; right: content_item.right; top: notifications_area.bottom } + } + PropertyChanges { + target: tray_area + state: "VERT" + height: tray_area.min_height + } + AnchorChanges { + target: arrow_area + anchors { left: content_item.left; right: content_item.right; top: tray_area.bottom } + } + PropertyChanges { + target: arrow_area + height: arrow_area.visible ? arrow_area.arrow_size + 2*JS.ARROW_MARGINS : 1 + state: plasmoid.location === LeftEdge ? "LEFT_EDGE" : "RIGHT_EDGE" + } + PropertyChanges { + target: popup_area + state: JS.USE_GRID_IN_POPUP ? "SQR_V" : "" + } + PropertyChanges { + target: content_item + width: root_item.width + height: notifications_area.height + tray_area.height + arrow_area.height + } + PropertyChanges { + target: root_item + minimumWidth: JS.MINIMUM_SIZE + minimumHeight: content_item.height + } + }, + + State { + name: "FLOAT" + extend: "_HORZ" + when: (plasmoid.formFactor === Floating) + + PropertyChanges { + target: notifications_area + state: "SQR_H" + width: notifications_area.min_width + height: notifications_area.min_height + } + AnchorChanges { + target: notifications_area + anchors { left: content_item.left; verticalCenter: content_item.verticalCenter } + } + AnchorChanges { + target: tray_area + anchors { left: notifications_area.right; verticalCenter: content_item.verticalCenter } + } + PropertyChanges { + target: tray_area + state: "SQR_V" + width: tray_area.min_width + height: tray_area.min_height + } + PropertyChanges { + target: content_item + width: notifications_area.width + tray_area.width + arrow_area.width + height: Math.max(notifications_area.min_height, tray_area.min_height, arrow_area.arrow_size) + } + PropertyChanges { + target: root_item + minimumWidth: content_item.width + minimumHeight: content_item.height + } + } + ] + + +} diff --git a/plasma/generic/applets/systemtray/plasma-applet-systemtray.desktop b/plasma/generic/applets/systemtray/plasma-applet-systemtray.desktop new file mode 100644 index 00000000..e7799142 --- /dev/null +++ b/plasma/generic/applets/systemtray/plasma-applet-systemtray.desktop @@ -0,0 +1,176 @@ +[Desktop Entry] +Name=System Tray +Name[af]=Stelsellaai +Name[ar]=صينية النظام +Name[ast]=Bandexa del sistema +Name[be]=Сістэмны трэй +Name[be@latin]=Systemny trej +Name[bg]=Системен панел +Name[bn]=সিস্টেম ট্রে +Name[bn_IN]=সিস্টেম ট্রে +Name[br]=Barlenn ar reizhiad +Name[bs]=sistemska kaseta +Name[ca]=Safata del sistema +Name[ca@valencia]=Safata del sistema +Name[cs]=Systémová část panelu +Name[csb]=Systemòwi zabiérnik +Name[cy]=Bar Tasgau +Name[da]=Statusområde +Name[de]=Systemabschnitt der Kontrollleiste +Name[el]=Πλαίσιο συστήματος +Name[en_GB]=System Tray +Name[eo]=Sistempleto +Name[es]=Bandeja del sistema +Name[et]=Süsteemne dokk +Name[eu]=Sistema-erretilua +Name[fa]=سینی سیستم +Name[fi]=Ilmoitusalue +Name[fr]=Boîte à miniatures +Name[fy]=Systeemfak +Name[ga]=Tráidire an Chórais +Name[gl]=Bandexa do sistema +Name[gu]=સિસ્ટમ ટ્રે +Name[he]=מגש המערכת +Name[hi]=तंत्र तश्तरी +Name[hne]=तंत्र तस्तरी +Name[hr]=Sistemski blok +Name[hsb]=Systemowa wotkładka +Name[hu]=Paneltálca +Name[ia]=Tabuliero de systema +Name[id]=Baki Sistem +Name[is]=Kerfisbakki +Name[it]=Vassoio di sistema +Name[ja]=システムトレイ +Name[ka]=სისტემური პანელი +Name[kk]=Жүйелік сөре +Name[km]=ថាស​ប្រព័ន្ធ +Name[kn]=ವ್ಯವಸ್ಥಾ ಖಾನೆ (ಟ್ರೇ) +Name[ko]=시스템 트레이 +Name[lt]=Sistemos dėklas +Name[lv]=Sistēmas ikonu josla +Name[mai]=तंत्र तश्तरी +Name[mk]=Системска лента +Name[ml]=സിസ്റ്റം ട്രേ +Name[mr]=प्रणाली ट्रे +Name[ms]=Dulang Sistem +Name[nb]=Systemkurv +Name[nds]=Paneel-Systeemafsnitt +Name[ne]=प्रणाली ट्रे +Name[nl]=Systeemvak +Name[nn]=Systemtrau +Name[or]=ତନ୍ତ୍ର ଧାରକ +Name[pa]=ਸਿਸਟਮ ਟਰੇ +Name[pl]=Tacka systemowa +Name[pt]=Bandeja do Sistema +Name[pt_BR]=Área de notificação +Name[ro]=Tavă de sistem +Name[ru]=Системный лоток +Name[se]=Vuogádatgárcu +Name[si]=පද්ධතිය තැටිය +Name[sk]=Systémová lišta +Name[sl]=Sistemska vrstica +Name[sr]=системска касета +Name[sr@ijekavian]=системска касета +Name[sr@ijekavianlatin]=sistemska kaseta +Name[sr@latin]=sistemska kaseta +Name[sv]=Systembricka +Name[ta]=சாதன தட்டு +Name[te]=వ్యవస్థ ట్రె +Name[tg]=Системный лоток +Name[th]=ถาดระบบ +Name[tr]=Sistem Çekmecesi +Name[ug]=سىستېما قوندىقى +Name[uk]=Системний лоток +Name[vi]=Khay hệ thống +Name[wa]=Boesse ås imådjetes sistinme +Name[xh]=Itreyi Yendlela yokusebenza +Name[x-test]=xxSystem Trayxx +Name[zh_CN]=系统托盘 +Name[zh_TW]=系統匣 +Comment=Access hidden applications minimized in the system tray +Comment[ar]=انفذ إلى التطبيقات المخفية المصغرة في صينية النظام +Comment[ast]=Acceder a aplicaciones anubríes minimizaes na bandexa del sistema +Comment[be@latin]=Dostup da schavanych u systemnym trei aplikacyjaŭ +Comment[bg]=Достъп до минимизираните в системния панел програми +Comment[bs]=Pristup skrivenim programima minimizovanim u sistemsku kasetu +Comment[ca]=Accés a les aplicacions minimitzades ocultes en la safata del sistema +Comment[ca@valencia]=Accés a les aplicacions minimitzades ocultes en la safata del sistema +Comment[cs]=Přístup ke skrytým aplikacím, které jsou minimalizované v systémové oblasti +Comment[csb]=Dôwô mòżnotã taceniô ë minimalizowaniô aplikacëjów do systemòwégò zabiérnika +Comment[da]=Tilgå skjulte programmer der er minimeret i statusområdet +Comment[de]=Ermöglicht den Zugriff auf Programme, die im Systemabschnitt der Kontrollleiste laufen. +Comment[el]=Πρόσβαση κρυφών εφαρμογών ελαχιστοποιημένων στο πλαίσιο συστήματος +Comment[en_GB]=Access hidden applications minimised in the system tray +Comment[eo]=Atingi kaŝitan minimumigitajn aplikaĵojn en la taskopleto +Comment[es]=Acceder a aplicaciones ocultas minimizadas en la bandeja del sistema +Comment[et]=Süsteemsesse salve minimeeritud peidetud rakenduste kasutamine +Comment[eu]=Atzitu sistema-erretiluan ikonotuta dauden ezkutuko aplikazioak +Comment[fi]=Hae piilotettuja sovelluksia, jotka on pienennetty ilmoitusalueelle +Comment[fr]=Accède aux applications cachées et réduites dans la boîte à miniatures +Comment[fy]=Jou tagong ta programma's dy't yn it systeemfak rinne +Comment[ga]=Rochtain feidhmchláir atá íoslaghdaithe i dtráidire an chórais +Comment[gl]=Accede a programas ocultos minimizados na bandexa do sistema +Comment[gu]=સિસ્ટમ ટ્રેમાં નીચાં કરેલ છુપાયેલ કાર્યક્રમોને જુઓ +Comment[he]=גישה ליישומים נסתרים הממוזערים במגש המערכת +Comment[hi]=तंत्र तश्तरी में न्यूनतम किए गए छुपे अनुप्रयोगों पर पहुँच +Comment[hne]=सिस्टम ट्रे मं छोटा करे लुकाय गे अनुपरयोग मं पहुंच +Comment[hr]=Pristup skrivenim aplikacijama minimiziranim u sistemskom bloku +Comment[hu]=Minimalizált alkalmazások elérését teszi lehetővé a paneltálcáról +Comment[ia]=Accede a applicationes celate minimisate in le tabuliero de systema +Comment[id]=Akses aplikasi tersembunyi yang diminimalkan di baki sistem +Comment[is]=Aðgangur að földum forritum sem ganga í kerfisbakkanum +Comment[it]=Accedi alle applicazioni minimizzate nel vassoio di sistema +Comment[ja]=システムトレイに最小化されたアプリケーションにアクセスします +Comment[kk]=Жүйелік сөреге түйілген жасырын қолданбаларға қатынау +Comment[km]=ចូល​ដំណើរការ​កម្មវិធី​ដែល​លាក់​ដែល​បានបង្រួម​នៅ​ក្នុង​ថាស​ប្រព័ន្ធ +Comment[kn]=ವ್ಯವಸ್ಥಾ ಖಾನೆಯಲ್ಲಿ (ಟ್ರೇ) ಕನಿಷ್ಠೀಕರಿಸಲಾದ ಅಡಗಿಸಲಾದ ಅನ್ವಯಗಳನ್ನು ನಿಲುಕಿಸಿಕೋ +Comment[ko]=시스템 트레이에 숨어 있는 프로그램에 접근합니다 +Comment[lt]=Prieiti prie sistemos dėkle paslėptų programų +Comment[lv]=Piekļūst slēptām programmām, kas minimizētas sistēmas ikonu joslā +Comment[mk]=Пристап до скриените апликации што се наоѓаат во сис. лента +Comment[ml]=സിസ്റ്റം ട്രേയില്‍ മിനിമൈസ് ആയിരിക്കുന്ന ഒളിഞ്ഞിരിയ്ക്കുന്ന പ്രയോഗങ്ങളെ സമീപിയ്ക്കുക +Comment[mr]=system tray अंतर्गत प्रवेश करिता लपविलेले अनुप्रयोग लहान करा +Comment[nb]=Få tilgang til skjulte programmer som er minimert i systemkurven +Comment[nds]=Togriep op versteken Programmen binnen den Systeemafsnitt +Comment[nl]=Biedt toegang tot programma's die in het systeemvak draaien +Comment[nn]=Tilgang til program minimerte i systemtrauet +Comment[or]=ତନ୍ତ୍ର ଟ୍ରେରେ ଆକାର ଛୋଟହୋଇ ଲୁକ୍କାୟିତ ପ୍ରୟୋଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରନ୍ତୁ +Comment[pa]=ਸਿਸਟਮ ਟਰੇ ਵਿੱਚ ਲੁਕਵੀਆਂ ਘੱਟੋ-ਘੱਟ ਕੀਤੀਆਂ ਆਈਟਮਾਂ ਲਈ ਅਸੈੱਸ +Comment[pl]=Dostęp do programów zminimalizowanych na tacce systemowej +Comment[pt]=Aceder às aplicações escondidas e minimizadas na bandeja do sistema +Comment[pt_BR]=Acessa aplicativos ocultos minimizados na área de notificação +Comment[ro]=Accesați aplicațiile ascunse minimizate în tava de sistem +Comment[ru]=Показ значков приложений, свёрнутых в системный лоток +Comment[si]=පද්ධති තැටියේ හකුළා සඟවා ඇති යෙදුම් වලට පිවිසෙන්න +Comment[sk]=Prístup k skrytým aplikáciam minimalizovaným do systémovej lišty +Comment[sl]=Dostopajte do skritih programov, pomanjšanih v sistemsko vrstico +Comment[sr]=Приступ скривеним програмима минимизованим у системску касету +Comment[sr@ijekavian]=Приступ скривеним програмима минимизованим у системску касету +Comment[sr@ijekavianlatin]=Pristup skrivenim programima minimizovanim u sistemsku kasetu +Comment[sr@latin]=Pristup skrivenim programima minimizovanim u sistemsku kasetu +Comment[sv]=Kom åt dolda program minimerade i systembrickan +Comment[ta]=Access hidden applications minimized in the system tray +Comment[te]=సిస్టమ్ ట్రేనందు మినిమైజ్ కాబడి దాగివున్న అనువవర్తనములను యాక్సిస్ చేయుము +Comment[th]=เข้าใช้งานโปรแกรมที่ซ่อนตัวอยู่ในถาดระบบ +Comment[tr]=Sistem çekmecesine küçültülen uygulamalara erişin +Comment[ug]=سىستېما قونداققا كىچىكلىتىپ يوشۇرۇلغان پروگراممىلارنى زىيارەت +Comment[uk]=Доступ до прихованих програм, мінімізованих до системного лотка +Comment[vi]=Truy cập các ứng dụng ẩn được thu nhỏ trong khay hệ thống +Comment[wa]=Åyoz accès ås programes catchîs metous ås pus ptit el boesse ås imådjetes do sistinme +Comment[x-test]=xxAccess hidden applications minimized in the system trayxx +Comment[zh_CN]=访问在系统托盘中最小化隐藏的应用程序 +Comment[zh_TW]=存取最小化在系統匣內的隱藏應用程式 +Icon=preferences-desktop-notification +Type=Service +X-KDE-ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_systemtray +X-KDE-PluginInfo-Author=Alexander Rodin +X-KDE-PluginInfo-Email=rodin.alexander@gmail.com +X-KDE-PluginInfo-Name=systemtray +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Windows and Tasks +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL v2+ +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtrayprotocol.cpp b/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtrayprotocol.cpp new file mode 100644 index 00000000..5fe0b7fa --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtrayprotocol.cpp @@ -0,0 +1,96 @@ +/*************************************************************************** + * dbussystemtrayprotocol.cpp * + * * + * Copyright (C) 2009 Marco Martin * + * * + * 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 "dbussystemtraytask.h" +#include "dbussystemtrayprotocol.h" + +#include + + +namespace SystemTray +{ + +DBusSystemTrayProtocol::DBusSystemTrayProtocol(QObject *parent) + : Protocol(parent), + m_dataEngine(Plasma::DataEngineManager::self()->loadEngine("statusnotifieritem")), + m_tasks() +{ +} + +DBusSystemTrayProtocol::~DBusSystemTrayProtocol() +{ + Plasma::DataEngineManager::self()->unloadEngine("statusnotifieritem"); +} + +void DBusSystemTrayProtocol::init() +{ + if (m_dataEngine->isValid()) { + initRegisteredServices(); + connect(m_dataEngine, SIGNAL(sourceAdded(QString)), + this, SLOT(newTask(QString))); + connect(m_dataEngine, SIGNAL(sourceRemoved(QString)), + this, SLOT(cleanupTask(QString))); + } +} + +void DBusSystemTrayProtocol::newTask(const QString &service) +{ + if (m_tasks.contains(service)) { + return; + } + + DBusSystemTrayTask *task = new DBusSystemTrayTask(service, m_dataEngine, this); + + m_tasks[service] = task; +} + +void DBusSystemTrayProtocol::cleanupTask(const QString &service) +{ + DBusSystemTrayTask *task = m_tasks.value(service); + + if (task) { + m_dataEngine->disconnectSource(service, task); + m_tasks.remove(service); + if (task->isValid()) { + emit task->destroyed(task); + } + task->deleteLater(); + } +} + +void DBusSystemTrayProtocol::initedTask(DBusSystemTrayTask *task) +{ + emit taskCreated(task); +} + +void DBusSystemTrayProtocol::initRegisteredServices() +{ + if (m_dataEngine->isValid()) { + QStringList registeredItems = m_dataEngine->sources(); + foreach (const QString &service, registeredItems) { + newTask(service); + } + } +} + +} + +#include "dbussystemtrayprotocol.moc" diff --git a/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtrayprotocol.h b/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtrayprotocol.h new file mode 100644 index 00000000..373f8716 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtrayprotocol.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2009 Marco Martin * + * * + * 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 DBUSSYSTEMTRAYPROTOCOL_H +#define DBUSSYSTEMTRAYPROTOCOL_H + +#include "../../core/protocol.h" + +#include + +#include + +#include + + +namespace SystemTray +{ + +class DBusSystemTrayTask; + +class DBusSystemTrayProtocol : public Protocol +{ + Q_OBJECT + friend class DBusSystemTrayTask; +public: + DBusSystemTrayProtocol(QObject *parent); + ~DBusSystemTrayProtocol(); + void init(); + +protected: + void initRegisteredServices(); + +protected Q_SLOTS: + void newTask(const QString &service); + void cleanupTask(const QString &taskId); + +private: + void initedTask(DBusSystemTrayTask *task); + + Plasma::DataEngine *m_dataEngine; + QHash m_tasks; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtraytask.cpp b/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtraytask.cpp new file mode 100644 index 00000000..189ce7db --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtraytask.cpp @@ -0,0 +1,409 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * * + * 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 "dbussystemtraytask.h" + +#include "dbussystemtrayprotocol.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace SystemTray +{ + +DBusSystemTrayTask::DBusSystemTrayTask(const QString &serviceName, Plasma::DataEngine *dataEngine, QObject *parent) + : Task(parent), + m_serviceName(serviceName), + m_taskId(serviceName), + m_customIconLoader(0), + m_dataEngine(dataEngine), + m_service(dataEngine->serviceForSource(serviceName)), + m_isMenu(false), + m_valid(false) +{ + kDebug(); + m_service->setParent(this); + + m_dataEngine->connectSource(serviceName, this); +} + +DBusSystemTrayTask::~DBusSystemTrayTask() +{ +} + +QGraphicsWidget* DBusSystemTrayTask::createWidget(Plasma::Applet */*host*/) +{ + return 0; // d-bus tasks don't have widgets but provide info for GUI; +} + +bool DBusSystemTrayTask::isValid() const +{ + return m_valid; +} + +bool DBusSystemTrayTask::isEmbeddable() const +{ + return false; // this task cannot be embed because it only provides information to GUI part +} + +bool DBusSystemTrayTask::isWidget() const +{ + return false; // isn't a widget +} + +void DBusSystemTrayTask::setShortcut(QString text) { + if (m_shortcut != text) { + m_shortcut = text; + emit changedShortcut(); + } +} + + +QString DBusSystemTrayTask::taskId() const +{ + return m_taskId; +} + +QIcon DBusSystemTrayTask::icon() const +{ + return m_icon; +} + +void DBusSystemTrayTask::activate1(int x, int y) const +{ + KConfigGroup params; + if (m_isMenu) { + params = m_service->operationDescription("ContextMenu"); + } else { + params = m_service->operationDescription("Activate"); + } + params.writeEntry("x", x); + params.writeEntry("y", y); + KJob *job = m_service->startOperationCall(params); + connect(job, SIGNAL(result(KJob*)), this, SLOT(_onContextMenu(KJob*))); +} + +void DBusSystemTrayTask::activate2(int x, int y) const +{ + KConfigGroup params = m_service->operationDescription("SecondaryActivate"); + params.writeEntry("x", x); + params.writeEntry("y", y); + m_service->startOperationCall(params); +} + +void DBusSystemTrayTask::activateHorzScroll(int delta) const +{ + _activateScroll(delta, "Horizontal"); +} + +// Copied from kde-runtime/plasma/declarativeimports/core/iconitem.cpp +bool static hasm_svgIcon(QVariant source) +{ + // Set up compat envrionment, afterwards it is 100% copy'n'pastable. + const QString element = source.toString(); + const QString filename = element.split("-").first(); + Plasma::Svg svgIcon; + Plasma::Svg *m_svgIcon = &svgIcon; + + //try as a svg toolbar icon + m_svgIcon->setImagePath("toolbar-icons/" + filename); + + //try as a svg normal icon (like systray) + if (!m_svgIcon->isValid() || !m_svgIcon->hasElement(element)) { + m_svgIcon->setImagePath("icons/" + filename); + } + m_svgIcon->setContainsMultipleImages(true); + + //success? + if (m_svgIcon->isValid() && m_svgIcon->hasElement(element)) { + return true; + } + return false; +} + +QVariant DBusSystemTrayTask::customIcon(QVariant variant) const +{ + if (variant.canConvert()) { + // If we have no icon loader there is nothing to be done with strings. + if (!m_customIconLoader) + return variant; + + // If an SVG icon can be found (via Plasma theme) the name needs to be + // passed along for IconItem to be able to resolve to the theme name as + // well. + if (hasm_svgIcon(variant)) + return variant; + + // Otherwise return a QIcon from our custom icon loader. + return QVariant(KIcon(variant.toString(), m_customIconLoader)); + } else { + // Most importantly QIcons. Nothing to do for those. + return variant; + } +} + +void DBusSystemTrayTask::activateVertScroll(int delta) const +{ + _activateScroll(delta, "Vertical"); +} + +void DBusSystemTrayTask::_activateScroll(int delta, QString direction) const +{ + KConfigGroup params = m_service->operationDescription("Scroll"); + params.writeEntry("delta", delta); + params.writeEntry("direction", direction); + m_service->startOperationCall(params); +} + +void DBusSystemTrayTask::activateContextMenu(int x, int y) const +{ + KConfigGroup params = m_service->operationDescription("ContextMenu"); + params.writeEntry("x", x); + params.writeEntry("y", y); + KJob *job = m_service->startOperationCall(params); + connect(job, SIGNAL(result(KJob*)), this, SLOT(_onContextMenu(KJob*))); +} + +void DBusSystemTrayTask::_onContextMenu(KJob *job) +{ + if (QCoreApplication::closingDown()) { + // apparently an edge case can be triggered due to the async nature of all this + // see: https://bugs.kde.org/show_bug.cgi?id=251977 + return; + } + + Plasma::ServiceJob *sjob = qobject_cast(job); + if (!sjob) { + return; + } + + QMenu *menu = qobject_cast(sjob->result().value()); + if (menu) { + int x = sjob->parameters()["x"].toInt(); + int y = sjob->parameters()["y"].toInt(); + emit showContextMenu(x, y, QVariant::fromValue(menu)); + } +} + +void DBusSystemTrayTask::dataUpdated(const QString &taskName, const Plasma::DataEngine::Data &properties) +{ + Q_UNUSED(taskName); + + const QString id = properties["Id"].toString(); + bool becomeValid = false; + if (!id.isEmpty() && id != m_taskId) { + m_taskId = id; + m_valid = true; + becomeValid = true; + setObjectName(QString("SystemTray-%1").arg(m_taskId)); + } + + QString cat = properties["Category"].toString(); + if (!cat.isEmpty()) { + int index = metaObject()->indexOfEnumerator("Category"); + int key = metaObject()->enumerator(index).keyToValue(cat.toLatin1()); + + if (key != -1) { + setCategory((Task::Category)key); + } + } + + if (properties["TitleChanged"].toBool() || becomeValid) { + QString title = properties["Title"].toString(); + if (!title.isEmpty()) { + bool is_title_changed = (name() != title); + setName(title); + if (is_title_changed) { + emit changedTitle(); + emit changed(this); + } + } + } + + if (properties["IconsChanged"].toBool() || becomeValid) { + syncIcons(properties); + emit changedIcons(); + } + + if (properties["StatusChanged"].toBool() || becomeValid) { + syncStatus(properties["Status"].toString()); + } + + if (properties["ToolTipChanged"].toBool() || becomeValid) { + syncToolTip(properties["ToolTipTitle"].toString(), + properties["ToolTipSubTitle"].toString(), + properties["ToolTipIcon"].value()); + } + + bool is_menu = properties["ItemIsMenu"].toBool(); + if (is_menu != m_isMenu) { + m_isMenu = is_menu; + emit changedIsMenu(); + } + + if (becomeValid) { + DBusSystemTrayProtocol *protocol = qobject_cast(parent()); + if (protocol) { + protocol->initedTask(this); + } + } +} + +void DBusSystemTrayTask::syncIcons(const Plasma::DataEngine::Data &properties) +{ + m_icon = properties["Icon"].value(); + m_attentionIcon = properties["AttentionIcon"].value(); + + QString icon_name = properties["IconName"].toString(); + QString att_icon_name = properties["AttentionIconName"].toString(); + QString movie_path = properties["AttentionMovieName"].toString(); + QString overlay_icon_name = properties["OverlayIconName"].value(); + QString icon_theme_path = properties["IconThemePath"].value(); + bool is_icon_name_changed = false; + bool is_att_icon_name_changed = false; + bool is_movie_path_changed = false; + bool is_overlay_icon_name_changed = false; + + if (icon_name != m_iconName) { + m_iconName = icon_name; + is_icon_name_changed = true; + } + + if (att_icon_name != m_attentionIconName) { + m_attentionIconName = att_icon_name; + is_att_icon_name_changed = true; + } + + if (!movie_path.isEmpty() && !QDir::isAbsolutePath(movie_path)) { + movie_path = KIconLoader::global()->moviePath(movie_path, KIconLoader::Panel); + } + + if (movie_path != m_moviePath) { + m_moviePath = movie_path; + is_movie_path_changed = true; + } + + if (overlay_icon_name != m_overlayIconName) { + m_overlayIconName = overlay_icon_name; + is_overlay_icon_name_changed = true; + } + + if (icon_theme_path != m_iconThemePath) { + m_iconThemePath = icon_theme_path; + + if (m_customIconLoader) { + delete m_customIconLoader; + m_customIconLoader = 0; + } + const QString path = m_iconThemePath; + if (!path.isEmpty()) { + // FIXME: If last part of path is not "icons", this won't work! + QStringList tokens = path.split('/', QString::SkipEmptyParts); + if (tokens.length() >= 3 && tokens.takeLast() == QLatin1String("icons")) { + QString appName = tokens.takeLast(); + QString prefix = QChar('/') % tokens.join("/"); + // FIXME: Fix KIconLoader and KIconTheme so that we can use + // our own instance of KStandardDirs + KGlobal::dirs()->addResourceDir("data", prefix); + // We use a separate instance of KIconLoader to avoid + // adding all application dirs to KIconLoader::global(), to + // avoid potential icon name clashes between application + // icons + m_customIconLoader = new KIconLoader(appName, 0 /* dirs */, this); + } else { + kWarning() << "Wrong IconThemePath" << path << ": too short or does not end with 'icons'"; + } + } + + // Trigger updates + is_icon_name_changed = true; + is_att_icon_name_changed = true; + is_overlay_icon_name_changed = true; + emit changedIcons(); + } + + // emit signals + if (is_icon_name_changed) { + emit changedIconName(); + } + if (is_att_icon_name_changed) { + emit changedAttIconName(); + } + if (is_movie_path_changed) { + emit changedMoviePath(); + } + if (is_overlay_icon_name_changed) { + emit changedOverlayIconName(); + } +} + + +//toolTip + +void DBusSystemTrayTask::syncToolTip(const QString &title, const QString &subTitle, const QIcon &toolTipIcon) +{ + if (title != m_tooltipTitle) { + m_tooltipTitle = title; + emit changedTooltipTitle(); + } + + if (subTitle != m_tooltipText) { + m_tooltipText = subTitle; + emit changedTooltipText(); + } + + bool is_icon_name_changed = (m_tooltipIcon.name() != toolTipIcon.name()); + + m_tooltipIcon = toolTipIcon; + emit changedTooltip(); + + if (is_icon_name_changed) { + emit changedTooltipIconName(); + } +} + + +//Status + +void DBusSystemTrayTask::syncStatus(QString newStatus) +{ + Task::Status status = (Task::Status)metaObject()->enumerator(metaObject()->indexOfEnumerator("Status")).keyToValue(newStatus.toLatin1()); + + if (this->status() == status) { + return; + } + + setStatus(status); +} + +} + +#include "dbussystemtraytask.moc" diff --git a/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtraytask.h b/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtraytask.h new file mode 100644 index 00000000..e9f0b9ef --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/dbussystemtray/dbussystemtraytask.h @@ -0,0 +1,149 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * * + * 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 DBUSSYSTEMTRAYTASK_H +#define DBUSSYSTEMTRAYTASK_H + +#include "../../core/task.h" + +#include + +class KIconLoader; +class KJob; + +namespace Plasma +{ + +class Service; + +} + +namespace SystemTray +{ + +class DBusSystemTrayTaskPrivate; + +class DBusSystemTrayTask : public Task +{ + Q_OBJECT + + Q_PROPERTY(QIcon icon READ icon NOTIFY changedIcons) + Q_PROPERTY(QIcon attIcon READ attIcon NOTIFY changedIcons) + Q_PROPERTY(QString overlayIconName READ overlayIconName NOTIFY changedOverlayIconName) + Q_PROPERTY(QString iconName READ iconName NOTIFY changedIconName) + Q_PROPERTY(QString attIconName READ attIconName NOTIFY changedAttIconName) + Q_PROPERTY(QString moviePath READ moviePath NOTIFY changedMoviePath) + Q_PROPERTY(bool isMenu READ isMenu NOTIFY changedIsMenu) + Q_PROPERTY(QString title READ title NOTIFY changedTitle) + Q_PROPERTY(QString tooltipTitle READ tooltipTitle NOTIFY changedTooltipTitle) + Q_PROPERTY(QString tooltipText READ tooltipText NOTIFY changedTooltipText) + Q_PROPERTY(QIcon tooltipIcon READ tooltipIcon NOTIFY changedTooltip) + // property tooltipIconName was introduced to make available some icons in tooltip + // while PlasmaCore.ToolTip doesn't provide property for icon (not only name of an icon) + Q_PROPERTY(QString tooltipIconName READ tooltipIconName NOTIFY changedTooltipIconName) + Q_PROPERTY(QString shortcut READ shortcut NOTIFY changedShortcut) + + friend class DBusSystemTrayProtocol; + +public: + DBusSystemTrayTask(const QString &name, Plasma::DataEngine *service, QObject *parent); + ~DBusSystemTrayTask(); + + QGraphicsWidget* createWidget(Plasma::Applet *host); + bool isValid() const; + bool isEmbeddable() const; + virtual QString taskId() const; + virtual QIcon icon() const; + virtual bool isWidget() const; + virtual TaskType type() const { return TypeStatusItem; } + + QString iconName() const { return m_iconName; } + QIcon attIcon() const { return m_attentionIcon; } + QString attIconName() const { return m_attentionIconName; } + QString moviePath() const { return m_moviePath; } + QString overlayIconName() const { return m_overlayIconName; } + QString title() const { return name(); } + bool isMenu() const { return m_isMenu; } + QString tooltipTitle() const { return m_tooltipTitle; } + QString tooltipText() const { return m_tooltipText; } + QIcon tooltipIcon() const { return m_tooltipIcon; } + QString tooltipIconName() const { return m_tooltipIcon.name(); } + QString shortcut() const { return m_shortcut; } + void setShortcut(QString text); + + Q_INVOKABLE void activateContextMenu(int x, int y) const; + Q_INVOKABLE void activate1(int x, int y) const; + Q_INVOKABLE void activate2(int x, int y) const; + Q_INVOKABLE void activateVertScroll(int delta) const; + Q_INVOKABLE void activateHorzScroll(int delta) const; + Q_INVOKABLE QVariant customIcon(QVariant variant) const; + +signals: + void changedIcons(); // if icons, icon names, movie path are changed + void changedIconName(); // if icon name changed + void changedAttIconName(); // if attention icon name is changed + void changedMoviePath(); + void changedOverlayIconName(); + void changedIsMenu(); + void changedTitle(); + void changedTooltip(); + void changedTooltipTitle(); + void changedTooltipText(); + void changedTooltipIconName(); + void changedShortcut(); + void showContextMenu(int x, int y, QVariant menu); + +private: + void syncToolTip(const QString &title, const QString &subTitle, const QIcon &toolTipIcon); + void syncIcons(const Plasma::DataEngine::Data &properties); + void _activateScroll(int delta, QString direction) const; + +private Q_SLOTS: + void syncStatus(QString status); + void dataUpdated(const QString &taskName, const Plasma::DataEngine::Data &taskData); + void _onContextMenu(KJob*); + +private: + QString m_serviceName; + QString m_taskId; + QIcon m_icon; + QString m_iconName; + QIcon m_attentionIcon; + QString m_attentionIconName; + QString m_shortcut; + QString m_moviePath; + QString m_overlayIconName; + QString m_iconThemePath; + QString m_tooltipTitle; + QString m_tooltipText; + QIcon m_tooltipIcon; + + KIconLoader *m_customIconLoader; + + Plasma::DataEngine *m_dataEngine; + Plasma::Service *m_service; + bool m_isMenu; + bool m_valid; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdographicswidget.cpp b/plasma/generic/applets/systemtray/protocols/fdo/fdographicswidget.cpp new file mode 100644 index 00000000..80fbed37 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdographicswidget.cpp @@ -0,0 +1,227 @@ +/*************************************************************************** + * fdographicswidget.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "fdographicswidget.h" +#include "x11embeddelegate.h" +#include "x11embedcontainer.h" + +#include +#include + +#include +#include + +#include + + +namespace SystemTray +{ + +class FdoGraphicsWidget::Private +{ +public: + Private() + : clientEmbedded(false) + { + } + + ~Private() + { + delete widget.data(); + } + + WId winId; + bool clientEmbedded; + QWeakPointer widget; +}; + +FdoGraphicsWidget::FdoGraphicsWidget(WId winId, QGraphicsWidget *parent) + : QGraphicsWidget(parent), + d(new Private()) +{ + d->winId = winId; + + setMinimumSize(22, 22); + setMaximumSize(48, 48); + resize(22, 22); + + setCacheMode(QGraphicsItem::NoCache); + + QGraphicsView *parentView = 0; + + foreach (QGraphicsView *view, scene()->views()) { + if (view->isVisible() && view->sceneRect().intersects(sceneBoundingRect())) { + parentView = view; + break; + } + } + + if (parentView) { + parentView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + } + + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), + this, SLOT(updateWidgetBackground())); + QTimer::singleShot(0, this, SLOT(setupXEmbedDelegate())); +} + + +FdoGraphicsWidget::~FdoGraphicsWidget() +{ + delete d; +} + + +void FdoGraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *parentWidget) +{ + QGraphicsWidget::paint(painter, option, parentWidget); + + QGraphicsView *parentView = 0; + foreach (QGraphicsView *view, scene()->views()) { + if (view->isVisible() && view->sceneRect().intersects(sceneBoundingRect())) { + parentView = view; + } + } + + if (!parentView) { + return; + } + + if (!d->widget) { + QTimer::singleShot(0, this, SLOT(setupXEmbedDelegate())); + return; + } else if (!d->clientEmbedded) { + return; + } + + QWidget *widget = d->widget.data(); + if (widget->parentWidget() != parentView) { + //kDebug() << "embedding into" << parentView->metaObject()->className() << "(" << d->winId << ")"; + widget->setParent(parentView); + } + + QPoint pos = parentView->mapFromScene(scenePos()); + pos += parentView->viewport()->pos(); + if (widget->pos() != pos) { + widget->move(pos); + } + + if (!widget->isVisible()) { + widget->show(); + } +} + +void FdoGraphicsWidget::hideEvent(QHideEvent *event) +{ + Q_UNUSED(event); + if (d->widget) { + d->widget.data()->hide(); + } +} + +void FdoGraphicsWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event); + if (d->widget) { + d->widget.data()->show(); + } +} + +void FdoGraphicsWidget::setupXEmbedDelegate() +{ + if (d->widget) { + return; + } + +#if QT_VERSION < 0x040401 + const Qt::ApplicationAttribute attr = (Qt::ApplicationAttribute)4; +#else + const Qt::ApplicationAttribute attr = Qt::AA_DontCreateNativeWidgetSiblings; +#endif + if (!QApplication::testAttribute(attr)) { + QApplication::setAttribute(attr); + } + + X11EmbedDelegate *widget = new X11EmbedDelegate(); + widget->setMinimumSize(22, 22); + widget->setMaximumSize(48, 48); + widget->resize(size().toSize()); + widget->move(QPoint(size().width()/2, size().height()/2) - QPoint(11, 11)); + + connect(widget->container(), SIGNAL(clientIsEmbedded()), + this, SLOT(handleClientEmbedded())); + connect(widget->container(), SIGNAL(clientClosed()), + this, SLOT(handleClientClosed())); + connect(widget->container(), SIGNAL(error(QX11EmbedContainer::Error)), + this, SLOT(handleClientError(QX11EmbedContainer::Error))); + + widget->container()->embedSystemTrayClient(d->winId); + d->widget = widget; +} + +void FdoGraphicsWidget::updateWidgetBackground() +{ + X11EmbedDelegate *widget = d->widget.data(); + if (!widget) { + return; + } + + QPalette palette = widget->palette(); + palette.setBrush(QPalette::Window, Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor)); + widget->setPalette(palette); + widget->setBackgroundRole(QPalette::Window); +} + + +void FdoGraphicsWidget::handleClientEmbedded() +{ + //kDebug() << "client embedded (" << d->winId << ")"; + d->clientEmbedded = true; + update(); +} + + +void FdoGraphicsWidget::handleClientClosed() +{ + emit clientClosed(); + //kDebug() << "client closed (" << d->winId << ")"; +} + + +void FdoGraphicsWidget::handleClientError(QX11EmbedContainer::Error error) +{ + Q_UNUSED(error); + + //kDebug() << "client error (" << d->winId << ")"; + emit clientClosed(); +} + +void FdoGraphicsWidget::resizeEvent(QGraphicsSceneResizeEvent *event) +{ + if (d->widget) { + d->widget.data()->resize(size().toSize()); + } + +} + +} + +#include "fdographicswidget.moc" diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdographicswidget.h b/plasma/generic/applets/systemtray/protocols/fdo/fdographicswidget.h new file mode 100644 index 00000000..fbe95720 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdographicswidget.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * fdographicswidget.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 FDOGRAPHICSWIDGET_H +#define FDOGRAPHICSWIDGET_H + +#include +#include + + +namespace SystemTray +{ + +class FdoGraphicsWidget : public QGraphicsWidget +{ + Q_OBJECT + +public: + FdoGraphicsWidget(WId winId, QGraphicsWidget *parent = 0); + ~FdoGraphicsWidget(); + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +signals: + void clientClosed(); + +protected: + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); + void resizeEvent(QGraphicsSceneResizeEvent *event); + +private slots: + void setupXEmbedDelegate(); + void handleClientEmbedded(); + void handleClientClosed(); + void handleClientError(QX11EmbedContainer::Error); + void updateWidgetBackground(); + +private: + class Private; + Private* const d; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdonotification.cpp b/plasma/generic/applets/systemtray/protocols/fdo/fdonotification.cpp new file mode 100644 index 00000000..08381cf0 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdonotification.cpp @@ -0,0 +1,40 @@ +/*************************************************************************** + * fdonotification.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "fdonotification.h" + + +namespace SystemTray +{ + +FdoNotification::FdoNotification(WId winId, QObject *parent) + : Notification(parent), + m_winId(winId) +{ +} + + +FdoNotification::~FdoNotification() +{ + emit notificationDeleted(m_winId); +} + +} diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdonotification.h b/plasma/generic/applets/systemtray/protocols/fdo/fdonotification.h new file mode 100644 index 00000000..c35bf692 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdonotification.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * fdonotification.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 FDONOTIFICATION_H +#define FDONOTIFICATION_H + +#include "../../core/notification.h" + + +namespace SystemTray +{ + +class FdoNotification : public Notification +{ + Q_OBJECT + + friend class FdoSelectionManager; + friend class FdoSelectionManagerPrivate; + +public: + FdoNotification(WId winId, QObject *parent = 0); + ~FdoNotification(); + +signals: + void notificationDeleted(WId winId); + +private: + WId m_winId; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdoprotocol.cpp b/plasma/generic/applets/systemtray/protocols/fdo/fdoprotocol.cpp new file mode 100644 index 00000000..c1bb8b13 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdoprotocol.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + * fdoprotocol.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "fdoprotocol.h" + +#include "fdoselectionmanager.h" + + +namespace SystemTray +{ + +FdoProtocol::FdoProtocol(QObject *parent) + : Protocol(parent), + m_selectionManager(0) +{ +} + +FdoProtocol::~FdoProtocol() +{ + delete m_selectionManager; +} + +void FdoProtocol::init() +{ + m_selectionManager = new FdoSelectionManager; + connect(m_selectionManager, SIGNAL(taskCreated(SystemTray::Task*)), + this, SIGNAL(taskCreated(SystemTray::Task*))); + connect(m_selectionManager, SIGNAL(notificationCreated(SystemTray::Notification*)), + this, SIGNAL(notificationCreated(SystemTray::Notification*))); +} + +} + +#include "fdoprotocol.moc" + diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdoprotocol.h b/plasma/generic/applets/systemtray/protocols/fdo/fdoprotocol.h new file mode 100644 index 00000000..b006967d --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdoprotocol.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * fdoprotocol.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 FDOTASKPROTOCOL_H +#define FDOTASKPROTOCOL_H + +#include "../../core/protocol.h" + + +namespace SystemTray +{ + +class FdoSelectionManager; + +class FdoProtocol : public Protocol +{ + Q_OBJECT + +public: + FdoProtocol(QObject *parent); + ~FdoProtocol(); + void init(); + +private: + FdoSelectionManager *m_selectionManager; +}; + +} + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdoselectionmanager.cpp b/plasma/generic/applets/systemtray/protocols/fdo/fdoselectionmanager.cpp new file mode 100644 index 00000000..4257202f --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdoselectionmanager.cpp @@ -0,0 +1,428 @@ +/*************************************************************************** + * fdoselectionmanager.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "fdoselectionmanager.h" +#include "fdotask.h" +#include "x11embedpainter.h" + +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#ifdef HAVE_XFIXES +# include +#endif + +#ifdef HAVE_XDAMAGE +# include +#endif + +#ifdef HAVE_XCOMPOSITE +# include +#endif + +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + + +namespace SystemTray +{ + +static FdoSelectionManager *s_manager = 0; +static X11EmbedPainter *s_painter = 0; + +#if defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE) && defined(HAVE_XCOMPOSITE) +struct DamageWatch +{ + QWidget *container; + Damage damage; +}; + +static int damageEventBase = 0; +static QMap damageWatches; +static QCoreApplication::EventFilter oldEventFilter; + +// Global event filter for intercepting damage events +static bool x11EventFilter(void *message, long int *result) +{ + XEvent *event = reinterpret_cast(message); + if (event->type == damageEventBase + XDamageNotify) { + XDamageNotifyEvent *e = reinterpret_cast(event); + if (DamageWatch *damageWatch = damageWatches.value(e->drawable)) { + // Create a new region and empty the damage region into it. + // The window is small enough that we don't really care about the region; + // we'll just throw it away and schedule a full repaint of the container. + XserverRegion region = XFixesCreateRegion(e->display, 0, 0); + XDamageSubtract(e->display, e->damage, None, region); + XFixesDestroyRegion(e->display, region); + damageWatch->container->update(); + } + } + + if (oldEventFilter && oldEventFilter != x11EventFilter) { + return oldEventFilter(message, result); + } else { + return false; + } +} +#endif + + +struct MessageRequest +{ + long messageId; + long timeout; + long bytesRemaining; + QByteArray message; +}; + + +class FdoSelectionManagerPrivate +{ +public: + FdoSelectionManagerPrivate(FdoSelectionManager *q) + : q(q), + notificationsEngine(0), + haveComposite(false) + { + display = QX11Info::display(); + selectionAtom = XInternAtom(display, "_NET_SYSTEM_TRAY_S" + QByteArray::number(QX11Info::appScreen()), false); + opcodeAtom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", false); + messageAtom = XInternAtom(display, "_NET_SYSTEM_TRAY_MESSAGE_DATA", false); + visualAtom = XInternAtom(display, "_NET_SYSTEM_TRAY_VISUAL", false); + +#if defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE) && defined(HAVE_XCOMPOSITE) + int eventBase, errorBase; + bool haveXfixes = XFixesQueryExtension(display, &eventBase, &errorBase); + bool haveXdamage = XDamageQueryExtension(display, &damageEventBase, &errorBase); + bool haveXComposite = XCompositeQueryExtension(display, &eventBase, &errorBase); + + if (haveXfixes && haveXdamage && haveXComposite) { + haveComposite = true; + oldEventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter); + } +#endif + } + + void createNotification(WId winId); + + void handleRequestDock(const XClientMessageEvent &event); + void handleBeginMessage(const XClientMessageEvent &event); + void handleMessageData(const XClientMessageEvent &event); + void handleCancelMessage(const XClientMessageEvent &event); + + Display *display; + Atom selectionAtom; + Atom opcodeAtom; + Atom messageAtom; + Atom visualAtom; + + QHash messageRequests; + QHash tasks; + + FdoSelectionManager *q; + Plasma::DataEngine *notificationsEngine; + + bool haveComposite; +}; + +FdoSelectionManager::FdoSelectionManager() + : d(new FdoSelectionManagerPrivate(this)) +{ + // Init the selection later just to ensure that no signals are sent + // until after construction is done and the creating object has a + // chance to connect. + QTimer::singleShot(0, this, SLOT(initSelection())); +} + + +FdoSelectionManager::~FdoSelectionManager() +{ +#if defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE) && defined(HAVE_XCOMPOSITE) + if (d->haveComposite && QCoreApplication::instance()) { + QCoreApplication::instance()->setEventFilter(oldEventFilter); + } +#endif + + if (s_manager == this) { + s_manager = 0; + delete s_painter; + s_painter = 0; + } + + delete d; +} + +FdoSelectionManager *FdoSelectionManager::manager() +{ + return s_manager; +} + +X11EmbedPainter *FdoSelectionManager::painter() +{ + return s_painter; +} + +void FdoSelectionManager::addDamageWatch(QWidget *container, WId client) +{ +#if defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE) && defined(HAVE_XCOMPOSITE) + DamageWatch *damage = new DamageWatch; + damage->container = container; + damage->damage = XDamageCreate(QX11Info::display(), client, XDamageReportNonEmpty); + damageWatches.insert(client, damage); +#endif +} + +void FdoSelectionManager::removeDamageWatch(QWidget *container) +{ +#if defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE) && defined(HAVE_XCOMPOSITE) + for (QMap::Iterator it = damageWatches.begin(); it != damageWatches.end(); ++it) + { + DamageWatch *damage = *(it); + if (damage->container == container) { + XDamageDestroy(QX11Info::display(), damage->damage); + damageWatches.erase(it); + delete damage; + break; + } + } +#endif +} + + +bool FdoSelectionManager::haveComposite() const +{ + return d->haveComposite; +} + + +bool FdoSelectionManager::x11Event(XEvent *event) +{ + if (event->type == ClientMessage) { + if (event->xclient.message_type == d->opcodeAtom) { + switch (event->xclient.data.l[1]) { + case SYSTEM_TRAY_REQUEST_DOCK: + d->handleRequestDock(event->xclient); + return true; + case SYSTEM_TRAY_BEGIN_MESSAGE: + d->handleBeginMessage(event->xclient); + return true; + case SYSTEM_TRAY_CANCEL_MESSAGE: + d->handleCancelMessage(event->xclient); + return true; + } + } else if (event->xclient.message_type == d->messageAtom) { + d->handleMessageData(event->xclient); + return true; + } + } + + return QWidget::x11Event(event); +} + + +void FdoSelectionManager::initSelection() +{ + XSetSelectionOwner(d->display, d->selectionAtom, winId(), CurrentTime); + + WId selectionOwner = XGetSelectionOwner(d->display, d->selectionAtom); + if (selectionOwner != winId()) { + // FIXME: Hmmm... Reading the docs on XSetSelectionOwner, + // this should not be possible. + kDebug() << "Tried to set selection owner to" << winId() << "but it is set to" << selectionOwner; + return; + } + + // Prefer the ARGB32 visual if available + int nvi; + VisualID visual = XVisualIDFromVisual((Visual*)QX11Info::appVisual()); + XVisualInfo templ; + templ.visualid = visual; + XVisualInfo *xvi = XGetVisualInfo(d->display, VisualIDMask, &templ, &nvi); + if (xvi && xvi[0].depth > 16) { + templ.screen = xvi[0].screen; + templ.depth = 32; + templ.c_class = TrueColor; + XFree(xvi); + xvi = XGetVisualInfo(d->display, VisualScreenMask | VisualDepthMask | VisualClassMask, + &templ, &nvi); + for (int i = 0; i < nvi; i++) { + XRenderPictFormat *format = XRenderFindVisualFormat(d->display, xvi[i].visual); + if (format && format->type == PictTypeDirect && format->direct.alphaMask) { + visual = xvi[i].visualid; + break; + } + } + XFree(xvi); + } + XChangeProperty(d->display, winId(), d->visualAtom, XA_VISUALID, 32, + PropModeReplace, (const unsigned char*)&visual, 1); + + if (!s_painter) { + s_painter = new X11EmbedPainter; + } + s_manager = this; + + WId root = QX11Info::appRootWindow(); + XClientMessageEvent xev; + + xev.type = ClientMessage; + xev.window = root; + xev.message_type = XInternAtom(d->display, "MANAGER", false); + xev.format = 32; + xev.data.l[0] = CurrentTime; + xev.data.l[1] = d->selectionAtom; + xev.data.l[2] = winId(); + xev.data.l[3] = 0; + xev.data.l[4] = 0; + + XSendEvent(d->display, root, false, StructureNotifyMask, (XEvent*)&xev); +} + + +void FdoSelectionManagerPrivate::handleRequestDock(const XClientMessageEvent &event) +{ + const WId winId = (WId)event.data.l[2]; + + if (tasks.contains(winId)) { + kDebug() << "got a dock request from an already existing task"; + return; + } + + FdoTask *task = new FdoTask(winId, q); + + tasks[winId] = task; + q->connect(task, SIGNAL(taskDeleted(WId)), q, SLOT(cleanupTask(WId))); + + emit q->taskCreated(task); +} + + +void FdoSelectionManager::cleanupTask(WId winId) +{ + d->tasks.remove(winId); +} + + +void FdoSelectionManagerPrivate::handleBeginMessage(const XClientMessageEvent &event) +{ + const WId winId = event.window; + + MessageRequest request; + request.messageId = event.data.l[4]; + request.timeout = event.data.l[2]; + request.bytesRemaining = event.data.l[3]; + + if (request.bytesRemaining) { + messageRequests[winId] = request; + } +} + + +void FdoSelectionManagerPrivate::handleMessageData(const XClientMessageEvent &event) +{ + const WId winId = event.window; + const char *messageData = event.data.b; + + if (!messageRequests.contains(winId)) { + kDebug() << "Unexpected message data from" << winId; + return; + } + + MessageRequest &request = messageRequests[winId]; + const int messageSize = qMin(request.bytesRemaining, 20l); + request.bytesRemaining -= messageSize; + request.message += QByteArray(messageData, messageSize); + + if (request.bytesRemaining == 0) { + createNotification(winId); + messageRequests.remove(winId); + } +} + + +void FdoSelectionManagerPrivate::createNotification(WId winId) +{ + if (!tasks.contains(winId)) { + kDebug() << "message request from unknown task" << winId; + return; + } + + MessageRequest &request = messageRequests[winId]; + Task *task = tasks[winId]; + + QString message = QString::fromUtf8(request.message); + message = QTextDocument(message).toHtml(); + + if (!notificationsEngine) { + notificationsEngine = Plasma::DataEngineManager::self()->loadEngine("notifications"); + } + //FIXME: who is the source in this case? + Plasma::Service *service = notificationsEngine->serviceForSource("notification"); + KConfigGroup op = service->operationDescription("createNotification"); + + if (op.isValid()) { + op.writeEntry("appName", task->name()); + //FIXME: find a way to pass icons trough here + op.writeEntry("appIcon", task->name()); + + //op.writeEntry("summary", task->name()); + op.writeEntry("body", message); + op.writeEntry("timeout", (int)request.timeout); + KJob *job = service->startOperationCall(op); + QObject::connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater())); + } else { + delete service; + kDebug() << "invalid operation"; + } +} + + +void FdoSelectionManagerPrivate::handleCancelMessage(const XClientMessageEvent &event) +{ + const WId winId = event.window; + const long messageId = event.data.l[2]; + + if (messageRequests.contains(winId) && messageRequests[winId].messageId == messageId) { + messageRequests.remove(winId); + } +} + + +} diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdoselectionmanager.h b/plasma/generic/applets/systemtray/protocols/fdo/fdoselectionmanager.h new file mode 100644 index 00000000..c86a2d54 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdoselectionmanager.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * fdoselectionmanager.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 FDOSELECTIONMANAGER_H +#define FDOSELECTIONMANAGER_H + +#include + +namespace SystemTray +{ + +class Notification; +class Task; +class X11EmbedPainter; +class FdoSelectionManagerPrivate; + +class FdoSelectionManager : public QWidget +{ + Q_OBJECT + +public: + static FdoSelectionManager *manager(); + static X11EmbedPainter *painter(); + + FdoSelectionManager(); + ~FdoSelectionManager(); + + void addDamageWatch(QWidget *container, WId client); + void removeDamageWatch(QWidget *container); + bool haveComposite() const; + +signals: + void taskCreated(SystemTray::Task *task); + void notificationCreated(SystemTray::Notification *notification); + +protected: + bool x11Event(XEvent *event); + +private slots: + void initSelection(); + void cleanupTask(WId winId); + +private: + friend class FdoSelectionManagerPrivate; + FdoSelectionManagerPrivate* const d; +}; + +} + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdotask.cpp b/plasma/generic/applets/systemtray/protocols/fdo/fdotask.cpp new file mode 100644 index 00000000..1d2d7f9a --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdotask.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + * fdotask.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "fdographicswidget.h" +#include "fdotask.h" + +#include +#include + +namespace SystemTray +{ + +class FdoTask::Private +{ +public: + Private(WId winId) + : winId(winId), + widget(0) + { + KWindowInfo info = KWindowSystem::windowInfo(winId, NET::WMName, NET::WM2WindowClass); + + // FIXME: This isn't unique + taskId = info.windowClassName(); + + name = info.name(); + if (name.isEmpty()) { + name = taskId; + } + + icon = KWindowSystem::icon(winId); + } + + WId winId; + QString name; + QString taskId; + QIcon icon; + FdoGraphicsWidget *widget; +}; + + +FdoTask::FdoTask(WId winId, QObject *parent) + : Task(parent), + d(new Private(winId)) +{ + setCategory(ApplicationStatus); + setName(d->name); +} + +FdoTask::~FdoTask() +{ + emit taskDeleted(d->winId); + delete d; +} + +bool FdoTask::isEmbeddable() const +{ + return !isUsed(); +} + +bool FdoTask::isWidget() const { + return true; +} + +QString FdoTask::taskId() const +{ + return d->taskId; +} + +QIcon FdoTask::icon() const +{ + return d->icon; +} + +void FdoTask::abandon(Plasma::Applet *host) +{ + forget(host); + if (d->widget) { + d->widget->hide(); + } +} + +QGraphicsWidget* FdoTask::createWidget(Plasma::Applet *applet) +{ + if (!d->widget) { + d->widget = new FdoGraphicsWidget(d->winId, applet); + connect(d->widget, SIGNAL(clientClosed()), this, SLOT(deleteLater())); + } + + return d->widget; +} + +} + +#include "fdotask.moc" diff --git a/plasma/generic/applets/systemtray/protocols/fdo/fdotask.h b/plasma/generic/applets/systemtray/protocols/fdo/fdotask.h new file mode 100644 index 00000000..0a0a0ab9 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/fdotask.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * fdotask.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 FDOTASK_H +#define FDOTASK_H + +#include "../../core/task.h" + + +namespace SystemTray +{ + +class FdoTask : public Task +{ + Q_OBJECT + +public: + FdoTask(WId winId, QObject *parent); + ~FdoTask(); + + bool isEmbeddable() const; + QString taskId() const; + QIcon icon() const; + void abandon(Plasma::Applet *host); + virtual bool isWidget() const; + virtual TaskType type() const { return TypeX11Task; } + +signals: + void taskDeleted(WId winId); + +protected: + virtual QGraphicsWidget* createWidget(Plasma::Applet *applet); + +private: + class Private; + Private* const d; +}; + +} + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/fdo/x11embedcontainer.cpp b/plasma/generic/applets/systemtray/protocols/fdo/x11embedcontainer.cpp new file mode 100644 index 00000000..a5bc8262 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/x11embedcontainer.cpp @@ -0,0 +1,252 @@ +/*************************************************************************** + * x11embedcontainer.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "x11embedcontainer.h" +#include "x11embedpainter.h" +#include "fdoselectionmanager.h" + +// KDE +#include + +// Qt +#include +#include +#include + +// Xlib +#include + +#include +#include + +#ifdef HAVE_XCOMPOSITE +# include +#endif + + +namespace SystemTray +{ + +class X11EmbedContainer::Private +{ +public: + Private(X11EmbedContainer *q) + : q(q), + picture(None), + updatesEnabled(true) + { + } + + ~Private() + { + if (picture) { + XRenderFreePicture(QX11Info::display(), picture); + } + } + + X11EmbedContainer *q; + + XWindowAttributes attr; + Picture picture; + bool updatesEnabled; + QImage oldBackgroundImage; +}; + + +X11EmbedContainer::X11EmbedContainer(QWidget *parent) + : QX11EmbedContainer(parent), + d(new Private(this)) +{ + connect(this, SIGNAL(clientIsEmbedded()), + this, SLOT(ensureValidSize())); +} + + +X11EmbedContainer::~X11EmbedContainer() +{ + FdoSelectionManager::manager()->removeDamageWatch(this); + delete d; +} + + +void X11EmbedContainer::embedSystemTrayClient(WId clientId) +{ + Display *display = QX11Info::display(); + + if (!XGetWindowAttributes(display, clientId, &d->attr)) { + emit error(QX11EmbedContainer::Unknown); + return; + } + + XSetWindowAttributes sAttr; + sAttr.background_pixel = BlackPixel(display, DefaultScreen(display)); + sAttr.border_pixel = BlackPixel(display, DefaultScreen(display)); + sAttr.colormap = d->attr.colormap; + + WId parentId = parentWidget() ? parentWidget()->winId() : DefaultRootWindow(display); + Window winId = XCreateWindow(display, parentId, 0, 0, d->attr.width, d->attr.height, + 0, d->attr.depth, InputOutput, d->attr.visual, + CWBackPixel | CWBorderPixel | CWColormap, &sAttr); + + XWindowAttributes attr; + if (!XGetWindowAttributes(display, winId, &attr)) { + emit error(QX11EmbedContainer::Unknown); + return; + } + + create(winId); + +#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE) + XRenderPictFormat *format = XRenderFindVisualFormat(display, d->attr.visual); + if (format && format->type == PictTypeDirect && format->direct.alphaMask && + FdoSelectionManager::manager()->haveComposite()) + { + // Redirect ARGB windows to offscreen storage so we can composite them ourselves + XRenderPictureAttributes attr; + attr.subwindow_mode = IncludeInferiors; + + d->picture = XRenderCreatePicture(display, clientId, format, CPSubwindowMode, &attr); + XCompositeRedirectSubwindows(display, winId, CompositeRedirectManual); + FdoSelectionManager::manager()->addDamageWatch(this, clientId); + + //kDebug() << "Embedded client uses an ARGB visual -> compositing."; + } else { + //kDebug() << "Embedded client is not using an ARGB visual."; + } +#endif + + // repeat everything from QX11EmbedContainer's ctor that might be relevant + setFocusPolicy(Qt::StrongFocus); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setAcceptDrops(true); + setEnabled(false); + + XSelectInput(display, winId, + KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + KeymapStateMask | + PointerMotionMask | + EnterWindowMask | LeaveWindowMask | + FocusChangeMask | + ExposureMask | + StructureNotifyMask | + SubstructureNotifyMask); + + XFlush(display); + + embedClient(clientId); + + // FIXME: This checks that the client is still valid. Qt won't pick it up + // if the client closes before embedding completes. However, what happens + // if the close happens after this point? Should checks happen on a timer + // until embedding completes perhaps? + if (!XGetWindowAttributes(QX11Info::display(), clientId, &d->attr)) { + emit error(QX11EmbedContainer::Unknown); + return; + } +} + + +void X11EmbedContainer::ensureValidSize() +{ + QSize s = QSize(qBound(minimumSize().width(), width(), maximumSize().width()), + qBound(minimumSize().height(), height(), maximumSize().height())); + resize(s); +} + + +void X11EmbedContainer::setUpdatesEnabled(bool enabled) +{ + d->updatesEnabled = enabled; +} + + +void X11EmbedContainer::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + + if (!d->updatesEnabled) { + return; + } + + if (!d->picture) { + FdoSelectionManager::painter()->updateContainer(this); + return; + } + + // Taking a detour via a QPixmap is unfortunately the only way we can get + // the window contents into Qt's backing store. + QPixmap pixmap = toX11Pixmap(QPixmap(size())); + pixmap.fill(Qt::transparent); + XRenderComposite(x11Info().display(), PictOpSrc, d->picture, None, pixmap.x11PictureHandle(), + 0, 0, 0, 0, 0, 0, width(), height()); + QPainter p(this); + p.drawPixmap(0, 0, pixmap); +} + +void X11EmbedContainer::setBackgroundPixmap(QPixmap background) +{ + if (!clientWinId()) { + return; + } + + //Prevent updating the background-image if possible. Updating can cause a very annoying flicker due to the XClearArea, and thus has to be kept to a minimum + QImage image; + if (background.paintEngine()->type() != QPaintEngine::X11) + image = background.toImage(); // With the raster graphics system this call just returns the backing image, so the image data isn't copied. + else + image = background.copy().toImage(); //With the X11 graphics engine, we have to create a copy first, else we get a crash + + if(d->oldBackgroundImage == image) { + return; + } + d->oldBackgroundImage = image; + + Display* display = QX11Info::display(); + XSetWindowBackgroundPixmap(display, clientWinId(), toX11Pixmap(background).handle()); + XClearArea(display, clientWinId(), 0, 0, 0, 0, True); +} + +// Qt has qt_toX11Pixmap(), but that's sadly not public API. So the only +// option seems to be to create X11-based QPixmap using QPixmap::fromX11Pixmap() +// and draw the non-native pixmap to it. +// NOTE: The alpha-channel is not preserved if it exists, but for X pixmaps it generally should not be needed anyway. +QPixmap X11EmbedContainer::toX11Pixmap(const QPixmap& pix) +{ + if (pix.handle() != 0) // X11 pixmap + return pix; + QPixmap ret; + Pixmap xpix = XCreatePixmap(pix.x11Info().display(), RootWindow(pix.x11Info().display(), pix.x11Info().screen()), + pix.width(), pix.height(), QX11Info::appDepth()); + { + QPixmap wrk = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); + QPainter paint(&wrk); + paint.drawPixmap(0, 0, pix); + paint.end(); + ret = wrk.copy(); + } // free resources so that xpix can be freed (QPixmap does not own it) + XFreePixmap(pix.x11Info().display(), xpix); + return ret; +} + +} + +#include "x11embedcontainer.moc" diff --git a/plasma/generic/applets/systemtray/protocols/fdo/x11embedcontainer.h b/plasma/generic/applets/systemtray/protocols/fdo/x11embedcontainer.h new file mode 100644 index 00000000..a58fafa5 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/x11embedcontainer.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * x11embedcontainer.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 X11EMBEDCONTAINER_H +#define X11EMBEDCONTAINER_H + +#include + + +namespace SystemTray +{ + +class X11EmbedContainer : public QX11EmbedContainer +{ + Q_OBJECT + +public: + X11EmbedContainer(QWidget *parent = 0); + ~X11EmbedContainer(); + + void embedSystemTrayClient(WId id); + void setUpdatesEnabled(bool enabled); + void setBackgroundPixmap(QPixmap background); + +protected: + void paintEvent(QPaintEvent *event); + +private slots: + void ensureValidSize(); + +private: + static QPixmap toX11Pixmap(const QPixmap& pix); + class Private; + Private* const d; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/fdo/x11embeddelegate.cpp b/plasma/generic/applets/systemtray/protocols/fdo/x11embeddelegate.cpp new file mode 100644 index 00000000..7a3715b4 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/x11embeddelegate.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * x11embeddelegate.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "x11embedcontainer.h" +#include "x11embeddelegate.h" + +#include + +namespace SystemTray +{ + +class X11EmbedDelegate::Private +{ +public: + X11EmbedContainer *container; +}; + + +X11EmbedDelegate::X11EmbedDelegate(QWidget *parent) + : QWidget(parent), + d(new Private()) +{ + d->container = new X11EmbedContainer(this); + d->container->move(0, 0); + d->container->show(); +} + + +X11EmbedDelegate::~X11EmbedDelegate() +{ + delete d; +} + + +void X11EmbedDelegate::setParent(QWidget *newParent) +{ + if (parent()) { + parent()->removeEventFilter(this); + } + QWidget::setParent(newParent); + if (newParent) { + newParent->installEventFilter(this); + } +} + + +void X11EmbedDelegate::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + d->container->resize(size()); +} + + +X11EmbedContainer* X11EmbedDelegate::container() +{ + return d->container; +} + + +bool X11EmbedDelegate::eventFilter(QObject *watched, QEvent *event) +{ + bool ret = QWidget::eventFilter(watched, event); + + if (event->type() == QEvent::Hide) { + setParent(0); + } + + return ret; +} + +} + +#include "x11embeddelegate.moc" diff --git a/plasma/generic/applets/systemtray/protocols/fdo/x11embeddelegate.h b/plasma/generic/applets/systemtray/protocols/fdo/x11embeddelegate.h new file mode 100644 index 00000000..a4979899 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/x11embeddelegate.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * x11embeddelegate.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 X11EMBEDDELEGATE_H +#define X11EMBEDDELEGATE_H + +#include + +namespace SystemTray +{ + +class X11EmbedContainer; + +class X11EmbedDelegate : public QWidget +{ + Q_OBJECT + +public: + X11EmbedDelegate(QWidget *parent = 0); + ~X11EmbedDelegate(); + + void setParent(QWidget *parent); + X11EmbedContainer* container(); + + bool eventFilter(QObject *watched, QEvent *event); + +protected: + void resizeEvent(QResizeEvent *event); + +private: + class Private; + Private* const d; +}; + +} + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/fdo/x11embedpainter.cpp b/plasma/generic/applets/systemtray/protocols/fdo/x11embedpainter.cpp new file mode 100644 index 00000000..6076cf4f --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/x11embedpainter.cpp @@ -0,0 +1,152 @@ +/*************************************************************************** + * x11embedpainter.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 "x11embedpainter.h" + +#include +#include +#include + +#include + + +#define MAX_PAINTS_PER_SEC 20 +#define MIN_TIME_BETWEEN_PAINTS (1000 / MAX_PAINTS_PER_SEC) + + +namespace SystemTray +{ + +class X11EmbedPainter::Private +{ +public: + Private(X11EmbedPainter *parent) + : q(parent), + lastPaintTime(QTime::currentTime()), + fastPaints(0) + { + lastPaintTime.addMSecs(-MIN_TIME_BETWEEN_PAINTS); + + delayedPaintTimer.setSingleShot(true); + connect(&delayedPaintTimer, SIGNAL(timeout()), q, SLOT(performUpdates())); + } + + X11EmbedPainter *q; + QSet containers; + QTime lastPaintTime; + QTimer delayedPaintTimer; + int fastPaints; +}; + + +X11EmbedPainter::X11EmbedPainter() + : d(new Private(this)) +{ +} + + +X11EmbedPainter::~X11EmbedPainter() +{ + delete d; +} + + +void X11EmbedPainter::updateContainer(X11EmbedContainer *container) +{ + if (d->containers.contains(container)) { + return; + } + + d->containers.insert(container); + + connect(container, SIGNAL(destroyed(QObject*)), + this, SLOT(removeContainer(QObject*))); + + if (!d->delayedPaintTimer.isActive()) { + int msecsToNextPaint = MIN_TIME_BETWEEN_PAINTS - d->lastPaintTime.elapsed(); + if (msecsToNextPaint > 0 && msecsToNextPaint < MIN_TIME_BETWEEN_PAINTS) { + ++d->fastPaints; + if (d->fastPaints > 2) { + //kDebug() << "Delaying paint by" << msecsToNextPaint << "msecs"; + d->delayedPaintTimer.start(msecsToNextPaint); + } else { + d->delayedPaintTimer.start(0); + } + } else { + d->fastPaints = 0; + d->delayedPaintTimer.start(0); + } + } +} + + +void X11EmbedPainter::removeContainer(QObject *container) +{ + d->containers.remove(static_cast(container)); +} + + +void X11EmbedPainter::performUpdates() +{ + QMultiHash containersByParent; + + foreach (X11EmbedContainer *container, d->containers) { + QWidget *topWidget = container; + while (topWidget->parentWidget()) { + topWidget = topWidget->parentWidget(); + } + containersByParent.insert(topWidget, container); + container->setUpdatesEnabled(false); + } + + foreach (QWidget *parent, containersByParent.uniqueKeys()) { + QList containers = containersByParent.values(parent); + containersByParent.remove(parent); + + QRegion paintRegion; + QHash containerRects; + foreach (X11EmbedContainer *container, containers) { + QRect rect = QRect(container->mapTo(parent, QPoint(0, 0)), container->size()); + containerRects.insert(container, rect); + paintRegion = paintRegion.united(rect); + } + + QPixmap background = QPixmap(parent->size()); + parent->render(&background, paintRegion.boundingRect().topLeft(), paintRegion); + + foreach (X11EmbedContainer *container, containers) { + container->setBackgroundPixmap(background.copy(containerRects.value(container))); + } + } + + foreach (X11EmbedContainer *container, d->containers) { + container->setUpdatesEnabled(true); + disconnect(container, SIGNAL(destroyed(QObject*)), + this, SLOT(removeContainer(QObject*))); + } + + d->containers.clear(); + d->lastPaintTime.start(); +} + +} + +#include "x11embedpainter.moc" diff --git a/plasma/generic/applets/systemtray/protocols/fdo/x11embedpainter.h b/plasma/generic/applets/systemtray/protocols/fdo/x11embedpainter.h new file mode 100644 index 00000000..d5cea64d --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/fdo/x11embedpainter.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * x11embedpainter.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * * + * 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 X11EMBEDPAINTER_H +#define X11EMBEDPAINTER_H + +#include "x11embedcontainer.h" + +#include + + +namespace SystemTray +{ + +class X11EmbedPainter : public QObject +{ + Q_OBJECT + +public: + X11EmbedPainter(); + ~X11EmbedPainter(); + + void updateContainer(X11EmbedContainer *container); + +private slots: + void performUpdates(); + void removeContainer(QObject *container); + +private: + class Private; + Private* const d; +}; + +} + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtask.cpp b/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtask.cpp new file mode 100644 index 00000000..9531d3a7 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtask.cpp @@ -0,0 +1,205 @@ +/*************************************************************************** + * plasmoidtask.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * Copyright (C) 2008 Sebastian Kügler * + * Copyright (C) 2009 Marco Martin * + * * + * 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 "plasmoidtask.h" +#include + +#include +#include + +#include +#include +#include + + +namespace SystemTray +{ + +PlasmoidTask::PlasmoidTask(const QString &appletname, int id, QObject *parent, Plasma::Applet *host) + : Task(parent), + m_appletName(appletname), + m_taskId(appletname), + m_host(host), + m_takenByParent(false) +{ + setName(appletname); + setupApplet(appletname, id); +} + + +PlasmoidTask::~PlasmoidTask() +{ + emit taskDeleted(m_host, m_taskId); +} + + +bool PlasmoidTask::isEmbeddable() const +{ + return m_applet && !m_takenByParent; +} + +bool PlasmoidTask::isValid() const +{ + return !m_appletName.isEmpty() && m_applet; +} + + +QString PlasmoidTask::taskId() const +{ + return m_taskId; +} + + +QIcon PlasmoidTask::icon() const +{ + return m_icon; +} + +Plasma::Applet *PlasmoidTask::host() const +{ + return m_host; +} + +bool PlasmoidTask::isWidget() const { + return true; +} + +QGraphicsWidget* PlasmoidTask::createWidget(Plasma::Applet *host) +{ + if (host != m_host || !m_applet) { + return 0; + } + + Plasma::Applet *applet = m_applet.data(); + m_takenByParent = true; + applet->setParent(host); + applet->setParentItem(host); + KConfigGroup group = applet->config(); + group = group.parent(); + applet->restore(group); + applet->init(); + applet->updateConstraints(Plasma::StartupCompletedConstraint); + applet->flushPendingConstraintsEvents(); + applet->updateConstraints(Plasma::AllConstraints); + applet->flushPendingConstraintsEvents(); + + // make sure to record it in the configuration so that if we reload from the config, + // this applet is remembered + KConfigGroup dummy; + applet->save(dummy); + + connect(applet, SIGNAL(newStatus(Plasma::ItemStatus)), this, SLOT(newAppletStatus(Plasma::ItemStatus))); + + newAppletStatus(applet->status()); + + connect(applet, SIGNAL(configNeedsSaving()), host, SIGNAL(configNeedsSaving())); + connect(applet, SIGNAL(releaseVisualFocus()), host, SIGNAL(releaseVisualFocus())); + + return static_cast(applet); +} + +void PlasmoidTask::forwardConstraintsEvent(Plasma::Constraints constraints) +{ + Plasma::Applet *applet = m_applet.data(); + if (applet) { + applet->updateConstraints(constraints); + applet->flushPendingConstraintsEvents(); + } +} + +int PlasmoidTask::id() const +{ + if (m_applet) { + return m_applet.data()->id(); + } + + return 0; +} + +void PlasmoidTask::setupApplet(const QString &plugin, int id) +{ + Plasma::Applet *applet = Plasma::Applet::load(plugin, id); + m_applet = applet; + + if (!m_applet) { + kDebug() << "Could not load applet" << plugin; + return; + } + + //FIXME: System Information should be system services, but battery and devicenotifier are both there. we would need multiple categories + if (applet->category() == "System Information" || + applet->category() == "Network") { + setCategory(Hardware); + } else if (applet->category() == "Online Services") { + setCategory(Communications); + } + + setName(applet->name()); + + m_icon = KIcon(applet->icon()); + + applet->setFlag(QGraphicsItem::ItemIsMovable, false); + + connect(applet, SIGNAL(appletDestroyed(Plasma::Applet*)), this, SLOT(appletDestroyed(Plasma::Applet*))); + applet->setBackgroundHints(Plasma::Applet::NoBackground); +} + +void PlasmoidTask::appletDestroyed(Plasma::Applet *) +{ + emit destroyed(this); + forget(m_host); + deleteLater(); +} + +void PlasmoidTask::newAppletStatus(Plasma::ItemStatus status) +{ + Plasma::Applet *applet = m_applet.data(); + if (!applet) { + return; + } + + switch (status) { + case Plasma::PassiveStatus: + if (Plasma::PopupApplet *popupApplet = qobject_cast(applet)) { + popupApplet->hidePopup(); + } + setStatus(Task::Passive); + break; + + case Plasma::ActiveStatus: + setStatus(Task::Active); + break; + + case Plasma::NeedsAttentionStatus: + setStatus(Task::NeedsAttention); + break; + + default: + case Plasma::UnknownStatus: + setStatus(Task::UnknownStatus); + } +} + +} + +#include "plasmoidtask.moc" diff --git a/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtask.h b/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtask.h new file mode 100644 index 00000000..1a1dec69 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtask.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * plasmoidtask.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * Copyright (C) 2008 Sebastian Kügler * + * Copyright (C) 2009 Marco Martin * + * * + * 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 PLASMOIDTASK_H +#define PLASMOIDTASK_H + +#include "../../core/task.h" + +#include + +namespace SystemTray +{ + + +class PlasmoidTask : public Task +{ + Q_OBJECT + +public: + PlasmoidTask(const QString &appletName, int id, QObject *parent, Plasma::Applet *host); + virtual ~PlasmoidTask(); + + bool isValid() const; + virtual bool isEmbeddable() const; + virtual QString taskId() const; + virtual QIcon icon() const; + void forwardConstraintsEvent(Plasma::Constraints constraints); + int id() const; + Plasma::Applet *host() const; + virtual bool isWidget() const; + virtual TaskType type() const { return TypePlasmoid; } + +protected Q_SLOTS: + void appletDestroyed(Plasma::Applet *object); + void newAppletStatus(Plasma::ItemStatus status); + +Q_SIGNALS: + void taskDeleted(Plasma::Applet *host, const QString &taskId); + +protected: + virtual QGraphicsWidget* createWidget(Plasma::Applet *applet); + +private: + void setupApplet(const QString &plugin, int id); + + QString m_appletName; + QString m_taskId; + QIcon m_icon; + QWeakPointer m_applet; + Plasma::Applet *m_host; + bool m_takenByParent; +}; + +} + +#endif diff --git a/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtaskprotocol.cpp b/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtaskprotocol.cpp new file mode 100644 index 00000000..29e3d721 --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtaskprotocol.cpp @@ -0,0 +1,159 @@ +/*************************************************************************** + * plasmoidprotocol.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * Copyright (C) 2008 Sebastian Kügler * + * Copyright (C) 2009 Marco Martin * + * * + * 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 "plasmoidtask.h" +#include "plasmoidtaskprotocol.h" + +#include + +#include + +namespace SystemTray +{ + +PlasmoidProtocol::PlasmoidProtocol(QObject *parent) + : Protocol(parent) +{ +} + + +PlasmoidProtocol::~PlasmoidProtocol() +{ +} + + +void PlasmoidProtocol::init() +{ +} + +void PlasmoidProtocol::forwardConstraintsEvent(Plasma::Constraints constraints, Plasma::Applet *host) +{ + if (m_tasks.contains(host)) { + QHash tasksForHost = m_tasks.value(host); + foreach (PlasmoidTask *task, tasksForHost) { + task->forwardConstraintsEvent(constraints); + } + } +} + +void PlasmoidProtocol::loadFromConfig(Plasma::Applet *parent) +{ + QHash existingTasks = m_tasks.value(parent); + QSet seenNames; + + KConfigGroup appletGroup = parent->config(); + appletGroup = KConfigGroup(&appletGroup, "Applets"); + + foreach (const QString &groupName, appletGroup.groupList()) { + const KConfigGroup childGroup(&appletGroup, groupName); + const QString appletName = childGroup.readEntry("plugin", QString()); + + existingTasks.remove(appletName); + addApplet(appletName, groupName.toInt(), parent); + } + + QHashIterator it(existingTasks); + while (it.hasNext()) { + it.next(); + Plasma::Applet *applet = qobject_cast(it.value()->widget(parent, true)); + if (applet) { + applet->destroy(); + } + } +} + +void PlasmoidProtocol::addApplet(const QString appletName, const int id, Plasma::Applet *parent) +{ + PlasmoidTask *task = m_tasks.value(parent).value(appletName); + if (task) { + // the host already has one of these applets ... but let's make sure that the id is the same + // if it isn't, we have a duplicate in the config file and it should be removed + if (task->id() != id) { + KConfigGroup appletGroup = parent->config(); + appletGroup = KConfigGroup(&appletGroup, "Applets"); + appletGroup = KConfigGroup(&appletGroup, QString::number(id)); + appletGroup.deleteGroup(); + } + + return; + } + + kDebug() << "Registering task with the manager" << appletName; + task = new PlasmoidTask(appletName, id, this, parent); + + if (!task->isValid()) { + // we failed to load our applet *sob* + delete task; + return; + } + + + m_tasks[parent].insert(appletName, task); + connect(task, SIGNAL(taskDeleted(Plasma::Applet*,QString)), this, SLOT(cleanupTask(Plasma::Applet*,QString))); + emit taskCreated(task); +} + +void PlasmoidProtocol::removeApplet(const QString appletName, Plasma::Applet *parent) +{ + if (!m_tasks.contains(parent) || !m_tasks.value(parent).contains(appletName)) { + return; + } + + Plasma::Applet *applet = qobject_cast(m_tasks.value(parent).value(appletName)->widget(parent, true)); + + if (applet) { + applet->destroy(); + } +} + +void PlasmoidProtocol::cleanupTask(Plasma::Applet *host, const QString &taskId) +{ + kDebug() << "task with taskId" << taskId << "removed"; + if (m_tasks.contains(host)) { + m_tasks[host].remove(taskId); + if (m_tasks.value(host).isEmpty()) { + m_tasks.remove(host); + } + } +} + +QStringList PlasmoidProtocol::applets(Plasma::Applet *host) const +{ + QStringList list; + if (!m_tasks.contains(host)) { + return list; + } + + QHashIterator i(m_tasks.value(host)); + + while (i.hasNext()) { + i.next(); + list << i.key(); + } + + return list; +} + +} + +#include "plasmoidtaskprotocol.moc" diff --git a/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtaskprotocol.h b/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtaskprotocol.h new file mode 100644 index 00000000..31aaca1c --- /dev/null +++ b/plasma/generic/applets/systemtray/protocols/plasmoid/plasmoidtaskprotocol.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * plasmoidprotocol.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * Copyright (C) 2008 Sebastian Kügler * + * Copyright (C) 2009 Marco Martin * + * * + * 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 PLASMOIDTASKPROTOCOL_H +#define PLASMOIDTASKPROTOCOL_H + +#include "../../core/protocol.h" + +#include + +#include +#include + +namespace SystemTray +{ + +class PlasmoidTask; + +class PlasmoidProtocol : public Protocol +{ + Q_OBJECT + +public: + PlasmoidProtocol(QObject * parent); + ~PlasmoidProtocol(); + + void init(); + + void forwardConstraintsEvent(Plasma::Constraints constraints, Plasma::Applet *host); + void loadFromConfig(Plasma::Applet *parent); + void addApplet(const QString appletName, const int id, Plasma::Applet *parent); + void removeApplet(const QString appletName, Plasma::Applet *parent); + QStringList applets(Plasma::Applet *parent) const; + +private slots: + void cleanupTask(Plasma::Applet *host, const QString &taskId); + +private: + QHash > m_tasks; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/ui/applet.cpp b/plasma/generic/applets/systemtray/ui/applet.cpp new file mode 100644 index 00000000..bb951077 --- /dev/null +++ b/plasma/generic/applets/systemtray/ui/applet.cpp @@ -0,0 +1,825 @@ +/*************************************************************************** + * applet.cpp * + * * + * Copyright (C) 2008 Jason Stubbs * + * Copyright (C) 2008 Sebastian Sauer * + * Copyright (C) 2010 Marco Martin * + * * + * 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 "applet.h" +#include "widgetitem.h" +#include "mouseredirectarea.h" + +#include "../protocols/dbussystemtray/dbussystemtraytask.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "config.h" + +#include "../core/manager.h" + +static const bool DEFAULT_SHOW_APPS = true; +static const bool DEFAULT_SHOW_COMMUNICATION = true; +static const bool DEFAULT_SHOW_SERVICES = true; +static const bool DEFAULT_SHOW_HARDWARE = true; +static const bool DEFAULT_SHOW_UNKNOWN = true; +static const char KlipperName[] = "Klipper"; + +namespace SystemTray +{ + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +namespace +{ + +static void _RegisterEnums(QDeclarativeContext *context, const QMetaObject &meta) +{ + for (int i = 0, s = meta.enumeratorCount(); i < s; ++i) { + QMetaEnum e = meta.enumerator(i); + for (int i = 0, s = e.keyCount(); i < s; ++i) { + context->setContextProperty(e.key(i), e.value(i)); + } + } +} + +} // namespace + + +K_EXPORT_PLASMA_APPLET(systemtray, Applet) + + +Manager *Applet::s_manager = 0; +int Applet::s_managerUsage = 0; + +Applet::Applet(QObject *parent, const QVariantList &arguments) + : Plasma::Applet(parent, arguments), + m_widget(0), + m_firstRun(true) +{ + if (!s_manager) { + s_manager = new SystemTray::Manager(); + } + + ++s_managerUsage; + + setAspectRatioMode(Plasma::IgnoreAspectRatio); + setHasConfigurationInterface(true); +} + +Applet::~Applet() +{ + // stop listening to the manager + disconnect(s_manager, 0, this, 0); + + foreach (Task *task, s_manager->tasks()) { + // we don't care about the task updates anymore + disconnect(task, 0, this, 0); + + // delete our widget (if any); some widgets (such as the extender info one) + // may rely on the applet being around, so we need to delete them here and now + // while we're still kicking + if (task->isWidget()) + delete task->widget(this, false); + } + + delete m_widget; + + --s_managerUsage; + if (s_managerUsage < 1) { + delete s_manager; + s_manager = 0; + s_managerUsage = 0; + } +} + +void Applet::init() +{ + // First of all, we have to register new QML types because they won't be registered later + qmlRegisterType("Private", 0, 1, "WidgetItem"); + qmlRegisterType("Private", 0, 1, "MouseRedirectArea"); + + // Find data directory + KStandardDirs std_dirs; + QStringList dirs = std_dirs.findDirs("data", SYSTEMTRAY_DATA_INSTALL_DIR); + QString data_path; + if (!dirs.isEmpty()) { + data_path = dirs.at(0); + } else { + setFailedToLaunch(true, "Data directory for applet isn't found"); + return; + } + + // Create declarative engine, etc + m_widget = new Plasma::DeclarativeWidget(this); + m_widget->setInitializationDelayed(true); + connect(m_widget, SIGNAL(finished()), this, SLOT(_onWidgetCreationFinished())); + m_widget->setQmlPath(data_path + QString::fromLatin1("contents/ui/main.qml")); + + if (!m_widget->engine() || !m_widget->engine()->rootContext() || !m_widget->engine()->rootContext()->isValid() + || m_widget->mainComponent()->isError()) { + QString reason; + foreach (QDeclarativeError error, m_widget->mainComponent()->errors()) { + reason += error.toString(); + } + setFailedToLaunch(true, reason); + return; + } + + // setup context add global object "plasmoid" + QDeclarativeContext *root_context = m_widget->engine()->rootContext(); + root_context->setContextProperty("plasmoid", this); + + // add enumerations manually to global context + _RegisterEnums(root_context, Task::staticMetaObject); + _RegisterEnums(root_context, SystemTray::Applet::staticMetaObject); + + // add declarative widget to our applet + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addItem(m_widget); +} + + +void Applet::_onAddedTask(Task *task) +{ + if (task->isWidget()) { + // If task is presented as a widget then we should check that widget + if (!task->isEmbeddable(this)) { + //was a widget created previously? kill it + QGraphicsWidget *widget = task->widget(this, false); + if (widget) { + task->abandon(this); + } + return; + } + + QGraphicsWidget *widget = task->widget(this); + if (!widget) { + return; + } + + //If the applet doesn't want to show FDO tasks, remove (not just hide) any of them + //if the dbus icon has a category that the applet doesn't want to show remove it + if (!m_shownCategories.contains(task->category()) && !qobject_cast(widget)) { + task->abandon(this); + return; + } + } else if (!m_shownCategories.contains(task->category())) { + return; + } + + // provide task to qml code + emit newTask(task); + + DBusSystemTrayTask *dbus_task = qobject_cast(task); + if (dbus_task && !dbus_task->objectName().isEmpty() && dbus_task->shortcut().isEmpty()) { + // try to set shortcut + bool is_klipper = false; + QString default_shortcut; + if (dbus_task->name() == KlipperName) { + // for klipper we have to read its default hotkey from its config + is_klipper = true; + QString file = KStandardDirs::locateLocal("config", "kglobalshortcutsrc"); + KConfig config(file); + KConfigGroup cg(&config, "klipper"); + QStringList shortcutTextList = cg.readEntry("show_klipper_popup", QStringList()); + + if (shortcutTextList.size() >= 2) { + default_shortcut = shortcutTextList.first(); + if (default_shortcut.isEmpty()) { + default_shortcut = shortcutTextList[1]; + } + } + if (default_shortcut.isEmpty()) { + default_shortcut = "Ctrl+Alt+V"; + } + } + + QString action_name = _getActionName(task); + KConfigGroup cg = config(); + KConfigGroup shortcutsConfig = KConfigGroup(&cg, "Shortcuts"); + QString shortcut = shortcutsConfig.readEntryUntranslated(action_name, default_shortcut); + dbus_task->setShortcut(shortcut); + + if (is_klipper && shortcut == default_shortcut) { + // we have to write klipper's hotkey to config + if (shortcut.isEmpty()) + shortcutsConfig.deleteEntry(action_name); + else + shortcutsConfig.writeEntry(action_name, shortcut); + } + } +} + + +void Applet::_onRemovedTask(Task *task) +{ + //remove task from QML code + emit deletedTask(task); +} + +void Applet::_onStatusChangedTask() +{ + foreach (Task *task, s_manager->tasks()) { + if (task->status() == Task::NeedsAttention) { + setStatus(Plasma::NeedsAttentionStatus); + return; + } + } + + setStatus(Plasma::PassiveStatus); +} + +void Applet::_onWidgetCreationFinished() +{ + // add already existing tasks + QList tasks = s_manager->tasks(); + foreach (Task *t, tasks) { + _onAddedTask(t); + } + + connect(s_manager, SIGNAL(taskAdded(SystemTray::Task*)), this, SLOT(_onAddedTask(SystemTray::Task*))); + connect(s_manager, SIGNAL(taskRemoved(SystemTray::Task*)), this, SLOT(_onRemovedTask(SystemTray::Task*))); + connect(s_manager, SIGNAL(taskStatusChanged()), this, SLOT(_onStatusChangedTask())); +} + + +bool Applet::isFirstRun() +{ + return m_firstRun; +} + + +void Applet::configChanged() +{ + KConfigGroup gcg = globalConfig(); + KConfigGroup cg = config(); + + m_hiddenTypes = QSet::fromList(cg.readEntry("hidden", QStringList())); + m_alwaysShownTypes = QSet::fromList(cg.readEntry("alwaysShown", QStringList())); + + m_shownCategories.clear(); + + if (cg.readEntry("ShowApplicationStatus", gcg.readEntry("ShowApplicationStatus", DEFAULT_SHOW_APPS))) { + m_shownCategories.insert(Task::ApplicationStatus); + } + + if (cg.readEntry("ShowCommunications", gcg.readEntry("ShowCommunications", DEFAULT_SHOW_COMMUNICATION))) { + m_shownCategories.insert(Task::Communications); + } + + if (cg.readEntry("ShowSystemServices", gcg.readEntry("ShowSystemServices", DEFAULT_SHOW_SERVICES))) { + m_shownCategories.insert(Task::SystemServices); + } + + if (cg.readEntry("ShowHardware", gcg.readEntry("ShowHardware", DEFAULT_SHOW_HARDWARE))) { + m_shownCategories.insert(Task::Hardware); + } + + if (cg.readEntry("ShowUnknown", gcg.readEntry("ShowUnknown", DEFAULT_SHOW_UNKNOWN))) { + m_shownCategories.insert(Task::UnknownCategory); + } + + s_manager->loadApplets(this); + + // notify QML code about new user's preferences + emit visibilityPreferenceChanged(); +} + + +QString Applet::_getActionName(Task *task) const { + if (task->objectName().isEmpty()) + return QString(""); + return task->objectName() + QString("-") + QString::number(this->id()); +} + +void Applet::constraintsEvent(Plasma::Constraints constraints) +{ + if (constraints & Plasma::FormFactorConstraint) { + emit formFactorChanged(); + } + + if (constraints & Plasma::LocationConstraint) { + emit locationChanged(); + } + + if (constraints & Plasma::ImmutableConstraint) { + if (m_visibleItemsInterface) { + bool visible = (immutability() == Plasma::UserImmutable); + m_visibleItemsUi.visibleItemsView->setEnabled(immutability() == Plasma::Mutable); + m_visibleItemsUi.unlockLabel->setVisible(visible); + m_visibleItemsUi.unlockButton->setVisible(visible); + } + } + + if (constraints & Plasma::StartupCompletedConstraint) { + QTimer::singleShot(0, this, SLOT(checkDefaultApplets())); + configChanged(); + } + + s_manager->forwardConstraintsEvent(constraints, this); +} + +SystemTray::Manager *Applet::manager() const +{ + return s_manager; +} + +QSet Applet::shownCategories() const +{ + return m_shownCategories; +} + + +void Applet::propogateSizeHintChange(Qt::SizeHint which) +{ + emit sizeHintChanged(which); +} + +void Applet::createConfigurationInterface(KConfigDialog *parent) +{ + if (!m_autoHideInterface) { + m_autoHideInterface = new QWidget(); + m_visibleItemsInterface = new QWidget(); + + m_autoHideUi.setupUi(m_autoHideInterface.data()); + m_autoHideUi.icons->header()->setResizeMode(QHeaderView::ResizeToContents); + + m_visibleItemsUi.setupUi(m_visibleItemsInterface.data()); + + QAction *unlockAction = 0; + if (containment() && containment()->corona()) { + unlockAction = containment()->corona()->action("lock widgets"); + } + + if (unlockAction) { + disconnect(m_visibleItemsUi.unlockButton, SIGNAL(clicked()), this, SLOT(unlockContainment())); + connect(m_visibleItemsUi.unlockButton, SIGNAL(clicked()), unlockAction, SLOT(trigger()), Qt::UniqueConnection); + } else { + disconnect(m_visibleItemsUi.unlockButton, SIGNAL(clicked()), unlockAction, SLOT(trigger())); + connect(m_visibleItemsUi.unlockButton, SIGNAL(clicked()), this, SLOT(unlockContainment()), Qt::UniqueConnection); + } + + + connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); + connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); + + parent->addPage(m_visibleItemsInterface.data(), i18n("Display"), + "preferences-desktop-notification", + i18n("Choose which information to show")); + parent->addPage(m_autoHideInterface.data(), i18n("Entries"), "configure-toolbars"); + + bool visible = (immutability() == Plasma::UserImmutable); + //FIXME: always showing the scrollbar is due to a bug somewhere in QAbstractScrollArea, + //QListView and/or KCategorizedView; without it, under certain circumstances it will + //go into an infinite loop. too many people are running into this problem, so we are + //working around the problem rather than waiting for an upstream fix, which is against + //our usual policy. + //to determine if this line is no longer needed in the future, comment it out, lock + //widgets, then call up the configuration dialog for a system tray applet and click + //on the "unlock widgets" button. + m_visibleItemsUi.unlockLabel->setVisible(visible); + m_visibleItemsUi.unlockButton->setVisible(visible); + + m_visibleItemsUi.visibleItemsView->setEnabled(immutability() == Plasma::Mutable); + m_visibleItemsUi.visibleItemsView->setCategoryDrawer(new KCategoryDrawerV3(m_visibleItemsUi.visibleItemsView)); + m_visibleItemsUi.visibleItemsView->setMouseTracking(true); + m_visibleItemsUi.visibleItemsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_visibleItemsUi.visibleItemsView->setVerticalScrollMode(QListView::ScrollPerPixel); + + KCategorizedSortFilterProxyModel *visibleItemsModel = new KCategorizedSortFilterProxyModel(m_visibleItemsUi.visibleItemsView); + visibleItemsModel->setCategorizedModel(true); + + m_visibleItemsSourceModel = new QStandardItemModel(m_visibleItemsUi.visibleItemsView); + visibleItemsModel->setSourceModel(m_visibleItemsSourceModel.data()); + m_visibleItemsUi.visibleItemsView->setModel(visibleItemsModel); + } + + QStandardItemModel *visibleItemsSourceModel = m_visibleItemsSourceModel.data(); + // the lifespan of m_visibleItemsSourceModel is tied to the config UI, so it + // should always exist at this point + Q_ASSERT(visibleItemsSourceModel); + visibleItemsSourceModel->clear(); + m_autoHideUi.icons->clear(); + + QMultiMap sortedTasks; + foreach (Task *task, s_manager->tasks()) { + if (!m_shownCategories.contains(task->category())) { + continue; + } + + if (task->isWidget() && !task->widget(this, false)) { + // it is not being used by this widget + continue; + } + + sortedTasks.insert(task->name(), task); + } + + KConfigGroup gcg = globalConfig(); + KConfigGroup cg = config(); + KConfigGroup shortcutsConfig = KConfigGroup(&cg, "Shortcuts"); + + foreach (Task *task, sortedTasks) { + QTreeWidgetItem *listItem = new QTreeWidgetItem(m_autoHideUi.icons); + KComboBox *itemCombo = new KComboBox(m_autoHideUi.icons); + listItem->setText(0, task->name()); + listItem->setIcon(0, task->icon()); + listItem->setFlags(Qt::ItemIsEnabled); + listItem->setData(0, Qt::UserRole, task->taskId()); + + itemCombo->addItem(i18nc("Item will be automatically shown or hidden from the systray", "Auto")); + itemCombo->addItem(i18nc("Item is never visible in the systray", "Hidden")); + itemCombo->addItem(i18nc("Item is always visible in the systray", "Always Visible")); + + if (m_hiddenTypes.contains(task->taskId())) { + itemCombo->setCurrentIndex(1); + } else if (m_alwaysShownTypes.contains(task->taskId())) { + itemCombo->setCurrentIndex(2); + } else { + itemCombo->setCurrentIndex(0); + } + m_autoHideUi.icons->setItemWidget(listItem, 1, itemCombo); + + KKeySequenceWidget *button = new KKeySequenceWidget(m_autoHideUi.icons); + + DBusSystemTrayTask *dbus_task = qobject_cast(task); + Plasma::Applet *applet = qobject_cast(task->widget(this)); + + if (task && dbus_task && !dbus_task->objectName().isEmpty()) { + QString action_name = _getActionName(task); + QString shortcutText = shortcutsConfig.readEntryUntranslated(action_name, QString()); + button->setKeySequence(shortcutText); + } else if (task && applet) { + button->setKeySequence(applet->globalShortcut().primary()); + //no way to have a shortcut for the fdo protocol + } else { + button->setEnabled(false); + } + m_autoHideUi.icons->setItemWidget(listItem, 2, button); + m_autoHideUi.icons->addTopLevelItem(listItem); + + // try to make sure we have enough width! + int totalWidth = 0; + for (int i = 0; i < m_autoHideUi.icons->header()->count(); ++i) { + totalWidth += m_autoHideUi.icons->columnWidth(i); + } + m_autoHideUi.icons->setMinimumWidth(totalWidth + style()->pixelMetric(QStyle::PM_ScrollBarExtent)); + + connect(itemCombo, SIGNAL(currentIndexChanged(int)), parent, SLOT(settingsModified())); + connect(button, SIGNAL(keySequenceChanged(QKeySequence)), parent, SLOT(settingsModified())); + } + + const QString itemCategories = i18nc("Categories of items in the systemtray that will be shown or hidden", "Shown Item Categories"); + + QStandardItem *applicationStatusItem = new QStandardItem(); + applicationStatusItem->setText(i18nc("Systemtray items that describe the status of a generic application", "Application status")); + applicationStatusItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + bool checked = cg.readEntry("ShowApplicationStatus", + gcg.readEntry("ShowApplicationStatus", DEFAULT_SHOW_APPS)); + applicationStatusItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked); + applicationStatusItem->setData(itemCategories, KCategorizedSortFilterProxyModel::CategoryDisplayRole); + applicationStatusItem->setData("ShowApplicationStatus", Qt::UserRole+1); + visibleItemsSourceModel->appendRow(applicationStatusItem); + + QStandardItem *communicationsItem = new QStandardItem(); + communicationsItem->setText(i18nc("Items communication related, such as chat or email clients", "Communications")); + communicationsItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + checked = cg.readEntry("ShowCommunications", + gcg.readEntry("ShowCommunications", DEFAULT_SHOW_COMMUNICATION)); + communicationsItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked); + communicationsItem->setData(itemCategories, KCategorizedSortFilterProxyModel::CategoryDisplayRole); + communicationsItem->setData("ShowCommunications", Qt::UserRole+1); + visibleItemsSourceModel->appendRow(communicationsItem); + + QStandardItem *systemServicesItem = new QStandardItem(); + systemServicesItem->setText(i18nc("Items about the status of the system, such as a filesystem indexer", "System services")); + systemServicesItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + checked = cg.readEntry("ShowSystemServices", + gcg.readEntry("ShowSystemServices", DEFAULT_SHOW_SERVICES)); + systemServicesItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked); + systemServicesItem->setData(itemCategories, KCategorizedSortFilterProxyModel::CategoryDisplayRole); + systemServicesItem->setData("ShowSystemServices", Qt::UserRole+1); + visibleItemsSourceModel->appendRow(systemServicesItem); + + QStandardItem *hardwareControlItem = new QStandardItem(); + hardwareControlItem->setText(i18nc("Items about hardware, such as battery or volume control", "Hardware control")); + hardwareControlItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + checked = cg.readEntry("ShowHardware", + gcg.readEntry("ShowHardware", DEFAULT_SHOW_HARDWARE)); + hardwareControlItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked); + hardwareControlItem->setData(itemCategories, KCategorizedSortFilterProxyModel::CategoryDisplayRole); + hardwareControlItem->setData("ShowHardware", Qt::UserRole+1); + visibleItemsSourceModel->appendRow(hardwareControlItem); + + QStandardItem *unknownItem = new QStandardItem(); + unknownItem->setText(i18nc("Other uncategorized systemtray items", "Miscellaneous")); + unknownItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + checked = cg.readEntry("ShowUnknown", + gcg.readEntry("ShowUnknown", DEFAULT_SHOW_UNKNOWN)); + unknownItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked); + unknownItem->setData(itemCategories, KCategorizedSortFilterProxyModel::CategoryDisplayRole); + unknownItem->setData("ShowUnknown", Qt::UserRole+1); + visibleItemsSourceModel->appendRow(unknownItem); + + QStringList ownApplets = s_manager->applets(this); + + QMap sortedApplets; + foreach (const KPluginInfo &info, Plasma::Applet::listAppletInfo()) { + KService::Ptr service = info.service(); + if (service->property("X-Plasma-NotificationArea", QVariant::Bool).toBool()) { + // if we already have a plugin with this exact name in it, then check if it is the + // same plugin and skip it if it is indeed already listed + if (sortedApplets.contains(info.name())) { + + bool dupe = false; + // it is possible (though poor form) to have multiple applets + // with the same visible name but different plugins, so we hve to check all values + foreach (const KPluginInfo &existingInfo, sortedApplets.values(info.name())) { + if (existingInfo.pluginName() == info.pluginName()) { + dupe = true; + break; + } + } + + if (dupe) { + continue; + } + } + + // insertMulti becase it is possible (though poor form) to have multiple applets + // with the same visible name but different plugins + sortedApplets.insertMulti(info.name(), info); + } + } + + foreach (const KPluginInfo &info, sortedApplets) { + QStandardItem *item = new QStandardItem(); + item->setText(info.name()); + item->setIcon(KIcon(info.icon())); + item->setCheckable(true); + item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + item->setCheckState(ownApplets.contains(info.pluginName()) ? Qt::Checked : Qt::Unchecked); + item->setData(i18nc("Extra items to be manually added in the systray, such as little Plasma widgets", "Extra Items"), KCategorizedSortFilterProxyModel::CategoryDisplayRole); + item->setData(info.pluginName(), Qt::UserRole+2); + visibleItemsSourceModel->appendRow(item); + } + + connect(visibleItemsSourceModel, SIGNAL(itemChanged(QStandardItem*)), parent, SLOT(settingsModified())); +} + +//not always the corona lock action is available: netbook locks per-containment +void Applet::unlockContainment() +{ + if (containment() && containment()->immutability() == Plasma::UserImmutable) { + containment()->setImmutability(Plasma::Mutable); + } +} + +void Applet::configAccepted() +{ + KConfigGroup cg = config(); + KConfigGroup shortcutsConfig = KConfigGroup(&cg, "Shortcuts"); + + QStringList hiddenTypes; + QStringList alwaysShownTypes; + QTreeWidget *hiddenList = m_autoHideUi.icons; + for (int i = 0; i < hiddenList->topLevelItemCount(); ++i) { + QTreeWidgetItem *item = hiddenList->topLevelItem(i); + KComboBox *itemCombo = static_cast(hiddenList->itemWidget(item, 1)); + //kDebug() << (item->checkState() == Qt::Checked) << item->data(Qt::UserRole).toString(); + const QString taskTypeId = item->data(0, Qt::UserRole).toString(); + if (itemCombo->currentIndex() == 1) { + //Always hidden + hiddenTypes << taskTypeId; + } else if (itemCombo->currentIndex() == 2) { + //Always visible + alwaysShownTypes << taskTypeId; + } + + KKeySequenceWidget *keySeq = static_cast(hiddenList->itemWidget(item, 2)); + QKeySequence seq = keySeq->keySequence(); + Task *task = 0; + //FIXME: terribly inefficient + foreach (Task *candidateTask, s_manager->tasks()) { + if (candidateTask->taskId() == taskTypeId) { + task = candidateTask; + break; + } + } + + if (task) { + if (!task->isWidget()) { + DBusSystemTrayTask *dbus_task = qobject_cast(task); + if (dbus_task) { + QString shortcut = seq.toString(); + dbus_task->setShortcut(shortcut); + QString action_name = _getActionName(task); + if (seq.isEmpty()) + shortcutsConfig.deleteEntry(action_name); + else + shortcutsConfig.writeEntry(action_name, shortcut); + dbus_task->setShortcut(shortcut); + } + } else { + Plasma::Applet *applet = qobject_cast( task->widget(this) ); + if (applet) { + applet->setGlobalShortcut(KShortcut(seq)); + } + } + } + } + + cg.writeEntry("hidden", hiddenTypes); + cg.writeEntry("alwaysShown", alwaysShownTypes); + + QStringList applets = s_manager->applets(this); + + for (int i = 0; i <= m_visibleItemsSourceModel.data()->rowCount() - 1; i++) { + QModelIndex index = m_visibleItemsSourceModel.data()->index(i, 0); + QString itemCategory = index.data(Qt::UserRole+1).toString(); + QString appletName = index.data(Qt::UserRole+2).toString(); + if (!itemCategory.isEmpty()) { + QStandardItem *item = m_visibleItemsSourceModel.data()->itemFromIndex(index); + cg.writeEntry(itemCategory, (item->checkState() == Qt::Checked)); + } else if (!appletName.isEmpty()){ + QStandardItem *item = m_visibleItemsSourceModel.data()->itemFromIndex(index); + + if (item->checkState() != Qt::Unchecked && !applets.contains(appletName)) { + s_manager->addApplet(appletName, this); + } + + if (item->checkState() == Qt::Checked) { + applets.removeAll(appletName); + } + } + } + + foreach (const QString &appletName, applets) { + s_manager->removeApplet(appletName, this); + } + + emit configNeedsSaving(); +} + +void Applet::checkDefaultApplets() +{ + if (config().readEntry("DefaultAppletsAdded", false)) { + m_firstRun = false; + return; + } + + + QStringList applets = s_manager->applets(this); + if (!applets.contains("org.kde.networkmanagement")) { + s_manager->addApplet("org.kde.networkmanagement", this); + } + + if (!applets.contains("notifier")) { + s_manager->addApplet("notifier", this); + } + + if (!applets.contains("org.kde.notifications")) { + s_manager->addApplet("org.kde.notifications", this); + } + + if (!applets.contains("battery")) { + Plasma::DataEngineManager *engines = Plasma::DataEngineManager::self(); + Plasma::DataEngine *power = engines->loadEngine("powermanagement"); + if (power) { + const QStringList &batteries = power->query("Battery")["Sources"].toStringList(); + if (!batteries.isEmpty()) { + s_manager->addApplet("battery", this); + } + } + engines->unloadEngine("powermanagement"); + } + + config().writeEntry("DefaultAppletsAdded", true); +} + + +int Applet::getVisibilityPreference(QObject *task) const +{ + Task *t = qobject_cast(task); + if (!t) + return AutoVisibility; + if ( m_hiddenTypes.contains(t->taskId()) ) { + return AlwaysHidden; + } else if ( m_alwaysShownTypes.contains(t->taskId()) ) { + return AlwaysShown; + } + return AutoVisibility; +} + +QAction *Applet::createShortcutAction(QString action_id) const +{ + KAction *action = new KAction(parent()); + action->setObjectName(action_id); + return action; +} + +void Applet::updateShortcutAction(QAction *action, QString shortcut) const +{ + KAction *act = qobject_cast(action); + if (!act) { + return; + } + + act->forgetGlobalShortcut(); + if (!shortcut.isEmpty()) { + act->setGlobalShortcut(KShortcut(QKeySequence(shortcut)), + KAction::ShortcutTypes(KAction::ActiveShortcut | KAction::DefaultShortcut), + KAction::NoAutoloading); + } +} + +void Applet::destroyShortcutAction(QAction *action) const +{ + KAction *act = qobject_cast(action); + if (act) { + delete act; + } +} + +void Applet::showMenu(QObject *menu_var, int x, int y, QObject *item_var) const +{ + QGraphicsItem *item = qobject_cast(item_var); + QMenu *menu = qobject_cast(menu_var); + if (menu) { + QPoint pos(x, y); + menu->adjustSize(); + if (item && containment() && containment()->corona()) { + pos = containment()->corona()->popupPosition(item, menu->size()); + } else { + pos = Plasma::Applet::popupPosition(menu->size()); + } + menu->popup(pos); + } +} + +void Applet::hideFromTaskbar(qulonglong win_id) const +{ + if (win_id > 0) { + KWindowSystem::setState(win_id, NET::SkipTaskbar | NET::SkipPager); + } +} + +QString Applet::getUniqueId(QObject *obj) const +{ + return QString::number(reinterpret_cast(obj)); +} + +QPoint Applet::popupPosition(QObject *item_var, QSize size, int align) const +{ + QGraphicsItem *item = qobject_cast(item_var); + if ( item && containment() && containment()->corona() ) { + return containment()->corona()->popupPosition(item, size, (Qt::AlignmentFlag)align); + } + return Plasma::Applet::popupPosition(size, (Qt::AlignmentFlag)align); +} + + +} + +#include "applet.moc" diff --git a/plasma/generic/applets/systemtray/ui/applet.h b/plasma/generic/applets/systemtray/ui/applet.h new file mode 100644 index 00000000..0b4a8697 --- /dev/null +++ b/plasma/generic/applets/systemtray/ui/applet.h @@ -0,0 +1,174 @@ +/*************************************************************************** + * applet.h * + * * + * Copyright (C) 2008 Jason Stubbs * + * Copyright (C) 2010 Marco Martin * + * Copyright (C) 2012 Dmitry Ashkadov * + * * + * 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 APPLET_H +#define APPLET_H + +#include + +#include "ui_autohide.h" +#include "ui_visibleitems.h" + +#include "../core/task.h" + +namespace Plasma +{ +class ExtenderItem; +class TabBar; +class Dialog; +class DeclarativeWidget; +} + +class QStandardItemModel; + +namespace SystemTray +{ + +class Manager; + +class Applet : public Plasma::Applet +{ + Q_OBJECT + + Q_ENUMS(FormFactor) + Q_ENUMS(Location) + Q_ENUMS(VisibilityPreference) + + Q_PROPERTY(bool firstRun READ isFirstRun) + + // TODO: remove these properties in the future (they will be supported in Plasma::Applet) + Q_PROPERTY(int formFactor READ formFactor NOTIFY formFactorChanged) + Q_PROPERTY(int location READ location NOTIFY locationChanged) + +public: + // Form factor + enum FormFactor + { + Planar = Plasma::Planar, + MediaCenter = Plasma::MediaCenter, + Horizontal = Plasma::Horizontal, + Vertical = Plasma::Vertical + }; + + // Location + enum Location + { + Floating = Plasma::Floating, + Desktop = Plasma::Desktop, + FullScreen = Plasma::FullScreen, + TopEdge = Plasma::TopEdge, + BottomEdge = Plasma::BottomEdge, + LeftEdge = Plasma::LeftEdge, + RightEdge = Plasma::RightEdge + }; + + /// User's preference of visibility of task + enum VisibilityPreference { + AutoVisibility = 0, + AlwaysHidden, + AlwaysShown + }; + + explicit Applet(QObject *parent, const QVariantList &arguments = QVariantList()); + ~Applet(); + + void init(); + void constraintsEvent(Plasma::Constraints constraints); + Manager *manager() const; + QSet shownCategories() const; + bool isFirstRun(); + + Q_INVOKABLE int getVisibilityPreference(QObject *task) const; + Q_INVOKABLE QAction* createShortcutAction(QString action_id) const; + Q_INVOKABLE void updateShortcutAction(QAction *action, QString shortcut) const; + Q_INVOKABLE void destroyShortcutAction(QAction *action) const; + Q_INVOKABLE void showMenu(QObject *menu, int x, int y, QObject *item) const; + Q_INVOKABLE void hideFromTaskbar(qulonglong win_id) const; + Q_INVOKABLE QString getUniqueId(QObject *obj) const; + Q_INVOKABLE QPoint popupPosition(QObject *item, QSize size = QSize(0, 0), int align = Qt::AlignLeft) const; + +protected: + void createConfigurationInterface(KConfigDialog *parent); + void configChanged(); + + void mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_UNUSED(event); } + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_UNUSED(event); } + void hoverEnterEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event); } + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event); } + +signals: + void formFactorChanged(); + void locationChanged(); + void visibilityPreferenceChanged(); ///< If user has changed his preference on visibility of tasks + + /** + * This signal is emmited for each new task + * @param task a new task + */ + void newTask(QObject *task); + + /** + * This signal is emmited before task is deleted + * @param task a task that is being deleted + */ + void deletedTask(QObject *task); + +private Q_SLOTS: + void configAccepted(); + void unlockContainment(); + void propogateSizeHintChange(Qt::SizeHint which); + void checkDefaultApplets(); + + void _onAddedTask(SystemTray::Task*); + void _onRemovedTask(SystemTray::Task*); + void _onStatusChangedTask(); + + void _onWidgetCreationFinished(); + +private: + QString _getActionName(Task *task) const; + +private: + static SystemTray::Manager *s_manager; + static int s_managerUsage; + + QWeakPointer m_autoHideInterface; + QWeakPointer m_visibleItemsInterface; + QSet m_shownCategories; + QSet m_hiddenTypes; + QSet m_alwaysShownTypes; + QDateTime m_lastActivity; + Plasma::DeclarativeWidget *m_widget; + + Ui::AutoHideConfig m_autoHideUi; + Ui::VisibleItemsConfig m_visibleItemsUi; + + QWeakPointer m_visibleItemsSourceModel; + + bool m_firstRun; +}; + +} + + +#endif diff --git a/plasma/generic/applets/systemtray/ui/autohide.ui b/plasma/generic/applets/systemtray/ui/autohide.ui new file mode 100644 index 00000000..3b6efffa --- /dev/null +++ b/plasma/generic/applets/systemtray/ui/autohide.ui @@ -0,0 +1,58 @@ + + + AutoHideConfig + + + + 0 + 0 + 422 + 253 + + + + + 0 + + + + + false + + + 3 + + + true + + + 100 + + + 100 + + + true + + + + Item + + + + + Visibility + + + + + Keyboard Shortcut + + + + + + + + + diff --git a/plasma/generic/applets/systemtray/ui/mouseredirectarea.cpp b/plasma/generic/applets/systemtray/ui/mouseredirectarea.cpp new file mode 100644 index 00000000..753ece9a --- /dev/null +++ b/plasma/generic/applets/systemtray/ui/mouseredirectarea.cpp @@ -0,0 +1,185 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: GPLv2+ + * Authors: Dmitry Ashkadov + * + * 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 . + **********************************************************************************************************************/ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Includes +#include "mouseredirectarea.h" + +#include "../core/task.h" + +#include +#include +#include +#include +#include + +#include + + +namespace SystemTray +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class MouseRedirectArea +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template void MouseRedirectArea::forwardEvent(T *event, bool is_context_menu) +{ + if (!isEnabled() || !(m_task || m_widget) || !m_applet) + return; + QGraphicsObject *target = m_widget ? m_widget : (m_task ? m_task->widget(m_applet, false) : 0); + if (!target) + return; + + QPointF delta = target->sceneBoundingRect().center() - event->scenePos(); + event->setScenePos(target->sceneBoundingRect().center()); + event->setScreenPos((event->screenPos() + delta).toPoint()); + + if (m_isApplet) { + if (is_context_menu && m_applet->containment()) { + // redirect context menu event to containment because it is responsible for items of context menu of an applet + event->setPos(m_applet->containment()->mapFromScene(event->scenePos())); + scene()->sendEvent(m_applet->containment(), event); + } else { + event->setPos(scene()->itemAt(event->scenePos())->mapFromScene(event->scenePos())); + scene()->sendEvent(scene()->itemAt(event->scenePos()), event); + } + } else { + event->setPos(target->boundingRect().center()); + scene()->sendEvent(target, event); + } +} + + +MouseRedirectArea::MouseRedirectArea(QDeclarativeItem *parent) + : QDeclarativeItem(parent) + , m_widget(0) + , m_task(0) + , m_target(0) + , m_applet(0) + , m_isApplet(false) +{ + setAcceptHoverEvents(true); + setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton | Qt::MiddleButton); +} + +void MouseRedirectArea::setTarget(QObject *t) +{ + if (m_target != t) { + m_target = t; + processTarget(); + } +} + +void MouseRedirectArea::setApplet(QObject *a) +{ + Plasma::Applet *applet = qobject_cast(a); + if (m_applet != applet) { + m_applet = applet; + processTarget(); // it may be that target already set so we should process it + } +} + + +void MouseRedirectArea::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + if (!m_isApplet && m_widget) { + switch (event->orientation()) { + case Qt::Vertical: + emit scrollVert(event->delta()); + break; + case Qt::Horizontal: + emit scrollHorz(event->delta()); + break; + default: + break; + } + return; + } + forwardEvent(event); +} + + +void MouseRedirectArea::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) +{ + forwardEvent(event, true); +} + + +void MouseRedirectArea::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (!m_isApplet && m_widget) { + switch (event->button()) { + case Qt::MiddleButton: emit clickMiddle(); return; + case Qt::RightButton: emit clickRight(); return; + default: break; + } + } + forwardEvent(event); +} + + +void MouseRedirectArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + forwardEvent(event); +} + +void MouseRedirectArea::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + forwardEvent(event); + emit entered(); +} + + +void MouseRedirectArea::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + forwardEvent(event); + emit exited(); +} + +void MouseRedirectArea::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + QPointF pos = event->pos(); + emit changedMousePos(pos.x(), pos.y()); + forwardEvent(event); +} + +void MouseRedirectArea::processTarget() +{ + // we have target as QObject but it may be Task or Widget + if (!m_applet || !m_target) + return; // applet and target must be already set + + m_isApplet = false; + m_widget = 0; + m_task = 0; + m_task = qobject_cast(m_target); + if (m_task) { + QGraphicsWidget *widget = m_task->widget(m_applet); + m_isApplet = (qobject_cast(widget) != 0); + } else { + m_widget = qobject_cast(m_target); + } +} + + +} // namespace SystemTray diff --git a/plasma/generic/applets/systemtray/ui/mouseredirectarea.h b/plasma/generic/applets/systemtray/ui/mouseredirectarea.h new file mode 100644 index 00000000..15d114af --- /dev/null +++ b/plasma/generic/applets/systemtray/ui/mouseredirectarea.h @@ -0,0 +1,97 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: GPLv2+ + * Authors: Dmitry Ashkadov + * + * 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 __SYSTEMTRAY__MOUSEREDIRECTAREA_H +#define __SYSTEMTRAY__MOUSEREDIRECTAREA_H + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Includes +#include + +#include + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Forward declarations +class QGraphicsWidget; +class QGraphicsSceneWheelEvent; +class QGraphicsSceneContextMenuEvent; + + +namespace SystemTray +{ +class Task; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** @class MouseRedirectArea + * This helper class is intended to handle and redirect some mouse events + */ +class MouseRedirectArea: public QDeclarativeItem +{ + Q_OBJECT + + Q_PROPERTY(QObject* target READ target WRITE setTarget) + Q_PROPERTY(QObject* applet READ applet WRITE setApplet) +public: + explicit MouseRedirectArea(QDeclarativeItem *parent = 0); + + QObject* target() const { return m_target; } + void setTarget(QObject* t); + QObject *applet() const { return m_applet; } + void setApplet(QObject *applet); + +signals: + void clickMiddle(); + void clickRight(); + void scrollVert(int delta); + void scrollHorz(int delta); + void changedMousePos(qreal mouseX, qreal mouseY); + void entered(); + void exited(); + +private: //Events + virtual void wheelEvent(QGraphicsSceneWheelEvent *event); + virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + + template void forwardEvent(T *event, bool is_context_menu = false); + +private: // Methods + void processTarget(); + +private: //Variables + QGraphicsObject *m_widget; + Task *m_task; + QObject *m_target; + Plasma::Applet *m_applet; + bool m_isApplet; // true if target is an applet +}; + +} // namespace SystemTray + +#endif // __SYSTEMTRAY__MOUSEREDIRECTAREA_H diff --git a/plasma/generic/applets/systemtray/ui/visibleitems.ui b/plasma/generic/applets/systemtray/ui/visibleitems.ui new file mode 100644 index 00000000..dc747680 --- /dev/null +++ b/plasma/generic/applets/systemtray/ui/visibleitems.ui @@ -0,0 +1,87 @@ + + + VisibleItemsConfig + + + + 0 + 0 + 380 + 360 + + + + + 0 + 360 + + + + + 0 + + + + + Widgets are currently locked, disabling some options. + + + Qt::AlignCenter + + + true + + + + + + + + + Qt::Horizontal + + + + 34 + 24 + + + + + + + + Unlock Widgets + + + + + + + Qt::Horizontal + + + + 34 + 24 + + + + + + + + + + + + + + KCategorizedView + QListView +
kcategorizedview.h
+
+
+ + +
diff --git a/plasma/generic/applets/systemtray/ui/widgetitem.cpp b/plasma/generic/applets/systemtray/ui/widgetitem.cpp new file mode 100644 index 00000000..0756be96 --- /dev/null +++ b/plasma/generic/applets/systemtray/ui/widgetitem.cpp @@ -0,0 +1,138 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: GPLv2+ + * Authors: Dmitry Ashkadov + * + * 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 . + **********************************************************************************************************************/ + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Includes +#include "widgetitem.h" + +#include "../core/task.h" + +#include +#include + +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +namespace SystemTray +{ +// class WidgetItem +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +WidgetItem::WidgetItem(QDeclarativeItem *parent) + : QDeclarativeItem(parent), + m_applet(0) +{ + setClip(false); + connect(this, SIGNAL(widthChanged()), this, SLOT(afterWidthChanged()), Qt::QueuedConnection); + connect(this, SIGNAL(heightChanged()), this, SLOT(afterHeightChanged()), Qt::QueuedConnection); +} + + +WidgetItem::~WidgetItem() +{ + unbind(); +} + +void WidgetItem::setTask(QObject *task) +{ + Task *t = qobject_cast(task); + if (m_task.data() == t) + return; + unbind(); + m_task = t; + bind(); + emit changedTask(); +} + +void WidgetItem::setApplet(QObject *a) +{ + Plasma::Applet *applet = qobject_cast(a); + if (m_applet == applet) + return; + unbind(); + m_applet = applet; + bind(); +} + +void WidgetItem::unbind() +{ + if (m_applet && m_task) { + QGraphicsWidget *widget = m_task.data()->widget(m_applet, false); + if (widget && widget->parentItem() == this) { + widget->hide(); + widget->setParentItem(0); + } + } +} + +void WidgetItem::bind() +{ + if (m_applet && m_task) { + QGraphicsWidget *widget = m_task.data()->widget(m_applet); + if (widget) { + widget->setParentItem(this); + widget->setPos(0, 0); + widget->setPreferredSize(width(), width()); + widget->setMinimumSize(width(), width()); + widget->setMaximumSize(width(), width()); + widget->show(); + } + } +} + + +void WidgetItem::afterWidthChanged() +{ + if (!m_applet || !m_task) { + return; + } + + QGraphicsWidget *widget = m_task.data()->widget(m_applet); + if (widget) { + widget->setPreferredSize(width(), width()); + widget->setMinimumSize(width(), width()); + widget->setMaximumSize(width(), width()); + widget->show(); + } +} + +void WidgetItem::afterHeightChanged() +{ + if (!m_applet || !m_task) { + return; + } + + QGraphicsWidget *widget = m_task.data()->widget(m_applet); + if (widget) { + widget->setPreferredSize(width(), width()); + widget->setMinimumSize(width(), width()); + widget->setMaximumSize(width(), width()); + widget->show(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +} //namespace SystemTray + diff --git a/plasma/generic/applets/systemtray/ui/widgetitem.h b/plasma/generic/applets/systemtray/ui/widgetitem.h new file mode 100644 index 00000000..112b9b32 --- /dev/null +++ b/plasma/generic/applets/systemtray/ui/widgetitem.h @@ -0,0 +1,81 @@ +/*********************************************************************************************************************** + * KDE System Tray (Plasmoid) + * + * Copyright (C) 2012 ROSA + * License: GPLv2+ + * Authors: Dmitry Ashkadov + * + * 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 __SYSTEMTRAY__WIDGETITEM_H +#define __SYSTEMTRAY__WIDGETITEM_H + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Includess +#include "../core/task.h" + +#include + +#include + +namespace SystemTray +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// class WidgetItem +/** @class WidgetItem + * Represents declarative item containing an specified graphics widget. + */ +class WidgetItem: public QDeclarativeItem +{ + Q_OBJECT + + Q_PROPERTY(QObject* applet READ applet WRITE setApplet) ///< host applet + Q_PROPERTY(QObject* task READ task WRITE setTask NOTIFY changedTask) ///< task +public: + explicit WidgetItem(QDeclarativeItem *parent = 0); + virtual ~WidgetItem(); + +public: + QObject *task() const { return m_task.data(); } + void setTask(QObject *task); + + /** + * @return applet as a host for widget + */ + QObject *applet() const { return m_applet; } + void setApplet(QObject *applet); + +signals: + void changedTask(); + +private Q_SLOTS: + void afterWidthChanged(); + void afterHeightChanged(); + +private: + void bind(); + void unbind(); + + Plasma::Applet *m_applet; + QWeakPointer m_task; +}; + +} //namespace SystemTray + +#endif // __SYSTEMTRAY__WIDGETITEM_H diff --git a/plasma/generic/applets/webbrowser/CMakeLists.txt b/plasma/generic/applets/webbrowser/CMakeLists.txt new file mode 100644 index 00000000..8861595e --- /dev/null +++ b/plasma/generic/applets/webbrowser/CMakeLists.txt @@ -0,0 +1,19 @@ +project(webbrowser) + +set(webbrowser_SRCS + bookmarksdelegate.cpp + bookmarkitem.cpp + webbrowser.cpp + webviewoverlay.cpp + browserhistorycombobox.cpp + browsermessagebox.cpp + errorpage.cpp + webbrowserpage.cpp + ) + +kde4_add_ui_files(webbrowser_SRCS webbrowserconfig.ui ) +kde4_add_plugin(plasma_applet_webbrowser ${webbrowser_SRCS}) +target_link_libraries(plasma_applet_webbrowser ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS} ${QT_QTWEBKIT_LIBRARY} ${KDE4_KDEWEBKIT_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KPARTS_LIBS}) + +install(TARGETS plasma_applet_webbrowser DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-applet-webbrowser.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/applets/webbrowser/Messages.sh b/plasma/generic/applets/webbrowser/Messages.sh new file mode 100755 index 00000000..f2af74d8 --- /dev/null +++ b/plasma/generic/applets/webbrowser/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma_applet_webbrowser.pot +rm -f rc.cpp diff --git a/plasma/generic/applets/webbrowser/bookmarkitem.cpp b/plasma/generic/applets/webbrowser/bookmarkitem.cpp new file mode 100644 index 00000000..b6735ede --- /dev/null +++ b/plasma/generic/applets/webbrowser/bookmarkitem.cpp @@ -0,0 +1,70 @@ +/* Copyright (C) 2008 Marco Martin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bookmarkitem.h" + + +#include +#include +#include + +BookmarkItem::BookmarkItem(KBookmark &bookmark) + : QStandardItem(), + m_bookmark(bookmark) +{ +} + +BookmarkItem::~BookmarkItem() +{ +} + + + +KBookmark BookmarkItem::bookmark() const +{ + return m_bookmark; +} + +void BookmarkItem::setBookmark(const KBookmark &bookmark) +{ + m_bookmark = bookmark; +} + +QVariant BookmarkItem::data(int role) const +{ + if (m_bookmark.isNull()) { + return QStandardItem::data(role); + } + + switch (role) + { + case Qt::DisplayRole: + return m_bookmark.text(); + case Qt::DecorationRole: + if (m_bookmark.isGroup() && m_bookmark.icon().isNull()) { + return KIcon("folder-bookmarks"); + } else { + return KIcon(m_bookmark.icon()); + } + case UrlRole: + return m_bookmark.url().prettyUrl(); + default: + return QStandardItem::data(role); + } +} + diff --git a/plasma/generic/applets/webbrowser/bookmarkitem.h b/plasma/generic/applets/webbrowser/bookmarkitem.h new file mode 100644 index 00000000..c0a950a0 --- /dev/null +++ b/plasma/generic/applets/webbrowser/bookmarkitem.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2008 Marco Martin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BOOKMARKITEM_H +#define BOOKMARKITEM_H + + +#include +#include +#include + + +class BookmarkItem : public QStandardItem +{ + +public: + enum BookmarkRoles + { + UrlRole = Qt::UserRole+1 + }; + + BookmarkItem(KBookmark &bookmark); + ~BookmarkItem(); + + KBookmark bookmark() const; + void setBookmark(const KBookmark &bookmark); + QVariant data(int role) const; + + +private: + KBookmark m_bookmark; +}; + +#endif diff --git a/plasma/generic/applets/webbrowser/bookmarksdelegate.cpp b/plasma/generic/applets/webbrowser/bookmarksdelegate.cpp new file mode 100644 index 00000000..d5cab3a8 --- /dev/null +++ b/plasma/generic/applets/webbrowser/bookmarksdelegate.cpp @@ -0,0 +1,103 @@ +/* + Copyright 2008 Marco Martin + + 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. +*/ + +// Own +#include "bookmarksdelegate.h" + +#include +#include + +// Qt +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include + +// plasma +#include +#include + + +class BookmarksDelegatePrivate +{ +public: + BookmarksDelegatePrivate() { + } + + ~BookmarksDelegatePrivate() { + } +}; + + + + +BookmarksDelegate::BookmarksDelegate(QObject *parent) + : QStyledItemDelegate(parent), + d(/*new BookmarksDelegatePrivate*/0) +{ +} + +BookmarksDelegate::~BookmarksDelegate() +{ + delete d; +} + +void BookmarksDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QStyledItemDelegate::paint(painter, option, index); + + if (option.state & (QStyle::State_MouseOver | QStyle::State_Selected)) { + QRect destroyIconRect = QStyle::alignedRect(option.direction, + option.decorationPosition == QStyleOptionViewItem::Left ? + Qt::AlignRight : Qt::AlignLeft, + QSize(option.rect.height(), option.rect.height()), + option.rect); + painter->drawPixmap(destroyIconRect, KIcon("list-remove").pixmap(KIconLoader::SizeSmall, KIconLoader::SizeSmall)); + } +} + +bool BookmarksDelegate::editorEvent(QEvent *event, + QAbstractItemModel *model, + const QStyleOptionViewItem &option, + const QModelIndex &index) +{ + QRect destroyIconRect = QStyle::alignedRect(option.direction, + option.decorationPosition == QStyleOptionViewItem::Left ? + Qt::AlignRight : Qt::AlignLeft, + QSize(option.rect.height(), option.rect.height()), + option.rect); + + if (event->type() == QEvent::MouseButtonPress) { + QMouseEvent *mouseEvent = static_cast(event); + + if (destroyIconRect.contains(mouseEvent->pos())) { + emit destroyBookmark(index); + return true; + } + } + + return QStyledItemDelegate::editorEvent(event, model, option, index); +} + diff --git a/plasma/generic/applets/webbrowser/bookmarksdelegate.h b/plasma/generic/applets/webbrowser/bookmarksdelegate.h new file mode 100644 index 00000000..1706aef8 --- /dev/null +++ b/plasma/generic/applets/webbrowser/bookmarksdelegate.h @@ -0,0 +1,55 @@ +/* + Copyright 2008 Marco Martin + + 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 BOOKMARKSDELEGATE_H +#define BOOKMARKSDELEGATE_H + +// Qt +#include + + +class BookmarksDelegatePrivate; + +class BookmarksDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + + + BookmarksDelegate(QObject *parent = 0); + ~BookmarksDelegate(); + + //Reimplemented + virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + + + protected: + bool editorEvent(QEvent *event, + QAbstractItemModel *model, + const QStyleOptionViewItem &option, + const QModelIndex &index); + +Q_SIGNALS: + void destroyBookmark(const QModelIndex &index); + +private: + BookmarksDelegatePrivate * const d; +}; + +#endif // BOOKMARKSDELEGATE_H diff --git a/plasma/generic/applets/webbrowser/browserhistorycombobox.cpp b/plasma/generic/applets/webbrowser/browserhistorycombobox.cpp new file mode 100644 index 00000000..73b199c0 --- /dev/null +++ b/plasma/generic/applets/webbrowser/browserhistorycombobox.cpp @@ -0,0 +1,446 @@ +/* + * Copyright 2008 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "browserhistorycombobox.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace Plasma +{ + +class ComboBoxPrivate +{ +public: + ComboBoxPrivate(BrowserHistoryComboBox *comboBox) + : q(comboBox), + background(0), + customFont(false), + underMouse(false) + { + } + + ~ComboBoxPrivate() + { + } + + void syncActiveRect(); + void syncBorders(); + void animationUpdate(qreal progress); + + BrowserHistoryComboBox *q; + + FrameSvg *background; + FrameSvg *lineEditBackground; + int animId; + QPropertyAnimation *animation; + qreal opacity; + QRectF activeRect; + QStyle *style; + bool customFont; + bool underMouse; + Plasma::ComboBox *styleParent; + int progressValue; + bool displayProgress; +}; + +void ComboBoxPrivate::syncActiveRect() +{ + background->setElementPrefix("normal"); + + qreal left, top, right, bottom; + background->getMargins(left, top, right, bottom); + + background->setElementPrefix("active"); + qreal activeLeft, activeTop, activeRight, activeBottom; + background->getMargins(activeLeft, activeTop, activeRight, activeBottom); + + activeRect = QRectF(QPointF(0, 0), q->size()); + activeRect.adjust(left - activeLeft, top - activeTop, + -(right - activeRight), -(bottom - activeBottom)); + + background->setElementPrefix("normal"); +} + +void ComboBoxPrivate::syncBorders() +{ + //set margins from the normal element + qreal left, top, right, bottom; + + background->setElementPrefix("normal"); + background->getMargins(left, top, right, bottom); + q->setContentsMargins(left, top, right, bottom); + + //calc the rect for the over effect + syncActiveRect(); + + KComboBox *native = q->nativeWidget(); + if (customFont) { + native->setFont(q->font()); + } else { + native->setFont(Theme::defaultTheme()->font(Theme::DefaultFont)); + } +} + +void ComboBoxPrivate::animationUpdate(qreal progress) +{ + opacity = progress; + + // explicit update + q->update(); +} + +BrowserHistoryComboBox::BrowserHistoryComboBox(QGraphicsWidget *parent) + : QGraphicsProxyWidget(parent), + d(new ComboBoxPrivate(this)) +{ + d->background = new FrameSvg(this); + d->background->setImagePath("widgets/button"); + d->background->setCacheAllRenderedFrames(true); + d->background->setElementPrefix("normal"); + d->lineEditBackground = new FrameSvg(this); + d->lineEditBackground->setImagePath("widgets/lineedit"); + d->lineEditBackground->setCacheAllRenderedFrames(true); + setZValue(900); + + setAcceptHoverEvents(true); + + d->styleParent = new Plasma::ComboBox(); + d->style = d->styleParent->nativeWidget()->style(); + + setNativeWidget(new KComboBox); + + d->animation = new QPropertyAnimation(this, "animationUpdate", this); + d->animation->setStartValue(0); + d->animation->setEndValue(1); + + connect(Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(syncBorders())); + + d->displayProgress = false; + d->progressValue = 0; +} + +BrowserHistoryComboBox::~BrowserHistoryComboBox() +{ + delete d->styleParent; + delete d; +} + +QString BrowserHistoryComboBox::text() const +{ + return static_cast(widget())->currentText(); +} + +void BrowserHistoryComboBox::setStyleSheet(const QString &stylesheet) +{ + widget()->setStyleSheet(stylesheet); +} + +QString BrowserHistoryComboBox::styleSheet() +{ + return widget()->styleSheet(); +} + +void BrowserHistoryComboBox::setNativeWidget(KComboBox *nativeWidget) +{ + if (widget()) { + widget()->deleteLater(); + } + + connect(nativeWidget, SIGNAL(activated(QString)), this, SIGNAL(activated(QString))); + connect(nativeWidget, SIGNAL(currentIndexChanged(QString)), + this, SIGNAL(textChanged(QString))); + + setWidget(nativeWidget); + + nativeWidget->setAttribute(Qt::WA_NoSystemBackground); + nativeWidget->setStyle(d->style); + + d->syncBorders(); +} + +KComboBox *BrowserHistoryComboBox::nativeWidget() const +{ + return static_cast(widget()); +} + +void BrowserHistoryComboBox::addItem(const QString &text) +{ + static_cast(widget())->addItem(text); +} + +void BrowserHistoryComboBox::clear() +{ + static_cast(widget())->clear(); +} + +void BrowserHistoryComboBox::resizeEvent(QGraphicsSceneResizeEvent *event) +{ + if (d->background) { + //resize needed panels + d->syncActiveRect(); + + d->background->setElementPrefix("focus"); + d->background->resizeFrame(size()); + + d->background->setElementPrefix("active"); + d->background->resizeFrame(d->activeRect.size()); + + d->background->setElementPrefix("normal"); + d->background->resizeFrame(size()); + } + + QGraphicsProxyWidget::resizeEvent(event); +} + +void BrowserHistoryComboBox::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + QAbstractAnimation::State animState = d->animation->state(); + + if (!styleSheet().isNull() || + Theme::defaultTheme()->useNativeWidgetStyle()) { + QGraphicsProxyWidget::paint(painter, option, widget); + return; + } + + if (nativeWidget()->isEditable()) { + if (d->displayProgress) { + painter->fillRect(QRectF(option->rect.x() + 2, option->rect.y() + 3, (int) (((qreal) (option->rect.width() - 4) / 100) * d->progressValue), option->rect.height() - 4), Theme::defaultTheme()->color(Theme::LinkColor)); + } + if (d->lineEditBackground->hasElement("hint-focus-over-base")) { + QGraphicsProxyWidget::paint(painter, option, widget); + } + if (animState != QAbstractAnimation::Stopped || hasFocus() || d->underMouse) { + if (hasFocus()) { + d->lineEditBackground->setElementPrefix("focus"); + } else { + d->lineEditBackground->setElementPrefix("hover"); + } + qreal left, top, right, bottom; + d->lineEditBackground->getMargins(left, top, right, bottom); + d->lineEditBackground->resizeFrame(size()+QSizeF(left+right, top+bottom)); + if (qFuzzyCompare(d->opacity, (qreal)1.0)) { + d->lineEditBackground->paintFrame(painter, QPoint(-left, -top)); + } else { + QPixmap bufferPixmap = d->lineEditBackground->framePixmap(); + QPainter buffPainter(&bufferPixmap); + buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + buffPainter.fillRect(bufferPixmap.rect(), QColor(0, 0, 0, 256*d->opacity)); + buffPainter.end(); + painter->drawPixmap(bufferPixmap.rect().translated(QPoint(-left, -top)), bufferPixmap, bufferPixmap.rect()); + } + } + if (!d->lineEditBackground->hasElement("hint-focus-over-base")) { + QGraphicsProxyWidget::paint(painter, option, widget); + } + return; + } + + QPixmap bufferPixmap; + + //normal button + if (isEnabled()) { + d->background->setElementPrefix("normal"); + + if (animState == QAbstractAnimation::Stopped) { + d->background->paintFrame(painter); + } + //disabled widget + } else { + bufferPixmap = QPixmap(rect().size().toSize()); + bufferPixmap.fill(Qt::transparent); + + QPainter buffPainter(&bufferPixmap); + d->background->paintFrame(&buffPainter); + buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + buffPainter.fillRect(bufferPixmap.rect(), QColor(0, 0, 0, 128)); + + painter->drawPixmap(0, 0, bufferPixmap); + } + + //if is under mouse draw the animated glow overlay + if (isEnabled() && acceptHoverEvents()) { + if (animState!= QAbstractAnimation::Stopped) { + d->background->setElementPrefix("normal"); + QPixmap normalPix = d->background->framePixmap(); + d->background->setElementPrefix("active"); + painter->drawPixmap( + d->activeRect.topLeft(), + PaintUtils::transition(d->background->framePixmap(), normalPix, 1 - d->opacity)); + } else if (isUnderMouse()) { + d->background->setElementPrefix("active"); + d->background->paintFrame(painter, d->activeRect.topLeft()); + } + } + + if (nativeWidget()->hasFocus()) { + d->background->setElementPrefix("focus"); + d->background->paintFrame(painter); + } + + painter->setPen(Theme::defaultTheme()->color(Theme::ButtonTextColor)); + + QStyleOptionComboBox comboOpt; + + comboOpt.initFrom(nativeWidget()); + + comboOpt.palette.setColor( + QPalette::ButtonText, Theme::defaultTheme()->color(Theme::ButtonTextColor)); + comboOpt.currentIcon = nativeWidget()->itemIcon( + nativeWidget()->currentIndex()); + comboOpt.currentText = nativeWidget()->itemText( + nativeWidget()->currentIndex()); + comboOpt.editable = false; + + nativeWidget()->style()->drawControl( + QStyle::CE_ComboBoxLabel, &comboOpt, painter, nativeWidget()); + comboOpt.rect = nativeWidget()->style()->subControlRect( + QStyle::CC_ComboBox, &comboOpt, QStyle::SC_ComboBoxArrow, nativeWidget()); + nativeWidget()->style()->drawPrimitive( + QStyle::PE_IndicatorArrowDown, &comboOpt, painter, nativeWidget()); +} + +void BrowserHistoryComboBox::setAnimationUpdate(qreal progress) +{ + d->animationUpdate(progress); +} + +qreal BrowserHistoryComboBox::animationUpdate() const +{ + return d->opacity; +} + +void BrowserHistoryComboBox::focusInEvent(QFocusEvent *event) +{ + if (nativeWidget()->isEditable() && !d->underMouse) { + const int FadeInDuration = 75; + + if (d->animation->state() != QAbstractAnimation::Stopped) { + d->animation->stop(); + } + d->animation->setDuration(FadeInDuration); + d->animation->setDirection(QAbstractAnimation::Forward); + d->animation->start(); + } + + QGraphicsProxyWidget::focusInEvent(event); +} + +void BrowserHistoryComboBox::focusOutEvent(QFocusEvent *event) +{ + if (nativeWidget()->isEditable() && !d->underMouse) { + const int FadeOutDuration = 150; + + if (d->animation->state() != QAbstractAnimation::Stopped) { + d->animation->stop(); + } + d->animation->setDuration(FadeOutDuration); + d->animation->setDirection(QAbstractAnimation::Backward); + d->animation->start(); + } + + + QGraphicsProxyWidget::focusInEvent(event); +} + +void BrowserHistoryComboBox::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + d->underMouse = true; + if (nativeWidget()->isEditable() && hasFocus()) { + return; + } + const int FadeInDuration = 75; + + if (d->animation->state() != QAbstractAnimation::Stopped) { + d->animation->stop(); + } + d->animation->setDuration(FadeInDuration); + d->animation->setDirection(QAbstractAnimation::Forward); + d->animation->start(); + + d->background->setElementPrefix("active"); + + QGraphicsProxyWidget::hoverEnterEvent(event); +} + +void BrowserHistoryComboBox::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + d->underMouse = false; + if (nativeWidget()->isEditable() && hasFocus()) { + return; + } + + const int FadeOutDuration = 150; + + if (d->animation->state() != QAbstractAnimation::Stopped) { + d->animation->stop(); + } + d->animation->setDuration(FadeOutDuration); + d->animation->setDirection(QAbstractAnimation::Backward); + d->animation->start(); + + d->background->setElementPrefix("active"); + + QGraphicsProxyWidget::hoverLeaveEvent(event); +} + +void BrowserHistoryComboBox::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::FontChange) { + d->customFont = true; + nativeWidget()->setFont(font()); + } + + QGraphicsProxyWidget::changeEvent(event); +} + +void BrowserHistoryComboBox::setProgressValue(int value) +{ + d->progressValue = value; + update(); +} + +void BrowserHistoryComboBox::setDisplayProgress(bool enable) +{ + d->displayProgress = enable; + update(); +} + +} // namespace Plasma + +#include "browserhistorycombobox.moc" + diff --git a/plasma/generic/applets/webbrowser/browserhistorycombobox.h b/plasma/generic/applets/webbrowser/browserhistorycombobox.h new file mode 100644 index 00000000..f35a6738 --- /dev/null +++ b/plasma/generic/applets/webbrowser/browserhistorycombobox.h @@ -0,0 +1,133 @@ +/* + * Copyright 2008 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BROWSERHISTORYCOMBOBOX_H +#define BROWSERHISTORYCOMBOBOX_H + +#include + +class KComboBox; + +namespace Plasma +{ + +class ComboBoxPrivate; + +/** + * @class ComboBox plasma/widgets/combobox.h + * + * @short Provides a Plasma-themed combo box. + */ +class BrowserHistoryComboBox : public QGraphicsProxyWidget +{ + Q_OBJECT + + Q_PROPERTY(QGraphicsWidget *parentWidget READ parentWidget) + Q_PROPERTY(QString text READ text NOTIFY textChanged) + Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet) + Q_PROPERTY(KComboBox *nativeWidget READ nativeWidget WRITE setNativeWidget) + + Q_PROPERTY(qreal animationUpdate READ animationUpdate WRITE setAnimationUpdate) + +public: + explicit BrowserHistoryComboBox(QGraphicsWidget *parent = 0); + ~BrowserHistoryComboBox(); + + /** + * @return the display text + */ + QString text() const; + + /** + * Sets the stylesheet used to control the visual display of this ComboBox + * + * @arg stylesheet a CSS string + */ + void setStyleSheet(const QString &stylesheet); + + /** + * @return the stylesheet currently used with this widget + */ + QString styleSheet(); + + /** + * Sets the combo box wrapped by this ComboBox (widget must inherit KComboBox), ownership is transferred to the ComboBox + * + * @arg combo box that will be wrapped by this ComboBox + * @since KDE4.4 + */ + void setNativeWidget(KComboBox *nativeWidget); + + /** + * @return the native widget wrapped by this ComboBox + */ + KComboBox *nativeWidget() const; + + /** + * Adds an item to the combo box with the given text. The + * item is appended to the list of existing items. + */ + void addItem(const QString &text); + + void setProgressValue(int value); + + void setDisplayProgress(bool enable); + +public Q_SLOTS: + void clear(); + +Q_SIGNALS: + /** + * This signal is sent when the user chooses an item in the combobox. + * The item's text is passed. + */ + void activated(const QString &text); + + /** + * This signal is sent whenever the currentIndex in the combobox changes + * either through user interaction or programmatically. + * The item's text is passed. + */ + void textChanged(const QString &text); + +protected: + void resizeEvent(QGraphicsSceneResizeEvent *event); + void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget); + void focusInEvent(QFocusEvent *event); + void focusOutEvent(QFocusEvent *event); + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + void changeEvent(QEvent *event); + +private slots: + void setAnimationUpdate(qreal progress); + qreal animationUpdate() const; + +private: + ComboBoxPrivate * const d; + + friend class ComboBoxPrivate; + Q_PRIVATE_SLOT(d, void syncBorders()) +}; + +} // namespace Plasma + +#endif // multiple inclusion guard diff --git a/plasma/generic/applets/webbrowser/browsermessagebox.cpp b/plasma/generic/applets/webbrowser/browsermessagebox.cpp new file mode 100644 index 00000000..786102b2 --- /dev/null +++ b/plasma/generic/applets/webbrowser/browsermessagebox.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2010 Davide Bettio * + * * + * 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 "browsermessagebox.h" + +#include + +#include +#include +#include + +BrowserMessageBox::BrowserMessageBox(QGraphicsWidget *parent, QString message) + : QGraphicsWidget(parent) +{ + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this); + layout->setOrientation(Qt::Horizontal); + + Plasma::Label *messageLabel = new Plasma::Label(this); + messageLabel->setText(message); + layout->addItem(messageLabel); + + m_okButton = new Plasma::PushButton(this); + m_okButton->setText(i18n("OK")); + connect(m_okButton, SIGNAL(clicked()), this, SIGNAL(okClicked())); + layout->addItem(m_okButton); + + m_cancelButton = new Plasma::PushButton(this); + m_cancelButton->setText(i18n("Cancel")); + connect(m_cancelButton, SIGNAL(clicked()), this, SIGNAL(cancelClicked())); + layout->addItem(m_cancelButton); +} + +Plasma::PushButton *BrowserMessageBox::okButton() +{ + return m_okButton; +} + +Plasma::PushButton *BrowserMessageBox::cancelButton() +{ + return m_cancelButton; +} + +#include "browsermessagebox.moc" diff --git a/plasma/generic/applets/webbrowser/browsermessagebox.h b/plasma/generic/applets/webbrowser/browsermessagebox.h new file mode 100644 index 00000000..c167ffc3 --- /dev/null +++ b/plasma/generic/applets/webbrowser/browsermessagebox.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2010 Davide Bettio * + * * + * 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 BROWSERMESSAGEBOX_H +#define BROWSERMESSAGEBOX_H + +#include + +namespace Plasma +{ + class PushButton; +} + +class BrowserMessageBox : public QGraphicsWidget +{ + Q_OBJECT + + public: + BrowserMessageBox(QGraphicsWidget *parent, QString message); + + Plasma::PushButton *okButton(); + Plasma::PushButton *cancelButton(); + + private: + Plasma::PushButton *m_okButton; + Plasma::PushButton *m_cancelButton; + + Q_SIGNALS: + void okClicked(); + void cancelClicked(); +}; + +#endif diff --git a/plasma/generic/applets/webbrowser/errorpage.cpp b/plasma/generic/applets/webbrowser/errorpage.cpp new file mode 100644 index 00000000..6bd14ee5 --- /dev/null +++ b/plasma/generic/applets/webbrowser/errorpage.cpp @@ -0,0 +1,158 @@ +/* This file is part of the KDE project + * + * Copyright (C) Hamish Rodda, Urs Wolfer, Davide Bettio + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "errorpage.h" + +int webKitErrorToKIOError(int eValue) +{ + switch (eValue){ + case QNetworkReply::NoError: + return 0; + + case QNetworkReply::ConnectionRefusedError: + return KIO::ERR_COULD_NOT_CONNECT; + + case QNetworkReply::HostNotFoundError: + return KIO::ERR_UNKNOWN_HOST; + + case QNetworkReply::TimeoutError: + return KIO::ERR_SERVER_TIMEOUT; + + case QNetworkReply::OperationCanceledError: + return KIO::ERR_ABORTED; + + case QNetworkReply::ProxyNotFoundError: + return KIO::ERR_UNKNOWN_PROXY_HOST; + + case QNetworkReply::ContentAccessDenied: + return KIO::ERR_ACCESS_DENIED; + + case QNetworkReply::ContentOperationNotPermittedError: + return KIO::ERR_WRITE_ACCESS_DENIED; + + case QNetworkReply::ContentNotFoundError: + return KIO::ERR_NO_CONTENT; + + case QNetworkReply::AuthenticationRequiredError: + return KIO::ERR_COULD_NOT_AUTHENTICATE; + + case QNetworkReply::ProtocolUnknownError: + return KIO::ERR_UNSUPPORTED_PROTOCOL; + + case QNetworkReply::ProtocolInvalidOperationError: + return KIO::ERR_UNSUPPORTED_ACTION; + + default: + return KIO::ERR_UNKNOWN; + } +} + +/* + * from khtml_part code + */ +QString errorPageHtml( int errorCode, const QString& text, const KUrl& reqUrl ) +{ + QString errorName, techName, description; + QStringList causes, solutions; + + QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl ); + QDataStream stream(raw); + + stream >> errorName >> techName >> description >> causes >> solutions; + + QString url, protocol, datetime; + url = Qt::escape( reqUrl.prettyUrl() ); + protocol = reqUrl.protocol(); + datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), + KLocale::LongDate ); + + QString filename( KStandardDirs::locate( "data", "khtml/error.html" ) ); + QFile file( filename ); + bool isOpened = file.open( QIODevice::ReadOnly ); + if ( !isOpened ) + kWarning(6050) << "Could not open error html template:" << filename; + + QString html = QString( QLatin1String( file.readAll() ) ); + + html.replace( QLatin1String( "TITLE" ), i18n( "Error: %1 - %2", errorName, url ) ); + html.replace( QLatin1String( "DIRECTION" ), QApplication::isRightToLeft() ? "rtl" : "ltr" ); + KUrl iconUrl(KIconLoader::global()->iconPath( "dialog-warning", -KIconLoader::SizeHuge )); + iconUrl.setProtocol("file://"); + html.replace( QLatin1String( "ICON_PATH" ), iconUrl.url()); + + QString doc = QLatin1String( "

" ); + doc += i18n( "The requested operation could not be completed" ); + doc += QLatin1String( "

" ); + doc += errorName; + doc += QLatin1String( "

" ); + if ( !techName.isNull() ) { + doc += QLatin1String( "

" ); + doc += i18n( "Technical Reason: " ); + doc += techName; + doc += QLatin1String( "

" ); + } + doc += QLatin1String( "

" ); + doc += i18n( "Details of the Request:" ); + doc += QLatin1String( "

  • " ); + doc += i18n( "URL: %1" , url ); + doc += QLatin1String( "
  • " ); + if ( !protocol.isNull() ) { + doc += i18n( "Protocol: %1", protocol ); + doc += QLatin1String( "
  • " ); + } + doc += i18n( "Date and Time: %1" , datetime ); + doc += QLatin1String( "
  • " ); + doc += i18n( "Additional Information: %1" , text ); + doc += QLatin1String( "

" ); + doc += i18n( "Description:" ); + doc += QLatin1String( "

" ); + doc += description; + doc += QLatin1String( "

" ); + if ( causes.count() ) { + doc += QLatin1String( "

" ); + doc += i18n( "Possible Causes:" ); + doc += QLatin1String( "

  • " ); + doc += causes.join( "
  • " ); + doc += QLatin1String( "
" ); + } + if ( solutions.count() ) { + doc += QLatin1String( "

" ); + doc += i18n( "Possible Solutions:" ); + doc += QLatin1String( "

  • " ); + doc += solutions.join( "
  • " ); + doc += QLatin1String( "
" ); + } + + html.replace( QLatin1String("TEXT"), doc ); + + return html; +} diff --git a/plasma/generic/applets/webbrowser/errorpage.h b/plasma/generic/applets/webbrowser/errorpage.h new file mode 100644 index 00000000..a8239470 --- /dev/null +++ b/plasma/generic/applets/webbrowser/errorpage.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * Copyright (C) 2010 Davide Bettio * + * * + * 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 ERRORPAGE_H +#define ERRORPAGE_H + +#include +#include + +int webKitErrorToKIOError(int eValue); +QString errorPageHtml( int errorCode, const QString& text, const KUrl& reqUrl ); + +#endif diff --git a/plasma/generic/applets/webbrowser/plasma-applet-webbrowser.desktop b/plasma/generic/applets/webbrowser/plasma-applet-webbrowser.desktop new file mode 100644 index 00000000..5d83d243 --- /dev/null +++ b/plasma/generic/applets/webbrowser/plasma-applet-webbrowser.desktop @@ -0,0 +1,185 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Web Browser +Name[af]=Web Blaaier +Name[ar]=متصفح الوِب +Name[ast]=Restolador Web +Name[be]=Вандроўнік па Сеціве +Name[be@latin]=Hartač sieciva +Name[bg]=Уеб браузър +Name[bn]=ওয়েব ব্রাউজার +Name[bn_IN]=ওয়েব ব্রাউজার +Name[br]=Furcher an Internet +Name[bs]=veb pregledač +Name[ca]=Navegació Web +Name[ca@valencia]=Navegació Web +Name[cs]=Prohlížeč Webu +Name[csb]=Przezérnik WWW +Name[cy]=Porydd Gwê +Name[da]=Browser +Name[de]=Webbrowser +Name[el]=Περιηγητής ιστού +Name[en_GB]=Web Browser +Name[eo]=Retumilo +Name[es]=Navegador Web +Name[et]=Veebibrauser +Name[eu]=Web-arakatzailea +Name[fa]=مرورگر وب‌‌ +Name[fi]=Verkkoselain +Name[fr]=Navigateur Web +Name[fy]=Webblêder +Name[ga]=Brabhsálaí Gréasáin +Name[gl]=Navegador web +Name[gu]=વેબ બ્રાઉઝર +Name[he]=דפדפן אינטרנט +Name[hi]=वेब ब्राउज़र +Name[hne]=वेब ब्राउजर +Name[hr]=Web preglednik +Name[hsb]=Web Browser +Name[hu]=Webböngésző +Name[ia]=Navigator Web +Name[id]=Peramban Web +Name[is]=Vafri +Name[it]=Browser Web +Name[ja]=ウェブブラウザ +Name[ka]=ვებ ბრაუზერი +Name[kk]=Веб шолғышы +Name[km]=កម្មវិធី​រុករក​បណ្ដាញ +Name[kn]=ಚಾಲ ವೀಕ್ಷಕ +Name[ko]=웹 브라우저 +Name[ku]=Geroka Torê +Name[lt]=Žiniatinklio naršyklė +Name[lv]=Tīmekļa pārlūks +Name[mai]=वेब ब्राउजर +Name[mk]=Веб-прелистувач +Name[ml]=വെബ് ബ്രൌസര്‍ +Name[mr]=वेब ब्राऊजर +Name[ms]=Pelayar Web +Name[nb]=Nettleser +Name[nds]=Nettkieker +Name[ne]=वेब ब्राउजर +Name[nl]=Webbrowser +Name[nn]=Nettlesar +Name[oc]=Navigador web +Name[or]=ୱେବ ବ୍ରାଉଜର +Name[pa]=ਵੈੱਬ ਬਰਾਊਜ਼ਰ +Name[pl]=Przeglądarka sieciowa +Name[pt]=Navegação Web +Name[pt_BR]=Navegador Web +Name[ro]=Navigator de web +Name[ru]=Браузер +Name[se]=Fierpmádatlogan +Name[si]=වෙබ් ගවේශකය +Name[sk]=Webový prehliadač +Name[sl]=Spletni brskalnik +Name[sr]=веб прегледач +Name[sr@ijekavian]=веб прегледач +Name[sr@ijekavianlatin]=veb pregledač +Name[sr@latin]=veb pregledač +Name[sv]=Webbläsning +Name[ta]=வலை உலாவி +Name[te]=వెబ్ బ్రౌజర్ +Name[tg]=Намоишгари Интернет +Name[th]=เว็บเบราว์เซอร์ +Name[tr]=Web Tarayıcı +Name[ug]=توركۆرگۈ +Name[uk]=Переглядач інтернету +Name[uz]=Veb-brauzer +Name[uz@cyrillic]=Веб-браузер +Name[vi]=Trình duyệt Mạng +Name[wa]=Betchteu waibe +Name[xh]=Umkhangeli zincwadi we Web +Name[x-test]=xxWeb Browserxx +Name[zh_CN]=网络浏览器 +Name[zh_TW]=網頁瀏覽器 +Comment=A simple web browser +Comment[ar]=متصفح وِب بسيط +Comment[ast]=Restolador cenciellu +Comment[be@latin]=Prosty hartač sieciva +Comment[bg]=Обикновен уеб браузър +Comment[bn]=একটি সরল ওয়েব ব্রাউজার +Comment[bn_IN]=একটি সাধারণ ওয়েব ব্রাউজার +Comment[bs]=Jednostavan veb pregledač +Comment[ca]=Un navegador web senzill +Comment[ca@valencia]=Un navegador web senzill +Comment[cs]=Jednoduchý webový prohlížeč +Comment[csb]=Prosti przezérnik WWW +Comment[da]=En simpel webbrowser +Comment[de]=Einfacher Webbrowser +Comment[el]=Ένας απλός περιηγητής ιστού +Comment[en_GB]=A simple web browser +Comment[eo]=Simpla foliumilo +Comment[es]=Navegador sencillo +Comment[et]=Lihtne veebibrauser +Comment[eu]=Web-arakatzaile soila +Comment[fi]=Yksinkertainen selain +Comment[fr]=Un navigateur Web simple +Comment[fy]=In ienfâldige webblêder +Comment[ga]=Brabhsálaí simplí +Comment[gl]=Un navegador web simples +Comment[gu]=સરળ વેબ બ્રાઉઝર +Comment[he]=דפדפן אינטרנט פשוט +Comment[hi]=एक सादा वेब ब्राउज़र +Comment[hne]=एक सादा ब्राउजर +Comment[hr]=Jednostavni web preglednik +Comment[hsb]=Jednory web browser +Comment[hu]=Egyszerű webböngésző +Comment[ia]=Un simple navigator web +Comment[id]=Peramban web sederhana +Comment[is]=Einfaldur vafri +Comment[it]=Un semplice browser Web +Comment[ja]=シンプルなウェブブラウザ +Comment[kk]=Қарапайым веб шолғышы +Comment[km]=កម្មវិធី​រុករក​បណ្ដាញ​ធម្មតា +Comment[kn]=ಒಂದು ಸರಳ ಜಾಲ ವೀಕ್ಷಕ +Comment[ko]=간단한 웹 브라우저 +Comment[ku]=Geroka torê yê hêsan +Comment[lt]=Paprasta žiniatinklio naršyklė +Comment[lv]=Vienkāršs tīmekļa pārlūks +Comment[mk]=Едноставен веб-прелистувач +Comment[ml]=ലളിതമായ വെബ് ബ്രൌസര്‍ +Comment[mr]=सोपा वेब ब्राऊजर +Comment[nb]=Enkel nettleser +Comment[nds]=En eenfach Nettkieker +Comment[nl]=Eenvoudige webbrowser +Comment[nn]=Enkel nettlesar +Comment[or]=ଗୋଟିଏ ସରଳ ୱେବ ବ୍ରାଉଜର +Comment[pa]=ਇੱਕ ਸਧਾਰਨ ਵੈੱਬ ਬਰਾਊਜ਼ਰ +Comment[pl]=Prosta przeglądarka sieciowa +Comment[pt]=Um navegador Web simples +Comment[pt_BR]=Um navegador da Internet simples +Comment[ro]=Un navigator web simplu +Comment[ru]=Простой браузер +Comment[si]=සරල වෙබ් ගවේශකයක් +Comment[sk]=Jednoduchý webový prehliadač +Comment[sl]=Preprost spletni brskalnik +Comment[sr]=Једноставан веб прегледач +Comment[sr@ijekavian]=Једноставан веб прегледач +Comment[sr@ijekavianlatin]=Jednostavan veb pregledač +Comment[sr@latin]=Jednostavan veb pregledač +Comment[sv]=En enkel webbläsare +Comment[ta]=எளிய உலாவி +Comment[tg]=Веб-браузери Cisco +Comment[th]=เว็บเบราว์เซอร์พื้นฐาน +Comment[tr]=Basit bir ağ tarayıcı +Comment[ug]=ئاددىي توركۆرگۈ +Comment[uk]=Простий переглядач інтернету +Comment[wa]=On simpe betchteu waibe +Comment[x-test]=xxA simple web browserxx +Comment[zh_CN]=简单网络浏览器 +Comment[zh_TW]=簡易瀏覽器 +Type=Service +Icon=konqueror +ServiceTypes=Plasma/Applet +X-Plasma-DropMimeTypes=text/html + +X-KDE-Library=plasma_applet_webbrowser +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=webbrowser +X-KDE-PluginInfo-Version=0.5 +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category=Online Services +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPLv2+ +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/applets/webbrowser/webbrowser.cpp b/plasma/generic/applets/webbrowser/webbrowser.cpp new file mode 100644 index 00000000..43c93589 --- /dev/null +++ b/plasma/generic/applets/webbrowser/webbrowser.cpp @@ -0,0 +1,675 @@ +/*************************************************************************** + * Copyright (C) 2008 Marco Martin * + * Copyright (C) 2010 Davide Bettio * + * * + * 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 "webbrowser.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "bookmarksdelegate.h" +#include "bookmarkitem.h" +#include "webviewoverlay.h" +#include "browserhistorycombobox.h" +#include "browsermessagebox.h" +#include "errorpage.h" +#include "webbrowserpage.h" + +using Plasma::MessageButton; + +WebBrowser::WebBrowser(QObject *parent, const QVariantList &args) + : Plasma::PopupApplet(parent, args), + m_browser(0), + m_verticalScrollValue(0), + m_horizontalScrollValue(0), + m_completion(0), + m_bookmarkManager(0), + m_bookmarkModel(0), + m_autoRefreshTimer(0) +{ + setHasConfigurationInterface(true); + setAspectRatioMode(Plasma::IgnoreAspectRatio); + + m_historyCombo = 0; + m_graphicsWidget = 0; + m_webOverlay = 0; + + m_layout = 0; + resize(500,500); + if (!args.isEmpty()) { + m_url = KUrl(args.value(0).toString()); + } + setPopupIcon("konqueror"); +} + +QGraphicsWidget *WebBrowser::graphicsWidget() +{ + if (m_graphicsWidget) { + return m_graphicsWidget; + } + + m_layout = new QGraphicsLinearLayout(Qt::Vertical); + m_toolbarLayout = new QGraphicsLinearLayout(Qt::Horizontal); + m_statusbarLayout = new QGraphicsLinearLayout(Qt::Horizontal); + + m_back = addTool("go-previous", m_toolbarLayout); + m_forward = addTool("go-next", m_toolbarLayout); + + m_nativeHistoryCombo = new KHistoryComboBox(); + m_historyCombo = new Plasma::BrowserHistoryComboBox(this); + m_historyCombo->setNativeWidget(m_nativeHistoryCombo); + m_historyCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + m_historyCombo->setZValue(999); + + m_nativeHistoryCombo->setDuplicatesEnabled(false); + m_pixmapProvider = new KUrlPixmapProvider; + m_nativeHistoryCombo->setPixmapProvider(m_pixmapProvider); + + m_toolbarLayout->addItem(m_historyCombo); + m_go = addTool("go-jump-locationbar", m_toolbarLayout); + m_goAction = m_go->action(); + m_reloadAction = new QAction(KIcon("view-refresh"), QString(), this); + + m_layout->addItem(m_toolbarLayout); + + m_browser = new Plasma::WebView(this); + m_browser->setPage(new WebBrowserPage(this)); + m_browser->setPreferredSize(400, 400); + m_browser->setMinimumSize(130, 130); + m_browser->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + m_layout->addItem(m_browser); + + //bookmarks + m_bookmarkManager = KBookmarkManager::userBookmarksManager(); + connect(m_bookmarkManager, SIGNAL(changed(QString,QString)), this, SLOT(bookmarksModelInit())); + bookmarksModelInit(); + + m_bookmarksView = new Plasma::TreeView(this); + m_bookmarksView->setZValue(1); + m_bookmarksView->nativeWidget()->setAttribute(Qt::WA_NoSystemBackground, false); + m_bookmarksView->nativeWidget()->verticalScrollBar()->setStyle(QApplication::style()); + m_bookmarksView->nativeWidget()->horizontalScrollBar()->setStyle(QApplication::style()); + m_bookmarksView->setModel(m_bookmarkModel); + m_bookmarksView->nativeWidget()->setHeaderHidden(true); + m_bookmarksView->hide(); + + m_bookmarksDelegate = new BookmarksDelegate(this); + m_bookmarksView->nativeWidget()->setItemDelegate(m_bookmarksDelegate); + + connect(m_bookmarksDelegate, SIGNAL(destroyBookmark(QModelIndex)), this, SLOT(removeBookmark(QModelIndex))); + + m_layout->addItem(m_statusbarLayout); + + m_addBookmark = addTool("bookmark-new", m_statusbarLayout); + m_addBookmarkAction = m_addBookmark->action(); + m_removeBookmarkAction = new QAction(KIcon("list-remove"), QString(), this); + m_organizeBookmarks = addTool("bookmarks-organize", m_statusbarLayout); + + m_bookmarksViewAnimation = Plasma::Animator::create(Plasma::Animator::FadeAnimation, this); + m_bookmarksViewAnimation->setTargetWidget(m_bookmarksView); + connect(m_bookmarksViewAnimation, SIGNAL(finished()), this, SLOT(bookmarksAnimationFinished())); + + m_stop = addTool("process-stop", m_statusbarLayout); + + QGraphicsWidget *spacer = new QGraphicsWidget(this); + spacer->setMaximumWidth(INT_MAX); + spacer->setMaximumHeight(0); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + m_statusbarLayout->addItem(spacer); + + m_zoom = new Plasma::Slider(this); + m_zoom->setMaximum(100); + m_zoom->setMinimum(0); + m_zoom->setValue(50); + m_zoom->setOrientation(Qt::Horizontal); + m_zoom->hide(); + m_zoom->setMaximumWidth(200); + m_statusbarLayout->addItem(m_zoom); + + connect(m_zoom, SIGNAL(valueChanged(int)), this, SLOT(zoom(int))); + m_browser->setUrl(m_url); + m_browser->update(); + + connect(m_back->action(), SIGNAL(triggered()), this, SLOT(back())); + connect(m_forward->action(), SIGNAL(triggered()), this, SLOT(forward())); + connect(m_reloadAction, SIGNAL(triggered()), this, SLOT(reload())); + connect(m_goAction, SIGNAL(triggered()), this, SLOT(returnPressed())); + connect(m_stop->action(), SIGNAL(triggered()), m_browser->page()->action(QWebPage::Stop), SLOT(trigger())); + + connect(m_historyCombo->nativeWidget(), SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(m_historyCombo->nativeWidget(), SIGNAL(activated(int)), this, SLOT(returnPressed())); + connect(m_historyCombo, SIGNAL(activated(QString)), this, SLOT(comboTextChanged(QString))); + connect(m_browser->page()->mainFrame(), SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl))); + connect(m_browser, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int))); + + connect(m_addBookmarkAction, SIGNAL(triggered()), this, SLOT(addBookmark())); + connect(m_removeBookmarkAction, SIGNAL(triggered()), this, SLOT(removeBookmark())); + connect(m_organizeBookmarks->action(), SIGNAL(triggered()), this, SLOT(bookmarksToggle())); + connect(m_bookmarksView->nativeWidget(), SIGNAL(clicked(QModelIndex)), this, SLOT(bookmarkClicked(QModelIndex))); + + //Autocompletion stuff + m_completion = new KCompletion(); + m_nativeHistoryCombo->setCompletionObject(m_completion); + + m_graphicsWidget = new QGraphicsWidget(this); + m_graphicsWidget->setLayout(m_layout); + + m_back->setEnabled(m_browser->page()->history()->canGoBack()); + m_forward->setEnabled(m_browser->page()->history()->canGoForward()); + + configChanged(); + + connect(this, SIGNAL(messageButtonPressed(MessageButton)), this, SLOT(removeBookmarkMessageButtonPressed(MessageButton))); + + return m_graphicsWidget; +} + +WebBrowser::~WebBrowser() +{ + KConfigGroup cg = config(); + saveState(cg); + delete m_completion; + delete m_bookmarkModel; +} + +Plasma::IconWidget *WebBrowser::addTool(const QString &iconString, QGraphicsLinearLayout *layout) +{ + Plasma::IconWidget *icon = new Plasma::IconWidget(this); + QAction *action = new QAction(KIcon(iconString), QString(), this); + icon->setAction(action); + icon->setPreferredSize(icon->sizeFromIconSize(IconSize(KIconLoader::Toolbar))); + layout->addItem(icon); + + return icon; +} + +void WebBrowser::bookmarksModelInit() +{ + if (m_bookmarkModel) { + m_bookmarkModel->clear(); + } else { + m_bookmarkModel = new QStandardItemModel; + } + + fillGroup(0, m_bookmarkManager->root()); +} + +void WebBrowser::configChanged() +{ + KConfigGroup cg = config(); + + m_browser->setDragToScroll(cg.readEntry("DragToScroll", false)); + + if (!m_url.isValid()) { + m_url = KUrl(cg.readEntry("Url", "http://www.kde.org")); + m_verticalScrollValue = cg.readEntry("VerticalScrollValue", 0); + m_horizontalScrollValue = cg.readEntry("HorizontalScrollValue", 0); + int value = cg.readEntry("Zoom", 50); + m_zoom->setValue(value); + qreal zoomFactor = qMax((qreal)0.2, ((qreal)value/(qreal)50)); + if ((zoomFactor > 0.95) && (zoomFactor < 1.05)){ + zoomFactor = 1; + } + m_browser->setZoomFactor(zoomFactor); + m_browser->setUrl(m_url); + } + + m_autoRefresh = cg.readEntry("autoRefresh", false); + m_autoRefreshInterval = qMax(2, cg.readEntry("autoRefreshInterval", 5)); + + if (m_autoRefresh) { + m_autoRefreshTimer = new QTimer(this); + m_autoRefreshTimer->start(m_autoRefreshInterval*60*1000); + connect(m_autoRefreshTimer, SIGNAL(timeout()), this, SLOT(reload())); + } + + QStringList list = cg.readEntry("History list", QStringList()); + m_nativeHistoryCombo->setHistoryItems(list); +} + +void WebBrowser::fillGroup(BookmarkItem *parentItem, const KBookmarkGroup &group) +{ + KBookmark it = group.first(); + + while (!it.isNull()) { + BookmarkItem *bookmarkItem = new BookmarkItem(it); + bookmarkItem->setEditable(false); + + if (it.isGroup()) { + KBookmarkGroup grp = it.toGroup(); + fillGroup( bookmarkItem, grp ); + + } + + if (parentItem) { + parentItem->appendRow(bookmarkItem); + } else { + m_bookmarkModel->appendRow(bookmarkItem); + } + + it = m_bookmarkManager->root().next(it); + } +} + +void WebBrowser::saveState(KConfigGroup &cg) const +{ + cg.writeEntry("Url", m_url.prettyUrl()); + + if (m_historyCombo) { + const QStringList list = m_nativeHistoryCombo->historyItems(); + cg.writeEntry("History list", list); + } + + if (m_browser) { + cg.writeEntry("VerticalScrollValue", m_browser->page()->mainFrame()->scrollBarValue(Qt::Vertical)); + cg.writeEntry("HorizontalScrollValue", m_browser->page()->mainFrame()->scrollBarValue(Qt::Horizontal)); + } +} + +void WebBrowser::back() +{ + m_browser->page()->history()->back(); +} + +void WebBrowser::forward() +{ + m_browser->page()->history()->forward(); +} + +void WebBrowser::reload() +{ + m_browser->setUrl(m_url); +} + +void WebBrowser::returnPressed() +{ + KUrl url(m_nativeHistoryCombo->currentText()); + + + KUriFilter::self()->filterUri( url ); + + m_verticalScrollValue = 0; + m_horizontalScrollValue = 0; + m_browser->setUrl(url); +} + + +void WebBrowser::urlChanged(const QUrl &url) +{ + //ask for a favicon + Plasma::DataEngine *engine = dataEngine( "favicons" ); + if (engine) { + //engine->disconnectSource( url.toString(), this ); + engine->connectSource( url.toString(), this ); + + engine->query( url.toString() ); + } + + m_url = KUrl(url); + + if (m_bookmarkModel->match(m_bookmarkModel->index(0,0), BookmarkItem::UrlRole, m_url.prettyUrl()).isEmpty()) { + m_addBookmark->setAction(m_addBookmarkAction); + } else { + m_addBookmark->setAction(m_removeBookmarkAction); + } + + m_nativeHistoryCombo->addToHistory(m_url.prettyUrl()); + m_nativeHistoryCombo->setCurrentIndex(0); + + m_go->setAction(m_reloadAction); + + KConfigGroup cg = config(); + saveState(cg); + + m_back->setEnabled(m_browser->page()->history()->canGoBack()); + m_forward->setEnabled(m_browser->page()->history()->canGoForward()); + setAssociatedApplicationUrls(KUrl(url)); +} + +void WebBrowser::comboTextChanged(const QString &string) +{ + Q_UNUSED(string) + + m_go->setAction(m_goAction); +} + +void WebBrowser::dataUpdated( const QString &source, const Plasma::DataEngine::Data &data ) +{ + //TODO: find a way to update bookmarks and history combobox here, at the moment the data engine + // is only used to save the icon files + if (source == m_nativeHistoryCombo->currentText()) { + QPixmap favicon(QPixmap::fromImage(data["Icon"].value())); + if (!favicon.isNull()) { + m_nativeHistoryCombo->setItemIcon( + m_nativeHistoryCombo->currentIndex(), QIcon(favicon)); + setPopupIcon(QIcon(favicon)); + } + } +} + +void WebBrowser::addBookmark() +{ + KBookmark bookmark = m_bookmarkManager->root().addBookmark(m_browser->page()->mainFrame()->title(), m_url); + m_bookmarkManager->save(); + + BookmarkItem *bookmarkItem = new BookmarkItem(bookmark); + m_bookmarkModel->appendRow(bookmarkItem); + + m_addBookmark->setAction(m_removeBookmarkAction); +} + +void WebBrowser::removeBookmark(const QModelIndex &index) +{ + BookmarkItem *item = dynamic_cast(m_bookmarkModel->itemFromIndex(index)); + + if (item) { + KBookmark bookmark = item->bookmark(); + + const QString text(i18nc("@info", "Do you really want to remove the bookmark to %1?", bookmark.url().host())); + showMessage(KIcon("dialog-warning"), text, Plasma::ButtonYes | Plasma::ButtonNo); + return; + } + + if (item && item->parent()) { + item->parent()->removeRow(index.row()); + } else { + m_bookmarkModel->removeRow(index.row()); + } + +} + +void WebBrowser::removeBookmarkMessageButtonPressed(const Plasma::MessageButton button) +{ + if (button == Plasma::ButtonNo){ + return; + } + + const QModelIndexList list = m_bookmarkModel->match(m_bookmarkModel->index(0,0), BookmarkItem::UrlRole, m_url.prettyUrl()); + + if (!list.isEmpty()) { + const QModelIndex &index = list.first(); + BookmarkItem *item = dynamic_cast(m_bookmarkModel->itemFromIndex(index)); + + if (item) { + KBookmark bookmark = item->bookmark(); + + bookmark.parentGroup().deleteBookmark(bookmark); + m_bookmarkManager->save(); + } + + if (item && item->parent()) { + item->parent()->removeRow(index.row()); + } else { + m_bookmarkModel->removeRow(index.row()); + } + } + + m_addBookmark->setAction(m_addBookmarkAction); +} +void WebBrowser::removeBookmark() +{ + const QModelIndexList list = m_bookmarkModel->match(m_bookmarkModel->index(0,0), BookmarkItem::UrlRole, m_url.prettyUrl()); + + if (!list.isEmpty()) { + removeBookmark(list.first()); + } +} + +void WebBrowser::bookmarksToggle() +{ + if (m_bookmarksView->isVisible()) { + m_bookmarksViewAnimation->setProperty("startOpacity", 1); + m_bookmarksViewAnimation->setProperty("targetOpacity", 0); + m_bookmarksViewAnimation->start(); + } else { + m_bookmarksView->show(); + m_bookmarksView->setOpacity(0); + updateOverlaysGeometry(); + m_bookmarksViewAnimation->setProperty("startOpacity", 0); + m_bookmarksViewAnimation->setProperty("targetOpacity", 1); + m_bookmarksViewAnimation->start(); + } +} + +void WebBrowser::bookmarksAnimationFinished() +{ + if (qFuzzyCompare(m_bookmarksView->opacity() + 1, 1)){ + m_bookmarksView->hide(); + } +} + +void WebBrowser::bookmarkClicked(const QModelIndex &index) +{ + QStandardItem *item = m_bookmarkModel->itemFromIndex(index); + + if (item) { + KUrl url(item->data(BookmarkItem::UrlRole).value()); + + if (url.isValid()) { + m_browser->setUrl(url); + bookmarksToggle(); + } + } +} + +void WebBrowser::zoom(int value) +{ + config().writeEntry("Zoom", value); + m_browser->setZoomFactor((qreal)0.2 + ((qreal)value/(qreal)50)); +} + +void WebBrowser::loadProgress(int progress) +{ + m_historyCombo->setProgressValue(progress); + + if (progress == 100) { + m_historyCombo->setDisplayProgress(false); + m_stop->hide(); + m_stop->setMaximumWidth(0); + m_zoom->show(); + m_statusbarLayout->invalidate(); + + m_browser->page()->mainFrame()->setScrollBarValue(Qt::Vertical, m_verticalScrollValue); + m_browser->page()->mainFrame()->setScrollBarValue(Qt::Horizontal, m_horizontalScrollValue); + + } else { + m_historyCombo->setDisplayProgress(true); + m_stop->show(); + m_stop->setMaximumWidth(INT_MAX); + m_zoom->hide(); + m_statusbarLayout->invalidate(); + } +} + +void WebBrowser::createConfigurationInterface(KConfigDialog *parent) +{ + QWidget *widget = new QWidget(); + ui.setupUi(widget); + parent->addPage(widget, i18n("General"), icon()); + connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); + connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); + + ui.autoRefresh->setChecked(m_autoRefresh); + ui.autoRefreshInterval->setValue(m_autoRefreshInterval); + ui.autoRefreshInterval->setSuffix(ki18np(" minute", " minutes")); + ui.dragToScroll->setChecked(m_browser->dragToScroll()); + connect(ui.autoRefresh, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); + connect(ui.dragToScroll, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); + connect(ui.autoRefreshInterval, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified())); +} + +void WebBrowser::configAccepted() +{ + KConfigGroup cg = config(); + + m_autoRefresh = ui.autoRefresh->isChecked(); + m_autoRefreshInterval = ui.autoRefreshInterval->value(); + + cg.writeEntry("autoRefresh", m_autoRefresh); + cg.writeEntry("autoRefreshInterval", m_autoRefreshInterval); + cg.writeEntry("DragToScroll", ui.dragToScroll->isChecked()); + m_browser->setDragToScroll(ui.dragToScroll->isChecked()); + + if (m_autoRefresh) { + if (!m_autoRefreshTimer) { + m_autoRefreshTimer = new QTimer(this); + connect(m_autoRefreshTimer, SIGNAL(timeout()), this, SLOT(reload())); + } + + m_autoRefreshTimer->start(m_autoRefreshInterval*60*1000); + } else { + delete m_autoRefreshTimer; + m_autoRefreshTimer = 0; + } + + emit configNeedsSaving(); +} + +void WebBrowser::constraintsEvent(Plasma::Constraints constraints) +{ + if (constraints & Plasma::SizeConstraint){ + updateOverlaysGeometry(); + } +} + +void WebBrowser::updateOverlaysGeometry() +{ + QRect overlayGeometry(m_browser->pos().x() + contentsRect().x(), + m_browser->pos().y() + contentsRect().y(), + m_browser->geometry().width(), + m_browser->geometry().height()); + + if (m_bookmarksView->isVisible()) { + m_bookmarksView->setGeometry(overlayGeometry); + } + + if (m_webOverlay){ + m_webOverlay->setGeometry(overlayGeometry); + } +} + +void WebBrowser::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect) +{ + Q_UNUSED(option) + Q_UNUSED(contentsRect) + + if (!isIconified()){ + p->save(); + p->setBrush(QApplication::palette().window()); + p->setRenderHint(QPainter::Antialiasing); + p->setPen(Qt::NoPen); + p->drawRoundedRect(m_browser->pos().x() + contentsRect.x() - 2, + m_browser->pos().y() + contentsRect.y() - 2, + m_browser->geometry().width() + 4, + m_browser->geometry().height() + 4, + 2, 2); + p->restore(); + } +} + +void WebBrowser::closeWebViewOverlay() +{ + if (m_webOverlay){ + m_webOverlay->deleteLater(); + m_webOverlay = 0; + } +} + +QWebPage *WebBrowser::createWindow(QWebPage::WebWindowType type) +{ + Q_UNUSED(type) + + if (!m_webOverlay){ + m_webOverlay = new WebViewOverlay(this); + updateOverlaysGeometry(); + m_webOverlay->setZValue(999); + connect(m_webOverlay, SIGNAL(closeRequested()), this, SLOT(closeWebViewOverlay())); + } + + return m_webOverlay->page(); +} + +// +// Wallet managment +// + +void WebBrowser::saveFormDataRequested(const QString &uid, const QUrl &url) +{ + BrowserMessageBox *messageBox = new BrowserMessageBox(this, i18n("Do you want to store this password for %1?", url.host())); + messageBox->okButton()->setText(i18n("Store")); + messageBox->okButton()->setIcon(KIcon("document-save")); + messageBox->cancelButton()->setText(i18n("Do not store this time")); + messageBox->cancelButton()->setIcon(KIcon("dialog-cancel")); + m_layout->insertItem(1, messageBox); + walletRequests.insert(messageBox, uid); + connect(messageBox, SIGNAL(okClicked()), this, SLOT(acceptWalletRequest())); + connect(messageBox, SIGNAL(cancelClicked()), this, SLOT(rejectWalletRequest())); +} + +void WebBrowser::acceptWalletRequest() +{ + static_cast(m_browser->page())->wallet()->acceptSaveFormDataRequest( + walletRequests[static_cast(QObject::sender())]); + QObject::sender()->deleteLater(); +} + +void WebBrowser::rejectWalletRequest() +{ + static_cast(m_browser->page())->wallet()->rejectSaveFormDataRequest( + walletRequests[static_cast(QObject::sender())]); + QObject::sender()->deleteLater(); +} + +// +// End of wallet managment +// + +K_EXPORT_PLASMA_APPLET(webbrowser, WebBrowser) + +#include "webbrowser.moc" diff --git a/plasma/generic/applets/webbrowser/webbrowser.h b/plasma/generic/applets/webbrowser/webbrowser.h new file mode 100644 index 00000000..923f573d --- /dev/null +++ b/plasma/generic/applets/webbrowser/webbrowser.h @@ -0,0 +1,163 @@ +/*************************************************************************** + * Copyright (C) 2008 by Marco Martin * + * * + * 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 WEBBROWSER_H +#define WEBBROWSER_H + +#include +#include + +#include +#include + +#include "ui_webbrowserconfig.h" +#include "browsermessagebox.h" + +class WebViewOverlay; + +class QGraphicsLinearLayout; +class QStandardItemModel; +class QStandardItem; +class QTimer; +class KUrlPixmapProvider; +class KHistoryComboBox; +class KUrl; +class KCompletion; +class KBookmarkManager; +class KBookmarkGroup; +class QModelIndex; +class QAction; +class BookmarksDelegate; +class BookmarkItem; + +namespace Plasma +{ + class BrowserHistoryComboBox; + class IconWidget; + class ComboBox; + class WebView; + class TreeView; + class Slider; +} + + +using Plasma::MessageButton; + +class WebBrowser : public Plasma::PopupApplet +{ + Q_OBJECT +public: + WebBrowser(QObject *parent, const QVariantList &args); + ~WebBrowser(); + + QGraphicsWidget *graphicsWidget(); + void paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect); + QWebPage *createWindow(QWebPage::WebWindowType type); + + //TODO: put in a separate file + enum BookmarkRoles + { + UrlRole = Qt::UserRole+1, + BookmarkRole = Qt::UserRole+2 + }; + +public Q_SLOTS: + void dataUpdated(const QString &source, const Plasma::DataEngine::Data &data); + void saveFormDataRequested(const QString &uid, const QUrl &url); + +protected: + void saveState(KConfigGroup &cg) const; + Plasma::IconWidget *addTool(const QString &iconString, QGraphicsLinearLayout *layout); + void createConfigurationInterface(KConfigDialog *parent); + void constraintsEvent(Plasma::Constraints constraints); + +protected Q_SLOTS: + void back(); + void forward(); + void reload(); + void returnPressed(); + void urlChanged(const QUrl &url); + void comboTextChanged(const QString &string); + void addBookmark(); + void removeBookmark(const QModelIndex &index); + void removeBookmark(); + void bookmarksToggle(); + void bookmarkClicked(const QModelIndex &index); + void zoom(int value); + void loadProgress(int progress); + void bookmarksModelInit(); + void configAccepted(); + void configChanged(); + void bookmarksAnimationFinished(); + void removeBookmarkMessageButtonPressed(const MessageButton button); + void closeWebViewOverlay(); + + void acceptWalletRequest(); + void rejectWalletRequest(); + +private: + void fillGroup(BookmarkItem *parentItem, const KBookmarkGroup &group); + void updateOverlaysGeometry(); + QHash walletRequests; + + + QGraphicsLinearLayout *m_layout; + QGraphicsLinearLayout *m_toolbarLayout; + QGraphicsLinearLayout *m_statusbarLayout; + Plasma::WebView *m_browser; + WebViewOverlay *m_webOverlay; + KUrl m_url; + int m_verticalScrollValue; + int m_horizontalScrollValue; + KUrlPixmapProvider *m_pixmapProvider; + KCompletion *m_completion; + KBookmarkManager *m_bookmarkManager; + QStandardItemModel *m_bookmarkModel; + Plasma::TreeView *m_bookmarksView; + Plasma::Animation *m_bookmarksViewAnimation; + + QTimer *m_autoRefreshTimer; + bool m_autoRefresh; + int m_autoRefreshInterval; + + QGraphicsWidget *m_graphicsWidget; + + Plasma::BrowserHistoryComboBox *m_historyCombo; + KHistoryComboBox *m_nativeHistoryCombo; + BookmarksDelegate *m_bookmarksDelegate; + + Plasma::IconWidget *m_back; + Plasma::IconWidget *m_forward; + + Plasma::IconWidget *m_go; + QAction *m_goAction; + QAction *m_reloadAction; + + Plasma::IconWidget *m_addBookmark; + QAction *m_addBookmarkAction; + QAction *m_removeBookmarkAction; + + Plasma::IconWidget *m_organizeBookmarks; + Plasma::IconWidget *m_stop; + Plasma::Slider *m_zoom; + + Ui::WebBrowserConfig ui; +}; + +#endif diff --git a/plasma/generic/applets/webbrowser/webbrowserconfig.ui b/plasma/generic/applets/webbrowser/webbrowserconfig.ui new file mode 100644 index 00000000..1b1278b1 --- /dev/null +++ b/plasma/generic/applets/webbrowser/webbrowserconfig.ui @@ -0,0 +1,120 @@ + + + WebBrowserConfig + + + + 0 + 0 + 298 + 140 + + + + Dialog + + + + + + Auto refresh: + + + autoRefresh + + + + + + + + + + + + + + Interval: + + + autoRefreshInterval + + + + + + + false + + + + 0 + + + 0 + + + + + + 130 + 0 + + + + 2 + + + 5 + + + + + + + + + + Drag to scroll the page: + + + dragToScroll + + + + + + + + + + + + + + + KIntSpinBox + QSpinBox +
knuminput.h
+
+
+ + + + autoRefresh + toggled(bool) + intervalGroup + setEnabled(bool) + + + 238 + 11 + + + 238 + 39 + + + + +
diff --git a/plasma/generic/applets/webbrowser/webbrowserpage.cpp b/plasma/generic/applets/webbrowser/webbrowserpage.cpp new file mode 100644 index 00000000..3b236144 --- /dev/null +++ b/plasma/generic/applets/webbrowser/webbrowserpage.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2010 Davide Bettio * + * * + * 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 "webbrowserpage.h" +#include "webbrowser.h" +#include "errorpage.h" + +#include +#include + +#include + +WebBrowserPage::WebBrowserPage(WebBrowser *parent) + : KWebPage(parent) +{ + m_browser = parent; + //settings()->setAttribute(QWebSettings::JavaEnabled, true); + settings()->setAttribute(QWebSettings::PluginsEnabled, true); + + connect(networkAccessManager(), SIGNAL(finished(QNetworkReply*)), this, SLOT(networkAccessFinished(QNetworkReply*))); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(pageLoadFinished(bool))); + connect(wallet(), SIGNAL(saveFormDataRequested(QString,QUrl)), + m_browser, SLOT(saveFormDataRequested(QString,QUrl))); +} + +QWebPage *WebBrowserPage::createWindow(WebWindowType type) +{ + return m_browser->createWindow(type); +} + +void WebBrowserPage::pageLoadFinished(bool ok) +{ + if (ok){ + wallet()->fillFormData(mainFrame()); + } +} + +void WebBrowserPage::networkAccessFinished(QNetworkReply *nReply) +{ + switch (nReply->error()){ + case QNetworkReply::NoError: + case QNetworkReply::UnknownContentError: + case QNetworkReply::ContentNotFoundError: + return; + + default: + mainFrame()->setHtml(errorPageHtml(webKitErrorToKIOError(nReply->error()), nReply->url().toString(), nReply->url())); + } +} + +#include "webbrowserpage.moc" diff --git a/plasma/generic/applets/webbrowser/webbrowserpage.h b/plasma/generic/applets/webbrowser/webbrowserpage.h new file mode 100644 index 00000000..cd8e8c5b --- /dev/null +++ b/plasma/generic/applets/webbrowser/webbrowserpage.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2010 Davide Bettio * + * * + * 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 WEBBROWSERPAGE_H +#define WEBBROWSERPAGE_H + +#include + +class WebBrowser; + +class WebBrowserPage : public KWebPage +{ + Q_OBJECT + + public: + WebBrowserPage(WebBrowser *parent); + + protected: + QWebPage *createWindow(WebWindowType type); + + private Q_SLOTS: + void pageLoadFinished(bool ok); + void networkAccessFinished(QNetworkReply *nReply); + + private: + WebBrowser *m_browser; +}; + +#endif diff --git a/plasma/generic/applets/webbrowser/webviewoverlay.cpp b/plasma/generic/applets/webbrowser/webviewoverlay.cpp new file mode 100644 index 00000000..cfe00067 --- /dev/null +++ b/plasma/generic/applets/webbrowser/webviewoverlay.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2010 Davide Bettio * + * * + * 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 "webviewoverlay.h" + +#include +#include +#include +#include + +#include +#include + +#include "webbrowser.h" +#include "webbrowserpage.h" + +WebViewOverlay::WebViewOverlay(WebBrowser *parent) + : QGraphicsWidget(parent) +{ + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this); + layout->setOrientation(Qt::Vertical); + + m_webView = new Plasma::WebView(this); + m_webView->setPage(new WebBrowserPage(parent)); + m_webView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + layout->addItem(m_webView); + + m_closeButton = new Plasma::PushButton(this); + m_closeButton->setText(i18n("Close")); + connect(m_closeButton, SIGNAL(clicked()), this, SIGNAL(closeRequested())); + layout->addItem(m_closeButton); + connect(m_webView->page(), SIGNAL(windowCloseRequested()), this, SIGNAL(closeRequested())); +} + +QWebPage *WebViewOverlay::page() +{ + return m_webView->page(); +} + +void WebViewOverlay::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(widget) + + painter->fillRect(option->rect, QApplication::palette().window()); +} + +#include "webviewoverlay.moc" diff --git a/plasma/generic/applets/webbrowser/webviewoverlay.h b/plasma/generic/applets/webbrowser/webviewoverlay.h new file mode 100644 index 00000000..052a00ac --- /dev/null +++ b/plasma/generic/applets/webbrowser/webviewoverlay.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2010 Davide Bettio * + * * + * 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 WEBVIEWOVERLAY_H +#define WEBVIEWOVERLAY_H + +#include +#include + +class WebBrowser; + +namespace Plasma +{ + class PushButton; + class WebView; +} + +class WebViewOverlay : public QGraphicsWidget +{ + Q_OBJECT + + public: + WebViewOverlay(WebBrowser *parent); + QWebPage *page(); + + Q_SIGNALS: + void closeRequested(); + + protected: + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + private: + Plasma::WebView *m_webView; + Plasma::PushButton *m_closeButton; +}; + +#endif diff --git a/plasma/generic/containmentactions/CMakeLists.txt b/plasma/generic/containmentactions/CMakeLists.txt new file mode 100644 index 00000000..35c7b875 --- /dev/null +++ b/plasma/generic/containmentactions/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(contextmenu) +add_subdirectory(switchdesktop) +add_subdirectory(switchactivity) +add_subdirectory(paste) +add_subdirectory(switchwindow) +add_subdirectory(applauncher) +add_subdirectory(minimalcontextmenu) diff --git a/plasma/generic/containmentactions/applauncher/CMakeLists.txt b/plasma/generic/containmentactions/applauncher/CMakeLists.txt new file mode 100644 index 00000000..7025eaaf --- /dev/null +++ b/plasma/generic/containmentactions/applauncher/CMakeLists.txt @@ -0,0 +1,11 @@ +project(plasma-containmentactions-applauncher) + +set(applauncher_SRCS + launch.cpp +) + +kde4_add_plugin(plasma_containmentactions_applauncher ${applauncher_SRCS}) +target_link_libraries(plasma_containmentactions_applauncher ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_containmentactions_applauncher DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containmentactions-applauncher.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/containmentactions/applauncher/launch.cpp b/plasma/generic/containmentactions/applauncher/launch.cpp new file mode 100644 index 00000000..bef53e53 --- /dev/null +++ b/plasma/generic/containmentactions/applauncher/launch.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "launch.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include + +AppLauncher::AppLauncher(QObject *parent, const QVariantList &args) + : Plasma::ContainmentActions(parent, args), + m_action(new QAction(this)) +{ + m_menu = new KMenu(); + connect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(switchTo(QAction*))); + + m_action->setMenu(m_menu); +} + +AppLauncher::~AppLauncher() +{ + delete m_menu; +} + +void AppLauncher::init(const KConfigGroup &) +{ +} + +void AppLauncher::contextEvent(QEvent *event) +{ + makeMenu(); + m_menu->adjustSize(); + m_menu->exec(popupPosition(m_menu->size(), event)); +} + +QList AppLauncher::contextualActions() +{ + makeMenu(); + + QList list; + list << m_action; + return list; +} + +void AppLauncher::makeMenu() +{ + Plasma::DataEngine *apps = dataEngine("apps"); + if (!apps->isValid()) { + return; + } + + m_menu->clear(); + + //add the whole kmenu + Plasma::DataEngine::Data app = dataEngine("apps")->query("/"); + const QStringList sources = app.value("entries").toStringList(); + foreach (const QString &source, sources) { + addApp(m_menu, source); + } +} + +bool AppLauncher::addApp(QMenu *menu, const QString &source) +{ + if (source == "---") { + menu->addSeparator(); + return false; + } + + Plasma::DataEngine::Data app = dataEngine("apps")->query(source); + + if (!app.value("display").toBool()) { + kDebug() << "hidden entry" << source; + return false; + } + QString name = app.value("name").toString(); + if (name.isEmpty()) { + kDebug() << "failed source" << source; + return false; + } + + name.replace("&", "&&"); //escaping + KIcon icon(app.value("iconName").toString()); + + if (app.value("isApp").toBool()) { + QAction *action = menu->addAction(icon, name); + action->setData(source); + } else { //ooh, it's actually a group! + QMenu *subMenu = menu->addMenu(icon, name); + bool hasEntries = false; + foreach (const QString &source, app.value("entries").toStringList()) { + hasEntries = addApp(subMenu, source) || hasEntries; + } + + if (!hasEntries) { + delete subMenu; + return false; + } + } + return true; +} + +void AppLauncher::switchTo(QAction *action) +{ + QString source = action->data().toString(); + kDebug() << source; + Plasma::Service *service = dataEngine("apps")->serviceForSource(source); + if (service) { + Plasma::ServiceJob *job = service->startOperationCall(service->operationDescription("launch")); + connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater())); + } +} + +#include "launch.moc" diff --git a/plasma/generic/containmentactions/applauncher/launch.h b/plasma/generic/containmentactions/applauncher/launch.h new file mode 100644 index 00000000..55a96230 --- /dev/null +++ b/plasma/generic/containmentactions/applauncher/launch.h @@ -0,0 +1,55 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SWITCHWINDOW_HEADER +#define SWITCHWINDOW_HEADER + +#include + +class QAction; +class KMenu; + +class AppLauncher : public Plasma::ContainmentActions +{ + Q_OBJECT + public: + AppLauncher(QObject* parent, const QVariantList& args); + ~AppLauncher(); + + void init(const KConfigGroup &config); + + void contextEvent(QEvent *event); + QList contextualActions(); + //returns true if something (other than a separator) was successfully added + bool addApp(QMenu *menu, const QString &source); + + public slots: + void switchTo(QAction *action); + + protected: + void makeMenu(); + + private: + KMenu *m_menu; + QAction *m_action; +}; + +K_EXPORT_PLASMA_CONTAINMENTACTIONS(applauncher, AppLauncher) + +#endif diff --git a/plasma/generic/containmentactions/applauncher/plasma-containmentactions-applauncher.desktop b/plasma/generic/containmentactions/applauncher/plasma-containmentactions-applauncher.desktop new file mode 100644 index 00000000..4d108240 --- /dev/null +++ b/plasma/generic/containmentactions/applauncher/plasma-containmentactions-applauncher.desktop @@ -0,0 +1,168 @@ +[Desktop Entry] +Name=Application Launcher +Name[af]=Programlanseerder +Name[ar]=مطلق التطبيقات +Name[ast]=Llanzador d'aplicaciones +Name[be]=Запуск праграмаў +Name[be@latin]=Uklučeńnie aplikacyi +Name[bg]=Стартиране на програми +Name[bn]=অ্যাপলিকেশন লঞ্চার +Name[bn_IN]=অ্যাপ্লিকেশন সঞ্চালনকারী +Name[bs]=pokretač programa +Name[ca]=Llançador d'aplicacions +Name[ca@valencia]=Llançador d'aplicacions +Name[cs]=Spouštěč aplikací +Name[csb]=Zrëszôcz programów +Name[da]=Startmenu +Name[de]=K-Menü +Name[el]=Εκτέλεση εφαρμογών +Name[en_GB]=Application Launcher +Name[eo]=Aplikaĵolanĉilo +Name[es]=Lanzador de aplicaciones +Name[et]=Rakenduste käivitaja +Name[eu]=Aplikazio-abiarazlea +Name[fa]=راه‌انداز برنامه +Name[fi]=Sovelluskäynnistin +Name[fr]=Lanceur d'application +Name[fy]=In applikaashe starter +Name[ga]=Tosaitheoir Feidhmchlár +Name[gl]=Iniciador de programas +Name[gu]=કાર્યક્રમ ચલાવનાર +Name[he]=משגר יישומים +Name[hi]=अनुप्रयोग चालक +Name[hne]=अनुपरयोग चालू करइया +Name[hr]=Pokretač aplikacija +Name[hsb]=Startowar za aplikacije +Name[hu]=Programindító +Name[ia]=Lanceator de application +Name[id]=Peluncur Aplikasi +Name[is]=Forrita-Ræsir +Name[it]=Avviatore di applicazioni +Name[ja]=Kickoff アプリケーションランチャー +Name[kk]=Қолданбаны жегу +Name[km]=កម្មវិធី​ចាប់ផ្ដើម​កម្មវិធី​ +Name[kn]=ಅನ್ವಯ ಪ್ರಕ್ಷೇಪಕ (ಲಾಚರ್) +Name[ko]=프로그램 실행기 +Name[ku]=Deskpêkerê Sepanan +Name[lt]=Programų paleidiklis +Name[lv]=Programmu palaidējs +Name[mai]=अनुप्रयोग चालक +Name[mk]=Стартувач на апликации +Name[ml]=പ്രയോഗവിക്ഷേപിണി +Name[mr]=अनुप्रयोग प्रक्षेपक +Name[nb]=Programstarter +Name[nds]=Programmoproper +Name[ne]=अनुप्रयोक सुरुआतकर्ता +Name[nl]=Programmastarter +Name[nn]=Programstartar +Name[or]=ପ୍ରୟୋଗ ଆରମ୍ଭକର୍ତ୍ତା +Name[pa]=ਐਪਲੀਕੇਸ਼ ਲਾਂਚਰ +Name[pl]=Aktywator programów +Name[pt]=Lançador de Aplicações +Name[pt_BR]=Lançador de aplicativos +Name[ro]=Lansator de aplicații +Name[ru]=Меню запуска приложений +Name[se]=Prográmmaálggaheaddji +Name[si]=යෙදුම් ඇරඹුම +Name[sk]=Spúšťač aplikácií +Name[sl]=Zaganjalnik programov +Name[sr]=покретач програма +Name[sr@ijekavian]=покретач програма +Name[sr@ijekavianlatin]=pokretač programa +Name[sr@latin]=pokretač programa +Name[sv]=Starta program +Name[ta]=பயன்பாடு ஏவி +Name[te]=అనువర్తనం దించునది +Name[tg]=Оғози барномаҳо +Name[th]=ตัวเรียกใช้งานโปรแกรม +Name[tr]=Uygulama Başlatıcısı +Name[ug]=پروگرامما ئىجرا قىلغۇچ +Name[uk]=Інструмент запуску програм +Name[uz]=Dasturlarni ishga tushiruvchi +Name[uz@cyrillic]=Дастурларни ишга туширувчи +Name[vi]=Trình chạy ứng dụng +Name[wa]=Enondeu di programe +Name[x-test]=xxApplication Launcherxx +Name[zh_CN]=程序启动器 +Name[zh_TW]=應用程式啟動器 +Type=Service +Icon=preferences-desktop-launch-feedback +Comment=Simple application launcher +Comment[ar]=مطلق التطبيقات البسيط +Comment[ast]=Llanzador d'aplicaciones simple +Comment[bg]=Стартиране на програми +Comment[bs]=Jednostavan pokretač programa +Comment[ca]=Llançador d'aplicacions senzill +Comment[ca@valencia]=Llançador d'aplicacions senzill +Comment[cs]=Jednoduchý spouštěč aplikací +Comment[csb]=Prosti zrëszôcz programów +Comment[da]=Simpel startmenu +Comment[de]=Einfacher Anwendungsstarter +Comment[el]=Απλή εκτέλεση εφαρμογών +Comment[en_GB]=Simple application launcher +Comment[es]=Lanzador de aplicaciones sencillo +Comment[et]=Lihtne rakenduste käivitaja +Comment[eu]=Aplikazio-abiarazle soila +Comment[fi]=Yksinkertainen sovelluskäynnistin +Comment[fr]=Lanceur simple d'application +Comment[fy]=Ienfâldige applikaasje útfierder +Comment[ga]=Tosaitheoir simplí feidhmchlár +Comment[gl]=Iniciador simple de programas +Comment[he]=משגר יישומים פשוט +Comment[hi]=सरल अनुप्रयोग चालक +Comment[hr]=Jednostavan pokretač aplikacija +Comment[hu]=Egyszerű alkalmazásindító +Comment[ia]=Simple lanceator de application +Comment[id]=Peluncur aplikasi sederhana +Comment[is]=Einfaldur forritaræsir +Comment[it]=Semplice avviatore di applicazioni +Comment[ja]=シンプルなアプリケーションランチャー +Comment[kk]=Қапапайым қолданба жеккіші +Comment[km]=កម្មវិធី​ចាប់ផ្ដើម​កម្មវិធី​សាមញ្ញ​ +Comment[kn]=ಸರಳ ಅನ್ವಯ ಪ್ರಕ್ಷೇಪಕ (ಲಾಂಚರ್) +Comment[ko]=간단한 프로그램 실행기 +Comment[lt]=Paprastas programų paleidiklis +Comment[lv]=Vienkāršs programmu palaidējs +Comment[mk]=Едноставен стартувач на апликации +Comment[ml]=ലളിതമായ പ്രയോഗവിക്ഷേപിണി +Comment[mr]=सोपा अनुप्रयोग प्रक्षेपक +Comment[nb]=Enkel programstarter +Comment[nds]=Eenfach Programmoproper +Comment[nl]=Eenvoudige programmastarter +Comment[nn]=Enkel programstartar +Comment[pa]=ਸਧਾਰਨ ਐਪਲੀਕੇਸ਼ ਲਾਂਚਰ +Comment[pl]=Proste uruchamianie programów +Comment[pt]=Lançador de aplicações simples +Comment[pt_BR]=Lançador de aplicativos simples +Comment[ro]=Lansator de aplicații simplu +Comment[ru]=Упрощённое меню запуска приложений +Comment[si]=සරල යෙදුම් අරඹනය +Comment[sk]=Jednoduchý spúšťač aplikácií +Comment[sl]=Preprost zaganjalnik programov +Comment[sr]=Једноставан покретач програма +Comment[sr@ijekavian]=Једноставан покретач програма +Comment[sr@ijekavianlatin]=Jednostavan pokretač programa +Comment[sr@latin]=Jednostavan pokretač programa +Comment[sv]=Enkel programstart +Comment[tg]=Иҷрогари барномаҳо +Comment[th]=ตัวเรียกใช้งานโปรแกรมพื้นฐาน +Comment[tr]=Basit uygulama başlatıcı +Comment[ug]=ئاددىي پروگرامما ئىجراچىسى +Comment[uk]=Простий інструмент запуску програм +Comment[wa]=Simpe enondeu di programe +Comment[x-test]=xxSimple application launcherxx +Comment[zh_CN]=简易程序启动器 +Comment[zh_TW]=簡單的應用程式啟動器 + +ServiceTypes=Plasma/ContainmentActions + +X-KDE-Library=plasma_containmentactions_applauncher +X-KDE-PluginInfo-Author=Chani +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=applauncher +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + diff --git a/plasma/generic/containmentactions/contextmenu/CMakeLists.txt b/plasma/generic/containmentactions/contextmenu/CMakeLists.txt new file mode 100644 index 00000000..91d1fada --- /dev/null +++ b/plasma/generic/containmentactions/contextmenu/CMakeLists.txt @@ -0,0 +1,18 @@ +project(plasma-containmentactions-contextmenu) + +set(contextmenu_SRCS + menu.cpp +) + +set(krunner_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/krunner/dbus/org.kde.krunner.App.xml) +QT4_ADD_DBUS_INTERFACE(contextmenu_SRCS ${krunner_xml} krunner_interface) + +set(screensaver_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/screenlocker/dbus/org.freedesktop.ScreenSaver.xml) +QT4_ADD_DBUS_INTERFACE(contextmenu_SRCS ${screensaver_xml} screensaver_interface) + + +kde4_add_plugin(plasma_containmentactions_contextmenu ${contextmenu_SRCS}) +target_link_libraries(plasma_containmentactions_contextmenu ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} kworkspace) + +install(TARGETS plasma_containmentactions_contextmenu DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containmentactions-contextmenu.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/containmentactions/contextmenu/Messages.sh b/plasma/generic/containmentactions/contextmenu/Messages.sh new file mode 100755 index 00000000..bc81a943 --- /dev/null +++ b/plasma/generic/containmentactions/contextmenu/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_containmentactions_contextmenu.pot diff --git a/plasma/generic/containmentactions/contextmenu/menu.cpp b/plasma/generic/containmentactions/contextmenu/menu.cpp new file mode 100644 index 00000000..bfd60a12 --- /dev/null +++ b/plasma/generic/containmentactions/contextmenu/menu.cpp @@ -0,0 +1,313 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "menu.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "kworkspace/kworkspace.h" +#include "krunner_interface.h" +#include "screensaver_interface.h" + +#ifdef Q_OS_WIN +#define _WIN32_WINNT 0x0500 // require NT 5.0 (win 2k pro) +#include +#endif // Q_OS_WIN + +ContextMenu::ContextMenu(QObject *parent, const QVariantList &args) + : Plasma::ContainmentActions(parent, args), + m_runCommandAction(0), + m_lockScreenAction(0), + m_logoutAction(0), + m_separator1(0), + m_separator2(0), + m_separator3(0), + m_buttons(0) +{ +} + +ContextMenu::~ContextMenu() +{ +} + +void ContextMenu::init(const KConfigGroup &config) +{ + Plasma::Containment *c = containment(); + Q_ASSERT(c); + + m_actions.clear(); + QHash actions; + QSet disabled; + + if (c->containmentType() == Plasma::Containment::PanelContainment || + c->containmentType() == Plasma::Containment::CustomPanelContainment) { + m_actionOrder << "add widgets" << "_add panel" << "lock widgets" << "_context" << "remove"; + } else { + actions.insert("configure shortcuts", false); + m_actionOrder << "_context" << "_run_command" << "add widgets" << "_add panel" + << "manage activities" << "remove" << "lock widgets" << "_sep1" + <<"_lock_screen" << "_logout" << "_sep2" << "configure" + << "configure shortcuts" << "_sep3" << "_wallpaper"; + disabled.insert("configure shortcuts"); + } + + foreach (const QString &name, m_actionOrder) { + actions.insert(name, !disabled.contains(name)); + } + + QHashIterator it(actions); + while (it.hasNext()) { + it.next(); + m_actions.insert(it.key(), config.readEntry(it.key(), it.value())); + } + + // everything below should only happen once, so check for it + if (c->containmentType() == Plasma::Containment::PanelContainment || + c->containmentType() == Plasma::Containment::CustomPanelContainment) { + //FIXME: panel does its own config action atm... + } else if (!m_runCommandAction) { + m_runCommandAction = new QAction(i18n("Run Command..."), this); + m_runCommandAction->setIcon(KIcon("system-run")); + connect(m_runCommandAction, SIGNAL(triggered(bool)), this, SLOT(runCommand())); + + m_lockScreenAction = new QAction(i18n("Lock Screen"), this); + m_lockScreenAction->setIcon(KIcon("system-lock-screen")); + connect(m_lockScreenAction, SIGNAL(triggered(bool)), this, SLOT(lockScreen())); + + m_logoutAction = new QAction(i18n("Leave..."), this); + m_logoutAction->setIcon(KIcon("system-shutdown")); + connect(m_logoutAction, SIGNAL(triggered(bool)), this, SLOT(startLogout())); + + m_separator1 = new QAction(this); + m_separator1->setSeparator(true); + m_separator2 = new QAction(this); + m_separator2->setSeparator(true); + m_separator3 = new QAction(this); + m_separator3->setSeparator(true); + } +} + +void ContextMenu::contextEvent(QEvent *event) +{ + QList actions = contextualActions(); + if (actions.isEmpty()) { + return; + } + + KMenu desktopMenu; + desktopMenu.addActions(actions); + desktopMenu.adjustSize(); + desktopMenu.exec(popupPosition(desktopMenu.size(), event)); +} + +QList ContextMenu::contextualActions() +{ + Plasma::Containment *c = containment(); + Q_ASSERT(c); + QList actions; + foreach (const QString &name, m_actionOrder) { + if (!m_actions.value(name)) { + continue; + } + + if (name == "_context") { + actions << c->contextualActions(); + } if (name == "_wallpaper") { + if (c->wallpaper()) { + actions << c->wallpaper()->contextualActions(); + } + } else if (QAction *a = action(name)) { + actions << a; + } + } + + return actions; +} + +QAction *ContextMenu::action(const QString &name) +{ + Plasma::Containment *c = containment(); + Q_ASSERT(c); + if (name == "_sep1") { + return m_separator1; + } else if (name == "_sep2") { + return m_separator2; + } else if (name == "_sep3") { + return m_separator3; + } else if (name == "_add panel") { + if (c->corona() && c->corona()->immutability() == Plasma::Mutable) { + return c->corona()->action("add panel"); + } + } else if (name == "_run_command") { + if (KAuthorized::authorizeKAction("run_command")) { + return m_runCommandAction; + } + } else if (name == "_lock_screen") { + if (KAuthorized::authorizeKAction("lock_screen")) { + return m_lockScreenAction; + } + } else if (name == "_logout") { + if (KAuthorized::authorizeKAction("logout")) { + return m_logoutAction; + } + } else if (name == "manage activities") { + if (c->corona()) { + return c->corona()->action("manage activities"); + } + } else { + //FIXME: remove action: make removal of current activity possible + return c->action(name); + } + return 0; +} + +void ContextMenu::runCommand() +{ + if (!KAuthorized::authorizeKAction("run_command")) { + return; + } + + QString interface("org.kde.krunner"); + org::kde::krunner::App krunner(interface, "/App", QDBusConnection::sessionBus()); + krunner.display(); +} + +void ContextMenu::lockScreen() +{ + if (!KAuthorized::authorizeKAction("lock_screen")) { + return; + } + +#ifndef Q_OS_WIN + QString interface("org.freedesktop.ScreenSaver"); + org::freedesktop::ScreenSaver screensaver(interface, "/ScreenSaver", + QDBusConnection::sessionBus()); + if (screensaver.isValid()) { + screensaver.Lock(); + } +#else + LockWorkStation(); +#endif // !Q_OS_WIN +} + +void ContextMenu::startLogout() +{ + // this short delay is due to two issues: + // a) KWorkSpace's DBus alls are all syncronous + // b) the destrution of the menu that this action is in is delayed + // + // (a) leads to the menu hanging out where everyone can see it because + // the even loop doesn't get returned to allowing it to close. + // + // (b) leads to a 0ms timer not working since a 0ms timer just appends to + // the event queue, and then the menu closing event gets appended to that. + // + // ergo a timer with small timeout + QTimer::singleShot(10, this, SLOT(logout())); +} + +void ContextMenu::logout() +{ + if (!KAuthorized::authorizeKAction("logout")) { + return; + } + + KWorkSpace::requestShutDown(); +} + +QWidget* ContextMenu::createConfigurationInterface(QWidget* parent) +{ + QWidget *widget = new QWidget(parent); + QVBoxLayout *lay = new QVBoxLayout(); + widget->setLayout(lay); + widget->setWindowTitle(i18n("Configure Contextual Menu Plugin")); + m_buttons = new QButtonGroup(widget); + m_buttons->setExclusive(false); + + foreach (const QString &name, m_actionOrder) { + QCheckBox *item = 0; + + if (name == "_context") { + item = new QCheckBox(widget); + //FIXME better text + item->setText(i18n("[Other Actions]")); + } else if (name == "_wallpaper") { + item = new QCheckBox(widget); + item->setText(i18n("Wallpaper Actions")); + item->setIcon(KIcon("user-desktop")); + } else if (name == "_sep1" || name =="_sep2" || name == "_sep3") { + item = new QCheckBox(widget); + item->setText(i18n("[Separator]")); + } else { + QAction *a = action(name); + if (a) { + item = new QCheckBox(widget); + item->setText(a->text()); + item->setIcon(a->icon()); + } + } + + if (item) { + item->setChecked(m_actions.value(name)); + item->setProperty("actionName", name); + lay->addWidget(item); + m_buttons->addButton(item); + } + } + + return widget; +} + +void ContextMenu::configurationAccepted() +{ + QList buttons = m_buttons->buttons(); + QListIterator it(buttons); + while (it.hasNext()) { + QAbstractButton *b = it.next(); + if (b) { + m_actions.insert(b->property("actionName").toString(), b->isChecked()); + } + } +} + +void ContextMenu::save(KConfigGroup &config) +{ + QHashIterator it(m_actions); + while (it.hasNext()) { + it.next(); + config.writeEntry(it.key(), it.value()); + } +} + + +#include "menu.moc" diff --git a/plasma/generic/containmentactions/contextmenu/menu.h b/plasma/generic/containmentactions/contextmenu/menu.h new file mode 100644 index 00000000..85cd9de6 --- /dev/null +++ b/plasma/generic/containmentactions/contextmenu/menu.h @@ -0,0 +1,65 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CONTEXTMENU_HEADER +#define CONTEXTMENU_HEADER + +#include +#include + +class ContextMenu : public Plasma::ContainmentActions +{ + Q_OBJECT +public: + ContextMenu(QObject* parent, const QVariantList& args); + ~ContextMenu(); + + void init(const KConfigGroup&); + + void contextEvent(QEvent *event); + QList contextualActions(); + QAction* action(const QString &name); + + QWidget* createConfigurationInterface(QWidget* parent); + void configurationAccepted(); + void save(KConfigGroup &config); + +public slots: + void runCommand(); + void lockScreen(); + void startLogout(); + void logout(); + +private: + QAction *m_runCommandAction; + QAction *m_lockScreenAction; + QAction *m_logoutAction; + QAction *m_separator1; + QAction *m_separator2; + QAction *m_separator3; + + // action name and whether it is enabled or not + QHash m_actions; + QStringList m_actionOrder; + QButtonGroup *m_buttons; +}; + +K_EXPORT_PLASMA_CONTAINMENTACTIONS(contextmenu, ContextMenu) + +#endif diff --git a/plasma/generic/containmentactions/contextmenu/plasma-containmentactions-contextmenu.desktop b/plasma/generic/containmentactions/contextmenu/plasma-containmentactions-contextmenu.desktop new file mode 100644 index 00000000..9db0d321 --- /dev/null +++ b/plasma/generic/containmentactions/contextmenu/plasma-containmentactions-contextmenu.desktop @@ -0,0 +1,149 @@ +[Desktop Entry] +Name=Standard Menu +Name[ar]=القائمة المعيارية +Name[ast]=Menú standard +Name[bg]=Стандартно меню +Name[bs]=standardni meni +Name[ca]=Menú estàndard +Name[ca@valencia]=Menú estàndard +Name[cs]=Standardní nabídka +Name[csb]=Standardowé menu +Name[da]=Standardmenu +Name[de]=Standard-Menü +Name[el]=Τυπικό Μενού +Name[en_GB]=Standard Menu +Name[eo]=Defaŭlta Menuo +Name[es]=Menú estándar +Name[et]=Standardmenüü +Name[eu]=Menu estandarra +Name[fi]=Vakiovalikko +Name[fr]=Menu standard +Name[fy]=Standert menu +Name[ga]=Gnáthroghchlár +Name[gl]=Menú estándar +Name[he]=תפריט רגיל +Name[hi]=मानक मीनु +Name[hr]=Standardni izbornik +Name[hu]=Standard menü +Name[ia]=Menu standard +Name[id]=Menu Standar +Name[is]=Staðalvalmynd +Name[it]=Menu standard +Name[ja]=標準メニュー +Name[ka]=სტანდარტული მენიუ +Name[kk]=Стандартты мәзір +Name[km]=ម៉ឺនុយ​ស្តង់ដារ +Name[kn]=ಶಿಷ್ಟ ಪರಿವಿಡಿ +Name[ko]=표준 메뉴 +Name[lt]=Standartinis meniu +Name[lv]=Konteksta izvēlne +Name[mk]=Стандардно мени +Name[ml]=സ്റ്റാന്‍ഡര്‍ഡ് മെനു +Name[mr]=प्रमाणित मेन्यू +Name[nb]=Standardmeny +Name[nds]=Standardmenü +Name[nl]=Standaardmenu +Name[nn]=Standardmeny +Name[pa]=ਸਟੈਂਡਰਡ ਮੇਨੂ +Name[pl]=Menu standardowe +Name[pt]=Menu Normal +Name[pt_BR]=Menu padrão +Name[ro]=Meniu standard +Name[ru]=Стандартное контекстное меню +Name[si]=සම්මත මෙනුව +Name[sk]=Štandardné menu +Name[sl]=Običajni meni +Name[sr]=стандардни мени +Name[sr@ijekavian]=стандардни мени +Name[sr@ijekavianlatin]=standardni meni +Name[sr@latin]=standardni meni +Name[sv]=Standardmeny +Name[tg]=Менюи стандартӣ +Name[th]=เมนูมาตรฐาน +Name[tr]=Standart Menü +Name[ug]=ئۆلچەملىك تىزىملىك +Name[uk]=Стандартне меню +Name[wa]=Dressêye sitandård +Name[x-test]=xxStandard Menuxx +Name[zh_CN]=标准菜单 +Name[zh_TW]=標準選單 +Comment=The menu that normally shows on right-click +Comment[ar]=القائمة التي تظهر عادة عند الضغط بالزر الأيمن +Comment[ast]=El menú que se suel amosar al calcar col botón derechu +Comment[bg]=Менюто, което обикновено се появява при щракване с десен бутон на мишката +Comment[bs]=Meni koji se obično pokazuje na desni klik +Comment[ca]=Menú que es mostra normalment amb un clic del botó dret +Comment[ca@valencia]=Menú que es mostra normalment amb un clic del botó dret +Comment[cs]=Nabídka která se normálně zobrazuje po stisknutí pravého tlačítka +Comment[csb]=Menu wëskrzëniwóné zwëczajno pò klëkniãcô prawą knąpą +Comment[da]=Menuen der normalt vises ved højreklik +Comment[de]=Das Menü, welches für gewöhnlich durch einen Rechtsklick geöffnet wird +Comment[el]=Το μενού το οποίο εμφανίζεται με δεξί κλικ +Comment[en_GB]=The menu that normally shows on right-click +Comment[eo]=La menuo videblas per dekstra musklako +Comment[es]=El menú que se suele mostrar al hacer clic derecho +Comment[et]=Tavaliselt hiire parema nupu klõpsuga avanev menüü +Comment[eu]=Eskuineko botoiaz klik eginda agertu ohi den menua +Comment[fi]=Valikko, joka tavallisesti näkyy hiiren kakkospainikkeella +Comment[fr]=Le menu s'affichant normalement lors d'un clic droit +Comment[fy]=It menu dat normaal mei rjochts klik ferskynt +Comment[ga]=An roghchlár a thaispeántar tar éis deaschliceáil +Comment[gl]=O menú que se mostra xeralmente ao premer co botón dereito +Comment[he]=התפריט שמופיע בעת לחיצה על הכפתור הימני בעכבר +Comment[hr]=Izbornik koji se obično pojavljuje na desni klik +Comment[hu]=A jobb egérkattintásra megjelenő menü +Comment[ia]=Le menu que normalmente monstra se sur le pression dextere +Comment[id]=Menu yang normalnya muncul saat klik-kanan +Comment[is]=Valmyndin sem kemur venjulega upp við hægrismell +Comment[it]=Il menu che normalmente appare su clic destro +Comment[ja]=通常は右クリックで表示されるメニュー +Comment[kk]=Оң жақ түртімде шыға келетін кәдімгі мәзір +Comment[km]=ម៉ឺនុយ​ដែល​តាម​ធម្មតា​បង្ហាញ​នៅ​ពេល​ចុច​កណ្ដុរ​ស្ដាំ +Comment[kn]=ಸಾಮಾನ್ಯವಾಗಿ ಮೌಸ್‌ನ ಬಲ ಬದಿಯ ಕ್ಲಿಕ್‌ಗೆ ತೆರೆಯುವ ಪರಿವಿಡಿ +Comment[ko]=오른쪽 단추를 눌렀을 때 나타나는 메뉴 +Comment[lt]=Šis meniu paprastai rodomas po pelės dešinio klavišo paspaudimo +Comment[lv]=Izvēlne, kas parasti parādās pēc labā peles klikšķa +Comment[mk]=Менито што обично се појавува на десно кликнување +Comment[ml]=വലത്-ഞെക്കില്‍ സാധാരണ കാണിയ്ക്കുന്ന മെനു +Comment[mr]=उजवी क्लिक केल्यावर सामान्यतः दिसणारा मेन्यू +Comment[nb]=Menyen som vanligvis vises med høyre-klikk +Comment[nds]=Dat Menü, dat Een normalerwies mit de rechte Muustast opropen deit +Comment[nl]=Het menu dat normaal verschijnt bij rechtsklikken +Comment[nn]=Menyen som vanlegvis vert vist ved høgreklikking +Comment[pa]=ਮੇਨੂ, ਜੋ ਕਿ ਸੱਜੇ ਕਲਿੱਕ ਨਾਲ ਦਿਖਾਈ ਦਿੰਦਾ ਹੈ +Comment[pl]=Menu pokazujące się po kliknięciu prawym przyciskiem myszy +Comment[pt]=O menu que aparece normalmente com o botão direito +Comment[pt_BR]=O menu que normalmente aparece ao clicar com o botão direito +Comment[ro]=Meniul ce apare de obicei la clic-dreapta +Comment[ru]=Меню, которое обычно открывается правой кнопкой мыши +Comment[si]=දකුණු-ක්ලික් කිරීමට සාමාන්‍යයෙන් ලැබෙන මෙනුව +Comment[sk]=Menu, ktoré sa zvyčajne zobrazuje po kliknutí pravým tlačidlom myši +Comment[sl]=Meni, ki se običajno prikaže ob desnem kliku +Comment[sr]=Мени који се обично показује на десни клик +Comment[sr@ijekavian]=Мени који се обично показује на десни клик +Comment[sr@ijekavianlatin]=Meni koji se obično pokazuje na desni klik +Comment[sr@latin]=Meni koji se obično pokazuje na desni klik +Comment[sv]=Meny som normalt visas med högerklick +Comment[th]=เมนูปกติที่จะแสดงเมื่อมีการคลิกเมาส์ปุ่มขวา +Comment[tr]=Sağ tıklama ile doğal olarak gösterilen menü +Comment[ug]=چاشقىنەك ئوڭ توپچىسى چېكىلگەندە كۆرۈنىدىغان تىزىملىك +Comment[uk]=Меню, яке буде показано у відповідь на клацання правою кнопкою миші +Comment[wa]=Li dressêye k' on voet normålmint cwand on clitche droet +Comment[x-test]=xxThe menu that normally shows on right-clickxx +Comment[zh_CN]=通常在点击右键时显示的菜单 +Comment[zh_TW]=此選單通常由滑鼠右鍵叫出 +Type=Service +Icon=help-contextual +ServiceTypes=Plasma/ContainmentActions + +X-KDE-Library=plasma_containmentactions_contextmenu +X-KDE-PluginInfo-Author=Chani +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=contextmenu +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-HasConfigurationInterface=true diff --git a/plasma/generic/containmentactions/minimalcontextmenu/CMakeLists.txt b/plasma/generic/containmentactions/minimalcontextmenu/CMakeLists.txt new file mode 100644 index 00000000..66310f93 --- /dev/null +++ b/plasma/generic/containmentactions/minimalcontextmenu/CMakeLists.txt @@ -0,0 +1,11 @@ +project(plasma-containmentactions-minimalcontextmenu) + +set(contextmenu_SRCS + menu.cpp +) + +kde4_add_plugin(plasma_containmentactions_minimalcontextmenu ${contextmenu_SRCS}) +target_link_libraries(plasma_containmentactions_minimalcontextmenu ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_containmentactions_minimalcontextmenu DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containmentactions-minimalcontextmenu.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/containmentactions/minimalcontextmenu/menu.cpp b/plasma/generic/containmentactions/minimalcontextmenu/menu.cpp new file mode 100644 index 00000000..7dfe668e --- /dev/null +++ b/plasma/generic/containmentactions/minimalcontextmenu/menu.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "menu.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include + +ContextMenu::ContextMenu(QObject *parent, const QVariantList &args) + : Plasma::ContainmentActions(parent, args) +{ + m_separator = new QAction(this); + m_separator->setSeparator(true); +} + +ContextMenu::~ContextMenu() +{ +} + +void ContextMenu::contextEvent(QEvent *event) +{ + QList actions = contextualActions(); + if (actions.isEmpty()) { + return; + } + + KMenu desktopMenu; + desktopMenu.addActions(actions); + desktopMenu.adjustSize(); + desktopMenu.exec(popupPosition(desktopMenu.size(), event)); +} + +QList ContextMenu::contextualActions() +{ + Plasma::Containment *c = containment(); + Q_ASSERT(c); + QList actions; + actions << c->contextualActions(); + if (c->wallpaper() && + !c->wallpaper()->contextualActions().isEmpty()) { + actions << m_separator; + actions << c->wallpaper()->contextualActions(); + } + return actions; +} + +#include "menu.moc" diff --git a/plasma/generic/containmentactions/minimalcontextmenu/menu.h b/plasma/generic/containmentactions/minimalcontextmenu/menu.h new file mode 100644 index 00000000..db413ea4 --- /dev/null +++ b/plasma/generic/containmentactions/minimalcontextmenu/menu.h @@ -0,0 +1,43 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CONTEXTMENU_HEADER +#define CONTEXTMENU_HEADER + +#include +#include + +class ContextMenu : public Plasma::ContainmentActions +{ + Q_OBJECT +public: + ContextMenu(QObject* parent, const QVariantList& args); + ~ContextMenu(); + + void contextEvent(QEvent *event); + QList contextualActions(); + +private: + QAction *m_separator; + +}; + +K_EXPORT_PLASMA_CONTAINMENTACTIONS(minimalcontextmenu, ContextMenu) + +#endif diff --git a/plasma/generic/containmentactions/minimalcontextmenu/plasma-containmentactions-minimalcontextmenu.desktop b/plasma/generic/containmentactions/minimalcontextmenu/plasma-containmentactions-minimalcontextmenu.desktop new file mode 100644 index 00000000..a2a8b650 --- /dev/null +++ b/plasma/generic/containmentactions/minimalcontextmenu/plasma-containmentactions-minimalcontextmenu.desktop @@ -0,0 +1,80 @@ +[Desktop Entry] +Name=Minimal Menu +Name[ar]=القائمة المصغرة +Name[ast]=Menú mínimu +Name[bg]=Малко меню +Name[bs]=najmanji meni +Name[ca]=Menú mínim +Name[ca@valencia]=Menú mínim +Name[cs]=Minimální nabídka +Name[da]=Minimal menu +Name[de]=Minimales Menü +Name[el]=Ελάχιστο μενού +Name[en_GB]=Minimal Menu +Name[es]=Menú mínimo +Name[et]=Minimaalne menüü +Name[eu]=Menu minimoa +Name[fi]=Minimaalinen valikko +Name[fr]=Menu minimum +Name[ga]=Roghchlár Íosta +Name[gl]=Menú mínimo +Name[he]=תפריט מינימלי +Name[hi]=न्युतम मीनु +Name[hr]=Minimalni izbornik +Name[hu]=Minimális menü +Name[ia]=Menu minime +Name[id]=Menu Minimal +Name[is]=Lágmarksvalmynd +Name[it]=Menu minimo +Name[ja]=最小メニュー +Name[ka]=მინიმალური მენიუ +Name[kk]=Minimal Menu +Name[km]=ម៉ឺនុយ​អប្បបរមា +Name[kn]=ಅತ್ಯಲ್ಪ ಪರಿವಿಡಿ +Name[ko]=최소 메뉴 +Name[lt]=Minimalistinis meniu +Name[lv]=Minimāla izvēlne +Name[mk]=Минимално мени +Name[mr]=किमान मेन्यू +Name[nb]=Minimal meny +Name[nds]=Minimaalmenü +Name[nl]=Minimaal menu +Name[nn]=Liten meny +Name[pa]=ਘੱਟੋ-ਘੱਟ ਮੈਨੂ +Name[pl]=Menu minimalistyczne +Name[pt]=Menu Mínimo +Name[pt_BR]=Menu Minimalista +Name[ro]=Meniu minim +Name[ru]=Минимальное меню +Name[si]=අවම මෙනුව +Name[sk]=Minimálne menu +Name[sl]=Minimalen meni +Name[sr]=најмањи мени +Name[sr@ijekavian]=најмањи мени +Name[sr@ijekavianlatin]=najmanji meni +Name[sr@latin]=najmanji meni +Name[sv]=Minimal meny +Name[tg]=Менюи хурдтарин +Name[th]=เมนูย่อ +Name[tr]=Basit Menü +Name[ug]=ئەڭ كىچىك تىزىملىك +Name[uk]=Мінімальне меню +Name[wa]=Dressêye å pus ptit +Name[x-test]=xxMinimal Menuxx +Name[zh_CN]=最小化菜单 +Name[zh_TW]=最小化選單 +Type=Service +Icon=help-contextual +ServiceTypes=Plasma/ContainmentActions +NoDisplay=true + +X-KDE-Library=plasma_containmentactions_minimalcontextmenu +X-KDE-PluginInfo-Author=Chani +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=minimalcontextmenu +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL + +X-Plasma-HasConfigurationInterface=false diff --git a/plasma/generic/containmentactions/paste/CMakeLists.txt b/plasma/generic/containmentactions/paste/CMakeLists.txt new file mode 100644 index 00000000..10ce544b --- /dev/null +++ b/plasma/generic/containmentactions/paste/CMakeLists.txt @@ -0,0 +1,11 @@ +project(plasma-containmentactions-paste) + +set(paste_SRCS + paste.cpp +) + +kde4_add_plugin(plasma_containmentactions_paste ${paste_SRCS}) +target_link_libraries(plasma_containmentactions_paste ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_containmentactions_paste DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containmentactions-paste.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/containmentactions/paste/paste.cpp b/plasma/generic/containmentactions/paste/paste.cpp new file mode 100644 index 00000000..c51a6920 --- /dev/null +++ b/plasma/generic/containmentactions/paste/paste.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "paste.h" + +#include +#include + +#include + +Paste::Paste(QObject *parent, const QVariantList &args) + : Plasma::ContainmentActions(parent, args) +{ +} + +void Paste::contextEvent(QEvent *event) +{ + QPointF scenePos; + QPoint screenPos; + switch (event->type()) { + case QEvent::GraphicsSceneMousePress: + event->accept(); + return; + case QEvent::GraphicsSceneMouseRelease: { + QGraphicsSceneMouseEvent *e = static_cast(event); + scenePos = e->scenePos(); + screenPos = e->screenPos(); + break; } + case QEvent::GraphicsSceneWheel: { + QGraphicsSceneWheelEvent *e = static_cast(event); + scenePos = e->scenePos(); + screenPos = e->screenPos(); + break; } + default: //can't get the pos + return; + } + paste(scenePos, screenPos); +} + +#include "paste.moc" diff --git a/plasma/generic/containmentactions/paste/paste.h b/plasma/generic/containmentactions/paste/paste.h new file mode 100644 index 00000000..8a91da38 --- /dev/null +++ b/plasma/generic/containmentactions/paste/paste.h @@ -0,0 +1,36 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PASTE_HEADER +#define PASTE_HEADER + +#include + +class Paste : public Plasma::ContainmentActions +{ + Q_OBJECT + public: + Paste(QObject* parent, const QVariantList& args); + + void contextEvent(QEvent *event); +}; + +K_EXPORT_PLASMA_CONTAINMENTACTIONS(paste, Paste) + +#endif diff --git a/plasma/generic/containmentactions/paste/plasma-containmentactions-paste.desktop b/plasma/generic/containmentactions/paste/plasma-containmentactions-paste.desktop new file mode 100644 index 00000000..2c00688c --- /dev/null +++ b/plasma/generic/containmentactions/paste/plasma-containmentactions-paste.desktop @@ -0,0 +1,149 @@ +[Desktop Entry] +Name=Paste +Name[ar]=ألصِق +Name[ast]=Apegar +Name[bg]=Поставяне +Name[bn]=পেস্ট +Name[bs]=naljepljivanje +Name[ca]=Enganxa +Name[ca@valencia]=Apega +Name[cs]=Vložit +Name[csb]=Wlepi +Name[da]=Indsæt +Name[de]=Einfügen +Name[el]=Επικόλληση +Name[en_GB]=Paste +Name[eo]=Glui +Name[es]=Pegar +Name[et]=Asetamine +Name[eu]=Itsatsi +Name[fa]=چسباندن +Name[fi]=Liitä +Name[fr]=Coller +Name[fy]=Plakke +Name[ga]=Greamaigh +Name[gl]=Apegar +Name[gu]=ચોટાડો +Name[he]=הדבקה +Name[hi]=चिपकाएँ +Name[hr]=Umetni +Name[hu]=Beillesztés +Name[ia]=Colla +Name[id]=Tempel +Name[is]=Líma +Name[it]=Incolla +Name[ja]=貼り付け +Name[kk]=Орналастыру +Name[km]=បិទភ្ជាប់ +Name[kn]=ಅಂಟಿಸು +Name[ko]=붙여넣기 +Name[lt]=Įterpti +Name[lv]=Ielīmēt +Name[ml]=ഒട്ടിയ്ക്കുക +Name[mr]=चिटकवा +Name[nb]=Lim inn +Name[nds]=Infögen +Name[nl]=Plakken +Name[nn]=Tekstbitar +Name[pa]=ਚੇਪੋ +Name[pl]=Wklej +Name[pt]=Colar +Name[pt_BR]=Colar +Name[ro]=Lipește +Name[ru]=Вставка текста +Name[si]=අලවන්න +Name[sk]=Vložiť +Name[sl]=Lepljenje +Name[sr]=налепљивање +Name[sr@ijekavian]=наљепљивање +Name[sr@ijekavianlatin]=naljepljivanje +Name[sr@latin]=nalepljivanje +Name[sv]=Klistra in +Name[tg]=Часпондан +Name[th]=วาง +Name[tr]=Yapıştır +Name[ug]=چاپلا +Name[uk]=Вставка +Name[wa]=Aclaper +Name[x-test]=xxPastexx +Name[zh_CN]=粘贴 +Name[zh_TW]=貼上 +Type=Service +Icon=edit-paste +Comment=Creates a widget from the contents of the clipboard +Comment[ar]=أنشئ ودجة من محتويات الحافظة +Comment[ast]=Crea un elementu gráficu colos conteníos del cartafueyu +Comment[bg]=Създаване на джаджа със съдържанието на системния буфер +Comment[bs]=Stvara grafičku kontrolu na osnovu sadržaja klipborda +Comment[ca]=Crea un estri a partir del contingut del porta-retalls +Comment[ca@valencia]=Crea un estri a partir del contingut del porta-retalls +Comment[cs]=Vytvoří widget z obsahu schránky +Comment[da]=Opretter en widget ud fra indholdet af udklipsholderen +Comment[de]=Erzeugt ein Miniprogramm aus dem Inhalt der Zwischenablage +Comment[el]=Δημιουργία γραφικού συστατικού από τα περιεχόμενα του προχείρου. +Comment[en_GB]=Creates a widget from the contents of the clipboard +Comment[eo]=Krei fenestraĵon el la enhavo de la tondejo +Comment[es]=Crea un elemento gráfico con los contenidos del portapapeles +Comment[et]=Vidina loomine lõikepuhvri sisu põhjal +Comment[eu]=Trepeta bat sortzen du arbelaren edukiarekin +Comment[fi]=Luo käyttöliittymäelementin leikepöydän sisällöstä +Comment[fr]=Crée un composant graphique à partir du contenu du presse-papier +Comment[fy]=Makket in widget fan de ynhâld fan in klamboerd +Comment[ga]=Cruthaíonn sé giuirléid ó inneachar na gearrthaisce +Comment[gl]=Crea un widget a partir do contido do portarretallos +Comment[he]=משמש ליצירת ווידג׳ט מתוכן לוח העריכה +Comment[hr]=Stvara widget iz sadržaja međuspremnika +Comment[hu]=Készít egy widgetet a vágólap tartalmából +Comment[ia]=Il crea elemento graphic (Widget) ex le contentos del area de transferentia (clipboard) +Comment[id]=Membuat widget dari isi papan klip +Comment[is]=Búa til græju úr innihaldi klippispjaldsins +Comment[it]=Crea un oggetto dai contenuti degli appunti +Comment[ja]=クリップボードの内容からウィジェットを作成します +Comment[kk]=Алмасу буферіндегісінен виджетті құру +Comment[km]=បង្កើត​ធាតុក្រាហ្វិក​ពី​មាតិកា​របស់​ក្ដារតម្បៀតខ្ទាស់ +Comment[kn]=ನಕಲುಫಲಕದಲ್ಲಿರುವ (ಕ್ಲಿಪ್‌ಬೋರ್ಡ್) ವಿಷಯಗಳಿಂದ ಒಂದು ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟವನ್ನು(ವಿಡ್ಗೆಟ್) ನಿರ್ಮಿಸುತ್ತದೆ +Comment[ko]=클립보드 내용을 기반으로 위젯을 만듭니다 +Comment[lt]=Sukuria valdiklį iš laikinosios atmintinės turinio +Comment[lv]=Izveido sīkrīku no starpliktuves satura +Comment[ml]=ഓര്‍മ്മച്ചെപ്പിലെ ഉള്ളടക്കങ്ങള്‍ കൊണ്ട് ഒരു ഉരുപ്പടിയുണ്ടാക്കുന്നു +Comment[mr]=क्लिपबोर्ड मधील मजकूरावरुन विजेट बनवितो +Comment[nb]=Lager et skjermelement av innholdet fra utklippstavla +Comment[nds]=Stellt ut den Twischenaflaag-Inholt en Lüttprogramm op +Comment[nl]=Maakt een widget aan uit de inhoud van het klembord +Comment[nn]=Lag eit element frå innhaldet på utklippstavla +Comment[pa]=ਕਲਿੱਪਬੋਰਡ ਦੀ ਸਮੱਗਰੀ ਤੋਂ ਵਿਦਜੈੱਟ ਬਣਾਉ +Comment[pl]=Tworzy element interfejsu z zawartości schowka +Comment[pt]=Cria um elemento a partir do conteúdo da área de transferência +Comment[pt_BR]=Cria um widget a partir do conteúdo da área de transferência +Comment[ro]=Creează un control din conținutul clipboard-ului +Comment[ru]=Создание виджета с содержимым буфера обмена +Comment[si]=ක්ලිප් පුවරුවේ අන්තර්‍ගතය භාවිතයෙන් විජෙට්ටුවක් නිර්‍මාණය කරන්න +Comment[sk]=Vytvorí widget z obsahu schránky +Comment[sl]=Ustvari gradnik iz vsebine odložišča +Comment[sr]=Ствара виџет на основу садржаја клипборда +Comment[sr@ijekavian]=Ствара виџет на основу садржаја клипборда +Comment[sr@ijekavianlatin]=Stvara vidžet na osnovu sadržaja klipborda +Comment[sr@latin]=Stvara vidžet na osnovu sadržaja klipborda +Comment[sv]=Skapa komponent från klippbordets innehåll +Comment[th]=สร้างวิดเจ็ตจากเนื้อหาของคลิปบอร์ด +Comment[tr]=Pano içeriğininden bir gereç oluşturur +Comment[ug]=چاپلاش تاختىدىكى مەزمۇندىن widget قۇرىدۇ +Comment[uk]=Створює віджет з вмістом буфера обміну даними +Comment[vi]=Tạo một widget từ nội dung của bảng nhớ tạm +Comment[wa]=Ahive ene ahesse avou ç' k' i gn a e presse-papî +Comment[x-test]=xxCreates a widget from the contents of the clipboardxx +Comment[zh_CN]=从剪贴板内容中创建部件 +Comment[zh_TW]=從剪貼簿內容建立一元件 + +ServiceTypes=Plasma/ContainmentActions + +X-KDE-Library=plasma_containmentactions_paste +X-KDE-PluginInfo-Author=Chani +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=paste +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + diff --git a/plasma/generic/containmentactions/switchactivity/CMakeLists.txt b/plasma/generic/containmentactions/switchactivity/CMakeLists.txt new file mode 100644 index 00000000..dee043c7 --- /dev/null +++ b/plasma/generic/containmentactions/switchactivity/CMakeLists.txt @@ -0,0 +1,12 @@ +project(plasma-containmentactions-switchactivity) +include_directories(${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kworkspace) + +set(switchactivity_SRCS + switch.cpp +) + +kde4_add_plugin(plasma_containmentactions_switchactivity ${switchactivity_SRCS}) +target_link_libraries(plasma_containmentactions_switchactivity ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} kworkspace) + +install(TARGETS plasma_containmentactions_switchactivity DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containmentactions-switchactivity.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/containmentactions/switchactivity/Messages.sh b/plasma/generic/containmentactions/switchactivity/Messages.sh new file mode 100755 index 00000000..3c54a526 --- /dev/null +++ b/plasma/generic/containmentactions/switchactivity/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_containmentactions_switchactivity.pot diff --git a/plasma/generic/containmentactions/switchactivity/plasma-containmentactions-switchactivity.desktop b/plasma/generic/containmentactions/switchactivity/plasma-containmentactions-switchactivity.desktop new file mode 100644 index 00000000..073516a8 --- /dev/null +++ b/plasma/generic/containmentactions/switchactivity/plasma-containmentactions-switchactivity.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +Name=Switch Activity +Name[ar]=بدّل النشاط +Name[ast]=Camudar xera +Name[bg]=Превключване на дейност +Name[bs]=prebacivanje aktivnosti +Name[ca]=Canvi d'activitat +Name[ca@valencia]=Canvi d'activitat +Name[cs]=Přepnout aktivitu +Name[da]=Skift aktivitet +Name[de]=Aktivität wechseln +Name[el]=Εναλλαγή δραστηριότητας +Name[en_GB]=Switch Activity +Name[eo]=Ŝalti Aktivecon +Name[es]=Cambiar actividad +Name[et]=Tegevuse vahetamine +Name[eu]=Jardueraz aldatu +Name[fi]=Vaihda aktiviteettia +Name[fr]=Changer d'activité +Name[fy]=Aktiviteit wikselje +Name[ga]=Athraigh Gníomhaíocht +Name[gl]=Trocar de actividade +Name[he]=מחליף פעילות +Name[hi]=क्रिया बदलें +Name[hr]=Prebaci aktivnost +Name[hu]=Aktivitásváltás +Name[ia]=Commuta activitate +Name[id]=Aktivitas Pindah +Name[is]=Skipta um virkni +Name[it]=Cambia attività +Name[ja]=アクティビティを切り替え +Name[kk]=Белсенділікті ауыстыру +Name[km]=ប្ដូរ​សកម្មភាព +Name[kn]=ಚಟುವಟಿಕೆಯನ್ನು ಬದಲಾಯಿಸು +Name[ko]=활동 전환 +Name[lt]=Pakeisti veiklą +Name[lv]=Pārslēgt aktivitāti +Name[mk]=Смени активност +Name[ml]=പ്രക്രിയ മാറ്റുക +Name[mr]=वेगळ्या कार्यपध्दती वर जा +Name[nb]=Bytt aktivitet +Name[nds]=Aktiviteet wesseln +Name[nl]=Activiteit omschakelen +Name[nn]=Byt aktivitet +Name[pa]=ਐਕਟਵਿਟੀ ਬਦਲੋ +Name[pl]=Przełącz działanie +Name[pt]=Mudar de Actividade +Name[pt_BR]=Alternar atividade +Name[ro]=Comutare activitate +Name[ru]=Переключение комнат +Name[si]=කාර්‍යය මාරුකරන්න +Name[sk]=Prepnúť aktivitu +Name[sl]=Preklapljanje med dejavnostmi +Name[sr]=пребацивање активности +Name[sr@ijekavian]=пребацивање активности +Name[sr@ijekavianlatin]=prebacivanje aktivnosti +Name[sr@latin]=prebacivanje aktivnosti +Name[sv]=Byt aktivitet +Name[tg]=Мубодилаи амалиёт +Name[th]=สลับกิจกรรม +Name[tr]=Etkinlik Değiştir +Name[ug]=پائالىيەت ئالماشتۇر +Name[uk]=Перемкнути простір дій +Name[wa]=Potchî a ene ôte activité +Name[x-test]=xxSwitch Activityxx +Name[zh_CN]=切换活动 +Name[zh_TW]=切換活動 +Type=Service +Icon=dashboard-show +Comment=Switch to another activity +Comment[ar]=بدّل إلى نشاط آخر +Comment[ast]=Camudar a otra xera +Comment[bg]=Превключване към друга дейност +Comment[bs]=Prebacuje na drugu aktivnost +Comment[ca]=Canvia a una altra activitat +Comment[ca@valencia]=Canvia a una altra activitat +Comment[cs]=Přepnout na jinou aktivitu +Comment[da]=Skift til en anden aktivitet +Comment[de]=Ermöglich Ihnen, zu einer anderen Aktivität zu wechseln +Comment[el]=Εναλλαγή σε μία άλλη δραστηριότητα +Comment[en_GB]=Switch to another activity +Comment[eo]=Ŝalti al alia aktiveco +Comment[es]=Cambiar a otra actividad +Comment[et]=Lülitumine teisele tegevusele +Comment[eu]=Aldatu beste jarduera batera +Comment[fi]=Vaihda toiseen aktiviteettiin +Comment[fr]=Passe à une autre activité +Comment[fy]=Nei in oare aktiviteit wikselje +Comment[ga]=Roghnaigh gníomhaíocht eile +Comment[gl]=Troca de actividade +Comment[he]=משמש למעבר בין פעילות +Comment[hr]=Prebaci na drugu aktivnost +Comment[hu]=Váltás másik aktivitásra +Comment[ia]=Commuta a altere activitate +Comment[id]=Pindah ke aktivitas lain +Comment[is]=Skipta í aðra virkni +Comment[it]=Passa ad un'altra attività +Comment[ja]=他のアクティビティに切り替えます +Comment[kk]=Басқа белсенділігіне ауысу +Comment[km]=ប្ដូរ​ទៅ​សកម្មភាព​ផ្សេង +Comment[kn]=ಬೇರೊಂದು ಚಟುವಟಿಕೆಗೆ ಬದಲಾಯಿಸು +Comment[ko]=다른 활동으로 전환합니다 +Comment[lt]=Persijungti į kitą veiklą +Comment[lv]=Pārslēgties uz citu aktivitāti +Comment[mk]=Се префрла на друга активност +Comment[ml]=മറ്റൊരു പ്രക്രിയിലേയ്ക്കുള്ള മാറ്റം +Comment[mr]=वेगळ्या कार्यपध्दती वर जा +Comment[nb]=Bytt til en annen aktivitet +Comment[nds]=Na en anner Aktiviteet wesseln +Comment[nl]=Schakel naar een andere activiteit +Comment[nn]=Byt til ein annan aktivitet +Comment[pa]=ਹੋਰ ਐਕਟਵਿਟੀ ਲਈ ਬਦਲੋ +Comment[pl]=Przełącz do innego działania +Comment[pt]=Mudar para outra actividade +Comment[pt_BR]=Alterna para outra atividade +Comment[ro]=Comută la altă activitate +Comment[ru]=Переключение на другую комнату +Comment[si]=වෙනත් කාර්‍යයකට මාරුවන්න +Comment[sk]=Prepne na inú aktivitu +Comment[sl]=Preklapljanje med razpoložljivimi dejavnostmi +Comment[sr]=Пребацује на другу активност +Comment[sr@ijekavian]=Пребацује на другу активност +Comment[sr@ijekavianlatin]=Prebacuje na drugu aktivnost +Comment[sr@latin]=Prebacuje na drugu aktivnost +Comment[sv]=Byt till en annan aktivitet +Comment[tg]=Мубодила ба дигар амалиёт +Comment[th]=สลับไปยังกิจกรรมอื่น ๆ +Comment[tr]=Başka bir etkinliğe geç +Comment[ug]=باشقا بىر پائالىيەتكە ئالماشتۇر +Comment[uk]=Перемкнутися на інший простір дій +Comment[wa]=Potchî a ene ôte activité +Comment[x-test]=xxSwitch to another activityxx +Comment[zh_CN]=切换到另一个活动 +Comment[zh_TW]=切換到其它活動 + +ServiceTypes=Plasma/ContainmentActions + +X-KDE-Library=plasma_containmentactions_switchactivity +X-KDE-PluginInfo-Author=Chani +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=switchactivity +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + diff --git a/plasma/generic/containmentactions/switchactivity/switch.cpp b/plasma/generic/containmentactions/switchactivity/switch.cpp new file mode 100644 index 00000000..a97c5262 --- /dev/null +++ b/plasma/generic/containmentactions/switchactivity/switch.cpp @@ -0,0 +1,223 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "switch.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QWeakPointer) + +SwitchActivity::SwitchActivity(QObject *parent, const QVariantList &args) + : Plasma::ContainmentActions(parent, args), + m_menu(new KMenu()), + m_action(new QAction(this)) +{ + //This is an awful hack, but I need to keep the old behaviour for plasma-netbook + //while using the new activity API for plasma-desktop. + //TODO 4.6 convert netbook to the activity API so we won't need this + m_useNepomuk = (qApp->applicationName() == "plasma-desktop"); + + connect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(switchTo(QAction*))); + + m_action->setMenu(m_menu); + m_menu->setTitle(i18n("Activities")); +} + +SwitchActivity::~SwitchActivity() +{ + delete m_menu; +} + +void SwitchActivity::contextEvent(QEvent *event) +{ + switch (event->type()) { + case QEvent::GraphicsSceneMousePress: + contextEvent(static_cast(event)); + break; + case QEvent::GraphicsSceneWheel: + wheelEvent(static_cast(event)); + break; + default: + break; + } +} + +void SwitchActivity::makeMenu() +{ + m_menu->clear(); + m_menu->addTitle(i18n("Activities")); + + if (m_useNepomuk) { + Plasma::DataEngine *engine = dataEngine("org.kde.activities"); + if (!engine->isValid()) { + return; + } + + Plasma::DataEngine::Data data = engine->query("Status"); + QStringList activities = data["Running"].toStringList(); + foreach (const QString& id, activities) { + Plasma::DataEngine::Data data = engine->query(id); + QAction *action = m_menu->addAction(KIcon(data["Icon"].toString()), data["Name"].toString()); + action->setData(QVariant(id)); + if (data["Current"].toBool()) { + action->setEnabled(false); + } + } + } else { + Plasma::Containment *myCtmt = containment(); + if (!myCtmt) { + return; + } + + Plasma::Corona *c = myCtmt->corona(); + if (!c) { + return; + } + + QList containments = c->containments(); + foreach (Plasma::Containment *ctmt, containments) { + if (ctmt->containmentType() == Plasma::Containment::PanelContainment || + ctmt->containmentType() == Plasma::Containment::CustomPanelContainment || + c->offscreenWidgets().contains(ctmt)) { + continue; + } + + QString name = ctmt->activity(); + if (name.isEmpty()) { + name = ctmt->name(); + } + QAction *action = m_menu->addAction(name); + action->setData(QVariant::fromValue >(QWeakPointer(ctmt))); + + //WARNING this assumes the plugin will only ever be set on activities, not panels! + if (ctmt == myCtmt) { + action->setEnabled(false); + } + } + } + + m_menu->adjustSize(); +} + +void SwitchActivity::contextEvent(QGraphicsSceneMouseEvent *event) +{ + makeMenu(); + m_menu->exec(popupPosition(m_menu->size(), event)); +} + +QList SwitchActivity::contextualActions() +{ + makeMenu(); + + QList list; + list << m_action; + return list; +} + +void SwitchActivity::switchTo(QAction *action) +{ + if (m_useNepomuk) { + QString id = action->data().toString(); + Plasma::Service *service = dataEngine("org.kde.activities")->serviceForSource(id); + KConfigGroup op = service->operationDescription("setCurrent"); + Plasma::ServiceJob *job = service->startOperationCall(op); + connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater())); + } else { + QWeakPointer ctmt = action->data().value >(); + if (!ctmt) { + return; + } + Plasma::Containment *myCtmt = containment(); + if (!myCtmt) { + return; + } + + ctmt.data()->setScreen(myCtmt->screen(), myCtmt->desktop()); + } +} + +void SwitchActivity::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + int step = (event->delta() < 0) ? 1 : -1; + + if (m_useNepomuk) { + Plasma::DataEngine *engine = dataEngine("org.kde.activities"); + if (!engine->isValid()) { + return; + } + + Plasma::DataEngine::Data data = engine->query("Status"); + QStringList list = data["Running"].toStringList(); + QString current = data["Current"].toString(); + int start = list.indexOf(current); + int next = (start + step + list.size()) % list.size(); + + Plasma::Service *service = engine->serviceForSource(list.at(next)); + KConfigGroup op = service->operationDescription("setCurrent"); + Plasma::ServiceJob *job = service->startOperationCall(op); + connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater())); + return; + } + + Plasma::Containment *myCtmt = containment(); + if (!myCtmt) { + return; + } + + Plasma::Corona *c = myCtmt->corona(); + if (!c) { + return; + } + + QList containments = c->containments(); + int start = containments.indexOf(myCtmt); + int i = (start + step + containments.size()) % containments.size(); + + //FIXME we *really* need a proper way to cycle through activities + while (i != start) { + Plasma::Containment *ctmt = containments.at(i); + if (ctmt->containmentType() == Plasma::Containment::PanelContainment || + ctmt->containmentType() == Plasma::Containment::CustomPanelContainment || + c->offscreenWidgets().contains(ctmt)) { + //keep looking + i = (i + step + containments.size()) % containments.size(); + } else { + break; + } + } + + Plasma::Containment *ctmt = containments.at(i); + if (ctmt && ctmt != myCtmt) { + ctmt->setScreen(myCtmt->screen(), myCtmt->desktop()); + } +} + + +#include "switch.moc" diff --git a/plasma/generic/containmentactions/switchactivity/switch.h b/plasma/generic/containmentactions/switchactivity/switch.h new file mode 100644 index 00000000..e3807283 --- /dev/null +++ b/plasma/generic/containmentactions/switchactivity/switch.h @@ -0,0 +1,52 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SWITCHACTIVITY_HEADER +#define SWITCHACTIVITY_HEADER + +#include + +class QAction; +class KMenu; + +class SwitchActivity : public Plasma::ContainmentActions +{ + Q_OBJECT + public: + SwitchActivity(QObject* parent, const QVariantList& args); + ~SwitchActivity(); + + void contextEvent(QEvent *event); + void contextEvent(QGraphicsSceneMouseEvent *event); + void wheelEvent(QGraphicsSceneWheelEvent *event); + QList contextualActions(); + + private slots: + void switchTo(QAction *action); + void makeMenu(); + + private: + KMenu *m_menu; + QAction *m_action; + bool m_useNepomuk; +}; + +K_EXPORT_PLASMA_CONTAINMENTACTIONS(switchactivity, SwitchActivity) + +#endif diff --git a/plasma/generic/containmentactions/switchdesktop/CMakeLists.txt b/plasma/generic/containmentactions/switchdesktop/CMakeLists.txt new file mode 100644 index 00000000..c6f30da6 --- /dev/null +++ b/plasma/generic/containmentactions/switchdesktop/CMakeLists.txt @@ -0,0 +1,11 @@ +project(plasma-containmentactions-switchdesktop) + +set(switchdesktop_SRCS + desktop.cpp +) + +kde4_add_plugin(plasma_containmentactions_switchdesktop ${switchdesktop_SRCS}) +target_link_libraries(plasma_containmentactions_switchdesktop ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_containmentactions_switchdesktop DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containmentactions-switchdesktop.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/containmentactions/switchdesktop/Messages.sh b/plasma/generic/containmentactions/switchdesktop/Messages.sh new file mode 100755 index 00000000..de79ab5e --- /dev/null +++ b/plasma/generic/containmentactions/switchdesktop/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_containmentactions_switchdesktop.pot diff --git a/plasma/generic/containmentactions/switchdesktop/desktop.cpp b/plasma/generic/containmentactions/switchdesktop/desktop.cpp new file mode 100644 index 00000000..6844985b --- /dev/null +++ b/plasma/generic/containmentactions/switchdesktop/desktop.cpp @@ -0,0 +1,112 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "desktop.h" + +#include +#include + +#include +#include +#include + +SwitchDesktop::SwitchDesktop(QObject *parent, const QVariantList &args) + : Plasma::ContainmentActions(parent, args), + m_menu(new KMenu()), + m_action(new QAction(this)) +{ + m_menu->setTitle(i18n("Virtual Desktops")); + connect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(switchTo(QAction*))); + + m_action->setMenu(m_menu); +} + +SwitchDesktop::~SwitchDesktop() +{ + delete m_menu; +} + +void SwitchDesktop::contextEvent(QEvent *event) +{ + switch (event->type()) { + case QEvent::GraphicsSceneMousePress: + contextEvent(static_cast(event)); + break; + case QEvent::GraphicsSceneWheel: + wheelEvent(static_cast(event)); + break; + default: + break; + } +} + +void SwitchDesktop::makeMenu() +{ + m_menu->clear(); + m_menu->addTitle(i18n("Virtual Desktops")); + const int numDesktops = KWindowSystem::numberOfDesktops(); + const int currentDesktop = KWindowSystem::currentDesktop(); + + for (int i = 1; i <= numDesktops; ++i) { + QString name = KWindowSystem::desktopName(i); + QAction *action = m_menu->addAction(QString("%1: %2").arg(i).arg(name)); + action->setData(i); + if (i == currentDesktop) { + action->setEnabled(false); + } + } + + m_menu->adjustSize(); +} + +void SwitchDesktop::contextEvent(QGraphicsSceneMouseEvent *event) +{ + makeMenu(); + m_menu->exec(popupPosition(m_menu->size(), event)); +} + +QList SwitchDesktop::contextualActions() +{ + makeMenu(); + QList list; + list << m_action; + return list; +} + +void SwitchDesktop::switchTo(QAction *action) +{ + const int desktop = action->data().toInt(); + KWindowSystem::setCurrentDesktop(desktop); +} + +void SwitchDesktop::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + kDebug() << event->orientation() << event->delta(); + const int numDesktops = KWindowSystem::numberOfDesktops(); + const int currentDesktop = KWindowSystem::currentDesktop(); + + if (event->delta() < 0) { + KWindowSystem::setCurrentDesktop(currentDesktop % numDesktops + 1); + } else { + KWindowSystem::setCurrentDesktop((numDesktops + currentDesktop - 2) % numDesktops + 1); + } +} + + +#include "desktop.moc" diff --git a/plasma/generic/containmentactions/switchdesktop/desktop.h b/plasma/generic/containmentactions/switchdesktop/desktop.h new file mode 100644 index 00000000..8834da8a --- /dev/null +++ b/plasma/generic/containmentactions/switchdesktop/desktop.h @@ -0,0 +1,53 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SWITCHDESKTOP_HEADER +#define SWITCHDESKTOP_HEADER + +#include + +class QAction; +class KMenu; + +class SwitchDesktop : public Plasma::ContainmentActions +{ + Q_OBJECT + public: + SwitchDesktop(QObject* parent, const QVariantList& args); + ~SwitchDesktop(); + + void contextEvent(QEvent *event); + void contextEvent(QGraphicsSceneMouseEvent *event); + void wheelEvent(QGraphicsSceneWheelEvent *event); + QList contextualActions(); + + private: + void makeMenu(); + + private slots: + void switchTo(QAction *action); + + private: + KMenu *m_menu; + QAction *m_action; +}; + +K_EXPORT_PLASMA_CONTAINMENTACTIONS(switchdesktop, SwitchDesktop) + +#endif diff --git a/plasma/generic/containmentactions/switchdesktop/plasma-containmentactions-switchdesktop.desktop b/plasma/generic/containmentactions/switchdesktop/plasma-containmentactions-switchdesktop.desktop new file mode 100644 index 00000000..13583c0c --- /dev/null +++ b/plasma/generic/containmentactions/switchdesktop/plasma-containmentactions-switchdesktop.desktop @@ -0,0 +1,150 @@ +[Desktop Entry] +Name=Switch Desktop +Name[ar]=بدّل سطح المكتب +Name[ast]=Camudar escritoriu +Name[bg]=Превключване на работен плот +Name[bn]=অন্য ডেস্কটপ +Name[bs]=prebacivanje površi +Name[ca]=Canvi d'escriptori +Name[ca@valencia]=Canvi d'escriptori +Name[cs]=Přepnout plochu +Name[da]=Skift skrivebord +Name[de]=Arbeitsfläche wechseln +Name[el]=Εναλλαγή Επιφάνειας εργασίας +Name[en_GB]=Switch Desktop +Name[eo]=Ŝalti Labortablon +Name[es]=Cambiar escritorio +Name[et]=Töölaua vahetamine +Name[eu]=Aldatu mahaigainez +Name[fi]=Vaihda työpöytää +Name[fr]=Changer de bureau +Name[fy]=Buroblêd wikselje +Name[ga]=Athraigh an Deasc +Name[gl]=Trocar de escritorio +Name[gu]=ડેસ્કટોપ બદલો +Name[he]=מחליף שולחנות עבודה +Name[hi]=डेस्कटॉप बदलें +Name[hr]=Prebaci radnu površinu +Name[hu]=Asztalváltás +Name[ia]=Commuta scriptorio +Name[id]=Pindah Desktop +Name[is]=Skipta um skjáborð +Name[it]=Cambia desktop +Name[ja]=デスクトップを切り替え +Name[kk]=Жұмыс үстелді ауыстыру +Name[km]=ប្ដូរ​ផ្ទៃតុ +Name[kn]=ಗಣಕತೆರೆಯನ್ನು ಬದಲಾಯಿಸು +Name[ko]=데스크톱 전환 +Name[lt]=Pakeisti darbastalį +Name[lv]=Pārslēgt darbvirsmu +Name[mk]=Смени раб. површина +Name[ml]=പണിയിടം മാറുക +Name[mr]=वेगळ्या डेस्कटॉप वर जा +Name[nb]=Bytt skrivebord +Name[nds]=Schriefdisch wesseln +Name[nl]=Bureaublad omschakelen +Name[nn]=Byt skrivebord +Name[pa]=ਡੈਸਕਟਾਪ ਬਦਲੋ +Name[pl]=Przełącz pulpit +Name[pt]=Mudar de Ecrã +Name[pt_BR]=Alternar área de trabalho +Name[ro]=Comutare birou +Name[ru]=Переключение рабочих столов +Name[si]=වැඩතලය මාරුකරන්න +Name[sk]=Prepnúť plochu +Name[sl]=Preklapljanje med namizji +Name[sr]=пребацивање површи +Name[sr@ijekavian]=пребацивање површи +Name[sr@ijekavianlatin]=prebacivanje površi +Name[sr@latin]=prebacivanje površi +Name[sv]=Byt skrivbord +Name[tg]=Мубодилаи мизи корӣ +Name[th]=สลับพื้นที่ทำงาน +Name[tr]=Masaüstünü Değiştir +Name[ug]=ئۈستەلئۈستى ئالماشتۇر +Name[uk]=Перемкнути стільницю +Name[wa]=Potchî a èn ôte sicribanne +Name[x-test]=xxSwitch Desktopxx +Name[zh_CN]=切换桌面 +Name[zh_TW]=切換桌面 +Type=Service +Icon=user-desktop +Comment=Switch to another virtual desktop +Comment[ar]=بدّل إلى سطح مكتب افتراضي آخر +Comment[ast]=Camudar a otru escritoriu virtual +Comment[bg]=Превключване към друг работен плот +Comment[bs]=Prebacuje na drugu virtuelnu površ +Comment[ca]=Canvia a un altre escriptori virtual +Comment[ca@valencia]=Canvia a un altre escriptori virtual +Comment[cs]=Přepnout na jinou virtuální plochu +Comment[da]=Skift til et andet virtuelt skrivebord +Comment[de]=Ermöglicht Ihnen, zu einer anderen virtuellen Arbeitsfläche zu wechseln. +Comment[el]=Εναλλαγή σε μία άλλη εικονική επιφάνειας εργασίας +Comment[en_GB]=Switch to another virtual desktop +Comment[eo]=Ŝalti al alia virtuala labortablo +Comment[es]=Cambiar a otro escritorio virtual +Comment[et]=Lülitumine teisele virtuaalsele töölauale +Comment[eu]=Aldatu beste alegiazko mahaigain batera +Comment[fi]=Vaihda toiseen virtuaalityöpöytään +Comment[fr]=Passe à un autre bureau virtuel +Comment[fy]=Nei in oare firuele buroblêd wikselje +Comment[ga]=Athraigh an deasc fhíorúil +Comment[gl]=Troca para outro escritorio virtual +Comment[he]=משמש למעבר לשולחן עבודה וירטואלי אחר +Comment[hi]=दूसरे आभासी डेस्कटॉप्स पर स्विच करें +Comment[hr]=Prebaci na drugu virtualnu radnu površinu +Comment[hu]=Váltás másik virtuális asztalra +Comment[ia]=Commuta a altere scriptorio virtual +Comment[id]=Berpindah ke desktop virtual lain +Comment[is]=Skiptir milli sýndarskjáborða +Comment[it]=Passa ad un altro desktop virtuale +Comment[ja]=他の仮想デスクトップに切り替えます +Comment[kk]=Басқа виртуалды үстелге ауысу +Comment[km]=ប្ដូរ​ទៅ​ផ្ទៃតុ​និម្មិត​ផ្សេង​ទៀត +Comment[kn]=ಮತ್ತೊಂದು ವಾಸ್ತವಪ್ರಾಯ ಗಣಕತೆರೆಗೆ ಬದಲಾಯಿಸು +Comment[ko]=다른 가상 데스크톱으로 전환합니다 +Comment[lt]=Pereiti į kitą virtualų darbastalį +Comment[lv]=Pārslēgties uz citu virtuālo darbvirsmu +Comment[mk]=Менување на друга виртуелна раб. површина +Comment[ml]=മറ്റൊരു മായാ പണിയിടത്തിലേയ്ക്കു് മാറുക +Comment[mr]=वेगळ्या आभासी डेस्कटॉप वर जा +Comment[nb]=Bytt til et annet virtuelt skrivebord +Comment[nds]=Na en anner Schriefdischen wesseln +Comment[nl]=Schakel naar een andere virtueel bureaublad +Comment[nn]=Byt til eit anna virtuelt skrivebord +Comment[pa]=ਵੁਰਚੁਅਲ ਡੈਸਕਟਾਪਾਂ ਵਿੱਚ ਸਵਿੱਚ ਕਰੋ +Comment[pl]=Przełączenie między wirtualnymi pulpitami +Comment[pt]=Mudar para outro ecrã virtual +Comment[pt_BR]=Alterna para outra área de trabalho +Comment[ro]=Comută la alt birou virtual +Comment[ru]=Переключение на другой рабочий стол +Comment[si]=වෙනත් අතත්‍ය වැඩතලයක් වෙත මාරුවන්න +Comment[sk]=Prepne na inú virtuálnu plochu +Comment[sl]=Preklapljanje med navideznimi namizji +Comment[sr]=Пребацује на другу виртуелну површ +Comment[sr@ijekavian]=Пребацује на другу виртуелну површ +Comment[sr@ijekavianlatin]=Prebacuje na drugu virtuelnu površ +Comment[sr@latin]=Prebacuje na drugu virtuelnu površ +Comment[sv]=Byt till ett annat virtuellt skrivbord +Comment[tg]=Мубодилаи мизи кориҳои виртуалӣ +Comment[th]=สลับไปยังพื้นที่ทำงานเสมือนตัวอื่น ๆ +Comment[tr]=Başka bir sanal masaüstüne geç +Comment[ug]=باشقا بىر مەۋھۇم ئۈستەلئۈستىگە ئالماشتۇر +Comment[uk]=Перемкнутися на іншу віртуальну стільницю +Comment[wa]=Potchî a èn ôte forveyou scribanne +Comment[x-test]=xxSwitch to another virtual desktopxx +Comment[zh_CN]=切换到另一个虚拟桌面 +Comment[zh_TW]=切換到其它虛擬桌面 + +ServiceTypes=Plasma/ContainmentActions + +X-KDE-Library=plasma_containmentactions_switchdesktop +X-KDE-PluginInfo-Author=Chani +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=switchdesktop +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + diff --git a/plasma/generic/containmentactions/switchwindow/CMakeLists.txt b/plasma/generic/containmentactions/switchwindow/CMakeLists.txt new file mode 100644 index 00000000..1e9f2bfe --- /dev/null +++ b/plasma/generic/containmentactions/switchwindow/CMakeLists.txt @@ -0,0 +1,12 @@ +project(plasma-containmentactions-switchwindow) + +set(switchwindow_SRCS + switch.cpp +) +kde4_add_ui_files(switchwindow_SRCS config.ui) + +kde4_add_plugin(plasma_containmentactions_switchwindow ${switchwindow_SRCS}) +target_link_libraries(plasma_containmentactions_switchwindow ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_containmentactions_switchwindow DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containmentactions-switchwindow.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/containmentactions/switchwindow/Messages.sh b/plasma/generic/containmentactions/switchwindow/Messages.sh new file mode 100755 index 00000000..7f28e587 --- /dev/null +++ b/plasma/generic/containmentactions/switchwindow/Messages.sh @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma_containmentactions_switchwindow.pot diff --git a/plasma/generic/containmentactions/switchwindow/config.ui b/plasma/generic/containmentactions/switchwindow/config.ui new file mode 100644 index 00000000..a3b6b120 --- /dev/null +++ b/plasma/generic/containmentactions/switchwindow/config.ui @@ -0,0 +1,38 @@ + + Config + + + + 0 + 0 + 388 + 108 + + + + + + + Display all windows in one list + + + + + + + Display a submenu for each desktop + + + + + + + Display only the current desktop's windows + + + + + + + + diff --git a/plasma/generic/containmentactions/switchwindow/plasma-containmentactions-switchwindow.desktop b/plasma/generic/containmentactions/switchwindow/plasma-containmentactions-switchwindow.desktop new file mode 100644 index 00000000..52e913a8 --- /dev/null +++ b/plasma/generic/containmentactions/switchwindow/plasma-containmentactions-switchwindow.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +Name=Switch Window +Name[ar]=بدّل النافذة +Name[ast]=Camudar ventana +Name[bg]=Превключване на прозорци +Name[bs]=prebacivanje prozora +Name[ca]=Canvi de finestra +Name[ca@valencia]=Canvi de finestra +Name[cs]=Přepnout okna +Name[da]=Skift vindue +Name[de]=Fenster wechseln +Name[el]=Εναλλαγή παραθύρου +Name[en_GB]=Switch Window +Name[eo]=Ŝalti fenestron +Name[es]=Cambiar ventana +Name[et]=Akna vahetamine +Name[eu]=Aldatu leihoz +Name[fi]=Vaihda ikkunaa +Name[fr]=Changer de fenêtre +Name[fy]=Finster wikselje +Name[ga]=Athraigh an Fhuinneog +Name[gl]=Tocar de xanela +Name[he]=מחליף חלונות +Name[hi]=विंडो बदलें +Name[hr]=Prebaci prozor +Name[hu]=Ablakváltás +Name[ia]=Commuta fenestra +Name[id]=Pindah Jendela +Name[is]=Skipta um glugga +Name[it]=Cambia finestra +Name[ja]=ウィンドウを切り替え +Name[kk]=Терезені ауыстыру +Name[km]=ប្ដូរ​បង្អួច +Name[kn]=ಕಿಟಿಕಿಯನ್ನು ಬದಲಾಯಿಸು +Name[ko]=창 전환 +Name[lt]=Pakeisti langą +Name[lv]=Pārslēgt logu +Name[mk]=Смени прозорец +Name[ml]=ജാലകം മാറുക +Name[mr]=वेगळ्या चौकट वर जा +Name[nb]=Bytt vindu +Name[nds]=Finster wesseln +Name[nl]=Venster omschakelen +Name[nn]=Byt vindauge +Name[pa]=ਵਿੰਡੋ ਬਦਲੋ +Name[pl]=Przełącz okno +Name[pt]=Mudar de Janela +Name[pt_BR]=Alternar janela +Name[ro]=Comutare fereastră +Name[ru]=Переключение окон +Name[si]=කවුළුව මාරුකරන්න +Name[sk]=Prepnúť okno +Name[sl]=Preklapljanje med okni +Name[sr]=пребацивање прозора +Name[sr@ijekavian]=пребацивање прозора +Name[sr@ijekavianlatin]=prebacivanje prozora +Name[sr@latin]=prebacivanje prozora +Name[sv]=Byt fönster +Name[tg]=Мубодилаи тирезаҳо +Name[th]=สลับหน้าต่าง +Name[tr]=Pencereyi Değiştir +Name[ug]=كۆزنەك ئالماشتۇر +Name[uk]=Перемкнути вікно +Name[wa]=Passer a ene ôte finiesse +Name[x-test]=xxSwitch Windowxx +Name[zh_CN]=切换窗口 +Name[zh_TW]=切換視窗 +Type=Service +Icon=preferences-system-windows +Comment=Show a list of windows to switch to +Comment[ar]=أظهر لائحة بالنوافذ للانتقال لإحداها +Comment[ast]=Amosar una llista de ventanes a les que camudar +Comment[bg]=Списък с прозорци за превключване +Comment[bs]=Pokazuje spisak prozora za prebacivanje +Comment[ca]=Mostra una llista de les finestres per a canviar +Comment[ca@valencia]=Mostra una llista de les finestres per a canviar +Comment[cs]=Zobrazit seznam oken k přepnutí +Comment[da]=Vis en liste over åbne vinduer at skifte til +Comment[de]=Eine Liste aller Fenster anzeigen +Comment[el]=Εμφάνιση λίστας παραθύρων για εναλλαγή +Comment[en_GB]=Show a list of windows to switch to +Comment[eo]=Montri liston de festestro por komuti +Comment[es]=Mostrar una lista de ventanas a las que cambiar +Comment[et]=Võimalike akende loendi näitamine +Comment[eu]=Erakutsi hauta ditzakezun leihoen zerrenda bat +Comment[fi]=Näytä luettelo ikkunoista, joihin voi vaihtaa +Comment[fr]=Affiche une liste de fenêtres pouvant être activées +Comment[fy]=Lit in list sjen mei finsters om nei ta te wikseljen +Comment[gl]=Mostrar unha lista de xanelas ás que pode ir +Comment[he]=משמש להצגת רשימת חלונות שניתן לעבור אליהם +Comment[hr]=Prikaži listu prozora na koju se moguće prebaciti +Comment[hu]=Ablakok listájának megjelenítése váltáshoz +Comment[ia]=Monstra un lista de fenestras ubi commutar +Comment[id]=Tampilkan senarai jendela yang akan dipindahkan +Comment[is]=Sýna lista yfir glugga sem hægt er að skipta yfir í +Comment[it]=Mostra un elenco di finestre a cui passare +Comment[ja]=他のウィンドウに切り替えるためにウィンドウのリストを表示します +Comment[kk]=Ауысатын терезелер тізімін ұсыну +Comment[km]=បង្ហាញ​បញ្ជី​បង្អួច​ដើម្បី​ផ្លាស់ប្ដូរ +Comment[kn]=ವಿಂಡೊವನ್ನು ಬದಲಾಯಿಸಲು ವಿಂಡೊಗಳ ಒಂದು ಪಟ್ಟಿಯನ್ನು ತೋರಿಸು +Comment[ko]=전환할 수 있는 창 목록을 표시합니다 +Comment[lt]=Rodo langų, į kuriuos galima rodyti, sąrašą +Comment[lv]=Pārādīt logu sarakstu uz ko pārslēgties +Comment[mk]=Прикажува листа на прозорци во кои може да се префрлите +Comment[ml]=മാറാവുന്ന ജാലകങ്ങളടെ പട്ടിക കാണിയ്ക്കുക +Comment[mr]=वेगळ्या चौकट वर जाण्यासाठी यादी दर्शवा +Comment[nb]=Vis en liste over vinduer som kan byttes til +Comment[nds]=Finstern oplisten un dor henwesseln +Comment[nl]=Toon een lijst met vensters waarnaar om te schakelen +Comment[nn]=Vis ei oversikt over vindauge å byta til +Comment[pa]=ਬਦਲਣ ਲਈ ਵਿੰਡੋਜ਼ ਦੀ ਲਿਸਟ ਵੇਖੋ +Comment[pl]=Pokazanie listy okien, na które można się przełączyć +Comment[pt]=Mostrar uma lista com as janelas para onde mudar +Comment[pt_BR]=Exibe uma lista de janelas para alternar +Comment[ro]=Arată o listă de ferestre de comutat +Comment[ru]=Показать список окон +Comment[si]=මාරුවීම සඳහා කවුළු ලැයිස්තුව පෙන්වන්න +Comment[sk]=Zobrazenie zoznamu okien na prepnutie +Comment[sl]=Prikaže seznam oken na katere je mogoče preklopiti +Comment[sr]=Показује списак прозора за пребацивање +Comment[sr@ijekavian]=Показује списак прозора за пребацивање +Comment[sr@ijekavianlatin]=Pokazuje spisak prozora za prebacivanje +Comment[sr@latin]=Pokazuje spisak prozora za prebacivanje +Comment[sv]=Visa en lista med fönster att byta till +Comment[th]=แสดงรายการของหน้าต่างที่สามารถจะสลับไปใช้ได้ +Comment[tr]=Değiştirilecek pencereler listesini göster +Comment[ug]=كۆزنەك ئالماشتۇرۇشقا ئىشلىتىدىغان تىزىمنى كۆرسىتىدۇ +Comment[uk]=Показує список вікон для перемикання +Comment[wa]=Mostrer ene djivêye des fniesse k' on sait potchî dvins +Comment[x-test]=xxShow a list of windows to switch toxx +Comment[zh_CN]=显示可供切换的窗口列表 +Comment[zh_TW]=列出視窗並切換 + +ServiceTypes=Plasma/ContainmentActions + +X-KDE-Library=plasma_containmentactions_switchwindow +X-KDE-PluginInfo-Author=Chani +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=switchwindow +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-HasConfigurationInterface=true + diff --git a/plasma/generic/containmentactions/switchwindow/switch.cpp b/plasma/generic/containmentactions/switchwindow/switch.cpp new file mode 100644 index 00000000..593b91c6 --- /dev/null +++ b/plasma/generic/containmentactions/switchwindow/switch.cpp @@ -0,0 +1,264 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "switch.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +SwitchWindow::SwitchWindow(QObject *parent, const QVariantList &args) + : Plasma::ContainmentActions(parent, args), + m_menu(new KMenu()), + m_action(new QAction(this)), + m_mode(AllFlat), + m_clearOrderTimer(0) +{ + m_menu->setTitle(i18n("Windows")); + connect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(switchTo(QAction*))); + + m_action->setMenu(m_menu); +} + +SwitchWindow::~SwitchWindow() +{ + delete m_menu; +} + +void SwitchWindow::init(const KConfigGroup &config) +{ + m_mode = (MenuMode)config.readEntry("mode", (int)AllFlat); +} + +QWidget* SwitchWindow::createConfigurationInterface(QWidget* parent) +{ + QWidget *widget = new QWidget(parent); + m_ui.setupUi(widget); + widget->setWindowTitle(i18n("Configure Switch Window Plugin")); + switch (m_mode) { + case AllFlat: + m_ui.flatButton->setChecked(true); + break; + case DesktopSubmenus: + m_ui.subButton->setChecked(true); + break; + case CurrentDesktop: + m_ui.curButton->setChecked(true); + break; + } + return widget; +} + +void SwitchWindow::configurationAccepted() +{ + if (m_ui.flatButton->isChecked()) { + m_mode = AllFlat; + } else if (m_ui.subButton->isChecked()) { + m_mode = DesktopSubmenus; + } else { + m_mode = CurrentDesktop; + } +} + +void SwitchWindow::save(KConfigGroup &config) +{ + config.writeEntry("mode", (int)m_mode); +} + +void SwitchWindow::contextEvent(QEvent *event) +{ + switch (event->type()) { + case QEvent::GraphicsSceneMousePress: + contextEvent(static_cast(event)); + break; + case QEvent::GraphicsSceneWheel: + wheelEvent(static_cast(event)); + break; + default: + break; + } +} + +void SwitchWindow::makeMenu() +{ + m_menu->clear(); + Plasma::DataEngine *tasks = dataEngine("tasks"); + if (!tasks->isValid()) { + return; + } + + QMultiHash desktops; + + //make all the window actions + foreach (const QString &source, tasks->sources()) { + Plasma::DataEngine::Data window = tasks->query(source); + if (window.value("startup").toBool()) { + //kDebug() << "skipped fake task" << source; + continue; + } + if (!window.value("onCurrentActivity").toBool()) { + continue; + } + + QString name = window.value("visibleNameWithState").toString(); + if (name.isEmpty()) { + kDebug() << "failed source" << source; + continue; + } + + QAction *action = new QAction(name, m_menu); + action->setIcon(window.value("icon").value()); + action->setData(source); + desktops.insert(window.value("desktop").toInt(), action); + } + + //sort into menu + if (m_mode == CurrentDesktop) { + int currentDesktop = KWindowSystem::currentDesktop(); + m_menu->addTitle(i18n("Windows")); + m_menu->addActions(desktops.values(currentDesktop)); + m_menu->addActions(desktops.values(-1)); + } else { + int numDesktops = KWindowSystem::numberOfDesktops(); + if (m_mode == AllFlat) { + for (int i = 1; i <= numDesktops; ++i) { + if (desktops.contains(i)) { + QString name = KWindowSystem::desktopName(i); + name = QString("%1: %2").arg(i).arg(name); + m_menu->addTitle(name); + m_menu->addActions(desktops.values(i)); + } + } + if (desktops.contains(-1)) { + m_menu->addTitle(i18n("All Desktops")); + m_menu->addActions(desktops.values(-1)); + } + } else { //submenus + for (int i = 1; i <= numDesktops; ++i) { + if (desktops.contains(i)) { + QString name = KWindowSystem::desktopName(i); + name = QString("%1: %2").arg(i).arg(name); + KMenu *subMenu = new KMenu(name, m_menu); + subMenu->addActions(desktops.values(i)); + m_menu->addMenu(subMenu); + } + } + if (desktops.contains(-1)) { + KMenu *subMenu = new KMenu(i18n("All Desktops"), m_menu); + subMenu->addActions(desktops.values(-1)); + m_menu->addMenu(subMenu); + } + } + } + + m_menu->adjustSize(); +} + +void SwitchWindow::contextEvent(QGraphicsSceneMouseEvent *event) +{ + makeMenu(); + if (!m_menu->isEmpty()) { + m_menu->exec(popupPosition(m_menu->size(), event)); + } +} + +QList SwitchWindow::contextualActions() +{ + makeMenu(); + QList list; + list << m_action; + return list; +} + +void SwitchWindow::switchTo(QAction *action) +{ + QString source = action->data().toString(); + kDebug() << source; + Plasma::Service *service = dataEngine("tasks")->serviceForSource(source); + if (service) { + service->startOperationCall(service->operationDescription("activateRaiseOrIconify")); + } +} + +void SwitchWindow::clearWindowsOrder() +{ + kDebug() << "CLEARING>......................."; + m_windowsOrder.clear(); +} + +void SwitchWindow::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + //TODO somehow find the "next" or "previous" window + //without changing hte window order (don't want to always go between two windows) + if (m_windowsOrder.isEmpty()) { + m_windowsOrder = KWindowSystem::stackingOrder(); + } else { + if (!m_clearOrderTimer) { + m_clearOrderTimer = new QTimer(this); + connect(m_clearOrderTimer, SIGNAL(timeout()), this, SLOT(clearWindowsOrder())); + m_clearOrderTimer->setSingleShot(true); + m_clearOrderTimer->setInterval(1000); + } + + m_clearOrderTimer->start(); + } + + const WId activeWindow = KWindowSystem::activeWindow(); + const bool up = event->delta() > 0; + bool next = false; + WId first = 0; + WId last = 0; + for (int i = 0; i < m_windowsOrder.count(); ++i) { + const WId id = m_windowsOrder.at(i); + const KWindowInfo info(id, NET::WMDesktop | NET::WMVisibleName | NET::WMWindowType); + if (info.windowType(NET::NormalMask | NET::DialogMask | NET::UtilityMask) != -1 && info.isOnCurrentDesktop()) { + if (next) { + KWindowSystem::forceActiveWindow(id); + return; + } + + if (first == 0) { + first = id; + } + + if (id == activeWindow) { + if (up) { + next = true; + } else if (last) { + KWindowSystem::forceActiveWindow(last); + return; + } + } + + last = id; + } + } + + KWindowSystem::forceActiveWindow(up ? first : last); +} + + +#include "switch.moc" diff --git a/plasma/generic/containmentactions/switchwindow/switch.h b/plasma/generic/containmentactions/switchwindow/switch.h new file mode 100644 index 00000000..fee0334f --- /dev/null +++ b/plasma/generic/containmentactions/switchwindow/switch.h @@ -0,0 +1,71 @@ +/* + * Copyright 2009 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SWITCHWINDOW_HEADER +#define SWITCHWINDOW_HEADER + +#include "ui_config.h" +#include + +class QAction; +class QTimer; +class KMenu; + +class SwitchWindow : public Plasma::ContainmentActions +{ + Q_OBJECT + public: + SwitchWindow(QObject* parent, const QVariantList& args); + ~SwitchWindow(); + + void init(const KConfigGroup &config); + QWidget* createConfigurationInterface(QWidget* parent); + void configurationAccepted(); + void save(KConfigGroup &config); + + void contextEvent(QEvent *event); + void contextEvent(QGraphicsSceneMouseEvent *event); + void wheelEvent(QGraphicsSceneWheelEvent *event); + QList contextualActions(); + + private: + void makeMenu(); + + private slots: + void clearWindowsOrder(); + void switchTo(QAction *action); + + private: + enum MenuMode { + AllFlat = 0, + DesktopSubmenus, + CurrentDesktop + }; + + KMenu *m_menu; + QAction *m_action; + Ui::Config m_ui; + MenuMode m_mode; + QTimer *m_clearOrderTimer; + QList m_windowsOrder; +}; + +K_EXPORT_PLASMA_CONTAINMENTACTIONS(switchwindow, SwitchWindow) + +#endif diff --git a/plasma/generic/dataengines/CMakeLists.txt b/plasma/generic/dataengines/CMakeLists.txt new file mode 100644 index 00000000..d240683d --- /dev/null +++ b/plasma/generic/dataengines/CMakeLists.txt @@ -0,0 +1,44 @@ +add_subdirectory(applicationjobs) +add_subdirectory(activities) +add_subdirectory(apps) +add_subdirectory(devicenotifications) +add_subdirectory(dict) +add_subdirectory(executable) +add_subdirectory(favicons) +add_subdirectory(filebrowser) +add_subdirectory(geolocation) +add_subdirectory(hotplug) +add_subdirectory(keystate) +add_subdirectory(mpris2) +#add_subdirectory(network) +add_subdirectory(notifications) +# KDE5: remove the nowplaying engine +add_subdirectory(nowplaying) +add_subdirectory(places) +add_subdirectory(powermanagement) +add_subdirectory(soliddevice) +add_subdirectory(time) +add_subdirectory(weather) +add_subdirectory(statusnotifieritem) +add_subdirectory(share) + +if (NepomukCore_FOUND AND Soprano_FOUND) + add_subdirectory(metadata) +endif () + +if(Boost_FOUND AND KdepimLibs_FOUND) + if(Akonadi_FOUND) + add_subdirectory(akonadi) + endif(Akonadi_FOUND) + add_subdirectory(calendar) + add_subdirectory(rss) +endif(Boost_FOUND AND KdepimLibs_FOUND) + +if(NOT WIN32) + add_subdirectory(mouse) + add_subdirectory(systemmonitor) + if(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop") + add_subdirectory(tasks) + endif(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop") +endif(NOT WIN32) + diff --git a/plasma/generic/dataengines/Mainpage.dox b/plasma/generic/dataengines/Mainpage.dox new file mode 100644 index 00000000..52dcca06 --- /dev/null +++ b/plasma/generic/dataengines/Mainpage.dox @@ -0,0 +1,10 @@ +/** +* @mainpage Engines +* +* Plasma engines power widgets. +* +*/ + +// DOXYGEN_SET_PROJECT_NAME = Engines +// DOXYGEN_SET_RECURSIVE = YES +// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/plasma/generic/dataengines/activities/ActivityData.cpp b/plasma/generic/dataengines/activities/ActivityData.cpp new file mode 100644 index 00000000..d98e8c1e --- /dev/null +++ b/plasma/generic/dataengines/activities/ActivityData.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 Ivan Cukic + * + * 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) any later version, 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; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "ActivityData.h" + +#include +#include + +class ActivityDataStaticInit { +public: + ActivityDataStaticInit() + { + qDBusRegisterMetaType < ActivityData > (); + qDBusRegisterMetaType < QList < ActivityData > > (); + } + + static ActivityDataStaticInit _instance; + +}; + +ActivityDataStaticInit ActivityDataStaticInit::_instance; + +ActivityData::ActivityData() +{ +} + +ActivityData::ActivityData(const ActivityData & source) +{ + score = source.score; + id = source.id; +} + +ActivityData & ActivityData::operator = (const ActivityData & source) +{ + if (&source != this) { + score = source.score; + id = source.id; + } + + return *this; +} + +QDBusArgument & operator << (QDBusArgument & arg, const ActivityData r) +{ + arg.beginStructure(); + + arg << r.id; + arg << r.score; + + arg.endStructure(); + + return arg; +} + +const QDBusArgument & operator >> (const QDBusArgument & arg, ActivityData & r) +{ + arg.beginStructure(); + + arg >> r.id; + arg >> r.score; + + arg.endStructure(); + + return arg; +} + +QDebug operator << (QDebug dbg, const ActivityData & r) +{ + dbg << "ActivityData(" << r.score << r.id << ")"; + return dbg.space(); +} diff --git a/plasma/generic/dataengines/activities/ActivityData.h b/plasma/generic/dataengines/activities/ActivityData.h new file mode 100644 index 00000000..a36e85a2 --- /dev/null +++ b/plasma/generic/dataengines/activities/ActivityData.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 Ivan Cukic + * + * 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) any later version, 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; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ACTIVITY_DATA_H_ +#define ACTIVITY_DATA_H_ + +#include +#include +#include +#include + +class ActivityData { +public: + ActivityData(); + ActivityData(const ActivityData & source); + ActivityData & operator = (const ActivityData & source); + + double score; + QString id; + +}; + +typedef QList ActivityDataList; +Q_DECLARE_METATYPE(ActivityData) +Q_DECLARE_METATYPE(ActivityDataList) + +QDBusArgument & operator << (QDBusArgument & arg, const ActivityData); +const QDBusArgument & operator >> (const QDBusArgument & arg, ActivityData & rec); + +QDebug operator << (QDebug dbg, const ActivityData & r); + +#endif // ACTIVITY_DATA_H_ diff --git a/plasma/generic/dataengines/activities/CMakeLists.txt b/plasma/generic/dataengines/activities/CMakeLists.txt new file mode 100644 index 00000000..068d07a1 --- /dev/null +++ b/plasma/generic/dataengines/activities/CMakeLists.txt @@ -0,0 +1,28 @@ +project(activityengine) + +set(activity_engine_SRCS + ActivityData.cpp + activityengine.cpp + activityservice.cpp + activityjob.cpp) + +set_source_files_properties(org.kde.ActivityManager.ActivityRanking.xml PROPERTIES INCLUDE "ActivityData.h") +qt4_add_dbus_interface( + activity_engine_SRCS org.kde.ActivityManager.ActivityRanking.xml + ActivityRankingInterface + ) + +kde4_add_plugin(plasma_engine_activities ${activity_engine_SRCS}) +target_link_libraries(plasma_engine_activities + ${KDE4_KDECORE_LIBS} + ${KDE4_PLASMA_LIBS} + ${KACTIVITIES_LIBRARY}) + +install(TARGETS plasma_engine_activities + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-engine-activities.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) + +install(FILES activities.operations + DESTINATION ${DATA_INSTALL_DIR}/plasma/services) diff --git a/plasma/generic/dataengines/activities/activities.operations b/plasma/generic/dataengines/activities/activities.operations new file mode 100644 index 00000000..c438c506 --- /dev/null +++ b/plasma/generic/dataengines/activities/activities.operations @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/activities/activityengine.cpp b/plasma/generic/dataengines/activities/activityengine.cpp new file mode 100644 index 00000000..2774a01c --- /dev/null +++ b/plasma/generic/dataengines/activities/activityengine.cpp @@ -0,0 +1,270 @@ +/* + * Copyright 2010 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "activityengine.h" +#include "activityservice.h" +#include "ActivityRankingInterface.h" + +#include +#include + +#include +#include + +#define ACTIVITYMANAGER_SERVICE "org.kde.kactivitymanagerd" +#define ACTIVITYRANKING_OBJECT "/ActivityRanking" + +ActivityEngine::ActivityEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) +{ + Q_UNUSED(args); +} + +void ActivityEngine::init() +{ + if (qApp->applicationName() == "plasma-netbook") { + //hack for the netbook + //FIXME can I read a setting or something instead? + } else { + m_activityController = new KActivities::Controller(this); + m_currentActivity = m_activityController->currentActivity(); + QStringList activities = m_activityController->listActivities(); + //setData("allActivities", activities); + foreach (const QString &id, activities) { + insertActivity(id); + } + + connect(m_activityController, SIGNAL(activityAdded(QString)), this, SLOT(activityAdded(QString))); + connect(m_activityController, SIGNAL(activityRemoved(QString)), this, SLOT(activityRemoved(QString))); + connect(m_activityController, SIGNAL(currentActivityChanged(QString)), this, SLOT(currentActivityChanged(QString))); + + //some convenience sources for times when checking every activity source would suck + //it starts with _ so that it can easily be filtered out of sources() + //maybe I should just make it not included in sources() instead? + m_runningActivities = m_activityController->listActivities(KActivities::Info::Running); + setData("Status", "Current", m_currentActivity); + setData("Status", "Running", m_runningActivities); + + m_watcher = new QDBusServiceWatcher( + ACTIVITYMANAGER_SERVICE, + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForRegistration + | QDBusServiceWatcher::WatchForUnregistration, + this); + + connect(m_watcher, SIGNAL(serviceRegistered(QString)), + this, SLOT(enableRanking())); + connect(m_watcher, SIGNAL(serviceUnregistered(QString)), + this, SLOT(disableRanking())); + + if (QDBusConnection::sessionBus().interface()->isServiceRegistered(ACTIVITYMANAGER_SERVICE)) { + enableRanking(); + } + } +} + +void ActivityEngine::insertActivity(const QString &id) +{ + //id -> name, icon, state + KActivities::Info *activity = new KActivities::Info(id, this); + m_activities[id] = activity; + setData(id, "Name", activity->name()); + setData(id, "Icon", activity->icon()); + setData(id, "Current", m_currentActivity == id); + setData(id, "Encrypted", false); + + QString state; + switch (activity->state()) { + case KActivities::Info::Running: + state = "Running"; + break; + case KActivities::Info::Starting: + state = "Starting"; + break; + case KActivities::Info::Stopping: + state = "Stopping"; + break; + case KActivities::Info::Stopped: + state = "Stopped"; + break; + case KActivities::Info::Invalid: + default: + state = "Invalid"; + } + setData(id, "State", state); + setData(id, "Score", m_activityScores.value(id)); + + connect(activity, SIGNAL(infoChanged()), this, SLOT(activityDataChanged())); + connect(activity, SIGNAL(stateChanged(KActivities::Info::State)), this, SLOT(activityStateChanged())); + + m_runningActivities << id; +} + +void ActivityEngine::disableRanking() +{ + delete m_activityRankingClient; +} + +void ActivityEngine::enableRanking() +{ + m_activityRankingClient = new org::kde::ActivityManager::ActivityRanking( + ACTIVITYMANAGER_SERVICE, + ACTIVITYRANKING_OBJECT, + QDBusConnection::sessionBus() + ); + connect(m_activityRankingClient, SIGNAL(rankingChanged(QStringList,ActivityDataList)), + this, SLOT(rankingChanged(QStringList,ActivityDataList))); + + QDBusMessage msg = QDBusMessage::createMethodCall(ACTIVITYMANAGER_SERVICE, + ACTIVITYRANKING_OBJECT, + "org.kde.ActivityManager.ActivityRanking", + "activities"); + QDBusPendingReply reply = QDBusConnection::sessionBus().asyncCall(msg); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(activityScoresReply(QDBusPendingCallWatcher*))); +} + +void ActivityEngine::activityScoresReply(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply reply = *watcher; + if (reply.isError()) { + kDebug() << "Error getting activity scores: " << reply.error().message(); + } else { + setActivityScores(reply.value()); + } + + watcher->deleteLater(); +} + +void ActivityEngine::rankingChanged(const QStringList &topActivities, const ActivityDataList &activities) +{ + Q_UNUSED(topActivities) + + setActivityScores(activities); +} + +void ActivityEngine::setActivityScores(const ActivityDataList &activities) +{ + QSet presentActivities; + m_activityScores.clear(); + + foreach (const ActivityData &activity, activities) { + if (m_activities.contains(activity.id)) { + setData(activity.id, "Score", activity.score); + } + presentActivities.insert(activity.id); + m_activityScores[activity.id] = activity.score; + } + + foreach (const QString &activityId, m_activityController->listActivities()) { + if (!presentActivities.contains(activityId) && m_activities.contains(activityId)) { + setData(activityId, "Score", 0); + } + } +} + +void ActivityEngine::activityAdded(const QString &id) +{ + insertActivity(id); + setData("Status", "Running", m_runningActivities); +} + +void ActivityEngine::activityRemoved(const QString &id) +{ + removeSource(id); + KActivities::Info *activity = m_activities.take(id); + if (activity) { + delete activity; + } + m_runningActivities.removeAll(id); + setData("Status", "Running", m_runningActivities); +} + +void ActivityEngine::currentActivityChanged(const QString &id) +{ + setData(m_currentActivity, "Current", false); + m_currentActivity = id; + setData(id, "Current", true); + setData("Status", "Current", id); +} + +void ActivityEngine::activityDataChanged() +{ + KActivities::Info *activity = qobject_cast(sender()); + if (!activity) { + return; + } + setData(activity->id(), "Name", activity->name()); + setData(activity->id(), "Icon", activity->icon()); + setData(activity->id(), "Encrypted", false); + setData(activity->id(), "Current", m_currentActivity == activity->id()); + setData(activity->id(), "Score", m_activityScores.value(activity->id())); +} + +void ActivityEngine::activityStateChanged() +{ + KActivities::Info *activity = qobject_cast(sender()); + const QString id = activity->id(); + if (!activity) { + return; + } + QString state; + switch (activity->state()) { + case KActivities::Info::Running: + state = "Running"; + break; + case KActivities::Info::Starting: + state = "Starting"; + break; + case KActivities::Info::Stopping: + state = "Stopping"; + break; + case KActivities::Info::Stopped: + state = "Stopped"; + break; + case KActivities::Info::Invalid: + default: + state = "Invalid"; + } + setData(id, "State", state); + + if (activity->state() == KActivities::Info::Running) { + if (!m_runningActivities.contains(id)) { + m_runningActivities << id; + } + } else { + m_runningActivities.removeAll(id); + } + + setData("Status", "Running", m_runningActivities); +} + + +Plasma::Service *ActivityEngine::serviceForSource(const QString &source) +{ + //FIXME validate the name + ActivityService *service = new ActivityService(m_activityController, source); + service->setParent(this); + return service; +} + +K_EXPORT_PLASMA_DATAENGINE(activities, ActivityEngine) + +#include "activityengine.moc" diff --git a/plasma/generic/dataengines/activities/activityengine.h b/plasma/generic/dataengines/activities/activityengine.h new file mode 100644 index 00000000..d6824a06 --- /dev/null +++ b/plasma/generic/dataengines/activities/activityengine.h @@ -0,0 +1,81 @@ +/* + * Copyright 2010 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ACTIVITY_ENGINE_H +#define ACTIVITY_ENGINE_H + +#include + +#include +#include + +#include "ActivityData.h" +#include "ActivityRankingInterface.h" + + +class QDBusServiceWatcher; + +class ActivityService; + +namespace KActivities +{ + class Controller; + class Info; +} + + +class ActivityEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + ActivityEngine(QObject* parent, const QVariantList& args); + Plasma::Service *serviceForSource(const QString &source); + void init(); + +public slots: + void activityAdded(const QString &id); + void activityRemoved(const QString &id); + void currentActivityChanged(const QString &id); + + void activityDataChanged(); + void activityStateChanged(); + + void disableRanking(); + void enableRanking(); + void rankingChanged(const QStringList &topActivities, const ActivityDataList &activities); + void activityScoresReply(QDBusPendingCallWatcher *watcher); + +private: + void insertActivity(const QString &id); + void setActivityScores(const ActivityDataList &activities); + + KActivities::Controller *m_activityController; + QHash m_activities; + QStringList m_runningActivities; + QString m_currentActivity; + + org::kde::ActivityManager::ActivityRanking *m_activityRankingClient; + QDBusServiceWatcher *m_watcher; + QHash m_activityScores; + + friend class ActivityService; +}; + +#endif // SEARCHLAUNCH_ENGINE_H diff --git a/plasma/generic/dataengines/activities/activityjob.cpp b/plasma/generic/dataengines/activities/activityjob.cpp new file mode 100644 index 00000000..77ce52ad --- /dev/null +++ b/plasma/generic/dataengines/activities/activityjob.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "activityjob.h" + +#include +#include + +#include +#include + +ActivityJob::ActivityJob(KActivities::Controller *controller, const QString &id, const QString &operation, QMap ¶meters, QObject *parent) : + ServiceJob(parent->objectName(), operation, parameters, parent), + m_activityController(controller), + m_id(id) +{ +} + +ActivityJob::~ActivityJob() +{ +} + +void ActivityJob::start() +{ + const QString operation = operationName(); + if (operation == "add") { + //I wonder how well plasma will handle this... + QString name = parameters()["Name"].toString(); + if (name.isEmpty()) { + name = i18n("unnamed"); + } + const QString activityId = m_activityController->addActivity(name); + setResult(activityId); + return; + } + if (operation == "remove") { + QString id = parameters()["Id"].toString(); + m_activityController->removeActivity(id); + setResult(true); + return; + } + + //m_id is needed for the rest + if (m_id.isEmpty()) { + setResult(false); + return; + } + if (operation == "setCurrent") { + m_activityController->setCurrentActivity(m_id); + setResult(true); + return; + } + if (operation == "stop") { + m_activityController->stopActivity(m_id); + setResult(true); + return; + } + if (operation == "start") { + m_activityController->startActivity(m_id); + setResult(true); + return; + } + if (operation == "setName") { + m_activityController->setActivityName(m_id, parameters()["Name"].toString()); + setResult(true); + return; + } + if (operation == "setIcon") { + m_activityController->setActivityIcon(m_id, parameters()["Icon"].toString()); + setResult(true); + return; + } + if (operation == "setEncrypted") { + m_activityController->setActivityEncrypted(m_id, parameters()["Encrypted"].toBool()); + setResult(true); + return; + } + if (operation == "toggleActivityManager") { + QDBusMessage message = QDBusMessage::createMethodCall("org.kde.plasma-desktop", + "/App", + QString(), + "toggleActivityManager"); + QDBusConnection::sessionBus().call(message, QDBus::NoBlock); + setResult(true); + return; + } + setResult(false); +} + +#include "activityjob.moc" diff --git a/plasma/generic/dataengines/activities/activityjob.h b/plasma/generic/dataengines/activities/activityjob.h new file mode 100644 index 00000000..a8d59d39 --- /dev/null +++ b/plasma/generic/dataengines/activities/activityjob.h @@ -0,0 +1,48 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ACTIVITYJOB_H +#define ACTIVITYJOB_H + +// plasma +#include + +namespace KActivities +{ + class Controller; +} // namespace KActivities + +class ActivityJob : public Plasma::ServiceJob +{ + + Q_OBJECT + + public: + ActivityJob(KActivities::Controller *controller, const QString &id, const QString &operation, QMap ¶meters, QObject *parent = 0); + ~ActivityJob(); + + protected: + void start(); + + private: + KActivities::Controller *m_activityController; + QString m_id; + +}; + +#endif // TASKJOB_H diff --git a/plasma/generic/dataengines/activities/activityservice.cpp b/plasma/generic/dataengines/activities/activityservice.cpp new file mode 100644 index 00000000..4760d108 --- /dev/null +++ b/plasma/generic/dataengines/activities/activityservice.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2010 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "activityservice.h" +#include "activityjob.h" + +ActivityService::ActivityService(KActivities::Controller *controller, const QString &source) + : m_activityController(controller), + m_id(source) +{ + setName("activities"); +} + +ServiceJob *ActivityService::createJob(const QString &operation, QMap ¶meters) +{ + return new ActivityJob(m_activityController, m_id, operation, parameters, this); +} + +#include "activityservice.moc" diff --git a/plasma/generic/dataengines/activities/activityservice.h b/plasma/generic/dataengines/activities/activityservice.h new file mode 100644 index 00000000..e964a81d --- /dev/null +++ b/plasma/generic/dataengines/activities/activityservice.h @@ -0,0 +1,50 @@ +/* + * Copyright 2010 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ACTIVITY_SERVICE_H +#define ACTIVITY_SERVICE_H + +#include "activityengine.h" + +#include +#include + +using namespace Plasma; + +namespace KActivities +{ + class Controller; +} // namespace KActivities + + +class ActivityService : public Plasma::Service +{ + Q_OBJECT + +public: + ActivityService(KActivities::Controller *controller, const QString &source); + ServiceJob *createJob(const QString &operation, + QMap ¶meters); + +private: + KActivities::Controller *m_activityController; + QString m_id; +}; + +#endif // SEARCHLAUNCH_SERVICE_H diff --git a/plasma/generic/dataengines/activities/org.kde.ActivityManager.ActivityRanking.xml b/plasma/generic/dataengines/activities/org.kde.ActivityManager.ActivityRanking.xml new file mode 100644 index 00000000..11374014 --- /dev/null +++ b/plasma/generic/dataengines/activities/org.kde.ActivityManager.ActivityRanking.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/activities/plasma-engine-activities.desktop b/plasma/generic/dataengines/activities/plasma-engine-activities.desktop new file mode 100644 index 00000000..1409da77 --- /dev/null +++ b/plasma/generic/dataengines/activities/plasma-engine-activities.desktop @@ -0,0 +1,130 @@ +[Desktop Entry] +Name=Activities Engine +Name[ar]=محرك الأنشطة +Name[bg]=Ядро за дейности +Name[bs]=motor aktivnosti +Name[ca]=Motor d'activitats +Name[ca@valencia]=Motor d'activitats +Name[cs]=Stroj aktivit +Name[da]=Aktivitetsmotor +Name[de]=Aktivitätenverwaltung +Name[el]=Μηχανή δραστηριοτήτων +Name[en_GB]=Activities Engine +Name[es]=Motor de actividades +Name[et]=Tegevuste mootor +Name[eu]=Jarduera-motorra +Name[fi]=Aktiviteettimoottori +Name[fr]=Moteur d'activités +Name[ga]=Inneall Gníomhaíochta +Name[gl]=Motor de actividades +Name[he]=מנוע הפעילויות +Name[hr]=Mehanizam aktivnosti +Name[hu]=Aktivitások modul +Name[ia]=Motor de activitate +Name[is]=Virknivél +Name[it]=Motore delle attività +Name[ja]=アクティビティエンジン +Name[kk]=Белсенділік тетігі +Name[km]=ម៉ាស៊ីន​សកម្មភាព +Name[kn]=ಚಟುವಟಿಕೆ ಎಂಜಿನ್ +Name[ko]=활동 엔진 +Name[lt]=Veiklų modulis +Name[lv]=Aktivitāšu dzinējs +Name[mr]=कार्यपध्दती इंजिन +Name[nb]=Aktivitetsmotor +Name[nds]=Aktivitetenpleger +Name[nl]=Activiteiten-engine +Name[pa]=ਸਰਗਰਮੀ ਇੰਜਣ +Name[pl]=Silnik działań +Name[pt]=Motor de Actividades +Name[pt_BR]=Mecanismo de atividades +Name[ro]=Motor de activități +Name[ru]=Источник данных для комнат +Name[sk]=Nástroj aktivít +Name[sl]=Pogon za dejavnosti +Name[sr]=мотор активности +Name[sr@ijekavian]=мотор активности +Name[sr@ijekavianlatin]=motor aktivnosti +Name[sr@latin]=motor aktivnosti +Name[sv]=Aktivitetsgränssnitt +Name[th]=กลไกจัดการกิจกรรม +Name[tr]=Etkinlik Motoru +Name[ug]=پائالىيەت ماتورى +Name[uk]=Рушій просторів дій +Name[vi]=Cơ chế cho Hoạt động +Name[wa]=Moteur d' activités +Name[x-test]=xxActivities Enginexx +Name[zh_CN]=活动引擎 +Name[zh_TW]=活動引擎 +Comment=Information on Plasma Activities +Comment[ar]=معلومات عن أنشطة بلازما +Comment[bg]=Данни за дейности в Plasma +Comment[bs]=Podaci o plazma aktivnostima +Comment[ca]=Informació quant a activitats del Plasma +Comment[ca@valencia]=Informació quant a activitats del Plasma +Comment[cs]=Informace o Plasma aktivitách. +Comment[da]=Information om Plasma-aktiviteter +Comment[de]=Informationen über Plasma-Aktivitäten +Comment[el]=Πληροφορίες για τις δραστηριότητες Plasma +Comment[en_GB]=Information on Plasma Activities +Comment[es]=Información sobre las actividades de Plasma +Comment[et]=Teave Plasma tegevuste kohta. +Comment[eu]=Plasmaren jarduerei buruzko informazioa +Comment[fi]=Tietoja Plasma-aktiviteeteista +Comment[fr]=Informations sur les activités de Plasma +Comment[gl]=Información acerca das actividades de Plasma +Comment[he]=מידע אודות הפעילויות של Plasma +Comment[hr]=Informacije o Plasminim aktivnostima +Comment[hu]=Információk a Plasma aktivitásokról +Comment[ia]=Information re activitates de Plasma +Comment[is]=Upplýsingar um Plasma virkni +Comment[it]=Informazioni sulle attività di Plasma +Comment[ja]=Plasma アクティビティの情報 +Comment[kk]=Plasma белсенділігі туралы мәлімет +Comment[km]=ព័ត៌មាន​អំពី​សកម្មភាព​ប្លាស្មា +Comment[kn]=ಪ್ಲಾಸ್ಮಾ ಚಟುವಟಿಕೆಗಳ ಬಗೆಗೆ ಮಾಹಿತಿ. +Comment[ko]=Plasma 활동 정보 +Comment[lt]=Informacija apie Plasma veiklas +Comment[lv]=Informācija par Plasma aktivitātēm +Comment[mr]=प्लाज्मा कार्यपध्दती बद्दल माहिती +Comment[nb]=Informasjon om Plasma-aktiviteter +Comment[nds]=Informatschonen över Plasma-Aktiviteten +Comment[nl]=Informatie over Plasma activiteiten +Comment[nn]=Informasjon om Plasma-aktivitetar +Comment[pa]=ਪਲਾਜ਼ਮਾ ਸਰਗਰਮੀਆਂ ਲਈ ਜਾਣਕਾਰੀ +Comment[pl]=Informacje o działaniach Plazmy +Comment[pt]=Informação sobre as Actividades do Plasma +Comment[pt_BR]=Informações sobre as atividades do Plasma +Comment[ro]=Informații despre activitățile Plasma +Comment[ru]=Сведения о комнатах Plasma +Comment[sk]=Informácie o Plasma aktivitách +Comment[sl]=Podatki o dejavnostih za Plasmo +Comment[sr]=Подаци о плазма активностима +Comment[sr@ijekavian]=Подаци о плазма активностима +Comment[sr@ijekavianlatin]=Podaci o plasma aktivnostima +Comment[sr@latin]=Podaci o plasma aktivnostima +Comment[sv]=Information om aktiviteter i Plasma +Comment[th]=ข้อมูลเกี่ยวกับกิจกรรมต่างๆ ของพลาสมา +Comment[tr]=Plasma Etkinliklerindeki Bilgiler +Comment[ug]=پلازما پائالىيىتىدىكى ئۇچۇر +Comment[uk]=Інформація про простори дій Плазми +Comment[vi]=Thông tin về các Hoạt động Plasma +Comment[wa]=Pondants et djondants so les activités di Plasma +Comment[x-test]=xxInformation on Plasma Activitiesxx +Comment[zh_CN]=关于 Plasma 活动的信息 +Comment[zh_TW]=Plasma 活動的資訊 +Type=Service +Icon=preferences-activities + +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-Library=plasma_engine_activities +X-Plasma-EngineName=activities +X-KDE-PluginInfo-Author=Chani Armitage +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=org.kde.activities +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/dataengines/akonadi/CMakeLists.txt b/plasma/generic/dataengines/akonadi/CMakeLists.txt new file mode 100644 index 00000000..7f0dd346 --- /dev/null +++ b/plasma/generic/dataengines/akonadi/CMakeLists.txt @@ -0,0 +1,29 @@ +include_directories( + ${Boost_INCLUDE_DIR} + ${KDEPIMLIBS_INCLUDE_DIRS} +) + +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) + +set(akonadi_engine_srcs + akonadiengine.cpp +) + +kde4_add_plugin(plasma_engine_akonadi ${akonadi_engine_srcs}) + +target_link_libraries( + plasma_engine_akonadi + ${KDE4_KPIMUTILS_LIBS} + ${KDE4_KDECORE_LIBS} + ${KDE4_AKONADI_LIBS} + ${KDE4_PLASMA_LIBS} + ${KDE4_KMIME_LIBS} + ${KDE4_AKONADI_KMIME_LIBS} + ${KDE4_KABC_LIBS} + ${QT_QTXML_LIBRARY} + microblog +) + +install(TARGETS plasma_engine_akonadi DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-engine-akonadi.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/dataengines/akonadi/akonadiengine.cpp b/plasma/generic/dataengines/akonadi/akonadiengine.cpp new file mode 100644 index 00000000..b7c4372d --- /dev/null +++ b/plasma/generic/dataengines/akonadi/akonadiengine.cpp @@ -0,0 +1,486 @@ +/* + Copyright (c) 2007 Volker Krause + Copyright (c) 2009 Sebastian Kügler + + 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 "akonadiengine.h" + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace Akonadi; + +AkonadiEngine::AkonadiEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent), + m_emailMonitor(0), + m_contactMonitor(0), + m_microBlogMonitor(0) +{ + Q_UNUSED(args); + setMaxSourceCount( 512 ); // Guard against loading thousands of emails + // TODO: monitoring for new microblog collections +} + +void AkonadiEngine::initEmailMonitor() +{ + m_emailMonitor = new Monitor( this ); + m_emailMonitor->setMimeTypeMonitored("message/rfc822"); + //m_emailMonitor->setCollectionMonitored(Collection::root(), false); + m_emailMonitor->itemFetchScope().fetchFullPayload( true ); + connect(m_emailMonitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), + SLOT(emailItemAdded(Akonadi::Item)) ); + connect(m_emailMonitor, SIGNAL(itemChanged(Akonadi::Item,QSet)), + SLOT(emailItemAdded(Akonadi::Item)) ); + // remove the monitor on a source that's not used + connect(this, SIGNAL(sourceRemoved(QString)), SLOT(stopMonitor(QString))); +} + +void AkonadiEngine::initContactMonitor() +{ + m_contactMonitor = new Monitor( this ); + m_contactMonitor->setMimeTypeMonitored("text/directory"); + m_contactMonitor->setCollectionMonitored(Collection::root(), false); + m_contactMonitor->itemFetchScope().fetchFullPayload(); + connect(m_contactMonitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), + SLOT(contactItemAdded(Akonadi::Item)) ); + connect(m_contactMonitor, SIGNAL(itemChanged(Akonadi::Item,QSet)), + SLOT(contactItemAdded(Akonadi::Item)) ); + // remove the monitor on a source that's not used + connect(this, SIGNAL(sourceRemoved(QString)), SLOT(stopMonitor(QString))); +} + +void AkonadiEngine::initMicroBlogMonitor() +{ + // TODO: set up monitoring for "application/x-vnd.kde.microblog" + m_microBlogMonitor = new Monitor( this ); + m_microBlogMonitor->setMimeTypeMonitored( "application/x-vnd.kde.microblog" ); + m_microBlogMonitor->setCollectionMonitored(Collection::root(), false); + m_microBlogMonitor->itemFetchScope().fetchFullPayload(); + connect(m_microBlogMonitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), + SLOT(microBlogItemAdded(Akonadi::Item)) ); + connect(m_microBlogMonitor, SIGNAL(itemChanged(Akonadi::Item,QSet)), + SLOT(microBlogItemAdded(Akonadi::Item)) ); + // remove the monitor on a source that's not used + connect(this, SIGNAL(sourceRemoved(QString)), SLOT(stopMonitor(QString))); +} + +AkonadiEngine::~AkonadiEngine() +{ +} + +QStringList AkonadiEngine::sources() const +{ + return QStringList() << "EmailCollections" << "ContactCollections" << "MicroBlogs"; +} + +void AkonadiEngine::fetchEmailCollectionsDone(KJob* job) +{ + // called when the job fetching email collections from Akonadi emits result() + if ( job->error() ) { + kDebug() << "Job Error:" << job->errorString(); + } else { + CollectionFetchJob* cjob = static_cast( job ); + int i = 0; + foreach( const Collection &collection, cjob->collections() ) { + if (collection.contentMimeTypes().contains("message/rfc822")) { + //kDebug() << "EmailCollection setting data:" << collection.name() << collection.url() << collection.contentMimeTypes(); + i++; + setData("EmailCollections", QString("EmailCollection-%1").arg(collection.id()), collection.name()); + } + } + kDebug() << i << "Email collections are in now"; + scheduleSourcesUpdated(); + } +} + +void AkonadiEngine::fetchContactCollectionsDone(KJob* job) +{ + // called when the job fetching contact collections from Akonadi emits result() + if ( job->error() ) { + kDebug() << "Job Error:" << job->errorString(); + } else { + CollectionFetchJob* cjob = static_cast( job ); + int i = 0; + foreach( const Collection &collection, cjob->collections() ) { + if (collection.contentMimeTypes().contains("text/directory")) { + //kDebug() << "ContactCollection setting data:" << collection.name() << collection.url() << collection.contentMimeTypes(); + i++; + setData("ContactCollections", QString("ContactCollection-%1").arg(collection.id()), collection.name()); + } + } + kDebug() << i << "Contact collections are in now"; + scheduleSourcesUpdated(); + } +} + +void AkonadiEngine::fetchMicroBlogCollectionsDone(KJob* job) +{ + // called when the job fetching microblog collections from Akonadi emits result() + if ( job->error() ) { + kDebug() << "Job Error:" << job->errorString(); + } else { + CollectionFetchJob* cjob = static_cast( job ); + int i = 0; + foreach( const Collection &collection, cjob->collections() ) { + if (collection.contentMimeTypes().contains("application/x-vnd.kde.microblog")) { + kDebug() << "Microblog setting data:" << collection.name() << collection.url() << collection.contentMimeTypes(); + i++; + setData("MicroblogCollection", QString("MicroBlog-%1").arg(collection.id()), collection.name()); + } + } + kDebug() << i << "MicroBlog collections are in now"; + scheduleSourcesUpdated(); + } +} + +bool AkonadiEngine::sourceRequestEvent(const QString &name) +{ + kDebug() << "Source requested:" << name << sources(); + + if (name == "EmailCollections") { + Collection emailCollection(Collection::root()); + emailCollection.setContentMimeTypes(QStringList() << "message/rfc822"); + CollectionFetchJob *fetch = new CollectionFetchJob( emailCollection, CollectionFetchJob::Recursive); + connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchEmailCollectionsDone(KJob*)) ); + // For async data fetching, it's mandatory to set the data source to empty before returning true + setData(name, DataEngine::Data()); + return true; + + } else if (name.startsWith(QString("EmailCollection-"))) { + qlonglong id = name.split('-')[1].toLongLong(); + ItemFetchJob* fetch = new ItemFetchJob( Collection( id ), this ); + if (!m_emailMonitor) { + initEmailMonitor(); + } + m_emailMonitor->setCollectionMonitored(Collection( id ), true); + fetch->fetchScope().fetchPayloadPart( MessagePart::Envelope ); + connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchEmailCollectionDone(KJob*)) ); + connect( fetch, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(emailItemsReceived(Akonadi::Item::List)) ); + m_jobCollections[fetch] = name; + setData(name, DataEngine::Data()); + return true; + + } else if (name.startsWith(QString("Email-"))) { + qlonglong id = name.split('-')[1].toLongLong(); + ItemFetchJob* fetch = new ItemFetchJob( Item( id ), this ); + if (!m_emailMonitor) { + initEmailMonitor(); + } + m_emailMonitor->setItemMonitored(Item( id ), true); + fetch->fetchScope().fetchFullPayload( true ); + connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchEmailCollectionDone(KJob*)) ); + connect( fetch, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(emailItemsReceived(Akonadi::Item::List)) ); + m_jobCollections[fetch] = name; + setData(name, DataEngine::Data()); + return true; + + } else if (name == "ContactCollections") { + Collection contactCollection(Collection::root()); + contactCollection.setContentMimeTypes(QStringList() << "text/directory"); + + CollectionFetchJob* fetch = new CollectionFetchJob( contactCollection, CollectionFetchJob::Recursive); + connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchContactCollectionsDone(KJob*)) ); + setData(name, DataEngine::Data()); + return true; + + } else if (name.startsWith(QString("ContactCollection-"))) { + qlonglong id = name.split('-')[1].toLongLong(); + ItemFetchJob *fetch = new ItemFetchJob( Collection( id ), this ); + if (!m_contactMonitor) { + initContactMonitor(); + } + m_contactMonitor->setCollectionMonitored(Collection( id ), true); // FIXME: should be contacts monitor + fetch->fetchScope().fetchFullPayload(); + connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchContactCollectionDone(KJob*)) ); + setData(name, DataEngine::Data()); + return true; + + } else if (name.startsWith(QString("Contact-"))) { + kDebug() << "Fetching contact" << name; + qlonglong id = name.split('-')[1].toLongLong(); + ItemFetchJob *fetch = new ItemFetchJob( Item( id ), this ); + if (!m_contactMonitor) { + initContactMonitor(); + } + m_contactMonitor->setItemMonitored(Item( id ), true); // FIXME: should be contacts monitor + fetch->fetchScope().fetchFullPayload(); + connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchContactCollectionDone(KJob*)) ); + setData(name, DataEngine::Data()); + return true; + + } else if (name == "MicroBlogs") { + Collection microblogCollection(Collection::root()); + microblogCollection.setContentMimeTypes(QStringList() << "application/x-vnd.kde.microblog"); + CollectionFetchJob *fetch = new CollectionFetchJob( microblogCollection, CollectionFetchJob::Recursive); + connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchMicroBlogCollectionsDone(KJob*)) ); + setData(name, DataEngine::Data()); + return true; + + } else if (name.startsWith(QString("MicroBlog-"))) { + qlonglong id = name.split('-')[1].toLongLong(); + kDebug() << "MicroBlog ID" << id << " requested" << name; + ItemFetchJob *fetch = new ItemFetchJob( Akonadi::Collection( id )); + if (!m_microBlogMonitor) { + initMicroBlogMonitor(); + } + m_microBlogMonitor->setItemMonitored(Item( id ), true); + fetch->fetchScope().fetchFullPayload(); + connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchMicroBlogDone(KJob*)) ); + setData(name, DataEngine::Data()); + return true; + } + // We don't understand the request. + kDebug() << "Don't know what to do with:" << name; + return false; +} + +void AkonadiEngine::stopMonitor(const QString &name) +{ + if (name.startsWith(QString("EmailCollection-"))) { + // Stop monitoring this one + qlonglong id = name.split('-')[1].toLongLong(); + m_emailMonitor->setCollectionMonitored( Collection( id ), false); + kDebug() << "Removed monitor from:" << name << id; + } +} + +void AkonadiEngine::emailItemsReceived(const Akonadi::Item::List &items) +{ + foreach (const Akonadi::Item &item, items) { + emailItemAdded(item); + } +} + +void AkonadiEngine::emailItemAdded(const Akonadi::Item &item, const QString &collection) +{ + if ( !item.hasPayload() ) { + return; + } + MessagePtr msg = item.payload(); + if (msg) { + QString source = QString::number( item.id() ); + source = "Email-" + source; + //kDebug() << "new source adding:" << source << item.url() << msg->subject()->asUnicodeString(); + + setData( source, "Id", item.id() ); + setData( source, "Collection", collection); + setData( source, "Url", item.url().url() ); + setData( source, "Subject", msg->subject()->asUnicodeString() ); + setData( source, "From", msg->from()->asUnicodeString() ); + setData( source, "DateTime", msg->date()->dateTime().date() ); + setData( source, "To", msg->to()->asUnicodeString() ); + setData( source, "Cc", msg->cc()->asUnicodeString() ); + setData( source, "Bcc", msg->bcc()->asUnicodeString() ); + setData( source, "Body", QString(msg->mainBodyPart()->body())); + // Flags + //kDebug() << item.flags(); + setData( source, "Flag-New", !item.hasFlag("\\Seen") ); + setData( source, "Flag-Task", item.hasFlag("\\Task") ); // not in Akonadi! + setData( source, "Flag-Important", item.hasFlag("important") ); + setData( source, "Flag-Attachment", item.hasFlag("has_attachment") ); + setData( source, "Flag-Spam", item.hasFlag("spam") ); + setData( source, "Flag-Draft", item.hasFlag("\\Draft") ); + setData( source, "Flag-Answered", item.hasFlag("\\Answered") ); + setData( source, "Flag-Deleted", item.hasFlag("\\Deleted") ); + setData( source, "Flag-Flagged", item.hasFlag("\\Flagged") ); + + if (!collection.isEmpty()) { + setData( collection, source, msg->subject()->asUnicodeString()); + } + printMessage(msg); + scheduleSourcesUpdated(); + } +} + +void AkonadiEngine::printMessage(const MessagePtr msg) +{ + return; + kDebug() << "sub" << msg->subject()->asUnicodeString(); + return; + kDebug() << "=============== New Item" << msg->from()->asUnicodeString() << msg->subject()->asUnicodeString(); + kDebug() << "sub" << msg->subject()->asUnicodeString(); + kDebug() << "from" << msg->from()->asUnicodeString(); + kDebug() << "date" << msg->date()->dateTime().date(); + kDebug() << "to" << msg->to()->asUnicodeString(); + kDebug() << "cc" << msg->cc()->asUnicodeString(); + kDebug() << "bcc" << msg->bcc()->asUnicodeString(); + kDebug() << "body" << msg->mainBodyPart()->body(); +} + +void AkonadiEngine::fetchEmailCollectionDone(KJob* job) +{ + if ( job->error() ) { + kDebug() << "Job Error:" << job->errorString(); + return; + } + const QString col = m_jobCollections[job]; + Item::List items = static_cast( job )->items(); + foreach ( const Item &item, items ) { + emailItemAdded(item, col); + } + m_jobCollections.remove(job); + scheduleSourcesUpdated(); +} + +void AkonadiEngine::fetchContactCollectionDone(KJob* job) +{ + if ( job->error() ) { + return; + } + Item::List items = static_cast( job )->items(); + foreach ( const Item &item, items ) { + contactItemAdded( item ); + } +} + +void AkonadiEngine::fetchMicroBlogDone(KJob* job) +{ + if (job->error()) { + kDebug() << "Microblog job failed:" << job->errorString(); + } else { + Item::List items = static_cast( job )->items(); + kDebug() << "Adding microblogs" << items.count(); + foreach (const Item &item, items) { + microBlogItemAdded(item); + } + } +} + + +void AkonadiEngine::microBlogItemAdded(const Akonadi::Item &item) +{ + // Get the Akonadi::Item's XML payload and parse that, then + // put it into the DataEngine's Data + kDebug() << "Checking one item"; + if (item.hasPayload()) { + Microblog::StatusItem s = item.payload(); + const QString source = QString("MicroBlog-%1").arg(s.id()); + kDebug() << "Adding" << source << s.keys(); + setData(source, "Date", s.date()); + setData(source, "Foo", "Bar"); + foreach (const QString &key, s.keys()) { + setData(source, key, s.value(key)); + } + scheduleSourcesUpdated(); + } else { + kDebug() << "Wrong payload (not a StatusItem)"; + } +} + +void AkonadiEngine::printContact(const QString &source, const KABC::Addressee &a) +{ + kDebug() << "-----------------------------------"; + kDebug() << source; + kDebug() << "name" << a.name(); + kDebug() << "formattedName" << a.formattedName(); + kDebug() << "nameLabel" << a.nameLabel(); + kDebug() << "given" << a.givenName(); + kDebug() << "familyName" << a.familyName(); + kDebug() << "realName" << a.realName(); + kDebug() << "organization" << a.organization(); + kDebug() << "department" << a.department(); + kDebug() << "role" << a.role(); + kDebug() << "emails" << a.emails(); + kDebug() << "fullEmail" << a.fullEmail(); + kDebug() << "photoUrl" << a.photo().url(); + kDebug() << "note" << a.note(); + + QStringList phoneNumbers; + foreach (const KABC::PhoneNumber &pn, a.phoneNumbers()) { + const QString key = QString("Phone-%1").arg(pn.typeLabel()); + kDebug() << key << a.phoneNumber(pn.type()).number(); + phoneNumbers << a.phoneNumber(pn.type()).number(); + } + kDebug() << "phoneNumbers" << phoneNumbers; + + kDebug() << "additionalName" << a.additionalName(); + +} + +void AkonadiEngine::contactItemAdded( const Akonadi::Item &item ) +{ + if (item.hasPayload()) { + //kDebug() << item.id() << "item has payload ..."; + KABC::Addressee a = item.payload(); + if (!a.isEmpty()) { + const QString source = QString("Contact-%1").arg(item.id()); + setData(source, "Id", item.id()); + setData(source, "Url", item.url().url()); + + // Name and related + setData(source, "Name", a.formattedName()); + setData(source, "GivenName", a.givenName()); + setData(source, "FamilyName", a.familyName()); + setData(source, "NickName", a.nickName()); + setData(source, "RealName", a.realName()); + setData(source, "AdditionalName", a.additionalName()); + + // Organization and related + setData(source, "Organization", a.organization()); + setData(source, "Department", a.department()); + setData(source, "Role", a.role()); + + // EMail and related + setData(source, "Emails", a.emails()); + setData(source, "FullEmail", a.fullEmail()); + + // Phone and related + QStringList phoneNumbers; + foreach (const KABC::PhoneNumber &pn, a.phoneNumbers()) { + const QString key = QString("Phone-%1").arg(pn.typeLabel()); + setData(source, key, a.phoneNumber(pn.type()).number()); + phoneNumbers << a.phoneNumber(pn.type()).number(); + } + setData(source, "PhoneNumbers", phoneNumbers); + + // Personal + setData(source, "Birthday", a.birthday()); + setData(source, "Photo", a.photo().data()); + setData(source, "PhotoUrl", a.photo().url()); + setData(source, "Latitude", a.geo().latitude()); + setData(source, "Longitude", a.geo().longitude()); + + // addresses + + // categories + + // note, + setData(source, "Note", a.note()); + // prefix + + // ... + //printContact(source, a); + + scheduleSourcesUpdated(); + } + } +} + +#include "akonadiengine.moc" diff --git a/plasma/generic/dataengines/akonadi/akonadiengine.h b/plasma/generic/dataengines/akonadi/akonadiengine.h new file mode 100644 index 00000000..c1457064 --- /dev/null +++ b/plasma/generic/dataengines/akonadi/akonadiengine.h @@ -0,0 +1,85 @@ +/* + Copyright (c) 2007 Volker Krause + Copyright (c) 2009 Sebastian Kügler + + 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 AKONADIENGINE_H +#define AKONADIENGINE_H + +#include + +#include +#include + +#include +#include + +#include +typedef boost::shared_ptr MessagePtr; + +class KJob; + +class AkonadiEngine : public Plasma::DataEngine +{ + Q_OBJECT + + public: + AkonadiEngine( QObject* parent, const QVariantList& args ); + ~AkonadiEngine(); + QStringList sources() const; + + protected: + bool sourceRequestEvent(const QString &name); + + private slots: + + void stopMonitor(const QString &name); + + void fetchEmailCollectionDone(KJob* job); // done retrieving whole collection + void fetchContactCollectionDone(KJob* job); // done retrieving a whole contact collection + void fetchMicroBlogDone(KJob* job); + + void emailItemsReceived(const Akonadi::Item::List &items); + + void fetchEmailCollectionsDone(KJob* job); // got list of collections + void fetchContactCollectionsDone(KJob* job); + void fetchMicroBlogCollectionsDone(KJob* job); + + void emailItemAdded(const Akonadi::Item &item, const QString &collection = QString()); + void contactItemAdded(const Akonadi::Item & item); + void microBlogItemAdded(const Akonadi::Item &item); + + private: + void initEmailMonitor(); + void initContactMonitor(); + void initMicroBlogMonitor(); + // useful for debugging + void printMessage(MessagePtr msg); + void printContact(const QString &source, const KABC::Addressee &a); + + Akonadi::Monitor* m_emailMonitor; + Akonadi::Monitor* m_contactMonitor; + Akonadi::Monitor* m_microBlogMonitor; + + QHash m_jobCollections; +}; + +K_EXPORT_PLASMA_DATAENGINE(akonadi, AkonadiEngine) + +#endif diff --git a/plasma/generic/dataengines/akonadi/plasma-engine-akonadi.desktop b/plasma/generic/dataengines/akonadi/plasma-engine-akonadi.desktop new file mode 100644 index 00000000..66226a9b --- /dev/null +++ b/plasma/generic/dataengines/akonadi/plasma-engine-akonadi.desktop @@ -0,0 +1,152 @@ +[Desktop Entry] +Name=Akonadi +Name[ar]=أكونادي +Name[ast]=Akonadi +Name[bg]=Akonadi +Name[bs]=Akonadi +Name[ca]=Akonadi +Name[ca@valencia]=Akonadi +Name[cs]=Akonadi +Name[da]=Akonadi +Name[de]=Akonadi +Name[el]=Akonadi +Name[en_GB]=Akonadi +Name[eo]=Akonadi +Name[es]=Akonadi +Name[et]=Akonadi +Name[eu]=Akonadi +Name[fi]=Akonadi +Name[fr]=Akonadi +Name[fy]=Akonadi +Name[ga]=Akonadi +Name[gl]=Akonadi +Name[gu]=Akonadi +Name[he]=Akonadi +Name[hi]=अकोनादी +Name[hr]=Akonadi +Name[hu]=Akonadi +Name[ia]=Akonadi +Name[id]=Akonadi +Name[is]=Akonadi +Name[it]=Akonadi +Name[ja]=Akonadi +Name[ka]=Akonadi +Name[kk]=Akonadi +Name[km]=Akonadi +Name[kn]=Akonadi +Name[ko]=Akonadi +Name[lt]=Akonadi +Name[lv]=Akonadi +Name[mai]=Akonadi +Name[mk]=Akonadi +Name[ml]=അകോനാഡി +Name[mr]=आकोनाडी +Name[nb]=Akonadi +Name[nds]=Akonadi +Name[nl]=Akonadi +Name[nn]=Akonadi +Name[pa]=ਅਕੌਂਡੀ +Name[pl]=Akonadi +Name[pt]=Akonadi +Name[pt_BR]=Akonadi +Name[ro]=Akonadi +Name[ru]=Akonadi +Name[si]=Akonadi +Name[sk]=Akonadi +Name[sl]=Akonadi +Name[sr]=Аконади +Name[sr@ijekavian]=Аконади +Name[sr@ijekavianlatin]=Akonadi +Name[sr@latin]=Akonadi +Name[sv]=Akonadi +Name[tg]=Akonadi +Name[th]=Akonadi +Name[tr]=Akonadi +Name[ug]=Akonadi +Name[uk]=Akonadi +Name[vi]=Akonadi +Name[wa]=Akonadi +Name[x-test]=xxAkonadixx +Name[zh_CN]=Akonadi +Name[zh_TW]=Akonadi +Comment=Akonadi PIM data engine +Comment[ar]=محرك بيانات إدارة المعلومات الشخصية أكونادي +Comment[ast]=Motor de datos Akonadi PIM +Comment[bg]=Ядро за данни Akonadi PIM +Comment[bs]=PIM datomotor Akonadija +Comment[ca]=Motor de dades PIM de l'Akonadi +Comment[ca@valencia]=Motor de dades PIM de l'Akonadi +Comment[cs]=Datový nástroj Akonadi PIM +Comment[csb]=Czérownik pòdôwków Akonadi PIM +Comment[da]=Akonadi datamotor til PIM +Comment[de]=PIM-Datentreiber für Akonadi +Comment[el]=Μηχανή δεδομένων Akonadi PIM +Comment[en_GB]=Akonadi PIM data engine +Comment[eo]=Datuma Motoro de Akonadi PIM +Comment[es]=Motor de datos Akonadi PIM +Comment[et]=Akonadi PIM-i andmete mootor +Comment[eu]=Akonadi PIM datuen motorra +Comment[fi]=Akonadi PIM -tietomoottori +Comment[fr]=Moteur de données PIM d'Akonadi +Comment[fy]=Akonadi PIM gegevensmotor +Comment[ga]=Inneall sonraí PIM Akonadi +Comment[gl]=Motor de datos PIM de Akonadi +Comment[he]=מנוע תוכן של Akonadi PIM +Comment[hi]=अकोनाडी PIM डाटा इंजिन +Comment[hr]=Akonadi mehanizam za upravljanje osobnim informacijama +Comment[hu]=Akonadi adatkezelő modul +Comment[ia]=Motor de datos de Akonadi PIM +Comment[id]=Mesin data PIM Akonadi +Comment[is]=Akonadi gagnavél fyrir persónuupplýsingar (PIM) +Comment[it]=Motore dei dati PIM di Akonadi +Comment[ja]=Akonadi PIM データエンジン +Comment[kk]=Akonadi PIM деректер тетігі +Comment[km]=ម៉ាស៊ីន​ទិន្នន័យ Akonadi PIM +Comment[kn]=Akonadi PIM ದತ್ತ ಸಾಧನ +Comment[ko]=Akonadi PIM 데이터 엔진 +Comment[lt]=Akonadi PIM duomenų variklis +Comment[lv]=Akonadi PIM datu dzinējs +Comment[mk]=Податочна машина Akonadi PIM +Comment[ml]=അകോനാഡി പിം ഡേറ്റാ എഞ്ചിന്‍ +Comment[mr]=आकोनाडी PIM डेटा इन्जीन +Comment[nb]=Akonadi PIM datamotor +Comment[nds]=De PIM-Datenkarn Akonadi +Comment[nl]=Akonadi PIM gegevensengine +Comment[nn]=Akonadi PIM-datamotor +Comment[pa]=ਅਕੌਂਡੀ PIM ਡਾਟਾ ਇੰਜਣ +Comment[pl]=Silnik danych PIM Akonadi +Comment[pt]=Motor de dados PIM do Akonadi +Comment[pt_BR]=Mecanismo de dados PIM do Akonadi +Comment[ro]=Motor de date Akonadi PIM +Comment[ru]=Источник данных Plasma для работы с личными данными, хранящимися в Akonadi +Comment[si]=Akonadi PIM දත්ත එන්ජිම +Comment[sk]=Dátový nástroj Akonadi PIM +Comment[sl]=Podatkovni pogon za upravljanje z osebnimi podatki +Comment[sr]=ПИМ датомотор Аконадија +Comment[sr@ijekavian]=ПИМ датомотор Аконадија +Comment[sr@ijekavianlatin]=PIM datomotor Akonadija +Comment[sr@latin]=PIM datomotor Akonadija +Comment[sv]=Akonadi datagränssnitt för personlig information +Comment[tg]=Системаи санаи Python +Comment[th]=กลไกข้อมูล Akonadi PIM +Comment[tr]=Akonadi PIM veri motoru +Comment[ug]=Akonadi PIM سانلىق-مەلۇمات ماتورى +Comment[uk]=Рушій даних Akonadi PIM +Comment[vi]=Cơ chế dữ liệu Akonadi PIM +Comment[wa]=Éndjin d' dinêyes PIM Akonadi +Comment[x-test]=xxAkonadi PIM data enginexx +Comment[zh_CN]=Akonadi 个人信息管理数据引擎 +Comment[zh_TW]=Akonadi PIM 資料引擎 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=akonadi +X-KDE-Library=plasma_engine_akonadi + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=akonadi +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/applicationjobs/CMakeLists.txt b/plasma/generic/dataengines/applicationjobs/CMakeLists.txt new file mode 100644 index 00000000..5b7a1aab --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/CMakeLists.txt @@ -0,0 +1,21 @@ +project(kuiserver_engine) + +#include (KDE4Defaults) +#include (MacroLibrary) + +set(kuiserver_engine_SRCS + kuiserverengine.cpp + jobcontrol.cpp + jobaction.cpp +) + +qt4_add_dbus_adaptor(kuiserver_engine_SRCS ${KDE4_DBUS_INTERFACES_DIR}/org.kde.JobViewV2.xml kuiserverengine.h JobView jobviewadaptor ) +qt4_add_dbus_adaptor(kuiserver_engine_SRCS ${KDE4_DBUS_INTERFACES_DIR}/org.kde.JobViewServer.xml kuiserverengine.h KuiserverEngine jobviewserveradaptor ) + +kde4_add_plugin(plasma_engine_applicationjobs ${kuiserver_engine_SRCS}) +target_link_libraries(plasma_engine_applicationjobs ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) + +install(TARGETS plasma_engine_applicationjobs DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-applicationjobs.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install(FILES applicationjobs.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + diff --git a/plasma/generic/dataengines/applicationjobs/Messages.sh b/plasma/generic/dataengines/applicationjobs/Messages.sh new file mode 100755 index 00000000..d37a3e02 --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_kuiserver.pot diff --git a/plasma/generic/dataengines/applicationjobs/applicationjobs.operations b/plasma/generic/dataengines/applicationjobs/applicationjobs.operations new file mode 100644 index 00000000..5b8f5e61 --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/applicationjobs.operations @@ -0,0 +1,8 @@ + + + + + + + diff --git a/plasma/generic/dataengines/applicationjobs/jobaction.cpp b/plasma/generic/dataengines/applicationjobs/jobaction.cpp new file mode 100644 index 00000000..1a76ce55 --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/jobaction.cpp @@ -0,0 +1,51 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "jobaction.h" +#include "kuiserverengine.h" + +#include + +void JobAction::start() +{ + kDebug() << "Trying to perform the action" << operationName(); + + if (!m_jobView) { + setErrorText(i18nc("%1 is the subject (can be anything) upon which the job is performed", + "The JobView for %1 cannot be found", destination())); + setError(-1); + emitResult(); + return; + } + + //TODO: check with capabilities before performing actions. + if (operationName() == "resume") { + m_jobView->requestStateChange(JobView::Running); + } else if (operationName() == "suspend") { + m_jobView->requestStateChange(JobView::Suspended); + } else if (operationName() == "stop") { + m_jobView->requestStateChange(JobView::Stopped); + //in case the app crashed and won't call terminate on the jobview. + m_jobView->terminate(i18n("Job canceled by user.")); + } + + emitResult(); +} + +#include "jobaction.moc" + diff --git a/plasma/generic/dataengines/applicationjobs/jobaction.h b/plasma/generic/dataengines/applicationjobs/jobaction.h new file mode 100644 index 00000000..3b46040f --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/jobaction.h @@ -0,0 +1,46 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef JOBACTION_H +#define JOBACTION_H + +#include "kuiserverengine.h" + +#include + +class JobAction : public Plasma::ServiceJob +{ + Q_OBJECT + + public: + JobAction(JobView *jobView, + const QString& operation, + QMap& parameters, + QObject* parent = 0) + : ServiceJob(jobView->objectName(), operation, parameters, parent), + m_jobView(jobView) + { + } + + void start(); + + private: + JobView *m_jobView; +}; + +#endif //JOBVIEW_H diff --git a/plasma/generic/dataengines/applicationjobs/jobcontrol.cpp b/plasma/generic/dataengines/applicationjobs/jobcontrol.cpp new file mode 100644 index 00000000..57d26ff9 --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/jobcontrol.cpp @@ -0,0 +1,38 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "jobcontrol.h" +#include "jobaction.h" +#include "kuiserverengine.h" + +JobControl::JobControl(QObject* parent, JobView *jobView) + : Plasma::Service(parent), + m_jobView(jobView) +{ + setName("applicationjobs"); + setDestination(jobView->objectName()); +} + +Plasma::ServiceJob* JobControl::createJob(const QString& operation, + QMap& parameters) +{ + return new JobAction(m_jobView, operation, parameters, this); +} + +#include "jobcontrol.moc" + diff --git a/plasma/generic/dataengines/applicationjobs/jobcontrol.h b/plasma/generic/dataengines/applicationjobs/jobcontrol.h new file mode 100644 index 00000000..68c79824 --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/jobcontrol.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef JOBCONTROL_H +#define JOBCONTROL_H + +#include + +class JobView; + +class JobControl : public Plasma::Service +{ + Q_OBJECT + + public: + JobControl(QObject* parent, JobView *jobview); + + protected: + Plasma::ServiceJob* createJob(const QString& operation, + QMap& parameters); + + private: + JobView *m_jobView; + +}; + +#endif // JOBCONTROL_H diff --git a/plasma/generic/dataengines/applicationjobs/kuiserverengine.cpp b/plasma/generic/dataengines/applicationjobs/kuiserverengine.cpp new file mode 100644 index 00000000..59a4de7f --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/kuiserverengine.cpp @@ -0,0 +1,380 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "jobviewadaptor.h" +#include "jobviewserveradaptor.h" +#include "kuiserverengine.h" +#include "jobcontrol.h" + +#include + +#include + +#include + + +uint JobView::s_jobId = 0; + +static const int UPDATE_INTERVAL = 100; + +JobView::JobView(QObject* parent) + : Plasma::DataContainer(parent), + m_capabilities(-1), + m_percent(0), + m_speed(0), + m_totalBytes(0), + m_processedBytes(0), + m_state(UnknownState), + m_bytesUnitId(-1), + m_unitId(0) +{ + m_jobId = ++s_jobId; + setObjectName(QString("Job %1").arg(s_jobId)); + + new JobViewV2Adaptor(this); + + m_objectPath.setPath(QString("/DataEngine/applicationjobs/JobView_%1").arg(m_jobId)); + QDBusConnection::sessionBus().registerObject(m_objectPath.path(), this); + + setSuspended(false); +} + +JobView::~JobView() +{ + QDBusConnection::sessionBus().unregisterObject(m_objectPath.path(), QDBusConnection::UnregisterTree); +} + +uint JobView::jobId() const +{ + return m_jobId; +} + +void JobView::scheduleUpdate() +{ + if (!m_updateTimer.isActive()) { + m_updateTimer.start(UPDATE_INTERVAL, this); + } +} + +void JobView::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == m_updateTimer.timerId()) { + m_updateTimer.stop(); + checkForUpdate(); + + if (m_state == Stopped) { + emit becameUnused(objectName()); + } + } else { + Plasma::DataContainer::timerEvent(event); + } +} + +void JobView::terminate(const QString &errorMessage) +{ + setData("error", errorMessage); + QTimer::singleShot(0, this, SLOT(finished())); +} + +void JobView::finished() +{ + if (m_state != Stopped) { + m_state = Stopped; + setData("state", "stopped"); + setData("speed", QVariant()); + setData("numericSpeed", QVariant()); + scheduleUpdate(); + } +} + +JobView::State JobView::state() +{ + return m_state; +} + +void JobView::setSuspended(bool suspended) +{ + if (suspended) { + if (m_state != Suspended) { + m_state = Suspended; + setData("state", "suspended"); + setData("speed", QVariant()); + setData("numericSpeed", QVariant()); + scheduleUpdate(); + } + } else if (m_state != Running) { + m_state = Running; + setData("state", "running"); + setData("speed", speedString()); + setData("numericSpeed", m_speed); + scheduleUpdate(); + } +} + +int JobView::unitId(const QString &unit) +{ + int id = 0; + if (m_unitMap.contains(unit)) { + id = m_unitMap.value(unit); + } else { + id = m_unitId; + setData(QString("totalUnit%1").arg(id), unit); + setData(QString("totalAmount%1").arg(id), 0); + setData(QString("processedUnit%1").arg(id), unit); + setData(QString("processedAmount%1").arg(id), 0); + m_unitMap.insert(unit, m_unitId); + + if (unit == "bytes") { + m_bytesUnitId = id; + } + + ++m_unitId; + scheduleUpdate(); + } + + return id; +} + +void JobView::updateEta() +{ + if (m_speed < 1) { + setData("eta", 0); + return; + } + + if (m_totalBytes < 1) { + setData("eta", 0); + return; + } + + const qlonglong remaining = 1000 * (m_totalBytes - m_processedBytes); + setData("eta", remaining / m_speed); +} + +void JobView::setTotalAmount(qlonglong amount, const QString &unit) +{ + const int id = unitId(unit); + const QString amountString = QString("totalAmount%1").arg(id); + const qlonglong prevTotal = data().value(amountString).toLongLong(); + if (prevTotal != amount) { + if (id == m_bytesUnitId) { + m_totalBytes = amount; + updateEta(); + } + + setData(amountString, amount); + scheduleUpdate(); + } +} + +void JobView::setProcessedAmount(qlonglong amount, const QString &unit) +{ + const int id = unitId(unit); + const QString processedString = QString("processedAmount%1").arg(id); + const qlonglong prevTotal = data().value(processedString).toLongLong(); + if (prevTotal != amount) { + if (id == m_bytesUnitId) { + m_processedBytes = amount; + updateEta(); + } + + setData(processedString, amount); + scheduleUpdate(); + } +} + +void JobView::setDestUrl(const QDBusVariant & destUrl) +{ + Q_UNUSED(destUrl); +} + +void JobView::setPercent(uint percent) +{ + if (m_percent != percent) { + m_percent = percent; + setData("percentage", m_percent); + scheduleUpdate(); + } +} + +void JobView::setSpeed(qlonglong bytesPerSecond) +{ + if (m_speed != bytesPerSecond) { + m_speed = bytesPerSecond; + setData("speed", speedString()); + setData("numericSpeed", m_speed); + + if (m_bytesUnitId > -1) { + updateEta(); + } + + scheduleUpdate(); + } +} + +QString JobView::speedString() const +{ + return i18nc("Byes per second", "%1/s", KGlobal::locale()->formatByteSize(m_speed)); +} + +void JobView::setInfoMessage(const QString &infoMessage) +{ + if (data().value("infoMessage") != infoMessage) { + setData("infoMessage", infoMessage); + scheduleUpdate(); + } +} + +bool JobView::setDescriptionField(uint number, const QString &name, const QString &value) +{ + const QString labelString = QString("label%1").arg(number); + const QString labelNameString = QString("labelName%1").arg(number); + + if (!data().contains(labelNameString) || data().value(labelString) != value) { + setData(labelNameString, name); + setData(labelString, value); + scheduleUpdate(); + } + return true; +} + +void JobView::clearDescriptionField(uint number) +{ + const QString labelString = QString("label%1").arg(number); + const QString labelNameString = QString("labelName%1").arg(number); + + setData(labelNameString, QVariant()); + setData(labelString, QVariant()); + scheduleUpdate(); +} + +void JobView::setAppName(const QString &appName) +{ + // don't need to update, this is only set once at creation + setData("appName", appName); +} + +void JobView::setAppIconName(const QString &appIconName) +{ + // don't need to update, this is only set once at creation + setData("appIconName", appIconName); +} + +void JobView::setCapabilities(int capabilities) +{ + if (m_capabilities != uint(capabilities)) { + m_capabilities = capabilities; + setData("suspendable", m_capabilities & KJob::Suspendable); + setData("killable", m_capabilities & KJob::Killable); + scheduleUpdate(); + } +} + +QDBusObjectPath JobView::objectPath() const +{ + return m_objectPath; +} + +void JobView::requestStateChange(State state) +{ + switch (state) { + case Running: + emit resumeRequested(); + break; + case Suspended: + emit suspendRequested(); + break; + case Stopped: + emit cancelRequested(); + break; + default: + break; + } +} + +KuiserverEngine::KuiserverEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) +{ + new JobViewServerAdaptor(this); + + QDBusConnection bus = QDBusConnection::sessionBus(); + bus.registerObject(QLatin1String("/DataEngine/applicationjobs/JobWatcher"), this); + + setMinimumPollingInterval(500); + + m_pendingJobsTimer.setSingleShot(true); + m_pendingJobsTimer.setInterval(500); + connect(&m_pendingJobsTimer, SIGNAL(timeout()), this, SLOT(processPendingJobs())); +} + +KuiserverEngine::~KuiserverEngine() +{ + QDBusConnection::sessionBus() + .unregisterObject(QLatin1String("/DataEngine/applicationjobs/JobWatcher"), QDBusConnection::UnregisterTree); + qDeleteAll(m_pendingJobs); +} + +QDBusObjectPath KuiserverEngine::requestView(const QString &appName, + const QString &appIconName, int capabilities) +{ + JobView *jobView = new JobView(this); + jobView->setAppName(appName); + jobView->setAppIconName(appIconName); + jobView->setCapabilities(capabilities); + connect(jobView, SIGNAL(becameUnused(QString)), this, SLOT(removeSource(QString))); + + m_pendingJobs << jobView; + m_pendingJobsTimer.start(); + + return jobView->objectPath(); +} + +void KuiserverEngine::processPendingJobs() +{ + foreach (JobView *jobView, m_pendingJobs) { + if (jobView->state() == JobView::Stopped) { + delete jobView; + } else { + addSource(jobView); + } + } + + m_pendingJobs.clear(); +} + +Plasma::Service* KuiserverEngine::serviceForSource(const QString& source) +{ + JobView *jobView = qobject_cast(containerForSource(source)); + if (jobView) { + return new JobControl(this, jobView); + } else { + return DataEngine::serviceForSource(source); + } +} + +void KuiserverEngine::init() +{ + // register with the Job UI Serer to receive notifications of jobs becoming available + QDBusInterface interface("org.kde.kuiserver", "/JobViewServer"/* object to connect to */, + ""/* use the default interface */, QDBusConnection::sessionBus(), this); + interface.asyncCall(QLatin1String("registerService"), QDBusConnection::sessionBus().baseService(), "/DataEngine/applicationjobs/JobWatcher"); +} + +K_EXPORT_PLASMA_DATAENGINE(kuiserver, KuiserverEngine) + +#include "kuiserverengine.moc" diff --git a/plasma/generic/dataengines/applicationjobs/kuiserverengine.h b/plasma/generic/dataengines/applicationjobs/kuiserverengine.h new file mode 100644 index 00000000..c03b0700 --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/kuiserverengine.h @@ -0,0 +1,145 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KUISERVERENGINE_H +#define KUISERVERENGINE_H + +#include +#include +#include + +#include +#include + +class JobView; + +namespace Plasma +{ + class Service; +} // namespace Plasma + +class KuiserverEngine : public Plasma::DataEngine +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.JobViewServer") + +public: + KuiserverEngine(QObject* parent, const QVariantList& args); + ~KuiserverEngine(); + + void init(); + + QDBusObjectPath requestView(const QString &appName, const QString &appIconName, + int capabilities); + Plasma::Service* serviceForSource(const QString& source); + +private Q_SLOTS: + void processPendingJobs(); + +private: + QTimer m_pendingJobsTimer; + QList m_pendingJobs; +}; + +class JobView : public Plasma::DataContainer +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.JobViewV2") + +public: + enum State { + UnknownState = -1, + Running = 0, + Suspended = 1, + Stopped = 2 + }; + + JobView(QObject *parent = 0); + ~JobView(); + + uint jobId() const; + JobView::State state(); + + void setTotalAmount(qlonglong amount, const QString &unit); + QString totalAmountSize() const; + QString totalAmountFiles() const; + + void setProcessedAmount(qlonglong amount, const QString &unit); + + void setSpeed(qlonglong bytesPerSecond); + QString speedString() const; + + void setInfoMessage(const QString &infoMessage); + QString infoMessage() const; + + bool setDescriptionField(uint number, const QString &name, const QString &value); + void clearDescriptionField(uint number); + + void setAppName(const QString &appName); + void setAppIconName(const QString &appIconName); + void setCapabilities(int capabilities); + void setPercent(uint percent); + void setSuspended(bool suspended); + + //vestigal, required to implement this dbus interface + void setDestUrl(const QDBusVariant &destUrl); + + void terminate(const QString &errorMessage); + + QDBusObjectPath objectPath() const; + + void requestStateChange(State state); + +public Q_SLOTS: + void finished(); + +Q_SIGNALS: + void suspendRequested(); + void resumeRequested(); + void cancelRequested(); + +protected: + void timerEvent(QTimerEvent *event); + +private: + void scheduleUpdate(); + void updateEta(); + int unitId(const QString &unit); + + QDBusObjectPath m_objectPath; + QBasicTimer m_updateTimer; + + uint m_capabilities; + uint m_percent; + uint m_jobId; + + // for ETA calculation we cache these values + qlonglong m_speed; + qlonglong m_totalBytes; + qlonglong m_processedBytes; + + State m_state; + + QMap m_unitMap; + int m_bytesUnitId; + int m_unitId; + + static uint s_jobId; +}; + +#endif diff --git a/plasma/generic/dataengines/applicationjobs/plasma-dataengine-applicationjobs.desktop b/plasma/generic/dataengines/applicationjobs/plasma-dataengine-applicationjobs.desktop new file mode 100644 index 00000000..53c1b3c9 --- /dev/null +++ b/plasma/generic/dataengines/applicationjobs/plasma-dataengine-applicationjobs.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +Name=Application Job Information +Name[ar]=معلومات مهام التطبيقات +Name[ast]=Información de xera d'aplicación +Name[be@latin]=Źviestki pra zadańnie aplikacyi +Name[bs]=podaci o poslovima programâ +Name[ca]=Informació de les tasques de les aplicacions +Name[ca@valencia]=Informació de les tasques de les aplicacions +Name[cs]=Informace o práci aplikace +Name[csb]=Wëdowiédzô ò robòce aplikacëjów +Name[da]=Information om programjob +Name[de]=Anwendungsaufgaben-Informationen +Name[el]=Πληροφορίες εργασιών εφαρμογών +Name[en_GB]=Application Job Information +Name[eo]=Aplikaĵaj Taskaj Informoj +Name[es]=Información de tarea de aplicación +Name[et]=Rakenduste tööde teave +Name[eu]=Aplikazioko lanei buruzko informazioa +Name[fi]=Sovellustyötiedot +Name[fr]=Informations sur les tâches d'applications en cours d'exécution +Name[fy]=Programma taak ynformaasje +Name[ga]=Eolas Faoi Jabanna Feidhmchláir +Name[gl]=Información de tarefas de programa +Name[gu]=કાર્યક્રમ કાર્ય માહિતી +Name[he]=מידע אודות עבודת יישום +Name[hi]=अनुप्रयोग कार्य जानकारी +Name[hne]=अनुपरयोग काम सूचना +Name[hr]=Informacije o poslovima aplikacija +Name[hu]=Az alkalmazások jellemzői +Name[ia]=Information de travalio de application +Name[id]=Informasi Tugas Aplikasi +Name[is]=Tilkynningar um verkefni forrita +Name[it]=Informazioni sui processi delle applicazioni +Name[ja]=アプリケーションのジョブ情報 +Name[kk]=Қолданба тапсырмасының ақпараты +Name[km]=ព័ត៌មាន​ការងារ​របស់​កម្មវិធី +Name[kn]=ಅನ್ವಯ ಕಾರ್ಯ ಮಾಹಿತಿ +Name[ko]=프로그램 작업 정보 +Name[ku]=Agahiyên Karê Sepanê +Name[lt]=Programos darbo informacija +Name[lv]=Programmas darba informācija +Name[ml]=പ്രയോഗ ജോലി അറിയിപ്പുകള്‍ +Name[mr]=अनुप्रयोग कार्यविषयी माहिती +Name[nb]=Informasjon om programjobb +Name[nds]=Programm-Opgaavinformatschoon +Name[nl]=Programmataakmeldingen +Name[nn]=Informasjon om programjobb +Name[or]=ପ୍ରୟୋଗ କାର୍ଯ୍ୟ ସୂଚନା +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਜਾਬ ਜਾਣਕਾਰੀ +Name[pl]=Informacja o zadaniu programu +Name[pt]=Informação da Tarefa da Aplicação +Name[pt_BR]=Informações da tarefa do aplicativo +Name[ro]=Informație despre sarcina aplicației +Name[ru]=Системные уведомления +Name[si]=යෙදුම් කාර්‍යය තොරතුරු +Name[sk]=Informácie o aplikácii +Name[sl]=Opravila programov +Name[sr]=подаци о пословима програма̂ +Name[sr@ijekavian]=подаци о пословима програма̂ +Name[sr@ijekavianlatin]=podaci o poslovima programâ̂ +Name[sr@latin]=podaci o poslovima programâ̂ +Name[sv]=Information om programjobb +Name[ta]=பயன்பாட்டு பணி விவரம் +Name[tg]=Иттилооти корҳои барнома +Name[th]=ข้อมูลงานของโปรแกรม +Name[tr]=Uygulama Görev Bilgileri +Name[ug]=پروگرامما خىزمەت ئۇچۇرى +Name[uk]=Відомості про завдання програми +Name[vi]=Thông tin công việc ứng dụng +Name[wa]=Pondants et djondants so les bouyes des programes +Name[x-test]=xxApplication Job Informationxx +Name[zh_CN]=程序任务信息 +Name[zh_TW]=應用程式工作資訊 +Comment=Application job updates (via kuiserver) +Comment[ar]=تحديثات مهام التطبيقات (عن طريق kuiserver) +Comment[ast]=Anovamientos de l'aplicación (vía kuiserver) +Comment[bs]=Ažuriranja programskih poslova (preko KUI‑servera) +Comment[ca]=Actualització de treballs d'aplicacions (via kuiserver) +Comment[ca@valencia]=Actualització de treballs d'aplicacions (via kuiserver) +Comment[cs]=Aktualizace úloh aplikací (pomocí kuiserver) +Comment[da]=Jobopdateringer for program (via kuiserver) +Comment[de]=Aktualisierung von Anwendungs-Aktionen (via kuiserver) +Comment[el]=Ενημέρωση εργασιών εφαρμογών (μέσω kuiserver) +Comment[en_GB]=Application job updates (via kuiserver) +Comment[eo]=Apikaĵaj taskoj ĝisdatigitaj (per kuiserver) +Comment[es]=Actualizaciones de la aplicación (vía kuiserver) +Comment[et]=Rakenduse töö uuendused (kuiserver'i kaudu) +Comment[eu]=Aplikazioko lanen eguneratzeak (kuiserver bidez) +Comment[fi]=Sovellustyöpäivitykset (kuiserver-palvelimen kautta) +Comment[fr]=Mise à jours des tâches d'application (via « kuiserver ») +Comment[fy]=Applikaasje taak fernijing (mei kuiserver) +Comment[gl]=Actualización de tarefa do programa (mediante kuiserver) +Comment[he]=עידכוני עבודת יישום (באמצעות kuiserver) +Comment[hr]=Ažuriranja poslova aplikacija (preko kuiservera) +Comment[hu]=Feladatfrissítő (a kuiserveren keresztül) +Comment[ia]=Actualisationes de travalio de application (via kuiserver) +Comment[id]=Tugas aplikasi dimutakhirkan (via kuiserver) +Comment[is]=Uppfærslutilkynningar um verkefni forrita (með kuiserver) +Comment[it]=Aggiornamenti sui processi delle applicazioni (via kuiserver) +Comment[ja]=アプリケーションジョブ更新 (kuiserver 経由) +Comment[kk]=Қолданба тапсырмасын жаңарту (kuiserver арқылы) +Comment[km]=បច្ចុប្បន្នភាព​​ការងារ​របស់​កម្មវិធី (តាមរយៈ kuiserver) +Comment[kn]=ಅನ್ವಯ ಕಾರ್ಯ ಅಪ್‌ಡೇಟ್‌ಗಳು (kuiserver ಮೂಲಕ) +Comment[ko]=프로그램 작업 업데이트 (kuiserver를 통하여) +Comment[lt]=Programų darbų atnaujinimai (per kuiserver) +Comment[lv]=Programmas darba atjauninājumu (izm. kuiserver) +Comment[mai]=अनुप्रयोग कार्य अद्यतन (kuiserver के द्वारा) +Comment[ml]=പ്രയോഗ ജോലിയിലെ മാറ്റങ്ങള്‍ (കൂയിസെര്‍വര്‍ വഴി) +Comment[mr]=अनुप्रयोग कार्य अद्ययावत माहिती (kuiserver द्वारे) +Comment[nb]=Programjobb-oppdateringer (via kuiserver) +Comment[nds]=Programmopgaav-Opfrischen (över »kuiserver«) +Comment[nl]=Applicatiejob bijwerken (via kuiserver) +Comment[nn]=Oppdateringar for programjobbar (gjennom kuiserver) +Comment[pa]=ਐਪਲੀਕੇਸ਼ਨ ਜਾਬ ਅੱਪਡੇਟ (kuiserver ਰਾਹੀਂ) +Comment[pl]=Uaktualnienia zadań programu (przez kuiserver) +Comment[pt]=Actualizações das tarefas da aplicação (através do 'kuiserver') +Comment[pt_BR]=Atualizações de tarefas de aplicativos (via kuiserver) +Comment[ro]=Actualizări pentru sarcina aplicației (via kuiserver) +Comment[ru]=Обновление заданий приложений (с помощью диспетчера заданий) +Comment[si]=යෙදුම් කාර්‍ය යාවත්කාලීන (kuiserver වෙතින්) +Comment[sk]=Aktualizácie úloh aplikácií (pomocou kuiserver) +Comment[sl]=Obveščanje o opravilih programov (prek KUIServer) +Comment[sr]=Ажурирања програмских послова (преко КУИ‑сервера) +Comment[sr@ijekavian]=Ажурирања програмских послова (преко КУИ‑сервера) +Comment[sr@ijekavianlatin]=Ažuriranja programskih poslova (preko KUIServera) +Comment[sr@latin]=Ažuriranja programskih poslova (preko KUIServera) +Comment[sv]=Uppdateringar av information om programjobb (via kuiserver) +Comment[tg]=Иттилооти амалҳои система (via kuiserver) +Comment[th]=ปรับปรุงงานของโปรแกรม (ผ่านทาง kuiserver) +Comment[tr]=Uygulama görevi güncellemeleri (kuiserver ile) +Comment[ug]=پروگرامما ۋەزىپىسى يېڭىلاندى(kuiserver ئارقىلىق) +Comment[uk]=Оновлення завдань програми (через kuiserver) +Comment[wa]=Metaedjes a djoû des bouyes des programes (via kuiserver) +Comment[x-test]=xxApplication job updates (via kuiserver)xx +Comment[zh_CN]=提供程序任务更新信息(通过 kuiserver) +Comment[zh_TW]=應用程式工作更新(透過 kuiserver) +Type=Service +X-KDE-ServiceTypes=Plasma/DataEngine +Icon=tool-animator +X-KDE-Library=plasma_engine_applicationjobs + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=applicationjobs +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= diff --git a/plasma/generic/dataengines/apps/CMakeLists.txt b/plasma/generic/dataengines/apps/CMakeLists.txt new file mode 100644 index 00000000..05d139cb --- /dev/null +++ b/plasma/generic/dataengines/apps/CMakeLists.txt @@ -0,0 +1,13 @@ +set(apps_engine_SRCS + appsengine.cpp + appsource.cpp + appservice.cpp + appjob.cpp +) + +kde4_add_plugin(plasma_engine_apps ${apps_engine_SRCS}) +target_link_libraries(plasma_engine_apps ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_engine_apps DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-apps.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES apps.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) diff --git a/plasma/generic/dataengines/apps/appjob.cpp b/plasma/generic/dataengines/apps/appjob.cpp new file mode 100644 index 00000000..3a91b1e4 --- /dev/null +++ b/plasma/generic/dataengines/apps/appjob.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "appjob.h" + +#include + +AppJob::AppJob(AppSource *source, const QString &operation, QMap ¶meters, QObject *parent) : + ServiceJob(source->objectName(), operation, parameters, parent), + m_source(source) +{ +} + +AppJob::~AppJob() +{ +} + +void AppJob::start() +{ + const QString operation = operationName(); + if (operation == "launch") { + QString path = m_source->getApp()->entryPath(); + new KRun(KUrl(path), 0); + setResult(true); + return; + } + setResult(false); +} + +#include "appjob.moc" diff --git a/plasma/generic/dataengines/apps/appjob.h b/plasma/generic/dataengines/apps/appjob.h new file mode 100644 index 00000000..2d59aec1 --- /dev/null +++ b/plasma/generic/dataengines/apps/appjob.h @@ -0,0 +1,45 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TASKJOB_H +#define TASKJOB_H + +// plasma +#include + +// own +#include "appsource.h" + +class AppJob : public Plasma::ServiceJob +{ + + Q_OBJECT + + public: + AppJob(AppSource *source, const QString &operation, QMap ¶meters, QObject *parent = 0); + ~AppJob(); + + protected: + void start(); + + private: + AppSource *m_source; + +}; + +#endif // TASKJOB_H diff --git a/plasma/generic/dataengines/apps/apps.operations b/plasma/generic/dataengines/apps/apps.operations new file mode 100644 index 00000000..837549f8 --- /dev/null +++ b/plasma/generic/dataengines/apps/apps.operations @@ -0,0 +1,5 @@ + + + + + diff --git a/plasma/generic/dataengines/apps/appsengine.cpp b/plasma/generic/dataengines/apps/appsengine.cpp new file mode 100644 index 00000000..340705c0 --- /dev/null +++ b/plasma/generic/dataengines/apps/appsengine.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "appsengine.h" +#include "appsource.h" + +#include + +AppsEngine::AppsEngine(QObject *parent, const QVariantList &args) : + Plasma::DataEngine(parent, args) +{ + Q_UNUSED(args); +} + +AppsEngine::~AppsEngine() +{ +} + +void AppsEngine::init() +{ + addGroup(KServiceGroup::root()); + connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), this, SLOT(sycocaChanged(QStringList))); +} + +void AppsEngine::sycocaChanged(const QStringList &changes) +{ + if (changes.contains("apps") || changes.contains("xdgdata-apps")) { + removeAllSources(); + addGroup(KServiceGroup::root()); + } +} + +Plasma::Service *AppsEngine::serviceForSource(const QString &name) +{ + AppSource *source = dynamic_cast(containerForSource(name)); + // if source does not exist, return null service + if (!source) { + return Plasma::DataEngine::serviceForSource(name); + } + + // if source represents a group or something, return null service + if (!source->isApp()) { + return Plasma::DataEngine::serviceForSource(name); + } + // if source represent a proper app, return real service + Plasma::Service *service = source->createService(); + service->setParent(this); + return service; +} + +void AppsEngine::addGroup(KServiceGroup::Ptr group) +{ + if (!(group && group->isValid())) { + return; + } + AppSource *appSource = new AppSource(group, this); + //TODO listen for changes + addSource(appSource); + //do children + foreach (const KServiceGroup::Ptr subGroup, group->groupEntries(KServiceGroup::NoOptions)) { + addGroup(subGroup); + } + foreach (const KService::Ptr app, group->serviceEntries(KServiceGroup::NoOptions)) { + addApp(app); + } +} + +void AppsEngine::addApp(KService::Ptr app) +{ + AppSource *appSource = new AppSource(app, this); + //TODO listen for changes + addSource(appSource); +} + +K_EXPORT_PLASMA_DATAENGINE(apps, AppsEngine) + +#include "appsengine.moc" diff --git a/plasma/generic/dataengines/apps/appsengine.h b/plasma/generic/dataengines/apps/appsengine.h new file mode 100644 index 00000000..d19b4a11 --- /dev/null +++ b/plasma/generic/dataengines/apps/appsengine.h @@ -0,0 +1,66 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TASKSENGINE_H +#define TASKSENGINE_H + +// plasma +#include +#include + +#include +#include + +/** + * Apps Data Engine + * + * FIXME + * This engine provides information regarding tasks (windows that are currently open) + * as well as startup tasks (windows that are about to open). + * Each task and startup is represented by a unique source. Sources are added and removed + * as windows are opened and closed. You cannot request a customized source. + * + * A service is also provided for each task. It exposes some operations that can be + * performed on the windows (ex: maximize, minimize, activate). + * + * The data and operations are provided and handled by the taskmanager library. + * It should be noted that only a subset of data and operations are exposed. + */ +class AppsEngine : public Plasma::DataEngine +{ + + Q_OBJECT + + public: + AppsEngine(QObject *parent, const QVariantList &args); + ~AppsEngine(); + Plasma::Service *serviceForSource(const QString &name); + + protected: + virtual void init(); + + private slots: + void sycocaChanged(const QStringList &changes); + + private: + friend class AppSource; + void addGroup(KServiceGroup::Ptr group); + void addApp(KService::Ptr app); +}; + +#endif // TASKSENGINE_H diff --git a/plasma/generic/dataengines/apps/appservice.cpp b/plasma/generic/dataengines/apps/appservice.cpp new file mode 100644 index 00000000..adf1240b --- /dev/null +++ b/plasma/generic/dataengines/apps/appservice.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "appservice.h" + +// own +#include "appjob.h" + +AppService::AppService(AppSource *source) : + Plasma::Service(source), + m_source(source) +{ + setName("apps"); +} + +AppService::~AppService() +{ +} + +Plasma::ServiceJob *AppService::createJob(const QString &operation, QMap ¶meters) +{ + return new AppJob(m_source, operation, parameters, this); +} + +#include "appservice.moc" diff --git a/plasma/generic/dataengines/apps/appservice.h b/plasma/generic/dataengines/apps/appservice.h new file mode 100644 index 00000000..cd6e4f6c --- /dev/null +++ b/plasma/generic/dataengines/apps/appservice.h @@ -0,0 +1,48 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TASKSERVICE_H +#define TASKSERVICE_H + +// plasma +#include +#include + +// own +#include "appsource.h" + +/** + * App Service + */ +class AppService : public Plasma::Service +{ + + Q_OBJECT + + public: + AppService(AppSource *source); + ~AppService(); + + protected: + Plasma::ServiceJob *createJob(const QString &operation, QMap ¶meters); + + private: + AppSource *m_source; +}; + +#endif // TASKSERVICE_H diff --git a/plasma/generic/dataengines/apps/appsource.cpp b/plasma/generic/dataengines/apps/appsource.cpp new file mode 100644 index 00000000..0596a452 --- /dev/null +++ b/plasma/generic/dataengines/apps/appsource.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "appsource.h" +#include "appsengine.h" +#include "appservice.h" + +#include + +AppSource::AppSource(KServiceGroup::Ptr group, QObject *parent) : + Plasma::DataContainer(parent), + m_group(group), + m_app(), + m_isApp(false) +{ + setObjectName(m_group->entryPath()); + setData("isApp", false); + updateGroup(); +} + +AppSource::AppSource(KService::Ptr app, QObject *parent) : + Plasma::DataContainer(parent), + m_group(), + m_app(app), + m_isApp(true) +{ + setObjectName(m_app->storageId()); + setData("isApp", true); + updateApp(); +} + +AppSource::~AppSource() +{ +} + +Plasma::Service *AppSource::createService() +{ + return new AppService(this); +} + +KService::Ptr AppSource::getApp() +{ + return m_app; +} + +bool AppSource::isApp() const +{ + return m_isApp; +} + +void AppSource::updateGroup() +{ + setData("iconName", m_group->icon()); + setData("name", m_group->caption()); + setData("comment", m_group->comment()); + setData("display", !m_group->noDisplay()); + + QStringList entries; + foreach (KSycocaEntry::Ptr p, m_group->entries(true, false, true)) { + if (p->isType(KST_KService)) { + const KService::Ptr service = KService::Ptr::staticCast(p); + entries << service->storageId(); + } else if (p->isType(KST_KServiceGroup)) { + const KServiceGroup::Ptr service = KServiceGroup::Ptr::staticCast(p); + entries << service->entryPath(); + } else if (p->isType(KST_KServiceSeparator)) { + entries << "---"; + } else { + kDebug() << "unexpected object in entry list"; + } + } + setData("entries", entries); + + checkForUpdate(); +} + +void AppSource::updateApp() +{ + setData("iconName", m_app->icon()); + setData("name", m_app->name()); + setData("genericName", m_app->genericName()); + setData("menuId", m_app->menuId()); + setData("entryPath", m_app->entryPath()); + setData("comment", m_app->comment()); + setData("keywords", m_app->keywords()); + setData("categories", m_app->categories()); + setData("display", !m_app->noDisplay()); + checkForUpdate(); +} + +#include "appsource.moc" diff --git a/plasma/generic/dataengines/apps/appsource.h b/plasma/generic/dataengines/apps/appsource.h new file mode 100644 index 00000000..92fc3c8e --- /dev/null +++ b/plasma/generic/dataengines/apps/appsource.h @@ -0,0 +1,59 @@ +/* + * Copyright 2009 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TASKSOURCE_H +#define TASKSOURCE_H + +// plasma +#include + +#include +#include + +/** + * App Source + */ +class AppSource : public Plasma::DataContainer +{ + + Q_OBJECT + + public: + AppSource(KServiceGroup::Ptr startup, QObject *parent); + AppSource(KService::Ptr app, QObject *parent); + ~AppSource(); + + protected: + Plasma::Service *createService(); + KService::Ptr getApp(); + bool isApp() const; + + private slots: + void updateGroup(); + void updateApp(); + + private: + friend class AppsEngine; + friend class AppJob; + KServiceGroup::Ptr m_group; + KService::Ptr m_app; + bool m_isApp; + +}; + +#endif // TASKSOURCE_H diff --git a/plasma/generic/dataengines/apps/plasma-dataengine-apps.desktop b/plasma/generic/dataengines/apps/plasma-dataengine-apps.desktop new file mode 100644 index 00000000..0302e3a0 --- /dev/null +++ b/plasma/generic/dataengines/apps/plasma-dataengine-apps.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +Name=Application Information +Name[ar]=معلومات التطبيقات +Name[ast]=Información de l'aplicación +Name[bn]=অ্যাপলিকেশন তথ্য +Name[bs]=podaci o programima +Name[ca]=Informació de les aplicacions +Name[ca@valencia]=Informació de les aplicacions +Name[cs]=Informace o aplikaci +Name[csb]=Wëdowiédzô ò aplikacëji +Name[da]=Programinformation +Name[de]=Anwendungsinformationen +Name[el]=Πληροφορίες εφαρμογών +Name[en_GB]=Application Information +Name[eo]=Aplikaĵaj Informoj +Name[es]=Información de la aplicación +Name[et]=Rakenduse teave +Name[eu]=Aplikazioari buruzko informazioa +Name[fi]=Sovellustiedot +Name[fr]=Informations sur l'application +Name[fy]=Applikaasje ynformaasje +Name[ga]=Eolas faoi Fheidhmchláir +Name[gl]=Información do programa +Name[gu]=કાર્યક્રમ માહિતી +Name[he]=מידע אודות יישום +Name[hi]=अनुप्रयोग जानकारी +Name[hr]=Informacije o aplikacijama +Name[hu]=Az alkalmazások jellemzői +Name[ia]=Information de application +Name[id]=Informasi Aplikasi +Name[is]=Upplýsingar um forrit +Name[it]=Informazioni sulle applicazioni +Name[ja]=アプリケーションの情報 +Name[kk]=Қолданбаның ақпараты +Name[km]=ព័ត៌មាន​កម្មវិធី +Name[kn]=ಅನ್ವಯ ಮಾಹಿತಿ +Name[ko]=프로그램 정보 +Name[lt]=Programos informacija +Name[lv]=Programmas informācija +Name[mk]=Информации за апликации +Name[ml]=പ്രയോഗ വിവരം +Name[mr]=अनुप्रयोग माहिती +Name[nb]=Informasjon om program +Name[nds]=Programm-Informatschoon +Name[nl]=Programmainformatie +Name[nn]=Programinformasjon +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਜਾਣਕਾਰੀ +Name[pl]=Informacja o programie +Name[pt]=Informação da Aplicação +Name[pt_BR]=Informações do aplicativo +Name[ro]=Informații despre aplicații +Name[ru]=Информация о приложениях +Name[si]=යෙදුම් තොරතුරු +Name[sk]=Informácie o aplikácii +Name[sl]=Podatki o programih +Name[sr]=подаци о програмима +Name[sr@ijekavian]=подаци о програмима +Name[sr@ijekavianlatin]=podaci o programima +Name[sr@latin]=podaci o programima +Name[sv]=Information om program +Name[tg]=Иттилооти барнома +Name[th]=ข้อมูลของโปรแกรม +Name[tr]=Uygulama Bilgileri +Name[ug]=پروگرامما ئۇچۇرى +Name[uk]=Відомості щодо програм +Name[vi]=Thông tin ứng dụng +Name[wa]=Pondants et djondants do programe +Name[x-test]=xxApplication Informationxx +Name[zh_CN]=程序信息 +Name[zh_TW]=應用程式資訊 +Comment=Information and launching of all applications in the app menu. +Comment[ar]=معلومات وتشغيل جميع البرامج في قائمة البرامج +Comment[ast]=Información y execución de toles aplicaciones nel menú d'aplicaciones. +Comment[bs]=Podaci o programima iz programskog menija i njihovo pokretanje. +Comment[ca]=Informació i execució de totes les aplicacions en el menú d'aplicacions. +Comment[ca@valencia]=Informació i execució de totes les aplicacions en el menú d'aplicacions. +Comment[cs]=Informace a spouštění všech aplikací v nabídce aplikací. +Comment[da]=Information og opstart af alle programmer i programmenuen. +Comment[de]=Informationen und Starten aller Anwendungen im Programmmenü. +Comment[el]=Πληροφορίες και εκτέλεση όλων των εφαρμογών στο μενού εφαρμογών. +Comment[en_GB]=Information and launching of all applications in the app menu. +Comment[es]=Información y ejecución de todas las aplicaciones en el menú de aplicaciones. +Comment[et]=Kõigi rakenduste menüü rakenduste teave ja käivitamine. +Comment[eu]=Aplikazio-menuko aplikazio guztiei buruzko informazioa eta haien abiaraztea. +Comment[fi]=Tietoja ja kaikkien sovellusten käynnistäminen sovellusvalikossa. +Comment[fr]=Informations et démarrage de toutes les applications du menu des applications. +Comment[fy]=Ynformaasje en útfiere fan alle applikaasjes yn it app menu. +Comment[gl]=Información e inicio de todos os programas do menú. +Comment[he]=מידע והפעלה של כל היישומים בתפריט היישומים. +Comment[hr]=Informacije i pokretanja od svih aplikacija u izborniku aplikacija. +Comment[hu]=Az alkalmazásmenü alkalmazásainak indítása és jellemzőinek megjelenítése. +Comment[ia]=Information e lanceamento de omne applicationes in le menu de app +Comment[id]=Informasi dan meluncurkan semua aplikasi di menu aplikasi. +Comment[is]=Upplýsingar um og ræsing allra forrita í forritavalmyndinni. +Comment[it]=Informazioni e avvio di tutte le applicazioni nel loro menu. +Comment[ja]=アプリケーションメニューのすべてのアプリケーション用の情報・起動サービスです。 +Comment[kk]=Қолданбаның мәзірінен барлық қолданбаларды жегу және олардын ақпараттары. +Comment[km]=ព័ត៌មាន និង​ការ​ចាប់ផ្ដើម​កម្មវិធី​ទាំងអស់​នៅ​ក្នុង​ម៉ឺនុយ​កម្មវិធី ។ +Comment[kn]=App ಮೆನುವಿನಲ್ಲಿರುವ ಎಲ್ಲಾ ಅನ್ವಯಗಳ ಬಗೆಗಿನ ಮಾಹಿತಿ ಹಾಗು ಪ್ರಕ್ಷೇಪಣೆ(ಲಾಂಚಿಂಗ್). +Comment[ko]=프로그램 메뉴의 정보를 보고 실행할 수 있도록 합니다. +Comment[lt]=Programų leistukai ir informacija iš programų meniu. +Comment[lv]=Visu programmu informācija un palaišana programmu izvēlnē. +Comment[mk]=Информации и стартување на сите апликации од менито за апликации +Comment[ml]=ആപ്പ് മെനുവിലെ പ്രയോഗങ്ങളുടെ വിവരവും തുടക്കവും. +Comment[mr]=अनुप्रयोग मेन्यू मधील अनुप्रयोगांची माहिती व प्रक्षेपण +Comment[nb]=Informasjon og oppstart av alle programmer i programmenyen. +Comment[nds]=Infos över un opropen vun all Programmen binnen dat Programmmenü +Comment[nl]=Informatie en starten van alle programma's in het progmenu. +Comment[nn]=Informasjon og køyring av alle programma i programmenyen. +Comment[pa]=ਐਪਲੀਕੇਸ਼ਨ ਮੇਨ ਵਿੱਚ ਸਭ ਐਪਲੀਕੇਸ਼ਨਾਂ ਲਈ ਜਾਣਕਾਰੀ ਅਤੇ ਚਲਾਉਣਾ। +Comment[pl]=Uruchamianie dowolnych programów z menu i informacja o nich. +Comment[pt]=Informação e lançamento de todas as aplicações no menu de aplicações. +Comment[pt_BR]=Informação e inicialização de todos os aplicativos no menu de aplicativos. +Comment[ro]=Informații și lansare de aplicații în meniul aplicațiilor. +Comment[ru]=Информация и запуск всех приложений из меню приложений. +Comment[si]=යෙදුම් මෙනුවේ ඇති සියළු යෙදුම් ආරම්භ කිරීමේ තොරතුරු +Comment[sk]=Informácie a spúšťanie všetkých aplikácií v menu aplikácie. +Comment[sl]=Podatki o vseh programih v meniju in njihovo zaganjanje +Comment[sr]=Подаци о програмима из програмског менија и њихово покретање. +Comment[sr@ijekavian]=Подаци о програмима из програмског менија и њихово покретање. +Comment[sr@ijekavianlatin]=Podaci o programima iz programskog menija i njihovo pokretanje. +Comment[sr@latin]=Podaci o programima iz programskog menija i njihovo pokretanje. +Comment[sv]=Information om och start av alla program i programmenyn. +Comment[tg]=Иттилоот ва оғозии ҳамаи барномаҳо аз меню. +Comment[th]=ข้อมูลและการเรียกใช้โปรแกรมทั้งหมดที่อยู่ในเมนูโปรแกรม +Comment[tr]=Uygulama menüsündeki tüm uygulamalar hakkında bilgiler ve uygulamaları çalıştırma. +Comment[ug]=ئۇچۇر كۆرسىتىدۇ ياكى تىزىملىكتىكى ھەممە پروگراممىلارنى ئىجرا قىلىدۇ +Comment[uk]=Відомості і запуск всіх програма з меню програм. +Comment[vi]=Thông tin và khởi chạy tất cả các ứng dụng trong trình đơn ứng dụng. +Comment[wa]=Informåcions eyet enondaedje di tos les programes del dressêye des programes. +Comment[x-test]=xxInformation and launching of all applications in the app menu.xx +Comment[zh_CN]=显示信息或启动菜单中的所有应用程序。 +Comment[zh_TW]=列出資訊或啟動選單中所有應用程式 +Type=Service +Icon=user-desktop + +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-Library=plasma_engine_apps + +X-KDE-PluginInfo-Author=Chani +X-KDE-PluginInfo-Email=chani@kde.org +X-KDE-PluginInfo-Name=apps +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/dataengines/calendar/CMakeLists.txt b/plasma/generic/dataengines/calendar/CMakeLists.txt new file mode 100644 index 00000000..6ad3b610 --- /dev/null +++ b/plasma/generic/dataengines/calendar/CMakeLists.txt @@ -0,0 +1,44 @@ +project(calendar_engine) + +include_directories( + ${KDEPIMLIBS_INCLUDE_DIRS} + ${Boost_INCLUDE_DIR} +) + +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) + +set(calendar_engine_srcs + calendarengine.cpp +) + +if(Akonadi_FOUND) + ADD_DEFINITIONS(-DAKONADI_FOUND) + set(calendar_engine_srcs ${calendar_engine_srcs} + eventdatacontainer.cpp + ) +endif(Akonadi_FOUND) + +kde4_add_plugin(plasma_engine_calendar ${calendar_engine_srcs}) + +target_link_libraries( + plasma_engine_calendar + ${KDEPIMLIBS_KHOLIDAYS_LIBRARY} + ${KDE4_KDECORE_LIBS} + ${KDE4_PLASMA_LIBS} + ${KDE4_KMIME_LIBS} + ${KDE4_KCALCORE_LIBS} + ${KDE4_KCALUTILS_LIBS} +) + +if(Akonadi_FOUND) + target_link_libraries( + plasma_engine_calendar + akonadi-calendar + ${KDE4_AKONADI_LIBS} + ${KDEPIMLIBS_AKONADI_KCAL_LIBS} + ) +endif(Akonadi_FOUND) + +install(TARGETS plasma_engine_calendar DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-calendar.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/dataengines/calendar/Messages.sh b/plasma/generic/dataengines/calendar/Messages.sh new file mode 100755 index 00000000..9a5efa3c --- /dev/null +++ b/plasma/generic/dataengines/calendar/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT `find . -name \*.cpp` -o $podir/plasma_engine_calendar.pot diff --git a/plasma/generic/dataengines/calendar/calendar.operations b/plasma/generic/dataengines/calendar/calendar.operations new file mode 100644 index 00000000..b429b8f2 --- /dev/null +++ b/plasma/generic/dataengines/calendar/calendar.operations @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/calendar/calendarengine.cpp b/plasma/generic/dataengines/calendar/calendarengine.cpp new file mode 100644 index 00000000..5b98d8a0 --- /dev/null +++ b/plasma/generic/dataengines/calendar/calendarengine.cpp @@ -0,0 +1,314 @@ +/* + Copyright (c) 2009 Davide Bettio + Copyright (c) 2010 Frederik Gladhorn + + 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 "calendarengine.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#ifdef AKONADI_FOUND +#include "eventdatacontainer.h" +#endif + +CalendarEngine::CalendarEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent) +{ + Q_UNUSED(args); +} + +CalendarEngine::~CalendarEngine() +{ + qDeleteAll(m_regions); +} + +bool CalendarEngine::sourceRequestEvent(const QString &request) +{ + kDebug() << "Request = " << request << '\n'; + + if (request.isEmpty()) { + return false; + } + + QStringList requestTokens = request.split(':'); + QString requestKey = requestTokens.takeFirst(); + + if (requestKey == "holidaysRegions" || + requestKey == "holidaysRegion" || + requestKey == "holidaysDefaultRegion" || + requestKey == "holidaysIsValidRegion" || + requestKey == "holidays" || + requestKey == "holidaysInMonth") { + return holidayCalendarSourceRequest(requestKey, requestTokens, request); + } + +#ifdef AKONADI_FOUND + if (requestKey == "events" || requestKey == "eventsInMonth") { + return akonadiCalendarSourceRequest(requestKey, requestTokens, request); + } +#endif + + return false; +} + +bool CalendarEngine::holidayCalendarSourceRequest(const QString& key, const QStringList& args, const QString& request) +{ + if (key == "holidaysRegions") { + QStringList regionList = KHolidays::HolidayRegion::regionCodes(); + Plasma::DataEngine::Data data; + foreach (const QString ®ionCode, regionList) { + Plasma::DataEngine::Data regionData; + KHolidays::HolidayRegion region(regionCode); + regionData.insert("Name", region.name()); + regionData.insert("Description", region.description()); + regionData.insert("CountryCode", region.countryCode()); + regionData.insert("Location", region.location()); + regionData.insert("LanguageCode", region.languageCode()); + data.insert(regionCode, regionData); + } + setData(request, data); + return true; + } + + if (key == "holidaysDefaultRegion") { + // If not set or the locale has changed since last set, then try determine a default region. + if(m_defaultHolidayRegion.isEmpty() || + m_defaultHolidayRegionCountry != KGlobal::locale()->country() || + m_defaultHolidayRegionLanguage != KGlobal::locale()->language()) { + + m_defaultHolidayRegion = QString(); + m_defaultHolidayRegionCountry = KGlobal::locale()->country(); + m_defaultHolidayRegionLanguage = KGlobal::locale()->language(); + + m_defaultHolidayRegion = KHolidays::HolidayRegion::defaultRegionCode( + m_defaultHolidayRegionCountry.toLower(), + m_defaultHolidayRegionLanguage.toLower() ); + if (m_defaultHolidayRegion.isEmpty()) { + m_defaultHolidayRegion = "NoDefault"; + } + } + + if (m_defaultHolidayRegion == "NoDefault") { + setData(request, QString()); + } else { + setData(request, m_defaultHolidayRegion); + } + return true; + } + + + int argsCount = args.count(); + if (argsCount < 1) { + return false; + } + + const QStringList regionCodeList = args.at(0).split(','); + if (regionCodeList.count() < 1) { + return false; + } + + foreach ( const QString ®ionCode, regionCodeList ) { + KHolidays::HolidayRegion *region = m_regions.value(regionCode); + if (!region || !region->isValid()) { + region = new KHolidays::HolidayRegion(regionCode); + if (region->isValid()) { + m_regions.insert(regionCode, region); + } else { + delete region; + return false; + } + } + } + + if (key == "holidaysIsValidRegion") { + if (regionCodeList.count() > 1) { + return false; + } + QString regionCode = regionCodeList.at(0); + if (m_regions.contains(regionCode)) { + setData(request, m_regions.value(regionCode)->isValid()); + } else { + setData(request, KHolidays::HolidayRegion::isValid(regionCode)); + } + return true; + } + + if (key == "holidaysRegion") { + Plasma::DataEngine::Data data; + foreach (const QString ®ionCode, regionCodeList) { + Plasma::DataEngine::Data regionData; + KHolidays::HolidayRegion *region = m_regions.value(regionCode); + regionData.insert("Name", region->name()); + regionData.insert("Description", region->description()); + regionData.insert("CountryCode", region->countryCode()); + regionData.insert("Location", region->location()); + regionData.insert("LanguageCode", region->languageCode()); + data.insert(regionCode, regionData); + } + setData(request, data); + return true; + } + + if (argsCount < 2) { + return false; + } + + QDate dateArg = QDate::fromString(args.at(1), Qt::ISODate); + if (!dateArg.isValid()) { + return false; + } + + if (key == "holidaysInMonth" || key == "holidays") { + QDate startDate, endDate; + if (key == "holidaysInMonth") { + int requestYear, requestMonth; + KGlobal::locale()->calendar()->getDate(dateArg, &requestYear, &requestMonth, 0); + int lastDay = KGlobal::locale()->calendar()->daysInMonth(dateArg); + KGlobal::locale()->calendar()->setDate(startDate, requestYear, requestMonth, 1); + KGlobal::locale()->calendar()->setDate(endDate, requestYear, requestMonth, lastDay); + } else if (argsCount == 2) { + startDate = dateArg; + endDate = dateArg; + } else if (argsCount < 3) { + return false; + } else { + startDate = dateArg; + endDate = QDate::fromString(args.at(2), Qt::ISODate); + } + + if (!startDate.isValid() || !endDate.isValid()) { + return false; + } + + QList holidayList; + foreach ( const QString ®ionCode, regionCodeList ) { + KHolidays::HolidayRegion *region = m_regions.value(regionCode); + KHolidays::Holiday::List holidays; + holidays = region->holidays(startDate, endDate, KHolidays::Holiday::MultidayHolidaysAsSingleEvents); + + foreach (const KHolidays::Holiday &holiday, holidays) { + if (!holiday.text().isEmpty()) { + Plasma::DataEngine::Data holidayData; + holidayData.insert("Name", holiday.text()); + holidayData.insert("RegionCode", regionCode); + holidayData.insert("ObservanceStartDate", holiday.observedStartDate().toString(Qt::ISODate)); + holidayData.insert("ObservanceEndDate", holiday.observedEndDate().toString(Qt::ISODate)); + holidayData.insert("ObservanceDuration", holiday.duration()); + // It's a blunt tool for now, we only know if it's a full public holiday or not + if ( holiday.dayType() == KHolidays::Holiday::NonWorkday ) { + holidayData.insert("ObservanceType", "PublicHoliday"); + } else { + holidayData.insert("ObservanceType", "Other"); + } + holidayList.append(QVariant(holidayData)); + } + } + } + + setData(request, QVariant(holidayList)); + return true; + } + + if (key == "isHoliday") { + bool isHoliday = false; + foreach ( const QString ®ionCode, regionCodeList ) { + KHolidays::HolidayRegion *region = m_regions.value(regionCode); + if (region->isHoliday(dateArg)) { + isHoliday = true; + } + } + setData(request, isHoliday); + return true; + } + + if (key == "description") { + QString summary; + foreach ( const QString ®ionCode, regionCodeList ) { + KHolidays::HolidayRegion *region = m_regions.value(regionCode); + KHolidays::Holiday::List holidays; + holidays = region->holidays(dateArg, KHolidays::Holiday::MultidayHolidaysAsSingleEvents); + foreach (const KHolidays::Holiday &holiday, holidays) { + if (!summary.isEmpty()) { + summary.append("\n"); + } + summary.append(holiday.text()); + } + } + + setData(request, summary); + return true; + } + + return false; +} + +#ifdef AKONADI_FOUND +bool CalendarEngine::akonadiCalendarSourceRequest(const QString& key, const QStringList& args, const QString& request) +{ + // figure out what time range was requested from the source string + QDate start; + QDate end; + if (key == "eventsInMonth") { + if (args.count() < 1) { + return false; + } + start = QDate::fromString(args.at(0), Qt::ISODate); + start.setDate(start.year(), start.month(), 1); + end = QDate(start.year(), start.month(), start.daysInMonth()); + } else if (key == "events") { + if (args.count() == 1) { + start = QDate::fromString(args.at(0), Qt::ISODate); + end = start.addDays(1); + } else { + if (args.count() < 2) { + return false; + } + start = QDate::fromString(args.at(0), Qt::ISODate); + end = QDate::fromString(args.at(1), Qt::ISODate); + } + } else { + return false; + } + + if (!start.isValid() || !end.isValid()) { + return false; + } + + if (!m_calendar) { + m_calendar = Akonadi::ETMCalendar::Ptr(new Akonadi::ETMCalendar()); + m_calendar->setCollectionFilteringEnabled(false); + } + + // create the corresponding EventDataContainer + addSource(new EventDataContainer(m_calendar, request, KDateTime(start, QTime(0, 0, 0)), KDateTime(end, QTime(23, 59, 59)))); + return true; +} + +#endif // AKONADI_FOUND + +#include "calendarengine.moc" diff --git a/plasma/generic/dataengines/calendar/calendarengine.h b/plasma/generic/dataengines/calendar/calendarengine.h new file mode 100644 index 00000000..21ad533e --- /dev/null +++ b/plasma/generic/dataengines/calendar/calendarengine.h @@ -0,0 +1,180 @@ +/* + Copyright (c) 2009 Davide Bettio + Copyright (c) 2010 Frederik Gladhorn + + 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 CALENDARENGINE_H +#define CALENDARENGINE_H + +#include + +#ifdef AKONADI_FOUND +# include +#endif + +namespace KHolidays +{ + class HolidayRegion; +} // namespace KHolidays + +/** + The calendar data engine delivers calendar events. + It can be queried for holidays or the akonadi calendar. + + Supported Holiday requests are: + + holidaysRegions + * Returns a list of available Holiday Region Codes + holidaysDefaultRegion + * Returns a QString of a sensible default Holiday Region + holdaysIsValidRegion:[regionCode] + * Returns a bool if given Holiday Region is valid + holdaysRegion:[regionCode(s)] + * Returns the details of the Holiday Regions + holidays:[regionCode(s)]:[YYYY-MM-DD]:[YYYY-MM-DD] + * Returns a QList of all holidays in a Holiday Region(s) between two given dates. + holidays:[regionCode(s)]:[YYYY-MM-DD] + * Returns a QList of all holidays in a Holiday Region(s) on a given day + holidaysInMonth:[regionCode(s)]:[YYYY-MM-DD] + * Returns a QList of all holidays in a Holiday Region(s) in a given month + isHoliday:[regionCode(s)]:[YYYY-MM-DD] + * Returns a bool if a given date is a Holiday in the given Holiday Region(s) + description:[regionCode(s)]:[YYYY-MM-DD] + * Returns a QString of all holiday names in a given Holiday Region(s) on a given date + + Where valid, regionCode(s) are a comma separated list of one or more valid Holiday Regions + + Each Holiday Region is a pair of a QString containing the regionCode and a Data containing value + pairs for: + "Name" Name of the Holiday Region String + "Description" The description of the Region String + "CountryCode" The country code of the Region String, ISO 3166-2 format + "Location" The location of the Region String, ISO 3166-1 format + "LanguageCode" The language of the Region String, ISO 639-1 format + + Each Holiday is a Data containing QString value pairs for: + "Name" Name of holiday String + "RegionCode" The Holiday Region code String + "ObservanceStartDate" The start date of the holiday ISO format Gregorian date + "ObservanceEndDate" The end date of the holiday ISO format Gregorian date + "ObservanceDuration" How many days the holiday lasts Integer + "ObservanceType" If the holiday is a day off "PublicHoliday", "Other" + + Note that multiple holidays can be returned for each date. + + Supported Akonadi requests are: + + eventsInMonth:[YYYY-MM-DD] + events:[YYYY-MM-DD]:[YYYY-MM-DD] + events:[YYYY-MM-DD] + + The returned data contains (not all fields guaranteed to be populated): + + "UID" QString + "Type" QString "Event", "Todo", Journal" + "Summary" QString + "Comments" QStringList + "Location" QString + "OrganizerName" QString + "OrganizerEmail" QString + "Priority" int + "StartDate" KDateTime + "EndDate" KDateTime + "RecurrenceDates" QList(QVariant(KDateTime)) + "Recurs" bool + "AllDay" bool + "Categories" QStringList + "Resources" QStringList + "DurationDays" int + "DurationSeconds" int + "Status" QString "None", "Tentative", "Confirmed", "Draft", + "Final", "Completed", "InProcess", + "Cancelled", "NeedsAction", "NonStandard", + "Unknown" + "StatusName" QString translated Status + "Secrecy" QString "Public", "Private", "Confidential", "Unknown" + "SecrecyName" QString translated Secrecy + "Occurrences" QList(QVariant(Plasma::DataEngine::Data)) + where each Data contains details of an occurence of the event: + "OccurrenceUid" QString for convenience, same as UID + "OccurrenceStartDate" KDateTime + "OccurrenceEndDate" KDateTime + + Event type specific data keys: + "EventMultiDay" bool + "EventHasEndDate" bool + "EventTransparency" QString "Opaque", "Transparent", "Unknown" + + Todo type specific data keys: + "TodoHasStartDate" bool + "TodoIsOpenEnded" bool + "TodoHasDueDate" bool + "TodoDueDate" KDateTime + "TodoIsCompleted" bool + "TodoIsInProgress" bool + "TodoIsNotStarted" bool + "TodoPercentComplete" int + "TodoHasCompletedDate" bool + "TodoCompletedDate" bool + + Fields still to be done: + Attendees + Attachments + Relations + Alarms + Custom Properties + Lat/Lon + Collection/Source + +*/ +class CalendarEngine : public Plasma::DataEngine +{ + Q_OBJECT + + public: + CalendarEngine( QObject* parent, const QVariantList& args ); + ~CalendarEngine(); + + protected: + /// general request for data from this data engine + bool sourceRequestEvent(const QString &name); + + private: + /// a request for holidays data + bool holidayCalendarSourceRequest(const QString& key, const QStringList& args, const QString& request); + + /// a request for data that comes from akonadi + /// creates EventDataContainers as needed + bool akonadiCalendarSourceRequest(const QString& key, const QStringList& args, const QString& request); + +#ifdef AKONADI_FOUND + /// this is the representation of the root calendar itself. it contains everything (calendars, incidences) + Akonadi::ETMCalendar::Ptr m_calendar; +#endif + + /// holiday calendar + QHash m_regions; + QString m_defaultHolidayRegion; // Cached value of default holiday region + QString m_defaultHolidayRegionCountry; // The locale country when the cached default calculated + QString m_defaultHolidayRegionLanguage; // The locale language when the cached default calculated +}; + +K_EXPORT_PLASMA_DATAENGINE(calendar, CalendarEngine) + +#endif diff --git a/plasma/generic/dataengines/calendar/eventdatacontainer.cpp b/plasma/generic/dataengines/calendar/eventdatacontainer.cpp new file mode 100644 index 00000000..27a1d580 --- /dev/null +++ b/plasma/generic/dataengines/calendar/eventdatacontainer.cpp @@ -0,0 +1,233 @@ +/* + Copyright (c) 2010 Frederik Gladhorn + + 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 "eventdatacontainer.h" + +#include + +#include +#include +#include +#include + +using namespace Akonadi; + +EventDataContainer::EventDataContainer(const Akonadi::ETMCalendar::Ptr &calendar, const QString& name, const KDateTime& start, const KDateTime& end, QObject* parent) + : Plasma::DataContainer(parent), + m_calendar(calendar), + m_name(name), + m_startDate(start), + m_endDate(end) +{ + // name under which this dataEngine source appears + setObjectName(name); + + // Connect directly to the calendar for now + connect(calendar.data(), SIGNAL(calendarChanged()), this, SLOT(updateData())); + + // create the initial data + updateData(); +} + +void EventDataContainer::updateData() +{ + removeAllData(); + updateEventData(); + updateTodoData(); + updateJournalData(); + checkForUpdate(); +} + +void EventDataContainer::updateEventData() +{ + KCalCore::Event::List events = m_calendar->events(m_startDate.date(), m_endDate.date(), m_calendar->timeSpec()); + + foreach (const KCalCore::Event::Ptr &event, events) { + Plasma::DataEngine::Data eventData; + populateIncidenceData(event, eventData); + + // Event specific fields + eventData["EventMultiDay"] = event->allDay(); + eventData["EventHasEndDate"] = event->hasEndDate(); + if (event->transparency() == KCalCore::Event::Opaque) { + eventData["EventTransparency"] = "Opaque"; + } else if (event->transparency() == KCalCore::Event::Transparent) { + eventData["EventTransparency"] = "Transparent"; + } else { + eventData["EventTransparency"] = "Unknown"; + } + + setData(event->uid(), eventData); + } +} + +void EventDataContainer::updateTodoData() +{ + QDate todoDate = m_startDate.date(); + while(todoDate <= m_endDate.date()) { + KCalCore::Todo::List todos = m_calendar->todos(todoDate); + + foreach (const KCalCore::Todo::Ptr &todo, todos) { + Plasma::DataEngine::Data todoData; + populateIncidenceData(todo, todoData); + + QVariant var; + // Todo specific fields + todoData["TodoHasStartDate"] = todo->hasStartDate(); + todoData["TodoIsOpenEnded"] = todo->isOpenEnded(); + todoData["TodoHasDueDate"] = todo->hasDueDate(); + var.setValue(todo->dtDue().toTimeSpec(m_calendar->timeSpec())); + todoData["TodoDueDate"] = var; + todoData["TodoIsCompleted"] = todo->isCompleted(); + todoData["TodoIsInProgress"] = todo->isInProgress(false); // ??? + todoData["TodoIsNotStarted"] = todo->isNotStarted(false); // ??? + todoData["TodoPercentComplete"] = todo->percentComplete(); + todoData["TodoHasCompletedDate"] = todo->hasCompletedDate(); + var.setValue(todo->completed().toTimeSpec(m_calendar->timeSpec())); + todoData["TodoCompletedDate"] = var; + + setData(todo->uid(), todoData); + } + + todoDate = todoDate.addDays(1); + } +} + +void EventDataContainer::updateJournalData() +{ + QDate journalDate = m_startDate.date(); + while(journalDate <= m_endDate.date()) { + KCalCore::Journal::List journals = m_calendar->journals(journalDate); + + foreach (const KCalCore::Journal::Ptr &journal, journals) { + Plasma::DataEngine::Data journalData; + populateIncidenceData(journal, journalData); + + // No Journal specific fields + setData(journal->uid(), journalData); + } + + journalDate = journalDate.addDays(1); + } +} + +void EventDataContainer::populateIncidenceData(const KCalCore::Incidence::Ptr &incidence, Plasma::DataEngine::Data &incidenceData) +{ + QVariant var; + incidenceData["UID"] = incidence->uid(); + incidenceData["Type"] = incidence->typeStr(); + incidenceData["Summary"] = incidence->summary(); + incidenceData["Description"] = incidence->description(); + incidenceData["Comments"] = incidence->comments(); + incidenceData["Location"] = incidence->location(); + incidenceData["OrganizerName"] = incidence->organizer()->name(); + incidenceData["OrganizerEmail"] = incidence->organizer()->email(); + incidenceData["Priority"] = incidence->priority(); + var.setValue(incidence->dtStart().toTimeSpec(m_calendar->timeSpec())); + incidenceData["StartDate"] = var; + + KCalCore::Event* event = dynamic_cast(incidence.data()); + if (event) { + var.setValue(event->dtEnd().toTimeSpec(m_calendar->timeSpec())); + incidenceData["EndDate"] = var; + } + // Build the Occurance Index, this lists all occurences of the Incidence in the required range + // Single occurance events just repeat the standard start/end dates + // Recurring Events use each recurrence start/end date + // The OccurenceUid is redundant, but it makes it easy for clients to just take() the data structure intact as a separate index + QList occurences; + // Build the recurrence list of start dates for recurring incidences only + QList recurrences; + if (incidence->recurs()) { + KCalCore::DateTimeList recurList = incidence->recurrence()->timesInInterval(m_startDate.toTimeSpec(m_calendar->timeSpec()), m_endDate.toTimeSpec(m_calendar->timeSpec())); + foreach(const KDateTime &recurDateTime, recurList) { + var.setValue(recurDateTime.toTimeSpec(m_calendar->timeSpec())); + recurrences.append(var); + Plasma::DataEngine::Data occurence; + occurence.insert("OccurrenceUid", incidence->uid()); + occurence.insert("OccurrenceStartDate", var); + var.setValue(incidence->endDateForStart(recurDateTime).toTimeSpec(m_calendar->timeSpec())); + occurence.insert("OccurrenceEndDate", var); + occurences.append(QVariant(occurence)); + } + } else { + Plasma::DataEngine::Data occurence; + occurence.insert("OccurrenceUid", incidence->uid()); + var.setValue(incidence->dtStart().toTimeSpec(m_calendar->timeSpec())); + occurence.insert("OccurrenceStartDate", var); + if (event) { + var.setValue(event->dtEnd().toTimeSpec(m_calendar->timeSpec())); + occurence.insert("OccurrenceEndDate", var); + } + occurences.append(QVariant(occurence)); + } + incidenceData["RecurrenceDates"] = QVariant(recurrences); + incidenceData["Occurrences"] = QVariant(occurences); + if (incidence->status() == KCalCore::Incidence::StatusNone) { + incidenceData["Status"] = "None"; + } else if (incidence->status() == KCalCore::Incidence::StatusTentative) { + incidenceData["Status"] = "Tentative"; + } else if (incidence->status() == KCalCore::Incidence::StatusConfirmed) { + incidenceData["Status"] = "Confirmed"; + } else if (incidence->status() == KCalCore::Incidence::StatusDraft) { + incidenceData["Status"] = "Draft"; + } else if (incidence->status() == KCalCore::Incidence::StatusFinal) { + incidenceData["Status"] = "Final"; + } else if (incidence->status() == KCalCore::Incidence::StatusCompleted) { + incidenceData["Status"] = "Completed"; + } else if (incidence->status() == KCalCore::Incidence::StatusInProcess) { + incidenceData["Status"] = "InProcess"; + } else if (incidence->status() == KCalCore::Incidence::StatusCanceled) { + incidenceData["Status"] = "Cancelled"; + } else if (incidence->status() == KCalCore::Incidence::StatusNeedsAction) { + incidenceData["Status"] = "NeedsAction"; + } else if (incidence->status() == KCalCore::Incidence::StatusX) { + incidenceData["Status"] = "NonStandard"; + } else { + incidenceData["Status"] = "Unknown"; + } + incidenceData["StatusName"] = KCalUtils::Stringify::incidenceStatus( incidence->status() ); + + if (incidence->secrecy() == KCalCore::Incidence::SecrecyPublic) { + incidenceData["Secrecy"] = "Public"; + } else if (incidence->secrecy() == KCalCore::Incidence::SecrecyPrivate) { + incidenceData["Secrecy"] = "Private"; + } else if (incidence->secrecy() == KCalCore::Incidence::SecrecyConfidential) { + incidenceData["Secrecy"] = "Confidential"; + } else { + incidenceData["Secrecy"] = "Unknown"; + } + incidenceData["SecrecyName"] = KCalUtils::Stringify::secrecyName( incidence->secrecy() ); + incidenceData["Recurs"] = incidence->recurs(); + incidenceData["AllDay"] = incidence->allDay(); + incidenceData["Categories"] = incidence->categories(); + incidenceData["Resources"] = incidence->resources(); + incidenceData["DurationDays"] = incidence->duration().asDays(); + incidenceData["DurationSeconds"] = incidence->duration().asSeconds(); + + //TODO Attendees + //TODO Attachments + //TODO Relations + //TODO Alarms + //TODO Custom Properties + //TODO Lat/Lon + //TODO Collection/Source +} + +#include "eventdatacontainer.moc" diff --git a/plasma/generic/dataengines/calendar/eventdatacontainer.h b/plasma/generic/dataengines/calendar/eventdatacontainer.h new file mode 100644 index 00000000..fd3996f5 --- /dev/null +++ b/plasma/generic/dataengines/calendar/eventdatacontainer.h @@ -0,0 +1,50 @@ +/* + Copyright (c) 2010 Frederik Gladhorn + + 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 EVENTDATACONTAINER_H +#define EVENTDATACONTAINER_H + +#include +#include +#include +#include + +class EventDataContainer : public Plasma::DataContainer +{ + Q_OBJECT +public: + EventDataContainer(const Akonadi::ETMCalendar::Ptr &calendar, const QString& name, const KDateTime& start, const KDateTime& end, QObject* parent = 0); + +public Q_SLOTS: + // update the list of incidents + void updateData(); + +private: + void updateEventData(); + void updateTodoData(); + void updateJournalData(); + void populateIncidenceData(const KCalCore::Incidence::Ptr &incidence, Plasma::DataEngine::Data &incidenceData); + + Akonadi::ETMCalendar::Ptr m_calendar; + QString m_name; + KDateTime m_startDate; + KDateTime m_endDate; +}; + +#endif diff --git a/plasma/generic/dataengines/calendar/plasma-dataengine-calendar.desktop b/plasma/generic/dataengines/calendar/plasma-dataengine-calendar.desktop new file mode 100644 index 00000000..bfc7e371 --- /dev/null +++ b/plasma/generic/dataengines/calendar/plasma-dataengine-calendar.desktop @@ -0,0 +1,161 @@ +[Desktop Entry] +Name=Calendar +Name[ar]=التقويم +Name[ast]=Calendariu +Name[be@latin]=Kalandar +Name[bg]=Календар +Name[bn]=ক্যালেণ্ডার +Name[bn_IN]=বর্ষপঞ্জি +Name[bs]=kalendar +Name[ca]=Calendari +Name[ca@valencia]=Calendari +Name[cs]=Kalendář +Name[csb]=Kalãdôrz +Name[da]=Kalender +Name[de]=Kalender +Name[el]=Ημερολόγιο +Name[en_GB]=Calendar +Name[eo]=Kalendaro +Name[es]=Calendario +Name[et]=Kalender +Name[eu]=Egutegia +Name[fa]=تقویم +Name[fi]=Kalenteri +Name[fr]=Calendrier +Name[fy]=Aginda +Name[ga]=Féilire +Name[gl]=Calendario +Name[gu]=કેલેન્ડર +Name[he]=לוח שנה +Name[hi]=कैलेन्डर +Name[hne]=कलेन्डर +Name[hr]=Kalendar +Name[hsb]=Protyka +Name[hu]=Naptár +Name[ia]=Calendario +Name[id]=Kalender +Name[is]=Dagatal +Name[it]=Calendario +Name[ja]=カレンダー +Name[kk]=Күнтізбе +Name[km]=ប្រតិទិន +Name[kn]=ದಿನಸೂಚಿ +Name[ko]=달력 +Name[ku]=Salname +Name[lt]=Kalendorius +Name[lv]=Kalendārs +Name[mai]=कैलेंडर +Name[mk]=Календар +Name[ml]=കലണ്ടര്‍ +Name[mr]=दिनदर्शिका +Name[nb]=Kalender +Name[nds]=Kalenner +Name[nl]=Kalender +Name[nn]=Kalender +Name[pa]=ਕੈਲੰਡਰ +Name[pl]=Kalendarz +Name[pt]=Calendário +Name[pt_BR]=Calendário +Name[ro]=Calendar +Name[ru]=Календарь +Name[si]=දිනදර්ශනය +Name[sk]=Kalendár +Name[sl]=Koledar +Name[sr]=календар +Name[sr@ijekavian]=календар +Name[sr@ijekavianlatin]=kalendar +Name[sr@latin]=kalendar +Name[sv]=Kalender +Name[ta]=நாட்காட்டி +Name[tg]=Тақвим +Name[th]=ปฏิทิน +Name[tr]=Takvim +Name[ug]=يىلنامە +Name[uk]=Календар +Name[vi]=Lịch +Name[wa]=Calindrî +Name[x-test]=xxCalendarxx +Name[zh_CN]=日历 +Name[zh_TW]=行事曆 +Comment=Calendar data engine +Comment[ar]=محرك بيانات التقويم +Comment[ast]=Motor de datos del calendariu +Comment[bg]=Ядро на календара +Comment[bs]=Kalendarski datomotor +Comment[ca]=Motor de dades de calendari +Comment[ca@valencia]=Motor de dades de calendari +Comment[cs]=Datový nástroj kalendáře +Comment[csb]=Kalãdôrz czérownika pòdôwków +Comment[da]=Datamtor til kalender +Comment[de]=Kalender-Datentreiber +Comment[el]=Μηχανή δεδομένων ημερολογίου +Comment[en_GB]=Calendar data engine +Comment[eo]=Kalendara datuma motoro +Comment[es]=Motor de datos del calendario +Comment[et]=Kalendri andmete mootor +Comment[eu]=Egutegiko datuen motorra +Comment[fi]=Kalenteritietomoottori +Comment[fr]=Moteur de données du calendrier +Comment[fy]=Kalinder gegevens motor +Comment[ga]=Inneall sonraí féilire +Comment[gl]=Motor de datos de calendario +Comment[gu]=કેલેન્ડર માહિતી એન્જિન +Comment[he]=מנוע תוכן לוחות שנה +Comment[hi]=कैलेन्डर डॉटा इंजन +Comment[hr]=Podatkovni mehanizam za kalendar +Comment[hu]=Naptárkezelő modul +Comment[ia]=Motor de datos de calendario +Comment[id]=Mesin data kalender +Comment[is]=Gagnavél fyrir dagatal +Comment[it]=Motore dei dati del calendario +Comment[ja]=カレンダー用データエンジン +Comment[kk]=Күнтізбе деректер тетігі +Comment[km]=ម៉ាស៊ីន​ទិន្នន័យ​ប្រតិទិន +Comment[kn]=ದಿನಸೂಚಿ ದತ್ತಾಂಶ ಸಾಧನ +Comment[ko]=달력 데이터 엔진 +Comment[lt]=Kalendoriaus duomenų variklis +Comment[lv]=Kalendāra datu dzinējs +Comment[mk]=Податочна машина за календари +Comment[ml]=കലണ്ടര്‍ ഡാറ്റ എഞ്ചിന്‍ +Comment[mr]=दिनदर्शिका डेटा इंजिन +Comment[nb]=Kalenderdata-motor +Comment[nds]=Kalenner-Datenkarn +Comment[nl]=Agendagegevensengine +Comment[nn]=Kalenderdatamotor +Comment[pa]=ਕੈਲੰਡਰ ਡਾਟਾ ਇੰਜਣ +Comment[pl]=Silnik danych kalendarza +Comment[pt]=Motor de dados do calendário +Comment[pt_BR]=Mecanismo de dados de calendário +Comment[ro]=Motor de date pentru calendar +Comment[ru]=Источник данных для календаря +Comment[si]=දිනදසුන් දත්ත එන්ජිම +Comment[sk]=Dátový nástroj kalendára +Comment[sl]=Podatkovni pogon s koledarskimi podatki +Comment[sr]=Календарски датомотор +Comment[sr@ijekavian]=Календарски датомотор +Comment[sr@ijekavianlatin]=Kalendarski datomotor +Comment[sr@latin]=Kalendarski datomotor +Comment[sv]=Datagränssnitt för kalendrar +Comment[tg]=Мудири тақвим +Comment[th]=ข้อมูลปฏิทินและกลไกจัดการ +Comment[tr]=Takvim veri motoru +Comment[ug]=يىلنامە سانلىق-مەلۇمات ماتورى +Comment[uk]=Рушій даних календаря +Comment[vi]=Cơ chế dữ liệu lịch biểu +Comment[wa]=Moteur di dnêyes do calindrî +Comment[x-test]=xxCalendar data enginexx +Comment[zh_CN]=日历数据引擎 +Comment[zh_TW]=行事曆資料引擎 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=office-calendar +X-KDE-Library=plasma_engine_calendar + +X-KDE-PluginInfo-Author=Davide Bettio +X-KDE-PluginInfo-Email=davide.bettio@kdemail.net +X-KDE-PluginInfo-Name=calendar +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/devicenotifications/CMakeLists.txt b/plasma/generic/dataengines/devicenotifications/CMakeLists.txt new file mode 100644 index 00000000..7eff4166 --- /dev/null +++ b/plasma/generic/dataengines/devicenotifications/CMakeLists.txt @@ -0,0 +1,12 @@ +set(device_notifications_engine_SRCS + devicenotificationsengine.cpp +) + +qt4_add_dbus_adaptor( device_notifications_engine_SRCS org.kde.DeviceNotifications.xml devicenotificationsengine.h DeviceNotificationsEngine ) + +kde4_add_plugin(plasma_engine_devicenotifications ${device_notifications_engine_SRCS}) + +target_link_libraries(plasma_engine_devicenotifications ${KDE4_PLASMA_LIBS} ${KDE4_KDECORE_LIBS}) + +install(TARGETS plasma_engine_devicenotifications DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-devicenotifications.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/plasma/generic/dataengines/devicenotifications/devicenotificationsengine.cpp b/plasma/generic/dataengines/devicenotifications/devicenotificationsengine.cpp new file mode 100644 index 00000000..fa92c0fb --- /dev/null +++ b/plasma/generic/dataengines/devicenotifications/devicenotificationsengine.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Jacopo De Simoi + * + * This program is free software you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * 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 "devicenotificationsengine.h" +#include "devicenotificationsadaptor.h" + +#include + +#include + +DeviceNotificationsEngine::DeviceNotificationsEngine( QObject* parent, const QVariantList& args ) + : Plasma::DataEngine( parent, args ), + m_id(0) +{ + new DeviceNotificationsAdaptor(this); + + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerService( "org.kde.DeviceNotifications" ); + dbus.registerObject( "/org/kde/DeviceNotifications", this ); +} + +DeviceNotificationsEngine::~DeviceNotificationsEngine() +{ + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.unregisterService( "org.kde.DeviceNotifications" ); +} + +void DeviceNotificationsEngine::init() +{ +} + +void DeviceNotificationsEngine::notify(int solidError, const QString& error, const QString& errorDetails, const QString &udi) +{ + kDebug() << error << errorDetails << udi; + const QString source = QString("notification %1").arg(m_id++); + + Plasma::DataEngine::Data notificationData; + notificationData.insert("solidError", solidError); + notificationData.insert("error", error); + notificationData.insert("errorDetails", errorDetails); + notificationData.insert("udi", udi); + + setData(source, notificationData ); +} + +K_EXPORT_PLASMA_DATAENGINE(devicenotifications, DeviceNotificationsEngine) + +#include "devicenotificationsengine.moc" diff --git a/plasma/generic/dataengines/devicenotifications/devicenotificationsengine.h b/plasma/generic/dataengines/devicenotifications/devicenotificationsengine.h new file mode 100644 index 00000000..b5f5326a --- /dev/null +++ b/plasma/generic/dataengines/devicenotifications/devicenotificationsengine.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 Jacopo De Simoi + * + * This program is free software you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * 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 DEVICENOTIFICATIONSENGINE_H +#define DEVICENOTIFICATIONSENGINE_H + +#include + +/** + * Engine which provides data sources for device notifications. + * Each notification is represented by one source. + */ +class DeviceNotificationsEngine : public Plasma::DataEngine +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.DeviceNotifications") + +public: + DeviceNotificationsEngine( QObject* parent, const QVariantList& args ); + ~DeviceNotificationsEngine(); + + virtual void init(); + + /** + * This function implements part of Notifications DBus interface. + * Once called, will add notification source to the engine + */ +public slots: + void notify(int solidError, const QString& error, const QString& errorDetails, const QString &udi); + +private: + uint m_id; +}; + +#endif diff --git a/plasma/generic/dataengines/devicenotifications/org.kde.DeviceNotifications.xml b/plasma/generic/dataengines/devicenotifications/org.kde.DeviceNotifications.xml new file mode 100644 index 00000000..efd08c39 --- /dev/null +++ b/plasma/generic/dataengines/devicenotifications/org.kde.DeviceNotifications.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/plasma/generic/dataengines/devicenotifications/plasma-dataengine-devicenotifications.desktop b/plasma/generic/dataengines/devicenotifications/plasma-dataengine-devicenotifications.desktop new file mode 100644 index 00000000..aa8f1e07 --- /dev/null +++ b/plasma/generic/dataengines/devicenotifications/plasma-dataengine-devicenotifications.desktop @@ -0,0 +1,133 @@ +[Desktop Entry] +Name=Device Notifications +Name[ar]=تنبيهات الأجهزة +Name[ast]=Notificaciones de preséu +Name[bg]=Уведомления от устройства +Name[bn]=ডিভাইস বিজ্ঞপ্তি +Name[bs]=Obavještenja o uređajima +Name[ca]=Notificacions dels dispositius +Name[ca@valencia]=Notificacions dels dispositius +Name[cs]=Oznamování zařízení +Name[da]=Enhedsbekendtgørelser +Name[de]=Geräte-Benachrichtigungen +Name[el]=Ειδοποιήσεις συσκευών +Name[en_GB]=Device Notifications +Name[es]=Notificaciones de dispositivo +Name[et]=Seadmete märguanded +Name[eu]=Gailu-jakinarazpenak +Name[fi]=Laiteilmoitukset +Name[fr]=Notifications des périphériques +Name[ga]=Fógraí Gléasanna +Name[gl]=Notificacións dos dispositivos +Name[he]=הודעות של התקנים +Name[hi]=औज़ार सूचनाएँ +Name[hr]=Obavijesti uređaja +Name[hu]=Eszközértesítések +Name[ia]=Notificationes de dispositivo +Name[id]=Notifikasi Divais +Name[is]=Tilkynningar um tæki +Name[it]=Notifiche dei dispositivi +Name[ja]=デバイスの通知 +Name[kk]=Құрылғы құлақтандырулары +Name[km]=ការ​​ជូន​ដំណឹង​​ឧបករណ៍ +Name[kn]=ಸಾಧನ ಸೂಚನೆಗಳು +Name[ko]=장치 알림 +Name[lt]=Pranešimai apie įrenginius +Name[lv]=Iekārtu paziņojumi +Name[mr]=साधन सूचना +Name[nb]=Enhetsvarslinger +Name[nds]=Reedschap-Bescheden +Name[nl]=Meldingen van apparaten +Name[pa]=ਜੰਤਰ ਨੋਟੀਫਿਕੇਸ਼ਨ +Name[pl]=Powiadomienia urządzeń +Name[pt]=Notificações de Dispositivos +Name[pt_BR]=Notificações de dispositivos +Name[ro]=Notificări dispozitive +Name[ru]=Уведомления об устройствах +Name[si]=මෙවලම් දැනුම් දීම් +Name[sk]=Upozornenia zariadení +Name[sl]=Obvestila o napravah +Name[sr]=Обавештења о уређајима +Name[sr@ijekavian]=Обавјештења о уређајима +Name[sr@ijekavianlatin]=Obavještenja o uređajima +Name[sr@latin]=Obaveštenja o uređajima +Name[sv]=Enhetsunderrättelser +Name[tg]=Огоҳиҳои дастгоҳ +Name[th]=การแจ้งเกี่ยวกับอุปกรณ์ +Name[tr]=Aygıt Bildirimleri +Name[ug]=ئۈسكۈنە ئۇقتۇرۇشلىرى +Name[uk]=Сповіщення про пристрої +Name[vi]=Thông báo thiết bị +Name[wa]=Notifiaedjes des éndjins +Name[x-test]=xxDevice Notificationsxx +Name[zh_CN]=设备通知 +Name[zh_TW]=裝置通知 +Comment=Passive device notifications for the user. +Comment[ar]=إشعارات مرئية غير متفاعلة للمستخدم +Comment[ast]=Notificaciones pasives de preseos pal usuariu. +Comment[bg]=Пасивни уведомления от устройствата за потребителя. +Comment[bs]=Pasivna obavještenja o uređajima za korisnika. +Comment[ca]=Notificacions passives de dispositius per a l'usuari. +Comment[ca@valencia]=Notificacions passives de dispositius per a l'usuari. +Comment[cs]=Pasivní upozornění zařízení pro uživatele. +Comment[da]=Passive enhedsbekendtgørelser til brugeren. +Comment[de]=Passive Benachrichtigungen für den Anwender. +Comment[el]=Παθητική συσκευή ειδοποιήσεων για το χρήστη. +Comment[en_GB]=Passive device notifications for the user. +Comment[es]=Notificaciones pasivas de dispositivos para el usuario. +Comment[et]=Passiivsed seadmete märguanded kasutajale. +Comment[eu]=Erabiltzailearentzako gailu-jakinarazpen pasiboak. +Comment[fi]=Passiivisia laiteilmoituksia käyttäjälle. +Comment[fr]=Notifications passives de périphériques pour l'utilisateur. +Comment[gl]=Notificacións pasivas dos dispositivos para o usuario. +Comment[he]=הודעות פאסיביות של התקנים למשתמש. +Comment[hr]=Pasivne obavijesti uređaja za korisnika. +Comment[hu]=Passzív eszközértesítések a felhasználónak. +Comment[ia]=Notificationes de dispositivo passive pro le usator. +Comment[id]=Notifikasi divais pasif untuk pengguna. +Comment[is]=Hlutlausar sjónrænar tilkynningar til notandans. +Comment[it]=Notifiche dei dispositivi passive per l'utente. +Comment[ja]=ユーザ用の受動的デバイス通知です。 +Comment[kk]=Құрылғы пайдаланушысына құлақтандырулары +Comment[km]=ការ​ជូនដំណឹង​ឧបករណ៍​សកម្ម​សម្រាប់​អ្នក​ប្រើ ។ +Comment[kn]=ಬಳಕೆದಾರನಿಗಾಗಿ ನಿಷ್ಕ್ರಿಯವಾಗಿರುವ ಸಾಧನ ಸೂಚನೆಗಳು. +Comment[ko]=사용자에게 보이는 수동적인 장치 알림입니다. +Comment[lt]=Pasyvūs pranešimai naudotojui apie įrenginius. +Comment[lv]=Pasīvi iekārtu paziņojumi lietotājam. +Comment[mr]=वापरकर्त्यासाठी साधन सूचना. +Comment[nb]=Passive enhetsvarslinger for brukeren. +Comment[nds]=Passiev Reedschap-Bescheden för den Bruker +Comment[nl]=Passieve meldingen van apparaten voor de gebruiker. +Comment[pa]=ਯੂਜ਼ਰ ਲਈ ਪੈਸਿਵ ਜੰਤਰ ਨੋਟੀਫਿਕੇਸ਼ਨ। +Comment[pl]=Bierne powiadomienia urządzenia dla użytkownika. +Comment[pt]=Notificações passivas de dispositivos para o utilizador. +Comment[pt_BR]=Notificações passivas de dispositivos para o usuário. +Comment[ro]=Notificări de dispozitiv pasive pentru utilizator. +Comment[ru]=Пассивные уведомления для пользователя об оборудовании. +Comment[si]=පරිශීලකයන් සඳහා නිශ්ක්‍රීය මෙවලම් දැනුම්දීම්. +Comment[sk]=Pasívne upozornenia zariadení pre užívateľa. +Comment[sl]=Pasivna obvestila o napravah za uporabnika. +Comment[sr]=Пасивна обавештења о уређајима за корисника. +Comment[sr@ijekavian]=Пасивна обавјештења о уређајима за корисника. +Comment[sr@ijekavianlatin]=Pasivna obavještenja o uređajima za korisnika. +Comment[sr@latin]=Pasivna obaveštenja o uređajima za korisnika. +Comment[sv]=Passiva enhetsunderrättelser för användaren. +Comment[th]=การแจ้งอุปกรณ์ที่ไม่มีปฏิกิริยาแก่ผู้ใช้ +Comment[tr]=Kullanıcı için pasif aygıt bildirimleri. +Comment[ug]=ئىشلەتكۈچىگە پاسسىپ كۆرۈنىدىغان ئۈسكۈنىلەرنى ئۇقتۇرىدۇ. +Comment[uk]=Пасивні сповіщення користувача щодо пристроїв. +Comment[wa]=Notifiaedjes doirmants des éndjins po l' uzeu. +Comment[x-test]=xxPassive device notifications for the user.xx +Comment[zh_CN]=为用户提供被动出现的设备通知。 +Comment[zh_TW]=給使用者的被動裝置通知。 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=device-notifier +X-KDE-Library=plasma_engine_devicenotifications + +X-KDE-PluginInfo-Author=Jacopo De Simoi +X-KDE-PluginInfo-Email=wilderkde@gmail.com +X-KDE-PluginInfo-Name=devicenotifications +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= diff --git a/plasma/generic/dataengines/dict/CMakeLists.txt b/plasma/generic/dataengines/dict/CMakeLists.txt new file mode 100644 index 00000000..2cab7c25 --- /dev/null +++ b/plasma/generic/dataengines/dict/CMakeLists.txt @@ -0,0 +1,12 @@ +project(plasma-dictengine) + +set(dict_engine_SRCS + dictengine.cpp +) + +kde4_add_plugin(plasma_engine_dict ${dict_engine_SRCS}) +target_link_libraries(plasma_engine_dict ${KDE4_KDECORE_LIBS} ${KDE4_PLASMA_LIBS} ${QT_QTNETWORK_LIBRARY}) + +install(TARGETS plasma_engine_dict DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-dict.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/plasma/generic/dataengines/dict/Messages.sh b/plasma/generic/dataengines/dict/Messages.sh new file mode 100755 index 00000000..29218d33 --- /dev/null +++ b/plasma/generic/dataengines/dict/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_dict.pot diff --git a/plasma/generic/dataengines/dict/buggywords b/plasma/generic/dataengines/dict/buggywords new file mode 100644 index 00000000..711fb3c0 --- /dev/null +++ b/plasma/generic/dataengines/dict/buggywords @@ -0,0 +1 @@ +which diff --git a/plasma/generic/dataengines/dict/dictengine.cpp b/plasma/generic/dataengines/dict/dictengine.cpp new file mode 100644 index 00000000..425b307d --- /dev/null +++ b/plasma/generic/dataengines/dict/dictengine.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2007 Thomas Georgiou and Jeff Cooper + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "dictengine.h" +#include + +#include +#include +#include + +#include + +DictEngine::DictEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) + , m_tcpSocket(0) +{ + Q_UNUSED(args) + m_serverName = "dict.org"; //In case we need to switch it later + m_dictName = "wn"; //Default, good dictionary +} + +DictEngine::~DictEngine() +{ +} + +void DictEngine::setDict(const QString &dict) +{ + m_dictName = dict; +} + +void DictEngine::setServer(const QString &server) +{ + m_serverName = server; +} + +static QString wnToHtml(const QString &word, QByteArray &text) +{ + Q_UNUSED(word) + QList splitText = text.split('\n'); + QString def; + def += "
\n"; + QRegExp linkRx("\\{(.*)\\}"); + linkRx.setMinimal(true); + + bool isFirst=true; + while (!splitText.empty()) { + //150 n definitions retrieved - definitions follow + //151 word database name - text follows + //250 ok (optional timing information here) + //552 No match + QString currentLine = splitText.takeFirst(); + if (currentLine.startsWith(QLatin1String("151"))) { + isFirst = true; + continue; + } + + if (currentLine.startsWith('.')) { + def += ""; + continue; + } + + if (!(currentLine.startsWith(QLatin1String("150")) + || currentLine.startsWith(QLatin1String("151")) + || currentLine.startsWith(QLatin1String("250")) + || currentLine.startsWith(QLatin1String("552")))) { + currentLine.replace(linkRx,"\\1"); + + if (isFirst) { + def += "
" + currentLine + "
\n
"; + isFirst = false; + continue; + } else { + if (currentLine.contains(QRegExp("([1-9]{1,2}:)"))) { + def += "\n
\n"; + } + currentLine.replace(QRegExp("^([\\s\\S]*[1-9]{1,2}:)"), "\\1"); + def += currentLine; + continue; + } + } + + } + + def += "
"; + return def; +} + +void DictEngine::getDefinition() +{ + m_tcpSocket->readAll(); + QByteArray ret; + + m_tcpSocket->write(QByteArray("DEFINE ")); + m_tcpSocket->write(m_dictName.toAscii()); + m_tcpSocket->write(QByteArray(" \"")); + m_tcpSocket->write(m_currentWord.toUtf8()); + m_tcpSocket->write(QByteArray("\"\n")); + m_tcpSocket->flush(); + + while (!ret.contains("250") && !ret.contains("552") && !ret.contains("550")) { + m_tcpSocket->waitForReadyRead(); + ret += m_tcpSocket->readAll(); + } + + connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(socketClosed())); + m_tcpSocket->disconnectFromHost(); + // setData(m_currentWord, m_dictName, ret); + // qWarning()< theHash; + m_tcpSocket->readAll(); + QByteArray ret; + + m_tcpSocket->write(QByteArray("SHOW DB\n"));; + m_tcpSocket->flush(); + + m_tcpSocket->waitForReadyRead(); + while (!ret.contains("250")) { + m_tcpSocket->waitForReadyRead(); + ret += m_tcpSocket->readAll(); + } + + QList retLines = ret.split('\n'); + QString tmp1, tmp2; + + while (!retLines.empty()) { + QString curr(retLines.takeFirst()); + + if (curr.startsWith(QLatin1String("554"))) { + //TODO: What happens if no DB available? + //TODO: Eventually there will be functionality to change the server... + break; + } + + // ignore status code and empty lines + if (curr.startsWith(QLatin1String("250")) || curr.startsWith(QLatin1String("110")) + || curr.isEmpty()) { + continue; + } + + if (!curr.startsWith('-') && !curr.startsWith('.')) { + curr = curr.trimmed(); + tmp1 = curr.section(' ', 0, 0); + tmp2 = curr.section(' ', 1); + // theHash.insert(tmp1, tmp2); + //kDebug() << tmp1 + " " + tmp2; + setData("list-dictionaries", tmp1, tmp2); + } + } + + m_tcpSocket->disconnectFromHost(); +// setData("list-dictionaries", "dictionaries", QByteArray(theHash); +} + + + +void DictEngine::socketClosed() +{ + m_tcpSocket->deleteLater(); + m_tcpSocket = 0; +} + +bool DictEngine::sourceRequestEvent(const QString &query) +{ + // FIXME: this is COMPLETELY broken .. it can only look up one query at a time! + // a DataContainer subclass that does the look up should probably be made + if (m_currentQuery == query) { + return false; + } + + if (m_tcpSocket) { + m_tcpSocket->abort(); //stop if lookup is in progress and new query is requested + m_tcpSocket->deleteLater(); + m_tcpSocket = 0; + } + + QStringList queryParts = query.split(':', QString::SkipEmptyParts); + if (queryParts.isEmpty()) { + return false; + } + + m_currentWord = queryParts.last(); + m_currentQuery = query; + + //asked for a dictionary? + if (queryParts.count() > 1) { + setDict(queryParts[queryParts.count()-2]); + //default to wordnet + } else { + setDict("wn"); + } + + //asked for a server? + if (queryParts.count() > 2) { + setServer(queryParts[queryParts.count()-3]); + //default to wordnet + } else { + setServer("dict.org"); + } + + if (m_currentWord.simplified().isEmpty()) { + setData(m_currentWord, m_dictName, QString()); + } else { + setData(m_currentWord, m_dictName, QString()); + m_tcpSocket = new KTcpSocket(this); + m_tcpSocket->abort(); + connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(socketClosed())); + + if (m_currentWord == "list-dictionaries") { + connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(getDicts())); + } else { + connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(getDefinition())); + } + + m_tcpSocket->connectToHost(m_serverName, 2628); + } + + return true; +} + +#include "dictengine.moc" diff --git a/plasma/generic/dataengines/dict/dictengine.h b/plasma/generic/dataengines/dict/dictengine.h new file mode 100644 index 00000000..d91f246c --- /dev/null +++ b/plasma/generic/dataengines/dict/dictengine.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 Thomas Georgiou and Jeff Cooper + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DICTENGINE_H +#define DICTENGINE_H +#include +#include +class KTcpSocket; + +/** + * This class evaluates the basic expressions given in the interface. + */ + + +class DictEngine: public Plasma::DataEngine +{ + Q_OBJECT + + public: + DictEngine( QObject* parent, const QVariantList& args ); + ~DictEngine(); + + protected: + bool sourceRequestEvent(const QString &word); + + private slots: + void getDefinition(); + void socketClosed(); + void getDicts(); + + private: + void setDict(const QString &dict); + void setServer(const QString &server); + + QHash m_dictNameToDictCode; + KTcpSocket *m_tcpSocket; + QString m_currentWord; + QString m_currentQuery; + QString m_dictName; + QString m_serverName; + +}; + +K_EXPORT_PLASMA_DATAENGINE(dict, DictEngine) + +#endif diff --git a/plasma/generic/dataengines/dict/plasma-dataengine-dict.desktop b/plasma/generic/dataengines/dict/plasma-dataengine-dict.desktop new file mode 100644 index 00000000..c8159510 --- /dev/null +++ b/plasma/generic/dataengines/dict/plasma-dataengine-dict.desktop @@ -0,0 +1,171 @@ +[Desktop Entry] +Name=Dictionary +Name[ar]=القاموس +Name[as]=অভিধান +Name[ast]=Diccionariu +Name[be@latin]=Słoŭnik +Name[bg]=Речник +Name[bn]=অভিধান +Name[bn_IN]=অভিধান +Name[bs]=rječnik +Name[ca]=Diccionari +Name[ca@valencia]=Diccionari +Name[cs]=Slovník +Name[csb]=Słowôrz +Name[da]=Ordbog +Name[de]=Wörterbuch +Name[el]=Λεξικό +Name[en_GB]=Dictionary +Name[eo]=Vortaro +Name[es]=Diccionario +Name[et]=Sõnaraamat +Name[eu]=Hiztegia +Name[fa]=واژه‌نامه +Name[fi]=Sanakirja +Name[fr]=Dictionnaire +Name[fy]=Wurdboek +Name[ga]=Foclóir +Name[gl]=Dicionario +Name[gu]=ડિક્શનરી +Name[he]=מילון +Name[hi]=शब्दकोश +Name[hne]=सब्दकोस +Name[hr]=Rječnik +Name[hu]=Szótár +Name[ia]=Dictionario +Name[id]=Kamus +Name[is]=Orðabók +Name[it]=Dizionario +Name[ja]=辞書 +Name[kk]=Сөздік +Name[km]=វចនានុក្រម +Name[kn]=ಶಬ್ದಕೋಶ +Name[ko]=사전 +Name[ku]=Ferheng +Name[lt]=Žodynas +Name[lv]=Vārdnīca +Name[mai]=शब्दकोश +Name[mk]=Речник +Name[ml]=നിഘണ്ടു +Name[mr]=माहितीकोष +Name[nb]=Ordbok +Name[nds]=Wöörbook +Name[nl]=Woordenboek +Name[nn]=Ordbok +Name[or]=ଅଭିଧାନ +Name[pa]=ਡਿਕਸ਼ਨਰੀ +Name[pl]=Słownik +Name[pt]=Dicionário +Name[pt_BR]=Dicionário +Name[ro]=Dicționar +Name[ru]=Словарь +Name[si]=ශබ්දකෝෂය +Name[sk]=Slovník +Name[sl]=Slovar +Name[sr]=речник +Name[sr@ijekavian]=рјечник +Name[sr@ijekavianlatin]=rječnik +Name[sr@latin]=rečnik +Name[sv]=Ordlista +Name[ta]=அகராதி +Name[tg]=Луғат +Name[th]=พจนานุกรม +Name[tr]=Sözlük +Name[ug]=لۇغەت +Name[uk]=Словник +Name[vi]=Từ điển +Name[wa]=Motî +Name[x-test]=xxDictionaryxx +Name[zh_CN]=词典 +Name[zh_TW]=字典 +Comment=Look up word meanings +Comment[af]=Slaan woordbetekenisse na +Comment[ar]=ابحث عن معنى الكلمة +Comment[ast]=Guetar significáu de les pallabres +Comment[be@latin]=Pošuk značeńniaŭ słovaŭ +Comment[bg]=Търсене значението на думи +Comment[bn_IN]=শব্দের অর্থ অনুসন্ধান করুন +Comment[bs]=Potražite značenja riječi +Comment[ca]=Cerca els significats de paraules +Comment[ca@valencia]=Cerca els significats de paraules +Comment[cs]=Vyhledávání významu slov +Comment[da]=Slå ords betydning op +Comment[de]=Nachschlagen von Wortbedeutungen +Comment[el]=Αναζήτηση σημασίας λέξεων +Comment[en_GB]=Look up word meanings +Comment[eo]=Serĉi difinojn de vortoj +Comment[es]=Buscar significado de las palabras +Comment[et]=Sõna tähenduse otsimine +Comment[eu]=Bilatu hitzen esanahiak +Comment[fi]=Tarkista sanojen merkityksiä +Comment[fr]=Connaître la signification des mots +Comment[fy]=Sykje de wurdbetekenissen op +Comment[ga]=Aimsigh sainmhíniú ar fhocal +Comment[gl]=Procura o significado de palabras +Comment[gu]=શબ્દનાં અર્થો શોધો +Comment[he]=בדיקת משמעויות של מילים +Comment[hi]=शब्द का अर्थ देखें +Comment[hne]=सब्द के मायने देखव +Comment[hr]=Pretražite riječi i njihova značenja +Comment[hu]=Értelmező szótár +Comment[ia]=Cerca significato de parola +Comment[id]=Cari arti kata +Comment[is]=Flettu upp merkingu orða +Comment[it]=Cerca i significati delle parole +Comment[ja]=単語の意味を調べる +Comment[kk]=Сөздің мәнін қарастыру +Comment[km]=រក​មើល​អត្ថន័យ​របស់​ពាក្យ +Comment[kn]=ಪದಗಳ ಅರ್ಥಗಳಿಗನ್ನು ಹುಡುಕು +Comment[ko]=단어의 뜻 찾기 +Comment[lt]=Žodžių prasmės paieška +Comment[lv]=Atrod vārdu nozīmes +Comment[mk]=Побарајте за значења на зборовите +Comment[ml]=വാക്കുകളുടെ അര്‍ത്ഥങ്ങള്‍ നിഘണ്ടുവില്‍ തെരയുക +Comment[mr]=शब्दांचे अर्थ शोधण्याकरिता लुकअप +Comment[nb]=Slå opp betydningen av ord +Comment[nds]=Woortbedüden naslaan +Comment[ne]=शब्दको अर्थ हेर्नुहोस् +Comment[nl]=Zoek de betekenis van woorden op +Comment[nn]=Slå opp tydinga til ord +Comment[pa]=ਸ਼ਬਦ ਅਰਥ ਖੋਜ +Comment[pl]=Wyszukiwanie znaczenia słów +Comment[pt]=Procurar os significados das palavras +Comment[pt_BR]=Procurar os significados das palavras +Comment[ro]=Caută înțelesul cuvintelor +Comment[ru]=Показ значений слов или перевода +Comment[se]=Oza maid sátni máksá +Comment[si]=වදන් තේරුම් සෙවීම +Comment[sk]=Vyhľadávanie významov slov +Comment[sl]=Poiščite pomene besed +Comment[sr]=Потражите значења речи +Comment[sr@ijekavian]=Потражите значења ријечи +Comment[sr@ijekavianlatin]=Potražite značenja riječi +Comment[sr@latin]=Potražite značenja reči +Comment[sv]=Slå upp ords betydelse +Comment[ta]=Look up word meanings +Comment[te]=పదము అర్ధాలను చూడుము +Comment[tg]=Выяснение значения слов +Comment[th]=ค้นหาความหมายของคำ +Comment[tr]=Sözcük anlamlarına bak +Comment[ug]=سۆز مەنىسىنى ئىزدە +Comment[uk]=Пошук значень слів +Comment[vi]=Tìm kiếm nghĩa của từ +Comment[wa]=Cweri çou k' on mot vout dire +Comment[x-test]=xxLook up word meaningsxx +Comment[zh_CN]=查阅单词含义 +Comment[zh_TW]=尋找單字的意義 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=accessories-dictionary +X-KDE-Library=plasma_engine_dict + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=dict +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License= + + diff --git a/plasma/generic/dataengines/executable/CMakeLists.txt b/plasma/generic/dataengines/executable/CMakeLists.txt new file mode 100644 index 00000000..2baf1fa9 --- /dev/null +++ b/plasma/generic/dataengines/executable/CMakeLists.txt @@ -0,0 +1,10 @@ +set(executable_engine_SRCS + executable.cpp +) + +kde4_add_plugin(plasma_engine_executable ${executable_engine_SRCS}) +target_link_libraries(plasma_engine_executable ${KDE4_PLASMA_LIBS} ${KDE4_KDECORE_LIBS}) + +install(TARGETS plasma_engine_executable DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-executable.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/plasma/generic/dataengines/executable/executable.cpp b/plasma/generic/dataengines/executable/executable.cpp new file mode 100644 index 00000000..1df8009e --- /dev/null +++ b/plasma/generic/dataengines/executable/executable.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007, 2008 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "executable.h" +#include +#include +ExecutableContainer::ExecutableContainer(const QString& command, QObject* parent) + : Plasma::DataContainer(parent), m_process(0) +{ + setObjectName(command); + connect(this, SIGNAL(updateRequested(DataContainer*)), this, SLOT(exec())); + exec(); +} + +ExecutableContainer::~ExecutableContainer() +{ + delete m_process; +} + +void ExecutableContainer::finished(int exitCode, QProcess::ExitStatus exitStatus) +{ + //kDebug() << objectName(); + setData("exit code", exitCode); + setData("exit status", exitStatus); + setData("stdout", QString::fromLocal8Bit(m_process->readAllStandardOutput())); + setData("stderr", QString::fromLocal8Bit(m_process->readAllStandardError())); + checkForUpdate(); +} + +void ExecutableContainer::exec() +{ + //kDebug() << objectName(); + if (!m_process) { + m_process = new KProcess(); + connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), + this, SLOT(finished(int,QProcess::ExitStatus))); + m_process->setOutputChannelMode(KProcess::SeparateChannels); + m_process->setShellCommand(objectName()); + } + + if (m_process->state() == QProcess::NotRunning) { + m_process->start(); + } else { + kDebug() << "Process" << objectName() << "already running. Pid:" << m_process->pid(); + } +} + + +ExecutableEngine::ExecutableEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) +{ + setMinimumPollingInterval(1000); +} + +bool ExecutableEngine::sourceRequestEvent(const QString& source) +{ + //kDebug() << source; + addSource(new ExecutableContainer(source, this)); + return true; +} + +#include "executable.moc" diff --git a/plasma/generic/dataengines/executable/executable.h b/plasma/generic/dataengines/executable/executable.h new file mode 100644 index 00000000..229b04a8 --- /dev/null +++ b/plasma/generic/dataengines/executable/executable.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007, 2008 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef EXECUTABLE_DATAENGINE_H +#define EXECUTABLE_DATAENGINE_H + +#include +#include +#include + +class ExecutableContainer : public Plasma::DataContainer +{ + Q_OBJECT + public: + explicit ExecutableContainer(const QString& command, QObject *parent = 0); + virtual ~ExecutableContainer(); + + protected slots: + void finished(int exitCode, QProcess::ExitStatus exitStatus); + void exec(); + + private: + KProcess* m_process; +}; + +class ExecutableEngine : public Plasma::DataEngine +{ + Q_OBJECT + public: + ExecutableEngine(QObject *parent, const QVariantList &args); + + protected: + virtual bool sourceRequestEvent(const QString& source); +}; + +K_EXPORT_PLASMA_DATAENGINE(executable, ExecutableEngine) + +#endif diff --git a/plasma/generic/dataengines/executable/plasma-dataengine-executable.desktop b/plasma/generic/dataengines/executable/plasma-dataengine-executable.desktop new file mode 100644 index 00000000..d91615e0 --- /dev/null +++ b/plasma/generic/dataengines/executable/plasma-dataengine-executable.desktop @@ -0,0 +1,161 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Run Commands +Name[ar]=شغّل أوامراً +Name[ast]=Executar órdenes +Name[be@latin]=Vykonvaj zahady +Name[bg]=Изпълнение на команди +Name[bn]=কমান্ড চালাও +Name[bn_IN]=কমান্ড সঞ্চালনা +Name[bs]=izvršavanje naredbi +Name[ca]=Execució d'ordres +Name[ca@valencia]=Execució d'ordes +Name[cs]=Spustit příkazy +Name[csb]=Zrëszanié pòlétów +Name[da]=Kør kommandoer +Name[de]=Befehle ausführen +Name[el]=Εκτέλεση εντολών +Name[en_GB]=Run Commands +Name[eo]=Lanĉi komandon +Name[es]=Ejecutar órdenes +Name[et]=Käsu käivitamine +Name[eu]=Exekutatu komandoak +Name[fi]=Suorita komentoja +Name[fr]=Exécuter des commandes +Name[fy]=Rin kommando's +Name[ga]=Rith Orduithe +Name[gl]=Executar ordes +Name[gu]=આદેશ ચલાવો +Name[he]=הרצת פקודות +Name[hi]=कमांड चलाएँ +Name[hne]=कमांड चलाव +Name[hr]=Pokreni naredbe +Name[hu]=Parancsvégrehajtó +Name[ia]=Exeque commandos +Name[id]=Jalankan Perintah +Name[is]=Keyra skipanir +Name[it]=Esegui comandi +Name[ja]=コマンドを実行 +Name[kk]=Команданы орындау +Name[km]=រត់​ពាក្យ​បញ្ជា +Name[kn]=ಆದೇಶಗಳನ್ನು ಚಲಾಯಿಸು +Name[ko]=명령 실행 +Name[ku]=Fermanan Bixebitîne +Name[lt]=Vykdyti komandas +Name[lv]=Palaist komandas +Name[mk]=Изврши наредби +Name[ml]=ആജ്ഞകള്‍ പ്രവര്‍ത്തിപ്പിയ്ക്കുക +Name[mr]=आदेश चालवा +Name[nb]=Kjør kommandoer +Name[nds]=Befehlen utföhren +Name[nl]=Commando's uitvoeren +Name[nn]=Køyr kommandoar +Name[or]=ନିର୍ଦ୍ଦେଶଗୁଡ଼ିକୁ ଚଲାନ୍ତୁ +Name[pa]=ਕਮਾਂਡਾਂ ਚਲਾਓ +Name[pl]=Uruchom polecenia +Name[pt]=Execução de Comandos +Name[pt_BR]=Executar comandos +Name[ro]=Execută comenzi +Name[ru]=Выполнить команду +Name[si]=විධාන ක්‍රියාත්මක කරන්න +Name[sk]=Spustiť príkazy +Name[sl]=Zaganjanje ukazov +Name[sr]=извршавање наредби +Name[sr@ijekavian]=извршавање наредби +Name[sr@ijekavianlatin]=izvršavanje naredbi +Name[sr@latin]=izvršavanje naredbi +Name[sv]=Kör kommandon +Name[ta]=இயக்க ஆணைகள் +Name[tg]=Иҷрои фармонҳо +Name[th]=ประมวลผลคำสั่ง +Name[tr]=Komut Çalıştır +Name[ug]=بۇيرۇقلارنى ئىجرا قىل +Name[uk]=Виконання команд +Name[wa]=Enonder des cmandes +Name[x-test]=xxRun Commandsxx +Name[zh_CN]=运行命令 +Name[zh_TW]=執行指令 +Comment=Run Executable Data Engine +Comment[ar]=شغل محرك البيانات التنفيذية +Comment[ast]=Executar motor de datos executables +Comment[be@latin]=Uklučaj systemu dostupu da źviestak +Comment[bg]=Изпълнение на програми +Comment[bs]=Datomotor pokretanja izvršnih +Comment[ca]=Motor de dades d'ordres executables +Comment[ca@valencia]=Motor de dades d'ordes executables +Comment[cs]=Spustit rozhraní pro spouštění programů +Comment[csb]=Zrëszanié wëkònëwólnëgò mòtóra pòdôwków +Comment[da]=Datamotor til at afvikle kørbare filer +Comment[de]=Datentreiber für ausführbare Objekte +Comment[el]=Μηχανή δεδομένων εκκίνησης εκτελέσιμων +Comment[en_GB]=Run Executable Data Engine +Comment[es]=Ejecutar motor de datos ejecutables +Comment[et]=Käsu käivitamise andmete mootor +Comment[eu]=Exekutatu exekutagarriaren datu-motorra +Comment[fi]=Suorita suoritettava datakone +Comment[fr]=Lancer le moteur de données d'exécutables +Comment[fy]=Utfierbere gegevensmotor starten +Comment[ga]=Rith Inneall Sonraí Executable +Comment[gl]=Executa o motor de dados de executábeis +Comment[gu]=ચલાવી શકાય તેવું માહિતી એન્જિન ચલાવો +Comment[he]=מנוע תוכן הרצת קובץ Executable +Comment[hi]=एक्जीक्यूटेबल डाटा इंजिन चलाएं +Comment[hne]=चलाय वाले डाटा इंजन चलाव +Comment[hr]=Pokreni izvršive podatkovne mehanizme +Comment[hu]=Adatkezelő futtatása +Comment[ia]=Motor per exequer datos executabile +Comment[id]=Jalankan Mesin Data Tereksekusi +Comment[is]=Gagnavél fyrir keyrslu forrita +Comment[it]=Motore di dati per esecuzione di comandi +Comment[ja]=コマンド実行のデータエンジン +Comment[kk]=Орындайтын деректер тетігін жегу +Comment[km]=រត់​ម៉ាស៊ីន​ទិន្នន័យ​ដែលអាច​ប្រតិបត្តិ​បាន +Comment[kn]=ಚಾಲನಾಯೋಗ್ಯವಾದ ದತ್ತ ಸಾಧನವನ್ನು ಚಲಾಯಿಸಿ +Comment[ko]=명령 실행 데이터 엔진 +Comment[ku]=Motora Dane yên Tên Xebitandin Bixebitîne +Comment[lt]=Leisti vykdomąjį duomenų variklį +Comment[lv]=Izpildfailu palaišanas datu dzinējs +Comment[ml]=പ്രവര്‍ത്തിക്കാന്‍ കഴിയുന്ന ഡേറ്റാ എഞ്ചിന്‍ പ്രവര്‍ത്തിപ്പിയ്ക്കുക +Comment[mr]=कार्यान्वितजोगी Data Engine चालवा +Comment[nb]=Datamotor for kjørbare filer/programmer +Comment[nds]=Programmoproop-Datenkarn +Comment[nl]=Uitvoerbare gegevensengine starten +Comment[nn]=Datamotor for kommandokøyrar +Comment[or]=ନିଷ୍ପାଦ୍ୟ ତଥ୍ୟ ଯନ୍ତ୍ର ଚଲାନ୍ତୁ +Comment[pa]=ਚੱਲਣਯੋਗ ਡਾਟਾ ਇੰਜਣ ਚਲਾਓ +Comment[pl]=Silnik uruchamiania wykonywalnych danych +Comment[pt]=Motor de Dados de Execução de Comandos +Comment[pt_BR]=Mecanismo de dados da execução de comandos +Comment[ro]=Motor de date pentru lansarea executabilelor +Comment[ru]=Источник данных исполняемых объектов +Comment[si]=ක්‍රියාකරවුම් දත්ත එන්ජිම +Comment[sk]=Dátový nástroj na spustenie programov +Comment[sl]=Podatkovni vir za zaganjanje ukazov +Comment[sr]=Датомотор покретања извршних +Comment[sr@ijekavian]=Датомотор покретања извршних +Comment[sr@ijekavianlatin]=Datomotor pokretanja izvršnih +Comment[sr@latin]=Datomotor pokretanja izvršnih +Comment[sv]=Datagränssnitt för att köra program +Comment[ta]=இயக்க வல்ல தேடு பொறி +Comment[tg]=Поставщик лент RSS +Comment[th]=กลไกข้อมูลการประมวลผลคำสั่ง +Comment[tr]=Çalıştırılabilir Veri Motorunu Başlat +Comment[ug]=ئىجراچان سانلىق-مەلۇمات ماتورىنى ئىجرا قىل +Comment[uk]=Виконати програму рушія даних +Comment[wa]=Enonder des éndjins des dnêyes enondåves +Comment[x-test]=xxRun Executable Data Enginexx +Comment[zh_CN]=运行程序数据引擎 +Comment[zh_TW]=執行可執行資料引擎 +ServiceTypes=Plasma/DataEngine +Type=Service +Icon=application-x-executable-script +X-KDE-Library=plasma_engine_executable + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=executable +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/favicons/CMakeLists.txt b/plasma/generic/dataengines/favicons/CMakeLists.txt new file mode 100644 index 00000000..9339ec5b --- /dev/null +++ b/plasma/generic/dataengines/favicons/CMakeLists.txt @@ -0,0 +1,12 @@ +set(favicons_engine_SRCS + favicons.cpp + faviconprovider.cpp +) + +kde4_add_plugin(plasma_engine_favicons ${favicons_engine_SRCS} ) +target_link_libraries(plasma_engine_favicons ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_engine_favicons DESTINATION ${PLUGIN_INSTALL_DIR} ) +install(FILES plasma-dataengine-favicons.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + + diff --git a/plasma/generic/dataengines/favicons/faviconprovider.cpp b/plasma/generic/dataengines/favicons/faviconprovider.cpp new file mode 100644 index 00000000..acad2a30 --- /dev/null +++ b/plasma/generic/dataengines/favicons/faviconprovider.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2007 Tobias Koenig + * Copyright (C) 2008 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include "faviconprovider.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +class FaviconProvider::Private +{ + public: + Private( FaviconProvider *parent ) + : q(parent) + { + } + + void imageRequestFinished( KJob *job ); + + FaviconProvider *q; + QImage image; + QString cachePath; +}; + +void FaviconProvider::Private::imageRequestFinished(KJob *job) +{ + if (job->error()) { + emit q->error(q); + return; + } + + KIO::StoredTransferJob *storedJob = qobject_cast(job); + image = QImage::fromData(storedJob->data()); + if (!image.isNull()) { + image.save(cachePath, "PNG"); + } + emit q->finished(q); +} + + +FaviconProvider::FaviconProvider(QObject *parent, const QString &url) + : QObject(parent), + m_url(url), + d(new Private(this)) +{ + KUrl faviconUrl(url); + if (faviconUrl.protocol().isEmpty()) { + faviconUrl = KUrl("http://" + url); + } + + const QString fileName = KMimeType::favIconForUrl(faviconUrl.url()); + + if (!fileName.isEmpty()) { + d->cachePath = KStandardDirs::locateLocal("cache", fileName + ".png"); + d->image.load(d->cachePath, "PNG"); + } else { + d->cachePath = KStandardDirs::locateLocal("cache", "favicons/" + faviconUrl.host() + ".png"); + faviconUrl.setPath("/favicon.ico"); + + if (faviconUrl.isValid()) { + KIO::StoredTransferJob *job = KIO::storedGet(faviconUrl, KIO::NoReload, KIO::HideProgressInfo); + //job->setProperty("uid", id); + connect(job, SIGNAL(result(KJob*)), this, SLOT(imageRequestFinished(KJob*))); + } + } +} + +FaviconProvider::~FaviconProvider() +{ + delete d; +} + +QImage FaviconProvider::image() const +{ + return d->image; +} + +QString FaviconProvider::identifier() const +{ + return m_url; +} + +#include "faviconprovider.moc" diff --git a/plasma/generic/dataengines/favicons/faviconprovider.h b/plasma/generic/dataengines/favicons/faviconprovider.h new file mode 100644 index 00000000..1f370f9d --- /dev/null +++ b/plasma/generic/dataengines/favicons/faviconprovider.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2007 Tobias Koenig + * Copyright (C) 2008 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation; 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 Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef FAVICONPROVIDER_H +#define FAVICONPROVIDER_H + +#include + +class QImage; + +/** + * This class provides a favicon for a given url + */ +class FaviconProvider : public QObject +{ + Q_OBJECT + + public: + /** + * Creates a new favicon provider. + * + * @param parent The parent object. + */ + FaviconProvider( QObject *parent, const QString &url); + + /** + * Destroys the favicon provider. + */ + ~FaviconProvider(); + + /** + * Returns the requested image. + * + * Note: This method returns only a valid image after the + * finished() signal has been emitted. + */ + QImage image() const; + + /** + * Returns the identifier of the comic request (name + date). + */ + QString identifier() const; + + Q_SIGNALS: + /** + * This signal is emitted whenever a request has been finished + * successfully. + * + * @param provider The provider which emitted the signal. + */ + void finished( FaviconProvider *provider ); + + /** + * This signal is emitted whenever an error has occurred. + * + * @param provider The provider which emitted the signal. + */ + void error( FaviconProvider *provider ); + + private: + QString m_url; + + class Private; + Private* const d; + + Q_PRIVATE_SLOT( d, void imageRequestFinished(KJob *job) ) +}; + +#endif diff --git a/plasma/generic/dataengines/favicons/favicons.cpp b/plasma/generic/dataengines/favicons/favicons.cpp new file mode 100644 index 00000000..2eae6738 --- /dev/null +++ b/plasma/generic/dataengines/favicons/favicons.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2007 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "favicons.h" + +#include "faviconprovider.h" + +FaviconsEngine::FaviconsEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) +{ +} + +FaviconsEngine::~FaviconsEngine() +{ +} + +bool FaviconsEngine::updateSourceEvent( const QString &identifier ) +{ + FaviconProvider *provider = new FaviconProvider(this, identifier); + + connect(provider, SIGNAL(finished(FaviconProvider*)), this, SLOT(finished(FaviconProvider*))); + connect(provider, SIGNAL(error(FaviconProvider*)), this, SLOT(error(FaviconProvider*))); + + if (provider->image() != QImage()) { + setData(provider->identifier(), "Icon", provider->image()); + } + + return true; +} + +bool FaviconsEngine::sourceRequestEvent(const QString &identifier) +{ + setData(identifier, QPixmap()); + return updateSourceEvent(identifier); +} + +void FaviconsEngine::finished(FaviconProvider *provider) +{ + setData(provider->identifier(), "Icon", provider->image()); + provider->deleteLater(); +} + +void FaviconsEngine::error(FaviconProvider *provider) +{ + setData(provider->identifier(), QImage()); + provider->deleteLater(); +} + +#include "favicons.moc" diff --git a/plasma/generic/dataengines/favicons/favicons.h b/plasma/generic/dataengines/favicons/favicons.h new file mode 100644 index 00000000..79565bf5 --- /dev/null +++ b/plasma/generic/dataengines/favicons/favicons.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007 Tobias Koenig + * Copyright (C) 2008 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef FAVICONS_DATAENGINE_H +#define FAVICONS_DATAENGINE_H + +#include + +class FaviconProvider; + +/** + * This class provides favicons for websites + * + * the queries are just the url of websites we want to fetch an icon + */ +class FaviconsEngine : public Plasma::DataEngine +{ + Q_OBJECT + + public: + FaviconsEngine( QObject* parent, const QVariantList& args ); + ~FaviconsEngine(); + + protected: + bool sourceRequestEvent( const QString &identifier ); + + protected Q_SLOTS: + bool updateSourceEvent( const QString &identifier ); + + private Q_SLOTS: + void finished( FaviconProvider* ); + void error( FaviconProvider* ); +}; + +K_EXPORT_PLASMA_DATAENGINE(favicons, FaviconsEngine) + +#endif diff --git a/plasma/generic/dataengines/favicons/plasma-dataengine-favicons.desktop b/plasma/generic/dataengines/favicons/plasma-dataengine-favicons.desktop new file mode 100644 index 00000000..bfc6704e --- /dev/null +++ b/plasma/generic/dataengines/favicons/plasma-dataengine-favicons.desktop @@ -0,0 +1,159 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Favicons +Name[ar]=أيقونات الويب +Name[ast]=Favicons +Name[be@latin]=Ikony sajtaŭ +Name[bg]=Уеб-икони +Name[bn]=ফ্যাভ-আইকন +Name[bn_IN]=Favicons +Name[bs]=favikone +Name[ca]=Icones de web +Name[ca@valencia]=Icones de web +Name[cs]=Oblíbené ikony +Name[csb]=Faviconë (ikònczi) +Name[da]=Favicons +Name[de]=Webseiten-Symbole +Name[el]=Αγαπημένα εικονίδια +Name[en_GB]=Favicons +Name[eo]=Favorikonoj +Name[es]=Favicons +Name[et]=Lemmikikoonid +Name[eu]=Gogoko-ikonoak +Name[fi]=Webbisivukuvakkeet +Name[fr]=Émoticônes +Name[fy]=Favicon-ôfbyldings +Name[ga]=Deilbhíní Ceanán +Name[gl]=Iconas de páxina web +Name[gu]=ફેવિકોન્સ +Name[he]=סמלי מועדפים +Name[hi]=फेविकॉन +Name[hne]=फेविकान +Name[hr]=Omiljene ikone +Name[hu]=Favikonok +Name[ia]=Favicons +Name[id]=Ikon Favorit +Name[is]=Veftáknmyndir (favicons) +Name[it]=Iconcine +Name[ja]=ファビコン +Name[kk]=Favicon таңбашалары +Name[km]=រូប​តំណាង​សំណព្វ +Name[kn]=ಫೆವಿಕಾನ್‌ಗಳು +Name[ko]=파비콘 +Name[ku]=Nîşanên Malperan +Name[lt]=Srities ženkliukai +Name[lv]=TīmekļaIkonas +Name[mai]=फेविकान +Name[mk]=Омилени икони +Name[ml]=ഇഷ്ടചിഹ്നങ്ങള്‍ +Name[mr]=Favicons +Name[nb]=Ikoner for favorittsteder +Name[nds]=Nettsieden-Lüttbiller +Name[nl]=Favicons +Name[nn]=Bokmerkeikon +Name[or]=Favicons +Name[pa]=ਫੇਵੀਕਾਨ +Name[pl]=Ikony witryn +Name[pt]='Favicons' +Name[pt_BR]=Favicons +Name[ro]=Pictograme favorite +Name[ru]=Значки сайтов +Name[si]=Favicons +Name[sk]=Favikony +Name[sl]=Ikone spletnih strani +Name[sr]=фавиконе +Name[sr@ijekavian]=фавиконе +Name[sr@ijekavianlatin]=favikone +Name[sr@latin]=favikone +Name[sv]=Favoritikoner +Name[ta]=சின்னங்கள் +Name[tg]=Нишонаҳои саҳифаи интернетӣ +Name[th]=ไอคอนเว็บ +Name[tr]=Site Simgeleri +Name[ug]=تور بېكەت سىنبەلگە +Name[uk]=Піктограми «Вибраного» +Name[wa]=Pititès imådjetes favicons +Name[x-test]=xxFaviconsxx +Name[zh_CN]=网站图标 +Name[zh_TW]=網站圖示 +Comment=Data Engine for getting favicons of web sites +Comment[ar]=محرك بيانات لجلب أيقونات مواقع الوِب +Comment[ast]=Motor de datos pa obtener favicons de los sitios web +Comment[be@latin]=Systema źviestak dla atrymańnia ikon sajtaŭ +Comment[bg]=Ядро за изтегляне на уеб-икони от сайтове +Comment[bs]=Datomotor za dobavljanje favikona veb sajtova +Comment[ca]=Motor de dades per obtenir icones de web dels llocs web +Comment[ca@valencia]=Motor de dades per obtindre icones de web dels llocs web +Comment[cs]=Mechanismus pro získávání ikon webových stránek +Comment[da]=Datamotor til at hente favicons fra hjemmesider +Comment[de]=Daten-Treiber zum Holen von Webseiten-Symbolen von Webseiten +Comment[el]=Μηχανή δεδομένων για ανάκτηση αγαπημένων εικονιδίων από ιστοσελίδες +Comment[en_GB]=Data Engine for getting favicons of web sites +Comment[es]=Motor de datos para obtener favicons de los sitios web +Comment[et]=Andmemootor lemmikikoonide hankimiseks veebilehekülgedelt +Comment[eu]=Webguneen gogoko-ikonoak eskuratzeko datu-motorra +Comment[fi]=Data-kone webbisivukuvakkeiden hakemiseksi +Comment[fr]=Moteur de données permettant d'obtenir les émoticônes des sites Web +Comment[fy]=Gegevens motor foar it krijen fan favicon-ôfbyldings fan websiden +Comment[ga]=Inneall Sonraí a fhaigheann deilbhíní ceanán ó shuímh Ghréasáin +Comment[gl]=Motor de datos para obter as iconas de páxina dos sitios web +Comment[gu]=વેબ સાઇટ્સનાં ફેવિકોન્સ મેળવવા માટે માહિતી એન્જિન +Comment[he]=מנוע תוכן להשגת סמלי מועדפים של אתרי אינטרנט +Comment[hi]=वेबसाइटों के फेविकॉन को प्राप्त करने के लिए डाटा इंजिन +Comment[hne]=वेब साइट के फेविकान लाय बर डाटा इंजिन +Comment[hr]=Podatkovni mehanizam za nabavljanje omiljenih ikona sa web stranica +Comment[hu]=Weboldalak favikonjainak letöltésére szolgáló adatmotor +Comment[ia]=Motor de datos per obtener favicons del sitos web +Comment[id]=Mesin Data untuk mendapatkan ikon favorit situs web +Comment[is]=Gagnavél til söfnunar á veftáknmyndum (favicons) +Comment[it]=Motore di dati per ottenere le iconcine dei siti Web +Comment[ja]=ウェブサイトのファビコンを取得するためのデータエンジン +Comment[kk]=Веб сайттарының таңбашаларын алу тетігі +Comment[km]=ម៉ាស៊ីន​ទិន្នន័យ​សម្រាប់​ទទួល​រូបតំណាង​សំណព្វ​របស់​តំបន់​បណ្ដាញ +Comment[kn]=ಜಾಲ ತಾಣಗಳ ಫೆವಿಕಾನ್‌ಗಳನ್ನು ಪಡೆಯಲು ನೆರವಾಗುವ ದತ್ತ ಎಂಜಿನ್ +Comment[ko]=웹 사이트의 파비콘을 가져오는 데이터 엔진 +Comment[lt]=Duomenų variklis srities ženkliukų atsisiuntimui iš interneto +Comment[lv]=Datu dzinējs tīmekļa vietņu ikonu ielādei +Comment[mk]=Податочна машина за добивање омилени икони од веб-локации +Comment[ml]=വെബ് സൈറ്റുകളുടെ ഇഷ്ടചിഹ്നങ്ങള്‍ ലഭിക്കാനുള്ള ഡേറ്റ എഞ്ചിന്‍ +Comment[mr]=संकेत स्थळाचे favicons प्राप्त करण्याकरिता Data Engine +Comment[nb]=Datamotor for å hente favorittikoner fra nettsider +Comment[nds]=Datenkarn för Nettsieden-Lüttbiller +Comment[nl]=Gegevensengine voor het ophalen van favicons van websites +Comment[nn]=Datamotor for henting av bokmerkeikon til nettsider +Comment[pa]=ਵੈੱਬ ਸਾਇਟਾਂ ਲਈ ਫੈਵੀਕਾਨ ਲੈਣ ਲਈ ਡਾਟਾ ਇੰਜਣ +Comment[pl]=Silnik danych do pobierania ikon witryn +Comment[pt]=Um motor de dados para obter os 'favicons' das páginas Web +Comment[pt_BR]=Mecanismo de dados para busca dos favicons de páginas Web +Comment[ro]=Motor de date pentru preluarea pictogramelor siturilor web +Comment[ru]=Источник данных значков сайтов +Comment[si]=වෙබ් අඩවි වල favicon ලබාගැනීමේ දත්ත එන්ජිම +Comment[sk]=Dátový nástroj na získavanie favikon z webových stránok +Comment[sl]=Podatkovni vir za pridobivanje ikon spletnih strani +Comment[sr]=Датомотор за добављање фавикона веб сајтова +Comment[sr@ijekavian]=Датомотор за добављање фавикона веб сајтова +Comment[sr@ijekavianlatin]=Datomotor za dobavljanje favikona veb sajtova +Comment[sr@latin]=Datomotor za dobavljanje favikona veb sajtova +Comment[sv]=Datagränssnitt för att hämta favoritikoner för webbplatser +Comment[ta]=Data Engine for getting favicons of web sites +Comment[te]=వెబ్ సైటులయొక్క ఫెవికాన్లను(ఫేవరేట్ఐకాన్‍స్) పొందుటకొరకు డాటా యింజన్ +Comment[th]=กลไกข้อมูลสำหรับรับค่าไอคอนหน้าเว็บของเว็บไซต์ +Comment[tr]=Ağ sitelerinden site simgelerini almak için bir Veri Motoru +Comment[ug]=تور بېكەت سىنبەلگىسىگە ئېرىشىدىغان سانلىق-مەلۇمات ماتورى +Comment[uk]=Рушій даних для отримання піктограм для вебсайтів +Comment[vi]=Cơ chế dữ liệu để lấy các favicon cho trang web +Comment[wa]=Moteur di dnêyes pos cweri des favicons des waibes +Comment[x-test]=xxData Engine for getting favicons of web sitesxx +Comment[zh_CN]=用于获取网站图标的数据引擎 +Comment[zh_TW]=取得網站的圖示的資料引擎 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=view-web-browser-dom-tree +X-KDE-Library=plasma_engine_favicons + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=favicons +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= diff --git a/plasma/generic/dataengines/filebrowser/CMakeLists.txt b/plasma/generic/dataengines/filebrowser/CMakeLists.txt new file mode 100644 index 00000000..528414f4 --- /dev/null +++ b/plasma/generic/dataengines/filebrowser/CMakeLists.txt @@ -0,0 +1,10 @@ +set(filebrowser_engine_SRCS + filebrowserengine.cpp +) + +kde4_add_plugin(plasma_engine_filebrowser ${filebrowser_engine_SRCS}) +target_link_libraries(plasma_engine_filebrowser ${KDE4_KDECORE_LIBS} ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) + +install(TARGETS plasma_engine_filebrowser DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-filebrowser.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/plasma/generic/dataengines/filebrowser/filebrowserengine.cpp b/plasma/generic/dataengines/filebrowser/filebrowserengine.cpp new file mode 100644 index 00000000..4a0cc93a --- /dev/null +++ b/plasma/generic/dataengines/filebrowser/filebrowserengine.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2007 Ivan Cukic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License either version 2, or + * (at your option) any later version 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; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "filebrowserengine.h" + +#include + +#include +#include +#include +#include + +#define InvalidIfEmpty(A) ((A.isEmpty())?(QVariant()):(QVariant(A))) +#define forMatchingSources for (DataEngine::SourceDict::iterator it = sources.begin(); it != sources.end(); ++it) \ + if (dir == QDir(it.key())) + +FileBrowserEngine::FileBrowserEngine(QObject* parent, const QVariantList& args) : + Plasma::DataEngine(parent, args), m_dirWatch(NULL) +{ + Q_UNUSED(args) + + m_dirWatch = new KDirWatch(this); + connect(m_dirWatch, SIGNAL(created( + const QString &)), this, SLOT(dirCreated(QString))); + connect(m_dirWatch, SIGNAL(deleted( + const QString &)), this, SLOT(dirDeleted(QString))); + connect(m_dirWatch, SIGNAL(dirty( + const QString &)), this, SLOT(dirDirty(QString))); +} + +FileBrowserEngine::~FileBrowserEngine() +{ + delete m_dirWatch; +} + +void FileBrowserEngine::init() +{ + kDebug() << "init() called"; +} + +bool FileBrowserEngine::sourceRequestEvent(const QString &path) +{ + kDebug() << "source requested() called: "<< path; + m_dirWatch->addDir(path); + setData(path, "type", QVariant("unknown")); + updateData (path, INIT); + return true; +} + +void FileBrowserEngine::dirDirty(const QString &path) +{ + updateData(path, DIRTY); +} + +void FileBrowserEngine::dirCreated(const QString &path) +{ + updateData(path, CREATED); +} + +void FileBrowserEngine::dirDeleted(const QString &path) +{ + updateData(path, DELETED); +} + +void FileBrowserEngine::updateData(const QString &path, EventType event) +{ + Q_UNUSED(event) + + ObjectType type = NOTHING; + if (QDir(path).exists()) { + type = DIRECTORY; + } else if (QFile::exists(path)) { + type = FILE; + } + + DataEngine::SourceDict sources = containerDict(); + + QDir dir(path); + clearData(path); + + if (type == DIRECTORY) { + kDebug() << "directory info processing: "<< path; + if (dir.isReadable()) { + const QStringList visibleFiles = dir.entryList(QDir::Files, QDir::Name); + const QStringList allFiles = dir.entryList(QDir::Files | QDir::Hidden, + QDir::Name); + + const QStringList visibleDirectories = dir.entryList(QDir::Dirs + | QDir::NoDotAndDotDot, QDir::Name); + const QStringList allDirectories = dir.entryList(QDir::Dirs + | QDir::NoDotAndDotDot | QDir::Hidden, QDir::Name); + + forMatchingSources { + kDebug() << "MATCH"; + it.value()->setData("item.type", QVariant("directory")); + + QVariant vdTmp; + if (!visibleDirectories.isEmpty()) vdTmp = QVariant(visibleDirectories); + it.value()->setData("directories.visible", vdTmp); + + QVariant adTmp; + if (!allDirectories.empty()) adTmp = QVariant(allDirectories); + it.value()->setData("directories.all", adTmp); + + QVariant vfTmp; + if (!visibleFiles.empty()) vfTmp = QVariant(visibleFiles); + it.value()->setData("files.visible", vfTmp); + + QVariant afTmp; + if (!allFiles.empty()) afTmp = QVariant(allFiles); + it.value()->setData("files.all", afTmp); + } + } + } else if (type == FILE) { + kDebug() << "file info processing: "<< path; + KFileMetaInfo kfmi(path, QString(), KFileMetaInfo::Everything); + if (kfmi.isValid()) { + kDebug() << "METAINFO: " << kfmi.keys(); + + forMatchingSources { + kDebug() << "MATCH"; + it.value()->setData("item.type", QVariant("file")); + + for (QHash< QString, KFileMetaInfoItem >::const_iterator i = kfmi.items().constBegin(); i != kfmi.items().constEnd(); ++i) { + it.value()->setData(i.key(), i.value().value()); + } + } + } + } else { + forMatchingSources { + it.value()->setData("item.type", QVariant("imaginary")); + } + }; + + scheduleSourcesUpdated(); + +} + +void FileBrowserEngine::clearData(const QString &path) +{ + QDir dir(path); + const DataEngine::SourceDict sources = containerDict(); + for (DataEngine::SourceDict::const_iterator it = sources.begin(); it + != sources.end(); ++it) { + if (dir == QDir(it.key())) { + kDebug() << "matched: "<< path << " "<< it.key(); + it.value()->removeAllData(); + + } else { + kDebug() << "didn't match: "<< path << " "<< it.key(); + } + } +} + +#include "filebrowserengine.moc" diff --git a/plasma/generic/dataengines/filebrowser/filebrowserengine.h b/plasma/generic/dataengines/filebrowser/filebrowserengine.h new file mode 100644 index 00000000..ad723d26 --- /dev/null +++ b/plasma/generic/dataengines/filebrowser/filebrowserengine.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2007 Ivan Cukic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License either version 2, or + * (at your option) any later version 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; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef FILEBROWSERENGINE_H +#define FILEBROWSERENGINE_H + +#include + +class KDirWatch; + +/** + * This class evaluates the basic expressions given in the interface. + */ +class FileBrowserEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + FileBrowserEngine( QObject* parent, const QVariantList& args ); + ~FileBrowserEngine(); + +protected: + bool sourceRequestEvent(const QString &path); + void init(); + +protected slots: + void dirDirty (const QString &path); + void dirCreated(const QString &path); + void dirDeleted(const QString &path); + +private: + enum EventType {INIT, DIRTY, CREATED, DELETED}; + enum ObjectType {NOTHING, FILE, DIRECTORY}; + + KDirWatch * m_dirWatch; + void updateData(const QString &path, EventType event); + void clearData(const QString &path); + + //QMap < QString, QStringList > m_regiteredListeners; +}; + +K_EXPORT_PLASMA_DATAENGINE(filebrowser, FileBrowserEngine) + +#endif diff --git a/plasma/generic/dataengines/filebrowser/plasma-dataengine-filebrowser.desktop b/plasma/generic/dataengines/filebrowser/plasma-dataengine-filebrowser.desktop new file mode 100644 index 00000000..b8f252a0 --- /dev/null +++ b/plasma/generic/dataengines/filebrowser/plasma-dataengine-filebrowser.desktop @@ -0,0 +1,162 @@ +[Desktop Entry] +Name=Files and Directories +Name[ar]=الملفات والمجلدات +Name[ast]=Ficheros y direutorios +Name[be@latin]=Fajły j katalohi +Name[bg]=Файлове и папки +Name[bn]=ফাইল এবং ডিরেক্টরি +Name[bn_IN]=ফাইল ও ডিরেক্টরি +Name[bs]=datoteke i fascikle +Name[ca]=Fitxers i directoris +Name[ca@valencia]=Fitxers i directoris +Name[cs]=Soubory a složky +Name[csb]=Lopczi ë katalodżi +Name[da]=Filer og mapper +Name[de]=Dateien und Ordner +Name[el]=Αρχεία και κατάλογοι +Name[en_GB]=Files and Directories +Name[eo]=Dosieroj kaj Dosierujoj +Name[es]=Archivos y directorios +Name[et]=Failid ja kataloogid +Name[eu]=Fitxategiak eta direktorioak +Name[fi]=Tiedostot ja kansiot +Name[fr]=Fichiers et dossiers +Name[fy]=triemmen en triemtafels +Name[ga]=Comhaid agus Comhadlanna +Name[gl]=Ficheiros e cartafoles +Name[gu]=ફાઇલો અને ડિરેક્ટરીઓ +Name[he]=קבצים ותיקיות +Name[hi]=फ़ाइलें तथा डिरेक्ट्रियाँ +Name[hne]=फाइल अउ डिरेक्टरी +Name[hr]=Datoteke i direktoriji +Name[hu]=Fájlok és mappák +Name[ia]=Files e directorios +Name[id]=Berkas dan Direktori +Name[is]=Skrár og möppur +Name[it]=File e cartelle +Name[ja]=ファイルとディレクトリ +Name[kk]=Файлдар мен Қапшықтар +Name[km]=ឯកសារ​ និង​ថត +Name[kn]=ಕಡತ ಹಾಗೂ ಕಡಕಕೋಶಗಳು +Name[ko]=파일과 디렉터리 +Name[lt]=Failai ir aplankai +Name[lv]=Faili un Mapes +Name[mai]=फाइल आओर निर्देशिका +Name[mk]=Датотеки и папки +Name[ml]=ഫയല്‍, തട്ട് എന്നിവ +Name[mr]=फाईल व संचयीका +Name[nb]=Filer og mapper +Name[nds]=Dateien un Ornern +Name[nl]=Bestanden en mappen +Name[nn]=Filer og mapper +Name[or]=ଫାଇଲ ଏବଂ ଡ଼ିରେକ୍ଟୋରୀଗୁଡ଼ିକ +Name[pa]=ਫਾਇਲਾਂ ਅਤੇ ਡਾਇਰੈਕਟਰੀਆਂ +Name[pl]=Pliki i katalogi +Name[pt]=Ficheiros e Pastas +Name[pt_BR]=Arquivos e pastas +Name[ro]=Fișiere și directoare +Name[ru]=Файлы и папки +Name[si]=ගොනු සහ බහලුම් +Name[sk]=Súbory a adresáre +Name[sl]=Datoteke in mape +Name[sr]=фајлови и фасцикле +Name[sr@ijekavian]=фајлови и фасцикле +Name[sr@ijekavianlatin]=fajlovi i fascikle +Name[sr@latin]=fajlovi i fascikle +Name[sv]=Filer och kataloger +Name[ta]=கோப்புகளும் அடைவுகளும் +Name[tg]=Проводник +Name[th]=ดูแฟ้มและไดเรกทอรี +Name[tr]=Dosyalar ve Dizinler +Name[ug]=ھۆججەت ۋە مۇندەرىجەلەر +Name[uk]=Файли і каталоги +Name[vi]=Tập tin và thư mục +Name[wa]=Fitchîs eyet ridants +Name[x-test]=xxFiles and Directoriesxx +Name[zh_CN]=文件和目录 +Name[zh_TW]=檔案與目錄 +Comment=Information about files and directories. +Comment[ar]=معلومات عن الملفات والمجلدات. +Comment[ast]=Información sobre los ficheros y direutorios. +Comment[bg]=Данни за файлове и папки. +Comment[bn]=ফাইল এবং ডিরেক্টরি সংক্রান্ত তথ্য। +Comment[bs]=Podaci o datotekema i fasciklama. +Comment[ca]=Informació quant a fitxers i directoris. +Comment[ca@valencia]=Informació quant a fitxers i directoris. +Comment[cs]=Informace o souborech a adresářích. +Comment[csb]=Wëdowiédzô ò lopkach ë katalogach. +Comment[da]=Information om filer og mapper. +Comment[de]=Informationen über Dateien und Ordner. +Comment[el]=Πληροφορίες για αρχεία και καταλόγους. +Comment[en_GB]=Information about files and directories. +Comment[eo]=Informoj pri dosieroj kaj dosierujoj +Comment[es]=Información sobre los archivos y directorios. +Comment[et]=Teave failide ja kataloogide kohta. +Comment[eu]=Fitxategi eta direktorioei buruzko informazioa +Comment[fi]=Tietoa tiedostosta ja hakemistoista. +Comment[fr]=Informations sur les fichiers et les dossiers. +Comment[fy]=Ynformaasje oer triemmen en triemtafels. +Comment[ga]=Eolas faoi chomhaid agus faoi chomhadlanna. +Comment[gl]=Información acerca de ficheiros e cartafoles. +Comment[gu]=ફાઇલો અને ડિરેક્ટરીઓ માટે માહિતી +Comment[he]=מידע על קבצים ותיקיות +Comment[hi]=फ़ाइलों व डिरेक्ट्रियों के बारे में जानकारी +Comment[hr]=Informacije o datotekama i direktorijima. +Comment[hu]=Fájl- és mappajellemzők. +Comment[ia]=Information re files e directorios. +Comment[id]=Informasi tentang berkas dan direktori. +Comment[is]=Upplýsingar um skrár og möppur. +Comment[it]=Informazioni su file e cartelle. +Comment[ja]=ファイルとディレクトリに関する情報 +Comment[kk]=Файлдар мен қыпшықтар туралы мәлімет +Comment[km]=ព័ត៌មាន​អំពី​ឯកសារ និង​ថត ។ +Comment[kn]=ಕಡತಗಳು ಹಾಗೂ ಕಡತಕೋಶಗಳ ಬಗೆಗೆ ಮಾಹಿತಿ. +Comment[ko]=파일과 디렉터리 정보입니다. +Comment[lt]=Informacija apie failus ir aplankus. +Comment[lv]=Informācija par failiem un mapēm. +Comment[mk]=Информации за датотеки и папки. +Comment[ml]=ഫയലുകളുടേയും തട്ടുകളുടേയും വിവരങ്ങള്‍. +Comment[mr]=फाईल्स व संचयीका विषयी माहिती. +Comment[nb]=Informasjon om filer og mapper. +Comment[nds]=Informatschonen över Dateien un Ornern +Comment[nl]=Informatie over bestanden en mappen. +Comment[nn]=Informasjon om filer og mapper. +Comment[pa]=ਫਾਇਲਾਂ ਅਤੇ ਡਾਇਰੈਕਟਰੀਆਂ ਵਾਸਤੇ ਜਾਣਕਾਰੀ +Comment[pl]=Informacje o plikach i katalogach. +Comment[pt]=Informação sobre os ficheiros e pastas. +Comment[pt_BR]=Informações sobre pastas e arquivos. +Comment[ro]=Informații despre fișiere și dosare. +Comment[ru]=Сведения о файлах и папках для виджетов. +Comment[si]=ගොනු හා බහාළුම් පිළිබඳ තොරතුරු +Comment[sk]=Informácie o súboroch a adresároch. +Comment[sl]=Podatki o datotekah in mapah. +Comment[sr]=Подаци о фајловима и фасциклама. +Comment[sr@ijekavian]=Подаци о фајловима и фасциклама. +Comment[sr@ijekavianlatin]=Podaci o fajlovima i fasciklama. +Comment[sr@latin]=Podaci o fajlovima i fasciklama. +Comment[sv]=Information om filer och kataloger. +Comment[tg]=Информация о папках и файлах для плазмоидов +Comment[th]=ข้อมูลเกี่ยวกับแฟ้มและไดเรกทอรีต่าง ๆ +Comment[tr]=Dosyalar ve dizinler hakkında bilgiler. +Comment[ug]=ھۆججەت ۋە مۇندەرىجەلەر ھەققىدە ئۇچۇرلار +Comment[uk]=Інформація про файли і каталоги. +Comment[vi]=Thông tin về tất cả các tập tin và thư mục. +Comment[wa]=Pondants et djondants so les ridants eyet les fitchîs. +Comment[x-test]=xxInformation about files and directories.xx +Comment[zh_CN]=关于文件和目录的信息。 +Comment[zh_TW]=關於檔案與目錄的資訊。 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=system-file-manager +X-KDE-Library=plasma_engine_filebrowser + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=filebrowser +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License= + + diff --git a/plasma/generic/dataengines/geolocation/CMakeLists.txt b/plasma/generic/dataengines/geolocation/CMakeLists.txt new file mode 100644 index 00000000..e911d593 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/CMakeLists.txt @@ -0,0 +1,63 @@ +project(geolocation) + +# ------------------------------------------------------------------------------------------------- + +set(plasma_geolocation_interface_SRCS geolocationprovider.cpp) +kde4_add_library(plasma-geolocation-interface SHARED ${plasma_geolocation_interface_SRCS}) +target_link_libraries(plasma-geolocation-interface ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) +target_link_libraries(plasma-geolocation-interface + LINK_INTERFACE_LIBRARIES ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) +set_target_properties(plasma-geolocation-interface PROPERTIES + VERSION ${GENERIC_LIB_VERSION} + SOVERSION ${GENERIC_LIB_SOVERSION} +) +install(TARGETS plasma-geolocation-interface ${INSTALL_TARGETS_DEFAULT_ARGS}) + +install(FILES geolocationprovider.h geolocation_export.h + DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/geolocation + COMPONENT Devel) + +#install(FILES includes/Interface +# DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Plasma/Geolocation +# COMPONENT Devel) +# ------------------------------------------------------------------------------------------------- + +set(plasma_dataengine_geolocation_SRCS geolocation.cpp) +kde4_add_plugin(plasma_engine_geolocation ${plasma_dataengine_geolocation_SRCS}) +target_link_libraries(plasma_engine_geolocation + plasma-geolocation-interface + ${KDE4_PLASMA_LIBS} + ${KDE4_KDECORE_LIBS} + ${KDE4_KIO_LIBS} + ${KDE4_SOLID_LIBS}) + +install(TARGETS plasma_engine_geolocation DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-geolocation.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES plasma-geolocationprovider.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) + +# ------------------------------------------------------------------------------------------------- + +set(plasma_geolocation_ip_SRCS location_ip.cpp) +kde4_add_plugin(plasma-geolocation-ip ${plasma_geolocation_ip_SRCS}) +target_link_libraries(plasma-geolocation-ip plasma-geolocation-interface) +install(FILES plasma-geolocation-ip.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(TARGETS plasma-geolocation-ip DESTINATION ${PLUGIN_INSTALL_DIR}) + +# ------------------------------------------------------------------------------------------------- + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) +macro_optional_find_package(libgps) +set_package_properties(libgps PROPERTIES DESCRIPTION "GPS support for geolocation" + URL "http://gpsd.berlios.de/" + TYPE OPTIONAL + ) +if(LIBGPS_FOUND) + include_directories(${LIBGPS_INCLUDES} ${LIBGPS_INCLUDE_DIR}) + set(plasma_geolocation_gps_SRCS location_gps.cpp) + kde4_add_plugin(plasma-geolocation-gps ${plasma_geolocation_gps_SRCS}) + target_link_libraries(plasma-geolocation-gps plasma-geolocation-interface ${LIBGPS_LIBRARIES}) + install(FILES plasma-geolocation-gps.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + install(TARGETS plasma-geolocation-gps DESTINATION ${PLUGIN_INSTALL_DIR}) +endif(LIBGPS_FOUND) + +# ------------------------------------------------------------------------------------------------- diff --git a/plasma/generic/dataengines/geolocation/cmake/modules/Findlibgps.cmake b/plasma/generic/dataengines/geolocation/cmake/modules/Findlibgps.cmake new file mode 100644 index 00000000..71a4a084 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/cmake/modules/Findlibgps.cmake @@ -0,0 +1,16 @@ +# LIBGPS_FOUND - system has the LIBGPS library +# LIBGPS_INCLUDE_DIR - the LIBGPS include directory +# LIBGPS_LIBRARIES - The libraries needed to use LIBGPS + +if(LIBGPS_INCLUDE_DIR AND LIBGPS_LIBRARIES) + set(LIBGPS_FOUND TRUE) +else(LIBGPS_INCLUDE_DIR AND LIBGPS_LIBRARIES) + + find_path(LIBGPS_INCLUDE_DIR NAMES gps.h) + find_library(LIBGPS_LIBRARIES NAMES gps) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(libgps DEFAULT_MSG LIBGPS_INCLUDE_DIR LIBGPS_LIBRARIES) + + mark_as_advanced(LIBGPS_INCLUDE_DIR LIBGPS_LIBRARIES) +endif(LIBGPS_INCLUDE_DIR AND LIBGPS_LIBRARIES) diff --git a/plasma/generic/dataengines/geolocation/geolocation.cpp b/plasma/generic/dataengines/geolocation/geolocation.cpp new file mode 100644 index 00000000..65c376ae --- /dev/null +++ b/plasma/generic/dataengines/geolocation/geolocation.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2009 Petri Damsten + * + * 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, see . + */ + +#include "geolocation.h" + +#include + +#include +#include + +static const char SOURCE[] = "location"; + +Geolocation::Geolocation(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) +{ + Q_UNUSED(args) + setMinimumPollingInterval(500); + connect(Solid::Networking::notifier(), SIGNAL(statusChanged(Solid::Networking::Status)), + this, SLOT(networkStatusChanged())); + m_updateTimer.setInterval(100); + m_updateTimer.setSingleShot(true); + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(actuallySetData())); +} + +void Geolocation::init() +{ + //TODO: should this be delayed even further, e.g. when the source is requested? + const KService::List offers = KServiceTypeTrader::self()->query("Plasma/GeolocationProvider"); + QVariantList args; + + foreach (const KService::Ptr service, offers) { + QString error; + GeolocationProvider *plugin = service->createInstance(0, args, &error); + if (plugin) { + m_plugins << plugin; + plugin->init(&m_data, &m_accuracy); + connect(plugin, SIGNAL(updated()), this, SLOT(pluginUpdated())); + connect(plugin, SIGNAL(availabilityChanged(GeolocationProvider*)), + this, SLOT(pluginAvailabilityChanged(GeolocationProvider*))); + } else { + kDebug() << "Failed to load GeolocationProvider:" << error; + } + } +} + +Geolocation::~Geolocation() +{ + qDeleteAll(m_plugins); +} + +QStringList Geolocation::sources() const +{ + return QStringList() << SOURCE; +} + +bool Geolocation::updateSourceEvent(const QString &name) +{ + //kDebug() << name; + if (name == SOURCE) { + return updatePlugins(GeolocationProvider::SourceEvent); + } + + return false; +} + +bool Geolocation::updatePlugins(GeolocationProvider::UpdateTriggers triggers) +{ + bool changed = false; + + foreach (GeolocationProvider *plugin, m_plugins) { + changed = plugin->requestUpdate(triggers) || changed; + } + + if (changed) { + m_updateTimer.start(); + } + + return changed; +} + +bool Geolocation::sourceRequestEvent(const QString &name) +{ + kDebug() << name; + if (name == SOURCE) { + updatePlugins(GeolocationProvider::ForcedUpdate); + setData(SOURCE, m_data); + return true; + } + + return false; +} + +void Geolocation::networkStatusChanged() +{ + kDebug() << "network status changed"; + const Solid::Networking::Status netStatus = Solid::Networking::status(); + if ((netStatus == Solid::Networking::Connected) || (netStatus == Solid::Networking::Unknown)) { + updatePlugins(GeolocationProvider::NetworkConnected); + } +} + +void Geolocation::pluginAvailabilityChanged(GeolocationProvider *provider) +{ + m_data.clear(); + m_accuracy.clear(); + + provider->requestUpdate(GeolocationProvider::ForcedUpdate); + + bool changed = false; + foreach (GeolocationProvider *plugin, m_plugins) { + changed = plugin->populateSharedData() || changed; + } + + if (changed) { + m_updateTimer.start(); + } +} + +void Geolocation::pluginUpdated() +{ + m_updateTimer.start(); +} + +void Geolocation::actuallySetData() +{ + setData(SOURCE, m_data); +} + +#include "geolocation.moc" diff --git a/plasma/generic/dataengines/geolocation/geolocation.h b/plasma/generic/dataengines/geolocation/geolocation.h new file mode 100644 index 00000000..88acc8b9 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/geolocation.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009 Petri Damstén + * + * 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, see . + */ + +#ifndef GEOLOCATION_DATAENGINE_H +#define GEOLOCATION_DATAENGINE_H + +#include + +#include +#include + +#include "geolocationprovider.h" + +class GeolocationProvider; + +class Geolocation : public Plasma::DataEngine +{ + Q_OBJECT + + public: + Geolocation(QObject* parent, const QVariantList& args); + virtual ~Geolocation(); + virtual void init(); + virtual QStringList sources() const; + + protected: + bool sourceRequestEvent(const QString &name); + bool updateSourceEvent(const QString& name); + bool updatePlugins(GeolocationProvider::UpdateTriggers triggers); + + protected slots: + void networkStatusChanged(); + void pluginAvailabilityChanged(GeolocationProvider *provider); + void pluginUpdated(); + void actuallySetData(); + + private: + Data m_data; + EntryAccuracy m_accuracy; + QList m_plugins; + QTimer m_updateTimer; +}; + +K_EXPORT_PLASMA_DATAENGINE(geolocation, Geolocation) + +#endif + diff --git a/plasma/generic/dataengines/geolocation/geolocation_export.h b/plasma/generic/dataengines/geolocation/geolocation_export.h new file mode 100644 index 00000000..c8df298f --- /dev/null +++ b/plasma/generic/dataengines/geolocation/geolocation_export.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + Copyright (C) 2009 Petri Damsten + + 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 GEOLOCATION_EXPORT_H +#define GEOLOCATION_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include + +#ifndef GEOLOCATION_EXPORT +# if defined(MAKE_PLASMA_GEOLOCATION_INTERFACE_LIB) +/* We are building this library */ +# define GEOLOCATION_EXPORT KDE_EXPORT +# else +/* We are using this library */ +# define GEOLOCATION_EXPORT KDE_IMPORT +# endif +#endif + +# ifndef GEOLOCATION_EXPORT_DEPRECATED +# define GEOLOCATION_EXPORT_DEPRECATED KDE_DEPRECATED GEOLOCATION_EXPORT +# endif + +#endif diff --git a/plasma/generic/dataengines/geolocation/geolocationprovider.cpp b/plasma/generic/dataengines/geolocation/geolocationprovider.cpp new file mode 100644 index 00000000..a8729e5a --- /dev/null +++ b/plasma/generic/dataengines/geolocation/geolocationprovider.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009 Aaron Seigo + * + * 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, see . + */ + +#include "geolocationprovider.h" + +GeolocationProvider::GeolocationProvider(QObject *parent, const QVariantList &args) + : QObject(parent), + m_sharedData(0), + m_sharedAccuracies(0), + m_accuracy(1000), + m_updateTriggers(SourceEvent), + m_available(true), + m_updating(false) +{ + Q_UNUSED(args) + m_updateTimer.setSingleShot(true); + m_updateTimer.setInterval(0); + qRegisterMetaType("Plasma::DataEngine::Data"); + connect(&m_updateTimer, SIGNAL(timeout()), this, SIGNAL(updated())); +} + +void GeolocationProvider::init(Plasma::DataEngine::Data *data, EntryAccuracy *accuracies) +{ + m_sharedData = data; + m_sharedAccuracies = accuracies; + init(); +} + +int GeolocationProvider::accuracy() const +{ + return m_accuracy; +} + +bool GeolocationProvider::isAvailable() const +{ + return m_available; +} + +bool GeolocationProvider::requestUpdate(GeolocationProvider::UpdateTriggers triggers) +{ + if (m_available && !m_updating && (triggers == ForcedUpdate || triggers & m_updateTriggers)) { + m_updating = true; + update(); + return true; + } + + return false; +} + +GeolocationProvider::UpdateTriggers GeolocationProvider::updateTriggers() const +{ + return m_updateTriggers; +} + +bool GeolocationProvider::populateSharedData() +{ + Plasma::DataEngine::Data::const_iterator it = m_data.constBegin(); + bool changed = false; + + while (it != m_data.constEnd()) { + if (!m_sharedData->contains(it.key()) || m_sharedAccuracies->value(it.key()) < m_accuracy) { + m_sharedData->insert(it.key(), it.value()); + m_sharedAccuracies->insert(it.key(), m_accuracy); + changed = true; + } + + ++it; + } + + return changed; +} + +void GeolocationProvider::setAccuracy(int accuracy) +{ + m_accuracy = accuracy; +} + +void GeolocationProvider::setIsAvailable(bool available) +{ + if (m_available == available) { + return; + } + + m_available = available; + emit availabilityChanged(this); +} + +void GeolocationProvider::setData(const Plasma::DataEngine::Data &data) +{ + m_updating = false; + m_data = data; + if (populateSharedData()) { + m_updateTimer.start(); + } +} + +void GeolocationProvider::setData(const QString &key, const QVariant &value) +{ + m_updating = false; + m_data.insert(key, value); + + if (!m_sharedData->contains(key) || m_sharedAccuracies->value("key") < m_accuracy) { + m_sharedData->insert(key, value); + m_sharedAccuracies->insert(key, accuracy()); + m_updateTimer.start(); + } +} + +void GeolocationProvider::setUpdateTriggers(UpdateTriggers triggers) +{ + m_updateTriggers = triggers; +} + +void GeolocationProvider::init() +{ +} + +void GeolocationProvider::update() +{ +} + +#include "geolocationprovider.moc" diff --git a/plasma/generic/dataengines/geolocation/geolocationprovider.h b/plasma/generic/dataengines/geolocation/geolocationprovider.h new file mode 100644 index 00000000..c8024d6c --- /dev/null +++ b/plasma/generic/dataengines/geolocation/geolocationprovider.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009 Aaron Seigo + * + * 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, see . + */ + +#ifndef GEOLOCATIONPROVIDER_H +#define GEOLOCATIONPROVIDER_H + +#include +#include +#include + +#include + +#include "geolocation_export.h" + +typedef QHash EntryAccuracy; + +class GEOLOCATION_EXPORT GeolocationProvider : public QObject +{ + Q_OBJECT + +public: + enum UpdateTrigger { ForcedUpdate = 0, SourceEvent = 1, NetworkConnected = 2 }; + Q_DECLARE_FLAGS(UpdateTriggers, UpdateTrigger) + + GeolocationProvider(QObject *parent = 0, const QVariantList &args = QVariantList()); + void init(Plasma::DataEngine::Data *data, EntryAccuracy *accuracies); + + UpdateTriggers updateTriggers() const; + int accuracy() const; + bool isAvailable() const; + bool requestUpdate(UpdateTriggers trigger); + bool populateSharedData(); + +Q_SIGNALS: + void updated(); + void availabilityChanged(GeolocationProvider *provider); + +protected: + void setAccuracy(int accuracy); + void setIsAvailable(bool available); + void setUpdateTriggers(UpdateTriggers triggers); + virtual void init(); + virtual void update(); + +protected Q_SLOTS: + void setData(const Plasma::DataEngine::Data &data); + void setData(const QString &key, const QVariant &value); + +private: + Plasma::DataEngine::Data *m_sharedData; + EntryAccuracy *m_sharedAccuracies; + Plasma::DataEngine::Data m_data; + QTimer m_updateTimer; + int m_accuracy; + UpdateTriggers m_updateTriggers; + bool m_available : 1; + bool m_updating : 1; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(GeolocationProvider::UpdateTriggers) + +#define K_EXPORT_PLASMA_GEOLOCATIONPROVIDER(libname, classname) \ +K_PLUGIN_FACTORY(factory, registerPlugin();) \ +K_EXPORT_PLUGIN(factory("plasma_GeolocationProvider_" #libname)) \ +K_EXPORT_PLUGIN_VERSION(1.0) + +#endif + diff --git a/plasma/generic/dataengines/geolocation/location_gps.cpp b/plasma/generic/dataengines/geolocation/location_gps.cpp new file mode 100644 index 00000000..225d1027 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/location_gps.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2009 Petri Damstén + * + * 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, see . + */ + +#include "location_gps.h" +#include + +Gpsd::Gpsd(gps_data_t* gpsdata) + : m_gpsdata(gpsdata) + , m_abort(false) +{ +} + +Gpsd::~Gpsd() +{ + m_abort = true; + m_condition.wakeOne(); + wait(); +} + +void Gpsd::update() +{ + if (!isRunning()) { + start(); + } else { + m_condition.wakeOne(); + } +} + +void Gpsd::run() +{ +#if defined( GPSD_API_MAJOR_VERSION ) && ( GPSD_API_MAJOR_VERSION >= 3 ) && defined( WATCH_ENABLE ) + gps_stream(m_gpsdata, WATCH_ENABLE, NULL); +#else + gps_query(m_gpsdata, "w+x\n"); +#endif + + while (!m_abort) { + Plasma::DataEngine::Data d; + +#if GPSD_API_MAJOR_VERSION >= 5 + if (gps_read(m_gpsdata) != -1) { +#else + if (gps_poll(m_gpsdata) != -1) { +#endif + //kDebug() << "poll ok"; + if (m_gpsdata->online) { + //kDebug() << "online"; + if (m_gpsdata->status != STATUS_NO_FIX) { + //kDebug() << "fix"; + d["accuracy"] = 30; + d["latitude"] = QString::number(m_gpsdata->fix.latitude); + d["longitude"] = QString::number(m_gpsdata->fix.longitude); + } + } + } + + emit dataReady(d); + + m_condition.wait(&m_mutex); + } +} + +Gps::Gps(QObject* parent, const QVariantList& args) + : GeolocationProvider(parent, args), + m_gpsd(0) +#if GPSD_API_MAJOR_VERSION >= 5 + , m_gpsdata(0) +#endif +{ +#if GPSD_API_MAJOR_VERSION >= 5 + m_gpsdata = new gps_data_t; + if (gps_open("localhost", DEFAULT_GPSD_PORT, m_gpsdata) != -1) { +#else + gps_data_t* m_gpsdata = gps_open("localhost", DEFAULT_GPSD_PORT); + if (m_gpsdata) { +#endif + kDebug() << "gpsd found."; + m_gpsd = new Gpsd(m_gpsdata); + connect(m_gpsd, SIGNAL(dataReady(Plasma::DataEngine::Data)), + this, SLOT(setData(Plasma::DataEngine::Data))); + } else { + kDebug() << "gpsd not found"; + } + + setIsAvailable(m_gpsd); +} + +Gps::~Gps() +{ + delete m_gpsd; +#if GPSD_API_MAJOR_VERSION >= 5 + delete m_gpsdata; +#endif +} + +void Gps::update() +{ + if (m_gpsd) { + m_gpsd->update(); + } +} + +K_EXPORT_PLASMA_GEOLOCATIONPROVIDER(gps, Gps) + +#include "location_gps.moc" diff --git a/plasma/generic/dataengines/geolocation/location_gps.h b/plasma/generic/dataengines/geolocation/location_gps.h new file mode 100644 index 00000000..dba65a26 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/location_gps.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009 Petri Damstén + * + * 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, see . + */ + +#ifndef GPS_H +#define GPS_H + +#include +#include +#include +#include + +#include "geolocationprovider.h" + +class Gpsd : public QThread +{ + Q_OBJECT +public: + Gpsd(gps_data_t* gpsdata); + virtual ~Gpsd(); + + void update(); + +signals: + void dataReady(const Plasma::DataEngine::Data& data); + +protected: + virtual void run(); + +private: + gps_data_t* m_gpsdata; + QMutex m_mutex; + QWaitCondition m_condition; + bool m_abort; +}; + +class Gps : public GeolocationProvider +{ + Q_OBJECT +public: + explicit Gps(QObject *parent = 0, const QVariantList &args = QVariantList()); + ~Gps(); + + void update(); + +private: + Gpsd* m_gpsd; +#if GPSD_API_MAJOR_VERSION >= 5 + gps_data_t* m_gpsdata; +#endif +}; + +#endif diff --git a/plasma/generic/dataengines/geolocation/location_ip.cpp b/plasma/generic/dataengines/geolocation/location_ip.cpp new file mode 100644 index 00000000..6ffe0b16 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/location_ip.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2009 Petri Damstén + * - Original Implementation. + * 2009 Andrew Coles + * - Extension to iplocationtools engine. + * + * 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, see . + */ + +#include "location_ip.h" +#include +#include +#include +#include + +class Ip::Private : public QObject { + +public: + QByteArray payload; + + void populateDataEngineData(Plasma::DataEngine::Data & outd) + { + QString country, countryCode, city, latitude, longitude, ip; + const QList &bl = payload.split('\n'); + payload.clear(); + foreach (const QByteArray &b, bl) { + const QList &t = b.split(':'); + if (t.count() > 1) { + const QByteArray k = t[0]; + const QByteArray v = t[1]; + if (k == "Latitude") { + latitude = v; + } else if (k == "Longitude") { + longitude = v; + } else if (k == "Country") { + QStringList cc = QString(v).split('('); + if (cc.count() > 1) { + country = cc[0].trimmed(); + countryCode = cc[1].replace(')', ""); + } + } else if (k == "City") { + city = v; + } else if (k == "IP") { + ip = v; + } + } + } + // ordering of first three to preserve backwards compatibility + outd["accuracy"] = 40000; + outd["country"] = country; + outd["country code"] = countryCode; + outd["city"] = city; + outd["latitude"] = latitude; + outd["longitude"] = longitude; + outd["ip"] = ip; + } +}; + +Ip::Ip(QObject* parent, const QVariantList& args) + : GeolocationProvider(parent, args), d(new Private()) +{ + setUpdateTriggers(SourceEvent | NetworkConnected); +} + +Ip::~Ip() +{ + delete d; +} + +void Ip::update() +{ + d->payload.clear(); + KIO::TransferJob *datajob = KIO::get(KUrl("http://api.hostip.info/get_html.php?position=true"), + KIO::NoReload, KIO::HideProgressInfo); + + if (datajob) { + kDebug() << "Fetching http://api.hostip.info/get_html.php?position=true"; + connect(datajob, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(readData(KIO::Job*,QByteArray))); + connect(datajob, SIGNAL(result(KJob*)), this, SLOT(result(KJob*))); + } else { + kDebug() << "Could not create job"; + } +} + +void Ip::readData(KIO::Job* job, const QByteArray& data) +{ + Q_UNUSED(job) + + if (data.isEmpty()) { + return; + } + d->payload.append(data); +} + +void Ip::result(KJob* job) +{ + Plasma::DataEngine::Data outd; + + if(job && !job->error()) { + d->populateDataEngineData(outd); + } else { + kDebug() << "error" << job->errorString(); + } + + setData(outd); +} + +K_EXPORT_PLASMA_GEOLOCATIONPROVIDER(ip, Ip) + +#include "location_ip.moc" diff --git a/plasma/generic/dataengines/geolocation/location_ip.h b/plasma/generic/dataengines/geolocation/location_ip.h new file mode 100644 index 00000000..a8eccd66 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/location_ip.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Petri Damstén + * + * 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, see . + */ + +#ifndef IP_H +#define IP_H + +#include "geolocationprovider.h" + +class KJob; +namespace KIO { + class Job; +} + +class Ip : public GeolocationProvider +{ + Q_OBJECT +public: + explicit Ip(QObject *parent = 0, const QVariantList &args = QVariantList()); + ~Ip(); + + virtual void update(); + +protected slots: + void readData(KIO::Job *, const QByteArray& data); + void result(KJob* job); + +private: + class Private; + Private *const d; + +}; + +#endif diff --git a/plasma/generic/dataengines/geolocation/plasma-dataengine-geolocation.desktop b/plasma/generic/dataengines/geolocation/plasma-dataengine-geolocation.desktop new file mode 100644 index 00000000..9a7a6ffd --- /dev/null +++ b/plasma/generic/dataengines/geolocation/plasma-dataengine-geolocation.desktop @@ -0,0 +1,150 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Geolocation +Name[ar]=الموقع الجغرافي +Name[ast]=Xeollocalización +Name[bg]=Геолокация +Name[bs]=geolokacija +Name[ca]=Geolocalització +Name[ca@valencia]=Geolocalització +Name[cs]=Geolokace +Name[csb]=Geògrafnô lokalizacëjô +Name[da]=Geo-lokalisering +Name[de]=Geolokalisierung +Name[el]=Γεωτοποθέτηση +Name[en_GB]=Geolocation +Name[eo]=GeoLokado +Name[es]=Geolocalización +Name[et]=Geolokatsioon +Name[eu]=Geokokapena +Name[fi]=Paikkasijainti +Name[fr]=Géo-localisation +Name[fy]=Geolokaasje +Name[ga]=Geolocation +Name[gl]=Xeolocalización +Name[he]=מציאת מיקום גאוגרפי +Name[hr]=Geolociranje +Name[hu]=Földrajzi helyzet +Name[ia]=Geolocation +Name[id]=Geolokasi +Name[is]=Hnattstaðsetningar +Name[it]=Geolocalizzazione +Name[ja]=ジオロケーション +Name[kk]=Жердегі орны +Name[km]=ទីតាំង​ភូមិសាស្ដ្រ +Name[kn]=ಭೂಪ್ರದೇಶ +Name[ko]=위치 +Name[lt]=Geolokacija +Name[lv]=Ģeolokācija +Name[mk]=Геолоцирање +Name[ml]=ഭൂസ്ഥാനങ്ങള്‍ +Name[mr]=जिओलोकेशन +Name[nb]=Geografisk plassering +Name[nds]=Eersteden +Name[nl]=Geolocatie +Name[nn]=Geolocation +Name[pa]=ਭੂਗੋਲਿਕ ਟਿਕਾਣਾ +Name[pl]=Geolokalizacja +Name[pt]=Geo-Localização +Name[pt_BR]=Localização geográfica +Name[ro]=Geolocație +Name[ru]=Местоположение +Name[si]=පිහිටුම +Name[sk]=Geolokalizácia +Name[sl]=Geolokacija +Name[sr]=геолокација +Name[sr@ijekavian]=геолокација +Name[sr@ijekavianlatin]=geolokacija +Name[sr@latin]=geolokacija +Name[sv]=Geografisk lokalisering +Name[tg]=Ҷойгиршавӣ +Name[th]=การระบุพิกัดตำแหน่ง +Name[tr]=Geolocation +Name[ug]=جۇغراپىيىلىك ئورۇن +Name[uk]=Геопозиціювання +Name[vi]=Vị trí địa lý +Name[wa]=Djeyoplaeçmint +Name[x-test]=xxGeolocationxx +Name[zh_CN]=地理 +Name[zh_TW]=Geolocation +Comment=Geolocation Data Engine +Comment[ar]=محرك بيانات الموقع الجغرافي +Comment[ast]=Motor de datos de xeollocalización +Comment[bg]=Ядро с данни за геолокация +Comment[bs]=Datomotor geolokacije +Comment[ca]=Motor de dades de geolocalització +Comment[ca@valencia]=Motor de dades de geolocalització +Comment[cs]=Datový nástroj geolokace +Comment[csb]=Czérownik pòdôwków geògrafny lokalizacëji +Comment[da]=Datamotor til geo-lokalisering +Comment[de]=Geolokalisierungs-Datentreiber +Comment[el]=Μηχανή δεδομένων γεωτοποθέτησης +Comment[en_GB]=Geolocation Data Engine +Comment[eo]=Datuma motoro de GeoLokado +Comment[es]=Motor de datos de geolocalización +Comment[et]=Geolokatsiooni andmete mootor +Comment[eu]=Geokokapen datuen motorra +Comment[fi]=Paikkasijaintidatakone +Comment[fr]=Moteur de données de géo-localisation +Comment[fy]=Geolokaasje gegevens motor +Comment[ga]=Inneall Sonraí Geolocation +Comment[gl]=Motor de datos de xeolocalización +Comment[he]=מנוע תוכן מציאת מיקום גאוגרפי +Comment[hr]=Podatkovni mehanizam za geolociranje +Comment[hu]=Kezelőmodul a földrajzi helyzet kiírásához +Comment[ia]=Motor de datos de geolocation +Comment[id]=Mesin Data Geolokasi +Comment[is]=Gagnavél fyrir hnattstaðsetningu +Comment[it]=Motore di dati per la geolocalizzazione +Comment[ja]=ジオロケーション用データエンジン +Comment[kk]=Жердегі орын туралы деректер тетігі +Comment[km]=ម៉ាស៊ីន​ទិន្នន័យ​ Geolocation +Comment[kn]=ಭೂಪ್ರದೇಶ ದತ್ತ ಯಂತ್ರ +Comment[ko]=위치 데이터 엔진 +Comment[lt]=Geolokacijos duomenų variklis +Comment[lv]=Ģeolokācijas datu dzinējs +Comment[mai]=भूअवस्थिति डाटा इंजिन +Comment[mk]=Машина за податоци за геолоцирање +Comment[ml]=ഭൂസ്ഥാനങ്ങള്‍ക്കുള്ള ഡേറ്റാ എഞ്ചിന്‍ +Comment[mr]=जिओलोकेशन डेटा इंजिन +Comment[nb]=Datamotor for geografisk plassering +Comment[nds]=Eersteden-Datenkarn +Comment[nl]=Geolocatie gegevensengine +Comment[nn]=Geolocation-datamotor +Comment[pa]=ਭੂਗੋਲਿਕ-ਟਿਕਾਣਾ ਡਾਟਾ ਇੰਜਣ +Comment[pl]=Silnik danych geolokalizacji +Comment[pt]=Motor de Dados de Geo-Localização +Comment[pt_BR]=Mecanismo de dados de localização geográfica +Comment[ro]=Motor de date Geolocație +Comment[ru]=Источник данных о местоположении +Comment[si]=භූපිහිටුම් දත්ත එන්ජිම +Comment[sk]=Dátový nástroj geolokalizácie +Comment[sl]=Podatkovni pogon s podatki o geolokaciji +Comment[sr]=Датомотор геолокације +Comment[sr@ijekavian]=Датомотор геолокације +Comment[sr@ijekavianlatin]=Datomotor geolokacije +Comment[sr@latin]=Datomotor geolokacije +Comment[sv]=Datagränssnitt för geografisk lokalisering +Comment[tg]=Барномаҳои луғат +Comment[th]=กลไกข้อมูลการระบุพิกัดตำแหน่ง +Comment[tr]=Geolocation Veri Motoru +Comment[ug]=جۇغراپىيىلىك ئورۇن سانلىق-مەلۇمات ماتورى +Comment[uk]=Рушій даних геопозиціювання +Comment[vi]=Cơ chế dữ liệu vị trí địa lý +Comment[wa]=Éndjin di dnêyes di djeyoplaeçmint +Comment[x-test]=xxGeolocation Data Enginexx +Comment[zh_CN]=地理位置数据引擎 +Comment[zh_TW]=Geolocation 資料引擎 +ServiceTypes=Plasma/DataEngine +Type=Service +Icon=applications-internet +X-KDE-Library=plasma_engine_geolocation + +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=geolocation +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma@kde.org +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/geolocation/plasma-geolocation-gps.desktop b/plasma/generic/dataengines/geolocation/plasma-geolocation-gps.desktop new file mode 100644 index 00000000..460d0102 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/plasma-geolocation-gps.desktop @@ -0,0 +1,143 @@ +[Desktop Entry] +Name=Geolocation GPS +Name[ar]=الموقع الجغرافي جي بي اس +Name[ast]=Xeollocalización per aciu de GPS +Name[bg]=Геолокация (GPS) +Name[bs]=geolokacija GPS +Name[ca]=Geolocalització GPS +Name[ca@valencia]=Geolocalització GPS +Name[cs]=Geolokace GPS +Name[csb]=Geògrafnô lokalizacëjô GPS +Name[da]=GPS til geo-lokalisering +Name[de]=Geolokalisierung GPS +Name[el]=GPS Γεωτοποθέτηση +Name[en_GB]=Geolocation GPS +Name[eo]=GPS loktrovado +Name[es]=Geolocalización mediante GPS +Name[et]=Geolokatsioon GPS-ist +Name[eu]=GPS geokokapena +Name[fi]=Paikkasijainti GPS +Name[fr]=Géo-localisation par GPS +Name[fy]=Geolokaasje GPS +Name[ga]=Córas Suite Domhanda Geolocation +Name[gl]=Xeolocalización con GPS +Name[he]=מציאת מיקום גאוגרפי GPS +Name[hr]=GPS geolociranje +Name[hu]=GPS-alapú helyzetjelző +Name[ia]=Geolocation GPS +Name[id]=GPS Geolokasi +Name[is]=GPS hnattstaðsetning +Name[it]=Geolocalizzazione GPS +Name[ja]=ジオロケーション GPS +Name[kk]=GPS-тен орнын табу +Name[km]=ទីតាំង​ភូមិសាស្ត្រ GPS +Name[kn]=ಭೂಪ್ರದೇಶದ GPS +Name[ko]=GPS 위치 +Name[lt]=Geolokacinis GPS +Name[lv]=Ģeolokācija GPS +Name[mai]=भूअवस्थिति जीपीएस +Name[mk]=ГПС за геолоцирање +Name[ml]=ജിപിഎസ് ഭൂസ്ഥാനങ്ങള്‍ +Name[mr]=GPS जिओलोकेशन +Name[nb]=Geografisk plassering GPS +Name[nds]=GPS-Eersteed +Name[nl]=Geolocatie GPS +Name[nn]=Geolocation GPS +Name[pa]=ਭੂਗੋਲਿਕ-ਟਿਕਾਣਾ GPS +Name[pl]=Geolokalizacja: GPS +Name[pt]=Geo-Localização por GPS +Name[pt_BR]=Localização geográfica GPS +Name[ro]=GPS geolocație +Name[ru]=Геолокация по GPS +Name[si]=පිහිටුම් GPS +Name[sk]=Geolokalizácia GPS +Name[sl]=Geolokacija GPS +Name[sr]=геолокација ГПС +Name[sr@ijekavian]=геолокација ГПС +Name[sr@ijekavianlatin]=geolokacija GPS +Name[sr@latin]=geolokacija GPS +Name[sv]=Lokalisera geografiskt med GPS +Name[tg]=Ҷойгиршавии GPS +Name[th]=การระบุพิกัดตำแหน่งด้วย GPS +Name[tr]=Geolocation GPS +Name[ug]=جۇغراپىيىلىك ئورۇن GPS +Name[uk]=Геопозиціювання за GPS +Name[vi]=Vị trí địa lý GPS +Name[wa]=GPS di djeyoplaeçmint +Name[x-test]=xxGeolocation GPSxx +Name[zh_CN]=GPS 位置 +Name[zh_TW]=Geolocation GPS +Comment=Geolocation from GPS address. +Comment[ar]=الموقع الجغرافي من عنوان جي بي اس +Comment[ast]=Xeollocalización dende una direición GPS. +Comment[bg]=Геолокация от GPS адрес. +Comment[bs]=Geolociranje kroz GPS adresu. +Comment[ca]=Geolocalització des d'una adreça GPS. +Comment[ca@valencia]=Geolocalització des d'una adreça GPS. +Comment[cs]=Geolokace z GPS adresy. +Comment[csb]=Geògrafnô lokalizacëjô z adresë GPS. +Comment[da]=Geo-lokalisering ud fra GPS-adresse. +Comment[de]=Geolokalisierung mittels GPS-Koordinate. +Comment[el]=Γεωτοποθέτηση από GPS διεύθυνση. +Comment[en_GB]=Geolocation from GPS address. +Comment[eo]=Loktrovado el GPS adreso +Comment[es]=Geolocalización desde una dirección GPS. +Comment[et]=Geolokatsioon GPS-aadressi põhjal +Comment[eu]=Geokokapena GPS helbidetik. +Comment[fi]=Paikkasijainti GPS-osoitteesta. +Comment[fr]=Géo-localisation depuis une adresse GPS. +Comment[fy]=Geolokaasje fan GPS adres. +Comment[ga]=Suíomh geografach ó sheoladh GPS. +Comment[gl]=Xeolocaliza con datos de GPS. +Comment[he]=מציאת מיקום גאוגרפי ממיקום GPS. +Comment[hr]=Geolociranje s GPS adrese. +Comment[hu]=A földrajzi helyzet meghatározása GPS segítségével. +Comment[ia]=Geolocation ex adresse GPS. +Comment[id]=Geolokasi dari alamat GPS. +Comment[is]=Hnattstaðsetning eftir GPS vistfangi. +Comment[it]=Geolocalizzazione dalla posizione GPS. +Comment[ja]=GPS アドレスによるジオロケーション +Comment[kk]=GPS адресінен орнын табу +Comment[km]=ទីតាំង​ភូមិសាស្ត្រ​ពី​អាយដ្ឋាន GPS ។ +Comment[kn]=GPS ವಿಳಾಸದಿಂದ ಭೂಪ್ರದೇಶ. +Comment[ko]=GPS 위치에 따른 주소입니다. +Comment[lt]=Geolokacija pagal GPS adresą. +Comment[lv]=Ģeolokācija no GPS adreses. +Comment[mai]=GPS पता सँ भूअवस्थिति. +Comment[mk]=Геолокација преку ГПС-адреса. +Comment[ml]=ജിപിഎസ് വിലാസത്തില്‍ നിന്നും ഭൂസ്ഥാനങ്ങള്‍ +Comment[mr]=GPS पत्त्यावरुन जिओलोकेशन. +Comment[nb]=Geografisk plassering etter GPS-adresse. +Comment[nds]=Eersteed ut GPS-Adress +Comment[nl]=Geolocatie uit GPS-adres. +Comment[nn]=Geolocation med GPS-adresse. +Comment[pa]=GPS ਐਡਰੈੱਸ ਤੋਂ ਭੂਗੋਲਿਕ ਟਿਕਾਣਾ। +Comment[pl]=Geolokalizacja z adresu GPS. +Comment[pt]=Geo-localização a partir do endereço do GPS. +Comment[pt_BR]=Localização geográfica de endereços de GPS. +Comment[ro]=Geolocație din adresă GPS. +Comment[ru]=Геолокация по адресу GPS. +Comment[si]=GPS ලිපින මගින් පිහිටුම +Comment[sk]=Geolokalizácia z GPS adresy. +Comment[sl]=Geolokacija iz podatkov GPS. +Comment[sr]=Геолоцирање кроз ГПС адресу. +Comment[sr@ijekavian]=Геолоцирање кроз ГПС адресу. +Comment[sr@ijekavianlatin]=Geolociranje kroz GPS adresu. +Comment[sr@latin]=Geolociranje kroz GPS adresu. +Comment[sv]=Geografisk lokalisering från GPS-adress. +Comment[tg]=Ҷойгиршавии ҷуғрофӣ аз суроғаи GPS +Comment[th]=การระบุพิกัดตำแหน่งจากพิกัด GPS +Comment[tr]=GPS adresinden coğrafi konum. +Comment[ug]=GPS ئادرېسنىڭ جۇغراپىيىلىك ئورنى +Comment[uk]=Геопозиціювання за GPS-адресою +Comment[vi]=Vị trí địa lý từ địa chỉ GPS. +Comment[wa]=Djeyoplaeçmint a pårti d' ene adresse GPS. +Comment[x-test]=xxGeolocation from GPS address.xx +Comment[zh_CN]=GPS 地址产生的位置 +Comment[zh_TW]=從 GPS 位址取得 Geolocation。 +X-KDE-ServiceTypes=Plasma/GeolocationProvider +X-KDE-ParentApp=geolocation +Type=Service +Icon=applications-internet +X-KDE-Library=plasma-geolocation-gps +X-KDE-PluginInfo-Name=gps diff --git a/plasma/generic/dataengines/geolocation/plasma-geolocation-ip.desktop b/plasma/generic/dataengines/geolocation/plasma-geolocation-ip.desktop new file mode 100644 index 00000000..a1a84da1 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/plasma-geolocation-ip.desktop @@ -0,0 +1,143 @@ +[Desktop Entry] +Name=Geolocation IP +Name[ar]=المواقع الجغرافي عنوان الانترنت +Name[ast]=Xeollocalización per aciu d'IP +Name[bg]=Геолокация (IP) +Name[bs]=geolokacija IP +Name[ca]=Geolocalització IP +Name[ca@valencia]=Geolocalització IP +Name[cs]=Geolokace IP +Name[csb]=IP geògrafny lokalizacëji +Name[da]=IP-adresse til geo-lokalisering +Name[de]=Geolokalisierung IP +Name[el]=Γεωτοποθεσίες IP +Name[en_GB]=Geolocation IP +Name[eo]=GeoLokado IP +Name[es]=Geolocalización mediante IP +Name[et]=Geolokatsioon IP-st +Name[eu]=IP geokokapen +Name[fi]=Paikkasijainti-ip-osoite +Name[fr]=Géo-localisation par IP +Name[fy]=Geolokaasje IP +Name[ga]=Geolocation IP +Name[gl]=Xeolocalización pola IP +Name[he]=מציאת מיקום גיאוגרפי IP +Name[hr]=IP geolociranje +Name[hu]=Földrajzi helyzet IP címmel +Name[ia]=Geolocation IP +Name[id]=IP Geolokasi +Name[is]=IP vistfang hnattstaðsetningar +Name[it]=Geolocalizzazione IP +Name[ja]=ジオロケーション IP +Name[kk]=IP-ден орнын табу +Name[km]=IP ទីតាំង​ភូមិសាស្ត្រ +Name[kn]=ಭೂಪ್ರದೇಶದ IP +Name[ko]=IP 위치 +Name[lt]=Geolokacija pagal IP +Name[lv]=Ģeolokācija IP +Name[mai]=भूअवस्थिति IP +Name[mk]=ИП за геолоцирање +Name[ml]=ഭൂസ്ഥാന ഐപി +Name[mr]=जिओलोकेशन IP +Name[nb]=Geografisk plassering IP +Name[nds]=IP-Eersteed +Name[nl]=Geolocatie-IP +Name[nn]=Geolocation IP +Name[pa]=ਭੂਗੋਲਿਕ-ਟਿਕਾਣਾ IP +Name[pl]=Geolokalizacja: IP +Name[pt]=Geo-Localização por IP +Name[pt_BR]=Localização geográfica IP +Name[ro]=IP geolocație +Name[ru]=Геолокация по IP-адресу +Name[si]=පිහිටුම් IP +Name[sk]=Geolokalizácia IP +Name[sl]=Geolokacija IP +Name[sr]=геолокација ИП +Name[sr@ijekavian]=геолокација ИП +Name[sr@ijekavianlatin]=geolokacija IP +Name[sr@latin]=geolokacija IP +Name[sv]=Lokalisera geografiskt med IP-adress +Name[tg]=Ҷойгиршавии IP +Name[th]=การระบุพิกัดตำแหน่งจากไอพี +Name[tr]=Geolocation IP +Name[ug]=جۇغراپىيىلىك ئورۇن IP +Name[uk]=Геопозиціювання за IP +Name[vi]=Vị trí địa lý IP +Name[wa]=Gjeyoplaeçmint di l' IP +Name[x-test]=xxGeolocation IPxx +Name[zh_CN]=IP 位置 +Name[zh_TW]=Geolocation IP +Comment=Geolocation from IP address. +Comment[ar]=الموقع الجغرافي من عنوان الإنترنت +Comment[ast]=Xeollocalización dende una direición IP. +Comment[bg]=Геолокация по IP-адрес. +Comment[bs]=Geolociranje kroz IP adresu. +Comment[ca]=Geolocalització des d'una adreça IP. +Comment[ca@valencia]=Geolocalització des d'una adreça IP. +Comment[cs]=Geolokace z IP adresy. +Comment[csb]=Geògrafnô lokalizacëjô z adresë IP. +Comment[da]=Geo-lokalisering ud fra IP-adresse. +Comment[de]=Geolokalisierung mittels IP-Adresse. +Comment[el]=Γεωτοποθέτηση από IP διεύθυνση. +Comment[en_GB]=Geolocation from IP address. +Comment[eo]=Loktrovado el IP Adreso +Comment[es]=Geolocalización desde una dirección IP. +Comment[et]=Geolokatsioon IP-aadressi põhjal +Comment[eu]=Geokokapena IP helbidetik. +Comment[fi]=Paikkasijainti ip-osoitteesta. +Comment[fr]=Géo-localisation depuis une adresse IP. +Comment[fy]=Geolokaassje fan IP adres. +Comment[ga]=Suíomh geografach ó sheoladh IP. +Comment[gl]=Xeolocaliza mediante o enderezo IP. +Comment[he]=מציאת מיקום גאוגרפי באמצעות כתובת IP. +Comment[hr]=Geolociranje pomoću IP adrese. +Comment[hu]=Meghatározza a földrajzi helyzetet az IP cím alapján. +Comment[ia]=Geolocation ex adresse IP +Comment[id]=Geolokasi dari alamat IP. +Comment[is]=Hnattstaðsetning eftir IP vistfangi. +Comment[it]=Geolocalizzazione dall'indirizzo IP. +Comment[ja]=IP アドレスによるジオロケーション +Comment[kk]=IP адресінен орнын табу +Comment[km]=ទីតាំង​ភូមិសាស្ត្រ​ពី​​អាសយដ្ឋាន IP ។ +Comment[kn]=IP ವಿಳಾಸದಿಂದ ಭೂಪ್ರದೇಶ. +Comment[ko]=IP에서 얻어낸 주소입니다. +Comment[lt]=Geolokacija pagal IP adresą. +Comment[lv]=Ģeolokācija no IP adreses. +Comment[mai]=IP पता से भूअवस्थिति. +Comment[mk]=Геолокација преку ИП-адреса. +Comment[ml]=ഐപി വിലാസനതില്‍ നിന്നും ഭൂസ്ഥാനങ്ങള്‍ +Comment[mr]=IP पत्त्यावरुन जिओलोकेशन. +Comment[nb]=Geografisk plassering etter IP adresse. +Comment[nds]=Eersteed ut IP-Adress +Comment[nl]=Geolocatie uit IP-adres. +Comment[nn]=Geolocation med IP-adresse. +Comment[pa]=IP ਐਡਰੈੱਸ ਤੋਂ ਭੂਗੋਲਿਕ-ਟਿਕਾਣਾ +Comment[pl]=Geolokalizacja za pomocą adresu IP. +Comment[pt]=Geo-localização a partir do endereço IP. +Comment[pt_BR]=Localização geográfica de endereços IP. +Comment[ro]=Geolocație din adresă IP. +Comment[ru]=Геолокация по IP-адресу. +Comment[si]=IP ලිපින තුළින් පිහිටුම +Comment[sk]=Geolokalizácia z IP adresy. +Comment[sl]=Geolokacija iz naslova IP. +Comment[sr]=Геолоцирање кроз ИП адресу. +Comment[sr@ijekavian]=Геолоцирање кроз ИП адресу. +Comment[sr@ijekavianlatin]=Geolociranje kroz IP adresu. +Comment[sr@latin]=Geolociranje kroz IP adresu. +Comment[sv]=Geografisk lokalisering från IP-adress. +Comment[tg]=Ҷойгиршавии сурағаи интернетӣ. +Comment[th]=การระบุพิกัดตำแหน่งจากที่อยู่ไอพี +Comment[tr]=IP adresinden coğrafi konum. +Comment[ug]=IP ئادرېسنىڭ جۇغراپىيىلىك ئورنى. +Comment[uk]=Геопозиціювання за IP-адресою +Comment[vi]=Vị trí địa lý từ địa chỉ IP. +Comment[wa]=Djeyoplaeçmint a pårti d' ene adresse IP. +Comment[x-test]=xxGeolocation from IP address.xx +Comment[zh_CN]=IP 地址确定的位置 +Comment[zh_TW]=從 IP 位址取得 Geolocation。 +X-KDE-ServiceTypes=Plasma/GeolocationProvider +X-KDE-ParentApp=geolocation +Type=Service +Icon=applications-internet +X-KDE-Library=plasma-geolocation-ip +X-KDE-PluginInfo-Name=ip diff --git a/plasma/generic/dataengines/geolocation/plasma-geolocationprovider.desktop b/plasma/generic/dataengines/geolocation/plasma-geolocationprovider.desktop new file mode 100644 index 00000000..92682c43 --- /dev/null +++ b/plasma/generic/dataengines/geolocation/plasma-geolocationprovider.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Plasma/GeolocationProvider +Comment=Plasma Geolocation Provider +Comment[ar]=مزود الموقع الجغرافي لبلازما +Comment[ast]=Fornidor de xeollocalización de Plasma +Comment[bg]=Доставчик на геолокация Plasma +Comment[bs]=Plazma dobavljač geolokacije +Comment[ca]=Proveïdor de geolocalització del Plasma +Comment[ca@valencia]=Proveïdor de geolocalització del Plasma +Comment[cs]=Poskytovatel geolokace Plasma +Comment[csb]=Plazma geògrafny lokalizacëji +Comment[da]=Plasma geo-lokalisering-udbyder +Comment[de]=Plasma-Geolokalisierungs-Anbieter +Comment[el]=Πάροχος γεωτοποθέτησης Plasma +Comment[en_GB]=Plasma Geolocation Provider +Comment[eo]=Plasma GeoLokada provizanto +Comment[es]=Proveedor de geolocalización de Plasma +Comment[et]=Plasma geolokatsiooni pakkuja +Comment[eu]=Plasma geokokapen hornitzailea +Comment[fi]=Plasma-paikkasijaintitarjoaja +Comment[fr]=Fournisseur de géo-localisation de Plasma +Comment[fy]=Plasma Geolokaasje ferskaffer +Comment[ga]=Soláthraí Geolocation Plasma +Comment[gl]=Subministrador de xeolocalización para Plasma +Comment[he]=ספק מציאת מיקום גאוגרפי ל־Plasma +Comment[hr]=Podrška za Plasma geolociranje +Comment[hu]=Plasma helymeghatározó modul +Comment[ia]=Fornitor de geolocation de Plasma +Comment[id]=Penyedia Geolokasi Plasma +Comment[is]=Útgefandi hnattstaðsetningar fyrir Plasma +Comment[it]=Motore di geolocalizzazione di Plasma +Comment[ja]=Plasma ジオロケーション・プロバイダ +Comment[kk]=Plasma орнын табу құралы +Comment[km]=ក្រុមហ៊ុន​ផ្ដល់​ទីតាំង​ភូមិសាស្ត្រ​ប្លាស្មា +Comment[kn]=ಪ್ಲಾಸ್ಮಾ ಭೂಪ್ರದೇಶ ಒದಗಿಸುವ ಸಾಧನ +Comment[ko]=Plasma 위치 공급자 +Comment[lt]=Plasma geolokacijos paslaugos teikiklis +Comment[lv]=Plasma ģeolokācijas piegādātājs +Comment[mai]=प्लाज्मा भूअवस्थिति प्रदाता +Comment[ml]=പ്ലാസ്മയുടെ ഭൂസ്ഥാന ധാതാവ് +Comment[mr]=प्लाज्मा जिओलोकेशन पुरवठाकर्ता +Comment[nb]=Plasma-leverandør av geografisk plassering +Comment[nds]=Plasma sien Eersteden-Anbeder +Comment[nl]=Plasma Geolocatieleverancier +Comment[nn]=Plasma Geolocation-leverandør +Comment[pa]=ਪਲਾਜ਼ਮਾ ਭੂਗੋਲਿਕ ਪਰੋਵਾਇਡਰ +Comment[pl]=Dostawca geolokalizacji Plazmy +Comment[pt]=Fornecedor de Geo-Localização do Plasma +Comment[pt_BR]=Fornecedor de localização geográfica do Plasma +Comment[ro]=Furnizor de geolocație Plasma +Comment[ru]=Источник данных о географическом местонахождении +Comment[si]=ප්ලාස්මා පිහිටුම සැපයුම්කරු +Comment[sk]=Poskytovateľ geolokalizácie Plasma +Comment[sl]=Ponudnik geolokacije za Plasmo +Comment[sr]=Плазма добављач геолокације +Comment[sr@ijekavian]=Плазма добављач геолокације +Comment[sr@ijekavianlatin]=Plasma dobavljač geolokacije +Comment[sr@latin]=Plasma dobavljač geolokacije +Comment[sv]=Plasma geografisk lokalisering +Comment[tg]=Барномаҳои луғат +Comment[th]=ผู้ให้บริการพิกัดตำแหน่งของพลาสมา +Comment[tr]=Plasma Geolocation Sağlayıcı +Comment[ug]=پلازما جۇغراپىيىلىك ئورۇن تەمىنلىگۈچى +Comment[uk]=Інструмент геопозиціювання Плазми +Comment[wa]=Ahesseu di djeyopleçmint di Plasma +Comment[x-test]=xxPlasma Geolocation Providerxx +Comment[zh_CN]=Plasma 地理定位提供方 +Comment[zh_TW]=Plasma Geolocation 提供者 + diff --git a/plasma/generic/dataengines/hotplug/CMakeLists.txt b/plasma/generic/dataengines/hotplug/CMakeLists.txt new file mode 100644 index 00000000..bc94e1be --- /dev/null +++ b/plasma/generic/dataengines/hotplug/CMakeLists.txt @@ -0,0 +1,12 @@ +set(hotplug_engine_SRCS + hotplugengine.cpp + hotplugservice.cpp + hotplugjob.cpp +) + +kde4_add_plugin(plasma_engine_hotplug ${hotplug_engine_SRCS}) +target_link_libraries(plasma_engine_hotplug ${KDE4_PLASMA_LIBS} ${KDE4_KDECORE_LIBS} ${KDE4_SOLID_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_engine_hotplug DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-hotplug.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install(FILES hotplug.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services ) diff --git a/plasma/generic/dataengines/hotplug/hotplug.operations b/plasma/generic/dataengines/hotplug/hotplug.operations new file mode 100644 index 00000000..c58d0dc3 --- /dev/null +++ b/plasma/generic/dataengines/hotplug/hotplug.operations @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/plasma/generic/dataengines/hotplug/hotplugengine.cpp b/plasma/generic/dataengines/hotplug/hotplugengine.cpp new file mode 100644 index 00000000..38e16310 --- /dev/null +++ b/plasma/generic/dataengines/hotplug/hotplugengine.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2007 Menard Alexis + * + * This program is free software you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * 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 "hotplugengine.h" +#include "hotplugservice.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//solid specific includes +#include +#include +#include +#include +#include +#include + +//#define HOTPLUGENGINE_TIMING + +HotplugEngine::HotplugEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args), + m_dirWatch(new KDirWatch(this)) +{ + QStringList folders = KGlobal::dirs()->findDirs("data", "solid/actions/"); + foreach (const QString &folder, folders) { + m_dirWatch->addDir(folder, KDirWatch::WatchFiles); + } + connect(m_dirWatch, SIGNAL(dirty(QString)), this, SLOT(updatePredicates(QString))); +} + +HotplugEngine::~HotplugEngine() +{ + +} + +void HotplugEngine::init() +{ + findPredicates(); + + Solid::Predicate p(Solid::DeviceInterface::StorageAccess); + p |= Solid::Predicate(Solid::DeviceInterface::StorageDrive); + p |= Solid::Predicate(Solid::DeviceInterface::StorageVolume); + p |= Solid::Predicate(Solid::DeviceInterface::OpticalDrive); + p |= Solid::Predicate(Solid::DeviceInterface::PortableMediaPlayer); + p |= Solid::Predicate(Solid::DeviceInterface::SmartCardReader); + p |= Solid::Predicate(Solid::DeviceInterface::Camera); + QList devices = Solid::Device::listFromQuery(p); + foreach (const Solid::Device &dev, devices) { + m_startList.insert(dev.udi(), dev); + } + + connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(QString)), + this, SLOT(onDeviceAdded(QString))); + connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(QString)), + this, SLOT(onDeviceRemoved(QString))); + + m_encryptedPredicate = Solid::Predicate("StorageVolume", "usage", "Encrypted"); + + processNextStartupDevice(); +} + +Plasma::Service* HotplugEngine::serviceForSource(const QString& source) +{ + return new HotplugService (this, source); +} + +void HotplugEngine::processNextStartupDevice() +{ + if (!m_startList.isEmpty()) { + QHash::iterator it = m_startList.begin(); + //Solid::Device dev = const_cast(m_startList.takeFirst()); + onDeviceAdded(it.value(), false); + m_startList.erase(it); + } + + if (m_startList.isEmpty()) { + m_predicates.clear(); + } else { + QTimer::singleShot(0, this, SLOT(processNextStartupDevice())); + } +} + +void HotplugEngine::findPredicates() +{ + m_predicates.clear(); + + foreach (const QString &path, KGlobal::dirs()->findAllResources("data", "solid/actions/")) { + KDesktopFile cfg(path); + const QString string_predicate = cfg.desktopGroup().readEntry("X-KDE-Solid-Predicate"); + //kDebug() << path << string_predicate; + m_predicates.insert(KUrl(path).fileName(), Solid::Predicate::fromString(string_predicate)); + } + + if (m_predicates.isEmpty()) { + m_predicates.insert(QString(), Solid::Predicate::fromString(QString())); + } +} + +void HotplugEngine::updatePredicates(const QString &path) +{ + Q_UNUSED(path) + + findPredicates(); + + QHashIterator it(m_devices); + while (it.hasNext()) { + it.next(); + Solid::Device device(it.value()); + QString udi(it.key()); + + const QStringList predicates = predicatesForDevice(device); + if (!predicates.isEmpty()) { + if (sources().contains(udi)) { + Plasma::DataEngine::Data data; + data.insert("predicateFiles", predicates); + setData(udi, data); + } else { + onDeviceAdded(device, false); + } + } else if (!m_encryptedPredicate.matches(device) && sources().contains(udi)) { + removeSource(udi); + scheduleSourcesUpdated(); + } + } +} + +QStringList HotplugEngine::predicatesForDevice(Solid::Device &device) const +{ + QStringList interestingDesktopFiles; + //search in all desktop configuration file if the device inserted is a correct device + QHashIterator it(m_predicates); + //kDebug() << "=================" << udi; + while (it.hasNext()) { + it.next(); + if (it.value().matches(device)) { + //kDebug() << " hit" << it.key(); + interestingDesktopFiles << it.key(); + } + } + + return interestingDesktopFiles; +} + +void HotplugEngine::onDeviceAdded(const QString &udi) +{ + Solid::Device device(udi); + onDeviceAdded(device); +} + +void HotplugEngine::onDeviceAdded(Solid::Device &device, bool added) +{ + //kDebug() << "adding" << device.udi(); +#ifdef HOTPLUGENGINE_TIMING + QTime t; + t.start(); +#endif + // Skip things we know we don't care about + if (device.is()) { + Solid::StorageDrive *drive = device.as(); + if (!drive->isHotpluggable()) { +#ifdef HOTPLUGENGINE_TIMING + kDebug() << "storage, but not pluggable, returning" << t.restart(); +#endif + return; + } + } else if (device.is()) { + Solid::StorageVolume *volume = device.as(); + Solid::StorageVolume::UsageType type = volume->usage(); + if ((type == Solid::StorageVolume::Unused || + type == Solid::StorageVolume::PartitionTable) && !device.is()) { +#ifdef HOTPLUGENGINE_TIMING + kDebug() << "storage volume, but not of interest" << t.restart(); +#endif + return; + } + } + + m_devices.insert(device.udi(), device); + + if (m_predicates.isEmpty()) { + findPredicates(); + } + + const QStringList interestingDesktopFiles = predicatesForDevice(device); + const bool isEncryptedContainer = m_encryptedPredicate.matches(device); + + if (!interestingDesktopFiles.isEmpty() || isEncryptedContainer) { + //kDebug() << device.product(); + //kDebug() << device.vendor(); + //kDebug() << "number of interesting desktop file : " << interestingDesktopFiles.size(); + Plasma::DataEngine::Data data; + data.insert("added", added); + data.insert("udi", device.udi()); + + if (!device.description().isEmpty()) { + data.insert("text", device.description()); + } else { + data.insert("text", QString(device.vendor() + QLatin1Char(' ') + device.product())); + } + data.insert("icon", device.icon()); + data.insert("emblems", device.emblems()); + data.insert("predicateFiles", interestingDesktopFiles); + + QVariantList actions; + foreach(const QString& desktop, interestingDesktopFiles) { + QString actionUrl = KStandardDirs::locate("data", "solid/actions/" + desktop); + QList services = KDesktopFileActions::userDefinedServices(actionUrl, true); + if (!services.isEmpty()) { + Plasma::DataEngine::Data action; + action.insert("predicate", desktop); + action.insert("text", services[0].text()); + action.insert("icon", services[0].icon()); + actions << action; + } + } + data.insert("actions", actions); + + data.insert("isEncryptedContainer", isEncryptedContainer); + + setData(device.udi(), data); + //kDebug() << "add hardware solid : " << udi; + } + +#ifdef HOTPLUGENGINE_TIMING + kDebug() << "total time" << t.restart(); +#endif +} + +void HotplugEngine::onDeviceRemoved(const QString &udi) +{ + //kDebug() << "remove hardware:" << udi; + + if (m_startList.contains(udi)) { + m_startList.remove(udi); + return; + } + + m_devices.remove(udi); + removeSource(udi); + scheduleSourcesUpdated(); +} + +K_EXPORT_PLASMA_DATAENGINE(hotplug, HotplugEngine) + +#include "hotplugengine.moc" diff --git a/plasma/generic/dataengines/hotplug/hotplugengine.h b/plasma/generic/dataengines/hotplug/hotplugengine.h new file mode 100644 index 00000000..8a90c9c3 --- /dev/null +++ b/plasma/generic/dataengines/hotplug/hotplugengine.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 Menard Alexis + * + * This program is free software you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * 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 HOTPLUGENGINE_H +#define HOTPLUGENGINE_H + +#include + +#include +#include + +#include + +class KDirWatch; + +/** + * This class is connected with solid, filter devices and provide signal with source for applet in Plasma + */ +class HotplugEngine : public Plasma::DataEngine +{ + Q_OBJECT + + public: + HotplugEngine( QObject* parent, const QVariantList& args); + ~HotplugEngine(); + void init(); + Plasma::Service* serviceForSource(const QString& source); + + protected Q_SLOTS: + void onDeviceAdded(const QString &udi); + void onDeviceRemoved(const QString &udi); + + private: + void onDeviceAdded(Solid::Device &dev, bool added = true); + void findPredicates(); + QStringList predicatesForDevice(Solid::Device &device) const; + + private Q_SLOTS: + void processNextStartupDevice(); + void updatePredicates(const QString &path); + + private: + QHash m_predicates; + QHash m_startList; + QHash m_devices; + Solid::Predicate m_encryptedPredicate; + KDirWatch *m_dirWatch; +}; + +#endif diff --git a/plasma/generic/dataengines/hotplug/hotplugjob.cpp b/plasma/generic/dataengines/hotplug/hotplugjob.cpp new file mode 100644 index 00000000..b92afb88 --- /dev/null +++ b/plasma/generic/dataengines/hotplug/hotplugjob.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 Viranch Mehta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "hotplugjob.h" +#include "hotplugengine.h" + +#include +#include + +#include + +void HotplugJob::start() +{ + QString udi (m_dest); + QString operation = operationName(); + + if (operation == "invokeAction") { + QString action = parameters()["predicate"].toString(); + + QStringList desktopFiles; + desktopFiles << action; + QDBusInterface soliduiserver("org.kde.kded", "/modules/soliduiserver", "org.kde.SolidUiServer"); + QDBusReply reply = soliduiserver.call("showActionsDialog", udi, desktopFiles); + } + + emitResult(); +} + +#include "hotplugjob.moc" + diff --git a/plasma/generic/dataengines/hotplug/hotplugjob.h b/plasma/generic/dataengines/hotplug/hotplugjob.h new file mode 100644 index 00000000..64f10354 --- /dev/null +++ b/plasma/generic/dataengines/hotplug/hotplugjob.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Viranch Mehta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef HOTPLUG_JOB_H +#define HOTPLUG_JOB_H + +#include "hotplugengine.h" + +#include + +class HotplugJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + HotplugJob (HotplugEngine* engine, + const QString& destination, + const QString& operation, + QMap& parameters, + QObject* parent = 0) + : ServiceJob (destination, operation, parameters, parent), + m_engine (engine), + m_dest (destination) + { + } + + void start(); + +private: + HotplugEngine* m_engine; + QString m_dest; +}; + +#endif // HOTPLUG_JOB_H + diff --git a/plasma/generic/dataengines/hotplug/hotplugservice.cpp b/plasma/generic/dataengines/hotplug/hotplugservice.cpp new file mode 100644 index 00000000..df7d199a --- /dev/null +++ b/plasma/generic/dataengines/hotplug/hotplugservice.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 Viranch Mehta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "hotplugservice.h" +#include "hotplugjob.h" +#include "hotplugengine.h" + +HotplugService::HotplugService (HotplugEngine* parent, const QString& source) + : Plasma::Service (parent), + m_engine(parent) +{ + setName ("hotplug"); + setDestination (source); +} + +Plasma::ServiceJob* HotplugService::createJob (const QString& operation, + QMap & parameters) +{ + return new HotplugJob (m_engine, destination(), operation, parameters, this); +} + +#include "hotplugservice.moc" + diff --git a/plasma/generic/dataengines/hotplug/hotplugservice.h b/plasma/generic/dataengines/hotplug/hotplugservice.h new file mode 100644 index 00000000..e02a6539 --- /dev/null +++ b/plasma/generic/dataengines/hotplug/hotplugservice.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Viranch Mehta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef HOTPLUG_SERVICE_H +#define HOTPLUG_SERVICE_H + +#include + +class HotplugEngine; + +class HotplugService : public Plasma::Service +{ + Q_OBJECT + +public: + HotplugService (HotplugEngine* parent, const QString& source); + +protected: + Plasma::ServiceJob* createJob (const QString& operation, + QMap& parameters); + +private: + HotplugEngine *m_engine; + QString m_dest; +}; + +#endif // HOTPLUG_SERVICE_H + diff --git a/plasma/generic/dataengines/hotplug/plasma-dataengine-hotplug.desktop b/plasma/generic/dataengines/hotplug/plasma-dataengine-hotplug.desktop new file mode 100644 index 00000000..0d0024ab --- /dev/null +++ b/plasma/generic/dataengines/hotplug/plasma-dataengine-hotplug.desktop @@ -0,0 +1,146 @@ +[Desktop Entry] +Name=Hotplug Events +Name[ar]=أحداث التوصيل +Name[ast]=Eventos en caliente +Name[be@latin]=Źjaŭleńnie novych pryładaŭ +Name[bn]=হট-প্লাগ ঘটনাবলী +Name[bs]=događaji vrućeg uključivanja +Name[ca]=Esdeveniments de connexió en calent +Name[ca@valencia]=Esdeveniments de connexió en calent +Name[cs]=Události hotplugu +Name[csb]=Hotplug Event +Name[da]=Hotplug-begivenheder +Name[de]=Hotplug-Ereignisse +Name[el]=Γεγονότα Hotplug +Name[en_GB]=Hotplug Events +Name[eo]=Dumkura permuteblaj eventoj +Name[es]=Eventos en caliente +Name[et]=Hotplug-sündmused +Name[eu]=Hotplug gertaerak +Name[fi]=Hotplug-tapahtumat +Name[fr]=Événements de branchement à chaud +Name[fy]=Hotplug barren +Name[ga]=Imeachtaí Hotplug +Name[gl]=Acontecementos de Hotplug +Name[gu]=હોટપ્લગ ઇવેન્ટ્સ +Name[he]=אירועי חיבור התקנים נשלפים +Name[hi]=हाटप्लग घटनाएँ +Name[hne]=हाटप्लग घटना +Name[hr]=Događaji brzog uštekavanja +Name[hu]=Eszközcsatolást kezelő plazmoid +Name[ia]=Eventos de hotplug +Name[id]=Acara Hotplug +Name[is]=Hraðtengingaatburðir +Name[it]=Eventi di collegamento in marcia +Name[ja]=Hotplug イベント +Name[kk]=Істеп турғанда қосу оқиғалар +Name[km]=ព្រឹត្តិការណ៍​ដោត​ដើរ +Name[kn]=Hotplug ಘಟನೆಗಳು (ಈವೆಂಟ್) +Name[ko]=핫플러그 이벤트 +Name[lt]=Hotplug įvykiai +Name[lv]=Hotplug notikumi +Name[ml]=ഹോട്ട്പ്ലഗ് സംഭവങ്ങള്‍ +Name[mr]=हॉटप्लग घटना +Name[nb]=Tilkoblingshendelser +Name[nds]=Tokoppel-Begeefnissen +Name[nl]=Hotplug-gebeurtenissen +Name[nn]=Hotplug-hendingar +Name[pa]=ਹਾਟਪਲੱਗ ਈਵੈਂਟ +Name[pl]=Zdarzenia podłączenia "na gorąco" +Name[pt]=Eventos do Hotplug +Name[pt_BR]=Eventos do hotplug +Name[ro]=Evenimente de atașare +Name[ru]=Уведомление о подключении устройств +Name[si]=හොට් ප්ලග් අවස්ථා +Name[sk]=Hotplug udalosti +Name[sl]=Priključitve +Name[sr]=догађаји врућег укључивања +Name[sr@ijekavian]=догађаји врућег укључивања +Name[sr@ijekavianlatin]=događaji vrućeg uključivanja +Name[sr@latin]=događaji vrućeg uključivanja +Name[sv]=Inkopplingshändelser +Name[ta]=Hotplug Events +Name[tg]=Дастгоҳҳои пайвастшаванда +Name[th]=เหตุการณ์อุปกรณ์ Hot Plug +Name[tr]=Tak Kullan Olayları +Name[ug]=قىزىق قىستۇرۇش ھادىسىسى +Name[uk]=Події гарячого підключення +Name[vi]=Các sự kiện tháo lắp nóng +Name[wa]=Evenmints tchôd-tchôkîs +Name[x-test]=xxHotplug Eventsxx +Name[zh_CN]=热插拔事件 +Name[zh_TW]=熱插拔事件 +Comment=Tracks hot-pluggable devices as they appear and disappear. +Comment[ar]=تتابع الأجهزة المركبة عندما تظهر أو تختفي +Comment[ast]=Rexistra los preseos estrayibles cuando apaecen y desapaecen. +Comment[bs]=Prati pojavljivanja i nestanke vruće uklonjivih uređaja. +Comment[ca]=Segueix els dispositius de connexió en calent quan apareixen i desapareixen. +Comment[ca@valencia]=Segueix els dispositius de connexió en calent quan apareixen i desapareixen. +Comment[cs]=Oznamovat připojení a odpojení za běhu připojitelných zařízení +Comment[da]=Holder styr på flytbare enheder efterhånden som de dukker op og forsvinder. +Comment[de]=Überwacht Hotplug-Geräte auf Aktivierung und Deaktivierung +Comment[el]=Ανίχνευση συσκευών hot-plug καθώς εμφανίζονται και εξαφανίζονται. +Comment[en_GB]=Tracks hot-pluggable devices as they appear and disappear. +Comment[es]=Registra los dispositivos extraíbles cuando aparecen y desaparecen. +Comment[et]=Töö ajal ühendatavate seadmete ilmumise ja kadumise jälgimine. +Comment[eu]=Martxan konekta daitezkeen gailuen jarraipena egiten du agertu eta desagertzen diren heinean. +Comment[fi]=Jäljittää lennosta kytkeytyviä laitteita kun ne ilmaantuvat ja katoavat. +Comment[fr]=Surveille l'apparition ou la disparition des périphériques pouvant être connectés à chaud. +Comment[fy]=Hâld hot-pluggeble aparaten yn de gaten as se ferskine of ferside gean. +Comment[gl]=Segue a pista dos dispositivos conectábeis en quente á medida que van aparecendo e desaparecendo. +Comment[he]=משמש למעקב אחר התקנים נשלפים בעת חיבורם וניתוקם. +Comment[hr]=Pratite uređaje za brzo uštekavanje kako se pojavljuju i nestaju +Comment[hu]=Követi a menet közben csatolható (hot-pluggable) eszközöket. +Comment[ia]=Il tracia dispositivos hot-pluggable (insertabile a calide) assi como illos appare e disappare +Comment[id]=Lacak divais hot-plug ketika mereka muncul atau menghilang. +Comment[is]=Fylgist með hraðtengdum tækjum um leið og þau birtast eða hverfa. +Comment[it]=Sorveglia il collegamento e lo scollegamento dei dispositivi collegabili mentre il sistema è in funzione. +Comment[ja]=ホットプラグ可能なデバイスが抜き差しされるのを捕捉します。 +Comment[kk]=Істеп турғанда қосылатын құрылғылардың қосылғанын/ажыратылғанын бақылау. +Comment[km]=តាមដាន​ឧបករណ៍​ដែល​អាច​ដោត​ដើរ​ដូច​ពួកវា​បង្ហាញ និង​មិន​បង្ហាញ ។ +Comment[kn]=ಹಾಟ್‌-ಪ್ಲಗ್‌ ಮಾಡಬಹುದಾದಂತಹ ಸಾಧನಗಳು ಕಾಣಿಸಿಕೊಂಡಾಗ ಹಾಗು ಅಡಗಿಸಿದಾಗ ಅವುಗಳ ಜಾಡನ್ನು ಇರಿಸುತ್ತದೆ. +Comment[ko]=장치가 연결되고 해제될 때 기록합니다. +Comment[lt]=Seka įrenginių prijungimą ir atjungimą. +Comment[lv]=Seko līdzi noņemamo ierīču pieslēgšanai un atvienošanai. +Comment[ml]=കമ്പ്യൂട്ടര്‍ പ്രവര്‍ത്തിച്ചു് കൊണ്ടിരിക്കുമ്പോള്‍ കുത്താവുന്ന ഉപകരണങ്ങള്‍ പ്രത്യക്ഷപ്പെടുന്നതും അപ്രത്യക്ഷമാകുന്നതും നിരീക്ഷിക്കുന്നു. +Comment[mr]=हॉटप्लग करता येणाऱ्या साधनांवर लक्ष ठेवतो. +Comment[nb]=Sporer enheter som kan kobles til og fra ettersom de dukker opp og forsvinner +Comment[nds]=Luert op Reedschappen, de sik hitt tokoppeln laat +Comment[nl]=Volgt inplugbare apparaten als deze verschijnen en verdwijnen. +Comment[nn]=Sporar hotplug-einingar når dei dukkar opp og forsvinn. +Comment[pa]=ਹਾਟ-ਪਲੱਗਯੋਗ ਜੰਤਰ ਜਾਣਕਾਰੀ, ਜਿਵੇਂ ਉਹ ਲਗਾਏ ਤੇ ਹਟਾਏ ਜਾਣਗੇ। +Comment[pl]=Śledzenie urządzeń podłączanych "na gorąco", przy ich pojawianiu i znikaniu. +Comment[pt]=Segue os dispositivos removíveis, à medida que aparecem e desaparecem. +Comment[pt_BR]=Segue os dispositivos removíveis, à medida que aparecem e desaparecem. +Comment[ro]=Urmărește dispozitivele detașabile după cum apar sau dispar. +Comment[ru]=Следит за появлением и исчезновением подключаемых на лету устройств. +Comment[si]=හොට්-ප්ලග් කල හැකි උපකරණ ඒවා පෙනෙන හා නොපෙනෙන විට හඳුනාගන්න +Comment[sk]=Sleduje hot-plug zariadenia pri ich zobrazení a zmiznutí. +Comment[sl]=Sledi odstranljivim napravam, ki se pojavljajo in izginjajo. +Comment[sr]=Прати појављивања и нестанке вруће уклоњивих уређаја. +Comment[sr@ijekavian]=Прати појављивања и нестанке вруће уклоњивих уређаја. +Comment[sr@ijekavianlatin]=Prati pojavljivanja i nestanke vruće uklonjivih uređaja. +Comment[sr@latin]=Prati pojavljivanja i nestanke vruće uklonjivih uređaja. +Comment[sv]=Följer enheter som kan kopplas in under spänning när de dyker upp och försvinner. +Comment[th]=ติดตามการตรวจพบ/ไม่พบ อุปกรณ์ประเภทถอด/เสียบได้ +Comment[tr]=Takıldıklarında ve çıkarıldıklarında tak kullan aygıtlarını izler. +Comment[ug]=قىزىق قىستۇرۇلىدىغان ئۈسكۈنىلەرنىڭ ھاسىل بولۇشى ۋە يوقىلىشىنى ئىزلايدۇ. +Comment[uk]=Стежить за з’єднанням і від’єднанням портативних пристроїв. +Comment[wa]=Shût les édjins tchôd-tchôcåves cwand il aparexhèt et disparexhèt. +Comment[x-test]=xxTracks hot-pluggable devices as they appear and disappear.xx +Comment[zh_CN]=跟踪热插拔设备的产生与消失。 +Comment[zh_TW]=追蹤熱插拔裝置的插入與拔除。 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=drive-removable-media-usb +X-KDE-Library=plasma_engine_hotplug + +X-KDE-PluginInfo-Author=The Plasma Team +X-KDE-PluginInfo-Email=wilderkde@gmail.com +X-KDE-PluginInfo-Name=hotplug +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License= + diff --git a/plasma/generic/dataengines/keystate/CMakeLists.txt b/plasma/generic/dataengines/keystate/CMakeLists.txt new file mode 100644 index 00000000..3f921737 --- /dev/null +++ b/plasma/generic/dataengines/keystate/CMakeLists.txt @@ -0,0 +1,12 @@ +set(keystate_engine_SRCS + keystate.cpp + keyservice.cpp +) + +kde4_add_plugin(plasma_engine_keystate ${keystate_engine_SRCS}) +target_link_libraries(plasma_engine_keystate ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS}) + +install(TARGETS plasma_engine_keystate DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-keystate.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install(FILES modifierkeystate.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + diff --git a/plasma/generic/dataengines/keystate/Messages.sh b/plasma/generic/dataengines/keystate/Messages.sh new file mode 100755 index 00000000..0c9356c3 --- /dev/null +++ b/plasma/generic/dataengines/keystate/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT `find . -name \*.cpp` -o $podir/plasma_engine_keystate.pot diff --git a/plasma/generic/dataengines/keystate/keyservice.cpp b/plasma/generic/dataengines/keystate/keyservice.cpp new file mode 100644 index 00000000..dec8d3a1 --- /dev/null +++ b/plasma/generic/dataengines/keystate/keyservice.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2009 Aaron Seigo + * + * 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 + * This library is free software; you can redistribute it and/or + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "keyservice.h" + +#include + +KeyService::KeyService(QObject* parent, KModifierKeyInfo *keyInfo, Qt::Key key) + : Plasma::Service(parent), + m_keyInfo(keyInfo), + m_key(key) +{ + setName("modifierkeystate"); + setDestination("keys"); +} + +Plasma::ServiceJob* KeyService::createJob(const QString& operation, QMap& parameters) +{ + if (operation == "Lock") { + return new LockKeyJob(this, parameters); + } else if (operation == "Latch") { + return new LatchKeyJob(this, parameters); + } + + return 0; +} + +void KeyService::lock(bool lock) +{ + m_keyInfo->setKeyLocked(m_key, lock); +} + +void KeyService::latch(bool lock) +{ + m_keyInfo->setKeyLatched(m_key, lock); +} + +LockKeyJob::LockKeyJob(KeyService *service, const QMap ¶meters) + : Plasma::ServiceJob(service->destination(), "Lock", parameters, service), + m_service(service) +{ +} + +void LockKeyJob::start() +{ + m_service->lock(parameters().value("Lock").toBool()); + setResult(true); +} + +LatchKeyJob::LatchKeyJob(KeyService *service, const QMap ¶meters) + : Plasma::ServiceJob(service->destination(), "Lock", parameters, service), + m_service(service) +{ +} + +void LatchKeyJob::start() +{ + m_service->latch(parameters().value("Lock").toBool()); + setResult(true); +} + +#include "keyservice.moc" + +// vim: sw=4 sts=4 et tw=100 diff --git a/plasma/generic/dataengines/keystate/keyservice.h b/plasma/generic/dataengines/keystate/keyservice.h new file mode 100644 index 00000000..c6a0a1b1 --- /dev/null +++ b/plasma/generic/dataengines/keystate/keyservice.h @@ -0,0 +1,69 @@ +/* + * Copyright 2009 Aaron Seigo aseigo@kde.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef KEYSERVICE_H +#define KEYSERVICE_H + +#include +#include + +class KModifierKeyInfo; + +class KeyService : public Plasma::Service +{ + Q_OBJECT + +public: + KeyService(QObject* parent, KModifierKeyInfo *keyInfo, Qt::Key key); + void lock(bool lock); + void latch(bool lock); + +protected: + Plasma::ServiceJob* createJob(const QString& operation, QMap& parameters); + +private: + KModifierKeyInfo *m_keyInfo; + Qt::Key m_key; +}; + +class LockKeyJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + LockKeyJob(KeyService *service, const QMap ¶meters); + void start(); + +private: + KeyService *m_service; +}; + +class LatchKeyJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + LatchKeyJob(KeyService *service, const QMap ¶meters); + void start(); + +private: + KeyService *m_service; +}; + +#endif // KEYSERVICE_H diff --git a/plasma/generic/dataengines/keystate/keystate.cpp b/plasma/generic/dataengines/keystate/keystate.cpp new file mode 100644 index 00000000..99bdd760 --- /dev/null +++ b/plasma/generic/dataengines/keystate/keystate.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2009 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "keystate.h" + + +#include +#include "keyservice.h" + +KeyStatesEngine::KeyStatesEngine(QObject *parent, const QVariantList &args) + : Plasma::DataEngine(parent, args) +{ + m_mods.insert(Qt::Key_Shift, I18N_NOOP("Shift")); + m_mods.insert(Qt::Key_Control, I18N_NOOP("Ctrl")); + m_mods.insert(Qt::Key_Alt, I18N_NOOP("Alt")); + m_mods.insert(Qt::Key_Meta, I18N_NOOP("Meta")); + m_mods.insert(Qt::Key_Super_L, I18N_NOOP("Super")); + m_mods.insert(Qt::Key_Hyper_L, I18N_NOOP("Hyper")); + m_mods.insert(Qt::Key_AltGr, I18N_NOOP("AltGr")); + m_mods.insert(Qt::Key_NumLock, I18N_NOOP("Num Lock")); + m_mods.insert(Qt::Key_CapsLock, I18N_NOOP("Caps Lock")); + m_mods.insert(Qt::Key_ScrollLock, I18N_NOOP("Scroll Lock")); + + m_buttons.insert(Qt::LeftButton, I18N_NOOP("Left Button")); + m_buttons.insert(Qt::RightButton, I18N_NOOP("Right Button")); + m_buttons.insert(Qt::MidButton, I18N_NOOP("Middle Button")); + m_buttons.insert(Qt::XButton1, I18N_NOOP("First X Button")); + m_buttons.insert(Qt::XButton2, I18N_NOOP("Second X Button")); +} + +KeyStatesEngine::~KeyStatesEngine() +{ +} + +void KeyStatesEngine::init() +{ + QMap::const_iterator it; + QMap::const_iterator end = m_mods.constEnd(); + for (it = m_mods.constBegin(); it != end; ++it) { + if (m_keyInfo.knowsKey(it.key())) { + Data data; + data.insert(I18N_NOOP("Pressed"), m_keyInfo.isKeyPressed(it.key())); + data.insert(I18N_NOOP("Latched"), m_keyInfo.isKeyLatched(it.key())); + data.insert(I18N_NOOP("Locked"), m_keyInfo.isKeyLocked(it.key())); + setData(it.value(), data); + } + } + + QMap::const_iterator it2; + QMap::const_iterator end2 = m_buttons.constEnd(); + for (it2 = m_buttons.constBegin(); it2 != end2; ++it2) { + Data data; + data.insert(I18N_NOOP("Pressed"), m_keyInfo.isButtonPressed(it2.key())); + setData(it2.value(), data); + } + + connect(&m_keyInfo, SIGNAL(keyPressed(Qt::Key,bool)), this, SLOT(keyPressed(Qt::Key,bool))); + connect(&m_keyInfo, SIGNAL(keyLatched(Qt::Key,bool)), this, SLOT(keyLatched(Qt::Key,bool))); + connect(&m_keyInfo, SIGNAL(keyLocked(Qt::Key,bool)), this, SLOT(keyLocked(Qt::Key,bool))); + connect(&m_keyInfo, SIGNAL(buttonPressed(Qt::MouseButton,bool)), + this, SLOT(mouseButtonPressed(Qt::MouseButton,bool))); + connect(&m_keyInfo, SIGNAL(keyAdded(Qt::Key)), this, SLOT(keyAdded(Qt::Key))); + connect(&m_keyInfo, SIGNAL(keyRemoved(Qt::Key)), this, SLOT(keyRemoved(Qt::Key))); +} + +Plasma::Service *KeyStatesEngine::serviceForSource(const QString &source) +{ + QMap::const_iterator it; + QMap::const_iterator end = m_mods.constEnd(); + for (it = m_mods.constBegin(); it != end; ++it) { + if (it.value() == source) { + return new KeyService(this, &m_keyInfo, it.key()); + } + } + + return Plasma::DataEngine::serviceForSource(source); +} + +void KeyStatesEngine::keyPressed(Qt::Key key, bool state) +{ + if (m_mods.contains(key)) { + setData(m_mods.value(key), I18N_NOOP("Pressed"), state); + } +} + +void KeyStatesEngine::keyLatched(Qt::Key key, bool state) +{ + if (m_mods.contains(key)) { + setData(m_mods.value(key), I18N_NOOP("Latched"), state); + } +} + +void KeyStatesEngine::keyLocked(Qt::Key key, bool state) +{ + if (m_mods.contains(key)) { + setData(m_mods.value(key), I18N_NOOP("Locked"), state); + } +} + +void KeyStatesEngine::mouseButtonPressed(Qt::MouseButton button, bool state) +{ + if (m_buttons.contains(button)) { + setData(m_buttons.value(button), I18N_NOOP("Pressed"), state); + } +} + +void KeyStatesEngine::keyAdded(Qt::Key key) +{ + if (m_mods.contains(key)) { + Data data; + data.insert(I18N_NOOP("Pressed"), m_keyInfo.isKeyPressed(key)); + data.insert(I18N_NOOP("Latched"), m_keyInfo.isKeyLatched(key)); + data.insert(I18N_NOOP("Locked"), m_keyInfo.isKeyLocked(key)); + setData(m_mods.value(key), data); + } +} + +void KeyStatesEngine::keyRemoved(Qt::Key key) +{ + if (m_mods.contains(key)) { + removeSource(m_mods.value(key)); + } +} + +K_EXPORT_PLASMA_DATAENGINE(keystate, KeyStatesEngine) + +#include "keystate.moc" diff --git a/plasma/generic/dataengines/keystate/keystate.h b/plasma/generic/dataengines/keystate/keystate.h new file mode 100644 index 00000000..f1ab1433 --- /dev/null +++ b/plasma/generic/dataengines/keystate/keystate.h @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KEYSTATEENGINE_H +#define KEYSTATEENGINE_H + +#include + +#include + +/** + * This engine provides the current state of the keyboard modifiers + * and mouse buttons, primarily useful for accessibility feature support. + */ +class KeyStatesEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + KeyStatesEngine(QObject *parent, const QVariantList &args); + ~KeyStatesEngine(); + + void init(); + Plasma::Service *serviceForSource(const QString &source); + +protected: + //bool sourceRequestEvent(const QString &name); + //bool updateSourceEvent(const QString &source); + +protected Q_SLOTS: + void keyPressed(Qt::Key key, bool state); + void keyLatched(Qt::Key key, bool state); + void keyLocked(Qt::Key key, bool state); + void mouseButtonPressed(Qt::MouseButton button, bool state); + void keyAdded(Qt::Key key); + void keyRemoved(Qt::Key key); + +private: + KModifierKeyInfo m_keyInfo; + QMap m_mods; + QMap m_buttons; +}; + +#endif // KEYSTATEENGINE_H diff --git a/plasma/generic/dataengines/keystate/modifierkeystate.operations b/plasma/generic/dataengines/keystate/modifierkeystate.operations new file mode 100644 index 00000000..492ef4e0 --- /dev/null +++ b/plasma/generic/dataengines/keystate/modifierkeystate.operations @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/keystate/plasma-dataengine-keystate.desktop b/plasma/generic/dataengines/keystate/plasma-dataengine-keystate.desktop new file mode 100644 index 00000000..7a36af1f --- /dev/null +++ b/plasma/generic/dataengines/keystate/plasma-dataengine-keystate.desktop @@ -0,0 +1,148 @@ +[Desktop Entry] +Name=Keyboard and Mouse State +Name[ar]=حالة لوحة المفاتيح والفأرة +Name[ast]=Estáu del tecláu y del mur +Name[bg]=Състояние на клавиатура и мишка +Name[bn]=কীবোর্ড ও মাউস অবস্থা +Name[bs]=stanje tastature i miša +Name[ca]=Estat del teclat i ratolí +Name[ca@valencia]=Estat del teclat i ratolí +Name[cs]=Stav klávesnice a myši +Name[csb]=Stón klawiaturë ë mëszë +Name[da]=Tilstand for tastatur og mus +Name[de]=Status von Tastatur und Maus +Name[el]=Κατάσταση πληκτρολογίου και ποντικιού +Name[en_GB]=Keyboard and Mouse State +Name[eo]=Stato de klavaro kaj muso +Name[es]=Estado del teclado y del ratón +Name[et]=Klaviatuuri ja hiire olek +Name[eu]=Teklatuaren eta saguaren egoera +Name[fi]=Näppäimistön ja hiiren tila +Name[fr]=États du clavier et de la souris +Name[fy]=Toetseboerd en mûs tastân +Name[ga]=Staid an Mhéarchláir agus na Luiche +Name[gl]=Estado do teclado e do rato +Name[gu]=કીબોર્ડ અને માઉસ સ્થિતિ +Name[he]=מצב מקלדת ועכבר +Name[hi]=कुंजीपट व माउस स्थिति +Name[hr]=Stanje tipkovnice i miša +Name[hu]=Egér- és billentyűzetállapot-jelző +Name[ia]=Stato del mus e del claviero +Name[id]=Kondisi Papan Ketik dan Tetikus +Name[is]=Staða lyklaborðs og músar +Name[it]=Stato di tastiera e mouse +Name[ja]=キーボードとマウスの状態 +Name[kk]=Перенетақта мен тышқанның күй-жайы +Name[km]=ស្ថានភាព​ក្ដារចុច និង​កណ្ដុល +Name[kn]=ಕೀಲಿಮಣೆ ಮತ್ತು ಮೌಸ್‌ನ ಸ್ಥಿತಿ +Name[ko]=키보드와 마우스 상태 +Name[lt]=Klaviatūros ir pelės būklė +Name[lv]=Tastatūra un peles stāvoklis +Name[mk]=Состојба на тастатура и глушец +Name[ml]=കീബോര്‍ഡിന്റേയും മൌസിന്റേയും അവസ്ഥ +Name[mr]=कळफलक व माऊस स्थिती +Name[nb]=Tilstand for tastatur og mus +Name[nds]=Tastatuur- un Muus-Status +Name[nl]=Toetsenbord en muisstatus +Name[nn]=Status for tastatur og mus +Name[pa]=ਕੀ-ਬੋਰਡ ਅਤੇ ਮਾਊਂਸ ਹਾਲਤ +Name[pl]=Stan klawiatury i myszy +Name[pt]=Estado do Teclado e Rato +Name[pt_BR]=Estado do teclado e mouse +Name[ro]=Starea tastaturii și mausului +Name[ru]=Состояние клавиатуры и мыши +Name[si]=යතුරුපුවරුව සහ මවුස තත්වය +Name[sk]=Stav klávesnice a myši +Name[sl]=Stanje tipkovnice in miške +Name[sr]=стање тастатуре и миша +Name[sr@ijekavian]=стање тастатуре и миша +Name[sr@ijekavianlatin]=stanje tastature i miša +Name[sr@latin]=stanje tastature i miša +Name[sv]=Tillstånd för tangentbord och mus +Name[tg]=Клавиатура ва муш +Name[th]=สถานะของแป้นพิมพ์และเมาส์ +Name[tr]=Klavye ve Fare Durumu +Name[ug]=ھەرپتاختا ۋە چاشقىنەك ھالىتى +Name[uk]=Стан клавіатури і миші +Name[vi]=Bàn phím và trạng thái chuột +Name[wa]=Estat del taprece et del sori +Name[x-test]=xxKeyboard and Mouse Statexx +Name[zh_CN]=键盘和鼠标状态 +Name[zh_TW]=鍵盤與滑鼠狀態 +Comment=Keyboard modifier and mouse buttons states +Comment[ar]=حالة أزرار الفأرة و مغيرات لوحة المفاتيح +Comment[ast]=Estáu del modificador de tecláu y botones del mur +Comment[bg]=Състояние на клавиатурни модификатори и бутони на мишката +Comment[bs]=Stanja modifikatora na tastaturi i dugmadi miša +Comment[ca]=Modificador de l'estat del teclat i dels botons del ratolí +Comment[ca@valencia]=Modificador de l'estat del teclat i dels botons del ratolí +Comment[cs]=Stavy modifikátorů klávesnice a tlačítek myši +Comment[csb]=Mòdifikatora klawiaturë ë stónu klawiszów mëszë +Comment[da]=Tilstand for tastaturets ændringstaster og museknapper +Comment[de]=Status von Modifizierer- und Maustasten +Comment[el]=Τροποποιητής πληκτρολογίου και κατάστασης κουμπιών ποντικιού +Comment[en_GB]=Keyboard modifier and mouse buttons states +Comment[es]=Estado del modificador de teclado y botones del ratón +Comment[et]=Klaviatuuri muuteklahvide ja hiirenuppude olekud +Comment[eu]=Teklatuaren aldatzailearen eta saguaren botoien egoerak +Comment[fi]=Näppäimistömääre ja hiiren painikkeiden tilat +Comment[fr]=Modificateur du clavier et des états des boutons de souris +Comment[fy]=Toetseboerd bewurker en mûsknop tastân +Comment[gl]=Estados das modificadoras do teclado e dos botóns do rato +Comment[he]=המצב של לחצני מקלדת משני מצב ולחצני עכבר +Comment[hr]=Stanja tipaka ctrl, alt, shift i tipaka miša +Comment[hu]=Módosítóbillentyűk és egérgombok +Comment[ia]=Modificator de claviero e statos de buttones del mus +Comment[id]=Pengubah pepan ketik dan kondisi tombol tetikus +Comment[is]=Breytingar á lyklaborði og músarhnöppum +Comment[it]=Stati dei modificatori della tastiera e dei pulsanti del mouse +Comment[ja]=キーボードの修飾キーとマウスボタンの状態 +Comment[kk]=Перенетақта түрлендіргіш және тышқан батырмаларының күй-жайы +Comment[km]=កម្មវិធី​កែប្រែ​ក្ដារចុច និង​ស្ថានភាព​ប៊ូតុង​កណ្ដុរ +Comment[kn]=ಕೀಲಿಮಣೆ ಮಾರ್ಪಡಕ ಹಾಗು ಮೌಸ್ ಗುಂಡಿಗಳ ಸ್ಥಿತಿಗಳು +Comment[ko]=키보드 수정자 키 및 마우스 단추 상태 +Comment[lt]=Klaviatūros būsenos ir pelės mygtukų būsenos stebėklis +Comment[lv]=Tastatūras modifikatoru un peles pogu stāvoklis +Comment[ml]=കീബോര്‍ഡ് മോഡിഫയറിന്റേയും മൌസ് ബട്ടണിന്റെയും സ്ഥിതി +Comment[mr]=कळफलक परिवर्तक व माऊस बटन स्थिती +Comment[nb]=Tilstand for modifikatortaster og museknapper +Comment[nds]=Sünnertasten- un Muusknoop-Tostänn +Comment[nl]=Wijzigt toetsenbord en muisknoptoestanden +Comment[nn]=Status for valtastar og museknappar +Comment[pa]=ਕੀਬੋਰਡ ਸੋਧਕ ਅਤੇ ਮਾਊਂਸ ਬਟਨ ਹਾਲਤ +Comment[pl]=Stany modyfikatorów klawiatury i przycisków myszy +Comment[pt]=Estados das teclas modificadoras e dos botões do rato +Comment[pt_BR]=Estados do modificador de teclado e botões do mouse +Comment[ro]=Stările modificatorului de tastatură și a butoanelor mausului +Comment[ru]=Состояния клавиш-модификаторов на клавиатуре и кнопок мыши +Comment[si]=යතුරුපුවරු වෙනස්කිරීම් හා මවුස බොත්තම් තත්ව +Comment[sk]=Stavy modifikátorov klávesnice a tlačidiel myši +Comment[sl]=Stanje spremenilnih tipk tipkovnice in tipk miške +Comment[sr]=Стања модификатора на тастатури и дугмади миша +Comment[sr@ijekavian]=Стања модификатора на тастатури и дугмади миша +Comment[sr@ijekavianlatin]=Stanja modifikatora na tastaturi i dugmadi miša +Comment[sr@latin]=Stanja modifikatora na tastaturi i dugmadi miša +Comment[sv]=Tillstånd för väljartangenter och musknappar +Comment[th]=สถานะปุ่มเปลี่ยนหน้าที่ของแป้นพิมพ์และสถานะปุ่มของเมาส์ +Comment[tr]=Farenin ve klavyenin değiştirici tuşlarının durumları +Comment[ug]=ھەرپتاختا ئۆزگىرىشى ۋە چاشقىنەك توپچا ھالىتى +Comment[uk]=Стан модифікаторів клавіатури і кнопок миші +Comment[wa]=Candjaedje el taprece eyet estat des botons del sori +Comment[x-test]=xxKeyboard modifier and mouse buttons statesxx +Comment[zh_CN]=显示键盘修饰健及鼠标按键状态 +Comment[zh_TW]=鍵盤變更鍵與滑鼠按鍵狀態 +Type=Service +Icon=input-keyboard + +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-Library=plasma_engine_keystate + +X-KDE-PluginInfo-Author=Aaron Seigo +X-KDE-PluginInfo-Email=aseigo@kde.org +X-KDE-PluginInfo-Name=keystate +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Accessibility +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/dataengines/metadata/CMakeLists.txt b/plasma/generic/dataengines/metadata/CMakeLists.txt new file mode 100644 index 00000000..38f33238 --- /dev/null +++ b/plasma/generic/dataengines/metadata/CMakeLists.txt @@ -0,0 +1,20 @@ +project(metadata) + +set(metadata_engine_SRCS metadata_engine.cpp) + +kde4_add_plugin(plasma_engine_metadata ${metadata_engine_SRCS}) + +include_directories(${SOPRANO_INCLUDE_DIR} ${NEPOMUK_CORE_INCLUDE_DIR}) + +target_link_libraries(plasma_engine_metadata + ${KDE4_KIO_LIBS} + ${KDE4_KDECORE_LIBS} + ${KDE4_PLASMA_LIBS} + ${NEPOMUK_CORE_LIBRARY} + ${SOPRANO_LIBRARIES} ) + +install(TARGETS plasma_engine_metadata + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-engine-metadata.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/dataengines/metadata/Messages.sh b/plasma/generic/dataengines/metadata/Messages.sh new file mode 100644 index 00000000..ff842825 --- /dev/null +++ b/plasma/generic/dataengines/metadata/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_metadata.pot diff --git a/plasma/generic/dataengines/metadata/metadata_engine.cpp b/plasma/generic/dataengines/metadata/metadata_engine.cpp new file mode 100644 index 00000000..2fc341c1 --- /dev/null +++ b/plasma/generic/dataengines/metadata/metadata_engine.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2009 Anne-Marie Mahfouf + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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 "metadata_engine.h" + +#include +#include + +#include + +// Nepomuk +#include +#include +#include + +MetaDataEngine::MetaDataEngine(QObject* parent, const QVariantList& args) : + Plasma::DataEngine(parent, args) +{ +} + +MetaDataEngine::~MetaDataEngine() +{ +} + +void MetaDataEngine::init() +{ + Nepomuk2::ResourceManager::instance()->init(); +} + +bool MetaDataEngine::sourceRequestEvent(const QString &name) +{ + updateSourceEvent(name); + return true; +} + +bool MetaDataEngine::updateSourceEvent(const QString &name) +{ + // Get picture general properties through KFileMetaInfo + const KFileMetaInfo::WhatFlags flags = KFileMetaInfo::Fastest | + KFileMetaInfo::TechnicalInfo | + KFileMetaInfo::ContentInfo; + const KFileMetaInfo fileMetaInfo(name, QString(), flags); + if (fileMetaInfo.isValid()) { + const QHash& items = fileMetaInfo.items(); + QHash::const_iterator it = items.constBegin(); + const QHash::const_iterator end = items.constEnd(); + QString labelText; + while (it != end) { + const KFileMetaInfoItem& metaInfoItem = it.value(); + const QVariant& value = metaInfoItem.value(); + + if (value.isValid() && convertMetaInfo(metaInfoItem.name(), labelText)) { + if (labelText == i18nc("@label", "Size")) { + const QString s = QString::number(value.toDouble()/1024/1024, 'f', 2); + setData(name, labelText, QString::fromLatin1("%1 Mb").arg(s)); + } else if (labelText == i18nc("@label", "Source Modified")) { + QVariant newValue = QVariant(value.toDateTime()); + setData(name, labelText, newValue.toString()); + } else { + setData(name, labelText, value.toString()); + } + } + + ++it; + } + } + + // Get picture tags through Nepomuk + QUrl uri = QUrl(name); + QStringList tags; + Nepomuk2::Resource res( uri); + QList picTags = res.tags(); + Q_FOREACH(const Nepomuk2::Tag& tag, picTags) { + tags.append(tag.label() + ", "); + } + + setData(name, "tags", tags); + // Get picture comment through Nepomuk + setData(name, "comment", res.description()); + // Get picture rating through Nepomuk + setData(name, "rating", QString::number(res.rating())); + + return true; +} + +bool MetaDataEngine::convertMetaInfo(const QString& key, QString& text) const +{ + struct MetaKey { + const char* key; + QString text; + }; + + // keys list, more can be added + static const MetaKey keys[] = { + { "http://freedesktop.org/standards/xesam/1.0/core#cameraModel", i18nc("@label", "Model") }, + { "http://freedesktop.org/standards/xesam/1.0/core#focalLength", i18nc("@label", "Focal Length") }, + { "http://freedesktop.org/standards/xesam/1.0/core#mimeType", i18nc("@label", "Mime Type") }, + { "http://freedesktop.org/standards/xesam/1.0/core#cameraManufacturer", i18nc("@label", "Manufacturer") }, + { "http://freedesktop.org/standards/xesam/1.0/core#sourceModified", i18nc("@label", "Source Modified") }, + { "http://freedesktop.org/standards/xesam/1.0/core#orientation", i18nc("@label", "Orientation") }, + { "http://freedesktop.org/standards/xesam/1.0/core#flashUsed", i18nc("@label", "Flash Used") }, + { "http://freedesktop.org/standards/xesam/1.0/core#height", i18nc("@label", "Height") }, + { "http://freedesktop.org/standards/xesam/1.0/core#width", i18nc("@label", "Width") }, + { "http://freedesktop.org/standards/xesam/1.0/core#url", i18nc("@label", "Url") }, + { "http://freedesktop.org/standards/xesam/1.0/core#size", i18nc("@label", "Size") }, + { "http://freedesktop.org/standards/xesam/1.0/core#aperture", i18nc("@label", "Aperture") }, + { "http://freedesktop.org/standards/xesam/1.0/core#meteringMode", i18nc("@label", "Metering Mode") }, + { "http://freedesktop.org/standards/xesam/1.0/core#35mmEquivalent", i18nc("@label", "35mm Equivalent") }, + { "http://freedesktop.org/standards/xesam/1.0/core#fileExtension", i18nc("@label", "File Extension") }, + { "http://freedesktop.org/standards/xesam/1.0/core#name", i18nc("@label", "Name") }, + { "http://freedesktop.org/standards/xesam/1.0/core#exposureTime", i18nc("@label", "Exposure Time") } + }; + + // search if the key exists and get its value + int top = 0; + int bottom = sizeof(keys) / sizeof(MetaKey) - 1; + while (top <= bottom) { + const int result = key.compare(keys[top].key); + if (result == 0) { + text = keys[top].text; + return true; + } + top++; + } + + return false; +} + +K_EXPORT_PLASMA_DATAENGINE(metadata, MetaDataEngine) + +#include "metadata_engine.moc" diff --git a/plasma/generic/dataengines/metadata/metadata_engine.h b/plasma/generic/dataengines/metadata/metadata_engine.h new file mode 100644 index 00000000..f7f1d394 --- /dev/null +++ b/plasma/generic/dataengines/metadata/metadata_engine.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Anne-Marie Mahfouf + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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 METADATA_ENGINE_H_ +#define METADATA_ENGINE_H_ + +#include + + +class MetaDataEngine: public Plasma::DataEngine +{ + Q_OBJECT + +public: + MetaDataEngine(QObject* parent, const QVariantList& args); + ~MetaDataEngine(); + +protected: + void init(); + bool sourceRequestEvent(const QString& name); + +protected slots: + bool updateSourceEvent(const QString& source); + +private: + /** + * Converts the meta key \a key to a readable format into \a text. + * Returns true, if the string \a key represents a meta information + * that should be shown. If false is returned, \a text is not modified. + */ + bool convertMetaInfo(const QString& key, QString& text) const; + +}; + +#endif /* METADATA_ENGINE_H_ */ diff --git a/plasma/generic/dataengines/metadata/plasma-engine-metadata.desktop b/plasma/generic/dataengines/metadata/plasma-engine-metadata.desktop new file mode 100644 index 00000000..625bdbe1 --- /dev/null +++ b/plasma/generic/dataengines/metadata/plasma-engine-metadata.desktop @@ -0,0 +1,85 @@ +[Desktop Entry] +Name=Meta Data +Name[ar]=البيانات الوصفية +Name[ast]=Metadatos +Name[bg]=Мета данни +Name[bs]=metapodaci +Name[ca]=Metadades +Name[ca@valencia]=Metadades +Name[cs]=Metadata +Name[csb]=Pòdôwczi meta +Name[da]=Metadata +Name[de]=Metadaten +Name[el]=Μεταδεδομένα +Name[en_GB]=Meta Data +Name[eo]=Metaj Datumoj +Name[es]=Metadatos +Name[et]=Metaandmed +Name[eu]=Metadatuak +Name[fi]=Metatieto +Name[fr]=Méta données +Name[fy]=Meta gegevens +Name[ga]=Meiteashonraí +Name[gl]=Metadatos +Name[gu]=મેટા માહિતી +Name[he]=מידע על פריט המידע (Meta Data) +Name[hi]=मेटा डॉटा +Name[hr]=Metapodaci +Name[hu]=Metaadatok +Name[ia]=Meta datos +Name[id]=Meta Data +Name[is]=Metagögn +Name[ja]=メタデータ +Name[ka]=მეტამონაცემები +Name[kk]=Метадеректер +Name[km]=ទិន្នន័យ​មេតា +Name[kn]=ಮೆಟಾ ಡೇಟಾ +Name[ko]=메타 데이터 +Name[lt]=Meda duomenys +Name[lv]=Metadati +Name[mai]=मेटा डाटा +Name[mk]=Мета-податоци +Name[ml]=മെറ്റാ ഡാറ്റാ +Name[mr]=मेटा डेटा +Name[nb]=Metadata +Name[nds]=Metadaten +Name[nl]=Metadata +Name[nn]=Metadata +Name[pa]=ਮੇਟਾ ਡਾਟਾ +Name[pl]=Metadane +Name[pt]=Meta-Dados +Name[pt_BR]=Metadados +Name[ro]=Metadate +Name[ru]=Метаданные +Name[si]=මෙටා දත්ත +Name[sk]=Metadáta +Name[sl]=Metapodatki +Name[sr]=метаподаци +Name[sr@ijekavian]=метаподаци +Name[sr@ijekavianlatin]=metapodaci +Name[sr@latin]=metapodaci +Name[sv]=Metadata +Name[tg]=Маълумоти Meta +Name[th]=ข้อมูลกำกับ +Name[tr]=Meta Data +Name[ug]=مېتا سانلىق-مەلۇمات +Name[uk]=Метадані +Name[wa]=Meta-dnêyes +Name[x-test]=xxMeta Dataxx +Name[zh_CN]=元数据 +Name[zh_TW]=中繼資料 +Type=Service +Icon=nepomuk +X-KDE-ServiceTypes=Plasma/DataEngine + +X-Plasma-EngineName=metadata +X-KDE-Library=plasma_engine_metadata +X-KDE-PluginInfo-Author=Anne-Marie Mahfouf +X-KDE-PluginInfo-Email=annma@kde.org +X-KDE-PluginInfo-Name=metadata +X-KDE-PluginInfo-Version=0.0.1 +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category=Utilities +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/dataengines/mouse/CMakeLists.txt b/plasma/generic/dataengines/mouse/CMakeLists.txt new file mode 100644 index 00000000..86d7accb --- /dev/null +++ b/plasma/generic/dataengines/mouse/CMakeLists.txt @@ -0,0 +1,19 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../../) + +set(mouse_engine_SRCS + mouseengine.cpp +) + +if (X11_Xfixes_FOUND) + set(mouse_engine_SRCS ${mouse_engine_SRCS} cursornotificationhandler.cpp) +endif (X11_Xfixes_FOUND) + +kde4_add_plugin(plasma_engine_mouse ${mouse_engine_SRCS}) +target_link_libraries(plasma_engine_mouse ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${X11_LIBRARIES}) +if (X11_Xfixes_FOUND) + target_link_libraries(plasma_engine_mouse ${X11_Xfixes_LIB}) +endif (X11_Xfixes_FOUND) + +install(TARGETS plasma_engine_mouse DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-mouse.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/plasma/generic/dataengines/mouse/cursornotificationhandler.cpp b/plasma/generic/dataengines/mouse/cursornotificationhandler.cpp new file mode 100644 index 00000000..3cb9add2 --- /dev/null +++ b/plasma/generic/dataengines/mouse/cursornotificationhandler.cpp @@ -0,0 +1,114 @@ +/* + * Copyright © 2007 Fredrik Höglund + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "cursornotificationhandler.h" + +#include + +#include +#include + + +/* + * This class is a QWidget because we need an X window to + * be able to receive XFixes events. We don't actually map + * the widget. + */ + +CursorNotificationHandler::CursorNotificationHandler() + : QWidget(), currentName(0) +{ + Display *dpy = QX11Info::display(); + int errorBase; + haveXfixes = false; + + // Request cursor change notification events + if (XFixesQueryExtension(dpy, &fixesEventBase, &errorBase)) + { + int major, minor; + XFixesQueryVersion(dpy, &major, &minor); + + if (major >= 2) + { + XFixesSelectCursorInput(dpy, winId(), XFixesDisplayCursorNotifyMask); + haveXfixes = true; + } + } +} + + +CursorNotificationHandler::~CursorNotificationHandler() +{ +} + + +QString CursorNotificationHandler::cursorName() +{ + if (!haveXfixes) + return QString(); + + if (!currentName) + { + // Xfixes doesn't have a request for getting the current cursor name, + // but it's included in the XFixesCursorImage struct. + XFixesCursorImage *image = XFixesGetCursorImage(QX11Info::display()); + currentName = image->atom; + XFree(image); + } + + return cursorName(currentName); +} + + +QString CursorNotificationHandler::cursorName(Atom cursor) +{ + QString name; + + // XGetAtomName() is a synchronous call, so we cache the name + // in an atom<->string map the first time we see a name + // to keep the X server round trips down. + if (names.contains(cursor)) + name = names[cursor]; + else + { + char *data = XGetAtomName(QX11Info::display(), cursor); + name = QString::fromUtf8(data); + XFree(data); + + names.insert(cursor, name); + } + + return name; +} + + +bool CursorNotificationHandler::x11Event(XEvent* event) +{ + if (event->type != fixesEventBase + XFixesCursorNotify) + return false; + + XFixesCursorNotifyEvent *xfe = reinterpret_cast(event); + currentName = xfe->cursor_name; + + emit cursorNameChanged(cursorName(currentName)); + + return false; +} + +#include "cursornotificationhandler.moc" + diff --git a/plasma/generic/dataengines/mouse/cursornotificationhandler.h b/plasma/generic/dataengines/mouse/cursornotificationhandler.h new file mode 100644 index 00000000..7b4d3eb7 --- /dev/null +++ b/plasma/generic/dataengines/mouse/cursornotificationhandler.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2007 Fredrik Höglund + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CURSORNOTIFICATIONHANDLER_H +#define CURSORNOTIFICATIONHANDLER_H + +#include +#include + +#include + +class CursorNotificationHandler : public QWidget +{ + Q_OBJECT + +public: + CursorNotificationHandler(); + ~CursorNotificationHandler(); + + QString cursorName(); + +signals: + void cursorNameChanged(const QString &name); + +protected: + bool x11Event(XEvent *); + +private: + QString cursorName(Atom cursor); + +private: + bool haveXfixes; + int fixesEventBase; + Atom currentName; + QMap names; +}; + +#endif diff --git a/plasma/generic/dataengines/mouse/mouseengine.cpp b/plasma/generic/dataengines/mouse/mouseengine.cpp new file mode 100644 index 00000000..19a7fb74 --- /dev/null +++ b/plasma/generic/dataengines/mouse/mouseengine.cpp @@ -0,0 +1,103 @@ +/* + * Copyright © 2007 Fredrik Höglund + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mouseengine.h" + +#include + +#ifdef HAVE_XFIXES +# include "cursornotificationhandler.h" +#endif + + +MouseEngine::MouseEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args), timerId(0) +#ifdef HAVE_XFIXES +, handler(0) +#endif +{ + Q_UNUSED(args) +} + + +MouseEngine::~MouseEngine() +{ + if (timerId) + killTimer(timerId); +#ifdef HAVE_XFIXES + delete handler; +#endif +} + + +QStringList MouseEngine::sources() const +{ + QStringList list; + + list << QLatin1String("Position"); +#ifdef HAVE_XFIXES + list << QLatin1String("Name"); +#endif + + return list; +} + + +void MouseEngine::init() +{ + if (!timerId) + timerId = startTimer(40); + + // Init cursor position + QPoint pos = QCursor::pos(); + setData(QLatin1String("Position"), QVariant(pos)); + lastPosition = pos; + +#ifdef HAVE_XFIXES + handler = new CursorNotificationHandler; + connect(handler, SIGNAL(cursorNameChanged(QString)), SLOT(updateCursorName(QString))); + + setData(QLatin1String("Name"), QVariant(handler->cursorName())); +#endif + + scheduleSourcesUpdated(); +} + + +void MouseEngine::timerEvent(QTimerEvent *) +{ + QPoint pos = QCursor::pos(); + + if (pos != lastPosition) + { + setData(QLatin1String("Position"), QVariant(pos)); + lastPosition = pos; + + scheduleSourcesUpdated(); + } +} + + +void MouseEngine::updateCursorName(const QString &name) +{ + setData(QLatin1String("Name"), QVariant(name)); + scheduleSourcesUpdated(); +} + +#include "mouseengine.moc" + diff --git a/plasma/generic/dataengines/mouse/mouseengine.h b/plasma/generic/dataengines/mouse/mouseengine.h new file mode 100644 index 00000000..095abe24 --- /dev/null +++ b/plasma/generic/dataengines/mouse/mouseengine.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2007 Fredrik Höglund + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MOUSEENGINE_H +#define MOUSEENGINE_H + +#include +#include + +#ifdef HAVE_XFIXES +class CursorNotificationHandler; +#endif + +class MouseEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + MouseEngine(QObject* parent, const QVariantList& args); + ~MouseEngine(); + + QStringList sources() const; + +protected: + void init(); + void timerEvent(QTimerEvent*); + +private slots: + void updateCursorName(const QString &name); + +private: + QPoint lastPosition; + int timerId; +#ifdef HAVE_XFIXES + CursorNotificationHandler *handler; +#endif +}; + +K_EXPORT_PLASMA_DATAENGINE(mouse, MouseEngine) + +#endif diff --git a/plasma/generic/dataengines/mouse/plasma-dataengine-mouse.desktop b/plasma/generic/dataengines/mouse/plasma-dataengine-mouse.desktop new file mode 100644 index 00000000..1ecafc68 --- /dev/null +++ b/plasma/generic/dataengines/mouse/plasma-dataengine-mouse.desktop @@ -0,0 +1,153 @@ +[Desktop Entry] +Name=Pointer Position +Name[ar]=موقع المؤشر +Name[ast]=Posición del punteru +Name[be@latin]=Miesca kursora +Name[bg]=Разположение на курсора +Name[bs]=položaj pokazivača +Name[ca]=Posició de l'apuntador +Name[ca@valencia]=Posició de l'apuntador +Name[cs]=Pozice ukazatele +Name[da]=Markørposition +Name[de]=Mausposition +Name[el]=Θέση δρομέα +Name[en_GB]=Pointer Position +Name[eo]=Pozicio de la Montrilo +Name[es]=Posición del puntero +Name[et]=Kursori asukoht +Name[eu]=Erakuslearen kokalekua +Name[fi]=Osoittimen sijainti +Name[fr]=Position du pointeur +Name[fy]=Mûsoanwizer posysje +Name[ga]=Ionad na Luiche +Name[gl]=Posición do rato +Name[gu]=દર્શક સ્થિતિ +Name[he]=מיקום סמן +Name[hi]=संकेतक स्थान +Name[hne]=पाइन्टर स्थिति +Name[hr]=Pozicija pokazivača miša +Name[hu]=Egérpozíció +Name[ia]=Position de punctator +Name[id]=Posisi Penunjuk +Name[is]=Staðsetning bendils +Name[it]=Posizione del puntatore +Name[ja]=マウスポインタの位置 +Name[kk]=Көрсеткіш орны +Name[km]=ទីតាំង​ទស្សន៍​ទ្រនិច +Name[kn]=ಸೂಚಿಯ ಸ್ಥಳ +Name[ko]=포인터 위치 +Name[lt]=Rodyklės pozicija +Name[lv]=Peles pozīcija +Name[mk]=Позиција на покажувач +Name[ml]=സൂചികയുടെ സ്ഥാനം +Name[mr]=पॉइन्टर स्थान +Name[nb]=Pekerposisjon +Name[nds]=Muuswieser-Steed +Name[nl]=Muisaanwijzerpositie +Name[nn]=Peikarplassering +Name[or]=ସୂଚକ ସ୍ଥାନ +Name[pa]=ਪੁਆਇੰਟਰ ਸਥਿਤੀ +Name[pl]=Pozycja kursora +Name[pt]=Posição do Cursor +Name[pt_BR]=Posição do ponteiro +Name[ro]=Poziție indicator +Name[ru]=Положение указателя мыши +Name[si]=ලක්‍ෂක ස්ථානය +Name[sk]=Pozícia kurzora +Name[sl]=Položaj kazalca +Name[sr]=положај показивача +Name[sr@ijekavian]=положај показивача +Name[sr@ijekavianlatin]=položaj pokazivača +Name[sr@latin]=položaj pokazivača +Name[sv]=Pekarposition +Name[ta]=Pointer Position +Name[te]=సూచకి స్థానము +Name[tg]=Положение указателя мыши +Name[th]=ตำแหน่งของตัวชี้ +Name[tr]=İşaretçi Konumu +Name[ug]=نۇربەلگە ئورنى +Name[uk]=Позиція вказівника +Name[wa]=Eplaeçmint do pwinteu +Name[x-test]=xxPointer Positionxx +Name[zh_CN]=指针位置 +Name[zh_TW]=指標位置 +Comment=Mouse position and cursor +Comment[ar]=موقع الفأرة و المؤشر +Comment[ast]=Posición del mur y cursor +Comment[bg]=Позиция на мишката и курсора +Comment[bs]=Položaj miša i pokazivača +Comment[ca]=Posició del ratolí i del cursor +Comment[ca@valencia]=Posició del ratolí i del cursor +Comment[cs]=Pozice myši a kurzoru +Comment[da]=Museposition og markør +Comment[de]=Mausposition und Mauszeiger +Comment[el]=Θέση ποντικιού και δρομέα +Comment[en_GB]=Mouse position and cursor +Comment[eo]=Pozicio de la muso kaj kursoro +Comment[es]=Posición del ratón y cursor +Comment[et]=Hiire asukoht ja kursor +Comment[eu]=Saguaren kokalekua eta kurtsorea +Comment[fi]=Hiiren sijainti ja kohdistin +Comment[fr]=Position et curseur de la souris +Comment[fy]=Mûsposysje en rinnerke +Comment[ga]=Suíomh na luiche agus an cúrsóir +Comment[gl]=Posición do rato e do cursor +Comment[gu]=માઉસ સ્થિતિ અને કર્સર +Comment[he]=מיקום עכבר וסמן +Comment[hr]=Pozicija miša i pokazivača miša +Comment[hu]=Egérmutató-pozíció +Comment[ia]=Position e cursor del mus +Comment[id]=Posisi tetikus dan kursor +Comment[is]=Staðsetning músar og bendils +Comment[it]=Posizione e cursore del mouse +Comment[ja]=マウスの位置とカーソル +Comment[kk]=Тышқанның орны және меңзері +Comment[km]=ទីតាំង និង​ទស្សន៍ទ្រនិច្ច​កណ្ដុរ +Comment[kn]=ಮೌಸ್‌ನ ಸ್ಥಾನ ಹಾಗು ತೆರೆಸೂಚಕ +Comment[ko]=마우스 위치와 커서 +Comment[lt]=Pelės pozicija ir kursorius +Comment[lv]=Peles pozīcija un kursors +Comment[mai]=माउसक स्थिति आओर कर्सर +Comment[mk]=Позиција и покажувач на глушецот +Comment[ml]=മൌസിന്റെ സ്ഥാനവും ചൂണ്ടിയും +Comment[mr]=माऊस स्थान व कर्सर +Comment[nb]=Museposisjon og markør +Comment[nds]=Muussteed un Blinker +Comment[nl]=Muispositie en cursor +Comment[nn]=Plassering av musa og peikaren +Comment[pa]=ਮਾਊਸ ਸਥਿਤੀ ਅਤੇ ਕਰਸਰ +Comment[pl]=Pozycja myszy i kursora +Comment[pt]=Posição e cursor do rato +Comment[pt_BR]=Posição do mouse e cursor +Comment[ro]=Poziția și cursorul mausului +Comment[ru]=Положение мыши и вид указателя +Comment[si]=මවුස ස්ථානය හා කර්සරය +Comment[sk]=Pozícia myši a kurzora +Comment[sl]=Položaj miškine kazalke +Comment[sr]=Положај миша и показивач +Comment[sr@ijekavian]=Положај миша и показивач +Comment[sr@ijekavianlatin]=Položaj miša i pokazivač +Comment[sr@latin]=Položaj miša i pokazivač +Comment[sv]=Musposition och pekare +Comment[tg]=Ҷойгиршавии муш ва курсор +Comment[th]=ตำแหน่งตัวชี้และเคอร์เซอร์ของเมาส์ +Comment[tr]=Fare konumu ve işaretçisi +Comment[ug]=چاشقىنەك ئورنى ۋە نۇربەلگە +Comment[uk]=Позиція вказівника миші і курсора +Comment[wa]=1Eplaeçmint del sori et do cursoe +Comment[x-test]=xxMouse position and cursorxx +Comment[zh_CN]=鼠标位置和光标 +Comment[zh_TW]=滑鼠位置與游標 +Type=Service +X-KDE-ServiceTypes=Plasma/DataEngine +Icon=input-mouse +X-KDE-Library=plasma_engine_mouse + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=mouse +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/mpris2/CMakeLists.txt b/plasma/generic/dataengines/mpris2/CMakeLists.txt new file mode 100644 index 00000000..310ce7dd --- /dev/null +++ b/plasma/generic/dataengines/mpris2/CMakeLists.txt @@ -0,0 +1,32 @@ +project(plasma-dataengine-mpris2) + +add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) + +set(mpris2_engine_SRCS + mpris2engine.cpp + multiplexer.cpp + multiplexedservice.cpp + playercontrol.cpp + playeractionjob.cpp + playercontainer.cpp +) + +set_source_files_properties( + org.freedesktop.DBus.Properties.xml + org.mpris.MediaPlayer2.Player.xml + org.mpris.MediaPlayer2.xml + PROPERTIES + NO_NAMESPACE ON) +qt4_add_dbus_interface(mpris2_engine_SRCS org.freedesktop.DBus.Properties.xml dbusproperties) +qt4_add_dbus_interface(mpris2_engine_SRCS org.mpris.MediaPlayer2.Player.xml mprisplayer) +qt4_add_dbus_interface(mpris2_engine_SRCS org.mpris.MediaPlayer2.xml mprisroot) + +kde4_add_plugin(plasma_engine_mpris2 ${mpris2_engine_SRCS}) +target_link_libraries(plasma_engine_mpris2 + ${KDE4_PLASMA_LIBS} +) + +install(TARGETS plasma_engine_mpris2 DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-mpris2.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES mpris2.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + diff --git a/plasma/generic/dataengines/mpris2/Messages.sh b/plasma/generic/dataengines/mpris2/Messages.sh new file mode 100755 index 00000000..0e393ff3 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_mpris2.pot diff --git a/plasma/generic/dataengines/mpris2/TODO b/plasma/generic/dataengines/mpris2/TODO new file mode 100644 index 00000000..18057320 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/TODO @@ -0,0 +1,2 @@ +* add tracklist support (secondary source? eg: amarok:tracklist) +* add playlists support (secondary source? eg: amarok:playlists) diff --git a/plasma/generic/dataengines/mpris2/mpris2.operations b/plasma/generic/dataengines/mpris2/mpris2.operations new file mode 100644 index 00000000..5a49f0c3 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/mpris2.operations @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/mpris2/mpris2engine.cpp b/plasma/generic/dataengines/mpris2/mpris2engine.cpp new file mode 100644 index 00000000..16225a8a --- /dev/null +++ b/plasma/generic/dataengines/mpris2/mpris2engine.cpp @@ -0,0 +1,201 @@ +/* + * Copyright 2007-2012 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mpris2engine.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "playercontrol.h" +#include "playercontainer.h" +#include "multiplexer.h" +#include "multiplexedservice.h" + +Mpris2Engine::Mpris2Engine(QObject* parent, + const QVariantList& args) + : Plasma::DataEngine(parent) +{ + Q_UNUSED(args) + + setName("mpris2"); + + QDBusServiceWatcher *serviceWatcher = new QDBusServiceWatcher( + QString(), QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForOwnerChange, this); + connect(serviceWatcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), + this, SLOT(serviceOwnerChanged(QString,QString,QString))); + + QDBusPendingCall async = QDBusConnection::sessionBus().interface()->asyncCall("ListNames"); + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this); + connect(callWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(serviceNameFetchFinished(QDBusPendingCallWatcher*))); +} + +Plasma::Service* Mpris2Engine::serviceForSource(const QString& source) +{ + if (source == Multiplexer::sourceName) { + if (!m_multiplexer) { + createMultiplexer(); + } + return new MultiplexedService(m_multiplexer.data(), this); + } else { + PlayerContainer* container = qobject_cast(containerForSource(source)); + if (container) { + return new PlayerControl(container, this); + } else { + return DataEngine::serviceForSource(source); + } + } +} + +QStringList Mpris2Engine::sources() const +{ + if (m_multiplexer) + return DataEngine::sources(); + else + return DataEngine::sources() << Multiplexer::sourceName; +} + +void Mpris2Engine::serviceOwnerChanged( + const QString& serviceName, + const QString& oldOwner, + const QString& newOwner) +{ + if (!serviceName.startsWith(QLatin1String("org.mpris.MediaPlayer2."))) + return; + + QString sourceName = serviceName.mid(23); + + if (!oldOwner.isEmpty()) { + kDebug() << "MPRIS service" << serviceName << "just went offline"; + if (m_multiplexer) { + m_multiplexer.data()->removePlayer(sourceName); + } + removeSource(sourceName); + } + + if (!newOwner.isEmpty()) { + kDebug() << "MPRIS service" << serviceName << "just came online"; + addMediaPlayer(serviceName, sourceName); + } +} + +bool Mpris2Engine::updateSourceEvent(const QString& source) +{ + if (source == Multiplexer::sourceName) { + return false; + } else { + PlayerContainer *container = qobject_cast(containerForSource(source)); + if (container) { + container->refresh(); + return true; + } else { + return false; + } + } +} + +bool Mpris2Engine::sourceRequestEvent(const QString& source) +{ + if (source == Multiplexer::sourceName) { + createMultiplexer(); + return true; + } + return false; +} + +void Mpris2Engine::initialFetchFinished(PlayerContainer* container) +{ + kDebug() << "Props fetch for" << container->objectName() << "finished; adding"; + addSource(container); + if (m_multiplexer) { + m_multiplexer.data()->addPlayer(container); + } + // don't let future refreshes trigger this + disconnect(container, SIGNAL(initialFetchFinished(PlayerContainer*)), + this, SLOT(initialFetchFinished(PlayerContainer*))); + disconnect(container, SIGNAL(initialFetchFailed(PlayerContainer*)), + this, SLOT(initialFetchFailed(PlayerContainer*))); +} + +void Mpris2Engine::initialFetchFailed(PlayerContainer* container) +{ + kWarning() << "Failed to find working MPRIS2 interface for" << container->dbusAddress(); + container->deleteLater(); +} + +void Mpris2Engine::serviceNameFetchFinished(QDBusPendingCallWatcher* watcher) +{ + QDBusPendingReply propsReply = *watcher; + watcher->deleteLater(); + + if (propsReply.isError()) { + kWarning() << "Could not get list of available D-Bus services"; + } else { + foreach (const QString& serviceName, propsReply.value()) { + if (serviceName.startsWith("org.mpris.MediaPlayer2.")) { + kDebug() << "Found MPRIS2 service" << serviceName; + // watch out for race conditions; the media player could + // have appeared between starting the service watcher and + // this call being dealt with + // NB: _disappearing_ between sending this call and doing + // this processing is fine + QString sourceName = serviceName.mid(23); + PlayerContainer *container = qobject_cast(containerForSource(sourceName)); + if (!container) { + kDebug() << "Haven't already seen" << serviceName; + addMediaPlayer(serviceName, sourceName); + } + } + } + } +} + +void Mpris2Engine::addMediaPlayer(const QString& serviceName, const QString& sourceName) +{ + PlayerContainer *container = new PlayerContainer(serviceName, this); + container->setObjectName(sourceName); + connect(container, SIGNAL(initialFetchFinished(PlayerContainer*)), + this, SLOT(initialFetchFinished(PlayerContainer*))); + connect(container, SIGNAL(initialFetchFailed(PlayerContainer*)), + this, SLOT(initialFetchFailed(PlayerContainer*))); +} + +void Mpris2Engine::createMultiplexer() +{ + Q_ASSERT (!m_multiplexer); + m_multiplexer = new Multiplexer(this); + + SourceDict dict = containerDict(); + SourceDict::const_iterator i = dict.constBegin(); + while (i != dict.constEnd()) { + PlayerContainer *container = qobject_cast(i.value()); + m_multiplexer.data()->addPlayer(container); + ++i; + } + addSource(m_multiplexer.data()); +} + +#include "mpris2engine.moc" diff --git a/plasma/generic/dataengines/mpris2/mpris2engine.h b/plasma/generic/dataengines/mpris2/mpris2engine.h new file mode 100644 index 00000000..4d314f76 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/mpris2engine.h @@ -0,0 +1,65 @@ +/* + * Copyright 2007-2012 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MPRIS2ENGINE_H +#define MPRIS2ENGINE_H + +#include + +#include + +class QDBusPendingCallWatcher; +class PlayerContainer; +class Multiplexer; + +/** + * The MPRIS2 data engine. + */ +class Mpris2Engine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + Mpris2Engine(QObject* parent, const QVariantList& args); + + Plasma::Service* serviceForSource(const QString& source); + virtual QStringList sources() const; + +protected: + virtual bool sourceRequestEvent(const QString& source); + virtual bool updateSourceEvent(const QString& source); + +private slots: + void serviceOwnerChanged( + const QString& serviceName, + const QString& oldOwner, + const QString& newOwner); + void initialFetchFinished(PlayerContainer* container); + void initialFetchFailed(PlayerContainer* container); + void serviceNameFetchFinished(QDBusPendingCallWatcher* watcher); + +private: + void addMediaPlayer(const QString& serviceName, const QString& sourceName); + void createMultiplexer(); + + QWeakPointer m_multiplexer; +}; + +K_EXPORT_PLASMA_DATAENGINE(mpris2, Mpris2Engine) + +#endif // MPRIS2ENGINE_H diff --git a/plasma/generic/dataengines/mpris2/multiplexedservice.cpp b/plasma/generic/dataengines/mpris2/multiplexedservice.cpp new file mode 100644 index 00000000..a3b450d7 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/multiplexedservice.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2012 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "multiplexedservice.h" + +#include "multiplexer.h" +#include "playercontrol.h" + +MultiplexedService::MultiplexedService(Multiplexer *multiplexer, QObject *parent) + : Plasma::Service(parent) +{ + setObjectName(Multiplexer::sourceName + QLatin1String(" controller")); + setName("mpris2"); + setDestination(Multiplexer::sourceName); + + connect(multiplexer, SIGNAL(activePlayerChanged(PlayerContainer*)), + this, SLOT(activePlayerChanged(PlayerContainer*))); + + activePlayerChanged(multiplexer->activePlayer()); +} + +Plasma::ServiceJob* MultiplexedService::createJob(const QString& operation, + QMap& parameters) +{ + if (m_control) { + return m_control.data()->createJob(operation, parameters); + } + return 0; +} + +void MultiplexedService::updateEnabledOperations() +{ + if (m_control) { + foreach (const QString &op, operationNames()) { + setOperationEnabled(op, m_control.data()->isOperationEnabled(op)); + } + } else { + foreach (const QString &op, operationNames()) { + setOperationEnabled(op, false); + } + } +} + +void MultiplexedService::activePlayerChanged(PlayerContainer *container) +{ + delete m_control.data(); + + if (container) { + m_control = new PlayerControl(container, container->getDataEngine()); + connect(m_control.data(), SIGNAL(enabledOperationsChanged()), + this, SLOT(updateEnabledOperations())); + } + + updateEnabledOperations(); +} + diff --git a/plasma/generic/dataengines/mpris2/multiplexedservice.h b/plasma/generic/dataengines/mpris2/multiplexedservice.h new file mode 100644 index 00000000..c2c47400 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/multiplexedservice.h @@ -0,0 +1,49 @@ +/* + * Copyright 2012 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ +#ifndef MULTIPLEXEDSERVICE_H +#define MULTIPLEXEDSERVICE_H + +#include + +#include "playercontrol.h" +#include + +class Multiplexer; +class PlayerControl; + +class MultiplexedService : public Plasma::Service +{ + Q_OBJECT + +public: + MultiplexedService(Multiplexer *multiplexer, QObject *parent = 0); + +protected: + Plasma::ServiceJob *createJob(const QString &operation, + QMap ¶meters); + +private slots: + void updateEnabledOperations(); + void activePlayerChanged(PlayerContainer *container); + +private: + QWeakPointer m_control; +}; + +#endif // MULTIPLEXEDSERVICE_H diff --git a/plasma/generic/dataengines/mpris2/multiplexer.cpp b/plasma/generic/dataengines/mpris2/multiplexer.cpp new file mode 100644 index 00000000..d9e69897 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/multiplexer.cpp @@ -0,0 +1,198 @@ +/* + * Copyright 2012 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "multiplexer.h" + +#include + +// the '@' at the start is not valid for D-Bus names, so it will +// never interfere with an actual MPRIS2 player +const QLatin1String Multiplexer::sourceName = QLatin1String("@multiplex"); + +Multiplexer::Multiplexer(QObject* parent) + : DataContainer(parent) +{ + setObjectName(sourceName); +} + +void Multiplexer::addPlayer(PlayerContainer *container) +{ + bool makeActive = m_activeName.isEmpty(); + + if (container->data().value("PlaybackStatus") == QLatin1String("Playing")) { + m_playing.insert(container->objectName(), container); + if (!makeActive && + data().value("PlaybackStatus") != QLatin1String("Playing")) { + makeActive = true; + } + } else if (container->data().value("PlaybackStatus") == QLatin1String("Paused")) { + m_paused.insert(container->objectName(), container); + if (!makeActive && + data().value("PlaybackStatus") != QLatin1String("Playing") && + data().value("PlaybackStatus") != QLatin1String("Paused")) { + makeActive = true; + } + } else { + m_stopped.insert(container->objectName(), container); + } + + connect(container, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)), + this, SLOT(playerUpdated(QString,Plasma::DataEngine::Data))); + + if (makeActive) { + m_activeName = container->objectName(); + replaceData(container->data()); + checkForUpdate(); + emit activePlayerChanged(container); + } +} + +void Multiplexer::removePlayer(const QString &name) +{ + PlayerContainer *container = m_playing.take(name); + if (!container) + container = m_paused.take(name); + if (!container) + container = m_stopped.take(name); + if (container) + container->disconnect(this); + + if (name == m_activeName) { + setBestActive(); + } +} + +PlayerContainer *Multiplexer::activePlayer() const +{ + if (m_activeName.isEmpty()) { + return 0; + } + + PlayerContainer *container = m_playing.value(m_activeName); + if (!container) + container = m_paused.value(m_activeName); + if (!container) + container = m_stopped.value(m_activeName); + Q_ASSERT(container); + return container; +} + +void Multiplexer::playerUpdated(const QString &name, const Plasma::DataEngine::Data &newData) +{ + if (newData.value("PlaybackStatus") == QLatin1String("Playing")) { + if (!m_playing.contains(name)) { + PlayerContainer *container = m_paused.take(name); + if (!container) { + container = m_stopped.take(name); + } + Q_ASSERT(container); + m_playing.insert(name, container); + } + if (m_activeName != name && + data().value("PlaybackStatus") != QLatin1String("Playing")) { + m_activeName = name; + replaceData(newData); + checkForUpdate(); + emit activePlayerChanged(activePlayer()); + return; + } + } else if (newData.value("PlaybackStatus") == QLatin1String("Paused")) { + if (!m_paused.contains(name)) { + PlayerContainer *container = m_playing.take(name); + if (!container) { + container = m_stopped.take(name); + } + Q_ASSERT(container); + m_paused.insert(name, container); + } + if (m_activeName != name && + data().value("PlaybackStatus") != QLatin1String("Playing") && + data().value("PlaybackStatus") != QLatin1String("Paused")) { + m_activeName = name; + replaceData(newData); + checkForUpdate(); + emit activePlayerChanged(activePlayer()); + return; + } + } else { + if (!m_stopped.contains(name)) { + PlayerContainer *container = m_playing.take(name); + if (!container) { + container = m_paused.take(name); + } + Q_ASSERT(container); + m_stopped.insert(name, container); + } + } + + if (m_activeName == name) { + bool isPaused = newData.value("PlaybackStatus") == QLatin1String("Paused"); + bool isStopped = !isPaused && newData.value("PlaybackStatus") != QLatin1String("Playing"); + if (isPaused && !m_playing.isEmpty()) { + setBestActive(); + } else if (isStopped && (!m_playing.isEmpty() || !m_paused.isEmpty())) { + setBestActive(); + } else { + replaceData(newData); + checkForUpdate(); + } + } +} + +void Multiplexer::setBestActive() +{ + QHash::const_iterator it = m_playing.constBegin(); + if (it != m_playing.constEnd()) { + m_activeName = it.key(); + replaceData(it.value()->data()); + emit activePlayerChanged(it.value()); + } else { + it = m_paused.constBegin(); + if (it != m_paused.constEnd()) { + m_activeName = it.key(); + replaceData(it.value()->data()); + emit activePlayerChanged(it.value()); + } else { + it = m_stopped.constBegin(); + if (it != m_stopped.constEnd()) { + m_activeName = it.key(); + replaceData(it.value()->data()); + emit activePlayerChanged(it.value()); + } else { + m_activeName = QString(); + removeAllData(); + emit activePlayerChanged(0); + } + } + } + checkForUpdate(); +} + +void Multiplexer::replaceData(const Plasma::DataEngine::Data &data) +{ + removeAllData(); + + Plasma::DataEngine::Data::const_iterator it = data.constBegin(); + while (it != data.constEnd()) { + setData(it.key(), it.value()); + ++it; + } + setData("Source Name", m_activeName); +} + diff --git a/plasma/generic/dataengines/mpris2/multiplexer.h b/plasma/generic/dataengines/mpris2/multiplexer.h new file mode 100644 index 00000000..083cdf1a --- /dev/null +++ b/plasma/generic/dataengines/mpris2/multiplexer.h @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef MULTIPLEXER_H +#define MULTIPLEXER_H + +#include + +#include "playercontainer.h" + +#include + +class Multiplexer : public Plasma::DataContainer +{ + Q_OBJECT + +public: + static const QLatin1String sourceName; + + explicit Multiplexer(QObject *parent = 0); + + void addPlayer(PlayerContainer *container); + void removePlayer(const QString &name); + PlayerContainer *activePlayer() const; + +signals: + void activePlayerChanged(PlayerContainer *container); + +private slots: + void playerUpdated(const QString &name, const Plasma::DataEngine::Data &data); + +private: + void setBestActive(); + void replaceData(const Plasma::DataEngine::Data &data); + + QString m_activeName; + QHash m_playing; + QHash m_paused; + QHash m_stopped; +}; + +#endif // MULTIPLEXER_H diff --git a/plasma/generic/dataengines/mpris2/org.freedesktop.DBus.Properties.xml b/plasma/generic/dataengines/mpris2/org.freedesktop.DBus.Properties.xml new file mode 100644 index 00000000..8fef9c38 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/org.freedesktop.DBus.Properties.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/mpris2/org.mpris.MediaPlayer2.Player.xml b/plasma/generic/dataengines/mpris2/org.mpris.MediaPlayer2.Player.xml new file mode 100644 index 00000000..96349980 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/org.mpris.MediaPlayer2.Player.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/mpris2/org.mpris.MediaPlayer2.xml b/plasma/generic/dataengines/mpris2/org.mpris.MediaPlayer2.xml new file mode 100644 index 00000000..3bae600a --- /dev/null +++ b/plasma/generic/dataengines/mpris2/org.mpris.MediaPlayer2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/mpris2/plasma-dataengine-mpris2.desktop b/plasma/generic/dataengines/mpris2/plasma-dataengine-mpris2.desktop new file mode 100644 index 00000000..c5f88cbe --- /dev/null +++ b/plasma/generic/dataengines/mpris2/plasma-dataengine-mpris2.desktop @@ -0,0 +1,103 @@ +[Desktop Entry] +Name=MPRIS2 +Name[bs]=MPRIS2 +Name[ca]=MPRIS2 +Name[ca@valencia]=MPRIS2 +Name[cs]=MPRIS2 +Name[da]=MPRIS2 +Name[de]=MPRIS2 +Name[el]=MPRIS2 +Name[en_GB]=MPRIS2 +Name[es]=MPRIS2 +Name[et]=MPRIS2 +Name[eu]=MPRIS2 +Name[fi]=MPRIS2 +Name[fr]=MPRIS2 +Name[gl]=MPRIS2 +Name[he]=MPRIS2 +Name[hu]=MPRIS2 +Name[ia]=MPRIS2 +Name[it]=MPRIS2 +Name[kk]=MPRIS2 +Name[km]=MPRIS2 +Name[ko]=MPRIS2 +Name[lt]=MPRIS2 +Name[mr]=MPRIS2 +Name[nb]=MPRIS2 +Name[nds]=MPRIS2 +Name[nl]=MPRIS2 +Name[pa]=MPRIS2 +Name[pl]=MPRIS2 +Name[pt]=MPRIS2 +Name[pt_BR]=MPRIS2 +Name[ro]=MPRIS2 +Name[ru]=MPRIS2 +Name[sk]=MPRIS2 +Name[sl]=MPRIS2 +Name[sr]=МПРИС 2 +Name[sr@ijekavian]=МПРИС 2 +Name[sr@ijekavianlatin]=MPRIS 2 +Name[sr@latin]=MPRIS 2 +Name[sv]=MPRIS2 +Name[tr]=MPRIS2 +Name[uk]=MPRIS2 +Name[x-test]=xxMPRIS2xx +Name[zh_CN]=MPRIS2 +Name[zh_TW]=MPRIS2 +Comment=Provides information from and control over media players via MPRIS2 +Comment[bs]=Pruža informacije putem i kontrolom medija plejera pomoću MPRIS2 +Comment[ca]=Proporciona informació i controla els reproductors de suports via el MPRIS2 +Comment[ca@valencia]=Proporciona informació i controla els reproductors de suports via el MPRIS2 +Comment[cs]=Poskytuje informace a ovládání přehrávačů médií přes MPRIS2 +Comment[da]=Giver information fra og kontrol over medieafspillere via MPRIS2 +Comment[de]=Stellt Informationen über Medienspieler unter Verwendung von MPRIS2 bereit und ermöglicht deren Steuerung +Comment[el]=Παρέχει πληροφορίες και ελέγχει προγράμματα αναπαραγωγής πολυμέσων με το MPRIS2 +Comment[en_GB]=Provides information from and control over media players via MPRIS2 +Comment[es]=Proporciona información y control sobre reproductores multimedia vía MPRIS2 +Comment[et]=Teabe hankimine meediamängijatest ja nende juhtimine MPRIS2 kaudu +Comment[eu]=Multimedia-jotzaileei buruzko informazioa ematen du eta haiek kontrolatzen ditu MPRIS2 bidez +Comment[fi]=Mahdollistaa MPRIS2-yhteensopivien mediasoittimien hallinnan sekä tiedon välittämisen +Comment[fr]=Fournit des informations sur les lecteurs de média et les contrôle avec « MPRIS2 » +Comment[gl]=Fornece información e control de reprodutores multimedia mediante MPRIS2 +Comment[hu]=Információkat szolgáltat és vezérli a médialejátszókat az MPRIS2-n keresztül +Comment[ia]=Il provide information ex e control super media players via MPRIS2 +Comment[it]=Fornisce le informazioni da e controlla lettori multimediali via MPRIS2 +Comment[kk]=MPRIS2 арқылы медиаплейер мәліметін алып оны басқару мүмкіндігі +Comment[km]=ផ្ដល់​ព័ត៌មាន​ពី និង​ត្រួតពិនិត្យ​លើ​កម្មវិធី​ចាក់​មេឌៀ​តាមរយៈ MPRIS2 +Comment[ko]=MPRIS2를 통하여 미디어 재생기를 제어하고 정보 가져오기 +Comment[lt]=Pateikia informaciją iš MPRIS2 ir per jį valdo medijos grotuvus +Comment[mr]=MPRIS2 द्वारे मीडिया प्लेयर्स वर नियंत्रण व माहिती पुरवितो +Comment[nb]=Gir informasjon fra og kontroll over mediaspillere via MPRIS2-grensesnittet +Comment[nds]=Stellt Informatschonen ut un Kuntrull över Medienafspelers över MPRIS2 praat +Comment[nl]=Levert informatie uit en besturing aan mediaspelers via MPRIS2 +Comment[pl]=Dostarcza informacji z odtwarzaczy multimedialnych, a także steruje nimi przez MPRIS2 +Comment[pt]=Fornece informações e controla leitores multimédia através de MPRIS2 +Comment[pt_BR]=Fornece informações e controla leitores multimídia através de MPRIS2 +Comment[ro]=Furnizează informații de la și controlează lectorii multimedia prin MPRIS2 +Comment[ru]=Предоставление информации и управление медиапроигрывателем с помощью MPRIS2 +Comment[sk]=Poskytuje informácie z, a ovláda prehrávače médií cez MPRIS2 +Comment[sl]=Prikazuje podatke in omogoča nadzor predstavnostnih predvajalnikov +Comment[sr]=Подаци из медија плејера и управљање њима преко МПРИС‑а 2 +Comment[sr@ijekavian]=Подаци из медија плејера и управљање њима преко МПРИС‑а 2 +Comment[sr@ijekavianlatin]=Podaci iz medija plejera i upravljanje njima preko MPRIS‑a 2 +Comment[sr@latin]=Podaci iz medija plejera i upravljanje njima preko MPRIS‑a 2 +Comment[sv]=Tillhandahåller information från och styrning av mediaspelare via MPRIS2 +Comment[tr]=MPRIS2 kullanarak çokluortam oynatıcılara bilgi sağlar ve onları denetler +Comment[uk]=Надає дані з мультимедійних програвачів та керує ними за допомогою MPRIS2 +Comment[x-test]=xxProvides information from and control over media players via MPRIS2xx +Comment[zh_CN]=通过 MPRIS2 提供信息和控制播放器 +Comment[zh_TW]=透過 MPRIS2 取得媒體播放器的資訊並控制 + +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=applications-multimedia +X-KDE-Library=plasma_engine_mpris2 +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=mpris2 +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License= + diff --git a/plasma/generic/dataengines/mpris2/playeractionjob.cpp b/plasma/generic/dataengines/mpris2/playeractionjob.cpp new file mode 100644 index 00000000..fc656a00 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/playeractionjob.cpp @@ -0,0 +1,180 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "playeractionjob.h" + +#include "playercontrol.h" + +#include +#include +#include + +#include +#include +#include + +#include + +PlayerActionJob::PlayerActionJob(const QString& operation, + QMap& parameters, + PlayerControl* parent) + : ServiceJob(parent->name() + ": " + operation, operation, parameters, parent) + , m_controller(parent) +{ +} + +void PlayerActionJob::start() +{ + const QString operation(operationName()); + + kDebug() << "Trying to perform the action" << operationName(); + if (!m_controller->isOperationEnabled(operation)) { + setError(Denied); + emitResult(); + return; + } + + if (operation == QLatin1String("Quit") || operation == QLatin1String("Raise") + || operation == QLatin1String("SetFullscreen")) { + listenToCall(m_controller->rootInterface()->asyncCall(operation)); + } else if (operation == QLatin1String("Play") + || operation == QLatin1String("Pause") + || operation == QLatin1String("PlayPause") + || operation == QLatin1String("Stop") + || operation == QLatin1String("Next") + || operation == QLatin1String("Previous")) { + listenToCall(m_controller->playerInterface()->asyncCall(operation)); + } else if (operation == "Seek") { + if (parameters().value("microseconds").type() == QVariant::LongLong) { + listenToCall(m_controller->playerInterface()->Seek(parameters()["microseconds"].toLongLong())); + } else { + setErrorText("microseconds"); + setError(MissingArgument); + emitResult(); + } + } else if (operation == "SetPosition") { + if (parameters().value("microseconds").type() == QVariant::LongLong) { + listenToCall(m_controller->playerInterface()->SetPosition( + m_controller->trackId(), + parameters()["microseconds"].toLongLong())); + } else { + setErrorText("microseconds"); + setError(MissingArgument); + emitResult(); + } + } else if (operation == "OpenUri") { + if (parameters().value("uri").canConvert()) { + listenToCall(m_controller->playerInterface()->OpenUri( + QString::fromLatin1(parameters()["uri"].toUrl().toEncoded()))); + } else { + kDebug() << "uri was of type" << parameters().value("uri").userType(); + setErrorText("uri"); + setError(MissingArgument); + emitResult(); + } + } else if (operation == "SetLoopStatus") { + if (parameters().value("status").type() == QVariant::String) { + setDBusProperty(m_controller->playerInterface()->interface(), + "LoopStatus", QDBusVariant(parameters()["status"])); + } else { + setErrorText("status"); + setError(MissingArgument); + emitResult(); + } + } else if (operation == "SetShuffle") { + if (parameters().value("on").type() == QVariant::Bool) { + setDBusProperty(m_controller->playerInterface()->interface(), + "Shuffle", QDBusVariant(parameters()["on"])); + } else { + setErrorText("on"); + setError(MissingArgument); + emitResult(); + } + } else if (operation == "SetRate") { + if (parameters().value("rate").type() == QVariant::Double) { + setDBusProperty(m_controller->playerInterface()->interface(), + "Rate", QDBusVariant(parameters()["rate"])); + } else { + setErrorText("rate"); + setError(MissingArgument); + emitResult(); + } + } else if (operation == "SetVolume") { + if (parameters().value("level").type() == QVariant::Double) { + setDBusProperty(m_controller->playerInterface()->interface(), + "Volume", QDBusVariant(parameters()["level"])); + } else { + setErrorText("level"); + setError(MissingArgument); + emitResult(); + } + } else { + setError(UnknownOperation); + emitResult(); + } +} + +void PlayerActionJob::listenToCall(const QDBusPendingCall& call) +{ + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(callFinished(QDBusPendingCallWatcher*))); +} + +void PlayerActionJob::callFinished(QDBusPendingCallWatcher* watcher) +{ + QDBusPendingReply result = *watcher; + watcher->deleteLater(); + + if (result.isError()) { + // FIXME: try to be a bit cleverer with the error message? + setError(Failed); + setErrorText(result.error().message()); + } else { + setError(NoError); + } + + emitResult(); +} + +void PlayerActionJob::setDBusProperty(const QString& iface, const QString& propName, const QDBusVariant& value) +{ + listenToCall( + m_controller->propertiesInterface()->Set(iface, propName, value) + ); +} + +QString PlayerActionJob::errorString() const +{ + if (error() == Denied) { + return i18n("The media player '%1' cannot perform the action '%2'.", m_controller->name(), operationName()); + } else if (error() == Failed) { + return i18n("Attempting to perform the action '%1' failed with the message '%2'.", + operationName(), errorText()); + } else if (error() == MissingArgument) { + return i18n("The argument '%1' for the action '%2' is missing or of the wrong type.", operationName(), errorText()); + } else if (error() == UnknownOperation) { + return i18n("The operation '%1' is unknown.", operationName()); + } + return i18n("Unknown error."); +} + +#include "playeractionjob.moc" + +// vim: sw=4 sts=4 et tw=100 diff --git a/plasma/generic/dataengines/mpris2/playeractionjob.h b/plasma/generic/dataengines/mpris2/playeractionjob.h new file mode 100644 index 00000000..6fd80367 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/playeractionjob.h @@ -0,0 +1,74 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLAYERACTIONJOB_H +#define PLAYERACTIONJOB_H + +#include + +class QDBusPendingCallWatcher; +class QDBusPendingCall; +class QDBusVariant; +class PlayerControl; + +class PlayerActionJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + PlayerActionJob(const QString& operation, + QMap& parameters, + PlayerControl* parent); + + enum { + /** + * The media player reports that the operation is not possible + */ + Denied = UserDefinedError, + /** + * Calling the media player resulted in an error + */ + Failed, + /** + * An argument is missing or of wrong type + * + * errorText is argument name + */ + MissingArgument, + /** + * The operation name is unknown + */ + UnknownOperation + }; + + void start(); + + virtual QString errorString() const; + +private slots: + void callFinished(QDBusPendingCallWatcher*); + void setDBusProperty(const QString& iface, const QString& propName, const QDBusVariant& value); + +private: + void listenToCall(const QDBusPendingCall& call); + + PlayerControl *m_controller; +}; + +#endif // PLAYERACTIONJOB_H diff --git a/plasma/generic/dataengines/mpris2/playercontainer.cpp b/plasma/generic/dataengines/mpris2/playercontainer.cpp new file mode 100644 index 00000000..23323f06 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/playercontainer.cpp @@ -0,0 +1,397 @@ +/* + * Copyright 2012 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "playercontainer.h" + +#include +#include +#include + +#define MPRIS2_PATH "/org/mpris/MediaPlayer2" +#define POS_UPD_STRING "Position last updated (UTC)" + +#include +#include +#include + +#include +#include + +static QVariant::Type expPropType(const QString& propName) +{ + if (propName == QLatin1String("Identity")) + return QVariant::String; + else if (propName == QLatin1String("DesktopEntry")) + return QVariant::String; + else if (propName == QLatin1String("SupportedUriSchemes")) + return QVariant::StringList; + else if (propName == QLatin1String("SupportedMimeTypes")) + return QVariant::StringList; + else if (propName == QLatin1String("Fullscreen")) + return QVariant::Bool; + else if (propName == QLatin1String("PlaybackStatus")) + return QVariant::String; + else if (propName == QLatin1String("LoopStatus")) + return QVariant::String; + else if (propName == QLatin1String("Shuffle")) + return QVariant::Bool; + else if (propName == QLatin1String("Rate")) + return QVariant::Double; + else if (propName == QLatin1String("MinimumRate")) + return QVariant::Double; + else if (propName == QLatin1String("MaximumRate")) + return QVariant::Double; + else if (propName == QLatin1String("Volume")) + return QVariant::Double; + else if (propName == QLatin1String("Position")) + return QVariant::LongLong; + else if (propName == QLatin1String("Metadata")) + return QVariant::Map; + // we give out CanControl, as this may completely + // change the UI of the widget + else if (propName == QLatin1String("CanControl")) + return QVariant::Bool; + return QVariant::Invalid; +} + +static PlayerContainer::Cap capFromName(const QString& capName) +{ + if (capName == QLatin1String("CanQuit")) + return PlayerContainer::CanQuit; + else if (capName == QLatin1String("CanRaise")) + return PlayerContainer::CanRaise; + else if (capName == QLatin1String("CanSetFullscreen")) + return PlayerContainer::CanSetFullscreen; + else if (capName == QLatin1String("CanControl")) + return PlayerContainer::CanControl; + else if (capName == QLatin1String("CanPlay")) + return PlayerContainer::CanPlay; + else if (capName == QLatin1String("CanPause")) + return PlayerContainer::CanPause; + else if (capName == QLatin1String("CanSeek")) + return PlayerContainer::CanSeek; + else if (capName == QLatin1String("CanGoNext")) + return PlayerContainer::CanGoNext; + else if (capName == QLatin1String("CanGoPrevious")) + return PlayerContainer::CanGoPrevious; + return PlayerContainer::NoCaps; +} + +PlayerContainer::PlayerContainer(const QString& busAddress, QObject* parent) + : DataContainer(parent) + , m_caps(NoCaps) + , m_fetchesPending(0) + , m_dbusAddress(busAddress) + , m_currentRate(0.0) +{ + Q_ASSERT(!busAddress.isEmpty()); + Q_ASSERT(busAddress.startsWith(QLatin1String("org.mpris.MediaPlayer2."))); + + m_propsIface = new OrgFreedesktopDBusPropertiesInterface( + busAddress, MPRIS2_PATH, + QDBusConnection::sessionBus(), this); + + m_playerIface = new OrgMprisMediaPlayer2PlayerInterface( + busAddress, MPRIS2_PATH, + QDBusConnection::sessionBus(), this); + + m_rootIface = new OrgMprisMediaPlayer2Interface( + busAddress, MPRIS2_PATH, + QDBusConnection::sessionBus(), this); + + connect(m_propsIface, SIGNAL(PropertiesChanged(QString,QVariantMap,QStringList)), + this, SLOT(propertiesChanged(QString,QVariantMap,QStringList))); + + connect(m_playerIface, SIGNAL(Seeked(qlonglong)), + this, SLOT(seeked(qlonglong))); + + refresh(); +} + +void PlayerContainer::refresh() +{ + // despite these calls being async, we should never update values in the + // wrong order (eg: a stale GetAll response overwriting a more recent value + // from a PropertiesChanged signal) due to D-Bus message ordering guarantees. + + QDBusPendingCall async = m_propsIface->GetAll(OrgMprisMediaPlayer2Interface::staticInterfaceName()); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(getPropsFinished(QDBusPendingCallWatcher*))); + ++m_fetchesPending; + + async = m_propsIface->GetAll(OrgMprisMediaPlayer2PlayerInterface::staticInterfaceName()); + watcher = new QDBusPendingCallWatcher(async, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(getPropsFinished(QDBusPendingCallWatcher*))); + ++m_fetchesPending; +} + +static bool decodeUri(QVariantMap &map, const QString& entry) { + if (map.contains(entry)) { + QString urlString = map.value(entry).toString(); + QUrl url = QUrl::fromEncoded(urlString.toAscii()); + if (!url.isValid()) { + // try to be lenient + url = QUrl(urlString); + } + if (url.isValid()) { + map.insert(entry, QVariant(url)); + return true; + } else { + map.remove(entry); + return false; + } + } + // count it as a success if it doesn't exist + return true; +} + +void PlayerContainer::copyProperty(const QString& propName, const QVariant& _value, QVariant::Type expType, UpdateType updType) +{ + QVariant value = _value; + // we protect our users from bogus values + if (value.userType() == qMetaTypeId()) { + if (expType == QVariant::Map) { + QDBusArgument arg = value.value(); + if (arg.currentType() != QDBusArgument::MapType) { + kWarning() << m_dbusAddress << "exports" << propName + << "with the wrong type; it should be D-Bus type \"a{sv}\""; + return; + } + QVariantMap map; + arg >> map; + if (propName == QLatin1String("Metadata")) { + if (!decodeUri(map, QLatin1String("mpris:artUrl"))) { + kWarning() << m_dbusAddress << "has an invalid URL for the mpris:artUrl entry of the \"Metadata\" property"; + } + if (!decodeUri(map, QLatin1String("xesam:url"))) { + kWarning() << m_dbusAddress << "has an invalid URL for the xesam:url entry of the \"Metadata\" property"; + } + } + value = QVariant(map); + } + } + if (value.type() != expType) { + const char * gotTypeCh = QDBusMetaType::typeToSignature(value.userType()); + QString gotType = gotTypeCh ? QString::fromAscii(gotTypeCh) : ""; + const char * expTypeCh = QDBusMetaType::typeToSignature(expType); + QString expType = expTypeCh ? QString::fromAscii(expTypeCh) : ""; + + kWarning() << m_dbusAddress << "exports" << propName + << "as D-Bus type" << gotType + << "but it should be D-Bus type" << expType; + } + if (value.convert(expType)) { + if (propName == QLatin1String("Position")) { + + setData(POS_UPD_STRING, QDateTime::currentDateTimeUtc()); + + } else if (propName == QLatin1String("Metadata")) { + + if (updType == UpdatedSignal) { + QDBusObjectPath oldTrackId = data().value("Metadata").toMap().value("mpris:trackid").value(); + QDBusObjectPath newTrackId = value.toMap().value("mpris:trackid").value(); + if (oldTrackId != newTrackId) { + setData("Position", static_cast(0)); + setData(POS_UPD_STRING, QDateTime::currentDateTimeUtc()); + } + } + + } else if (propName == QLatin1String("Rate") && + data().value("PlaybackStatus").toString() == QLatin1String("Playing")) { + + if (data().contains("Position")) + recalculatePosition(); + m_currentRate = value.toDouble(); + + } else if (propName == QLatin1String("PlaybackStatus")) { + + if (data().contains("Position") && data().contains("PlaybackStatus")) { + recalculatePosition(); + + if (data().value("PlaybackStatus").toString() == QLatin1String("Playing") + && value.toString() == QLatin1String("Paused")) { + // Every time something that affects the predicted position changes + // (Rate or PlaybackStatus), we get a hundred milliseconds or so + // out, due to the time it takes for a D-Bus message to be delivered + // and processed. + // + // To try to prevent these errors from accumulating, we re-fetch + // the position when we enter paused mode; when paused, the position + // does not change, so we'll be about as accurate as we can be. + updatePosition(); + } + } + + // update the effective rate + if (data().contains("Rate")) { + if (value.toString() == QLatin1String("Playing")) + m_currentRate = data().value("Rate").toDouble(); + else + m_currentRate = 0.0; + } + if (value.toString() == QLatin1String("Stopped")) { + // assume the position has reset to 0, since this is really the + // only sensible value for a stopped track + setData("Position", static_cast(0)); + setData(POS_UPD_STRING, QDateTime::currentDateTimeUtc()); + } + } else if (propName == QLatin1String("DesktopEntry")) { + QString filename = value.toString() + QLatin1String(".desktop"); + KDesktopFile desktopFile("xdgdata-apps", filename); + QString iconName = desktopFile.readIcon(); + if (!iconName.isEmpty()) { + setData("Desktop Icon Name", iconName); + } + } + setData(propName, value); + } +} + +void PlayerContainer::updateFromMap(const QVariantMap& map, UpdateType updType) +{ + QMap::const_iterator i = map.constBegin(); + while (i != map.constEnd()) { + QVariant::Type type = expPropType(i.key()); + if (type != QVariant::Invalid) { + copyProperty(i.key(), i.value(), type, updType); + } + + Cap cap = capFromName(i.key()); + if (cap != NoCaps) { + if (i.value().type() == QVariant::Bool) { + if (i.value().toBool()) { + m_caps |= cap; + } else { + m_caps &= ~cap; + } + } else { + const char * gotTypeCh = QDBusMetaType::typeToSignature(i.value().userType()); + QString gotType = gotTypeCh ? QString::fromAscii(gotTypeCh) : ""; + + kWarning() << m_dbusAddress << "exports" << i.key() + << "as D-Bus type" << gotType + << "but it should be D-Bus type \"b\""; + } + } + // fake the CanStop capability + if (cap == CanControl || i.key() == QLatin1String("PlaybackStatus")) { + if ((m_caps & CanControl) && i.value().toString() != QLatin1String("Stopped")) { + kDebug() << "Enabling stop action"; + m_caps |= CanStop; + } else { + kDebug() << "Disabling stop action"; + m_caps &= ~CanStop; + } + } + ++i; + } +} + +void PlayerContainer::getPropsFinished(QDBusPendingCallWatcher* watcher) +{ + QDBusPendingReply propsReply = *watcher; + watcher->deleteLater(); + + if (m_fetchesPending < 1) { + // we already failed + return; + } + + if (propsReply.isError()) { + kWarning() << m_dbusAddress << "does not implement" + << OrgFreedesktopDBusPropertiesInterface::staticInterfaceName() + << "correctly"; + kDebug() << "Error message was" << propsReply.error().name() << propsReply.error().message(); + m_fetchesPending = 0; + emit initialFetchFailed(this); + return; + } + + updateFromMap(propsReply.value(), FetchAll); + checkForUpdate(); + + --m_fetchesPending; + if (m_fetchesPending == 0) { + emit initialFetchFinished(this); + } +} + +void PlayerContainer::updatePosition() +{ + QDBusPendingCall async = m_propsIface->Get(OrgMprisMediaPlayer2PlayerInterface::staticInterfaceName(), "Position"); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(getPositionFinished(QDBusPendingCallWatcher*))); +} + +void PlayerContainer::getPositionFinished(QDBusPendingCallWatcher* watcher) +{ + QDBusPendingReply propsReply = *watcher; + watcher->deleteLater(); + + if (propsReply.isError()) { + kWarning() << m_dbusAddress << "does not implement" + << OrgFreedesktopDBusPropertiesInterface::staticInterfaceName() + << "correctly"; + kDebug() << "Error message was" << propsReply.error().name() << propsReply.error().message(); + return; + } + + setData("Position", propsReply.value().toLongLong()); + setData(POS_UPD_STRING, QDateTime::currentDateTimeUtc()); + checkForUpdate(); +} + +void PlayerContainer::propertiesChanged( + const QString& interface, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties) +{ + Q_UNUSED(interface) + + updateFromMap(changedProperties, UpdatedSignal); + if (!invalidatedProperties.isEmpty()) { + refresh(); + } + checkForUpdate(); +} + +void PlayerContainer::seeked(qlonglong position) +{ + setData("Position", position); + setData(POS_UPD_STRING, QDateTime::currentDateTimeUtc()); + checkForUpdate(); +} + +void PlayerContainer::recalculatePosition() +{ + Q_ASSERT(data().contains("Position")); + + qint64 pos = data().value("Position").toLongLong(); + QDateTime lastUpdated = data().value(POS_UPD_STRING).toDateTime(); + QDateTime now = QDateTime::currentDateTimeUtc(); + qint64 diff = lastUpdated.msecsTo(now) * 1000; + qint64 newPos = pos + static_cast(diff * m_currentRate); + setData("Position", newPos); + setData(POS_UPD_STRING, now); +} + +#include "playercontainer.moc" diff --git a/plasma/generic/dataengines/mpris2/playercontainer.h b/plasma/generic/dataengines/mpris2/playercontainer.h new file mode 100644 index 00000000..34a2ad85 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/playercontainer.h @@ -0,0 +1,99 @@ +/* + * Copyright 2008-2012 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLAYERCONTAINER_H +#define PLAYERCONTAINER_H + +#include +#include + +class OrgFreedesktopDBusPropertiesInterface; +class OrgMprisMediaPlayer2Interface; +class OrgMprisMediaPlayer2PlayerInterface; +class PlayerControl; +class QDBusPendingCallWatcher; + +class PlayerContainer : public Plasma::DataContainer +{ + Q_OBJECT + +public: + explicit PlayerContainer(const QString& busAddress, QObject* parent = 0); + + QString dbusAddress() const { return m_dbusAddress; } + OrgFreedesktopDBusPropertiesInterface* propertiesInterface() const { return m_propsIface; } + OrgMprisMediaPlayer2Interface* rootInterface() const { return m_rootIface; } + OrgMprisMediaPlayer2PlayerInterface* playerInterface() const { return m_playerIface; } + + enum Cap { + NoCaps = 0, + CanQuit = 1 << 0, + CanRaise = 1 << 1, + CanSetFullscreen = 1 << 2, + CanControl = 1 << 3, + CanPlay = 1 << 4, + CanPause = 1 << 5, + CanSeek = 1 << 6, + CanGoNext = 1 << 7, + CanGoPrevious = 1 << 8, + // CanStop is not directly provided by the spec, + // but we infer it from PlaybackStatus and CanControl + CanStop = 1 << 9 + }; + Q_DECLARE_FLAGS(Caps, Cap) + Caps capabilities() const { return m_caps; } + + enum UpdateType { + FetchAll, + UpdatedSignal + }; + + void refresh(); + +signals: + void initialFetchFinished(PlayerContainer* self); + void initialFetchFailed(PlayerContainer* self); + void capsChanged(Caps newCaps); + +private slots: + void getPropsFinished(QDBusPendingCallWatcher* watcher); + void getPositionFinished(QDBusPendingCallWatcher* watcher); + void propertiesChanged(const QString& interface, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties); + void seeked(qlonglong position); + +private: + void copyProperty(const QString& propName, const QVariant& value, QVariant::Type expType, UpdateType updType); + void updateFromMap(const QVariantMap& map, UpdateType updType); + void updatePosition(); + void recalculatePosition(); + + Caps m_caps; + int m_fetchesPending; + QString m_dbusAddress; + OrgFreedesktopDBusPropertiesInterface *m_propsIface; + OrgMprisMediaPlayer2Interface *m_rootIface; + OrgMprisMediaPlayer2PlayerInterface *m_playerIface; + double m_currentRate; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(PlayerContainer::Caps) + +#endif // PLAYERCONTAINER_H diff --git a/plasma/generic/dataengines/mpris2/playercontrol.cpp b/plasma/generic/dataengines/mpris2/playercontrol.cpp new file mode 100644 index 00000000..e28fbc23 --- /dev/null +++ b/plasma/generic/dataengines/mpris2/playercontrol.cpp @@ -0,0 +1,94 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "playercontrol.h" + +#include "playeractionjob.h" +#include "playercontainer.h" + +#include +#include +#include + +#include +#include + +PlayerControl::PlayerControl(PlayerContainer* container, QObject* parent) + : Plasma::Service(parent) + , m_container(container) +{ + setObjectName(container->objectName() + QLatin1String(" controller")); + setName("mpris2"); + setDestination(container->objectName()); + + connect(container, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)), + this, SLOT(updateEnabledOperations())); + connect(container, SIGNAL(destroyed(QObject*)), + this, SLOT(containerDestroyed())); + updateEnabledOperations(); +} + +void PlayerControl::updateEnabledOperations() +{ + PlayerContainer::Caps caps = PlayerContainer::NoCaps; + if (m_container) + caps = m_container->capabilities(); + + setOperationEnabled("Quit", caps & PlayerContainer::CanQuit); + setOperationEnabled("Raise", caps & PlayerContainer::CanRaise); + setOperationEnabled("SetFullscreen", caps & PlayerContainer::CanSetFullscreen); + + setOperationEnabled("Play", caps & PlayerContainer::CanPlay); + setOperationEnabled("Pause", caps & PlayerContainer::CanPause); + setOperationEnabled("PlayPause", caps & PlayerContainer::CanPause); + setOperationEnabled("Stop", caps & PlayerContainer::CanStop); + setOperationEnabled("Next", caps & PlayerContainer::CanGoNext); + setOperationEnabled("Previous", caps & PlayerContainer::CanGoPrevious); + setOperationEnabled("Seek", caps & PlayerContainer::CanSeek); + setOperationEnabled("SetPosition", caps & PlayerContainer::CanSeek); + setOperationEnabled("OpenUri", caps & PlayerContainer::CanControl); + setOperationEnabled("SetVolume", caps & PlayerContainer::CanControl); + setOperationEnabled("SetLoopStatus", caps & PlayerContainer::CanControl); + setOperationEnabled("SetRate", caps & PlayerContainer::CanControl); + setOperationEnabled("SetShuffle", caps & PlayerContainer::CanControl); + + emit enabledOperationsChanged(); +} + +QDBusObjectPath PlayerControl::trackId() const +{ + return m_container->data().value("Metadata").toMap().value("mpris:trackid").value(); +} + +void PlayerControl::containerDestroyed() +{ + m_container = 0; +} + +Plasma::ServiceJob* PlayerControl::createJob(const QString& operation, + QMap& parameters) +{ + if (!m_container) + return 0; + return new PlayerActionJob(operation, parameters, this); +} + +#include "playercontrol.moc" + +// vim: sw=4 sts=4 et tw=100 diff --git a/plasma/generic/dataengines/mpris2/playercontrol.h b/plasma/generic/dataengines/mpris2/playercontrol.h new file mode 100644 index 00000000..100654bf --- /dev/null +++ b/plasma/generic/dataengines/mpris2/playercontrol.h @@ -0,0 +1,61 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLAYERCONTROL_H +#define PLAYERCONTROL_H + +#include "playercontainer.h" + +#include +#include + +class OrgFreedesktopDBusPropertiesInterface; +class OrgMprisMediaPlayer2Interface; +class OrgMprisMediaPlayer2PlayerInterface; + +class PlayerControl : public Plasma::Service +{ + Q_OBJECT + +public: + PlayerControl(PlayerContainer* container, QObject* parent); + + OrgMprisMediaPlayer2Interface* rootInterface() const + { return m_container->rootInterface(); } + OrgMprisMediaPlayer2PlayerInterface* playerInterface() const + { return m_container->playerInterface(); } + OrgFreedesktopDBusPropertiesInterface* propertiesInterface() const + { return m_container->propertiesInterface(); } + QDBusObjectPath trackId() const; + + Plasma::ServiceJob* createJob(const QString& operation, + QMap& parameters); + +signals: + void enabledOperationsChanged(); + +private slots: + void updateEnabledOperations(); + void containerDestroyed(); + +private: + PlayerContainer *m_container; +}; + +#endif // PLAYERCONTROL_H diff --git a/plasma/generic/dataengines/network/CMakeLists.txt b/plasma/generic/dataengines/network/CMakeLists.txt new file mode 100644 index 00000000..9e3272fd --- /dev/null +++ b/plasma/generic/dataengines/network/CMakeLists.txt @@ -0,0 +1,10 @@ +set(network_engine_SRCS + networkengine.cpp +) + +kde4_add_plugin(plasma_engine_network ${network_engine_SRCS}) +target_link_libraries(plasma_engine_network ${KDE4_KDECORE_LIBS} ${KDE4_PLASMA_LIBS} solidcontrol) + +install(TARGETS plasma_engine_network DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-network.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/plasma/generic/dataengines/network/Messages.sh b/plasma/generic/dataengines/network/Messages.sh new file mode 100755 index 00000000..357360a4 --- /dev/null +++ b/plasma/generic/dataengines/network/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_network.pot diff --git a/plasma/generic/dataengines/network/networkengine.cpp b/plasma/generic/dataengines/network/networkengine.cpp new file mode 100644 index 00000000..63478d9f --- /dev/null +++ b/plasma/generic/dataengines/network/networkengine.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2007 Percy Leonhardt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "networkengine.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +//#define SYSPATH "/sys/class/net/" + +NetworkEngine::NetworkEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args), + m_secondsSinceLastUpdate(0) +{ + Q_UNUSED(args) + setMinimumPollingInterval(1000); +} + +NetworkEngine::~NetworkEngine() +{ +} + +QStringList NetworkEngine::sources() const +{ + Solid::Control::NetworkInterfaceList iflist = Solid::Control::NetworkManager::networkInterfaces(); + + QStringList availableInterfaces; + foreach (Solid::Control::NetworkInterface *iface, iflist) { + availableInterfaces.append(iface->uni().section('/', -1)); + } + return availableInterfaces; +} + +bool NetworkEngine::sourceRequestEvent(const QString &name) +{ + Solid::Control::NetworkInterfaceList iflist = Solid::Control::NetworkManager::networkInterfaces(); + + foreach(Solid::Control::NetworkInterface *iface, iflist) { + if (name == iface->uni().section('/', -1)) { + setData(name, DataEngine::Data()); + setData(name, I18N_NOOP("UNI"), iface->uni()); + updateSourceEvent(name); + return true; + } + } + return false; +} + +bool NetworkEngine::updateSourceEvent(const QString &source) +{ + const QString uni = query(source)[I18N_NOOP("UNI")].toString(); + Solid::Control::NetworkInterface *iface = Solid::Control::NetworkManager::findNetworkInterface(uni); + if (!iface) { + // remove the source as the interface is no longer available + removeSource(source); + return false; + } + + // Check if it is a wireless interface. + bool isWireless = iface->type() == Solid::Control::NetworkInterface::Ieee80211; + setData(source, I18N_NOOP("Wireless"), isWireless); + Solid::Control::WirelessNetworkInterface *wlan = 0; + + if (isWireless) { + wlan = static_cast(iface); + + QStringList availableNetworks; + Solid::Control::AccessPointList apList = wlan->accessPoints(); + foreach (const QString &apId, apList) { + Solid::Control::AccessPoint *ap = wlan->findAccessPoint(apId); + availableNetworks += ap->ssid(); + } + setData(source, I18N_NOOP("Available networks"), availableNetworks); + } + + Solid::Control::NetworkInterface::ConnectionState connectionState = iface->connectionState(); + if (connectionState == Solid::Control::NetworkInterface::Activated) { + // update the interface + updateInterfaceData(source, iface); + if (isWireless) { + updateWirelessData(source, wlan); + } + } else if (connectionState != Solid::Control::NetworkInterface::Activated && + query(source)[I18N_NOOP("ConnectionState")].toString() == I18N_NOOP("Activated")) { + // the interface was disconnected + removeAllData(source); + setData(source, I18N_NOOP("UNI"), uni); + } + + switch (connectionState) { + case Solid::Control::NetworkInterface::Preparing: + setData(source, I18N_NOOP("ConnectionState"), "Preparing"); + break; + case Solid::Control::NetworkInterface::Configuring: + setData(source, I18N_NOOP("ConnectionState"), "Configuring"); + break; + case Solid::Control::NetworkInterface::NeedAuth: + setData(source, I18N_NOOP("ConnectionState"), "NeedAuth"); + break; + case Solid::Control::NetworkInterface::IPConfig: + setData(source, I18N_NOOP("ConnectionState"), "IPConfig"); + break; + case Solid::Control::NetworkInterface::Activated: + setData(source, I18N_NOOP("ConnectionState"), "Activated"); + break; + case Solid::Control::NetworkInterface::Failed: + setData(source, I18N_NOOP("ConnectionState"), "Failed"); + break; + case Solid::Control::NetworkInterface::Unmanaged: + setData(source, I18N_NOOP("ConnectionState"), "Unmanaged"); + break; + case Solid::Control::NetworkInterface::Unavailable: + setData(source, I18N_NOOP("ConnectionState"), "Unavailable"); + break; + default: + setData(source, I18N_NOOP("ConnectionState"), "UnknownState"); + break; + } + return true; +} + +void NetworkEngine::updateInterfaceData(const QString &source, const Solid::Control::NetworkInterface *iface) +{ + Q_ASSERT(iface); + Solid::Control::IPv4Config network = iface->ipV4Config(); + +#if 0 + if (network.isValid()) { + setData(source, I18N_NOOP("Broadcast"), network.broadcast()); + } else { + removeData(source, I18N_NOOP("Broadcast")); + } +#endif + + QList addresses = network.addresses(); + if (addresses.isEmpty()) { + removeData(source, I18N_NOOP("Gateway")); + removeData(source, I18N_NOOP("IP")); + removeData(source, I18N_NOOP("Subnet mask")); + } else { + // FIXME: assumes there is only one network for ethernet + Solid::Control::IPv4Address address = addresses[0]; + setData(source, I18N_NOOP("Gateway"), address.gateway()); + setData(source, I18N_NOOP("IP"), address.address()); + setData(source, I18N_NOOP("Subnet mask"), address.netMask()); + } +} + +void NetworkEngine::updateWirelessData(const QString &source, const Solid::Control::WirelessNetworkInterface *iface) +{ + Q_ASSERT(iface); + const QString currentAP = iface->activeAccessPoint(); + + using namespace Solid::Control; + AccessPoint *ap = iface->findAccessPoint(currentAP); + WirelessNetworkInterface::OperationMode mode(WirelessNetworkInterface::Unassociated); + WirelessNetworkInterface::Capabilities capabilities(WirelessNetworkInterface::NoCapability); + + if (ap) { + setData(source, I18N_NOOP("Link quality"), ap->signalStrength()); + setData(source, I18N_NOOP("Frequency"), ap->frequency()); + setData(source, I18N_NOOP("ESSID"), ap->ssid()); + setData(source, I18N_NOOP("Bitrate"), ap->maxBitRate()); + setData(source, I18N_NOOP("Accesspoint"), ap->hardwareAddress()); + mode = ap->mode(); + } else { + setData(source, I18N_NOOP("Accesspoint"), i18n("None")); + removeData(source, I18N_NOOP("Link quality")); + removeData(source, I18N_NOOP("Frequency")); + removeData(source, I18N_NOOP("ESSID")); + removeData(source, I18N_NOOP("Bitrate")); + } + + switch (mode) { + case WirelessNetworkInterface::Unassociated: + setData(source, I18N_NOOP("Mode"), "Unassociated"); + break; + case WirelessNetworkInterface::Adhoc: + setData(source, I18N_NOOP("Mode"), "Adhoc"); + break; + case WirelessNetworkInterface::Managed: + setData(source, I18N_NOOP("Mode"), "Managed"); + break; + case WirelessNetworkInterface::Master: + setData(source, I18N_NOOP("Mode"), "Master"); + break; + case WirelessNetworkInterface::Repeater: + setData(source, I18N_NOOP("Mode"), "Repeater"); + break; + default: + setData(source, I18N_NOOP("Mode"), i18n("Unknown")); + break; + } + + setData(source, I18N_NOOP("Encryption"), + (capabilities & Solid::Control::AccessPoint::Privacy) != 0); +} + +#include "networkengine.moc" diff --git a/plasma/generic/dataengines/network/networkengine.h b/plasma/generic/dataengines/network/networkengine.h new file mode 100644 index 00000000..e6a63486 --- /dev/null +++ b/plasma/generic/dataengines/network/networkengine.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007 Percy Leonhardt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NETWORKENGINE_H +#define NETWORKENGINE_H + +#include + +namespace Solid +{ + namespace Control + { + class NetworkInterface; + class WirelessNetworkInterface; + } // namespace Control +} // namespace Solid + +class NetworkEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + NetworkEngine(QObject* parent, const QVariantList& args); + ~NetworkEngine(); + + QStringList sources() const; + +protected: + bool sourceRequestEvent(const QString &name); + bool updateSourceEvent(const QString& source); + +private: + void updateWirelessData(const QString &source, const Solid::Control::WirelessNetworkInterface *iface); + void updateInterfaceData(const QString &source, const Solid::Control::NetworkInterface *iface); + + int m_secondsSinceLastUpdate; +}; + +K_EXPORT_PLASMA_DATAENGINE(network, NetworkEngine) + +#endif diff --git a/plasma/generic/dataengines/network/plasma-dataengine-network.desktop b/plasma/generic/dataengines/network/plasma-dataengine-network.desktop new file mode 100644 index 00000000..fa8d2ad0 --- /dev/null +++ b/plasma/generic/dataengines/network/plasma-dataengine-network.desktop @@ -0,0 +1,183 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Networking +Name[ar]=ربط الشبكات +Name[ast]=Rede +Name[be@latin]=Sietka +Name[bg]=Мрежа +Name[bn]=নেটওয়ার্কিং +Name[bn_IN]=নেটওয়ার্ক ব্যবস্থা +Name[bs]=umrežavanje +Name[ca]=Treball en xarxa +Name[ca@valencia]=Treball en xarxa +Name[cs]=Síťové nástroje +Name[csb]=Séc +Name[da]=Netværk +Name[de]=Netzwerk +Name[el]=Δίκτυο +Name[en_GB]=Networking +Name[eo]=Reto +Name[es]=Red +Name[et]=Võrk +Name[eu]=Sarea +Name[fi]=Verkkotyöskentely +Name[fr]=Réseau +Name[fy]=netwurkjen +Name[ga]=Líonrú +Name[gl]=Rede +Name[gu]=નેટવર્કિંગ +Name[he]=רשת +Name[hi]=नेटवर्किंग +Name[hne]=नेटवर्किंग +Name[hr]=Mreža +Name[hu]=Hálózatkezelő +Name[ia]=Networking (A proposito del rete) +Name[id]=Jaringan +Name[is]=Netvinnsla +Name[it]=Rete +Name[ja]=ネットワーキング +Name[kk]=Желі +Name[km]=ការ​តបណ្ដាញ +Name[kn]=ಜಾಲಬಂಧ +Name[ko]=네트워킹 +Name[ku]=Têketina Torê +Name[lt]=Tinklas +Name[lv]=Tīkls +Name[mai]=नेटवर्किंग +Name[mk]=Мрежа +Name[ml]=ശൃംഖല +Name[mr]=नेटवर्कींग +Name[nb]=Nettverk +Name[nds]=Nettwark +Name[nl]=Netwerken +Name[nn]=Nettverk +Name[or]=ନେଟୱର୍କିଙ୍ଗ +Name[pa]=ਨੈੱਟਵਰਕਿੰਗ +Name[pl]=Sieć +Name[pt]=Rede +Name[pt_BR]=Rede +Name[ro]=Rețea +Name[ru]=Сеть +Name[si]=ජාලය +Name[sk]=Sieť +Name[sl]=Povezovanje +Name[sr]=умрежавање +Name[sr@ijekavian]=умрежавање +Name[sr@ijekavianlatin]=umrežavanje +Name[sr@latin]=umrežavanje +Name[sv]=Nätverk +Name[ta]=பிணையம் +Name[tg]=Шабака +Name[th]=ระบบเครือข่าย +Name[tr]=Ağ +Name[ug]=تور +Name[uk]=Робота у мережі +Name[wa]=Rantoelaedje +Name[x-test]=xxNetworkingxx +Name[zh_CN]=网络 +Name[zh_TW]=網路 +Comment=Network interface information +Comment[af]=Netwerk koppelvlak informasie +Comment[ar]=معلومات عن واجهات الشبكة +Comment[as]=নে'টৱৰ্ক সংযোগমাধ্যমৰ তথ্য +Comment[ast]=Información sobre la interface de rede +Comment[be]=Звесткі пра сеткавы інтэрфейс +Comment[be@latin]=Źviestki pra sietkavyja interfejsy +Comment[bg]=Данни за мрежовите интерфейси +Comment[bn]=নেটওয়ার্ক ইন্টারফেস সংক্রান্ত তথ্য +Comment[bn_IN]=নেটওয়ার্ক ইন্টারফেস সংক্রান্ত তথ্য +Comment[br]=Titouroù diwar-benn an etrefasoù rouedad +Comment[bs]=podaci o mrežnom sučelju +Comment[ca]=Informació de la interfície de xarxa +Comment[ca@valencia]=Informació de la interfície de xarxa +Comment[cs]=Informace o síťových rozhraních +Comment[csb]=Wëdowiédzô ò sécowim interfejse +Comment[cy]=Gwybodaeth rhyngwynebau rhwydwaith +Comment[da]=Information om netværksgrænseflade +Comment[de]=Informationen zu Netzwerkschnittstellen +Comment[el]=Πληροφορίες διεπαφών δικτύου +Comment[en_GB]=Network interface information +Comment[eo]=Informoj pri retinterfaco +Comment[es]=Información sobre la interfaz de red +Comment[et]=Võrguliideste info +Comment[eu]=Sare-interfazeari buruzko informazioa +Comment[fa]=اطلاعات واسط شبکه +Comment[fi]=Verkkoliityntöjen tiedot +Comment[fr]=Informations sur les interfaces réseau +Comment[fy]=Netwurkynterface-ynformaasje +Comment[ga]=Eolas faoin gcomhéadan líonra +Comment[gl]=Información da interface de rede +Comment[gu]=નેટવર્ક ઇન્ટરફેસ માહિતી +Comment[he]=מידע על ממשקי רשת +Comment[hi]=नेटवर्क इंटरफेस जानकारी +Comment[hne]=नेटवर्क इंटरफेस जानकारी +Comment[hr]=Podaci o mrežnom sučelju +Comment[hsb]=Informacija wo syćowych interfejsach +Comment[hu]=A hálózati kártyák jellemzői +Comment[ia]=Information de interfacie de rete +Comment[id]=Informasi antarmuka jaringan +Comment[is]=Upplýsingar um netkort +Comment[it]=Informazioni sulle interfacce di rete +Comment[ja]=ネットワークインターフェースの情報 +Comment[ka]=ცნობები ქსელური ინტერფეისების შესახებ +Comment[kk]=Желі интерфейсінің мәліметі +Comment[km]=ព័ត៌មាន​ចំណុច​ប្រទាក់​បណ្ដាញ +Comment[kn]=ಜಾಲ ಸಂಪರ್ಕತಟಗಳ (ಇಂಟರ್ಫೇಸ್) ಮಾಹಿತಿ +Comment[ko]=네트워크 인터페이스 정보 +Comment[ku]=Agahiyên navrûyên torê +Comment[lt]=Tinklo sąsajos informacija +Comment[lv]=Tīkla ierīču informācija +Comment[mai]=नेटवर्क इंटरफेस सूचना +Comment[mk]=Информации за мрежните интерфејси +Comment[ml]=ശൃഖലാ വിനിമയതലങ്ങളെക്കുറിച്ചുള്ള വിവരം +Comment[mr]=संजाळ दुवा माहिती +Comment[ms]=Maklumat antara muka rangkaian +Comment[nb]=Informasjon om nettverksgrensesnitt +Comment[nds]=Informatschoon över de Nettwark-Koppelsteden +Comment[ne]=सञ्जाल इन्टरफेस सूचना +Comment[nl]=Netwerkinterface-informatie +Comment[nn]=Informasjon om nettverksgrensesnitt +Comment[or]=ନେଟୱର୍କ ଅନ୍ତାରାପୃଷ୍ଠ ସୂଚନା +Comment[pa]=ਨੈੱਟਵਰਕ ਇੰਟਰਫੇਸ ਜਾਣਕਾਰੀ +Comment[pl]=Informacje o interfejsach sieciowych +Comment[pt]=Informações sobre as interfaces de rede +Comment[pt_BR]=Informações da interface de rede +Comment[ro]=Afișează informații despre interfețele de rețea +Comment[ru]=Сведения о сетевых интерфейсах +Comment[se]=Fierbmalaktadiehtu +Comment[si]=ජාල මුහුණත් තොරතුරු +Comment[sk]=Informácie o sieťových rozhraniach +Comment[sl]=Podatki o omrežnih vmesnikih +Comment[sr]=Подаци о мрежним сучељима +Comment[sr@ijekavian]=Подаци о мрежним сучељима +Comment[sr@ijekavianlatin]=Podaci o mrežnim sučeljima +Comment[sr@latin]=Podaci o mrežnim sučeljima +Comment[sv]=Information om nätverksgränssnitt +Comment[ta]=பிணைய இடைமுகப்பு தகவல் +Comment[te]=నెట్వర్క్ ఇంటర్ ఫెస్ సమాచారం +Comment[tg]=Иттилооти воситаҳои шабака +Comment[th]=ข้อมูลแผงวงจรเครือข่าย +Comment[tr]=Ağ arayüz bilgisi +Comment[ug]=تور ئارايۈز ئۇچۇرلىرى +Comment[uk]=Інформація щодо інтерфейсів мережі +Comment[uz]=Tarmoq interfeyslari haqida maʼlumot +Comment[uz@cyrillic]=Тармоқ интерфейслари ҳақида маълумот +Comment[vi]=Thông tin giao diện mạng +Comment[wa]=Informåcion so l' eterface rantoele +Comment[xh]=Ulwazi lojongano lomsebenzi womnatha +Comment[x-test]=xxNetwork interface informationxx +Comment[zh_CN]=网络接口信息 +Comment[zh_TW]=網路界面資訊 +ServiceTypes=Plasma/DataEngine +Type=Service +Icon=network-workgroup +X-KDE-Library=plasma_engine_network + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=network +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/notifications/CMakeLists.txt b/plasma/generic/dataengines/notifications/CMakeLists.txt new file mode 100644 index 00000000..cf349715 --- /dev/null +++ b/plasma/generic/dataengines/notifications/CMakeLists.txt @@ -0,0 +1,15 @@ +set(notifications_engine_SRCS + notificationsengine.cpp + notificationservice.cpp + notificationaction.cpp +) + +qt4_add_dbus_adaptor( notifications_engine_SRCS org.freedesktop.Notifications.xml notificationsengine.h NotificationsEngine ) + +kde4_add_plugin(plasma_engine_notifications ${notifications_engine_SRCS}) + +target_link_libraries(plasma_engine_notifications ${KDE4_PLASMA_LIBS} ${KDE4_KDECORE_LIBS} ${KDE4_KNOTIFYCONFIG_LIBRARY}) + +install(TARGETS plasma_engine_notifications DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-notifications.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install(FILES notifications.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) diff --git a/plasma/generic/dataengines/notifications/Messages.sh b/plasma/generic/dataengines/notifications/Messages.sh new file mode 100755 index 00000000..5d52b61d --- /dev/null +++ b/plasma/generic/dataengines/notifications/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_notifications.pot diff --git a/plasma/generic/dataengines/notifications/notificationaction.cpp b/plasma/generic/dataengines/notifications/notificationaction.cpp new file mode 100644 index 00000000..f35bf19f --- /dev/null +++ b/plasma/generic/dataengines/notifications/notificationaction.cpp @@ -0,0 +1,73 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "notificationaction.h" +#include "notificationsengine.h" + +#include + +void NotificationAction::start() +{ + //kDebug() << "Trying to perform the action " << operationName() << " on " << destination(); + //kDebug() << "actionId: " << parameters()["actionId"].toString(); + //kDebug() << "params: " << parameters(); + + if (!m_engine) { + setErrorText(i18n("The notification dataEngine is not set.")); + setError(-1); + emitResult(); + return; + } + + const QStringList dest = destination().split(' '); + + uint id = 0; + if (dest.count() > 1 && !dest[1].toInt()) { + setErrorText(i18n("Invalid destination: %1", destination())); + setError(-2); + emitResult(); + return; + } else if (dest.count() > 1) { + id = dest[1].toUInt(); + } + + if (operationName() == "invokeAction") { + //kDebug() << "invoking action on " << id; + emit m_engine->ActionInvoked(id, parameters()["actionId"].toString()); + } else if (operationName() == "userClosed") { + //userClosedNotification deletes the job, so we have to invoke it queued, in this case emitResult() can be called + m_engine->metaObject()->invokeMethod(m_engine, "userClosedNotification", Qt::QueuedConnection, Q_ARG(uint, id)); + } else if (operationName() == "createNotification") { + int rv = m_engine->createNotification(parameters().value("appName").toString(), + parameters().value("appIcon").toString(), + parameters().value("summary").toString(), + parameters().value("body").toString(), + parameters().value("timeout").toInt(), + false, + QString() + ); + setResult(rv); + } else if (operationName() == "configureNotification") { + m_engine->configureNotification(parameters()["appRealName"].toString()); + } + + emitResult(); +} + +#include "notificationaction.moc" + diff --git a/plasma/generic/dataengines/notifications/notificationaction.h b/plasma/generic/dataengines/notifications/notificationaction.h new file mode 100644 index 00000000..cb084301 --- /dev/null +++ b/plasma/generic/dataengines/notifications/notificationaction.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NOTIFICATIONACTION_H +#define NOTIFICATIONACTION_H + +#include "notificationsengine.h" + +#include + +#include + +class NotificationAction : public Plasma::ServiceJob +{ + Q_OBJECT + + public: + NotificationAction(NotificationsEngine* engine, + const QString& destination, + const QString& operation, + QMap& parameters, + QObject* parent = 0) + : ServiceJob(destination, operation, parameters, parent), + m_engine(engine) + { + } + + void start(); + + private: + NotificationsEngine* m_engine; +}; + +#endif //NOTIFICATIONACTION_H diff --git a/plasma/generic/dataengines/notifications/notifications.operations b/plasma/generic/dataengines/notifications/notifications.operations new file mode 100644 index 00000000..93b7f0c5 --- /dev/null +++ b/plasma/generic/dataengines/notifications/notifications.operations @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/notifications/notificationsengine.cpp b/plasma/generic/dataengines/notifications/notificationsengine.cpp new file mode 100644 index 00000000..5294efac --- /dev/null +++ b/plasma/generic/dataengines/notifications/notificationsengine.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2008 Dmitry Suzdalev + * + * This program is free software you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * 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 "notificationsengine.h" +#include "notificationservice.h" +#include "notificationsadaptor.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +NotificationsEngine::NotificationsEngine( QObject* parent, const QVariantList& args ) + : Plasma::DataEngine( parent, args ), m_nextId( 1 ) +{ + new NotificationsAdaptor(this); + + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerService( "org.freedesktop.Notifications" ); + dbus.registerObject( "/org/freedesktop/Notifications", this ); +} + +NotificationsEngine::~NotificationsEngine() +{ + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.unregisterService( "org.freedesktop.Notifications" ); +} + +void NotificationsEngine::init() +{ +} + +inline void copyLineRGB32(QRgb* dst, const char* src, int width) +{ + const char* end = src + width * 3; + for (; src != end; ++dst, src+=3) { + *dst = qRgb(src[0], src[1], src[2]); + } +} + +inline void copyLineARGB32(QRgb* dst, const char* src, int width) +{ + const char* end = src + width * 4; + for (; src != end; ++dst, src+=4) { + *dst = qRgba(src[0], src[1], src[2], src[3]); + } +} + +static QImage decodeNotificationSpecImageHint(const QDBusArgument& arg) +{ + int width, height, rowStride, hasAlpha, bitsPerSample, channels; + QByteArray pixels; + char* ptr; + char* end; + + arg.beginStructure(); + arg >> width >> height >> rowStride >> hasAlpha >> bitsPerSample >> channels >> pixels; + arg.endStructure(); + //kDebug() << width << height << rowStride << hasAlpha << bitsPerSample << channels; + + #define SANITY_CHECK(condition) \ + if (!(condition)) { \ + kWarning() << "Sanity check failed on" << #condition; \ + return QImage(); \ + } + + SANITY_CHECK(width > 0); + SANITY_CHECK(width < 2048); + SANITY_CHECK(height > 0); + SANITY_CHECK(height < 2048); + SANITY_CHECK(rowStride > 0); + + #undef SANITY_CHECK + + QImage::Format format = QImage::Format_Invalid; + void (*fcn)(QRgb*, const char*, int) = 0; + if (bitsPerSample == 8) { + if (channels == 4) { + format = QImage::Format_ARGB32; + fcn = copyLineARGB32; + } else if (channels == 3) { + format = QImage::Format_RGB32; + fcn = copyLineRGB32; + } + } + if (format == QImage::Format_Invalid) { + kWarning() << "Unsupported image format (hasAlpha:" << hasAlpha << "bitsPerSample:" << bitsPerSample << "channels:" << channels << ")"; + return QImage(); + } + + QImage image(width, height, format); + ptr = pixels.data(); + end = ptr + pixels.length(); + for (int y=0; y end) { + kWarning() << "Image data is incomplete. y:" << y << "height:" << height; + break; + } + fcn((QRgb*)image.scanLine(y), ptr, width); + } + + return image; +} + +static QString findImageForSpecImagePath(const QString &_path) +{ + QString path = _path; + if (path.startsWith(QLatin1String("file:"))) { + KUrl url(path); + path = url.toLocalFile(); + } + return KIconLoader::global()->iconPath(path, -KIconLoader::SizeHuge, + true /* canReturnNull */); +} + +uint NotificationsEngine::Notify(const QString &app_name, uint replaces_id, + const QString &app_icon, const QString &summary, const QString &body, + const QStringList &actions, const QVariantMap &hints, int timeout) +{ + uint id = 0; + id = replaces_id ? replaces_id : m_nextId++; + + QString appname_str = app_name; + if (appname_str.isEmpty()) { + appname_str = i18n("Unknown Application"); + } + + if (timeout == -1) { + const int AVERAGE_WORD_LENGTH = 6; + const int WORD_PER_MINUTE = 250; + int count = summary.length() + body.length(); + timeout = 60000 * count / AVERAGE_WORD_LENGTH / WORD_PER_MINUTE; + + // Add two seconds for the user to notice the notification, and ensure + // it last at least five seconds, otherwise all the user see is a + // flash + timeout = 2000 + qMax(timeout, 3000); + } + + const QString source = QString("notification %1").arg(id); + if (replaces_id) { + Plasma::DataContainer *container = containerForSource(source); + if (container && container->data()["expireTimeout"].toInt() != timeout) { + int timerId = m_sourceTimers.value(source); + killTimer(timerId); + m_sourceTimers.remove(source); + m_timeouts.remove(timerId); + } + } + + Plasma::DataEngine::Data notificationData; + notificationData.insert("id", QString::number(id)); + notificationData.insert("appName", appname_str); + notificationData.insert("appIcon", app_icon); + notificationData.insert("summary", summary); + notificationData.insert("body", body); + notificationData.insert("actions", actions); + notificationData.insert("expireTimeout", timeout); + + QString appRealName; + bool configurable = false; + if (hints.contains("x-kde-appname")) { + appRealName = hints["x-kde-appname"].toString(); + configurable = true; + } + notificationData.insert("appRealName", appRealName); + notificationData.insert("configurable", configurable); + + QImage image; + if (hints.contains("image_data")) { + QDBusArgument arg = hints["image_data"].value(); + image = decodeNotificationSpecImageHint(arg); + } else if (hints.contains("image_path")) { + QString path = findImageForSpecImagePath(hints["image_path"].toString()); + if (!path.isEmpty()) { + image.load(path); + } + } else if (hints.contains("icon_data")) { + // This hint was in use in version 1.0 of the spec but has been + // replaced by "image_data" in version 1.1. We need to support it for + // users of the 1.0 version of the spec. + QDBusArgument arg = hints["icon_data"].value(); + image = decodeNotificationSpecImageHint(arg); + } + notificationData.insert("image", image); + + if (hints.contains("urgency")) { + notificationData.insert("urgency", hints["urgency"].toInt()); + } + + setData(source, notificationData); + + if (timeout) { + int timerId = startTimer(timeout); + m_sourceTimers.insert(source, timerId); + m_timeouts.insert(timerId, source); + } + + return id; +} + +void NotificationsEngine::timerEvent(QTimerEvent *event) +{ + const QString source = m_timeouts.value(event->timerId()); + if (!source.isEmpty()) { + killTimer(event->timerId()); + m_sourceTimers.remove(source); + m_timeouts.remove(event->timerId()); + removeSource(source); + emit NotificationClosed(source.split(" ").last().toInt(), 1); + return; + } + + Plasma::DataEngine::timerEvent(event); +} + +void NotificationsEngine::CloseNotification(uint id) +{ + removeSource(QString("notification %1").arg(id)); + emit NotificationClosed(id, 3); +} + +void NotificationsEngine::userClosedNotification(uint id) +{ + removeSource(QString("notification %1").arg(id)); + emit NotificationClosed(id, 2); +} + +Plasma::Service* NotificationsEngine::serviceForSource(const QString& source) +{ + return new NotificationService(this, source); +} + +QStringList NotificationsEngine::GetCapabilities() +{ + return QStringList() + << "body" + << "body-hyperlinks" + << "body-markup" + << "icon-static" + << "actions" + ; +} + +// FIXME: Signature is ugly +QString NotificationsEngine::GetServerInformation(QString& vendor, QString& version, QString& specVersion) +{ + vendor = "KDE"; + version = "1.0"; // FIXME + specVersion = "1.1"; + return "Plasma"; +} + +int NotificationsEngine::createNotification(const QString &appName, const QString &appIcon, const QString &summary, const QString &body, int timeout, bool configurable, const QString &appRealName) +{ + const QString source = QString("notification %1").arg(++m_nextId); + Plasma::DataEngine::Data notificationData; + notificationData.insert("id", QString::number(m_nextId)); + notificationData.insert("appName", appName); + notificationData.insert("appIcon", appIcon); + notificationData.insert("summary", summary); + notificationData.insert("body", body); + notificationData.insert("expireTimeout", timeout); + notificationData.insert("configurable", configurable); + notificationData.insert("appRealName", appRealName); + + setData(source, notificationData); + return m_nextId; +} + +void NotificationsEngine::configureNotification(const QString &appName) +{ + KNotifyConfigWidget::configure(0, appName); +} + +K_EXPORT_PLASMA_DATAENGINE(notifications, NotificationsEngine) + +#include "notificationsengine.moc" diff --git a/plasma/generic/dataengines/notifications/notificationsengine.h b/plasma/generic/dataengines/notifications/notificationsengine.h new file mode 100644 index 00000000..34d12add --- /dev/null +++ b/plasma/generic/dataengines/notifications/notificationsengine.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 Dmitry Suzdalev + * + * This program is free software you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * 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 NOTIFICATIONSENGINE_H +#define NOTIFICATIONSENGINE_H + +#include + +class QTimer; + +/** + * Engine which provides data sources for notifications. + * Each notification is represented by one source. + */ +class NotificationsEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + NotificationsEngine( QObject* parent, const QVariantList& args ); + ~NotificationsEngine(); + + virtual void init(); + + /** + * This function implements part of Notifications DBus interface. + * Once called, will add notification source to the engine + */ + uint Notify(const QString &app_name, uint replaces_id, const QString &app_icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantMap &hints, int timeout); + + void CloseNotification( uint id ); + + Plasma::Service* serviceForSource(const QString& source); + + QStringList GetCapabilities(); + + QString GetServerInformation(QString& vendor, QString& version, QString& specVersion); + + int createNotification(const QString &appName, const QString &appIcon, const QString &summary, const QString &body, int timeout, bool configurable, const QString &appRealName); + + void configureNotification(const QString &appName); + +public Q_SLOTS: + void userClosedNotification(uint id); + +signals: + void NotificationClosed( uint id, uint reason ); + void ActionInvoked( uint id, const QString& actionKey ); + +protected: + void timerEvent(QTimerEvent *event); + +private: + /** + * Holds the id that will be assigned to the next notification source + * that will be created + */ + uint m_nextId; + QHash m_timeouts; // timerIDs -> sources + QHash m_sourceTimers; // sources -> timerIDs + + friend class NotificationAction; +}; + +#endif diff --git a/plasma/generic/dataengines/notifications/notificationservice.cpp b/plasma/generic/dataengines/notifications/notificationservice.cpp new file mode 100644 index 00000000..b729da98 --- /dev/null +++ b/plasma/generic/dataengines/notifications/notificationservice.cpp @@ -0,0 +1,38 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "notificationservice.h" +#include "notificationaction.h" +#include "notificationsengine.h" + +NotificationService::NotificationService(NotificationsEngine* parent, const QString& source) + : Plasma::Service(parent), + m_notificationEngine(parent) +{ + setName("notifications"); + setDestination(source); +} + +Plasma::ServiceJob* NotificationService::createJob(const QString& operation, + QMap& parameters) +{ + return new NotificationAction(m_notificationEngine, destination(), operation, parameters, this); +} + +#include "notificationservice.moc" + diff --git a/plasma/generic/dataengines/notifications/notificationservice.h b/plasma/generic/dataengines/notifications/notificationservice.h new file mode 100644 index 00000000..d8f5b01f --- /dev/null +++ b/plasma/generic/dataengines/notifications/notificationservice.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NOTIFICATIONSERVICE_H +#define NOTIFICATIONSERVICE_H + +#include + +class NotificationsEngine; + +class NotificationService : public Plasma::Service +{ + Q_OBJECT + + public: + NotificationService(NotificationsEngine* parent, const QString& source); + + protected: + Plasma::ServiceJob* createJob(const QString& operation, + QMap& parameters); + + private: + NotificationsEngine* m_notificationEngine; + +}; + +#endif // NOTIFICATIONSERVICE_H diff --git a/plasma/generic/dataengines/notifications/org.freedesktop.Notifications.xml b/plasma/generic/dataengines/notifications/org.freedesktop.Notifications.xml new file mode 100644 index 00000000..8ddb421c --- /dev/null +++ b/plasma/generic/dataengines/notifications/org.freedesktop.Notifications.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/notifications/plasma-dataengine-notifications.desktop b/plasma/generic/dataengines/notifications/plasma-dataengine-notifications.desktop new file mode 100644 index 00000000..326db505 --- /dev/null +++ b/plasma/generic/dataengines/notifications/plasma-dataengine-notifications.desktop @@ -0,0 +1,150 @@ +[Desktop Entry] +Name=Application Notifications +Name[ar]=تنبيهات التطبيقات +Name[ast]=Notificaciones d'aplicaciones +Name[be@latin]=Infarmavańni aplikacyj +Name[bg]=Програмни съобщения +Name[bn]=অ্যাপলিকেশন বিজ্ঞপ্তি +Name[bn_IN]=অ্যাপ্লিকেশনের সূচনাবার্তা +Name[bs]=obavještenja programa +Name[ca]=Notificacions de les aplicacions +Name[ca@valencia]=Notificacions de les aplicacions +Name[cs]=Oznamování aplikací +Name[csb]=Dôwanié wiédzë ò aplikacëjach +Name[da]=Programbekendtgørelser +Name[de]=Anwendungs-Benachrichtigungen +Name[el]=Ειδοποιήσεις εφαρμογών +Name[en_GB]=Application Notifications +Name[eo]=Aplikaĵaj Atentigoj +Name[es]=Notificaciones de aplicaciones +Name[et]=Rakenduste märguanded +Name[eu]=Aplikazioen jakinarazpenak +Name[fi]=Sovellusilmoitukset +Name[fr]=Notifications des applications +Name[fy]=Applikaasje ntifikaasjes +Name[ga]=Fógairtí Feidhmchláir +Name[gl]=Notificacións dos programas +Name[gu]=કાર્યક્રમ નોંધણીઓ +Name[he]=הודעות יישומים +Name[hi]=अनुप्रयोग सूचनाएँ +Name[hne]=अनुपरयोग सूचना +Name[hr]=Obavijesti aplikacija +Name[hu]=Értesítő üzenetek +Name[ia]=Notificationes de application +Name[id]=Notifikasi Aplikasi +Name[is]=Tilkynningar forrita +Name[it]=Notifiche delle applicazioni +Name[ja]=アプリケーションの通知 +Name[kk]=Қолданба құлақтандырулары +Name[km]=ការ​ជូនដំណឹង​កម្មវិធី​ +Name[kn]=ಅನ್ವಯ ಸೂಚನೆಗಳು +Name[ko]=프로그램 알림 +Name[ku]=Hişyariyên Sepanê +Name[lt]=Programų pranešimai +Name[lv]=Programmu paziņojumi +Name[mk]=Известувања за апликации +Name[ml]=പ്രയോഗ അറിയിപ്പുകള്‍ +Name[mr]=अनुप्रयोग सूचना +Name[nb]=Programvarslinger +Name[nds]=Programm-Bescheden +Name[nl]=Programmameldingen +Name[nn]=Programvarsel +Name[or]=ପ୍ରୟୋଗ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਨੋਟੀਫਿਕੇਸ਼ਨ +Name[pl]=Powiadomienia programów +Name[pt]=Notificações das Aplicações +Name[pt_BR]=Notificações do aplicativo +Name[ro]=Notificări aplicații +Name[ru]=Уведомления приложений +Name[si]=යෙදුම් දැනුම් දීම් +Name[sk]=Upozornenia aplikácií +Name[sl]=Obvestila programov +Name[sr]=обавештења програма +Name[sr@ijekavian]=обавјештења програма +Name[sr@ijekavianlatin]=obavještenja programa +Name[sr@latin]=obaveštenja programa +Name[sv]=Programunderrättelser +Name[ta]=அமைப்பு குறிப்பகள் +Name[tg]=Огоҳномаҳои система +Name[th]=การแจ้งให้ทราบของโปรแกรม +Name[tr]=Uygulama Bildirimleri +Name[ug]=پروگرامما ئۇقتۇرۇشى +Name[uk]=Сповіщення програм +Name[vi]=Thông báo cho ứng dụng +Name[wa]=Notifiaedjes do programe +Name[x-test]=xxApplication Notificationsxx +Name[zh_CN]=应用程序通知 +Name[zh_TW]=應用程式通知 +Comment=Passive visual notifications for the user. +Comment[ar]=إشعارات مرئية غير متفاعلة للمستخدم +Comment[ast]=Notificaciones visuales pasives pal usuariu. +Comment[bg]=Пасивни визуални съобщения за потребителя. +Comment[bs]=Pasivna vizuelna obavještenja za korisnika. +Comment[ca]=Notificacions visuals passives per a l'usuari. +Comment[ca@valencia]=Notificacions visuals passives per a l'usuari. +Comment[cs]=Pasivní vizuální upozornění pro uživatele. +Comment[da]=Passive visuelle bekendtgørelser til brugeren. +Comment[de]=Passive sichtbare Benachrichtigungen für den Anwender. +Comment[el]=Παθητικές οπτικές ειδοποιήσεις για το χρήστη. +Comment[en_GB]=Passive visual notifications for the user. +Comment[es]=Notificaciones visuales pasivas para el usuario. +Comment[et]=Passiivsed visuaalsed märguanded kasutajale. +Comment[eu]=Erabiltzailearentzako ikusizko jakinarazpen pasiboak. +Comment[fi]=Passiivinen visuaali-ilmoitus käyttäjälle. +Comment[fr]=Notifications visuelles passives pour l'utilisateur +Comment[fy]=Pasive fisuele notifikaasje foar de brûker. +Comment[gl]=Notificacións visuais pasivas para o usuario. +Comment[he]=הודעות ויזאוליות פאסיביות עבור המשתמש. +Comment[hr]=Pasivne vizualne obavijesti korisniku. +Comment[hu]=Passzív értesítő üzeneteket tud küldeni a felhasználónak. +Comment[ia]=Notificationes visual passive pro le usator. +Comment[id]=Notifikasi visual pasif untuk pengguna. +Comment[is]=Hlutlausar sjónrænar tilkynningar til notandans. +Comment[it]=Notifiche visuali passive per l'utente. +Comment[ja]=ユーザ用の受動的ビジュアル通知 +Comment[kk]=Үнсіз көрсетілетін құлақтандыру. +Comment[km]=ការ​ជូនដំណឹង​ដែល​មើល​សម្រាប់​អ្នកប្រើ ។ +Comment[kn]=ಬಳಕೆದಾರನ ನಿಷ್ಕ್ರಿಯವಾಗಿರುವ ದೃಶ್ಯ ಸೂಚನೆಗಳು. +Comment[ko]=사용자에게 보이는 수동적인 알림입니다. +Comment[lt]=Pasyvūs vizualūs pranešimai naudotojui. +Comment[lv]=Pasīvi vizuālie paziņojumi lietotājam. +Comment[mk]=Пасивни визуелни известувања за корисникот. +Comment[ml]=ഉപയോക്താവിനുള്ള നടപടി വേണ്ടാത്ത ദൃശ്യ സൂചനകള്‍ +Comment[mr]=वापरकर्त्यासाठी दर्शनीय सूचना. +Comment[nb]=Passive visuelle varslinger for brukeren. +Comment[nds]=Passiev sichtbor Bescheden för den Bruker +Comment[nl]=Passieve visuele meldingen voor de gebruiker. +Comment[nn]=Passive visuelle varsel for brukaren. +Comment[pa]=ਯੂਜ਼ਰ ਲਈ ਪੈਸਿਵ ਦਿੱਖ ਨੋਟੀਫਿਕੇਸ਼ਨ। +Comment[pl]=Bierne, graficzne powiadomienia dla użytkownika. +Comment[pt]=Notificações passivas visuais para o utilizador. +Comment[pt_BR]=Notificações visuais passivas para o usuário. +Comment[ro]=Notificări vizuale pasive pentru utilizator. +Comment[ru]=Пассивные визуальные уведомления для пользователя. +Comment[si]=පරිශීලකයන් සඳහා නිශ්ක්‍රීය දෘශ්‍ය දැන්වීම්. +Comment[sk]=Pasívne vizuálne upozornenia pre užívateľa. +Comment[sl]=Pasivna vidna obvestila za uporabnika. +Comment[sr]=Пасивна визуелна обавештења за корисника. +Comment[sr@ijekavian]=Пасивна визуелна обавјештења за корисника. +Comment[sr@ijekavianlatin]=Pasivna vizuelna obavještenja za korisnika. +Comment[sr@latin]=Pasivna vizuelna obaveštenja za korisnika. +Comment[sv]=Passiva visuella underrättelser för användaren. +Comment[th]=ระบบการแจ้งให้ผู้ใช้งานทราบถึงเหตุการณ์ต่าง ๆ +Comment[tr]=Kullanıcı için pasif görsel bildirimler. +Comment[ug]=ئىشلەتكۈچىگە پاسسىپ كۆرۈنىدىغان كۆرۈش ئۈنۈم ئۇقتۇرۇشىنى تەمىنلەيدۇ +Comment[uk]=Пасивні візуальні сповіщення для користувача. +Comment[wa]=Notifiaedjes doirmants veyåves po l' uzeu. +Comment[x-test]=xxPassive visual notifications for the user.xx +Comment[zh_CN]=为用户提供被动出现的视觉通知。 +Comment[zh_TW]=給使用者的被動視覺通知。 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=preferences-desktop-notification +X-KDE-Library=plasma_engine_notifications + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=notifications +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= diff --git a/plasma/generic/dataengines/nowplaying/CMakeLists.txt b/plasma/generic/dataengines/nowplaying/CMakeLists.txt new file mode 100644 index 00000000..6e1b8c57 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/CMakeLists.txt @@ -0,0 +1,56 @@ +project(plasma-dataengine-nowplaying) + +set(nowplaying_engine_SRCS + nowplayingengine.cpp + playercontrol.cpp + playeractionjob.cpp + playercontainer.cpp + playerinterface/player.cpp + playerinterface/playerfactory.cpp + playerinterface/dbuswatcher.cpp + playerinterface/pollingwatcher.cpp + playerinterface/juk.cpp + playerinterface/mpris/mpris.cpp + playerinterface/mpris/mprisdbustypes.cpp + playerinterface/mpris2/mpris2.cpp +) + +qt4_add_dbus_interface(nowplaying_engine_SRCS playerinterface/org.kde.juk.player.xml juk_interface) + +set(mpris_player_desc playerinterface/mpris/org.freedesktop.MediaPlayer.player.xml) +set_source_files_properties(${mpris_player_desc} PROPERTIES + NO_NAMESPACE true + INCLUDE "playerinterface/mpris/mprisdbustypes.h" + CLASSNAME MprisPlayer +) +qt4_add_dbus_interface(nowplaying_engine_SRCS ${mpris_player_desc} mprisplayer) + +if(GLIB2_FOUND) + macro_optional_find_package(Xmms) + set_package_properties(Xmms PROPERTIES DESCRIPTION "X MultiMedia System development libraries" + URL "http://www.xmms.org" + TYPE OPTIONAL + PURPOSE "Support for XMMS in the Now Playing data engine" + ) + if(XMMS_FOUND) + include_directories(${XMMS_INCLUDE_DIRS}) + include_directories(${GLIB2_INCLUDE_DIR}) + set(nowplaying_engine_SRCS ${nowplaying_engine_SRCS} playerinterface/xmms.cpp) + message(STATUS "Found XMMS: the nowplaying dataengine will support XMMS 1.x") + else(XMMS_FOUND) + message(STATUS "Could NOT find XMMS: the nowplaying dataengine will NOT support XMMS 1.x") + endif(XMMS_FOUND) +endif(GLIB2_FOUND) + +configure_file(config-nowplaying.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-nowplaying.h) + +kde4_add_plugin(plasma_engine_nowplaying ${nowplaying_engine_SRCS}) +target_link_libraries(plasma_engine_nowplaying ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS} ${QT_QTGUI_LIBRARY}) +if(XMMS_FOUND) + target_link_libraries(plasma_engine_nowplaying ${XMMS_LDFLAGS}) +endif(XMMS_FOUND) + +install(TARGETS plasma_engine_nowplaying DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-nowplaying.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES nowplaying.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + diff --git a/plasma/generic/dataengines/nowplaying/Messages.sh b/plasma/generic/dataengines/nowplaying/Messages.sh new file mode 100755 index 00000000..eaac8ef0 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_nowplaying.pot diff --git a/plasma/generic/dataengines/nowplaying/TODO b/plasma/generic/dataengines/nowplaying/TODO new file mode 100644 index 00000000..557902f1 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/TODO @@ -0,0 +1,9 @@ +- add plugin support + - make juk, xmms support plugins +- MPD support +- support players in Kelly's spreadsheet (see panel-devel list) +- VLC pre-DBus support? See /usr/include/vlc/mediacontrol.h +- find a player that exports album artwork, and test +- separate the watchers and plugin bits into a library? +- unify the watchers? +- finish service support diff --git a/plasma/generic/dataengines/nowplaying/config-nowplaying.cmake b/plasma/generic/dataengines/nowplaying/config-nowplaying.cmake new file mode 100644 index 00000000..c5960660 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/config-nowplaying.cmake @@ -0,0 +1 @@ +#cmakedefine XMMS_FOUND diff --git a/plasma/generic/dataengines/nowplaying/nowplaying.operations b/plasma/generic/dataengines/nowplaying/nowplaying.operations new file mode 100644 index 00000000..4a5587d0 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/nowplaying.operations @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/nowplaying/nowplayingengine.cpp b/plasma/generic/dataengines/nowplaying/nowplayingengine.cpp new file mode 100644 index 00000000..620dcb0d --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/nowplayingengine.cpp @@ -0,0 +1,148 @@ +/* + * Copyright 2007 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "nowplayingengine.h" + +#include + +#include + +#include +#include + +#include "playerinterface/player.h" +#include "playerinterface/playerfactory.h" +#include "playerinterface/dbuswatcher.h" +#include "playerinterface/pollingwatcher.h" +#include "playerinterface/mpris/mpris.h" +#include "playerinterface/mpris2/mpris2.h" +#include "playerinterface/juk.h" +#ifdef XMMS_FOUND +#include "playerinterface/xmms.h" +#endif // XMMS_FOUND + +#include "playercontrol.h" +#include "playercontainer.h" + +NowPlayingEngine::NowPlayingEngine(QObject* parent, + const QVariantList& args) + : Plasma::DataEngine(parent), + dbusWatcher(new DBusWatcher(this)), + pollingWatcher(0) +{ + Q_UNUSED(args) + + setData("players", QStringList()); + + kWarning() << "The \"nowplaying\" engine is deprecated; use the \"mpris2\" engine instead"; + + connect(dbusWatcher, SIGNAL(newPlayer(Player::Ptr)), + this, SLOT(addPlayer(Player::Ptr))); + connect(dbusWatcher, SIGNAL(playerDisappeared(Player::Ptr)), + this, SLOT(removePlayer(Player::Ptr))); + + dbusWatcher->addFactory(new Mpris2Factory(dbusWatcher)); + dbusWatcher->addFactory(new MprisFactory(dbusWatcher)); + dbusWatcher->addFactory(new JukFactory(dbusWatcher)); + +#ifdef XMMS_FOUND + pollingWatcher = new PollingWatcher(this); + connect(pollingWatcher, SIGNAL(newPlayer(Player::Ptr)), + this, SLOT(addPlayer(Player::Ptr))); + connect(pollingWatcher, SIGNAL(playerDisappeared(Player::Ptr)), + this, SLOT(removePlayer(Player::Ptr))); + pollingWatcher->addFactory(new XmmsFactory(pollingWatcher)); +#endif +} + +Plasma::Service* NowPlayingEngine::serviceForSource(const QString& source) +{ + PlayerContainer* container = qobject_cast(containerForSource(source)); + if (container) { + return container->service(this); + } else { + return DataEngine::serviceForSource(source); + } +} + + +bool NowPlayingEngine::sourceRequestEvent(const QString& source) +{ + kDebug() << "Source" << source << "was requested"; + if (source == "help") { + setData(source, "Use 'players' to get a list of players.\n" + "Use 'properties' to get a list of all properties that may be returned." + ); + return true; + } else if (source == "properties") { + setData(source, "State", "QString - playing|paused|stopped"); + setData(source, "Artist", "QString - the artist metadata for the\n" + " current track, if available"); + setData(source, "Album", "QString - the album metadata for the\n" + " current track, if available"); + setData(source, "Title", "QString - the title metadata for the\n" + " current track, if available"); + setData(source, "Track number", "int - the album/collection track number\n" + " (eg: on a CD) if known, 0 otherwise"); + setData(source, "Comment", "QString - the comment metadata for the\n" + " current track, if available"); + setData(source, "Genre", "QString - the comment metadata for the\n" + " current track, if available"); + setData(source, "Length", "int - the length of the current track\n" + " in seconds, 0 if unknown"); + setData(source, "Position", "int - the position of the current track\n" + " in seconds, 0 if unknown"); + setData(source, "Volume", "float - the volume, given as a float\n" + " between 0 and 1, or -1 if unknown"); + setData(source, "Artwork", "QPixmap - the album artwork, if available"); + setData(source, "Lyrics", "QString - song lyrics, if available"); + return true; + } + + return false; +} + +void NowPlayingEngine::addPlayer(Player::Ptr player) +{ + kDebug() << "Adding player" << player->name(); + Plasma::DataContainer *container = containerForSource("players"); + QStringList players; + if (container) { + players = container->data()["players"].toStringList(); + } + + players << player->name(); + setData("players", players); + + addSource(new PlayerContainer(player, this)); +} + +void NowPlayingEngine::removePlayer(Player::Ptr player) +{ + kDebug() << "Player" << player->name() << "disappeared"; + Plasma::DataContainer *container = containerForSource("players"); + if (container) { + QStringList players = container->data()["players"].toStringList(); + players.removeAll(player->name()); + setData("players", players); + } + + removeSource(player->name()); +} + +#include "nowplayingengine.moc" diff --git a/plasma/generic/dataengines/nowplaying/nowplayingengine.h b/plasma/generic/dataengines/nowplaying/nowplayingengine.h new file mode 100644 index 00000000..e525b0ae --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/nowplayingengine.h @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NOWPLAYINGENGINE_H +#define NOWPLAYINGENGINE_H + +#include + +#include +#include + +#include "playerinterface/player.h" + +class DBusWatcher; +class PollingWatcher; + +/** + * The Now Playing data engine. + * + * Use plasmaengineexplorer and request the "help" source for more info. + */ +class NowPlayingEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + NowPlayingEngine(QObject* parent, const QVariantList& args); + Plasma::Service* serviceForSource(const QString& source); + +protected: + bool sourceRequestEvent(const QString &source); + +private slots: + void addPlayer(Player::Ptr player); + void removePlayer(Player::Ptr player); + +private: + DBusWatcher* dbusWatcher; + PollingWatcher* pollingWatcher; +}; + +K_EXPORT_PLASMA_DATAENGINE(nowplaying, NowPlayingEngine) + +#endif // NOWPLAYINGENGINE_H diff --git a/plasma/generic/dataengines/nowplaying/plasma-dataengine-nowplaying.desktop b/plasma/generic/dataengines/nowplaying/plasma-dataengine-nowplaying.desktop new file mode 100644 index 00000000..e654732f --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/plasma-dataengine-nowplaying.desktop @@ -0,0 +1,163 @@ +[Desktop Entry] +Name=Now Playing +Name[ar]=المشغلة حالياً +Name[ast]=Reproduciendo +Name[be@latin]=Ciapier hraje +Name[bg]=В момента се слуша +Name[bn]=এখন চলছে +Name[bn_IN]=বর্তমানে চলমান +Name[bs]=trenutna svirka +Name[ca]=Ara està en reproducció +Name[ca@valencia]=Ara està en reproducció +Name[cs]=Nyní přehrávám +Name[csb]=Terô grajë +Name[da]=Afspiller nu +Name[de]=Musiktitel-Anzeige +Name[el]=Αναπαράγεται τώρα +Name[en_GB]=Now Playing +Name[eo]=Nun legas +Name[es]=Reproduciendo +Name[et]=Praegu mängitakse +Name[eu]=Orain jotzen +Name[fa]=اکنون در حال پخش است +Name[fi]=Nyt soi +Name[fr]=En cours de lecture +Name[fy]=Spilet ôf +Name[ga]=Á Sheinm Anois +Name[gl]=Estase a reproducir +Name[gu]=અત્યારે વગાડે છે +Name[he]=מתנגן עכשיו +Name[hi]=अभी बजाया जा रहा है +Name[hne]=अभी बजावत हे +Name[hr]=Trenutno svira +Name[hu]=Most ezt hallgatom +Name[ia]=Ora il reproduce +Name[id]=Saat Ini Diputar +Name[is]=Nú í spilun +Name[ja]=今聴いているもの +Name[kk]=Қазір орындалуда +Name[km]=ឥឡូវ​កំពុង​ចាក់ +Name[kn]=ಪ್ರಸ್ತತ ನಿರೂಪಣೆ +Name[ko]=지금 재생 중 +Name[ku]=Niha lêdêde +Name[lt]=Dabar grojama +Name[lv]=Šobrīd atskaņo +Name[mai]=आब बाजि रहल अछि +Name[mk]=Сега е пуштено +Name[ml]=ഇപ്പോള്‍ പാടുന്നതു് +Name[mr]=आता चालवीत आहे +Name[nb]=Spiller nå +Name[nds]=Lopen Stück +Name[nl]=Speelt nu +Name[nn]=Spelar no +Name[or]=ବର୍ତ୍ତମାନ ଚାଲୁଅଛି +Name[pa]=ਹੁਣ ਚੱਲਦਾ +Name[pl]=Teraz odtwarzany +Name[pt]=Agora a Tocar +Name[pt_BR]=Reproduzindo agora +Name[ro]=În redare +Name[ru]=Сейчас проигрывается +Name[si]=දැන් වාදනය වන්නේ +Name[sk]=Teraz hrá +Name[sl]=Trenutno se predvaja +Name[sr]=тренутна свирка +Name[sr@ijekavian]=тренутна свирка +Name[sr@ijekavianlatin]=trenutna svirka +Name[sr@latin]=trenutna svirka +Name[sv]=Spelar nu +Name[ta]=Now Playing +Name[tg]=Музыка воспроизводимая в данный момент +Name[th]=กำลังเล่นอยู่ +Name[tr]=Şimdi Dinleniyor +Name[ug]=قويۇۋاتىدۇ +Name[uk]=Зараз відтворюється +Name[wa]=Djouwé asteure +Name[x-test]=xxNow Playingxx +Name[zh_CN]=正在收听 +Name[zh_TW]=現正播放 + +Comment=Lists currently playing music +Comment[ar]=تسرد الموسيقى المشغلة حالياً +Comment[ast]=Amuesa la música que ta sonando +Comment[be@latin]=Pakazvaje muzyku, jakuju ciapier hraje systema +Comment[bg]=Списък на текущо възпроизвежданата музика +Comment[bs]=Pokazuje koja muzika trenutno svira +Comment[ca]=Llista la música que s'està reproduint actualment +Comment[ca@valencia]=Llista la música que s'està reproduint actualment +Comment[cs]=Vypíše aktuálně přehrávanou hudbu +Comment[da]=Lister musik som aktuelt afspilles +Comment[de]=Listet die derzeit laufenden Titel auf +Comment[el]=Εμφάνιση της μουσικής που αναπαράγεται αυτήν τη στιγμή +Comment[en_GB]=Lists currently playing music +Comment[eo]=Listigas la nunan muzikon +Comment[es]=Muestra la música que está sonando +Comment[et]=Näitab parajasti esitatavat muusikat +Comment[eu]=Une honetan jotzen ari den musika zerrendatzen du +Comment[fi]=Luettelee parhaillaan soitettavan musiikin +Comment[fr]=Liste les musiques en cours d'écoute +Comment[fy]=Lit de track sjen dy no ôfspile wurdt +Comment[ga]=Taispeánann sé an ceol atá ag seinm faoi láthair +Comment[gl]=Lista a música que está a tocar +Comment[gu]=વાગતું સંગીત દર્શાવે છે +Comment[he]=משמש להצגת המוזיקה המתנגנת כעת +Comment[hi]=मौज़ूदा बज रहे संगीत की सूची +Comment[hne]=अभी जउन संगीत बजत हे वो सूची +Comment[hr]=Prikaz glazbe koja trenutno svira +Comment[hu]=Kiírja a lejátszott számok jellemzőit +Comment[ia]=Il lista le music currentemente reproducite +Comment[id]=Senarai musik yang dimainkan saat ini +Comment[is]=Telur upp hvaða tónlist er verið að spila +Comment[ja]=今聴いているものを表示します +Comment[kk]=Қазір орындалып жатқан әуендер тізімі +Comment[km]=រាយ​តន្ដ្រី​ដែល​កពុង​ចាក់ +Comment[kn]=ಪ್ರಸ್ತುತದಲ್ಲಿ ನಿರೂಪಣೆಯಾಗುತ್ತಿರುವ ಸಂಗೀತವನ್ನು ಪಟ್ಟಿಮಾಡುತ್ತದೆ +Comment[ko]=현재 재생 중인 음악 표시하기 +Comment[lt]=Pateikia dabar grojamos muzikos pavadinimą +Comment[lv]=Parāda pašlaik atskaņoto mūziku +Comment[mk]=Приказ на тековната музика +Comment[ml]=ഇപ്പോള്‍ പാടുന്ന പാട്ടു് കാണിക്കുന്നു. +Comment[mr]=वर्तमानात चालविले जाणाऱ्या संगीताची यादी करतो +Comment[nb]=Vis hvilken musikk som spilles nå +Comment[nds]=Wiest opstunns afspeelt Musik +Comment[nl]=Toont de track die momenteel wordt afgespeeld +Comment[nn]=Oversikt over musikken som vert spela +Comment[pa]=ਇਸ ਸਮੇਂ ਚੱਲਦਾ ਸੰਗੀਤ ਇੰਜਣ +Comment[pl]=Pokazuje obecnie odtwarzany utwór +Comment[pt]=Apresenta a música actualmente em reprodução +Comment[pt_BR]=Lista a música atualmente em reprodução +Comment[ro]=Afișează muzicaaa în curs de redare +Comment[ru]=Звучащее сейчас произведение +Comment[si]=දැන් වාදනය වන සංගීතය දක්වයි +Comment[sk]=Zobrazí aktuálne prehrávanú hudbu +Comment[sl]=Poda skladbo, ki se trenutno predvaja +Comment[sr]=Показује која музика тренутно свира +Comment[sr@ijekavian]=Показује која музика тренутно свира +Comment[sr@ijekavianlatin]=Pokazuje koja muzika trenutno svira +Comment[sr@latin]=Pokazuje koja muzika trenutno svira +Comment[sv]=Listar musik som för närvarande spelas +Comment[ta]=Lists currently playing music +Comment[te]=ప్రస్తుతం ప్లేచేస్తున్న మ్యూజిక్‌ను జాబితాచేస్తోంది +Comment[tg]=Сообщает о воспроизводимой музыке +Comment[th]=เรียกรายการดนตรีที่กำลังเล่นอยู่ในปัจจุบัน +Comment[tr]=O anda dinlenen müziği listeler +Comment[ug]=نۆۋەتتە قويۇلۇۋاتقان نەغمە تىزىمىنى كۆرسىتىدۇ +Comment[uk]=Показує список музики, що відтворюється +Comment[vi]=Liệt kê bài hát hiện đang phát +Comment[wa]=Fwait l' djivêye del muzike djouwêye pol moumint +Comment[x-test]=xxLists currently playing musicxx +Comment[zh_CN]=列出当前正在播放的音乐 +Comment[zh_TW]=列出目前播放的音樂 + +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=applications-multimedia +X-KDE-Library=plasma_engine_nowplaying +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=nowplaying +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License= + diff --git a/plasma/generic/dataengines/nowplaying/playeractionjob.cpp b/plasma/generic/dataengines/nowplaying/playeractionjob.cpp new file mode 100644 index 00000000..0aa1c25d --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playeractionjob.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "playeractionjob.h" + +#include + +void PlayerActionJob::start() +{ + kDebug() << "Trying to perform the action" << operationName(); + if (!m_player) { + setErrorText(i18n("The player '%1' cannot be found.", destination())); + setError(-1); + emitResult(); + return; + } + + const QString operation(operationName()); + if (operation == "play") { + if (m_player->canPlay()) { + m_player->play(); + } else { + setErrorText(i18n("The player '%1' cannot perform the action 'play'.", m_player->name())); + setError(-1); + } + } else if (operation == "pause") { + if (m_player->canPause()) { + m_player->pause(); + } else { + setErrorText(i18n("The player '%1' cannot perform the action 'pause'.", m_player->name())); + setError(-1); + } + } else if (operation == "stop") { + if (m_player->canStop()) { + m_player->stop(); + } else { + setErrorText(i18n("The player '%1' cannot perform the action 'stop'.", m_player->name())); + setError(-1); + } + } else if (operation == "previous") { + if (m_player->canGoPrevious()) { + m_player->previous(); + } else { + setErrorText(i18n("The player '%1' cannot perform the action 'previous'.", m_player->name())); + setError(-1); + } + } else if (operation == "next") { + if (m_player->canGoNext()) { + m_player->next(); + } else { + setErrorText(i18n("The player '%1' cannot perform the action 'next'.", m_player->name())); + setError(-1); + } + } else if (operation == "volume") { + if (m_player->canSetVolume()) { + if (parameters().contains("level")) { + qreal volume = parameters()["level"].toDouble(); + if (volume >= 0.0 && volume <= 1.0) { + m_player->setVolume(volume); + } else { + setErrorText(i18n("The 'level' argument to the 'volume' command must be between 0 and 1.")); + setError(-2); + } + } else { + setErrorText(i18n("The 'volume' command requires a 'level' argument.")); + setError(-2); + } + } else { + setErrorText(i18n("The player '%1' cannot perform the action 'volume'.", m_player->name())); + setError(-1); + } + } else if (operation == "seek") { + if (m_player->canSeek()) { + if (parameters().contains("seconds")) { + qreal time = parameters()["seconds"].toInt(); + if (time >= 0 && time <= m_player->length()) { + m_player->seek(time); + } else { + setErrorText(i18n("The 'seconds' argument to the 'seek' command must be " + "between 0 and the length of the track.")); + setError(-2); + } + } else { + setErrorText(i18n("The 'seek' command requires a 'seconds' argument.")); + setError(-2); + } + } else { + setErrorText(i18n("The player '%1' cannot perform the action 'seek'.", m_player->name())); + setError(-1); + } + } + if (error()) { + kDebug() << "Failed with error" << errorText(); + } + emitResult(); +} + +#include "playeractionjob.moc" + +// vim: sw=4 sts=4 et tw=100 diff --git a/plasma/generic/dataengines/nowplaying/playeractionjob.h b/plasma/generic/dataengines/nowplaying/playeractionjob.h new file mode 100644 index 00000000..2ff24e2b --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playeractionjob.h @@ -0,0 +1,54 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLAYERACTIONJOB_H +#define PLAYERACTIONJOB_H + +#include +#include +#include "playerinterface/player.h" + +#include + +class PlayerActionJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + PlayerActionJob(Player::Ptr player, + const QString& operation, + QMap& parameters, + QObject* parent = 0) + : ServiceJob(player->name(), operation, parameters, parent), + m_player(player) + { + if (player) { + setObjectName("PlayerActionJob: " + player->name() + ": " + operation); + } else { + setObjectName("PlayerActionJob: null player: " + operation); + } + } + + void start(); + +private: + Player::Ptr m_player; +}; + +#endif // PLAYERACTIONJOB_H diff --git a/plasma/generic/dataengines/nowplaying/playercontainer.cpp b/plasma/generic/dataengines/nowplaying/playercontainer.cpp new file mode 100644 index 00000000..490a6d38 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playercontainer.cpp @@ -0,0 +1,82 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "playercontainer.h" + +#include + +#include "playercontrol.h" + +PlayerContainer::PlayerContainer(Player::Ptr player, QObject* parent) + : DataContainer(parent) + , m_player(player) +{ + Q_ASSERT(m_player); + + setObjectName(m_player->name()); + + connect(this, SIGNAL(updateRequested(DataContainer*)), + this, SLOT(updateInfo())); +} + +Plasma::Service* PlayerContainer::service(QObject* parent) +{ + kDebug() << "Creating controller"; + Plasma::Service *controller = new PlayerControl(parent, m_player); + connect(this, SIGNAL(updateRequested(DataContainer*)), + controller, SLOT(updateEnabledOperations())); + return controller; +} + +void PlayerContainer::updateInfo() +{ + if (!m_player->isRunning()) { + kDebug() << objectName() << "isn't running"; + return; + } + + switch(m_player->state()) { + case Player::Playing: + setData("State", "playing"); + break; + case Player::Paused: + setData("State", "paused"); + break; + case Player::Stopped: + setData("State", "stopped"); + break; + } + + setData("Artist", m_player->artist()); + setData("Album", m_player->album()); + setData("Title", m_player->title()); + setData("Track number", m_player->trackNumber()); + setData("Comment", m_player->comment()); + setData("Genre", m_player->genre()); + setData("Lyrics", m_player->lyrics()); + setData("Length", m_player->length()); + setData("Position", m_player->position()); + setData("Volume", m_player->volume()); + setData("Artwork", m_player->artwork()); + + // propagate changes + checkForUpdate(); +} + +#include "playercontainer.moc" diff --git a/plasma/generic/dataengines/nowplaying/playercontainer.h b/plasma/generic/dataengines/nowplaying/playercontainer.h new file mode 100644 index 00000000..950c4448 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playercontainer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLAYERCONTAINER_H +#define PLAYERCONTAINER_H + +#include + +#include "playerinterface/player.h" + +class PlayerControl; + +class PlayerContainer : public Plasma::DataContainer +{ + Q_OBJECT + +public: + explicit PlayerContainer(Player::Ptr player, QObject* parent = 0); + + Plasma::Service* service(QObject* parent = 0); + +public slots: + void updateInfo(); + +private: + Player::Ptr m_player; +}; + +#endif // PLAYERCONTAINER_H diff --git a/plasma/generic/dataengines/nowplaying/playercontrol.cpp b/plasma/generic/dataengines/nowplaying/playercontrol.cpp new file mode 100644 index 00000000..6fca5e1c --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playercontrol.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "playercontrol.h" +#include "playeractionjob.h" + +#include + +PlayerControl::PlayerControl(QObject* parent, Player::Ptr player) + : Plasma::Service(parent), + m_player(player) +{ + setObjectName( QLatin1String("nowplaying controller" )); + setName("nowplaying"); + if (m_player) { + setDestination(m_player->name()); + setObjectName( QLatin1String("nowplaying controller for" ) + m_player->name()); + kDebug() << "Created a player control for" << m_player->name(); + } else { + kDebug() << "Created a dead player control"; + } + updateEnabledOperations(); +} + +void PlayerControl::updateEnabledOperations() +{ + if (m_player) { + /* + kDebug() << "Updating operations:" + << "\n Play:" << m_player->canPlay() + << "\n Pause:" << m_player->canPause() + << "\n Stop:" << m_player->canStop() + << "\n Next:" << m_player->canGoNext() + << "\n Previous:" << m_player->canGoPrevious() + << "\n Volume:" << m_player->canSetVolume() + << "\n Seek:" << m_player->canSeek(); + */ + setOperationEnabled("play", m_player->canPlay()); + setOperationEnabled("pause", m_player->canPause()); + setOperationEnabled("stop", m_player->canStop()); + setOperationEnabled("next", m_player->canGoNext()); + setOperationEnabled("previous", m_player->canGoPrevious()); + setOperationEnabled("volume", m_player->canSetVolume()); + setOperationEnabled("seek", m_player->canSeek()); + } else { + kDebug() << "No player"; + } +} + +Plasma::ServiceJob* PlayerControl::createJob(const QString& operation, + QMap& parameters) +{ + kDebug() << "Job" << operation << "with arguments" << parameters << "requested"; + return new PlayerActionJob(m_player, operation, parameters, this); +} + +#include "playercontrol.moc" + +// vim: sw=4 sts=4 et tw=100 diff --git a/plasma/generic/dataengines/nowplaying/playercontrol.h b/plasma/generic/dataengines/nowplaying/playercontrol.h new file mode 100644 index 00000000..7344b11c --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playercontrol.h @@ -0,0 +1,45 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLAYERCONTROL_H +#define PLAYERCONTROL_H + +#include + +#include "playerinterface/player.h" + +class PlayerControl : public Plasma::Service +{ + Q_OBJECT + +public: + PlayerControl(QObject* parent, Player::Ptr player); + +public slots: + void updateEnabledOperations(); + +protected: + Plasma::ServiceJob* createJob(const QString& operation, + QMap& parameters); + +private: + Player::Ptr m_player; +}; + +#endif // PLAYERCONTROL_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/dbuswatcher.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/dbuswatcher.cpp new file mode 100644 index 00000000..beab52f4 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/dbuswatcher.cpp @@ -0,0 +1,124 @@ +/* + * Copyright 2008 Alex Merry + * + * 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 program. If not, see . + */ +#include "dbuswatcher.h" + +#include "player.h" +#include "playerfactory.h" + +#include +#include + +DBusWatcher::DBusWatcher(QObject* parent) + : QObject(parent), + m_bus(0) +{ + setObjectName( QLatin1String("DBusWatcher" )); + QDBusConnection sessionCon = QDBusConnection::sessionBus(); + if (sessionCon.isConnected()) { + m_bus = sessionCon.interface(); + connect(m_bus, SIGNAL(serviceOwnerChanged(QString,QString,QString)), + this, SLOT(serviceChange(QString,QString,QString))); + } else { + kWarning() << "Couldn't connect to session bus"; + } +} + +QList DBusWatcher::players() +{ + return m_players.values(); +} + +void DBusWatcher::addFactory(DBusPlayerFactory* factory) +{ + m_factories.append(factory); + + QDBusReply reply = m_bus->registeredServiceNames(); + if (reply.isValid()) { + QStringList services = reply.value(); + foreach (const QString &name, services) { + if (factory->matches(name)) { + QDBusReply ownerReply = m_bus->serviceOwner(name); + if (m_players.contains(name)) { + kWarning() << "Two factories tried to claim the same service:" << name; + } else if (ownerReply.isValid()) { + QString owner = ownerReply.value(); + kDebug() << "Service" << name << "has owner" << owner; + if (!m_owners.contains(owner)) { + QVariantList args; + args << QVariant(name); + Player::Ptr player = factory->create(args); + if (!player.isNull()) { + m_players[name] = player; + m_owners << owner; + emit(newPlayer(player)); + } else { + kDebug() << "Failed to get player" << name; + } + } + } + } + } + } else { + kWarning() << "Couldn't get service names:" << reply.error().message(); + } +} + +void DBusWatcher::serviceChange(const QString& name, + const QString& oldOwner, + const QString& newOwner) +{ + if (oldOwner.isEmpty() && !newOwner.isEmpty()) { + kDebug() << "Service" << name << "has owner" << newOwner; + if (m_owners.contains(newOwner)) { + kDebug() << "Owner" << newOwner << "is already being dealt with"; + // something is already dealing with this media player + return; + } + // got a new service + foreach (DBusPlayerFactory* factory, m_factories) { + if (factory->matches(name)) { + if (m_players.contains(name)) { + kWarning() << "Two factories tried to claim the same service:" << name; + } else { + QVariantList args; + args << QVariant(name); + Player::Ptr player = factory->create(args); + if (!player.isNull()) { + m_players[name] = player; + m_owners << newOwner; + emit(newPlayer(player)); + } else { + kDebug() << "Failed to get player" << name << "; trying other factories"; + } + } + } + } + } else if (!oldOwner.isEmpty() && newOwner.isEmpty()) { + m_owners.removeAll(oldOwner); + // an old service disappeared + if (m_players.contains(name)) { + Player::Ptr player = m_players[name]; + m_players.remove(name); + emit(playerDisappeared(player)); + } + } else if (!oldOwner.isEmpty() && !newOwner.isEmpty()) { + if (m_owners.removeAll(oldOwner) > 0) { + kDebug() << "Service" << name << "had owner" << oldOwner << "and is now owned by" << newOwner; + m_owners << newOwner; + } + } +} diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/dbuswatcher.h b/plasma/generic/dataengines/nowplaying/playerinterface/dbuswatcher.h new file mode 100644 index 00000000..38522ef6 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/dbuswatcher.h @@ -0,0 +1,70 @@ +/* + * Copyright 2008 Alex Merry + * + * 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 program. If not, see . + */ + +#ifndef DBUSWATCHER_H +#define DBUSWATCHER_H + +#include +#include +#include + +#include "player.h" + +class QDBusConnectionInterface; +class DBusPlayerFactory; + +class DBusWatcher : public QObject +{ + Q_OBJECT + +public: + DBusWatcher(QObject* parent = 0); + + QList players(); + + /** + * Adds a service to watch for. + * + * @param factory the factory for the player + */ + void addFactory(DBusPlayerFactory* factory); + +Q_SIGNALS: + /** + * A new service appeared on D-Bus + */ + void newPlayer(Player::Ptr player); + /** + * A player disappeared from D-Bus + * + * @param player the now-invalid player + */ + void playerDisappeared(Player::Ptr player); + +private Q_SLOTS: + void serviceChange(const QString& name, + const QString& oldOwner, + const QString& newOwner); + +private: + QStringList m_owners; + QList m_factories; + QHash m_players; + QDBusConnectionInterface* m_bus; +}; + +#endif // DBUSWATCHER_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/juk.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/juk.cpp new file mode 100644 index 00000000..ad3deb69 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/juk.cpp @@ -0,0 +1,244 @@ +/* + * Copyright 2007 Alex Merry + * Copyright 2009 Michael Pyne + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "juk.h" +#include "juk_p.h" +#include + +#include + + +JukFactory::JukFactory(QObject* parent) + : DBusPlayerFactory(parent) +{ + setObjectName( QLatin1String("JukFactory" )); +} + +Player::Ptr JukFactory::create(const QVariantList& args) +{ + Q_UNUSED(args); + + Juk* player = new Juk(this); + if (!player->isRunning()) { + delete player; + player = 0; + } + return Player::Ptr(player); +} + +bool JukFactory::matches(const QString& serviceName) +{ + return serviceName == "org.kde.juk"; +} + + + + + +Juk::Juk(PlayerFactory* factory) + : Player(factory), + jukPlayer(new JukPlayer("org.kde.juk", "/Player", + QDBusConnection::sessionBus())) +{ + setName("JuK"); +} + +Juk::~Juk() +{ + delete jukPlayer; +} + +bool Juk::isRunning() +{ + if (!jukPlayer->isValid()) { + delete jukPlayer; + jukPlayer = new JukPlayer("org.kde.juk", "/Player", + QDBusConnection::sessionBus()); + } + return jukPlayer->isValid(); +} + +Player::State Juk::state() +{ + if (jukPlayer->isValid()) { + if (jukPlayer->playing()) { + return Playing; + } + if (jukPlayer->paused()) { + return Paused; + } + } + return Stopped; +} + +QString Juk::artist() +{ + if (jukPlayer->isValid()) { + return jukPlayer->trackProperty("Artist"); + } + return QString(); +} + +QString Juk::album() +{ + if (jukPlayer->isValid()) { + return jukPlayer->trackProperty("Album"); + } + return QString(); +} + +QString Juk::title() +{ + if (jukPlayer->isValid()) { + return jukPlayer->trackProperty("Title"); + } + return QString(); +} + +int Juk::trackNumber() +{ + if (jukPlayer->isValid()) { + return jukPlayer->trackProperty("Track").value().toInt(); + } + return 0; +} + +QString Juk::comment() +{ + if (jukPlayer->isValid()) { + return jukPlayer->trackProperty("Comment"); + } + return QString(); +} + +QString Juk::genre() +{ + if (jukPlayer->isValid()) { + return jukPlayer->trackProperty("Genre"); + } + return QString(); +} + +int Juk::length() +{ + if (jukPlayer->isValid()) { + return jukPlayer->totalTime(); + } + return 0; +} + +int Juk::position() +{ + if (jukPlayer->isValid()) { + return jukPlayer->currentTime(); + } + return 0; +} + +float Juk::volume() +{ + if (jukPlayer->isValid()) { + return jukPlayer->volume(); + } + return 0; +} + +void Juk::play() +{ + if (jukPlayer->isValid()) { + jukPlayer->play(); + } +} + +void Juk::pause() +{ + if (jukPlayer->isValid()) { + jukPlayer->pause(); + } +} + +void Juk::stop() +{ + if (jukPlayer->isValid()) { + jukPlayer->stop(); + } +} + +void Juk::previous() +{ + if (jukPlayer->isValid()) { + jukPlayer->back(); + } +} + +void Juk::next() +{ + if (jukPlayer->isValid()) { + jukPlayer->forward(); + } +} + +void Juk::setVolume(qreal volume) { + if (jukPlayer->isValid()) { + jukPlayer->setVolume(volume); + } +} + +QPixmap Juk::artwork() +{ + if(!jukPlayer->isValid()) + return QPixmap(); + + QString playingPath = jukPlayer->trackProperty("Path"); + + // Caching is employed since some players have to make temp files for + // their cover art. If we were to grab a cover once per second that + // could be disastrous. + if(playingPath == m_lastPath) + return m_artwork; + + m_lastPath = playingPath; + if(playingPath.isEmpty()) { + m_artwork = QPixmap(); + return m_artwork; + } + + // JuK only supports this method starting from KDE 4.3 + QDBusInterface collectionIface("org.kde.juk", "/Collection", "org.kde.juk.collection"); + QDBusReply reply = collectionIface.call("trackCover", playingPath); + + if(reply.isValid() && !reply.value().isEmpty()) { + m_artwork = QPixmap(reply.value()); + return m_artwork; + } + + m_artwork = QPixmap(); + return m_artwork; +} + +void Juk::seek(int time) +{ + if (jukPlayer->isValid()) { + // jukPlayer->seek() wants milliseconds + jukPlayer->seek(time * 1000); + } +} + + +#include "juk.moc" diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/juk.h b/plasma/generic/dataengines/nowplaying/playerinterface/juk.h new file mode 100644 index 00000000..5f446189 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/juk.h @@ -0,0 +1,35 @@ +/* + * Copyright 2007 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef JUK_H +#define JUK_H + +#include "playerfactory.h" + +class JukFactory : public DBusPlayerFactory +{ + Q_OBJECT + +public: + explicit JukFactory(QObject* parent = 0); + Player::Ptr create(const QVariantList& args = QVariantList()); + bool matches(const QString& serviceName); +}; + + +#endif // JUK_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/juk_p.h b/plasma/generic/dataengines/nowplaying/playerinterface/juk_p.h new file mode 100644 index 00000000..d8f672c7 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/juk_p.h @@ -0,0 +1,75 @@ +/* + * Copyright 2008 Alex Merry + * + * 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 program. If not, see . + */ +#ifndef JUK_P_H +#define JUK_P_H + +#include "juk.h" +#include "player.h" + +#include +#include +#include + +class OrgKdeJukPlayerInterface; + + + +class Juk : public Player +{ +public: + Juk(PlayerFactory* factory = 0); + ~Juk(); + + bool isRunning(); + State state(); + QString artist(); + QString album(); + QString title(); + int trackNumber(); + QString comment(); + QString genre(); + int length(); + int position(); + float volume(); + + bool canPlay() { return state() != Playing; } + void play(); + bool canPause() { return true; } + void pause(); + bool canStop() { return state() != Stopped; } + void stop(); + bool canGoPrevious() { return true; } + void previous(); + bool canGoNext() { return true; } + void next(); + + bool canSetVolume() { return true; } + void setVolume(qreal volume); + + QPixmap artwork(); + + bool canSeek() { return state() != Stopped; } + void seek(int time); + +private: + QPixmap m_artwork; + QString m_lastPath; + typedef OrgKdeJukPlayerInterface JukPlayer; + JukPlayer* jukPlayer; +}; + +#endif // JUK_P_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris.cpp new file mode 100644 index 00000000..4bed1b12 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris.cpp @@ -0,0 +1,396 @@ +/* + * Copyright 2007 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mpris.h" +#include "mpris_p.h" +#include + +#include +#include + +#include +#include + + + +MprisFactory::MprisFactory(QObject* parent) + : DBusPlayerFactory(parent) +{ + setObjectName( QLatin1String("MprisFactory" )); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); +} + +Player::Ptr MprisFactory::create(const QVariantList& args) +{ + if (args.isEmpty()) { + return Player::Ptr(0); + } + + QString dbusName(args.first().toString()); + if (dbusName.isEmpty()) { + return Player::Ptr(0); + } + + Mpris* player = new Mpris(dbusName, this); + if (!player->isRunning()) { + delete player; + player = 0; + } + + return Player::Ptr(player); +} + +bool MprisFactory::matches(const QString& serviceName) +{ + return serviceName.startsWith(QLatin1String("org.mpris")) && + !serviceName.startsWith(QLatin1String("org.mpris.MediaPlayer2")); +} + + + +Mpris::Mpris(const QString& name, PlayerFactory* factory) + : QObject(), + Player(factory), + m_player(0), + m_playerName(name), + m_artworkLoaded(false) +{ + if (!name.startsWith(QLatin1String("org.mpris"))) { + m_playerName = "org.mpris." + name; + } + setName(m_playerName); + setup(); +} + +Mpris::~Mpris() +{ + delete m_player; +} + +void Mpris::setup() +{ + delete m_player; + m_player = new MprisPlayer( + m_playerName, + "/Player", + QDBusConnection::sessionBus()); + + m_metadata.clear(); + m_state = Stopped; + m_caps = NO_CAPS; + + if (m_player->isValid()) { + connect(m_player, SIGNAL(CapsChange(int)), + this, SLOT(capsChanged(int))); + connect(m_player, SIGNAL(TrackChange(QVariantMap)), + this, SLOT(trackChanged(QVariantMap))); + connect(m_player, SIGNAL(StatusChange(MprisDBusStatus)), + this, SLOT(stateChanged(MprisDBusStatus))); + + QDBusReply caps = m_player->GetCaps(); + if (caps.isValid()) { + capsChanged(caps); + } + + QDBusReply metadata = m_player->GetMetadata(); + if (metadata.isValid()) { + trackChanged(metadata); + } + + QDBusReply status = m_player->GetStatus(); + if (status.isValid()) { + stateChanged(status); + } + } +} + +bool Mpris::isRunning() +{ + if (!m_player->isValid()) { + setup(); + } + + return m_player->isValid(); +} + +Player::State Mpris::state() +{ + return m_state; +} + +QString Mpris::artist() +{ + if (m_metadata.contains("artist")) { + return m_metadata["artist"].toString(); + } + return QString(); +} + +QString Mpris::album() +{ + if (m_metadata.contains("album")) { + return m_metadata["album"].toString(); + } + return QString(); +} + +QString Mpris::title() +{ + if (m_metadata.contains("title")) { + return m_metadata["title"].toString(); + } + return QString(); +} + +int Mpris::trackNumber() +{ + QVariant track; + if (m_metadata.contains("trackNumber")) { + track = m_metadata["trackNumber"]; + } else if (m_metadata.contains("tracknumber")) { + track = m_metadata["tracknumber"]; + } + if (track.isValid()) { + if (track.canConvert(QVariant::Int)) { + return track.toInt(); + } else { + QString text = track.toString(); + int pos = text.indexOf('/'); + if (pos >= 0) { + text.truncate(pos); + } + return text.toInt(); + } + } + return 0; +} + +QString Mpris::comment() +{ + if (m_metadata.contains("comment")) { + return m_metadata["comment"].toString(); + } + return QString(); +} + +QString Mpris::genre() +{ + if (m_metadata.contains("genre")) { + return m_metadata["genre"].toString(); + } + return QString(); +} + +QString Mpris::lyrics() +{ + if (m_metadata.contains("lyrics")) { + return m_metadata["lyrics"].toString(); + } + return QString(); +} + +int Mpris::length() +{ + if (m_metadata.contains("time")) { + return m_metadata["time"].toInt(); + } else if (m_metadata.contains("length")) { + // stupid audacious... + return m_metadata["length"].toInt()/1000; + } + return 0; +} + +int Mpris::position() +{ + if (m_player->isValid()) { + QDBusReply positionMs = m_player->PositionGet(); + if (positionMs.isValid()) { + return positionMs / 1000; + } + } + return 0; +} + +float Mpris::volume() +{ + if (m_player->isValid()) { + QDBusReply volumePercent = m_player->VolumeGet(); + if (volumePercent.isValid()) + return ((float)volumePercent) / 100; + } + return 0; +} + +QPixmap Mpris::artwork() +{ + if (m_artworkLoaded) { + return m_artwork; + } + + m_artwork = QPixmap(); + const QString arturl = m_metadata["arturl"].toString(); + if (!arturl.isEmpty()) { + if (!m_artfiles.contains(arturl) || + (!m_artfiles[arturl].isEmpty() && !QFile::exists(m_artfiles[arturl]))) { + QString artfile; + if (!KIO::NetAccess::download(arturl, artfile, 0)) { + kWarning() << KIO::NetAccess::lastErrorString(); + artfile.clear(); + } + + m_artfiles[arturl] = artfile; + } + + const QString url = m_artfiles[arturl]; + if (!url.isEmpty()) { + m_artwork = QPixmap(url); + } + } + + m_artworkLoaded = true; + return m_artwork; +} + +bool Mpris::canPlay() +{ + return m_caps & CAN_PLAY; +} + +void Mpris::play() +{ + if (m_player->isValid()) { + m_player->Play(); + } +} + +bool Mpris::canPause() +{ + return m_caps & CAN_PAUSE; +} + +void Mpris::pause() +{ + if (m_player->isValid()) { + m_player->Pause(); + } +} + +bool Mpris::canStop() +{ + return m_state != Stopped; +} + +void Mpris::stop() +{ + if (m_player->isValid()) { + m_player->Stop(); + } +} + +bool Mpris::canGoPrevious() +{ + return m_caps & CAN_GO_PREV; +} + +void Mpris::previous() +{ + if (m_player->isValid()) { + m_player->Prev(); + } +} + +bool Mpris::canGoNext() +{ + return m_caps & CAN_GO_NEXT; +} + +void Mpris::next() +{ + if (m_player->isValid()) { + m_player->Next(); + } +} + +bool Mpris::canSetVolume() +{ + return true; +} + +void Mpris::setVolume(qreal volume) +{ + if (m_player->isValid()) { + m_player->VolumeSet((int)(volume * 100)); + } +} + +bool Mpris::canSeek() +{ + return m_caps & CAN_SEEK; +} + +void Mpris::seek(int time) +{ + if (m_player->isValid()) { + // m_player->seek() wants milliseconds + m_player->PositionSet(time * 1000); + } +} + +// SLOTS + +void Mpris::trackChanged(const QVariantMap& metadata) +{ + //kDebug() << m_playerName << "metadata:" << metadata; + const QString oldArt = m_metadata.value("arturl").toString(); + m_metadata = metadata; + if (m_artworkLoaded) { + m_artworkLoaded = oldArt == m_metadata.value("arturl"); + } +} + +void Mpris::stateChanged(MprisDBusStatus state) +{ + kDebug() << m_playerName << "state:" << state.play; + switch (state.play) { + case MprisDBusStatus::Playing: + m_state = Playing; + break; + case MprisDBusStatus::Paused: + m_state = Paused; + break; + case MprisDBusStatus::Stopped: + m_state = Stopped; + break; + default: + kDebug() << m_playerName << "unexpected state" << state.play; + } +} + +void Mpris::capsChanged(int caps) +{ + kDebug() << m_playerName << "capabilities:" << caps; + m_caps = (DBusCaps)caps; + if (!(caps & CAN_PROVIDE_METADATA)) { + m_metadata.clear(); + } +} + + +#include "mpris.moc" +#include "mpris_p.moc" diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris.h b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris.h new file mode 100644 index 00000000..cb8cf83b --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris.h @@ -0,0 +1,34 @@ +/* + * Copyright 2007 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MPRIS_H +#define MPRIS_H + +#include "../playerfactory.h" + +class MprisFactory : public DBusPlayerFactory +{ + Q_OBJECT + +public: + explicit MprisFactory(QObject* parent = 0); + Player::Ptr create(const QVariantList& args = QVariantList()); + bool matches(const QString& serviceName); +}; + +#endif // MPRIS_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris_p.h b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris_p.h new file mode 100644 index 00000000..d8c3121c --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mpris_p.h @@ -0,0 +1,89 @@ +/* + * Copyright 2008 Alex Merry + * + * 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 program. If not, see . + */ +#ifndef MPRIS_P_H +#define MPRIS_P_H + +#include "mpris.h" +#include "mprisdbustypes.h" +#include "../player.h" + +#include + +class MprisPlayer; + +class Mpris : public QObject, public Player +{ + Q_OBJECT + +public: + /** + * @param name the media player name. + */ + explicit Mpris(const QString& name, + PlayerFactory* factory = 0); + ~Mpris(); + + bool isRunning(); + State state(); + QString artist(); + QString album(); + QString title(); + int trackNumber(); + QString comment(); + QString genre(); + QString lyrics(); + int length(); + int position(); + float volume(); + QPixmap artwork(); + + bool canPlay(); + void play(); + bool canPause(); + void pause(); + bool canStop(); + void stop(); + bool canGoPrevious(); + void previous(); + bool canGoNext(); + void next(); + + bool canSetVolume(); + void setVolume(qreal volume); + + bool canSeek(); + void seek(int time); + +private Q_SLOTS: + void trackChanged(const QVariantMap& metadata); + void stateChanged(MprisDBusStatus state); + void capsChanged(int caps); + +private: + void setup(); + MprisPlayer* m_player; + + QString m_playerName; + QVariantMap m_metadata; + State m_state; + DBusCaps m_caps; + QMap m_artfiles; + bool m_artworkLoaded; + QPixmap m_artwork; +}; + +#endif // MPRIS_P_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mprisdbustypes.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mprisdbustypes.cpp new file mode 100644 index 00000000..2d42a50c --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mprisdbustypes.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2008 Alex Merry + * + * 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, see . + */ +#include "mprisdbustypes.h" + +// Marshall the MprisDBusVersion data into a D-BUS argument +QDBusArgument &operator<<(QDBusArgument &argument, const MprisDBusVersion &version) +{ + argument.beginStructure(); + argument << version.major << version.minor; + argument.endStructure(); + return argument; +} + +// Retrieve the MprisDBusVersion data from the D-BUS argument +const QDBusArgument &operator>>(const QDBusArgument &argument, MprisDBusVersion &version) +{ + argument.beginStructure(); + argument >> version.major >> version.minor; + argument.endStructure(); + return argument; +} + +// Marshall the MprisDBusStatus data into a D-BUS argument +QDBusArgument &operator<<(QDBusArgument &argument, const MprisDBusStatus &status) +{ + argument.beginStructure(); + argument << (qint32)status.play; + argument << (qint32)status.random; + argument << (qint32)status.trackRepeat; + argument << (qint32)status.playlistRepeat; + argument.endStructure(); + return argument; +} + +// Retrieve the MprisDBusStatus data from the D-BUS argument +const QDBusArgument &operator>>(const QDBusArgument &argument, MprisDBusStatus &status) +{ + qint32 play, random, trackRepeat, playlistRepeat; + + argument.beginStructure(); + argument >> play; + argument >> random; + argument >> trackRepeat; + argument >> playlistRepeat; + argument.endStructure(); + + status.play = (MprisDBusStatus::PlayMode)play; + status.random = (MprisDBusStatus::RandomMode)random; + status.trackRepeat = (MprisDBusStatus::TrackRepeatMode)trackRepeat; + status.playlistRepeat = (MprisDBusStatus::PlaylistRepeatMode)playlistRepeat; + + return argument; +} + +// vim: sw=4 sts=4 et tw=100 diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mprisdbustypes.h b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mprisdbustypes.h new file mode 100644 index 00000000..325f3e49 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/mprisdbustypes.h @@ -0,0 +1,79 @@ +#ifndef MPRISDEFS_H +#define MPRISDEFS_H + +#include + +enum DBusCaps { + NO_CAPS = 0, + CAN_GO_NEXT = 1 << 0, + CAN_GO_PREV = 1 << 1, + CAN_PAUSE = 1 << 2, + CAN_PLAY = 1 << 3, + CAN_SEEK = 1 << 4, + CAN_PROVIDE_METADATA = 1 << 5, + CAN_HAS_TRACKLIST = 1 << 6, + UNKNOWN_CAP = 1 << 7 +}; + + +struct MprisDBusVersion +{ + quint16 major; + quint16 minor; +}; + +Q_DECLARE_METATYPE(MprisDBusVersion) + +// Marshall the MprisDBusVersion data into a D-BUS argument +QDBusArgument &operator<<(QDBusArgument &argument, const MprisDBusVersion &version); +// Retrieve the MprisDBusVersion data from the D-BUS argument +const QDBusArgument &operator>>(const QDBusArgument &argument, MprisDBusVersion &version); + + +struct MprisDBusStatus +{ + enum PlayMode { + Playing = 0, + Paused = 1, + Stopped = 2 + }; + + enum RandomMode { + Linear = 0, + Random = 1 + }; + + enum TrackRepeatMode { + GoToNext = 0, + RepeatCurrent = 1 + }; + + enum PlaylistRepeatMode { + StopWhenFinished = 0, + PlayForever = 1 + }; + + MprisDBusStatus(PlayMode _play = Stopped, + RandomMode _random = Linear, + TrackRepeatMode _trackRepeat = GoToNext, + PlaylistRepeatMode _playlistRepeat = StopWhenFinished) + : play(_play), + random(_random), + trackRepeat(_trackRepeat), + playlistRepeat(_playlistRepeat) + { + } + PlayMode play; + RandomMode random; + TrackRepeatMode trackRepeat; + PlaylistRepeatMode playlistRepeat; +}; + +Q_DECLARE_METATYPE(MprisDBusStatus) + +// Marshall the MprisDBusStatus data into a D-BUS argument +QDBusArgument &operator<<(QDBusArgument &argument, const MprisDBusStatus &status); +// Retrieve the MprisDBusStatus data from the D-BUS argument +const QDBusArgument &operator>>(const QDBusArgument &argument, MprisDBusStatus &status); + +#endif // MPRISDEFS_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.player.xml b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.player.xml new file mode 100644 index 00000000..302c3830 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.player.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.root.xml b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.root.xml new file mode 100644 index 00000000..aa93e4bd --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.root.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.tracklist.xml b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.tracklist.xml new file mode 100644 index 00000000..e8cb127b --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris/org.freedesktop.MediaPlayer.tracklist.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2.cpp new file mode 100644 index 00000000..b28378da --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2.cpp @@ -0,0 +1,500 @@ +/* + * Copyright 2011 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mpris2.h" +#include "mpris2_p.h" + +#include +#include +#include + +#include +#include + +#define MPRIS2_PATH "/org/mpris/MediaPlayer2" +#define MPRIS2_ROOT_IFACE "org.mpris.MediaPlayer2" +#define MPRIS2_PLAYER_IFACE "org.mpris.MediaPlayer2.Player" +#define DBUS_PROPS_IFACE "org.freedesktop.DBus.Properties" + +Mpris2Factory::Mpris2Factory(QObject* parent) + : DBusPlayerFactory(parent) +{ + setObjectName( QLatin1String("Mpris2Factory" )); +} + +Player::Ptr Mpris2Factory::create(const QVariantList& args) +{ + if (args.isEmpty()) { + return Player::Ptr(0); + } + + QString dbusName(args.first().toString()); + if (dbusName.isEmpty()) { + return Player::Ptr(0); + } + + Mpris2* player = new Mpris2(dbusName, this); + if (!player->isRunning()) { + delete player; + player = 0; + } + + return Player::Ptr(player); +} + +bool Mpris2Factory::matches(const QString& serviceName) +{ + return serviceName.startsWith(QLatin1String("org.mpris.MediaPlayer2.")); +} + + + +Mpris2::Mpris2(const QString& name, PlayerFactory* factory) + : QObject(), + Player(factory), + rootIface(0), + playerIface(0), + propsIface(0), + m_pos(0), + m_rate(0), + m_currentRate(0), + m_playerName(name), + m_volume(0.0f), + m_state(Stopped), + m_canControl(false), + m_canPlay(false), + m_canPause(false), + m_canGoPrevious(false), + m_canGoNext(false), + m_canSeek(false), + m_artworkLoaded(false) +{ + if (!name.startsWith(QLatin1String("org.mpris.MediaPlayer2."))) { + m_playerName = "org.mpris.MediaPlayer2." + name; + } + setName(m_playerName); + setup(); +} + +Mpris2::~Mpris2() +{ +} + +static Mpris2::State playbackStatusToState(const QString &status) +{ + if (status == "Playing") { + return Mpris2::Playing; + } else if (status == "Paused") { + return Mpris2::Paused; + } else { + return Mpris2::Stopped; + } +} + +static QVariantMap demarshallMetadata(const QVariant &value) +{ + if (!value.canConvert()) { + const char * gotTypeCh = QDBusMetaType::typeToSignature(value.userType()); + QString gotType = gotTypeCh ? QString::fromAscii(gotTypeCh) : ""; + kDebug() << "Expected variant containing a QDBusArgument, got ready-demarshalled item of type" << gotType; + return QVariantMap(); + } + QVariantMap metadata; + QDBusArgument arg = value.value(); + arg >> metadata; + return metadata; +} + +void Mpris2::updatePosition(qreal rate) +{ + QDBusReply reply = propsIface->call("Get", MPRIS2_PLAYER_IFACE, "Position"); + if (!reply.isValid()) { + kDebug() << DBUS_PROPS_IFACE ".Get(\"" MPRIS2_PLAYER_IFACE "\", \"Position\") failed at " + MPRIS2_PATH " on" << m_playerName << " with error " << + reply.error().name(); + m_pos = position(); + } else { + m_pos = reply.value().variant().toLongLong() / 1000L; + } + m_posLastUpdated = QDateTime::currentDateTime().toUTC(); + m_rate = rate; + m_currentRate = (m_state == Playing) ? m_rate : 0.0; +} + +bool Mpris2::getAllProps() +{ + QDBusReply identityReply = propsIface->call("Get", MPRIS2_ROOT_IFACE, "Identity"); + if (!identityReply.isValid()) { + kDebug() << DBUS_PROPS_IFACE ".Get(\"" MPRIS2_ROOT_IFACE "\", \"Identity\") failed at " + MPRIS2_PATH " on" << m_playerName << " with error " << + identityReply.error().name(); + return false; + } + m_identity = identityReply.value().variant().toString(); + if (m_identity.isEmpty()) { + kDebug() << "Empty player identity; giving up"; + return false; + } + + QDBusReply playerPropsReply = propsIface->call("GetAll", MPRIS2_PLAYER_IFACE); + if (!playerPropsReply.isValid()) { + kDebug() << DBUS_PROPS_IFACE ".GetAll(\"" MPRIS2_PLAYER_IFACE "\") failed at " + MPRIS2_PATH " on" << m_playerName << " with error " << + playerPropsReply.error().name(); + return false; + } + m_posLastUpdated = QDateTime::currentDateTime().toUTC(); + + QVariantMap props = playerPropsReply.value(); + m_state = playbackStatusToState(props.value("PlaybackStatus").toString()); + m_metadata = demarshallMetadata(props.value("Metadata")); + m_volume = props.value("Volume").toDouble(); + m_canControl = props.value("CanControl").toBool(); + m_canPlay = m_canControl && props.value("CanPlay").toBool(); + m_canPause = m_canControl && props.value("CanPause").toBool(); + m_canGoPrevious = m_canControl && props.value("CanGoPrevious").toBool(); + m_canGoNext = m_canControl && props.value("CanGoNext").toBool(); + m_canSeek = m_canControl && props.value("CanSeek").toBool(); + m_pos = props.value("Position").toLongLong() / 1000L; + m_rate = props.value("Rate").toDouble(); + m_currentRate = (m_state == Playing) ? m_rate : 0.0; + + return true; +} + +void Mpris2::setup() +{ + delete propsIface; + delete rootIface; + delete playerIface; + + propsIface = new QDBusInterface(m_playerName, MPRIS2_PATH, DBUS_PROPS_IFACE, QDBusConnection::sessionBus(), this); + rootIface = new QDBusInterface(m_playerName, MPRIS2_PATH, MPRIS2_ROOT_IFACE, QDBusConnection::sessionBus(), this); + playerIface = new QDBusInterface(m_playerName, MPRIS2_PATH, MPRIS2_PLAYER_IFACE, QDBusConnection::sessionBus(), this); + + if (getAllProps()) { + QDBusConnection::sessionBus().connect( + playerIface->service(), + playerIface->path(), + playerIface->interface(), + "Seeked", /* signature, */ + this, + SLOT(Seeked(qint64))); + QStringList matchArgs; + matchArgs << MPRIS2_PLAYER_IFACE; + QDBusConnection::sessionBus().connect( + propsIface->service(), + propsIface->path(), + propsIface->interface(), + "PropertiesChanged", + matchArgs, + QString(), // signature + this, + SLOT(PropertiesChanged(QString,QVariantMap,QStringList))); + } else { + m_identity.clear(); + } +} + +bool Mpris2::isRunning() +{ + if (m_identity.isEmpty()) { + setup(); + } + + return !m_identity.isEmpty(); +} + +Player::State Mpris2::state() +{ + return m_state; +} + +QString Mpris2::artist() +{ + if (m_metadata.contains("xesam:artist")) { + QStringList entries = m_metadata.value("xesam:artist").toStringList(); + if (!entries.isEmpty()) + return entries.first(); + } + return QString(); +} + +QString Mpris2::album() +{ + return m_metadata.value("xesam:album").toString(); +} + +QString Mpris2::title() +{ + return m_metadata.value("xesam:title").toString(); +} + +int Mpris2::trackNumber() +{ + QVariant track; + if (m_metadata.contains("xesam:trackNumber")) { + track = m_metadata.value("xesam:trackNumber"); + } + if (track.isValid() && track.canConvert(QVariant::Int)) { + return track.toInt(); + } + return 0; +} + +QString Mpris2::comment() +{ + if (m_metadata.contains("xesam:comment")) { + return m_metadata.value("xesam:comment").toStringList().join("\n"); + } + return QString(); +} + +QString Mpris2::genre() +{ + if (m_metadata.contains("xesam:genre")) { + QStringList entries = m_metadata.value("xesam:genre").toStringList(); + if (!entries.isEmpty()) + return entries.first(); + } + return QString(); +} + +QString Mpris2::lyrics() +{ + return m_metadata.value("xesam:asText").toString(); +} + +int Mpris2::length() +{ + qlonglong lengthMicros = m_metadata.value("mpris:length").toLongLong(); + return static_cast(lengthMicros / 1000000L); +} + +int Mpris2::position() +{ + return static_cast(positionMs() / 1000L); +} + +qint64 Mpris2::positionMs() +{ + qint64 elapsed = m_posLastUpdated.msecsTo(QDateTime::currentDateTime()); + return m_pos + (m_currentRate * elapsed); +} + +float Mpris2::volume() +{ + return m_volume; +} + +QPixmap Mpris2::artwork() +{ + if (m_artworkLoaded) { + return m_artwork; + } + + m_artwork = QPixmap(); + const QString arturl = m_metadata.value("mpris:artUrl").toString(); + if (!arturl.isEmpty()) { + if (!m_artfiles.contains(arturl) || + (!m_artfiles[arturl].isEmpty() && !QFile::exists(m_artfiles[arturl]))) { + QString artfile; + if (!KIO::NetAccess::download(arturl, artfile, 0)) { + kWarning() << "Could not download artwork from" << arturl << ":" << KIO::NetAccess::lastErrorString(); + artfile.clear(); + } + + m_artfiles[arturl] = artfile; + } + + const QString url = m_artfiles.value(arturl); + if (!url.isEmpty()) { + m_artwork = QPixmap(url); + } + } + + m_artworkLoaded = true; + return m_artwork; +} + +bool Mpris2::canPlay() +{ + return m_canPlay; +} + +void Mpris2::play() +{ + playerIface->asyncCall("Play"); +} + +bool Mpris2::canPause() +{ + return m_canPause; +} + +void Mpris2::pause() +{ + playerIface->asyncCall("Pause"); +} + +bool Mpris2::canStop() +{ + return m_canControl; +} + +void Mpris2::stop() +{ + playerIface->asyncCall("Stop"); +} + +bool Mpris2::canGoPrevious() +{ + return m_canGoPrevious; +} + +void Mpris2::previous() +{ + playerIface->asyncCall("Previous"); +} + +bool Mpris2::canGoNext() +{ + return m_canGoNext; +} + +void Mpris2::next() +{ + playerIface->asyncCall("Next"); +} + +bool Mpris2::canSetVolume() +{ + return m_canControl; +} + +void Mpris2::setVolume(qreal volume) +{ + QDBusVariant value = QDBusVariant(QVariant(static_cast(volume))); + propsIface->asyncCall("Set", MPRIS2_PLAYER_IFACE, "Volume", QVariant::fromValue(value)); +} + +bool Mpris2::canSeek() +{ + return m_canSeek; +} + +void Mpris2::seek(int time) +{ + if (!m_metadata.contains("mpris:trackid")) { + kDebug() << "No mpris:trackid; aborting seek"; + return; + } + QDBusObjectPath trackid = m_metadata.value("mpris:trackid").value(); + if (trackid.path().isEmpty()) { + kDebug() << "Empty path for mpris:trackid; aborting seek"; + return; + } + playerIface->asyncCall("SetPosition", + QVariant::fromValue(trackid), + QVariant::fromValue((qint64)time * 1000000L)); +} + +QVariant Mpris2::getPlayerProp(const QString& prop) +{ + QDBusReply reply = propsIface->call("Get", MPRIS2_PLAYER_IFACE, prop); + if (!reply.isValid()) { + kDebug() << DBUS_PROPS_IFACE ".Get( \"" MPRIS2_PLAYER_IFACE "\"," + << prop + << ") failed at " MPRIS2_PATH " on" + << m_playerName + << " with error " + << reply.error().name(); + return QVariant(); + } + return reply.value().variant(); +} + +bool Mpris2::updateBoolProp(const QString &name, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties, + bool currentVal) +{ + if (changedProperties.contains(name)) { + kDebug() << "Property" << name << "changed from" << currentVal << "to" << changedProperties.value(name).toBool(); + return changedProperties.value(name).toBool(); + } else if (invalidatedProperties.contains(name)) { + bool newVal = getPlayerProp(name).toBool(); + kDebug() << "Property" << name << "changed (inv) from" << currentVal << "to" << newVal; + return newVal; + } + return currentVal; +} + +// SLOTS + +void Mpris2::Seeked(qint64 position) +{ + m_pos = position / 1000L; + m_posLastUpdated = QDateTime::currentDateTime().toUTC(); +} + +void Mpris2::PropertiesChanged(const QString& interface, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties) +{ + if (interface != MPRIS2_PLAYER_IFACE) + return; + + State origState = m_state; + qreal rate = m_rate; + if (changedProperties.contains("PlaybackStatus")) { + m_state = playbackStatusToState(changedProperties.value("PlaybackStatus").toString()); + } else if (invalidatedProperties.contains("PlaybackStatus")) { + m_state = playbackStatusToState(getPlayerProp("PlaybackStatus").toString()); + } + if (changedProperties.contains("Rate")) { + rate = changedProperties.value("Rate").toDouble(); + } else if (invalidatedProperties.contains("Rate")) { + rate = getPlayerProp("Rate").toDouble(); + } + if (origState != m_state || !qFuzzyCompare(m_rate, rate)) { + updatePosition(rate); + } + + if (changedProperties.contains("Metadata")) { + m_metadata = demarshallMetadata(changedProperties.value("Metadata")); + } else if (invalidatedProperties.contains("Metadata")) { + m_metadata = demarshallMetadata(getPlayerProp("Metadata")); + } + + if (changedProperties.contains("Volume")) { + m_volume = changedProperties.value("Volume").toDouble(); + } else if (invalidatedProperties.contains("Volume")) { + m_volume = getPlayerProp("Volume").toDouble(); + } + + m_canPlay = m_canControl && updateBoolProp("CanPlay", changedProperties, invalidatedProperties, m_canPlay); + m_canPause = m_canControl && updateBoolProp("CanPause", changedProperties, invalidatedProperties, m_canPause); + m_canGoPrevious = m_canControl && updateBoolProp("CanGoPrevious", changedProperties, invalidatedProperties, m_canGoPrevious); + m_canGoNext = m_canControl && updateBoolProp("CanGoNext", changedProperties, invalidatedProperties, m_canGoNext); + m_canSeek = m_canControl && updateBoolProp("CanSeek", changedProperties, invalidatedProperties, m_canSeek); +} + +#include "mpris2.moc" +#include "mpris2_p.moc" +// vim:et:sts=4:sw=4 diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2.h b/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2.h new file mode 100644 index 00000000..0ab36504 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2.h @@ -0,0 +1,35 @@ +/* + * Copyright 2011 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MPRIS2_H +#define MPRIS2_H + +#include "../playerfactory.h" + +class Mpris2Factory : public DBusPlayerFactory +{ + Q_OBJECT + +public: + explicit Mpris2Factory(QObject* parent = 0); + Player::Ptr create(const QVariantList& args = QVariantList()); + bool matches(const QString& serviceName); +}; + +#endif // MPRIS2_H +// vim:et:sts=4:sw=4 diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2_p.h b/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2_p.h new file mode 100644 index 00000000..04a3a762 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/mpris2/mpris2_p.h @@ -0,0 +1,113 @@ +/* + * Copyright 2011 Alex Merry + * + * 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 program. If not, see . + */ +#ifndef MPRIS2_P_H +#define MPRIS2_P_H + +#include "mpris2.h" +#include "../player.h" + +#include +#include +class QDBusInterface; + +class Mpris2 : public QObject, public Player +{ + Q_OBJECT + +public: + /** + * @param name the media player name. + */ + explicit Mpris2(const QString& name, + PlayerFactory* factory = 0); + ~Mpris2(); + + bool isRunning(); + State state(); + QString artist(); + QString album(); + QString title(); + int trackNumber(); + QString comment(); + QString genre(); + QString lyrics(); + int length(); + int position(); + float volume(); + QPixmap artwork(); + + bool canPlay(); + void play(); + bool canPause(); + void pause(); + bool canStop(); + void stop(); + bool canGoPrevious(); + void previous(); + bool canGoNext(); + void next(); + + bool canSetVolume(); + void setVolume(qreal volume); + + bool canSeek(); + void seek(int time); + +private Q_SLOTS: + void Seeked(qint64 position); + void PropertiesChanged(const QString& interface, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties); + +private: + qint64 positionMs(); + void setup(); + bool getAllProps(); + void updatePosition(qreal rate); + QVariant getPlayerProp(const QString& prop); + bool updateBoolProp(const QString &name, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties, + bool currentVal); + + QDBusInterface* rootIface; + QDBusInterface* playerIface; + QDBusInterface* propsIface; + + qint64 m_pos; // milliseconds + qreal m_rate; + qreal m_currentRate; // 0.0 if not playing, Rate otherwise + QDateTime m_posLastUpdated; + + QString m_playerName; + QString m_identity; + QVariantMap m_metadata; + float m_volume; + State m_state; + bool m_canControl; + bool m_canPlay; + bool m_canPause; + bool m_canGoPrevious; + bool m_canGoNext; + bool m_canSeek; + QMap m_artfiles; + bool m_artworkLoaded; + QPixmap m_artwork; +}; + +#endif // MPRIS2_P_H +// vim:et:sts=4:sw=4 diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/org.kde.juk.player.xml b/plasma/generic/dataengines/nowplaying/playerinterface/org.kde.juk.player.xml new file mode 100644 index 00000000..bb6e18d4 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/org.kde.juk.player.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/player.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/player.cpp new file mode 100644 index 00000000..b0f2680b --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/player.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "player.h" + +Player::Player(PlayerFactory* factory) + : m_factory(factory) +{ +} + +Player::~Player() +{ +} + +PlayerFactory* Player::factory() const +{ + return m_factory; +} + +QString Player::name() const +{ + Q_ASSERT(!m_name.isEmpty()); + return m_name; +} + +QString Player::artist() +{ + return QString(); +} + +QString Player::album() +{ + return QString(); +} + +QString Player::title() +{ + return QString(); +} + +int Player::trackNumber() +{ + return 0; +} + +QString Player::comment() +{ + return QString(); +} + +QString Player::genre() +{ + return QString(); +} + +QString Player::lyrics() +{ + return QString(); +} + +int Player::length() +{ + return 0; +} + +int Player::position() +{ + return 0; +} + +float Player::volume() +{ + return -1; +} + +QPixmap Player::artwork() +{ + return QPixmap(); +} + +bool Player::canPlay() +{ + return false; +} + +void Player::play() +{ +} + +bool Player::canPause() +{ + return false; +} + +void Player::pause() +{ +} + +bool Player::canStop() +{ + return false; +} + +void Player::stop() +{ +} + +bool Player::canGoPrevious() +{ + return false; +} + +void Player::previous() +{ +} + +bool Player::canGoNext() +{ + return false; +} + +void Player::next() +{ +} + +bool Player::canSetVolume() +{ + return false; +} + +void Player::setVolume(qreal) +{ +} + +bool Player::canSeek() +{ + return false; +} + +void Player::seek(int) +{ +} + +void Player::setName(const QString& name) +{ + m_name = name; +} + diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/player.h b/plasma/generic/dataengines/nowplaying/playerinterface/player.h new file mode 100644 index 00000000..9c2e0fcd --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/player.h @@ -0,0 +1,171 @@ +/* + * Copyright 2007 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLAYER_H +#define PLAYER_H + +#include +#include +#include +#include + +class PlayerFactory; + +/** + * Interface for getting information from and controlling a + * media player + */ +class Player : public QSharedData +{ +public: + typedef KSharedPtr Ptr; + + Player(PlayerFactory* factory = 0); + virtual ~Player(); + /** + * a pointer to the factory that created this player object + */ + PlayerFactory* factory() const; + /** + * The name of this player + */ + QString name() const; + /** + * Current state of the player + */ + enum State { + Playing, + Paused, + Stopped + }; + /** + * Whether the player is running and accessible + */ + virtual bool isRunning() = 0; + /** + * Current state of the player + * + * Undefined if !running() + * + * See State + */ + virtual State state() = 0; + /** Artist for current track. May be empty */ + virtual QString artist(); + /** Album for current track. May be empty */ + virtual QString album(); + /** Title of current track. May be empty */ + virtual QString title(); + /** + * Track number of current track. + * + * Note that this is the track on a CD or in an album, not + * the playlist position + * + * 0 if no track defined, or unknown. + */ + virtual int trackNumber(); + /** Comment for current track. May be empty */ + virtual QString comment(); + /** Genre of current track. May be empty */ + virtual QString genre(); + /** Lyrics of current track. May be empty */ + virtual QString lyrics(); + /** + * Length of current track in seconds. + * + * 0 if unknown. + */ + virtual int length(); + /** + * Position of current track in seconds. + * + * 0 if unknown, not defined if Stopped. + */ + virtual int position(); + /** + * Current volume + * + * Value should be between 0 and 1 + * + * -1 if unknown + */ + virtual float volume(); + /** + * Album artwork + * + * Null (pm.isNull()) if none available + */ + virtual QPixmap artwork(); + + // Commands + + /** + * Play a track + */ + virtual bool canPlay(); + virtual void play(); + /** + * Pause the currently playing track + */ + virtual bool canPause(); + virtual void pause(); + /** + * Stop the currently playing track + * + * canStop() should usually be state() != Stopped if + * stop() is implemented + */ + virtual bool canStop(); + virtual void stop(); + /** + * Move to the previous track + */ + virtual bool canGoPrevious(); + virtual void previous(); + /** + * Move to the next track + */ + virtual bool canGoNext(); + virtual void next(); + + /** + * Set the volume + * + * Must be between 0 and 1 + */ + virtual bool canSetVolume(); + virtual void setVolume(qreal volume); + + /** + * Set the position (in seconds) + * + * Should be <= length() + */ + virtual bool canSeek(); + virtual void seek(int time); + +protected: + void setName(const QString& name); + +private: + QString m_name; + PlayerFactory* m_factory; +}; + +#endif // PLAYER_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/playerfactory.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/playerfactory.cpp new file mode 100644 index 00000000..53c1724d --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/playerfactory.cpp @@ -0,0 +1,26 @@ +#include "playerfactory.h" + +PlayerFactory::PlayerFactory(QObject* parent) + : QObject(parent) +{ + setObjectName( QLatin1String("PlayerFactory" )); +} + +PollingPlayerFactory::PollingPlayerFactory(QObject* parent) + : PlayerFactory(parent) +{ + setObjectName( QLatin1String("PollingPlayerFactory" )); +} + +DBusPlayerFactory::DBusPlayerFactory(QObject* parent) + : PlayerFactory(parent) +{ + setObjectName( QLatin1String("DBusPlayerFactory" )); +} + +Player::Ptr DBusPlayerFactory::create(const QString& serviceName) +{ + return create(QVariantList() << QVariant(serviceName)); +} + +#include "playerfactory.moc" diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/playerfactory.h b/plasma/generic/dataengines/nowplaying/playerinterface/playerfactory.h new file mode 100644 index 00000000..27371f31 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/playerfactory.h @@ -0,0 +1,81 @@ +/* + * Copyright 2008 Alex Merry + * + * 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 program. If not, see . + */ + +#ifndef PLAYERFACTORY_H +#define PLAYERFACTORY_H + +#include +#include + +#include "player.h" + +/** + * A player factory that creates players. + */ +class PlayerFactory : public QObject +{ + Q_OBJECT +public: + PlayerFactory(QObject* parent = 0); + /** + * Create a player. + * + * Returns 0 if a valid player could not be created. + */ + virtual Player::Ptr create(const QVariantList& args = QVariantList()) = 0; +}; + +/** + * A player factory that is polled. + */ +class PollingPlayerFactory : public PlayerFactory +{ + Q_OBJECT +public: + PollingPlayerFactory(QObject* parent = 0); + /** + * Whether create(args) will return a player + * + * Note that just because this returns true, it + * should not be assumed that create(args) will not + * return 0. However, if this returns false, + * it can be assumed that create(args) will always + * return 0. + */ + virtual bool exists(const QVariantList& args = QVariantList()) = 0; +}; + +/** + * A player factory that creates players based on a + * DBus service. + */ +class DBusPlayerFactory : public PlayerFactory +{ + Q_OBJECT +public: + DBusPlayerFactory(QObject* parent = 0); + /** + * Whether the given dbus service name is a service + * for this player + */ + virtual bool matches(const QString& serviceName) = 0; + // don't let the QString overload hide this + virtual Player::Ptr create(const QVariantList& args = QVariantList()) = 0; + Player::Ptr create(const QString& serviceName); +}; + +#endif // PLAYERFACTORY_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/pollingwatcher.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/pollingwatcher.cpp new file mode 100644 index 00000000..6aa65f1d --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/pollingwatcher.cpp @@ -0,0 +1,77 @@ +#include "pollingwatcher.h" + +#include + +#include + +#include "player.h" +#include "playerfactory.h" + +PollingWatcher::PollingWatcher(QObject* parent) + : QObject(parent), + m_timer(0) +{ + setObjectName( QLatin1String("PollingWatcher" )); +} + +QList PollingWatcher::players() +{ + return m_players.values(); +} + +void PollingWatcher::addFactory(PollingPlayerFactory* factory) +{ + if (factory->exists()) { + Player::Ptr player = factory->create(); + if (!player.isNull()) { + m_players.insert(player); + m_usedFactories.insert(factory); + emit newPlayer(player); + } else { + kWarning() << "Failed to create a player"; + m_polledFactories.insert(factory); + } + } else { + m_polledFactories.insert(factory); + } + + if (!m_timer) { + m_timer = new QTimer(this); + m_timer->setInterval(5000); + connect(m_timer, SIGNAL(timeout()), this, SLOT(checkPlayers())); + m_timer->start(); + } +} + +void PollingWatcher::checkPlayers() +{ + foreach (Player::Ptr player, m_players) { + if (!player->isRunning()) { + m_players.remove(player); + PollingPlayerFactory* factory = + qobject_cast(player->factory()); + if (factory) { + m_usedFactories.remove(factory); + m_polledFactories.insert(factory); + } else { + kWarning() << "Missing factory for player" << player->name(); + } + emit playerDisappeared(player); + } + } + foreach (PollingPlayerFactory* factory, m_polledFactories) { + if (factory->exists()) { + Player::Ptr player = factory->create(); + if (!player.isNull()) { + m_players.insert(player); + m_polledFactories.remove(factory); + m_usedFactories.insert(factory); + emit newPlayer(player); + } else { + kWarning() << "Failed to create a player"; + } + } + } + m_timer->start(); +} + diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/pollingwatcher.h b/plasma/generic/dataengines/nowplaying/playerinterface/pollingwatcher.h new file mode 100644 index 00000000..34446da9 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/pollingwatcher.h @@ -0,0 +1,71 @@ +/* + * Copyright 2008 Alex Merry + * + * 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 program. If not, see . + */ +#ifndef POLLINGWATCHER_H +#define POLLINGWATCHER_H + + +#include +#include +#include + +#include "player.h" + +class QTimer; + +class PollingPlayerFactory; + +class PollingWatcher : public QObject +{ + Q_OBJECT + +public: + PollingWatcher(QObject* parent = 0); + + QList players(); + + /** + * Adds a service to watch for. + * + * @param factory the factory for the player + */ + void addFactory(PollingPlayerFactory* factory); + +Q_SIGNALS: + /** + * A new player is available + */ + void newPlayer(Player::Ptr player); + /** + * A previously existing player is no longer available + * + * @param player the now-invalid player + */ + void playerDisappeared(Player::Ptr player); + +private Q_SLOTS: + void checkPlayers(); + +private: + // the factories we are waiting for player to appear on + QSet m_polledFactories; + // the factories we have a player for + QSet m_usedFactories; + QSet m_players; + QTimer* m_timer; +}; + +#endif // POLLINGWATCHER_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/xmms.cpp b/plasma/generic/dataengines/nowplaying/playerinterface/xmms.cpp new file mode 100644 index 00000000..1c344621 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/xmms.cpp @@ -0,0 +1,181 @@ +/* + * Copyright 2007 Alex Merry + * + * Based on Xmms support in the Kopete Now Listening plugin + * Copyright 2002 by Will Stephenson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "xmms.h" +#include "xmms_p.h" + +#include + +#include + +XmmsFactory::XmmsFactory(QObject* parent) + : PollingPlayerFactory(parent) +{ + setObjectName( QLatin1String("XmmsFactory" )); +} + +Player::Ptr XmmsFactory::create(const QVariantList& args) +{ + int session = 0; + if (!args.isEmpty() && args.first().canConvert()) { + session = args.first().toInt(); + if (session < 0) { + return Player::Ptr(0); + } + } + if (xmms_remote_is_running(session)) { + Xmms* player = new Xmms(session, this); + kDebug() << "Creating a player for XMMS session" << session; + return Player::Ptr(player); + } + return Player::Ptr(0); +} + +bool XmmsFactory::exists(const QVariantList& args) +{ + int session = 0; + if (!args.isEmpty() && args.first().canConvert()) { + session = args.first().toInt(); + } + return (session >= 0) && xmms_remote_is_running(session); +} + + + + + +Xmms::Xmms(int session, PlayerFactory* factory) + : Player(factory), + m_session(session) +{ + if (m_session == 0) { + setName("XMMS"); + } else { + setName("XMMS" + QString::number(m_session)); + } +} + +Xmms::~Xmms() +{ +} + +bool Xmms::isRunning() +{ + return xmms_remote_is_running(m_session); +} + +Player::State Xmms::state() +{ + if (xmms_remote_is_paused(m_session)) { + return Paused; + } else if (xmms_remote_is_playing(m_session)) { + return Playing; + } + return Stopped; +} + +QString Xmms::artist() +{ + // let's hope no-one changes the default title string + QString track = xmms_remote_get_playlist_title(m_session, xmms_remote_get_playlist_pos(0)); + return track.section(" - ", 0, 0); +} + +QString Xmms::album() +{ + return QString(); +} + +QString Xmms::title() +{ + // let's hope no-one changes the default title string + QString track = xmms_remote_get_playlist_title(m_session, xmms_remote_get_playlist_pos(0)); + return track.section(" - ", -1, -1); +} + +int Xmms::trackNumber() +{ + // we can get the playlist pos, but that's not what we mean by "trackNumber" + return 0; +} + +QString Xmms::comment() +{ + return QString(); +} + +QString Xmms::genre() +{ + return QString(); +} + +int Xmms::length() +{ + return xmms_remote_get_playlist_time(m_session, xmms_remote_get_playlist_pos(0)); +} + +int Xmms::position() +{ + return xmms_remote_get_output_time(m_session); +} + +float Xmms::volume() +{ + return xmms_remote_get_main_volume(m_session); +} + +void Xmms::play() +{ + xmms_remote_play(m_session); +} + +void Xmms::pause() +{ + xmms_remote_pause(m_session); +} + +void Xmms::stop() +{ + xmms_remote_stop(m_session); +} + +void Xmms::previous() +{ + xmms_remote_playlist_prev(m_session); +} + +void Xmms::next() +{ + xmms_remote_playlist_next(m_session); +} + +void Xmms::setVolume(qreal volume) +{ + xmms_remote_set_main_volume(m_session, volume); +} + +void Xmms::seek(int time) +{ + xmms_remote_jump_to_time(m_session, time); +} + + +#include "xmms.moc" diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/xmms.h b/plasma/generic/dataengines/nowplaying/playerinterface/xmms.h new file mode 100644 index 00000000..8e58c736 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/xmms.h @@ -0,0 +1,34 @@ +/* + * Copyright 2007 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef XMMS_H +#define XMMS_H + +#include "playerfactory.h" + +class XmmsFactory : public PollingPlayerFactory +{ + Q_OBJECT + +public: + explicit XmmsFactory(QObject* parent = 0); + Player::Ptr create(const QVariantList& args = QVariantList()); + bool exists(const QVariantList& args = QVariantList()); +}; + +#endif // XMMS_H diff --git a/plasma/generic/dataengines/nowplaying/playerinterface/xmms_p.h b/plasma/generic/dataengines/nowplaying/playerinterface/xmms_p.h new file mode 100644 index 00000000..10a6e513 --- /dev/null +++ b/plasma/generic/dataengines/nowplaying/playerinterface/xmms_p.h @@ -0,0 +1,62 @@ +/* + * Copyright 2008 Alex Merry + * + * 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 program. If not, see . + */ +#ifndef XMMS_P_H +#define XMMS_P_H + +#include "xmms.h" +#include "player.h" + +class Xmms : public Player +{ +public: + explicit Xmms(int session = 0, PlayerFactory* factory = 0); + ~Xmms(); + + bool isRunning(); + State state(); + QString artist(); + QString album(); + QString title(); + int trackNumber(); + QString comment(); + QString genre(); + int length(); + int position(); + float volume(); + + bool canPlay() { return state() != Playing; } + void play(); + bool canPause() { return true; } + void pause(); + bool canStop() { return state() != Stopped; } + void stop(); + bool canGoPrevious() { return true; } + void previous(); + bool canGoNext() { return true; } + void next(); + + bool canSetVolume() { return true; } + void setVolume(qreal volume); + + bool canSeek() { return state() != Stopped; } + void seek(int time); + +private: + int m_session; +}; + +#endif // XMMS_P_H diff --git a/plasma/generic/dataengines/places/CMakeLists.txt b/plasma/generic/dataengines/places/CMakeLists.txt new file mode 100644 index 00000000..016d6dc4 --- /dev/null +++ b/plasma/generic/dataengines/places/CMakeLists.txt @@ -0,0 +1,24 @@ +set(places_engine_SRCS + placesengine.cpp + placeservice.cpp + setupdevicejob.cpp +) + +AUTOMOC4_MOC_HEADERS(plasma_engine_places modeljob.h) + +kde4_add_plugin(plasma_engine_places ${places_engine_SRCS}) + +target_link_libraries(plasma_engine_places + plasma + ${KDE4_KIO_LIBS} + ${KDE4_KFILE_LIBS} + ${KDE4_SOLID_LIBS} +) + +install(TARGETS plasma_engine_places + DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-places.desktop + DESTINATION ${SERVICES_INSTALL_DIR} ) +install(FILES org.kde.places.operations + DESTINATION ${DATA_INSTALL_DIR}/plasma/services ) + diff --git a/plasma/generic/dataengines/places/TODO b/plasma/generic/dataengines/places/TODO new file mode 100644 index 00000000..5eeb9434 --- /dev/null +++ b/plasma/generic/dataengines/places/TODO @@ -0,0 +1,2 @@ +* periodic refresh? KFilePlacesModel doesn't broadcast + device setups etc. between programs diff --git a/plasma/generic/dataengines/places/jobs.h b/plasma/generic/dataengines/places/jobs.h new file mode 100644 index 00000000..e6867cd7 --- /dev/null +++ b/plasma/generic/dataengines/places/jobs.h @@ -0,0 +1,101 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ +#ifndef JOBS_H +#define JOBS_H + +#include "modeljob.h" + +class AddEditPlaceJob : public ModelJob +{ +public: + AddEditPlaceJob(KFilePlacesModel* model, + QModelIndex index, + const QVariantMap& parameters, + QObject* parent = 0) + : ModelJob(parent, model, index, (index.isValid() ? "Edit" : "Add"), parameters) + , m_text(parameters["Name"].toString()) + , m_url(parameters["Url"].toUrl()) + , m_icon(parameters["Icon"].toString()) + {} + + void start() + { + if (m_index.isValid()) { + m_model->editPlace(m_index, m_text, m_url, m_icon); + } else { + m_model->addPlace(m_text, m_url, m_icon); + } + } + +private: + QString m_text; + KUrl m_url; + QString m_icon; +}; + +class RemovePlaceJob : public ModelJob +{ +public: + RemovePlaceJob(KFilePlacesModel* model, const QModelIndex& index, + QObject* parent) + : ModelJob(parent, model, index, "Remove") + {} + + void start() + { + m_model->removePlace(m_index); + } +}; + +class ShowPlaceJob : public ModelJob +{ +public: + ShowPlaceJob(KFilePlacesModel* model, const QModelIndex& index, + bool show = true, QObject* parent = 0) + : ModelJob(parent, model, index, (show ? "Show" : "Hide")) + , m_show(show) + {} + + void start() + { + m_model->setPlaceHidden(m_index, m_show); + } + +private: + bool m_show; +}; + +class TeardownDeviceJob : public ModelJob +{ +public: + TeardownDeviceJob(KFilePlacesModel* model, const QModelIndex& index, + QObject* parent = 0) + : ModelJob(parent, model, index, "Teardown Device") + {} + + void start() + { + m_model->requestTeardown(m_index); + } +}; + +#include "setupdevicejob.h" + +#endif // JOBS_H + diff --git a/plasma/generic/dataengines/places/modeljob.h b/plasma/generic/dataengines/places/modeljob.h new file mode 100644 index 00000000..b505e371 --- /dev/null +++ b/plasma/generic/dataengines/places/modeljob.h @@ -0,0 +1,44 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ +#ifndef MODELJOB_H +#define MODELJOB_H + +#include +#include + +class ModelJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + ModelJob(QObject* parent, KFilePlacesModel* model, + const QModelIndex& index, const QString& operation, + const QVariantMap& parameters = QVariantMap()) + : ServiceJob(QString::number(index.row()), operation, parameters, parent) + , m_model(model) + , m_index(index) + {} + +protected: + KFilePlacesModel* m_model; + QModelIndex m_index; +}; + +#endif // MODELJOB_H + diff --git a/plasma/generic/dataengines/places/org.kde.places.operations b/plasma/generic/dataengines/places/org.kde.places.operations new file mode 100644 index 00000000..c33e8318 --- /dev/null +++ b/plasma/generic/dataengines/places/org.kde.places.operations @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/places/placesengine.cpp b/plasma/generic/dataengines/places/placesengine.cpp new file mode 100644 index 00000000..52139612 --- /dev/null +++ b/plasma/generic/dataengines/places/placesengine.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2008 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "placesengine.h" + +#include + +#include +#include + +#include "placeservice.h" + +PlacesEngine::PlacesEngine(QObject *parent, const QVariantList &args) + : Plasma::DataEngine(parent, args) +{ + connect(&m_placesModel, SIGNAL(modelReset()), + this, SLOT(modelReset())); + connect(&m_placesModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(dataChanged(QModelIndex,QModelIndex))); + connect(&m_placesModel, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(placesAdded(QModelIndex,int,int))); + connect(&m_placesModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(placesRemoved(QModelIndex,int,int))); + + sendAllData(); +} + +PlacesEngine::~PlacesEngine() +{ +} + +void PlacesEngine::modelReset() +{ + removeAllSources(); +} + +void PlacesEngine::placesAdded(const QModelIndex&, int start, int end) +{ + sendData(start, end); +} + +void PlacesEngine::placesRemoved(const QModelIndex&, int start, int end) +{ + kDebug() << "Places" << start << "through" << end << "removed"; + for (int index = start; index <= end; index++) { + removeSource(QString::number(index)); + } +} + +void PlacesEngine::dataChanged(const QModelIndex& topLeft, + const QModelIndex& bottomRight) +{ + sendData(topLeft.row(), bottomRight.row()); +} + +void PlacesEngine::sendAllData() +{ + sendData(0, m_placesModel.rowCount() - 1); +} + +Plasma::Service *PlacesEngine::serviceForSource(const QString &source) +{ + const int row = source.toInt(); + const QModelIndex index = m_placesModel.index(row, 0); + if (index.isValid()) { + return new PlaceService(this, &m_placesModel, index); + } + + return DataEngine::serviceForSource(source); +} + +void PlacesEngine::sendData(int start, int end) +{ + for (int row = start; row <= end; ++row) { + const QModelIndex index = m_placesModel.index(row, 0); + + Data map; + + const QString source = QString::number(row); + + setData(source, "name", m_placesModel.text(index)); + setData(source, "url", m_placesModel.url(index).url()); + setData(source, "icon", m_placesModel.icon(index)); + setData(source, "hidden", + m_placesModel.data(index, KFilePlacesModel::HiddenRole)); + setData(source, "setupNeeded", + m_placesModel.data(index, KFilePlacesModel::SetupNeededRole)); + setData(source, "isDevice", + m_placesModel.deviceForIndex(index).isValid()); + + const QString path = m_placesModel.url(index).path(); + if (!path.isEmpty()) { + // We can't get free space for unmounted volumes :-( + KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(path); + setData(source, "kBSize", info.size()/1024); // deprecated + setData(source, "kBUsed", info.used()/1024); // deprecated + setData(source, "kBAvailable", info.available()/1024); // deprecated + setData(source, "size (bytes)", info.size()); + setData(source, "used (bytes)", info.used()); + setData(source, "available (bytes)", info.available()); + } + } +} + +K_EXPORT_PLASMA_DATAENGINE(places, PlacesEngine) + +#include "placesengine.moc" + diff --git a/plasma/generic/dataengines/places/placesengine.h b/plasma/generic/dataengines/places/placesengine.h new file mode 100644 index 00000000..e787dbd7 --- /dev/null +++ b/plasma/generic/dataengines/places/placesengine.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLACESENGINE_H +#define PLACESENGINE_H + +#include + +#include + +class PlacesEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + PlacesEngine(QObject* parent, const QVariantList& args); + ~PlacesEngine(); + + Plasma::Service *serviceForSource(const QString &source); + +private Q_SLOTS: + // KFilePlacesModel + void modelReset(); + void placesAdded(const QModelIndex& parent, int start, int end); + void placesRemoved(const QModelIndex& parent, int start, int end); + void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + +private: + void sendData(int start, int end); + void sendAllData(); + + KFilePlacesModel m_placesModel; +}; + + +#endif // PLACESENGINE_H diff --git a/plasma/generic/dataengines/places/placeservice.cpp b/plasma/generic/dataengines/places/placeservice.cpp new file mode 100644 index 00000000..1765c3fa --- /dev/null +++ b/plasma/generic/dataengines/places/placeservice.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "placeservice.h" +#include "jobs.h" + +#include + + +PlaceService::PlaceService(QObject* parent, + KFilePlacesModel* model, + QModelIndex index) + : Plasma::Service(parent), + m_model(model), + m_index(index) +{ + setName("org.kde.places"); + if (m_index.isValid()) { + Q_ASSERT(m_index.model() == model); + setDestination(QString::number(m_index.row())); + kDebug() << "Created a place service for" << destination(); + } else { + kDebug() << "Created a dead place service"; + } +} + +Plasma::ServiceJob* PlaceService::createJob(const QString& operation, + QMap& parameters) +{ + kDebug() << "Job" << operation << "with arguments" << parameters << "requested"; + if (operation == "Add") { + return new AddEditPlaceJob(m_model, m_index, parameters, this); + } else if (operation == "Edit") { + return new AddEditPlaceJob(m_model, QModelIndex(), parameters, this); + } else if (operation == "Remove") { + return new RemovePlaceJob(m_model, m_index, this); + } else if (operation == "Hide") { + return new ShowPlaceJob(m_model, m_index, false, this); + } else if (operation == "Show") { + return new ShowPlaceJob(m_model, m_index, true, this); + } else if (operation == "Setup Device") { + return new SetupDeviceJob(m_model, m_index, this); + } else if (operation == "Teardown Device") { + return new TeardownDeviceJob(m_model, m_index, this); + } else { + // FIXME: BAD! No! + return 0; + } +} + +#include "placeservice.moc" + +// vim: sw=4 sts=4 et tw=100 diff --git a/plasma/generic/dataengines/places/placeservice.h b/plasma/generic/dataengines/places/placeservice.h new file mode 100644 index 00000000..7bea7624 --- /dev/null +++ b/plasma/generic/dataengines/places/placeservice.h @@ -0,0 +1,45 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLACESERVICE_H +#define PLACESERVICE_H + +#include + +#include "placesengine.h" + +class PlaceService : public Plasma::Service +{ + Q_OBJECT + +public: + PlaceService(QObject* parent, + KFilePlacesModel* model, + QModelIndex index = QModelIndex()); + +protected: + Plasma::ServiceJob* createJob(const QString& operation, + QMap& parameters); + +private: + KFilePlacesModel* m_model; + QModelIndex m_index; +}; + +#endif // PLACESERVICE_H diff --git a/plasma/generic/dataengines/places/plasma-dataengine-places.desktop b/plasma/generic/dataengines/places/plasma-dataengine-places.desktop new file mode 100644 index 00000000..4ed4e029 --- /dev/null +++ b/plasma/generic/dataengines/places/plasma-dataengine-places.desktop @@ -0,0 +1,156 @@ +[Desktop Entry] +Name=Places +Name[ar]=الأماكن +Name[ast]=Llugares +Name[be@latin]=Miescy +Name[bg]=Места +Name[bn]=স্থান +Name[bs]=mjesta +Name[ca]=Llocs +Name[ca@valencia]=Llocs +Name[cs]=Místa +Name[csb]=Place +Name[da]=Steder +Name[de]=Orte +Name[el]=Τοποθεσίες +Name[en_GB]=Places +Name[eo]=Lokoj +Name[es]=Lugares +Name[et]=Asukohad +Name[eu]=Tokiak +Name[fi]=Sijainnit +Name[fr]=Emplacements +Name[fy]=Places +Name[ga]=Áiteanna +Name[gl]=Lugares +Name[gu]=જગ્યાઓ +Name[he]=מקומות +Name[hi]=स्थान +Name[hne]=प्लेसेस +Name[hr]=Mjesta +Name[hu]=Helyek +Name[ia]=Placias +Name[id]=Tempat +Name[is]=Staðir +Name[it]=Risorse +Name[ja]=場所 +Name[ka]=ადგილები +Name[kk]=Орындар +Name[km]=កន្លែង +Name[kn]=ಸ್ಥಳಗಳು +Name[ko]=위치 +Name[ku]=Cih +Name[lt]=Vietos +Name[lv]=Vietas +Name[mai]=स्थान +Name[mk]=Места +Name[ml]=സ്ഥലങ്ങള്‍ +Name[mr]=जागा +Name[nb]=Steder +Name[nds]=Steden +Name[nl]=Locaties +Name[nn]=Stader +Name[or]=ସ୍ଥାନଗୁଡ଼ିକ +Name[pa]=ਥਾਵਾਂ +Name[pl]=Miejsca +Name[pt]=Locais +Name[pt_BR]=Locais +Name[ro]=Locuri +Name[ru]=Точки входа +Name[si]=ස්ථාන +Name[sk]=Miesta +Name[sl]=Mesta +Name[sr]=места +Name[sr@ijekavian]=мјеста +Name[sr@ijekavianlatin]=mjesta +Name[sr@latin]=mesta +Name[sv]=Platser +Name[ta]=Places +Name[tg]=Ҷойҳо +Name[th]=ที่หลัก ๆ +Name[tr]=Konumlar +Name[ug]=ئورۇنلار +Name[uk]=Місця +Name[wa]=Plaeces +Name[x-test]=xxPlacesxx +Name[zh_CN]=位置 +Name[zh_TW]=地方 +Comment=Places, as seen in the file manager and in file dialogs. +Comment[ar]=الأماكن كما تُرى في مدير الملفات وحوارات الملف. +Comment[ast]=Llugares, como se ven nel xestor de ficheros y nos diálogos de ficheros. +Comment[bg]=Местата, както се виждат във файловия мениджър и прозорците. +Comment[bs]=Mjesta, kako se vide u menadžeru datoteka i datotečnim dijalozima. +Comment[ca]=Llocs, com es veuen en el gestor de fitxers i en els diàlegs de fitxer. +Comment[ca@valencia]=Llocs, com es veuen en el gestor de fitxers i en els diàlegs de fitxer. +Comment[cs]=Umístění, jak je vidíte ve správci souborů a souborových dialozích. +Comment[da]=Steder, som de ses i filhåndteringen og fildialoger. +Comment[de]=Orte, wie sie im Dateimanager und in Dateiauswahl-Dialogen zu sehen sind. +Comment[el]=Τοποθεσίες, όπως εμφανίζονται στη διαχείριση αρχείων και στους διαλόγους αρχείων. +Comment[en_GB]=Places, as seen in the file manager and in file dialogues. +Comment[es]=Lugares, como se ven en el gestor de archivos y en los diálogos de archivos. +Comment[et]=Asukohad, nagu neid näeb failihalduris ja -dialoogides. +Comment[eu]=Tokiak, fitxategi-kudeatzailean eta fitxategien elkarrizketa-koadroetan ikusi bezala. +Comment[fi]=Paikat, kuten nähdään tiedostohallinnassa ja tiedostovalintaikkunoissa. +Comment[fr]=Emplacements, tel que vus par le gestionnaire de fichiers et les boîtes de dialogue de fichiers. +Comment[fy]=Plakken, lykas yn de triembehearder en triem dialogen. +Comment[ga]=Áiteanna, mar a fheictear sa bhainisteoir comhad agus i ndialóga comhad. +Comment[gl]=Os lugares tal como se ven no xestor de ficheiros e nos diálogos de ficheiros. +Comment[he]=מיקומים, כפי שהם נראים במנהל הקבצים ובתיבות דו־שיח של קבצים. +Comment[hr]=Mjesta, kao što ih se vidi u pregledniku datoteka i dialozima za izbor datoteka +Comment[hu]=Helyek panel (ahogy a fájlkezelőben és a fájlmegnyitó ablakokban látható). +Comment[ia]=Placias, tal como vidite in le gerente de file e in le dialogos de file +Comment[id]=Tempat, seperti terlihat di manajer berkas dan di dialog berkas. +Comment[is]=Staðir, eins og sýnt er í skráastjóra og samskiptagluggum. +Comment[it]=Risorse, come nel gestore dei file e nelle finestre di selezione dei file. +Comment[ja]=ファイルマネージャやファイル選択ダイアログに表示される場所 +Comment[kk]=Файл менеджерде және диалогында көрсетілетін орындар. +Comment[km]=កន្លែង ដូច​ដែល​បានឃើញ​នៅ​ក្នុង​កម្មវិធី​គ្រប់គ្រង​ឯកសារ និង​ប្រអប់​ឯកសារ ។ +Comment[kn]=ಕಡತ ವ್ಯವಸ್ಥಾಪಕದಲ್ಲಿ ಹಾಗು ಕಡತ ಸಂವಾದಗಳಲ್ಲಿ ಕಾಣಿಸುವ ಸ್ಥಳಗಳು. +Comment[ko]=파일 관리자와 파일 대화 상자에 나타나는 위치입니다. +Comment[lt]=Vietos, kaip jos matomos failų tvarkyklėje ir failų dialoguose. +Comment[lv]=Vietas, kas redzamas failu pārvaldniekā un failu atvēršanas logos. +Comment[mk]=Места, како што се гледаат во менаџерот на датотеки и во дијалозите за датотеки +Comment[ml]=ഫയല്‍ കാര്യസ്ഥനിലും ഫയല്‍ സംഭാഷണങ്ങളിലും കാണുന്നപോലെയുള്ള ഇടങ്ങള്‍. +Comment[mr]=फाईल व्यवस्थापक व फाईल संवादामध्ये दिसणाऱ्या जागा. +Comment[nb]=Steder, som sett i filbehandleren og fildialogene. +Comment[nds]=Steden, as för den Dateipleger un binnen Dateidialogen +Comment[nl]=Plaatsen, zoals deze gezien worden in de bestandsbeheerder en in bestandsdialogen. +Comment[nn]=Stader, slik ein kan sjå dei i filhandsamaren og dialogvindauge for filer. +Comment[pa]=ਥਾਵਾਂ, ਜਿਵੇਂ ਕਿ ਫਾਇਲ ਮੈਨੇਜਰ ਅਤੇ ਹੋਰ ਫਾਇਲ ਡਾਇਲਾਗ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। +Comment[pl]=Miejsca, widziane tak jak w przeglądarce plików i oknach dialogowych plików. +Comment[pt]=Os locais vistos nas janelas e gestores de ficheiros. +Comment[pt_BR]=Locais, como visto no gerenciador de arquivo e nos diálogos de arquivo. +Comment[ro]=Locuri, așa cum sînt văzute în gestionarul de fișiere și în dialogurile de fișier. +Comment[ru]=Точки входа, показываемые в диспетчере файлов и файловых диалогах. +Comment[si]=ස්ථාන, ගොනු පාලකයේ මෙන්ම ගොනු සංවාද වල පෙනෙන ආකාරයට +Comment[sk]=Miesta, ako sú vidieť v správcovi súborov a súborových dialógoch. +Comment[sl]=Mesta, kot jih je mogoče videti v upravljalniku datotek in pogovornih oknih za datoteke. +Comment[sr]=Места, како се виде у менаџеру фајлова и фајл дијалозима. +Comment[sr@ijekavian]=Места, како се виде у менаџеру фајлова и фајл дијалозима. +Comment[sr@ijekavianlatin]=Mesta, kako se vide u menadžeru fajlova i fajl dijalozima. +Comment[sr@latin]=Mesta, kako se vide u menadžeru fajlova i fajl dijalozima. +Comment[sv]=Platser som visas i filhanterare och fildialogrutor. +Comment[th]=ที่หลัก ๆ ที่จะถูกเห็นในเครื่องมือจัดการแฟ้มและในกล่องเลือกแฟ้ม +Comment[tr]=Konumlar, dosya yöneticisinde ve dosya açma pencerelerinde görünür. +Comment[ug]=ھۆججەت باشقۇرغۇچ ۋە ھۆججەت سۆزلەشكۈدە كۆرەلەيدىغان ئورۇننى تەمىنلەيدۇ. +Comment[uk]=Місця, так, як їх показано у менеджері файлів і діалогових вікнах. +Comment[wa]=Eplaeçmints, come i sont veyous e manaedjeu des fitchîs eyet ezès purneas di dvize des fitchîs. +Comment[x-test]=xxPlaces, as seen in the file manager and in file dialogs.xx +Comment[zh_CN]=提供文件管理器和文件对话框里能看到的位置。 +Comment[zh_TW]=在檔案管理員與檔案對話框中看到的「地方」項目。 +Type=Service +Icon=folder-favorites + +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-Library=plasma_engine_places + +X-KDE-PluginInfo-Author=Alex Merry +X-KDE-PluginInfo-Email=alex.merry@kdemail.net +X-KDE-PluginInfo-Name=places +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=System +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true + diff --git a/plasma/generic/dataengines/places/setupdevicejob.cpp b/plasma/generic/dataengines/places/setupdevicejob.cpp new file mode 100644 index 00000000..1bd99f8d --- /dev/null +++ b/plasma/generic/dataengines/places/setupdevicejob.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "setupdevicejob.h" + +void SetupDeviceJob::setupDone(const QModelIndex& index, bool success) +{ + if (index == m_index) { + setError(!success); + emitResult(); + } +} + +void SetupDeviceJob::setupError(const QString& message) +{ + if (!error() || errorText().isEmpty()) { + setErrorText(message); + } +} + +#include "setupdevicejob.moc" + +// vim: sw=4 sts=4 et tw=100 diff --git a/plasma/generic/dataengines/places/setupdevicejob.h b/plasma/generic/dataengines/places/setupdevicejob.h new file mode 100644 index 00000000..facf9e39 --- /dev/null +++ b/plasma/generic/dataengines/places/setupdevicejob.h @@ -0,0 +1,49 @@ +/* + * Copyright 2008 Alex Merry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ +#ifndef SETUPDEVICEJOB_H +#define SETUPDEVICEJOB_H + +#include "modeljob.h" + +class SetupDeviceJob : public ModelJob +{ + Q_OBJECT + +public: + SetupDeviceJob(KFilePlacesModel* model, QModelIndex index, + QObject* parent = 0) + : ModelJob(parent, model, index, "Setup Device") + { + connect(model, SIGNAL(setupDone(QModelIndex,bool)), + SLOT(setupDone(QModelIndex,bool))); + connect(model, SIGNAL(errorMessage(QString)), + SLOT(setupError(QString))); + } + + void start() + { + m_model->requestSetup(m_index); + } + +private slots: + void setupDone(const QModelIndex& index, bool success); + void setupError(const QString& message); +}; + +#endif // SETUPDEVICEJOB_H diff --git a/plasma/generic/dataengines/powermanagement/CMakeLists.txt b/plasma/generic/dataengines/powermanagement/CMakeLists.txt new file mode 100644 index 00000000..acd73b7f --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(powermanagement_engine_SRCS + powermanagementengine.cpp + powermanagementjob.cpp + powermanagementservice.cpp +) + +set(krunner_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/krunner/dbus/org.kde.krunner.App.xml) +QT4_ADD_DBUS_INTERFACE(powermanagement_engine_SRCS ${krunner_xml} krunner_interface) + +kde4_add_plugin(plasma_engine_powermanagement ${powermanagement_engine_SRCS}) +target_link_libraries(plasma_engine_powermanagement ${KDE4_KDECORE_LIBS} ${KDE4_SOLID_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4_KIDLETIME_LIBRARY} kworkspace) + +install(TARGETS plasma_engine_powermanagement DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-powermanagement.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install(FILES powermanagementservice.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + diff --git a/plasma/generic/dataengines/powermanagement/README.txt b/plasma/generic/dataengines/powermanagement/README.txt new file mode 100644 index 00000000..c657bc9f --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/README.txt @@ -0,0 +1,13 @@ +TODO: +====== +- Sleepstates don't match what solidshell reports +- ac plug state does not get updated +- this engine probably shares some functionality with + the solidengine, have a look at that and evaluate + +Notes +====== +There's a battery applet (also in kdebase) which uses this engine + +-- sebas + diff --git a/plasma/generic/dataengines/powermanagement/plasma-dataengine-powermanagement.desktop b/plasma/generic/dataengines/powermanagement/plasma-dataengine-powermanagement.desktop new file mode 100644 index 00000000..0e979a9a --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/plasma-dataengine-powermanagement.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +# ctxt: plasma data engine +Name=Power Management +Name[ar]=إدارة الطاقة +Name[ast]=Xestión d'enerxía +Name[bg]=Управление на захранването +Name[bn]=শক্তি ব্যবস্থাপনা +Name[bs]=upravljanje napajanjem +Name[ca]=Gestió d'energia +Name[ca@valencia]=Gestió d'energia +Name[cs]=Správa napájení +Name[csb]=Sprôwianié mòcą +Name[da]=Strømstyring +Name[de]=Energieverwaltung +Name[el]=Διαχείριση ενέργειας +Name[en_GB]=Power Management +Name[eo]=Energia administrado +Name[es]=Gestión de energía +Name[et]=Toitehaldus +Name[eu]=Energia-kudeaketa +Name[fi]=Virranhallinta +Name[fr]=Gestion de l'énergie +Name[fy]=Enerzjybehear +Name[ga]=Bainisteoireacht Cumhachta +Name[gl]=Xestión da enerxía +Name[gu]=પાવર વ્યવસ્થાપક +Name[he]=ניהול צריכת חשמל +Name[hi]=बिज़ली प्रबंधन +Name[hr]=Upravljanje potrošnjom energije +Name[hu]=Energiakezelő +Name[ia]=Gestion de energia +Name[id]=Manajemen Daya +Name[is]=Orkustýring +Name[it]=Gestione energetica +Name[ja]=電源管理 +Name[kk]=Қуаттандыруды басқару +Name[km]=ការ​គ្រប់គ្រង​ថាមពល​ +Name[kn]=ವಿದ್ಯುಚ್ಚಕ್ತಿಯ ನಿರ್ವಹಣೆ +Name[ko]=전원 관리 +Name[lt]=Energijos valdymas +Name[lv]=Energokontrole +Name[mk]=Менаџмент на енергија +Name[ml]=വൈദ്യുതി നടത്തിപ്പു് +Name[mr]=वीज व्यवस्थापन +Name[nb]=Strømstyring +Name[nds]=Stroomkuntrull +Name[nl]=Energiebeheer +Name[nn]=Straumstyring +Name[pa]=ਪਾਵਰ ਮੈਨਿਜਮੈਂਟ +Name[pl]=Zarządzanie energią +Name[pt]=Gestão de Energia +Name[pt_BR]=Gerenciamento de energia +Name[ro]=Gestiunea alimentării +Name[ru]=Управление питанием +Name[si]=බල පරිපාලනය +Name[sk]=Správa napájania +Name[sl]=Upravljanje z energijo +Name[sr]=управљање напајањем +Name[sr@ijekavian]=управљање напајањем +Name[sr@ijekavianlatin]=upravljanje napajanjem +Name[sr@latin]=upravljanje napajanjem +Name[sv]=Strömsparhantering +Name[tg]=Идоракунии барқ +Name[th]=การจัดการพลังงาน +Name[tr]=Güç Yönetimi +Name[ug]=توك مەنبەسىنى باشقۇرۇش +Name[uk]=Керування живленням +Name[wa]=Manaedjmint di l' enerdjeye +Name[x-test]=xxPower Managementxx +Name[zh_CN]=电源管理 +Name[zh_TW]=電源管理 +Comment=Battery, AC, sleep and PowerDevil information. +Comment[ar]=معلومات البطارية والتيار المتناوب والنوم وعفريت الطاقة. +Comment[ast]=Información de batería, CA, hibernación y PowerDevil. +Comment[bg]=Данни за батерия, AC, приспиване и PowerDevil +Comment[bs]=Podaci iz Strujnog đavola o bateriji, AC‑u, i spavanju. +Comment[ca]=Informació de la bateria, AC, suspensió i del PowerDevil. +Comment[ca@valencia]=Informació de la bateria, AC, suspensió i del PowerDevil. +Comment[cs]=Informace o baterii, AC a uspání. +Comment[da]=Information om batteri, strømforsyning, dvale og PowerDevil. +Comment[de]=Informationen zu Akku, Netzanschluss, Ruhezustand und PowerDevil. +Comment[el]=Πληροφορίες μπαταρίας, AC, αδράνειας και PowerDevil +Comment[en_GB]=Battery, AC, sleep and PowerDevil information. +Comment[es]=Información de batería, CA, hibernación y PowerDevil. +Comment[et]=Aku, voolutoite, puhkeseisundi ja PowerDevili teave. +Comment[eu]=Bateria, korronte alternoa, loa eta PowerDevil-i buruzko informazioa. +Comment[fi]=Akku, vaihtovirta, nukkumis- ja PowerDevil-tiedot. +Comment[fr]=Batterie, chargeur, veille et informations sur PowerDevil +Comment[fy]=Batterij, AC, sliepe en PowerDevil ynformaasje +Comment[ga]=Faisnéis a bhaineann leis an gcadhnra, ceangal SA, codladh agus PowerDevil. +Comment[gl]=Información da batería, corrente, hibernación e PowerDevil. +Comment[he]=מידע אודות סוללה, צריכת חשמל, מצב שינה ו־PowerDevil. +Comment[hr]=Informacije o bateriji, adapteru, spavanju i PowerDevilu. +Comment[hu]=A telepek, a tápellátás és a PowerDevil energiakezelő jellemzői. +Comment[ia]=Batteria, AC, reposo e information de PowerDevil. +Comment[id]=Informasi Baterai, AC, tidur dan PowerDevil. +Comment[is]=Upplýsingar um raflöður, AC-straum, svæfingu og PowerDevil orkustýringarpúkann. +Comment[it]=Informazioni su batteria, alimentazione, sospensione e PowerDevil +Comment[ja]=バッテリ、商用電源、スリープ、PowerDevil の情報。 +Comment[kk]=Батарея, тоқ, ұйықтау күйі және PowerDevil мәліметі. +Comment[km]=ព័ត៌មាន ថ្ម AC ដេក និង​ PowerDevil ។ +Comment[kn]=ವಿದ್ಯುತ್ಕೋಶ, AC, ಜಡ ಹಾಗು PowerDevil ಮಾಹಿತಿ. +Comment[ko]=배터리, AC, 절전 모드 및 PowerDevil 정보입니다. +Comment[lt]=Akumuliatoriaus, AC, miego ir PowerDevil informacija. +Comment[lv]=Baterija, barošana, gulēšanas un PowerDevil informācija. +Comment[ml]=ബാറ്ററി, എസി, നിദ്ര പിന്നെ പവര്‍ഡെവിള്‍ എന്നീ വിവരങ്ങള്‍. +Comment[mr]=बॅटरी, AC, व पॉवरडेव्हिल माहिती. +Comment[nb]=Informasjon om batteri, nettstrøm, hvilemodus og PowerDevil. +Comment[nds]=Batterie-, Stroom-, Utsett- un Stroomdüvel-Infos +Comment[nl]=Accu-, stroomvoorziening-, slaapstand- en PowerDevil-informatie. +Comment[nn]=Informasjon om batteristatus, lading og liknande. +Comment[pa]=ਬੈਟਰੀ, ਏਸੀ, ਸਲੀਪ ਅਤੇ ਪਾਵਰਡਿਵੈਲ ਜਾਣਕਾਰੀ ਹੈ। +Comment[pl]=Bateria, zasilacz, usypianie i informacje PowerDevil. +Comment[pt]=Informação sobre a bateria, corrente eléctrica e o PowerDevil. +Comment[pt_BR]=Bateria, adaptador de energia, dormir e informação do PowerDevil. +Comment[ro]=Informații despre acumulator, priză, adormire și PowerDevil. +Comment[ru]=Информация о батарее, электрической сети и PowerDevil. +Comment[si]=බැටරි, AC, නිද්‍රා හා PowerDevil තොරතුරු +Comment[sk]=Informácie o batérii, AC a uspaní. +Comment[sl]=Podatki o baterijah, omrežnem napajanju, pripravljenosti in PowerDevilu. +Comment[sr]=Подаци из Струјног ђавола о батерији, АЦ‑у, и спавању. +Comment[sr@ijekavian]=Подаци из Струјног ђавола о батерији, АЦ‑у, и спавању. +Comment[sr@ijekavianlatin]=Podaci iz Strujnog đavola o bateriji, AC‑u, i spavanju. +Comment[sr@latin]=Podaci iz Strujnog đavola o bateriji, AC‑u, i spavanju. +Comment[sv]=Information om batteri, nätspänning, viloläge och Powerdevil. +Comment[tg]=Батарея, AC, захираи барқ ва иттилооти PowerDevil. +Comment[th]=แบตเตอรี่, การเสียบปลั๊กไฟ, การพักเครื่อง และข้อมูลของ PowerDevil +Comment[tr]=Pil, Adaptör, uyku kipi ve PowerDevil bilgileri. +Comment[ug]=توكدان، ئۆزگىرىشچان توك مەنبەسى، سىستېما ئۇخلات ۋە PowerDevil ئۇچۇرىنى تەمىنلەيدۇ. +Comment[uk]=Акумулятор, мережеве живлення, відомості щодо присипляння і PowerDevil. +Comment[vi]=Thông tin pin, AC, chế độ ngủ và PowerDevil +Comment[wa]=Pondants et djondants sol batreye, l' AC, l' edoirmaedje eyet l' Diâle d' Enerdjeye. +Comment[x-test]=xxBattery, AC, sleep and PowerDevil information.xx +Comment[zh_CN]=提供电池、交流适配器、系统睡眠及 PowerDevil 信息。 +Comment[zh_TW]=電池、市電電源、睡眠模式與 PowerDevil 資訊。 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=preferences-system-power-management +X-KDE-Library=plasma_engine_powermanagement + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=powermanagement +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= diff --git a/plasma/generic/dataengines/powermanagement/powermanagementengine.cpp b/plasma/generic/dataengines/powermanagement/powermanagementengine.cpp new file mode 100644 index 00000000..341a0077 --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/powermanagementengine.cpp @@ -0,0 +1,486 @@ +/* + * Copyright 2007 Aaron Seigo + * Copyright 2007-2008 Sebastian Kuegler + * CopyRight 2007 Maor Vanmak + * Copyright 2008 Dario Freddi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "powermanagementengine.h" + +//solid specific includes +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "powermanagementservice.h" + +typedef QMap< QString, QString > StringStringMap; +Q_DECLARE_METATYPE(StringStringMap) + +PowermanagementEngine::PowermanagementEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) + , m_sources(basicSourceNames()) +{ + Q_UNUSED(args) + qDBusRegisterMetaType< StringStringMap >(); +} + +PowermanagementEngine::~PowermanagementEngine() +{} + +void PowermanagementEngine::init() +{ + connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(QString)), + this, SLOT(deviceAdded(QString))); + connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(QString)), + this, SLOT(deviceRemoved(QString))); + + // FIXME This check doesn't work, connect seems to always return true, hence the hack below + if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.Solid.PowerManagement")) { + if (!QDBusConnection::sessionBus().connect("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement/Actions/BrightnessControl", + "org.kde.Solid.PowerManagement.Actions.BrightnessControl", + "brightnessChanged", this, + SLOT(screenBrightnessChanged(int)))) { + kDebug() << "error connecting to Brightness changes via dbus"; + brightnessControlsAvailableChanged(false); + } else { + brightnessControlsAvailableChanged(true); + } + + if (!QDBusConnection::sessionBus().connect("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl", + "org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl", + "keyboardBrightnessChanged", this, + SLOT(keyboardBrightnessChanged(int)))) { + kDebug() << "error connecting to Keyboard Brightness changes via dbus"; + keyboardBrightnessControlsAvailableChanged(false); + } else { + keyboardBrightnessControlsAvailableChanged(true); + } + + sourceRequestEvent("PowerDevil"); + + if (!QDBusConnection::sessionBus().connect("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", + "batteryRemainingTimeChanged", this, + SLOT(batteryRemainingTimeChanged(qulonglong)))) { + kDebug() << "error connecting to remaining time changes"; + } + } +} + +QStringList PowermanagementEngine::basicSourceNames() const +{ + QStringList sources; + sources << "Battery" << "AC Adapter" << "Sleep States" << "PowerDevil"; + return sources; +} + +QStringList PowermanagementEngine::sources() const +{ + return m_sources; +} + +bool PowermanagementEngine::sourceRequestEvent(const QString &name) +{ + if (name == "Battery") { + const QList listBattery = Solid::Device::listFromType(Solid::DeviceInterface::Battery); + m_batterySources.clear(); + + if (listBattery.isEmpty()) { + setData("Battery", "Has Battery", false); + return true; + } + + uint index = 0; + QStringList batterySources; + + foreach (const Solid::Device &deviceBattery, listBattery) { + const Solid::Battery* battery = deviceBattery.as(); + + const QString source = QString("Battery%1").arg(index++); + + batterySources << source; + m_batterySources[deviceBattery.udi()] = source; + + connect(battery, SIGNAL(chargeStateChanged(int,QString)), this, + SLOT(updateBatteryChargeState(int,QString))); + connect(battery, SIGNAL(chargePercentChanged(int,QString)), this, + SLOT(updateBatteryChargePercent(int,QString))); + connect(battery, SIGNAL(plugStateChanged(bool,QString)), this, + SLOT(updateBatteryPlugState(bool,QString))); + + // Set initial values + updateBatteryChargeState(battery->chargeState(), deviceBattery.udi()); + updateBatteryChargePercent(battery->chargePercent(), deviceBattery.udi()); + updateBatteryPlugState(battery->isPlugged(), deviceBattery.udi()); + updateBatteryPowerSupplyState(battery->isPowerSupply(), deviceBattery.udi()); + + setData(source, "Vendor", deviceBattery.vendor()); + setData(source, "Product", deviceBattery.product()); + setData(source, "Capacity", battery->capacity()); + setData(source, "Type", batteryType(battery)); + } + + updateBatteryNames(); + + setData("Battery", "Has Battery", !batterySources.isEmpty()); + if (!batterySources.isEmpty()) { + setData("Battery", "Sources", batterySources); + QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", + "batteryRemainingTime"); + QDBusPendingReply reply = QDBusConnection::sessionBus().asyncCall(msg); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(batteryRemainingTimeReply(QDBusPendingCallWatcher*))); + } + + m_sources = basicSourceNames() + batterySources; + } else if (name == "AC Adapter") { + bool isPlugged = false; + + const QList list_ac = Solid::Device::listFromType(Solid::DeviceInterface::AcAdapter); + foreach (const Solid::Device & device_ac, list_ac) { + const Solid::AcAdapter* acadapter = device_ac.as(); + isPlugged |= acadapter->isPlugged(); + connect(acadapter, SIGNAL(plugStateChanged(bool,QString)), this, + SLOT(updateAcPlugState(bool)), Qt::UniqueConnection); + } + + updateAcPlugState(isPlugged); + } else if (name == "Sleep States") { + const QSet sleepstates = + Solid::PowerManagement::supportedSleepStates(); + // We first set all possible sleepstates to false, then enable the ones that are available + setData("Sleep States", "Standby", false); + setData("Sleep States", "Suspend", false); + setData("Sleep States", "Hibernate", false); + + foreach (const Solid::PowerManagement::SleepState &sleepstate, sleepstates) { + if (sleepstate == Solid::PowerManagement::StandbyState) { + setData("Sleep States", "Standby", true); + } else if (sleepstate == Solid::PowerManagement::SuspendState) { + setData("Sleep States", "Suspend", true); + } else if (sleepstate == Solid::PowerManagement::HibernateState) { + setData("Sleep States", "Hibernate", true); + } + //kDebug() << "Sleepstate \"" << sleepstate << "\" supported."; + } + } else if (name == "PowerDevil") { + if (m_brightnessControlsAvailable) { + QDBusMessage screenMsg = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement/Actions/BrightnessControl", + "org.kde.Solid.PowerManagement.Actions.BrightnessControl", + "brightness"); + QDBusPendingReply screenReply = QDBusConnection::sessionBus().asyncCall(screenMsg); + QDBusPendingCallWatcher *screenWatcher = new QDBusPendingCallWatcher(screenReply, this); + QObject::connect(screenWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(screenBrightnessReply(QDBusPendingCallWatcher*))); + } + + if (m_keyboardBrightnessControlsAvailable) { + QDBusMessage keyboardMsg = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl", + "org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl", + "keyboardBrightness"); + QDBusPendingReply keyboardReply = QDBusConnection::sessionBus().asyncCall(keyboardMsg); + QDBusPendingCallWatcher *keyboardWatcher = new QDBusPendingCallWatcher(keyboardReply, this); + QObject::connect(keyboardWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(keyboardBrightnessReply(QDBusPendingCallWatcher*))); + } + //any info concerning lock screen/screensaver goes here + } else if (name == "UserActivity") { + setData("UserActivity", "IdleTime", KIdleTime::instance()->idleTime()); + } else { + kDebug() << "Data for '" << name << "' not found"; + return false; + } + return true; +} + +QString PowermanagementEngine::batteryType(const Solid::Battery* battery) +{ + switch(battery->type()) { + case Solid::Battery::PrimaryBattery: + return QLatin1String("Battery"); + break; + case Solid::Battery::UpsBattery: + return QLatin1String("Ups"); + break; + case Solid::Battery::MonitorBattery: + return QLatin1String("Monitor"); + break; + case Solid::Battery::MouseBattery: + return QLatin1String("Mouse"); + break; + case Solid::Battery::KeyboardBattery: + return QLatin1String("Keyboad"); + break; + case Solid::Battery::PdaBattery: + return QLatin1String("Pda"); + break; + case Solid::Battery::PhoneBattery: + return QLatin1String("Phone"); + break; + default: + return QLatin1String("Unknown"); + } + + return QLatin1String("Unknown"); +} + +bool PowermanagementEngine::updateSourceEvent(const QString &source) +{ + if (source == "UserActivity") { + setData("UserActivity", "IdleTime", KIdleTime::instance()->idleTime()); + return true; + } + return Plasma::DataEngine::updateSourceEvent(source); +} + +Plasma::Service* PowermanagementEngine::serviceForSource(const QString &source) +{ + if (source == "PowerDevil") { + return new PowerManagementService(this); + } + + return 0; +} + +void PowermanagementEngine::updateBatteryChargeState(int newState, const QString& udi) +{ + QString state("Unknown"); + if (newState == Solid::Battery::NoCharge) { + state = "NoCharge"; + } else if (newState == Solid::Battery::Charging) { + state = "Charging"; + } else if (newState == Solid::Battery::Discharging) { + state = "Discharging"; + } + + const QString source = m_batterySources[udi]; + setData(source, "State", state); +} + +void PowermanagementEngine::updateBatteryPlugState(bool newState, const QString& udi) +{ + const QString source = m_batterySources[udi]; + setData(source, "Plugged in", newState); +} + +void PowermanagementEngine::updateBatteryChargePercent(int newValue, const QString& udi) +{ + const QString source = m_batterySources[udi]; + setData(source, "Percent", newValue); +} + +void PowermanagementEngine::updateBatteryPowerSupplyState(bool newState, const QString& udi) +{ + const QString source = m_batterySources[udi]; + setData(source, "Is Power Supply", newState); +} + +void PowermanagementEngine::updateBatteryNames() +{ + uint unnamedBatteries = 0; + foreach (QString source, m_batterySources) { + DataContainer *batteryDataContainer = containerForSource(source); + if (batteryDataContainer) { + const QString batteryVendor = batteryDataContainer->data()["Vendor"].toString(); + const QString batteryProduct = batteryDataContainer->data()["Product"].toString(); + + // Don't show battery name for primary power supply batteries. They usually have cryptic serial number names. + const bool showBatteryName = batteryDataContainer->data()["Type"].toString() != QLatin1String("Battery") || + !batteryDataContainer->data()["Is Power Supply"].toBool(); + + if (!batteryProduct.isEmpty() && batteryProduct != "Unknown Battery" && showBatteryName) { + if (!batteryVendor.isEmpty()) { + setData(source, "Pretty Name", QString(batteryVendor + ' ' + batteryProduct)); + } else { + setData(source, "Pretty Name", batteryProduct); + } + } else { + ++unnamedBatteries; + if (unnamedBatteries > 1) { + setData(source, "Pretty Name", i18nc("Placeholder is the battery number", "Battery %1", unnamedBatteries)); + } else { + setData(source, "Pretty Name", i18n("Battery")); + } + } + } + } +} + +void PowermanagementEngine::updateAcPlugState(bool newState) +{ + setData("AC Adapter", "Plugged in", newState); +} + +void PowermanagementEngine::deviceRemoved(const QString& udi) +{ + if (m_batterySources.contains(udi)) { + Solid::Device device(udi); + Solid::Battery* battery = device.as(); + if (battery) + battery->disconnect(); + + const QString source = m_batterySources[udi]; + m_batterySources.remove(udi); + removeSource(source); + + QStringList sourceNames(m_batterySources.values()); + sourceNames.removeAll(source); + setData("Battery", "Sources", sourceNames); + setData("Battery", "Has Battery", !sourceNames.isEmpty()); + } +} + +void PowermanagementEngine::deviceAdded(const QString& udi) +{ + Solid::Device device(udi); + if (device.isValid()) { + const Solid::Battery* battery = device.as(); + + if (battery) { + int index = 0; + QStringList sourceNames(m_batterySources.values()); + while (sourceNames.contains(QString("Battery%1").arg(index))) { + index++; + } + + const QString source = QString("Battery%1").arg(index); + sourceNames << source; + m_batterySources[device.udi()] = source; + + connect(battery, SIGNAL(chargeStateChanged(int,QString)), this, + SLOT(updateBatteryChargeState(int,QString))); + connect(battery, SIGNAL(chargePercentChanged(int,QString)), this, + SLOT(updateBatteryChargePercent(int,QString))); + connect(battery, SIGNAL(plugStateChanged(bool,QString)), this, + SLOT(updateBatteryPlugState(bool,QString))); + connect(battery, SIGNAL(powerSupplyStateChanged(bool,QString)), this, + SLOT(updateBatteryPowerSupplyState(bool,QString))); + + // Set initial values + updateBatteryChargeState(battery->chargeState(), device.udi()); + updateBatteryChargePercent(battery->chargePercent(), device.udi()); + updateBatteryPlugState(battery->isPlugged(), device.udi()); + updateBatteryPowerSupplyState(battery->isPowerSupply(), device.udi()); + + setData(source, "Vendor", device.vendor()); + setData(source, "Product", device.product()); + setData(source, "Capacity", battery->capacity()); + setData(source, "Type", batteryType(battery)); + + setData("Battery", "Sources", sourceNames); + setData("Battery", "Has Battery", !sourceNames.isEmpty()); + + updateBatteryNames(); + } + } +} + +void PowermanagementEngine::batteryRemainingTimeChanged(qulonglong time) +{ + //kDebug() << "Remaining time 2:" << time; + setData("Battery", "Remaining msec", time); +} + +void PowermanagementEngine::brightnessControlsAvailableChanged(bool available) +{ + setData("PowerDevil", "Screen Brightness Available", available); + m_brightnessControlsAvailable = available; +} + +void PowermanagementEngine::keyboardBrightnessControlsAvailableChanged(bool available) +{ + setData("PowerDevil", "Keyboard Brightness Available", available); + m_keyboardBrightnessControlsAvailable = available; +} + +void PowermanagementEngine::batteryRemainingTimeReply(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply reply = *watcher; + if (reply.isError()) { + kDebug() << "Error getting battery remaining time: " << reply.error().message(); + } else { + batteryRemainingTimeChanged(reply.value()); + } + + watcher->deleteLater(); +} + +void PowermanagementEngine::screenBrightnessChanged(int brightness) +{ + setData("PowerDevil", "Screen Brightness", brightness); +} + +void PowermanagementEngine::keyboardBrightnessChanged(int brightness) +{ + setData("PowerDevil", "Keyboard Brightness", brightness); +} + +void PowermanagementEngine::screenBrightnessReply(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply reply = *watcher; + if (reply.isError()) { + kDebug() << "Error getting screen brightness: " << reply.error().message(); + // FIXME Because the above check doesn't work, we unclaim backlight support as soon as it fails + brightnessControlsAvailableChanged(false); + } else { + screenBrightnessChanged(reply.value()); + } + + watcher->deleteLater(); +} + +void PowermanagementEngine::keyboardBrightnessReply(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply reply = *watcher; + if (reply.isError()) { + kDebug() << "Error getting keyboard brightness: " << reply.error().message(); + // FIXME Because the above check doesn't work, we unclaim backlight support as soon as it fails + keyboardBrightnessControlsAvailableChanged(false); + } else { + keyboardBrightnessChanged(reply.value()); + } + + watcher->deleteLater(); +} + +K_EXPORT_PLASMA_DATAENGINE(powermanagement, PowermanagementEngine) + +#include "powermanagementengine.moc" diff --git a/plasma/generic/dataengines/powermanagement/powermanagementengine.h b/plasma/generic/dataengines/powermanagement/powermanagementengine.h new file mode 100644 index 00000000..dafb6c28 --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/powermanagementengine.h @@ -0,0 +1,86 @@ +/* + * Copyright 2007 Aaron Seigo + * Copyright 2007-2008 Sebastian Kuegler + * Copyright 2008 Dario Freddi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef POWERMANAGEMENTENGINE_H +#define POWERMANAGEMENTENGINE_H + +#include + +#include +#include + +#include +#include + +class QDBusPendingCallWatcher; + +/** + * This class provides runtime information about the battery and AC status + * for use in power management Plasma applets. + */ +class PowermanagementEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + PowermanagementEngine( QObject* parent, const QVariantList& args ); + ~PowermanagementEngine(); + QStringList sources() const; + Plasma::Service* serviceForSource(const QString &source); + +protected: + bool sourceRequestEvent(const QString &name); + bool updateSourceEvent(const QString &source); + void init(); + +private slots: + void updateBatteryChargeState(int newState, const QString& udi); + void updateBatteryPlugState(bool newState, const QString& udi); + void updateBatteryChargePercent(int newValue, const QString& udi); + void updateBatteryPowerSupplyState(bool newState, const QString& udi); + void updateAcPlugState(bool newState); + void updateBatteryNames(); + + void deviceRemoved(const QString& udi); + void deviceAdded(const QString& udi); + void batteryRemainingTimeChanged(qulonglong time); + void batteryRemainingTimeReply(QDBusPendingCallWatcher*); + void screenBrightnessChanged(int brightness); + void keyboardBrightnessChanged(int brightness); + void screenBrightnessReply(QDBusPendingCallWatcher *watcher); + void keyboardBrightnessReply(QDBusPendingCallWatcher *watcher); + void brightnessControlsAvailableChanged(bool available); + void keyboardBrightnessControlsAvailableChanged(bool available); + +private: + QString batteryType(const Solid::Battery *battery); + QStringList basicSourceNames() const; + + QStringList m_sources; + + QHash m_batterySources; // + + bool m_brightnessControlsAvailable; + bool m_keyboardBrightnessControlsAvailable; + +}; + + +#endif diff --git a/plasma/generic/dataengines/powermanagement/powermanagementjob.cpp b/plasma/generic/dataengines/powermanagement/powermanagementjob.cpp new file mode 100644 index 00000000..06156d98 --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/powermanagementjob.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2011 Sebastian Kügler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include + +// kde-workspace/libs +#include + +#include + +#include "powermanagementjob.h" + +#include + +#include + +PowerManagementJob::PowerManagementJob(const QString &operation, QMap ¶meters, QObject *parent) : + ServiceJob(parent->objectName(), operation, parameters, parent) +{ +} + +PowerManagementJob::~PowerManagementJob() +{ +} + +void PowerManagementJob::start() +{ + const QString operation = operationName(); + //kDebug() << "starting operation ... " << operation; + + if (operation == "lockScreen") { + if (KAuthorized::authorizeKAction("lock_screen")) { + const QString interface("org.freedesktop.ScreenSaver"); + QDBusInterface screensaver(interface, "/ScreenSaver"); + screensaver.asyncCall("Lock"); + setResult(true); + return; + } + kDebug() << "operation denied " << operation; + setResult(false); + return; + } else if (operation == "suspend" || operation == "suspendToRam") { + setResult(suspend(Ram)); + return; + } else if (operation == "suspendToDisk") { + setResult(suspend(Disk)); + return; + } else if (operation == "suspendHybrid") { + setResult(suspend(Hybrid)); + return; + } else if (operation == "requestShutDown") { + requestShutDown(); + setResult(true); + return; + } else if (operation == "switchUser") { + // Taken from kickoff/core/itemhandlers.cpp + org::kde::krunner::App krunner("org.kde.krunner", "/App", QDBusConnection::sessionBus()); + krunner.switchUser(); + setResult(true); + return; + } else if (operation == "beginSuppressingSleep") { + setResult(Solid::PowerManagement::beginSuppressingSleep(parameters().value("reason").toString())); + return; + } else if (operation == "stopSuppressingSleep") { + setResult(Solid::PowerManagement::stopSuppressingSleep(parameters().value("cookie").toInt())); + return; + } else if (operation == "beginSuppressingScreenPowerManagement") { + setResult(Solid::PowerManagement::beginSuppressingScreenPowerManagement(parameters().value("reason").toString())); + return; + } else if (operation == "stopSuppressingScreenPowerManagement") { + setResult(Solid::PowerManagement::stopSuppressingScreenPowerManagement(parameters().value("cookie").toInt())); + return; + } else if (operation == "setBrightness") { + setScreenBrightness(parameters().value("brightness").toInt()); + setResult(true); + return; + } else if (operation == "setKeyboardBrightness") { + setKeyboardBrightness(parameters().value("brightness").toInt()); + setResult(true); + return; + } + + kDebug() << "don't know what to do with " << operation; + setResult(false); +} + +bool PowerManagementJob::suspend(const SuspendType &type) +{ + QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement/Actions/SuspendSession", + "org.kde.Solid.PowerManagement.Actions.SuspendSession", + callForType(type)); + QDBusConnection::sessionBus().asyncCall(msg); + return true; +} + +QString PowerManagementJob::callForType(const SuspendType &type) +{ + switch (type) { + case Disk: + return "suspendToDisk"; + break; + + case Hybrid: + return "suspendHybrid"; + break; + + default: + return "suspendToRam"; + break; + } +} + +void PowerManagementJob::setScreenBrightness(int value) +{ + QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement/Actions/BrightnessControl", + "org.kde.Solid.PowerManagement.Actions.BrightnessControl", + "setBrightness"); + msg << value; + QDBusConnection::sessionBus().asyncCall(msg); +} + +void PowerManagementJob::setKeyboardBrightness(int value) +{ + QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement/Actions/KeyboardBrightnessControl", + "org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl", + "setKeyboardBrightness"); + msg << value; + QDBusConnection::sessionBus().asyncCall(msg); +} + +void PowerManagementJob::requestShutDown() +{ + KWorkSpace::requestShutDown(); +} + +#include "powermanagementjob.moc" diff --git a/plasma/generic/dataengines/powermanagement/powermanagementjob.h b/plasma/generic/dataengines/powermanagement/powermanagementjob.h new file mode 100644 index 00000000..c1c7bf4a --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/powermanagementjob.h @@ -0,0 +1,47 @@ +/* + * Copyright 2011 Sebastian Kügler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef POWERMANAGEMENTJOB_H +#define POWERMANAGEMENTJOB_H + +// plasma +#include + +class PowerManagementJob : public Plasma::ServiceJob +{ + + Q_OBJECT + + public: + PowerManagementJob(const QString &operation, QMap ¶meters, + QObject *parent = 0); + ~PowerManagementJob(); + + protected: + void start(); + + private: + enum SuspendType { Ram, Disk, Hybrid }; + bool suspend(const SuspendType &type); + void requestShutDown(); + QString callForType(const SuspendType &type); + void setScreenBrightness(int value); + void setKeyboardBrightness(int value); +}; + +#endif // POWERMANAGEMENTJOB_H diff --git a/plasma/generic/dataengines/powermanagement/powermanagementservice.cpp b/plasma/generic/dataengines/powermanagement/powermanagementservice.cpp new file mode 100644 index 00000000..e5f2f5d7 --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/powermanagementservice.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2011 Sebastian Kügler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "powermanagementservice.h" +#include "powermanagementjob.h" + +PowerManagementService::PowerManagementService(QObject *parent) + : Plasma::Service(parent) +{ + setName("powermanagementservice"); +} + +ServiceJob *PowerManagementService::createJob(const QString &operation, + QMap ¶meters) +{ + return new PowerManagementJob(operation, parameters, this); +} + +#include "powermanagementservice.moc" diff --git a/plasma/generic/dataengines/powermanagement/powermanagementservice.h b/plasma/generic/dataengines/powermanagement/powermanagementservice.h new file mode 100644 index 00000000..9976ecab --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/powermanagementservice.h @@ -0,0 +1,39 @@ +/* + * Copyright 2011 Sebastian Kügler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef POWERMANAGEMENTSERVICE_H +#define POWERMANAGEMENTSERVICE_H + + +#include +#include + +using namespace Plasma; + + +class PowerManagementService : public Plasma::Service +{ + Q_OBJECT + +public: + PowerManagementService(QObject *parent = 0); + ServiceJob *createJob(const QString &operation, QMap ¶meters); +}; + +#endif // POWERMANAGEMENTSERVICE_H diff --git a/plasma/generic/dataengines/powermanagement/powermanagementservice.operations b/plasma/generic/dataengines/powermanagement/powermanagementservice.operations new file mode 100644 index 00000000..c9abbf9c --- /dev/null +++ b/plasma/generic/dataengines/powermanagement/powermanagementservice.operations @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/rss/CMakeLists.txt b/plasma/generic/dataengines/rss/CMakeLists.txt new file mode 100644 index 00000000..a1aec8c2 --- /dev/null +++ b/plasma/generic/dataengines/rss/CMakeLists.txt @@ -0,0 +1,13 @@ + +include_directories(${Boost_INCLUDE_DIR} ${KDEPIMLIBS_INCLUDE_DIR}) + +set(rss_engine_SRCS + rss.cpp +) + +kde4_add_plugin(plasma_engine_rss ${rss_engine_SRCS}) +target_link_libraries(plasma_engine_rss ${KDE4_PLASMA_LIBS} ${KDE4_KDECORE_LIBS} ${KDE4_SYNDICATION_LIBS} ${KDE4_SOLID_LIBS}) + +install(TARGETS plasma_engine_rss DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-rss.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/plasma/generic/dataengines/rss/Messages.sh b/plasma/generic/dataengines/rss/Messages.sh new file mode 100755 index 00000000..85329a4f --- /dev/null +++ b/plasma/generic/dataengines/rss/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_rss.pot diff --git a/plasma/generic/dataengines/rss/plasma-dataengine-rss.desktop b/plasma/generic/dataengines/rss/plasma-dataengine-rss.desktop new file mode 100644 index 00000000..e4c47b5f --- /dev/null +++ b/plasma/generic/dataengines/rss/plasma-dataengine-rss.desktop @@ -0,0 +1,165 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=RSS +Name[ar]=آر إس إس +Name[ast]=RSS +Name[be@latin]=RSS +Name[bg]=RSS +Name[bn]=RSS +Name[bn_IN]=RSS +Name[bs]=RSS +Name[ca]=RSS +Name[ca@valencia]=RSS +Name[cs]=RSS +Name[da]=RSS +Name[de]=RSS +Name[el]=RSS +Name[en_GB]=RSS +Name[eo]=RSS +Name[es]=RSS +Name[et]=RSS +Name[eu]=RSS +Name[fi]=RSS +Name[fr]=RSS +Name[fy]=RSS +Name[ga]=RSS +Name[gl]=RSS +Name[gu]=RSS +Name[he]=RSS +Name[hi]=आरएसएस +Name[hne]=आरएसएस +Name[hr]=RSS +Name[hu]=RSS-hírek +Name[ia]=RSS +Name[id]=RSS +Name[is]=RSS +Name[it]=RSS +Name[ja]=RSS +Name[ka]=RSS +Name[kk]=RSS +Name[km]=RSS +Name[kn]=RSS +Name[ko]=RSS +Name[ku]=RSS +Name[lt]=RSS +Name[lv]=RSS +Name[mai]=RSS +Name[mk]=RSS +Name[ml]=ആര്‍എസ്എസ് +Name[mr]=RSS +Name[nb]=RSS +Name[nds]=RSS +Name[nl]=RSS +Name[nn]=RSS +Name[or]=RSS +Name[pa]=RSS +Name[pl]=RSS +Name[pt]=RSS +Name[pt_BR]=RSS +Name[ro]=RSS +Name[ru]=Ленты новостей RSS +Name[si]=RSS +Name[sk]=RSS +Name[sl]=RSS +Name[sr]=РСС +Name[sr@ijekavian]=РСС +Name[sr@ijekavianlatin]=RSS +Name[sr@latin]=RSS +Name[sv]=RSS +Name[ta]=RSS +Name[te]=RSS +Name[tg]=Наворҳои RSS +Name[th]=หัวข้อข่าว (RSS) +Name[tr]=RSS +Name[ug]=RSS +Name[uk]=RSS +Name[wa]=RSS +Name[x-test]=xxRSSxx +Name[zh_CN]=RSS +Name[zh_TW]=RSS +Comment=RSS News Data Engine +Comment[ar]=محرك بيانات الخلاصات +Comment[ast]=Motor de RSS +Comment[be@latin]=Systema navinaŭ z žarołaŭ „RSS” +Comment[bg]=Зареждане на RSS емисии +Comment[bn_IN]=RSS খবরের ডাটা ইঞ্জিন +Comment[bs]=Datomotor RSS vesti +Comment[ca]=Motor de dades de notícies RSS +Comment[ca@valencia]=Motor de dades de notícies RSS +Comment[cs]=Služba RSS novinek +Comment[csb]=Mòtór pòdôwków dlô pòwrózków RSS +Comment[da]=Datamotor til RSS-nyheder +Comment[de]=Datentreiber für RSS-News +Comment[el]=Μηχανή δεδομένων ειδήσεων RSS +Comment[en_GB]=RSS News Data Engine +Comment[eo]=Datuma Motoro de RSS novaĵoj +Comment[es]=Motor de RSS +Comment[et]=RSS-voogude andmete mootor +Comment[eu]=RSS berrien datu-motorra +Comment[fi]=RSS-syötetietomoottori +Comment[fr]=Moteur de données des flux RSS +Comment[fy]=RSS nijs gegevens motor +Comment[ga]=Inneall Sonraí Nuachta RSS +Comment[gl]=Motor de datos de novas RSS +Comment[gu]=RSS સમાચાર માહિતી એન્જિન +Comment[he]=מנוע תוכן חדשות RSS +Comment[hi]=आरएसएस समाचार डाटा इंजिन +Comment[hne]=आरएसएस समाचार डाटा इंजन +Comment[hr]=Podatkovni mehanizam za vijesti preko RSS-a +Comment[hu]=RSS-hírkezelő +Comment[ia]=Motor de datos de novitates RSS +Comment[id]=Mesin Data Berita RSS +Comment[is]=RSS fréttagagnavél +Comment[it]=Motore di dati delle notizie RSS +Comment[ja]=RSS ニュースデータエンジン +Comment[kk]=RSS ақпарлар тетігі +Comment[km]=ម៉ាស៊ីន​ទិន្នន័យព័ត៌មាន RSS +Comment[kn]=RSS ಸುದ್ದಿ ದತ್ತಾಂಶ ಎಂಜಿನ್ +Comment[ko]=RSS 뉴스 데이터 엔진 +Comment[ku]=Motora Dane yên Nûçe yên RSS +Comment[lt]=RSS naujienų duomenų variklis +Comment[lv]=RSS ziņu datu dzinējs +Comment[ml]=ആര്‍എസ്എസ് ന്യൂസ് ഡേറ്റാ എഞ്ചിന്‍ +Comment[mr]=RSS समाचार डेटा इंजिन +Comment[nb]=RSS nyhets-datamotor +Comment[nds]=RSS-Stroom-Datenkarn +Comment[nl]=RSS-nieuws (gegevensengine) +Comment[nn]=Nyheitsmotor for RSS +Comment[or]=RSS ଖବର ତଥ୍ୟ ଯନ୍ତ୍ର +Comment[pa]=RSS ਖ਼ਬਰਾਂ ਡਾਟਾ ਇੰਜਣ +Comment[pl]=Silnik danych wiadomości RSS +Comment[pt]=Motor de Dados de Notícias RSS +Comment[pt_BR]=Mecanismo de dados de notícias RSS +Comment[ro]=Motor de date pentru știri RSS +Comment[ru]=Показ новостей из лент RSS +Comment[si]=RSS ප්‍රවෘත්ති දත්ත එන්ජිම +Comment[sk]=Dátový nástroj RSS noviniek +Comment[sl]=Podatkovni pogon za novice RSS +Comment[sr]=Датомотор РСС вести +Comment[sr@ijekavian]=Датомотор РСС вести +Comment[sr@ijekavianlatin]=Datomotor RSS vesti +Comment[sr@latin]=Datomotor RSS vesti +Comment[sv]=Datagränssnitt för RSS-nyheter +Comment[ta]=RSS News Data Engine +Comment[tg]=Поставщик лент RSS +Comment[th]=กลไกข้อมูล รับหัวข้อข่าว (RSS) +Comment[tr]=RSS Haber Veri Motoru +Comment[ug]=RSS خەۋەر سانلىق-مەلۇمات ماتورى +Comment[uk]=Рушій даних новин RSS +Comment[wa]=Moteur di dnêyes des noveles RSS +Comment[x-test]=xxRSS News Data Enginexx +Comment[zh_CN]=RSS 新闻数据引擎 +Comment[zh_TW]=RSS 新聞資料引擎 +ServiceTypes=Plasma/DataEngine +Type=Service +Icon=application-rss+xml +X-KDE-Library=plasma_engine_rss + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=rss +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/rss/rss.cpp b/plasma/generic/dataengines/rss/rss.cpp new file mode 100644 index 00000000..f3bab730 --- /dev/null +++ b/plasma/generic/dataengines/rss/rss.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2007 Aaron Seigo + * Copyright (C) 2007 Petri Damsten + * Copyright (C) 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +//Own +#include "rss.h" + +//KDE +#include +#include +#include +#include +#include +#include +#include +#include + +//Plasma +#include + +//Qt +#include +#include +#include +#include +#include + +#define TIMEOUT 15000 //timeout before updating the source if not all feeds + //are fetched. +#define CACHE_TIMEOUT 60 //time in seconds before the cached feeds are marked + //as out of date. +#define MINIMUM_INTERVAL 60000 +#define FAVICONINTERFACE "org.kde.FavIcon" + +RssEngine::RssEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args), + m_forceUpdate(false) +{ + Q_UNUSED(args) + setMinimumPollingInterval(MINIMUM_INTERVAL); + m_favIconsModule = new QDBusInterface("org.kde.kded", "/modules/favicons", + FAVICONINTERFACE); + m_signalMapper = new QSignalMapper(this); + connect(m_favIconsModule, SIGNAL(iconChanged(bool,QString,QString)), + this, SLOT(slotIconChanged(bool,QString,QString))); + connect(m_signalMapper, SIGNAL(mapped(QString)), + this, SLOT(timeout(QString))); + connect(Solid::Networking::notifier(), SIGNAL(statusChanged(Solid::Networking::Status)), + SLOT(networkStatusChanged(Solid::Networking::Status))); + +} + +RssEngine::~RssEngine() +{ + delete m_favIconsModule; +} + +void RssEngine::networkStatusChanged(Solid::Networking::Status status) +{ + if (status == Solid::Networking::Connected || status == Solid::Networking::Unknown) { + kDebug() << "network connected, force refreshing feeds in 3 seconds"; + // The forced update needs to happen after the new feeds are in, + // so remember to force the update in processRss() + m_forceUpdate = true; + // start updating the feeds + foreach(const QString &feedUrl, sources()) { + updateSourceEvent(feedUrl); + } + } +} + +bool RssEngine::updateSourceEvent(const QString &name) +{ + /* Plasmoids using this engine should be able to retrieve + * multiple feeds at the same time, so we allow a comma + * separated list of url's + */ + // NOTE: A comma separated list of feeds is not url compliant. Urls + // may and do contain commas see http://www.spiegel.de/schlagzeilen/rss/0,5291,,00.xml + // I have changed it to something more not url compliant " " three dots + // Otherwise take a list instead + const QStringList sources = name.split(' ', QString::SkipEmptyParts); + + foreach (const QString& source, sources) { + setStorageEnabled(source, true); + // Let's first see if we've got a recent cached version of + // the feed. This avoids 'large' amounts of unnecessary network + // traffic. + if (QDateTime::currentDateTime() > + m_feedTimes[source.toLower()].addSecs(CACHE_TIMEOUT)){ + kDebug() << "Cache from " << source << + " older than 60 seconds, refreshing..."; + + Syndication::Loader * loader = Syndication::Loader::create(); + connect(loader, SIGNAL(loadingComplete(Syndication::Loader*, + Syndication::FeedPtr, + Syndication::ErrorCode)), + this, SLOT(processRss(Syndication::Loader*, + Syndication::FeedPtr, + Syndication::ErrorCode))); + + m_feedMap.insert(loader, source); + m_sourceMap.insert(loader, name); + loader->loadFrom(source); + } else { + kDebug() << "Recent cached version of " << source << + " found. Skipping..."; + + // We might want to update the source: + if (cachesUpToDate(name)) { + updateFeeds(name, m_feedTitles[ source ] ); + } + } + } + + QTimer *timer = new QTimer(this); + m_timerMap[name] = timer; + timer->setSingleShot(true); + m_signalMapper->setMapping(timer, name); + + connect(timer, SIGNAL(timeout()), m_signalMapper, SLOT(map())); + + timer->start(TIMEOUT); + return true; +} + +void RssEngine::slotIconChanged(bool isHost, const QString& hostOrURL, + const QString& iconName) +{ + Q_UNUSED(isHost); + const QString iconFile = KGlobal::dirs()->findResource("cache", + iconName+".png"); + const QString url = hostOrURL.toLower(); + + m_feedIcons[url] = iconFile; + QMap map; + + for (int i = 0; i < m_feedItems[url].size(); i++) { + map = m_feedItems[url].at(i).toMap(); + map["icon"] = iconFile; + m_feedItems[url].replace(i, map); + } + + //Are there sources ready to get updated now? + foreach (const QString& source, m_sourceMap) { + if (source.contains(url, Qt::CaseInsensitive) && + cachesUpToDate(source)) { + kDebug() << "all caches from source " << source << + " up to date, updating..."; + updateFeeds(source, m_feedTitles[ source ] ); + } + } +} + +void RssEngine::timeout(const QString & source) +{ + kDebug() << "timout fired, updating source"; + updateFeeds(source, m_feedTitles[ source ] ); + m_signalMapper->removeMappings(m_timerMap[source]); +} + +bool RssEngine::sourceRequestEvent(const QString &name) +{ + setData(name, DataEngine::Data()); + updateSourceEvent(name); + return true; +} + +void RssEngine::processRss(Syndication::Loader* loader, + Syndication::FeedPtr feed, + Syndication::ErrorCode error) +{ + const QString url = m_feedMap.take(loader); + const QString source = m_sourceMap.take(loader); + QString title; + bool iconRequested = false; + KUrl u(url); + + if (error != Syndication::Success) { + kDebug() << "Syndication did not work out... url = " << url; + title = i18n("Syndication did not work out"); + setData(source, "title", i18n("Fetching feed failed.")); + setData(source, "link", url); + } else { + title = feed->title(); + QVariantList items; + QString location; + + foreach (const Syndication::ItemPtr& item, feed->items()) { + QMap dataItem; + + //some malformed rss feeds can have empty entries + if (item->title().isNull() && item->description().isNull() && dataItem["content"].isNull()) { + continue; + } + + dataItem["title"] = item->title(); + dataItem["feed_title"] = feed->title(); + dataItem["link"] = item->link(); + dataItem["feed_url"] = url; + dataItem["description"] = item->description(); + dataItem["content"] = item->content(); + dataItem["time"] = (uint)item->dateUpdated(); + if (!m_feedIcons.contains(url.toLower()) && !iconRequested) { + //lets request an icon, and only do this once per feed. + location = iconLocation(u); + if (location.isEmpty()) { + m_favIconsModule->call( "downloadHostIcon", u.url() ); + } else { + //the icon is already in cache, so call this slot manually. + slotIconChanged(false, u.url(), iconLocation(u)); + } + iconRequested = true; + } + dataItem["icon"] = m_feedIcons[url.toLower()]; + QStringList authors; + foreach (const boost::shared_ptr a, item->authors()) { + authors << a->name(); + } + dataItem["author"] = authors; + + items.append(dataItem); + + + if (!m_rssSourceNames.contains(url)) { + QMap sourceItem; + + sourceItem["feed_title"] = feed->title(); + sourceItem["feed_url"] = url; + sourceItem["icon"] = m_feedIcons[url.toLower()]; + + m_rssSources.append(sourceItem); + m_rssSourceNames.insert(url); + } + } + m_feedItems[url.toLower()] = items; + m_feedTimes[url.toLower()] = QDateTime::currentDateTime(); + m_feedTitles[url.toLower()] = title; + + // If we update the feeds every time a feed is fetched, + // only the first update will actually update a connected + // applet, which is actually sane, since plasma updates + // only one time each interval. This means, however, that + // we maybe want to delay updating the feeds untill either + // timeout, or all feeds are up to date. + if (cachesUpToDate(source)) { + kDebug() << "all caches from source " << source + << " up to date, updating..."; + updateFeeds(source, title); + if (m_forceUpdate) { + // Should be used with care ... + forceImmediateUpdateOfAllVisualizations(); + m_forceUpdate = false; + // and skip scheduleSourcesUpdated(), since we + // force a repaint anyway already + return; + } + } else { + kDebug() << "not all caches from source " << source + << ", delaying update."; + } + scheduleSourcesUpdated(); + } +} + +void RssEngine::updateFeeds(const QString & source, const QString & title) +{ + /** + * TODO: can this be improved? I'm calling mergeFeeds way too + * often here... + */ + const QVariantList list = mergeFeeds(source); + setData(source, "items", list); + + setData(source, "sources", m_rssSources); + const QStringList sourceNames = source.split(' ', QString::SkipEmptyParts); + if (sourceNames.size() > 1) { + setData(source, "title", i18np("1 RSS feed fetched", + "%1 RSS feeds fetched", sourceNames.size())); + } else { + setData(source, "title", title); + } +} + +bool RssEngine::cachesUpToDate(const QString & source) const +{ + const QStringList sources = source.split(' ', QString::SkipEmptyParts); + bool outOfDate = false; + foreach (const QString &url, sources) { + if (QDateTime::currentDateTime() > + m_feedTimes[url.toLower()].addSecs(CACHE_TIMEOUT)){ + outOfDate = true; + } + if (!m_feedIcons.contains(url.toLower())) { + outOfDate = true; + } + } + return (!outOfDate); +} + +bool compare(const QVariant &v1, const QVariant &v2) +{ + return v1.toMap()["time"].toUInt() > v2.toMap()["time"].toUInt(); +} + +QVariantList RssEngine::mergeFeeds(QString source) const +{ + QVariantList result; + const QStringList sources = source.split(' ', QString::SkipEmptyParts); + + foreach (const QString& feed, sources) { + result += m_feedItems[feed.toLower()]; + } + + qSort(result.begin(), result.end(), compare); + return result; +} + +QString RssEngine::iconLocation(const KUrl & url) const +{ + QDBusReply reply = m_favIconsModule->call( "iconForUrl", url.url() ); + if (reply.isValid()) { + QString result = reply; + return result; + } + return QString(); +} + +#include "rss.moc" + diff --git a/plasma/generic/dataengines/rss/rss.h b/plasma/generic/dataengines/rss/rss.h new file mode 100644 index 00000000..153a9c38 --- /dev/null +++ b/plasma/generic/dataengines/rss/rss.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 Aaron Seigo + * Copyright (C) 2007 Petri Damsten + * Copyright (C) 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef RSS_DATAENGINE_H +#define RSS_DATAENGINE_H + +#include +#include +#include +#include +#include +#include + +class QDBusInterface; +class QSignalMapper; + +/** + * This class can be used to fetch one or more rss feeds. By + * requesting a datasource with the url's of one or more rss + * feeds separated by " ", you will receive a merged list + * containing the items of all feeds requested. This list is + * sorted by timestamp. + * This class also fetches the favicons from all requested + * feeds. + */ +class RssEngine : public Plasma::DataEngine +{ + Q_OBJECT + + public: + RssEngine(QObject* parent, const QVariantList& args); + virtual ~RssEngine(); + + protected: + bool sourceRequestEvent(const QString &name); + bool updateSourceEvent(const QString& name); + + protected slots: + void processRss(Syndication::Loader* loader, + Syndication::FeedPtr feed, + Syndication::ErrorCode error); + void slotIconChanged(bool isHost, const QString& hostOrURL, + const QString& iconName); + void timeout(const QString & source); + void networkStatusChanged(Solid::Networking::Status status); + + private: + QVariantList mergeFeeds(QString source) const; + void updateFeeds(const QString & source, + const QString & title); + bool cachesUpToDate(const QString & source) const; + QString iconLocation(const KUrl & url) const; + + QHash m_feedMap; + QHash m_sourceMap; + QHash m_timerMap; + QHash m_feedItems; + QHash m_feedIcons; + QHash m_feedTitles; + QHash m_feedTimes; + bool m_forceUpdate; + + QVariantList m_rssSources; + QSet m_rssSourceNames; + + QDBusInterface * m_favIconsModule; + QSignalMapper * m_signalMapper; +}; + +K_EXPORT_PLASMA_DATAENGINE(rss, RssEngine) + +#endif + diff --git a/plasma/generic/dataengines/share/CMakeLists.txt b/plasma/generic/dataengines/share/CMakeLists.txt new file mode 100644 index 00000000..e2e58a6b --- /dev/null +++ b/plasma/generic/dataengines/share/CMakeLists.txt @@ -0,0 +1,43 @@ +project(shareengine) + +set(share_engine_SRCS + shareprovider.cpp + shareengine.cpp + shareservice.cpp + share_package.cpp) + +kde4_add_plugin(plasma_engine_share ${share_engine_SRCS}) +target_link_libraries(plasma_engine_share + ${KDE4_KDECORE_LIBS} + ${KDE4_PLASMA_LIBS} + ${KDE4_KIO_LIBS} + ${KDE4_KROSSCORE_LIBS}) + +install(TARGETS plasma_engine_share + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES data/plasma-dataengine-share.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) + +install(FILES data/plasma_shareprovider.desktop + DESTINATION ${SERVICETYPES_INSTALL_DIR}) + +install(FILES share.operations + DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + +set(sharepackage_SRCS + share_package.cpp + plugin_share_package.cpp +) + +add_subdirectory(backends) + +kde4_add_plugin(plasma_packagestructure_share + ${sharepackage_SRCS}) +target_link_libraries(plasma_packagestructure_share + ${KDE4_PLASMA_LIBS}) + +install(TARGETS plasma_packagestructure_share + DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES data/plasma-packagestructure-share.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/dataengines/share/Messages.sh b/plasma/generic/dataengines/share/Messages.sh new file mode 100755 index 00000000..96beed36 --- /dev/null +++ b/plasma/generic/dataengines/share/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_share.pot diff --git a/plasma/generic/dataengines/share/backends/CMakeLists.txt b/plasma/generic/dataengines/share/backends/CMakeLists.txt new file mode 100644 index 00000000..9f1f7d08 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/CMakeLists.txt @@ -0,0 +1,11 @@ +add_subdirectory(kde) +add_subdirectory(imgur) +add_subdirectory(pastebincom) +add_subdirectory(pasteubuntucom) +add_subdirectory(simplestimagehosting) +add_subdirectory(wklej) +add_subdirectory(wstaw) +add_subdirectory(pasteopensuseorg) +add_subdirectory(imgsusepasteorg) +add_subdirectory(privatepaste) +add_subdirectory(im9) diff --git a/plasma/generic/dataengines/share/backends/im9/CMakeLists.txt b/plasma/generic/dataengines/share/backends/im9/CMakeLists.txt new file mode 100644 index 00000000..a4f4c574 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/im9/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-im9.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-im9.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/im9/) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/im9) diff --git a/plasma/generic/dataengines/share/backends/im9/contents/code/main.js b/plasma/generic/dataengines/share/backends/im9/contents/code/main.js new file mode 100644 index 00000000..4ba04d47 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/im9/contents/code/main.js @@ -0,0 +1,47 @@ +/********************************************************************************** +* im9.eu backend for Plasma. +* Copyright (C) 2012 Michal Dutkiewicz +* +* 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. +* +**********************************************************************************/ + +function url() +{ + return 'http://api.im9.eu/kde-pastebin/'; +} + +function contentKey() +{ + return 'image'; +} + +function setup() +{ +} + +function handleResultData(data) +{ + var result = data.match('800\n(http://.+)\n'); + + if (result == '') + { + provider.error(data); + + return; + } + + provider.success(data.replace('800', '').replace('\n', '')); +} diff --git a/plasma/generic/dataengines/share/backends/im9/metadata.desktop b/plasma/generic/dataengines/share/backends/im9/metadata.desktop new file mode 100644 index 00000000..c69fae7b --- /dev/null +++ b/plasma/generic/dataengines/share/backends/im9/metadata.desktop @@ -0,0 +1,97 @@ +[Desktop Entry] +Name=im9.eu +Name[bs]=im9.eu +Name[ca]=im9.eu +Name[ca@valencia]=im9.eu +Name[cs]=im9.eu +Name[da]=im9.eu +Name[de]=im9.eu +Name[el]=im9.eu +Name[en_GB]=im9.eu +Name[es]=im9.eu +Name[et]=im9.eu +Name[eu]=im9.eu +Name[fi]=im9.eu +Name[fr]=im9.eu +Name[gl]=im9.eu +Name[hu]=im9.eu +Name[ia]=im9.eu +Name[it]=im9.eu +Name[kk]=im9.eu +Name[ko]=im9.eu +Name[lt]=im9.eu +Name[nb]=im9.eu +Name[nds]=im9.eu +Name[nl]=im9.eu +Name[pa]=im9.eu +Name[pl]=im9.eu +Name[pt]=im9.eu +Name[pt_BR]=im9.eu +Name[ro]=im9.eu +Name[ru]=im9.eu +Name[sk]=im9.eu +Name[sl]=im9.eu +Name[sr]=им9 +Name[sr@ijekavian]=им9 +Name[sr@ijekavianlatin]=im9 +Name[sr@latin]=im9 +Name[sv]=im9.eu +Name[tr]=im9.eu +Name[uk]=im9.eu +Name[x-test]=xxim9.euxx +Name[zh_CN]=im9.eu +Name[zh_TW]=im9.eu +Comment=Allows images to be shared using the im9.eu service +Comment[bs]=Dopušta dijeljenje slika preko servisa im9.eu +Comment[ca]=Permet la compartició d'imatges utilitzant el servei im9.eu +Comment[ca@valencia]=Permet la compartició d'imatges utilitzant el servei im9.eu +Comment[cs]=Povolí sdílení obrázků pomocí služby im9.eu +Comment[da]=Muliggør deling af billeder med tjenesten im9.eu +Comment[de]=Ermöglicht die Veröffentlichung von Bildern über den im9.eu-Dienst +Comment[el]=Επιτρέπει το μοίρασμα των εικόνων με την υπηρεσία im9.eu +Comment[en_GB]=Allows images to be shared using the im9.eu service +Comment[es]=Permite compartir imágenes a través del servicio im9.eu +Comment[et]=Piltide jagamine im9.eu teenuse kaudu +Comment[eu]=Irudiak im9.eu zerbitzuaren bidez partekatzeko aukera ematen du +Comment[fi]=Mahdollistaa kuvien jakamisen im9.eu-palvelussa +Comment[fr]=Permet le partage d'images à l'aide du service « im9.eu » +Comment[gl]=Permite compartir imaxes mediante o servizo im9.eu +Comment[hu]=Képek megosztása az im9.eu szolgáltatás használatával +Comment[ia]=Il permitte imagines de esser compartite per usage de servicio im9.eu +Comment[it]=Abilita la condivisione di immagini con il servizio img9.eu +Comment[kk]=im9.eu қызметі көмегімен кескіндерді ортақ қылуды рұқсат ету +Comment[ko]=im9.eu로 그림을 공유합니다 +Comment[lt]=Įjungia dalinimąsi nuotraukomis naudojant im9.eu tarnybą +Comment[nb]=Gjør det mulig å dele bilder via tjenesten im9.eu +Comment[nds]=Lett Di Biller över den Deenst "im9.eu" praatstellen +Comment[nl]=Staat het delen van afbeeldingen toe met gebruik van de service im9.eu +Comment[pa]=im9.eu ਸਰਵਿਸ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਚਿੱਤਰ ਸਾਂਝੇ ਕਰਨ ਲਈ ਸਹਾਇਕ +Comment[pl]=Pozwala na udostępnianie obrazów przy użyciu usługi im9.eu +Comment[pt]=Permite a partilha de imagens com o serviço do 'im9.eu' +Comment[pt_BR]=Permite o compartilhamento de imagens usando o serviço do im9.eu +Comment[ro]=Permite partajarea imaginilor cu serviciul im9.eu +Comment[ru]=Позволяет публиковать изображения на сервере im9.eu +Comment[sk]=Povolí zdieľanie obrázkov pomocou služby im9.eu +Comment[sl]=Omogoča deljenje slik prek storitve im9.eu +Comment[sr]=Дељење слика преко сервиса им9 +Comment[sr@ijekavian]=Дијељење слика преко сервиса им9 +Comment[sr@ijekavianlatin]=Dijeljenje slika preko servisa im9 +Comment[sr@latin]=Deljenje slika preko servisa im9 +Comment[sv]=Tillåter att bilder delas genom att använda tjänsten im9.eu +Comment[tr]=im9.eu hizmetini kullanarak resimleri paylaşmayı sağlar +Comment[uk]=Уможливлює оприлюднення зображень за допомогою служби im9.eu +Comment[x-test]=xxAllows images to be shared using the im9.eu servicexx +Comment[zh_CN]=用 im9.eu 服务共享图片 +Comment[zh_TW]=允許使用 im9.eu 服務分享影像 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=image/* + +X-KDE-PluginInfo-Name=im9 +X-KDE-PluginInfo-Author=Michał Dutkiewicz +X-KDE-PluginInfo-Email=emdeck@gmail.com +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/generic/dataengines/share/backends/imgsusepasteorg/CMakeLists.txt b/plasma/generic/dataengines/share/backends/imgsusepasteorg/CMakeLists.txt new file mode 100644 index 00000000..a4cfe41b --- /dev/null +++ b/plasma/generic/dataengines/share/backends/imgsusepasteorg/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-imgsusepasteorg.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-imgsusepasteorg.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/imgsusepasteorg) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/imgsusepasteorg) diff --git a/plasma/generic/dataengines/share/backends/imgsusepasteorg/contents/code/main.js b/plasma/generic/dataengines/share/backends/imgsusepasteorg/contents/code/main.js new file mode 100644 index 00000000..35b4201b --- /dev/null +++ b/plasma/generic/dataengines/share/backends/imgsusepasteorg/contents/code/main.js @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2010 by Will Stephenson * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://susepaste.org"; +} + +function contentKey() { + return "file"; +} + +function setup() { + provider.addPostItem("name", "KDE", "text/plain"); + provider.addPostItem("title", "mypaste", "text/plain"); + provider.addPostItem("lang", "image", "text/plain"); + provider.addPostItem("submit", "submit", "text/plain"); + provider.addPostItem("expire","1440","text/plain"); +} + +function handleResultData(data) { + console.log("--> data: " + data); + var res = data.match("(Info.+)"); + if (res != "") { + return; + } + provider.error(data); +} + +function handleRedirection(url) { + provider.success(url); +} diff --git a/plasma/generic/dataengines/share/backends/imgsusepasteorg/metadata.desktop b/plasma/generic/dataengines/share/backends/imgsusepasteorg/metadata.desktop new file mode 100644 index 00000000..7aade0be --- /dev/null +++ b/plasma/generic/dataengines/share/backends/imgsusepasteorg/metadata.desktop @@ -0,0 +1,119 @@ +[Desktop Entry] +Name=img.susepaste.org +Name[ar]=img.susepaste.org +Name[bg]=img.susepaste.org +Name[bs]=img.susepaste.org +Name[ca]=img.susepaste.org +Name[ca@valencia]=img.susepaste.org +Name[cs]=img.susepaste.org +Name[da]=img.susepaste.org +Name[de]=img.susepaste.org +Name[el]=img.susepaste.org +Name[en_GB]=img.susepaste.org +Name[es]=img.susepaste.org +Name[et]=img.susepaste.org +Name[eu]=img.susepaste.org +Name[fi]=img.susepaste.org +Name[fr]=img.susepaste.org +Name[gl]=img.susepaste.org +Name[he]=img.susepaste.org +Name[hr]=img.susepaste.org +Name[hu]=img.susepaste.org +Name[ia]=img.susepaste.org +Name[is]=img.susepaste.org +Name[it]=img.susepaste.org +Name[kk]=img.susepaste.org +Name[km]=img.susepaste.org +Name[ko]=img.susepaste.org +Name[lt]=img.susepaste.org +Name[lv]=img.susepaste.org +Name[mr]=img.susepaste.org +Name[nb]=img.susepaste.org +Name[nds]=img.susepaste.org +Name[nl]=img.susepaste.org +Name[pa]=img.susepaste.org +Name[pl]=img.susepaste.org +Name[pt]=img.susepaste.org +Name[pt_BR]=img.susepaste.org +Name[ro]=img.susepaste.org +Name[ru]=img.susepaste.org +Name[sk]=img.susepaste.org +Name[sl]=img.susepaste.org +Name[sr]=img.susepaste.org +Name[sr@ijekavian]=img.susepaste.org +Name[sr@ijekavianlatin]=img.susepaste.org +Name[sr@latin]=img.susepaste.org +Name[sv]=img.susepaste.org +Name[tr]=img.susepaste.org +Name[ug]=img.susepaste.org +Name[uk]=img.susepaste.org +Name[wa]=img.susepaste.org +Name[x-test]=xximg.susepaste.orgxx +Name[zh_CN]=img.susepaste.org +Name[zh_TW]=img.susepaste.org +Comment=Allows images to be shared using the susepaste.org service +Comment[ar]=يسمح للصور أن تُشارك بإستخدام خدمة susepaste.org +Comment[bg]=Позволява споделянето на картинки чрез susepaste.org +Comment[bs]=Dopušta dijeljenje slika preko servisa susepaste.org +Comment[ca]=Permet la compartició d'imatges utilitzant el servei susepaste.org +Comment[ca@valencia]=Permet la compartició d'imatges utilitzant el servei susepaste.org +Comment[cs]=Povolí sdílení obrázků pomocí služby susepaste.org +Comment[da]=Muliggør deling af billeder med tjenesten susepaste.org +Comment[de]=Ermöglicht die Veröffentlichung von Bildern über den susepaste.org-Dienst +Comment[el]=Επιτρέπει το μοίρασμα των εικόνων χρησιμοποιώντας την υπηρεσία susepaste.org +Comment[en_GB]=Allows images to be shared using the susepaste.org service +Comment[es]=Permite compartir imágenes a través del servicio de susepaste.org +Comment[et]=Piltide jagamine susepaste.org teenuse kaudu +Comment[eu]=Irudiak susepaste.org zerbitzuaren bidez partekatzeko aukera ematen du +Comment[fi]=Mahdollistaa kuvien jakamisen susepaste.org-palvelussa +Comment[fr]=Permet le partage d'images à l'aide du service « susepaste.org » +Comment[gl]=Permite compartir imaxes mediante o servizo susepaste.org +Comment[he]=מאפשר שיתוף תמונות באמצעות השירות susepaste.org +Comment[hr]=Omogućuje dijeljenje slika koristeći servis susepaste.org +Comment[hu]=Képek megosztása a susepaste.org szolgáltatás használatával +Comment[ia]=Il permitte images de esser compartite per usar le servicio susepaste.org +Comment[is]=Gerir kleift að deila myndum með susepaste.org þjónustunni +Comment[it]=Abilita la condivisione di immagini con il servizio susepaste.org +Comment[kk]=susepaste.org қызметі көмегімен кескіндерді ортақ қылуды рұқсат ету +Comment[km]=បើក​ការ​ចែករំលែក​រូបភាព​ ដោយ​ប្រើ​សេវា susepaste.org +Comment[ko]=susepaste.org로 그림을 공유합니다 +Comment[lt]=Įjungia dalinimąsį nuotraukomis naudojant susepaste.org tarnybą +Comment[lv]=Ļauj kopīgot attēlus, izmantojot susepaste.org servisu +Comment[mr]=susepaste.org सेवा वापरुन प्रतिमा शेअर करतो +Comment[nb]=Gjør det mulig å dele bilder via tjenesten susepaste.org +Comment[nds]=Biller op "img.susepaste.org" praatstellen +Comment[nl]=Staat het delen van afbeeldingen toe met gebruik van de service susepaste.org +Comment[pa]=susepaste.org ਸਰਵਿਸ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਚਿੱਤਰ ਸਾਂਝੇ ਕਰਨ ਲਈ ਸਹਾਇਕ +Comment[pl]=Pozwala na udostępnianie obrazów przy użyciu usługi susepaste.org +Comment[pt]=Permite a partilha de imagens com o serviço do 'susepaste.org' +Comment[pt_BR]=Permite o compartilhamento de imagens usando o serviço do susepaste.org +Comment[ro]=Permite partajarea imaginilor cu serviciul susepaste.org +Comment[ru]=Позволяет публиковать изображения на сервере susepaste.org +Comment[sk]=Povolí zdieľanie obrázkov pomocou služby susepaste.org +Comment[sl]=Omogoča deljenje slik prek storitve susepaste.org +Comment[sr]=Дељење слика преко сервиса susepaste.org +Comment[sr@ijekavian]=Дијељење слика преко сервиса susepaste.org +Comment[sr@ijekavianlatin]=Dijeljenje slika preko servisa susepaste.org +Comment[sr@latin]=Deljenje slika preko servisa susepaste.org +Comment[sv]=Tillåter att bilder delas genom att använda tjänsten susepaste.org +Comment[tr]=susepaste.org hizmeti kullanarak resim paylaşımı sağlar +Comment[ug]=رەسىملەرنى susepaste.org مۇلازىمىتىنى ئىشلىتىپ ھەمبەھىرلەشكە ئىجازەت +Comment[uk]=Уможливлює оприлюднення зображень за допомогою служби susepaste.org +Comment[vi]=Cho phép chia sẻ ảnh qua dịch vụ susepaste.org +Comment[wa]=Permete li pårtaedje d' imådjes e s' siervant do siervice susepaste.org +Comment[x-test]=xxAllows images to be shared using the susepaste.org servicexx +Comment[zh_CN]=用 susepaste.org 服务共享图片 +Comment[zh_TW]=允許使用 susepaste.org 服務分享影像 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=image/* + +X-KDE-PluginInfo-Name=imgsusepasteorg +X-KDE-PluginInfo-Author=Javier Llorente +X-KDE-PluginInfo-Email=javier@opensuse.org +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-Priority=1 + diff --git a/plasma/generic/dataengines/share/backends/imgur/CMakeLists.txt b/plasma/generic/dataengines/share/backends/imgur/CMakeLists.txt new file mode 100644 index 00000000..e71a1b43 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/imgur/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-imgur.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-imgur.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/imgur/) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/imgur) diff --git a/plasma/generic/dataengines/share/backends/imgur/contents/code/main.js b/plasma/generic/dataengines/share/backends/imgur/contents/code/main.js new file mode 100644 index 00000000..ab86abf5 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/imgur/contents/code/main.js @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2010 by Artur Duque de Souza * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://imgur.com/api/upload"; +} + +function contentKey() { + return "image"; +} + +function setup() { + // key associated with plasma-devel@kde.org + // thanks to Alan Schaaf of Imgur (alan@imgur.com) + provider.addPostItem("key", "d0757bc2e94a0d4652f28079a0be9379", "text/plain"); +} + +function handleResultData(data) { + var res = provider.parseXML("original_image", data); + if (res == "") { + provider.error(data); + return; + } + provider.success(res); +} diff --git a/plasma/generic/dataengines/share/backends/imgur/metadata.desktop b/plasma/generic/dataengines/share/backends/imgur/metadata.desktop new file mode 100644 index 00000000..5dcc2e67 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/imgur/metadata.desktop @@ -0,0 +1,125 @@ +[Desktop Entry] +Name=Imgur +Name[ast]=Imgur +Name[bg]=Imgur +Name[bs]=Imgur +Name[ca]=Imgur +Name[ca@valencia]=Imgur +Name[cs]=Imgur +Name[da]=Imgur +Name[de]=Imgur +Name[el]=Imgur +Name[en_GB]=Imgur +Name[es]=Imgur +Name[et]=Imgur +Name[eu]=Imgur +Name[fi]=Imgur +Name[fr]=Imgur +Name[ga]=Imgur +Name[gl]=Imgur +Name[he]=Imgur +Name[hi]=इंगुर +Name[hr]=Imgur +Name[hu]=Imgur +Name[ia]=Imgur +Name[is]=Imgur +Name[it]=Imgur +Name[ja]=Imgur +Name[kk]=Imgur +Name[km]=Imgur +Name[kn]=Imgur +Name[ko]=Imgur +Name[lt]=Imgur +Name[lv]=Imgur +Name[mr]=Imgur +Name[nb]=Imgur +Name[nds]=imgur +Name[nl]=Imgur +Name[pa]=Imgur +Name[pl]=Imgur +Name[pt]=Imgur +Name[pt_BR]=Imgur +Name[ro]=Imgur +Name[ru]=Imgur +Name[sk]=Imgur +Name[sl]=Imgur +Name[sr]=Имгур +Name[sr@ijekavian]=Имгур +Name[sr@ijekavianlatin]=Imgur +Name[sr@latin]=Imgur +Name[sv]=Imgur +Name[th]=Imgur +Name[tr]=Imgur +Name[ug]=Imgur +Name[uk]=Imgur +Name[vi]=Imgur +Name[wa]=Imgur +Name[x-test]=xxImgurxx +Name[zh_CN]=Imgur +Name[zh_TW]=Imgur +Comment=Allows images to be shared using the imgur service +Comment[ar]=يسمح للصور أن تُشارك بإستخدام خدمة imgur +Comment[bg]=Позволява споделянето на картинки чрез imgur +Comment[bs]=Dopušta dijeljenje slika preko servisa Imgur +Comment[ca]=Permet la compartició d'imatges utilitzant el servei imgur +Comment[ca@valencia]=Permet la compartició d'imatges utilitzant el servei imgur +Comment[cs]=Povolí sdílení obrázků pomocí služby imgur +Comment[da]=Muliggør deling af billeder med tjenesten imgur +Comment[de]=Ermöglicht die Veröffentlichung von Bildern über den Imgur-Dienst +Comment[el]=Επιτρέπει το μοίρασμα των εικόνων χρησιμοποιώντας την υπηρεσία imgur +Comment[en_GB]=Allows images to be shared using the imgur service +Comment[es]=Permite compartir imágenes a través del servicio de imgur +Comment[et]=Piltide jagamine imguri teenuse kaudu +Comment[eu]=Irudiak imgur zerbitzuaren bidez partekatzeko aukera ematen du +Comment[fi]=Mahdollistaa kuvien jakamisen imgur-palvelussa +Comment[fr]=Permet le partage d'images à l'aide du service « imgur » +Comment[gl]=Permite compartir imaxes mediante o servizo imgur +Comment[he]=מאפשר שיתוף תמונות באמצעות השירות imgur +Comment[hr]=Omogućuje dijeljenje slika koristeći servis imgur +Comment[hu]=Képek megosztása az imgur szolgáltatás használatával +Comment[ia]=Il permitte imagines de esser compartite per usage de servicio imgur +Comment[is]=Gerir kleift að deila myndum með imgur þjónustunni +Comment[it]=Abilita la condivisione di immagini con il servizio imgur +Comment[ja]=imgur のサービスを用いた画像の共有を有効にする +Comment[kk]=Imgur қызметі көмегімен кескіндерді ортақ қылуды рұқсат ету +Comment[km]=បើក​ការ​ចែករំលែក​រូបភាព ដោយ​ប្រើ​សេវា imgur​​ +Comment[ko]=imgur로 그림을 공유합니다 +Comment[lt]=Įjungia dalinimąsį nuotraukomis naudojant imgur tarnybą +Comment[lv]=Ļauj kopīgot attēlus, izmantojot imgur servisu +Comment[mr]=imgur सेवा वापरुन प्रतिमा शेअर करतो +Comment[nb]=Gjør det mulig å dele bilder via tjenesten imgur +Comment[nds]=Biller op "imgur" praatstellen +Comment[nl]=Staat het delen van afbeeldingen toe met gebruik van de service imgur +Comment[pa]=imgur ਸਰਵਿਸ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਚਿੱਤਰ ਸਾਂਝੇ ਕਰਨ ਲਈ ਸਹਾਇਕ +Comment[pl]=Pozwala na udostępnianie obrazów przy użyciu usługi imgur +Comment[pt]=Permite a partilha de imagens com o serviço do 'imgur' +Comment[pt_BR]=Permite o compartilhamento de imagens usando o serviço do imgur +Comment[ro]=Permite partajarea imaginilor cu serviciul imgur +Comment[ru]=Позволяет публиковать изображения на сервере imgur.com +Comment[sk]=Povolí zdieľanie obrázkov pomocou služby imgur +Comment[sl]=Omogoča deljenje slik prek storitve imgur +Comment[sr]=Дељење слика преко сервиса Имгур +Comment[sr@ijekavian]=Дијељење слика преко сервиса Имгур +Comment[sr@ijekavianlatin]=Dijeljenje slika preko servisa Imgur +Comment[sr@latin]=Deljenje slika preko servisa Imgur +Comment[sv]=Tillåter att bilder delas genom att använda tjänsten imgur +Comment[tr]=imgur servisini kullanarak resimleri paylaşmayı sağlar +Comment[ug]=رەسىملەرنى imgur مۇلازىمىتىنى ئىشلىتىپ ھەمبەھىرلەشكە ئىجازەت +Comment[uk]=Уможливлює оприлюднення зображень за допомогою служби imgur +Comment[vi]=Cho phép chia sẻ ảnh qua dịch vụ imgur +Comment[wa]=Permete li pårtaedje d' imådjes e s' siervant do siervice imgur +Comment[x-test]=xxAllows images to be shared using the imgur servicexx +Comment[zh_CN]=用 imgur 服务共享图片 +Comment[zh_TW]=允許使用 imgur 服務分享影像 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=image/* + +X-KDE-PluginInfo-Name=imgur +X-KDE-PluginInfo-Author=Artur de Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/generic/dataengines/share/backends/kde/CMakeLists.txt b/plasma/generic/dataengines/share/backends/kde/CMakeLists.txt new file mode 100644 index 00000000..8f323451 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/kde/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-kde.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-kde.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/kde/) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/kde) diff --git a/plasma/generic/dataengines/share/backends/kde/contents/code/main.js b/plasma/generic/dataengines/share/backends/kde/contents/code/main.js new file mode 100644 index 00000000..5746a4e0 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/kde/contents/code/main.js @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2010 by Artur Duque de Souza * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://paste.kde.org/api/xml/create"; +} + +function method() { + return "POST"; +} + +function contentKey() { + return "data"; +} + +function setup() { + provider.addQueryItem("language", "text"); +} + +function handleResultData(data) { + var res = provider.parseXML("id", data); + if (res == "") { + provider.error(data); + return; + } + provider.success("http://paste.kde.org/" + res); +} + diff --git a/plasma/generic/dataengines/share/backends/kde/metadata.desktop b/plasma/generic/dataengines/share/backends/kde/metadata.desktop new file mode 100644 index 00000000..32ab8792 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/kde/metadata.desktop @@ -0,0 +1,111 @@ +[Desktop Entry] +Name=paste.kde.org +Name[bs]=paste.kde.org +Name[ca]=paste.kde.org +Name[ca@valencia]=paste.kde.org +Name[cs]=paste.kde.org +Name[da]=paste.kde.org +Name[de]=paste.kde.org +Name[el]=paste.kde.org +Name[en_GB]=paste.kde.org +Name[es]=paste.kde.org +Name[et]=paste.kde.org +Name[eu]=paste.kde.org +Name[fi]=paste.kde.org +Name[fr]=paste.kde.org +Name[gl]=paste.kde.org +Name[hu]=paste.kde.org +Name[ia]=paste.kde.org +Name[it]=paste.kde.org +Name[kk]=paste.kde.org +Name[ko]=paste.kde.org +Name[lt]=paste.kde.org +Name[mr]=paste.kde.org +Name[nb]=paste.kde.org +Name[nds]=paste.kde.org +Name[nl]=paste.kde.org +Name[pa]=paste.kde.org +Name[pl]=paste.kde.org +Name[pt]=paste.kde.org +Name[pt_BR]=paste.kde.org +Name[ro]=paste.kde.org +Name[ru]=paste.kde.org +Name[sk]=paste.kde.org +Name[sl]=paste.kde.org +Name[sr]=paste.kde.org +Name[sr@ijekavian]=paste.kde.org +Name[sr@ijekavianlatin]=paste.kde.org +Name[sr@latin]=paste.kde.org +Name[sv]=paste.kde.org +Name[tr]=paste.kde.org +Name[uk]=paste.kde.org +Name[x-test]=xxpaste.kde.orgxx +Name[zh_CN]=paste.kde.org +Name[zh_TW]=paste.kde.org +Comment=Allows text to be shared using the kde.org service +Comment[ar]=يسمح للنصوص أن تُشارك بإستخدام خدمة kde.org +Comment[bg]=Позволява споделянето на текст чрез kde.org +Comment[bs]=Dopušta ijeljenje teksta preko servisa wklej.org +Comment[ca]=Permet la compartició de text utilitzant el servei kde.org +Comment[ca@valencia]=Permet la compartició de text utilitzant el servei kde.org +Comment[cs]=Povolí sdílení textů pomocí služby kde.org +Comment[da]=Muliggør deling af tekst med tjenesten kde.org +Comment[de]=Ermöglicht die Veröffentlichung von Text über den kde.org-Dienst +Comment[el]=Επιτρέπει στο κείμενο να γίνει κοινόχρηστο χρησιμοποιώντας την υπηρεσία kde.org +Comment[en_GB]=Allows text to be shared using the kde.org service +Comment[es]=Permite compartir texto a través del servicio de kde.org +Comment[et]=Teksti jagamine kde.org teenuse kaudu +Comment[eu]=Testua kde.org zerbitzuaren bidez partekatzeko aukera ematen du +Comment[fi]=Mahdollistaa tekstin jakamisen kde.org-palvelussa +Comment[fr]=Permet le partage de texte à l'aide du service « kde.org » +Comment[gl]=Permite compartir texto mediante o servizo kde.org +Comment[he]=מאפשר שיתוף טקסט באמצעות השירות kde.org +Comment[hr]=Omogućuje dijeljenje teksta koristeći servis kde.org +Comment[hu]=Szöveg megosztása a kde.org szolgáltatás használatával +Comment[ia]=Il permitte texto de esser compartite per usar le servicio kde.org +Comment[is]=Gerir kleift að deila texta með kde.org límklippusafninu +Comment[it]=Abilita la condivisione di immagini con il servizio kde.org +Comment[ja]=kde.org のサービスを用いたテキストの共有を有効にする +Comment[kk]=kde.org қызметі көмегімен мәтінді ортақ қылуды рұқсат ету +Comment[km]=បើក​ការ​ចែករំលែក​អត្ថបទ​ដោយ​ប្រើ​សេវា kde.org +Comment[ko]=kde.org로 텍스트를 공유합니다 +Comment[lt]=Įjungia dalinimąsį tekstu naudojant kde.org tarnybą +Comment[lv]=Ļauj kopīgot tekstu, izmantojot kde.org servisu +Comment[mr]=kde.org सेवा वापरुन पाठ्य शेअर करतो +Comment[nb]=Gjør det mulig å dele tekst via tjenesten kde.org +Comment[nds]=Text op "kde.org" praatstellen +Comment[nl]=Staat het delen van tekst toe met gebruik van de service kde.org +Comment[pa]=kde.org ਸਰਵਿਸ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਟੈਕਸਟ ਸਾਂਝਾ ਕਰਨਾ ਯੋਗ +Comment[pl]=Pozwala na udostępnianie tekstu przy użyciu usługi kde.org +Comment[pt]=Permite a partilha de texto com o serviço do 'kde.org' +Comment[pt_BR]=Permite o compartilhamento de texto usando o serviço do kde.org +Comment[ro]=Permite partajarea textului cu serviciul kde.org +Comment[ru]=Позволяет публиковать текст на сервере kde.org +Comment[sk]=Povolí zdieľanie textu pomocou služby kde.org +Comment[sl]=Omogoča deljenje besedila prek storitve kde.org +Comment[sr]=Дељење текста преко сервиса kde.org +Comment[sr@ijekavian]=Дијељење текста преко сервиса kde.org +Comment[sr@ijekavianlatin]=Dijeljenje teksta preko servisa kde.org +Comment[sr@latin]=Deljenje teksta preko servisa kde.org +Comment[sv]=Tillåter att text delas genom att använda tjänsten kde.org +Comment[tr]=kde.org servisini kullanarak metinleri paylaşmayı sağlar +Comment[ug]=تېكىستلەرنى kde.org مۇلازىمىتىنى ئىشلىتىپ ھەمبەھىرلەشكە ئىجازەت +Comment[uk]=Уможливлює оприлюднення фрагментів тексту за допомогою служби kde.org +Comment[vi]=Cho phép chia sẻ văn bản qua dịch vụ kde.org +Comment[wa]=Permete li pårtaedje di scrijhaedje e s' siervant do siervice kde.org +Comment[x-test]=xxAllows text to be shared using the kde.org servicexx +Comment[zh_CN]=用 kde.org 服务共享文字 +Comment[zh_TW]=允許使用 kde.org 服務分享文字 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=text/* + +X-KDE-PluginInfo-Name=kde +X-KDE-PluginInfo-Author=Artur de Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-Priority=100 + diff --git a/plasma/generic/dataengines/share/backends/pastebincom/CMakeLists.txt b/plasma/generic/dataengines/share/backends/pastebincom/CMakeLists.txt new file mode 100644 index 00000000..308f8030 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pastebincom/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-pastebincom.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-pastebincom.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/pastebincom/) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/pastebincom) diff --git a/plasma/generic/dataengines/share/backends/pastebincom/contents/code/main.js b/plasma/generic/dataengines/share/backends/pastebincom/contents/code/main.js new file mode 100644 index 00000000..ef4b70d4 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pastebincom/contents/code/main.js @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2010 by Artur Duque de Souza * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://pastebin.com/api_public.php"; +} + +function contentKey() { + return "paste_code"; +} + +function setup() { + provider.addQueryItem("paste_name", "Test"); +} + +function handleResultData(data) { + if (data.search("ERROR") != -1) { + provider.error(data); + return; + } + provider.success(data); +} + diff --git a/plasma/generic/dataengines/share/backends/pastebincom/metadata.desktop b/plasma/generic/dataengines/share/backends/pastebincom/metadata.desktop new file mode 100644 index 00000000..529fbc82 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pastebincom/metadata.desktop @@ -0,0 +1,126 @@ +[Desktop Entry] +Name=pastebin.com +Name[ar]=pastebin.com +Name[ast]=pastebin.com +Name[bg]=pastebin.com +Name[bs]=pastebin.com +Name[ca]=pastebin.com +Name[ca@valencia]=pastebin.com +Name[cs]=pastebin.com +Name[da]=pastebin.com +Name[de]=pastebin.com +Name[el]=pastebin.com +Name[en_GB]=pastebin.com +Name[es]=pastebin.com +Name[et]=pastebin.com +Name[eu]=pastebin.com +Name[fi]=pastebin.com +Name[fr]=pastebin.com +Name[ga]=pastebin.com +Name[gl]=pastebin.com +Name[gu]=pastebin.com +Name[he]=pastebin.com +Name[hi]=pastebin.com +Name[hr]=pastebin.com +Name[hu]=pastebin.com +Name[ia]=pastebin.com +Name[is]=pastebin.com +Name[it]=pastebin.com +Name[ja]=pastebin.com +Name[kk]=pastebin.com +Name[km]=pastebin.com +Name[ko]=pastebin.com +Name[lt]=pastebin.com +Name[lv]=pastebin.com +Name[mr]=pastebin.com +Name[nb]=pastebin.com +Name[nds]=pastebin.com +Name[nl]=pastebin.com +Name[pa]=pastebin.com +Name[pl]=pastebin.com +Name[pt]=pastebin.com +Name[pt_BR]=pastebin.com +Name[ro]=pastebin.com +Name[ru]=pastebin.com +Name[sk]=pastebin.com +Name[sl]=pastebin.com +Name[sr]=pastebin.com +Name[sr@ijekavian]=pastebin.com +Name[sr@ijekavianlatin]=pastebin.com +Name[sr@latin]=pastebin.com +Name[sv]=pastebin.com +Name[tg]=pastebin.com +Name[th]=pastebin.com +Name[tr]=pastebin.com +Name[ug]=pastebin.com +Name[uk]=pastebin.com +Name[wa]=pastebin.com +Name[x-test]=xxpastebin.comxx +Name[zh_CN]=pastebin.com +Name[zh_TW]=pastebin.com +Comment=Allows text to be shared using the pastebin.com service +Comment[ar]=يسمح للنصوص أن تُشارك بإستخدام خدمة pastebin.com +Comment[bg]=Позволява споделянето на текст чрез pastebin.com +Comment[bs]=Omogućava dijeljenje teksta preko servisa pastebin.com +Comment[ca]=Permet la compartició de text utilitzant el servei pastebin.com +Comment[ca@valencia]=Permet la compartició de text utilitzant el servei pastebin.com +Comment[cs]=Povolí sdílení textů pomocí služby pastebin.com +Comment[da]=Muliggør deling af tekst med tjenesten pastebin.com +Comment[de]=Ermöglicht die Veröffentlichung von Text über den pastebin.com-Dienst +Comment[el]=Επιτρέπει στο κείμενο να γίνει κοινόχρηστο χρησιμοποιώντας την υπηρεσία pastebin.com +Comment[en_GB]=Allows text to be shared using the pastebin.com service +Comment[es]=Permite compartir texto a través del servicio de pastebin.com +Comment[et]=Teksti jagamine pastebin.com teenuse kaudu +Comment[eu]=Testua pastebin.com zerbitzuaren bidez partekatzeko aukera ematen du +Comment[fi]=Mahdollistaa tekstin jakamisen pastebin.com-palvelussa +Comment[fr]=Permet le partage de texte à l'aide du service « pastebin.com » +Comment[gl]=Permite compartir texto mediante o servizo pastebin.org +Comment[he]=מאפשר שיתוף טקסט באמצעות השירות pastebin.com +Comment[hr]=Omogućuje dijeljenje teksta koristeći servis pastebin.com +Comment[hu]=Szöveg megosztása a pastebin.com szolgáltatás használatával +Comment[ia]=Il permitte texto de esser compartite per usar le servicio pastebin.com +Comment[is]=Gerir kleift að deila texta með pastebin.com límklippusafninu +Comment[it]=Abilita la condivisione di testo con il servizio pastebin.com +Comment[ja]=pastebin.com のサービスを用いたテキストの共有を有効にする +Comment[kk]=pastebin.com қызметі көмегімен мәтінді ортақ қылуды рұқсат ету +Comment[km]=បើក​ការ​ចែករំលែក​អត្ថបទ ដោយ​ប្រើ​សេវា pastebin.com +Comment[ko]=pastebin.com으로 텍스트를 공유합니다 +Comment[lt]=Įjungia dalinimąsį tekstu naudojant pastebin.com tarnybą +Comment[lv]=Ļauj kopīgot tekstu, izmantojot pastebin.com servisu +Comment[mr]=pastebin.com सेवा वापरुन पाठ्य शेअर करतो +Comment[nb]=Gjør det mulig å dele tekst via tjenesten pastebin.com +Comment[nds]=Text op "pastebin.com" praatstellen +Comment[nl]=Staat het delen van tekst toe met gebruik van de service pastebin.com +Comment[pa]=pastebin.com ਸਰਵਿਸ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਟੈਕਸਟ ਸਾਂਝਾ ਕਰੋ +Comment[pl]=Pozwala na udostępnianie tekstu przy użyciu usługi pastebin.com +Comment[pt]=Permite a partilha de texto com o serviço do 'pastebin.com' +Comment[pt_BR]=Permite o compartilhamento de texto usando o serviço do pastebin.com +Comment[ro]=Permite partajarea textului cu serviciul pastebin.com +Comment[ru]=Позволяет публиковать текст на сервере pastebin.com +Comment[sk]=Povolí zdieľanie textu pomocou služby pastebin.com +Comment[sl]=Omogoča deljenje besedila prek storitve pastebin.com +Comment[sr]=Дељење текста преко сервиса pastebin.com +Comment[sr@ijekavian]=Дијељење текста преко сервиса pastebin.com +Comment[sr@ijekavianlatin]=Dijeljenje teksta preko servisa pastebin.com +Comment[sr@latin]=Deljenje teksta preko servisa pastebin.com +Comment[sv]=Tillåter att text delas genom att använda tjänsten pastebin.com +Comment[tr]=pastebin.com servisini kullanarak metinleri paylaşmayı sağlar +Comment[ug]=تېكىستلەرنى pastebin.com مۇلازىمىتىنى ئىشلىتىپ ھەمبەھىرلەشكە ئىجازەت +Comment[uk]=Уможливлює оприлюднення фрагментів тексту за допомогою служби pastebin.com +Comment[vi]=Cho phép chia sẻ văn bản qua dịch vụ pastebin.com +Comment[wa]=Permete li pårtaedje di scrijhaedje e s' siervant do siervice pastebin.com +Comment[x-test]=xxAllows text to be shared using the pastebin.com servicexx +Comment[zh_CN]=用 pastebin.com 服务共享文字 +Comment[zh_TW]=允許使用 pastebin.com 服務分享文字 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=text/* + +X-KDE-PluginInfo-Name=pastebincom +X-KDE-PluginInfo-Author=Artur de Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/generic/dataengines/share/backends/pasteopensuseorg/CMakeLists.txt b/plasma/generic/dataengines/share/backends/pasteopensuseorg/CMakeLists.txt new file mode 100644 index 00000000..f2e6a93e --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pasteopensuseorg/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-pasteopensuseorg.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-pasteopensuseorg.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/pasteopensuseorg) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/pasteopensuseorg) diff --git a/plasma/generic/dataengines/share/backends/pasteopensuseorg/contents/code/main.js b/plasma/generic/dataengines/share/backends/pasteopensuseorg/contents/code/main.js new file mode 100644 index 00000000..6beaacb9 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pasteopensuseorg/contents/code/main.js @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2010 by Will Stephenson * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://paste.opensuse.org"; +} + +function contentKey() { + return "code"; +} + +function setup() { + provider.addQueryItem("name", "KDE"); + provider.addQueryItem("title", "mypaste"); + provider.addQueryItem("lang", "text"); + provider.addQueryItem("expire", "1440"); + provider.addQueryItem("submit", "submit"); +} + +function handleResultData(data) { + var res = data.match("(Info.+)"); + if (res != "") { + return; + } + provider.error(data); +} + +function handleRedirection(url) { + provider.success(url); +} diff --git a/plasma/generic/dataengines/share/backends/pasteopensuseorg/metadata.desktop b/plasma/generic/dataengines/share/backends/pasteopensuseorg/metadata.desktop new file mode 100644 index 00000000..67375527 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pasteopensuseorg/metadata.desktop @@ -0,0 +1,127 @@ +[Desktop Entry] +Name=paste.opensuse.org +Name[ar]=paste.opensuse.org +Name[ast]=paste.opensuse.org +Name[bg]=paste.opensuse.org +Name[bs]=paste.opensuse.org +Name[ca]=paste.opensuse.org +Name[ca@valencia]=paste.opensuse.org +Name[cs]=paste.opensuse.org +Name[da]=paste.opensuse.org +Name[de]=paste.opensuse.org +Name[el]=paste.opensuse.org +Name[en_GB]=paste.opensuse.org +Name[es]=paste.opensuse.org +Name[et]=paste.opensuse.org +Name[eu]=paste.opensuse.org +Name[fi]=paste.opensuse.org +Name[fr]=paste.opensuse.org +Name[ga]=paste.opensuse.org +Name[gl]=paste.opensuse.org +Name[gu]=paste.opensuse.org +Name[he]=paste.opensuse.org +Name[hi]=paste.opensuse.org +Name[hr]=paste.opensuse.org +Name[hu]=paste.opensuse.org +Name[ia]=paste.opensuse.org +Name[is]=paste.opensuse.org +Name[it]=paste.opensuse.org +Name[ja]=paste.opensuse.org +Name[kk]=paste.opensuse.org +Name[km]=paste.opensuse.org +Name[ko]=paste.opensuse.org +Name[lt]=paste.opensuse.org +Name[lv]=paste.opensuse.org +Name[mr]=paste.opensuse.org +Name[nb]=paste.opensuse.org +Name[nds]=paste.opensuse.org +Name[nl]=paste.opensuse.org +Name[pa]=paste.opensuse.org +Name[pl]=paste.opensuse.org +Name[pt]=paste.opensuse.org +Name[pt_BR]=paste.opensuse.org +Name[ro]=paste.opensuse.org +Name[ru]=paste.opensuse.org +Name[sk]=paste.opensuse.org +Name[sl]=paste.opensuse.org +Name[sr]=paste.opensuse.org +Name[sr@ijekavian]=paste.opensuse.org +Name[sr@ijekavianlatin]=paste.opensuse.org +Name[sr@latin]=paste.opensuse.org +Name[sv]=paste.opensuse.org +Name[tg]=paste.opensuse.org +Name[th]=paste.opensuse.org +Name[tr]=paste.opensuse.org +Name[ug]=paste.opensuse.org +Name[uk]=paste.opensuse.org +Name[wa]=paste.opensuse.org +Name[x-test]=xxpaste.opensuse.orgxx +Name[zh_CN]=paste.opensuse.org +Name[zh_TW]=paste.opensuse.org +Comment=Paste text with openSUSE +Comment[ast]=Apegar testu con openSUSE +Comment[bg]=Поставяне на текст през openSUSE +Comment[bs]=Opensuseov servis za naljepljivanje teksta +Comment[ca]=Enganxa text amb openSUSE +Comment[ca@valencia]=Apega text amb openSUSE +Comment[cs]=Vložit text s využitím openSUSE +Comment[da]=Indsæt tekst med openSUSE +Comment[de]=Text auf paste.opensuse.org veröffentlichen +Comment[el]=Επικόλληση κειμένου με το openSUSE +Comment[en_GB]=Paste text with openSUSE +Comment[es]=Pegar texto con openSUSE +Comment[et]=Teksti asetamine openSUSE abil +Comment[eu]=Itsatsi testua OpenSUSE-rekin +Comment[fi]=Liitä tekstiä openSUSEn avulla +Comment[fr]=Colle du texte avec Open-SUSE +Comment[gl]=Apega texto con openSUSE +Comment[he]=שיתוף קטעי טקסט באמצעות openSUSE +Comment[hr]=Zalijepi tekst pomoću openSUSE-a +Comment[hu]=Szöveg beillesztése openSUSE-val +Comment[ia]=Colla texto con openSUSE +Comment[is]=Líma texta með openSUSE +Comment[it]=Incolla testo con openSUSE +Comment[ja]=openSUSE でテキストを貼りつける +Comment[kk]=openSUSE-ден мәтіді алып орналастыру +Comment[km]=បិទភ្ជាប់​​នៅ​ក្នុង​អូផឹនស៊ូស៊ី +Comment[ko]=openSUSE 텍스트 공유 서비스 +Comment[lt]=Padėti tekstą naudojant openSUSE +Comment[lv]=Ielīmēt tekstu ar openSUSE +Comment[mr]=openSUSE वापरुन पाठ्य चिटकवा +Comment[nb]=Lim inn tekst med openSUSE +Comment[nds]=Text op "openSUSE" praatstellen +Comment[nl]=Plak tekst met openSUSE +Comment[pa]=openSUSE ਨਾਲ ਟੈਕਸਟ ਚੇਪੋopenSUSE ਨਾਲ ਟੈਕਸਟ ਚਪੇ +Comment[pl]=Wklejanie tekstu z openSUSE +Comment[pt]=Colar texto com o openSUSE +Comment[pt_BR]=Colar texto com o openSUSE +Comment[ro]=Lipește text cu openSUSE +Comment[ru]=Позволяет публиковать текст на сервере openSUSE +Comment[sk]=Vloží text pomocou služby openSUSE +Comment[sl]=Prilepite besedilo z openSUSE +Comment[sr]=Опенсусеов сервис за налепљивање текста +Comment[sr@ijekavian]=Опенсусеов сервис за наљепљивање текста +Comment[sr@ijekavianlatin]=OpenSuSE‑ov servis za naljepljivanje teksta +Comment[sr@latin]=OpenSuSE‑ov servis za nalepljivanje teksta +Comment[sv]=Klistra in text med openSUSE +Comment[tg]=Часпондани матн бо openSUSE +Comment[th]=แปะข้อความไปยังบริการของ openSUSE +Comment[tr]=Metinleri openSUSE servini kullanarak paylaş +Comment[ug]=openSUSE تىن تېكىست چاپلا +Comment[uk]=Вставити фрагмент тексту з openSUSE +Comment[wa]=Aclaper do tecse avou openSUSE +Comment[x-test]=xxPaste text with openSUSExx +Comment[zh_CN]=用 openSUSE 粘贴文字 +Comment[zh_TW]=用 openSUSE 貼上文字 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=text/* + +X-KDE-PluginInfo-Name=pasteopensuseorg +X-KDE-PluginInfo-Author=Will Stephenson +X-KDE-PluginInfo-Email=wstephenson@suse.de +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/generic/dataengines/share/backends/pasteubuntucom/CMakeLists.txt b/plasma/generic/dataengines/share/backends/pasteubuntucom/CMakeLists.txt new file mode 100644 index 00000000..294f20d9 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pasteubuntucom/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-pasteubuntucom.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-pasteubuntucom.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/pasteubuntucom) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/pasteubuntucom) diff --git a/plasma/generic/dataengines/share/backends/pasteubuntucom/contents/code/main.js b/plasma/generic/dataengines/share/backends/pasteubuntucom/contents/code/main.js new file mode 100644 index 00000000..e0d768b9 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pasteubuntucom/contents/code/main.js @@ -0,0 +1,41 @@ +/* + Copyright © 2010 Harald Sitter + + 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) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +function url() { + return "http://paste.ubuntu.com"; +} + +function contentKey() { + return "content"; +} + +function setup() { + provider.addQueryItem("poster", "KDE"); + provider.addQueryItem("syntax", "text"); +} + +function handleResultData(data) { + // Whenever no redirection was received, it is an error + provider.error(data); +} + +function handleRedirection(url) { + provider.success(url); +} diff --git a/plasma/generic/dataengines/share/backends/pasteubuntucom/metadata.desktop b/plasma/generic/dataengines/share/backends/pasteubuntucom/metadata.desktop new file mode 100644 index 00000000..00932a39 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/pasteubuntucom/metadata.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Name=paste.ubuntu.com +Name[ar]=paste.ubuntu.com +Name[ast]=paste.ubuntu.com +Name[bg]=paste.ubuntu.com +Name[bs]=paste.ubuntu.com +Name[ca]=paste.ubuntu.com +Name[ca@valencia]=paste.ubuntu.com +Name[cs]=paste.ubuntu.com +Name[da]=paste.ubuntu.com +Name[de]=paste.ubuntu.com +Name[el]=paste.ubuntu.com +Name[en_GB]=paste.ubuntu.com +Name[es]=paste.ubuntu.com +Name[et]=paste.ubuntu.com +Name[eu]=paste.ubuntu.com +Name[fi]=paste.ubuntu.com +Name[fr]=paste.ubuntu.com +Name[ga]=paste.ubuntu.com +Name[gl]=paste.ubuntu.com +Name[gu]=paste.ubuntu.com +Name[he]=paste.ubuntu.com +Name[hi]=paste.ubuntu.com +Name[hr]=paste.ubuntu.com +Name[hu]=paste.ubuntu.com +Name[ia]=paste.ubuntu.com +Name[is]=paste.ubuntu.com +Name[it]=paste.ubuntu.com +Name[ja]=paste.ubuntu.com +Name[kk]=paste.ubuntu.com +Name[km]=paste.ubuntu.com +Name[ko]=paste.ubuntu.com +Name[lt]=paste.ubuntu.com +Name[lv]=paste.ubuntu.com +Name[mr]=paste.ubuntu.com +Name[nb]=paste.ubuntu.com +Name[nds]=paste.ubuntu.com +Name[nl]=paste.ubuntu.com +Name[pa]=paste.ubuntu.com +Name[pl]=paste.ubuntu.com +Name[pt]=paste.ubuntu.com +Name[pt_BR]=paste.ubuntu.com +Name[ro]=paste.ubuntu.com +Name[ru]=paste.ubuntu.com +Name[sk]=paste.ubuntu.com +Name[sl]=paste.ubuntu.com +Name[sr]=paste.ubuntu.com +Name[sr@ijekavian]=paste.ubuntu.com +Name[sr@ijekavianlatin]=paste.ubuntu.com +Name[sr@latin]=paste.ubuntu.com +Name[sv]=paste.ubuntu.com +Name[th]=paste.ubuntu.com +Name[tr]=paste.ubuntu.com +Name[ug]=paste.ubuntu.com +Name[uk]=paste.ubuntu.com +Name[wa]=paste.ubuntu.com +Name[x-test]=xxpaste.ubuntu.comxx +Name[zh_CN]=paste.ubuntu.com +Name[zh_TW]=paste.ubuntu.com +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=text/* + +X-KDE-PluginInfo-Name=pasteubuntucom +X-KDE-PluginInfo-Author=Harald Sitter +X-KDE-PluginInfo-Email=apachelogger@ubuntu.com +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://www.ubuntu.com diff --git a/plasma/generic/dataengines/share/backends/privatepaste/CMakeLists.txt b/plasma/generic/dataengines/share/backends/privatepaste/CMakeLists.txt new file mode 100644 index 00000000..4dbbb3e9 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/privatepaste/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-privatepastecom.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-privatepastecom.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/privatepastecom) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/privatepastecom) diff --git a/plasma/generic/dataengines/share/backends/privatepaste/contents/code/main.js b/plasma/generic/dataengines/share/backends/privatepaste/contents/code/main.js new file mode 100644 index 00000000..243037f9 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/privatepaste/contents/code/main.js @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2010 by Artur Duque de Souza * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://privatepaste.com/save"; +} + +function contentKey() { + return "paste_content"; +} + +function setup() { + provider.addQueryItem("_xsrf", "d38415c699a0408ebfce524c2dc0a4ba"); + provider.addQueryItem("formatting", "No Formatting"); + provider.addQueryItem("line_numbers", "on"); + provider.addQueryItem("expire", "31536000"); + provider.addQueryItem("secure_paste", "off"); +} + +function handleResultData(data) { + var res = data.match("(Error.+)"); + if (res != "") { + return; + } + provider.error(data); +} + +function handleRedirection(url) { + provider.success(url); +} diff --git a/plasma/generic/dataengines/share/backends/privatepaste/metadata.desktop b/plasma/generic/dataengines/share/backends/privatepaste/metadata.desktop new file mode 100644 index 00000000..63f5bab5 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/privatepaste/metadata.desktop @@ -0,0 +1,125 @@ +[Desktop Entry] +Name=privatepaste.com +Name[ar]=privatepaste.com +Name[ast]=privatepaste.com +Name[bg]=privatepaste.com +Name[bs]=privatepaste.com +Name[ca]=privatepaste.com +Name[ca@valencia]=privatepaste.com +Name[cs]=privatepaste.com +Name[da]=privatepaste.com +Name[de]=privatepaste.com +Name[el]=privatepaste.com +Name[en_GB]=privatepaste.com +Name[es]=privatepaste.com +Name[et]=privatepaste.com +Name[eu]=privatepaste.com +Name[fi]=privatepaste.com +Name[fr]=privatepaste.com +Name[ga]=privatepaste.com +Name[gl]=privatepaste.com +Name[gu]=privatepaste.com +Name[he]=privatepaste.com +Name[hi]=privatepaste.com +Name[hr]=privatepaste.com +Name[hu]=privatepaste.com +Name[ia]=privatepaste.com +Name[is]=privatepaste.com +Name[it]=privatepaste.com +Name[ja]=privatepaste.com +Name[kk]=privatepaste.com +Name[km]=privatepaste.com +Name[ko]=privatepaste.com +Name[lt]=privatepaste.com +Name[lv]=privatepaste.com +Name[mr]=privatepaste.com +Name[nb]=privatepaste.com +Name[nds]=privatepaste.com +Name[nl]=privatepaste.com +Name[pa]=privatepaste.com +Name[pl]=privatepaste.com +Name[pt]=privatepaste.com +Name[pt_BR]=privatepaste.com +Name[ro]=privatepaste.com +Name[ru]=privatepaste.com +Name[sk]=privatepaste.com +Name[sl]=privatepaste.com +Name[sr]=privatepaste.com +Name[sr@ijekavian]=privatepaste.com +Name[sr@ijekavianlatin]=privatepaste.com +Name[sr@latin]=privatepaste.com +Name[sv]=privatepaste.com +Name[th]=privatepaste.com +Name[tr]=privatepaste.com +Name[ug]=privatepaste.com +Name[uk]=privatepaste.com +Name[wa]=privatepaste.com +Name[x-test]=xxprivatepaste.comxx +Name[zh_CN]=privatepaste.com +Name[zh_TW]=privatepaste.com +Comment=Paste text with the PrivatePaste.com service +Comment[ast]=Apegar testu per aciu del serviciu PrivatePaste.com +Comment[bg]=Поставяне на текст през услугата PrivatePaste.com +Comment[bs]=Naljepljivanje teksta preko servisa privatepaste.com +Comment[ca]=Enganxa text amb el servei PrivatePaste.com +Comment[ca@valencia]=Apega text amb el servei PrivatePaste.com +Comment[cs]=Vložit text s využitím služby PrivatePaste.com +Comment[da]=Indsæt tekst med tjenesten PrivatePaste.com +Comment[de]=Text auf PrivatePaste.com veröffentlichen +Comment[el]=Επικόλληση κειμένου με την υπηρεσία PrivatePaste.com +Comment[en_GB]=Paste text with the PrivatePaste.com service +Comment[es]=Pegar texto mediante el servicio PrivatePaste.com +Comment[et]=Teksti asetamine PrivatePaste.com teenuse abil +Comment[eu]=Itsatsi testua PrivatePaste.com zerbitzuaren bidez +Comment[fi]=Liitä tekstiä PrivatePaste.com-palvelun avulla +Comment[fr]=Colle du texte à l'aide du service « PrivatePaste.com » +Comment[gl]=Apega texto co servizo PrivatePaste.com +Comment[he]=שיתוף קטעי טקסט באמצעות PrivatePaste.com +Comment[hr]=Zalijepi tekst pomoću servisa PrivatePaste.com +Comment[hu]=Szöveg beillesztése a PrivatePaste.com szolgáltatással +Comment[ia]=Colla texto con le servicio PrivatePaste.com +Comment[is]=Líma texta með PrivatePaste.com límklippusafninu +Comment[it]=Incolla testo con il servizio PrivatePaste.com +Comment[ja]=PrivatePaste.com のサービスを用いてテキストを貼り付ける +Comment[kk]=PrivatePaste.com қызметінен мәтінді алып орналастыру +Comment[km]=បិទភ្ជាប់​អត្ថបទ​ដោយ​ប្រើ​សេវា PrivatePaste.com +Comment[ko]=PrivatePaste.com으로 텍스트를 공유합니다 +Comment[lt]=Padėti tekstą naudojant PrivatePaste.com tarnybą +Comment[lv]=Ielīmēt tekstu ar PrivatePaste.com servisu +Comment[mr]=privatepaste.com सेवा वापरुन पाठ्य चिटकवा +Comment[nb]=Lim inn tekst med tjenesten PrivatePaste.com +Comment[nds]=Text op "PrivatePaste.com" praatstellen +Comment[nl]=Plak tekst met de service PrivatePaste.com +Comment[pa]=PrivatePaste.com ਸਰਵਿਸ ਨਾਲ ਟੈਕਸਟ ਚੇਪੋ +Comment[pl]=Wklejanie tekstu z usługą PrivatePaste.com +Comment[pt]=Colar texto com o serviço PrivatePaste.com +Comment[pt_BR]=Colar texto com o serviço PrivatePaste.com +Comment[ro]=Lipește text cu serviciul PrivatePaste.com +Comment[ru]=Позволяет публиковать текст на сервере PrivatePaste.com +Comment[sk]=Vloží text pomocou služby PrivatePaste.com +Comment[sl]=Prilepite besedilo s storitvijo PrivatePaste.com +Comment[sr]=Налепљивање текста преко сервиса privatepaste.com +Comment[sr@ijekavian]=Наљепљивање текста преко сервиса privatepaste.com +Comment[sr@ijekavianlatin]=Naljepljivanje teksta preko servisa privatepaste.com +Comment[sr@latin]=Nalepljivanje teksta preko servisa privatepaste.com +Comment[sv]=Klistra in text med tjänsten PrivatePaste.com +Comment[th]=แปะข้อความไปยังบริการของ PrivatePaste.com +Comment[tr]=Metinleri PrivatePaste.com servisini kullanarak paylaş +Comment[ug]=PrivatePaste.com مۇلازىمىتىدىن تېكىست چاپلا +Comment[uk]=Вставка фрагментів тексту за допомогою служби PrivatePaste.com +Comment[wa]=Aclaper do tecse avou l' siervice PrivatePaste.com +Comment[x-test]=xxPaste text with the PrivatePaste.com servicexx +Comment[zh_CN]=用 PrivatePaste.com 服务粘贴文字 +Comment[zh_TW]=用 PrivatePaste.com 服務貼上文字 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=text/* + +X-KDE-PluginInfo-Name=privatepastecom +X-KDE-PluginInfo-Author=Artur Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/generic/dataengines/share/backends/simplestimagehosting/CMakeLists.txt b/plasma/generic/dataengines/share/backends/simplestimagehosting/CMakeLists.txt new file mode 100644 index 00000000..a7961fb0 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/simplestimagehosting/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-simplestimagehosting.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-simplestimagehosting.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/simplestimagehosting/) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/simplestimagehosting) diff --git a/plasma/generic/dataengines/share/backends/simplestimagehosting/contents/code/main.js b/plasma/generic/dataengines/share/backends/simplestimagehosting/contents/code/main.js new file mode 100644 index 00000000..bb68974d --- /dev/null +++ b/plasma/generic/dataengines/share/backends/simplestimagehosting/contents/code/main.js @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2010 by Artur Duque de Souza * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://api.simplest-image-hosting.net/upload:image,default"; +} + +function contentKey() { + return "fileName"; +} + +function setup() { +} + +function handleResultData(data) { + var res = data.match("800\n(http://.+)\n"); + if (res == "") { + provider.error(data); + return; + } + provider.success(data.replace("800", "").replace("\n", "")); +} diff --git a/plasma/generic/dataengines/share/backends/simplestimagehosting/metadata.desktop b/plasma/generic/dataengines/share/backends/simplestimagehosting/metadata.desktop new file mode 100644 index 00000000..acfed83c --- /dev/null +++ b/plasma/generic/dataengines/share/backends/simplestimagehosting/metadata.desktop @@ -0,0 +1,121 @@ +[Desktop Entry] +Name=Simplest Image Hosting +Name[ar]=أبسط إستضافة للصور +Name[ast]=Simplest Image Hosting +Name[bg]=Simplest Image Hosting +Name[bs]=Simplest Image Hosting +Name[ca]=Simplest Image Hosting +Name[ca@valencia]=Simplest Image Hosting +Name[cs]=Simplest Image Hosting +Name[da]=Simplest Image Hosting +Name[de]=Simplest Image Hosting +Name[el]=Πιο απλή φιλοξενία εικόνας +Name[en_GB]=Simplest Image Hosting +Name[es]=Simplest Image Hosting +Name[et]=Simplest Image Hosting +Name[eu]=Simplest Image Hosting +Name[fi]=Simplest Image Hosting +Name[fr]=Simplest Image Hosting +Name[gl]=Simplest Image Hosting +Name[he]=Simplest Image Hosting +Name[hr]=Simplest Image Hosting +Name[hu]=Simplest Image Hosting +Name[ia]=Simplest Image Hosting +Name[is]=Simplest Image Hosting +Name[it]=Simplest Image Hosting +Name[ja]=Simplest Image Hosting +Name[kk]=Simplest Image Hosting +Name[km]=ការ​បង្ហោះរូបភាព​សាមញ្ញ​បំផុត +Name[ko]=Simplest Image Hosting +Name[lt]=Paprasčiausias nuotraukų talpinimas +Name[lv]=Simplest Image Hosting +Name[mr]=सिंप्लेस्ट प्रतिमा होस्टींग +Name[nb]=Simplest Image Hosting +Name[nds]=Simplest-Image-Hosting +Name[nl]=Simplest Image Hosting +Name[pa]=ਸੈਂਪਲਸਟ ਈਮੇਜ਼ ਹੋਸਟਿੰਗ +Name[pl]=Simplest Image Hosting +Name[pt]=Simplest Image Hosting +Name[pt_BR]=Simplest Image Hosting +Name[ro]=Cea mai simplă găzduire de imagini +Name[ru]=Simplest-Image-Hosting.net +Name[sk]=Simplest Image Hosting +Name[sl]=Simplest Image Hosting +Name[sr]=Симплест имејџ хостинг +Name[sr@ijekavian]=Симплест имејџ хостинг +Name[sr@ijekavianlatin]=Simplest Image Hosting +Name[sr@latin]=Simplest Image Hosting +Name[sv]=Simplest Image Hosting +Name[th]=บริการ Simplest Image Hosting +Name[tr]=Simplest Image Hosting +Name[ug]=Simplest Image Hosting +Name[uk]=Simplest Image Hosting +Name[wa]=Simplest Image Hosting +Name[x-test]=xxSimplest Image Hostingxx +Name[zh_CN]=Simplest Image Hosting +Name[zh_TW]=Simplest Image Hosting +Comment=Allows images to be shared using the Simplest Image Hosting service +Comment[bg]=Позволява споделяне на изображения чрез услугата Simplest Image Hosting +Comment[bs]=Dijeljenje slika preko servisa Simplest image hosting +Comment[ca]=Permet la compartició d'imatges utilitzant el servei «Simplest Image Hosting» +Comment[ca@valencia]=Permet la compartició d'imatges utilitzant el servei «Simplest Image Hosting» +Comment[cs]=Povolí sdílení obrázků pomocí služby Simplest Image Hosting +Comment[da]=Muliggør deling af billeder med tjenesten Simplest Image Hosting +Comment[de]=Ermöglicht die Veröffentlichung von Bildern über den simplest-image-hosting.net-Dienst +Comment[el]=Επιτρέπει στις εικόνες να γίνουν κοινόχρηστες χρησιμοποιώντας την υπηρεσία imgur +Comment[en_GB]=Allows images to be shared using the Simplest Image Hosting service +Comment[es]=Permite compartir imágenes a través del servicio de Simplest Image Hosting +Comment[et]=Piltide jagamine Simplest Image Hosting teenuse kaudu +Comment[eu]=Irudiak Simplest Image Hosting zerbitzuaren bidez partekatzeko aukera ematen du +Comment[fi]=Mahdollistaa kuvien jakamisen Simplest Image Hosting -palvelussa +Comment[fr]=Permet le partage d'images à l'aide du service « Simplest Image Hosting » +Comment[gl]=Permite compartir imaxes mediante o servizo Simplest Image Hosting +Comment[he]=מאפשר שיתוף תמונות באמצעות השירות Simplest Image Hosting +Comment[hr]=Omogućuje dijeljenje slika koristeći servis Simplest Image Hosting +Comment[hu]=Képek megosztása a Simple Image Hosting szolgáltatás használatával +Comment[ia]=Il permitte imagines de esser compartite per usar le servicio Simplest Image Hosting +Comment[is]=Gerir kleift að deila myndum með Simplest Image Hosting þjónustunni +Comment[it]=Abilita la condivisione di immagini con il servizio Simplest Image Hosting +Comment[ja]=Simplest Image Hosting のサービスを用いたテキストの共有を有効にする +Comment[kk]=Simplest Image Hosting қызметі көмегімен кескіндерді ортақ қылуды рұқсат ету +Comment[km]=បើក​ការ​ចែករំលែក​រូបភាព​ ដោយ​ប្រើ​សេវា​បង្ហោះ​រូបភាព​សាមញ្ញ​បំផុត​ +Comment[ko]=Simplest Image Hosting으로 그림을 공유합니다 +Comment[lt]=Įjungia dalinimąsį nuotraukomis naudojant paprasčiausio nuotraukų talpinimo tarnybą +Comment[lv]=Ļauj kopīgot attēlus, izmantojot Simplest Image Hosting servisu +Comment[mr]=सिंप्लेस्ट प्रतिमा होस्टींग सेवा वापरुन प्रतिमा शेअर करतो +Comment[nb]=Gjør det mulig å dele bilder via tjenesten Simplest Image Hosting +Comment[nds]=Biller op "Simplest Image Hosting" praatstellen +Comment[nl]=Staat het delen van afbeeldingen toe met gebruik van de service Simplest Image Hosting +Comment[pa]=ਸੈਂਪਲਸਟ ਈਮੇਜ਼ ਹੋਸਟਿੰਗ ਸਰਵਿਸ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਚਿੱਤਰ ਸਾਂਝੇ ਕਰਨ ਲਈ ਸਹਾਇਕ +Comment[pl]=Pozwala na udostępnianie obrazów przy użyciu usługi Simplest Image Hosting +Comment[pt]=Permite a partilha de imagens com o serviço do Simplest Image Hosting +Comment[pt_BR]=Permite o compartilhamento de imagens usando o serviço do Simplest Image Hosting +Comment[ro]=Permite ca imaginile să fie partajate folosind serviciul Simplest Image Hosting +Comment[ru]=Позволяет публиковать изображения на сервере Simplest Image Hosting +Comment[sk]=Povolí zdieľanie obrázkov pomocou služby Simplest Image Hosting +Comment[sl]=Omogoča deljenje slik prek storitve Simplest Image Hosting +Comment[sr]=Дељење слика преко сервиса Симплест имејџ хостинг +Comment[sr@ijekavian]=Дијељење слика преко сервиса Симплест имејџ хостинг +Comment[sr@ijekavianlatin]=Dijeljenje slika preko servisa Simplest Image Hosting +Comment[sr@latin]=Deljenje slika preko servisa Simplest Image Hosting +Comment[sv]=Tillåter att bilder delas genom att använda Simplest Image Hosting +Comment[tr]=Simplest Image Hosting servisini kullanarak resimleri paylaşmayı sağlar +Comment[ug]=رەسىملەرنى Simplest Image Hosting مۇلازىمىتىنى ئىشلىتىپ ھەمبەھىرلەشكە ئىجازەت +Comment[uk]=Уможливлює оприлюднення зображень за допомогою служби Simplest Image Hosting +Comment[vi]=Cho phép chia sẻ ảnh qua dịch vụ Simplet Image Hosting +Comment[wa]=Permete li pårtaedje d' imådjes e s' siervant do siervice Simplest Image Hosting +Comment[x-test]=xxAllows images to be shared using the Simplest Image Hosting servicexx +Comment[zh_CN]=用最简单的图片主机服务共享图片 +Comment[zh_TW]=允許使用 Simplest Image Hosting 服務分享影像 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=image/* + +X-KDE-PluginInfo-Name=simplestimagehosting +X-KDE-PluginInfo-Author=Artur de Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/generic/dataengines/share/backends/wklej/CMakeLists.txt b/plasma/generic/dataengines/share/backends/wklej/CMakeLists.txt new file mode 100644 index 00000000..06344690 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/wklej/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-wklej.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-wklej.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/wklej/) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/wklej) diff --git a/plasma/generic/dataengines/share/backends/wklej/contents/code/main.js b/plasma/generic/dataengines/share/backends/wklej/contents/code/main.js new file mode 100644 index 00000000..7060a89c --- /dev/null +++ b/plasma/generic/dataengines/share/backends/wklej/contents/code/main.js @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2010 by Artur Duque de Souza * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://wklej.org"; +} + +function contentKey() { + return "body"; +} + +function setup() { + provider.addQueryItem("autor", "kde"); + provider.addQueryItem("syntax", "text"); +} + +function handleResultData(data) { + var res = provider.parseXML("title", data); + if (res == "") { + provider.error(data); + } + var id = res.split(" ")[1].replace("#", "http://wklej.org/id/"); + provider.success(id); +} + diff --git a/plasma/generic/dataengines/share/backends/wklej/metadata.desktop b/plasma/generic/dataengines/share/backends/wklej/metadata.desktop new file mode 100644 index 00000000..b478de53 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/wklej/metadata.desktop @@ -0,0 +1,126 @@ +[Desktop Entry] +Name=wklej.org +Name[ar]=wklej.org +Name[ast]=wklej.org +Name[bg]=wklej.org +Name[bs]=wklej.org +Name[ca]=wklej.org +Name[ca@valencia]=wklej.org +Name[cs]=wklej.org +Name[da]=wklej.org +Name[de]=wklej.org +Name[el]=wklej.org +Name[en_GB]=wklej.org +Name[es]=wklej.org +Name[et]=wklej.org +Name[eu]=wklej.org +Name[fi]=wklej.org +Name[fr]=wklej.org +Name[ga]=wklej.org +Name[gl]=wklej.org +Name[gu]=wklej.org +Name[he]=wklej.org +Name[hi]=wklej.org +Name[hr]=wklej.org +Name[hu]=wklej.org +Name[ia]=wklej.org +Name[is]=wklej.org +Name[it]=wklej.org +Name[ja]=wklej.org +Name[kk]=wklej.org +Name[km]=wklej.org +Name[ko]=wklej.org +Name[lt]=wklej.org +Name[lv]=wklej.org +Name[mr]=wklej.org +Name[nb]=wklej.org +Name[nds]=wklej.org +Name[nl]=wklej.org +Name[pa]=wklej.org +Name[pl]=wklej.org +Name[pt]=wklej.org +Name[pt_BR]=wklej.org +Name[ro]=wklej.org +Name[ru]=wklej.org +Name[sk]=wklej.org +Name[sl]=wklej.org +Name[sr]=wklej.org +Name[sr@ijekavian]=wklej.org +Name[sr@ijekavianlatin]=wklej.org +Name[sr@latin]=wklej.org +Name[sv]=wklej.org +Name[tg]=wklej.org +Name[th]=wklej.org +Name[tr]=wklej.org +Name[ug]=wklej.org +Name[uk]=wklej.org +Name[wa]=wklej.org +Name[x-test]=xxwklej.orgxx +Name[zh_CN]=wklej.org +Name[zh_TW]=wklej.org +Comment=Allows text to be shared using the wklej.org service +Comment[ar]=يسمح للنصوص أن تُشارك بإستخدام خدمة wklej.org +Comment[bg]=Позволява споделянето на текст чрез wklej.org +Comment[bs]=Dopušta dijeljenje teksta preko servisa wklej.org +Comment[ca]=Permet la compartició de text utilitzant el servei wklej.org +Comment[ca@valencia]=Permet la compartició de text utilitzant el servei wklej.org +Comment[cs]=Povolí sdílení textů pomocí služby wklej.org +Comment[da]=Muliggør deling af tekst med tjenesten wklej.org +Comment[de]=Ermöglicht die Veröffentlichung von Text über den wklej.org-Dienst +Comment[el]=Επιτρέπει στο κείμενο να γίνει κοινόχρηστο χρησιμοποιώντας την υπηρεσία wklej.org +Comment[en_GB]=Allows text to be shared using the wklej.org service +Comment[es]=Permite compartir texto a través del servicio de wklej.org +Comment[et]=Teksti jagamine wklej.org teenuse kaudu +Comment[eu]=Testua wklej.org zerbitzuaren bidez partekatzeko aukera ematen du +Comment[fi]=Mahdollistaa tekstin jakamisen wklej.org-palvelussa +Comment[fr]=Permet le partage de texte à l'aide du service « wklej.org » +Comment[gl]=Permite compartir texto mediante o servizo wklej.org +Comment[he]=מאפשר שיתוף טקסט באמצעות השירות wklej.org +Comment[hr]=Omogućuje dijeljenje teksta koristeći servis wklej.org +Comment[hu]=Szöveg megosztása a wklej.org szolgáltatás használatával +Comment[ia]=Il permitte texto de esser compartite per usar le servicio wklej.org +Comment[is]=Gerir kleift að deila texta með wklej.org þjónustunni +Comment[it]=Abilita la condivisione di testo con il servizio wklej.org +Comment[ja]=wklej.org のサービスを用いたテキストの共有を有効にする +Comment[kk]=wklej.org қызметі көмегімен мәтінді ортақ қылуды рұқсат ету +Comment[km]=បើក​ការ​ចែករំលែក​អត្ថបទ​ដោយ​ប្រើ​សេវា wklej.org +Comment[ko]=wklej.org로 텍스트를 공유합니다 +Comment[lt]=Įjungia dalinimąsį tekstu naudojant wklej.org tarnybą +Comment[lv]=Ļauj kopīgot tekstu, izmantojot wklej.org servisu +Comment[mr]=wklej.org सेवा वापरुन पाठ्य शेअर करतो +Comment[nb]=Gjør det mulig å dele tekst via tjenesten wklej.org +Comment[nds]=Text op "wklej.org" praatstellen +Comment[nl]=Staat het delen van tekst toe met gebruik van de service wklej.org +Comment[pa]=wklej.org ਸਰਵਿਸ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਟੈਕਸਟ ਸਾਂਝਾ ਕਰਨਾ ਯੋਗ +Comment[pl]=Pozwala na udostępnianie tekstu przy użyciu usługi wklej.org +Comment[pt]=Permite a partilha de texto com o serviço do 'wklej.org' +Comment[pt_BR]=Permite o compartilhamento de texto com o serviço do wklej.org +Comment[ro]=Permite partajarea textului cu serviciul wklej.org +Comment[ru]=Позволяет публиковать текст на сервере wklej.org +Comment[sk]=Povolí zdieľanie textu pomocou služby wklej.org +Comment[sl]=Omogoča deljenje besedila prek storitve wklej.org +Comment[sr]=Дељење текста преко сервиса wklej.org +Comment[sr@ijekavian]=Дијељење текста преко сервиса wklej.org +Comment[sr@ijekavianlatin]=Dijeljenje teksta preko servisa wklej.org +Comment[sr@latin]=Deljenje teksta preko servisa wklej.org +Comment[sv]=Tillåter att text delas genom att använda tjänsten wklej.org +Comment[tr]=wklej.org servisini kullanarak metinleri paylaşmayı sağlar +Comment[ug]=تېكىستلەرنى wklej.org مۇلازىمىتىنى ئىشلىتىپ ھەمبەھىرلەشكە ئىجازەت +Comment[uk]=Уможливлює оприлюднення фрагментів тексту за допомогою служби wklej.org +Comment[vi]=Cho phép chia sẻ văn bản qua dịch vụ wklej.org +Comment[wa]=Permete li pårtaedje di scrijhaedje e s' siervant do siervice wklej.org +Comment[x-test]=xxAllows text to be shared using the wklej.org servicexx +Comment[zh_CN]=用 wklej.org服务共享文字 +Comment[zh_TW]=允許使用 wklej.org 服務分享文字 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=text/* + +X-KDE-PluginInfo-Name=wklej +X-KDE-PluginInfo-Author=Artur de Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/generic/dataengines/share/backends/wstaw/CMakeLists.txt b/plasma/generic/dataengines/share/backends/wstaw/CMakeLists.txt new file mode 100644 index 00000000..3a31a16f --- /dev/null +++ b/plasma/generic/dataengines/share/backends/wstaw/CMakeLists.txt @@ -0,0 +1,7 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/metadata.desktop ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-wstaw.desktop COPYONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plasma-dataengine-share-addon-wstaw.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES metadata.desktop + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/wstaw/) + +install(DIRECTORY contents + DESTINATION ${DATA_INSTALL_DIR}/plasma/shareprovider/wstaw) diff --git a/plasma/generic/dataengines/share/backends/wstaw/contents/code/main.js b/plasma/generic/dataengines/share/backends/wstaw/contents/code/main.js new file mode 100644 index 00000000..607738c8 --- /dev/null +++ b/plasma/generic/dataengines/share/backends/wstaw/contents/code/main.js @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2010 by Artur Duque de Souza * + * * + * 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 . * + ***************************************************************************/ + +function url() { + return "http://wstaw.org"; +} + +function contentKey() { + return "pic"; +} + +function setup() { +} + +function handleResultData(data) { + var res = data.match("value=\"http://wstaw.org/m/.+\""); + if (res == null) { + provider.error(data); + return; + } + provider.success(res[0].replace("value=", "").replace("\"", "").replace("\"", "")); +} diff --git a/plasma/generic/dataengines/share/backends/wstaw/metadata.desktop b/plasma/generic/dataengines/share/backends/wstaw/metadata.desktop new file mode 100644 index 00000000..6fac7c8b --- /dev/null +++ b/plasma/generic/dataengines/share/backends/wstaw/metadata.desktop @@ -0,0 +1,126 @@ +[Desktop Entry] +Name=wstaw.org +Name[ar]=wstaw.org +Name[ast]=wstaw.org +Name[bg]=wstaw.org +Name[bs]=wstaw.org +Name[ca]=wstaw.org +Name[ca@valencia]=wstaw.org +Name[cs]=wstaw.org +Name[da]=wstaw.org +Name[de]=wstaw.org +Name[el]=wstaw.org +Name[en_GB]=wstaw.org +Name[es]=wstaw.org +Name[et]=wstaw.org +Name[eu]=wstaw.org +Name[fi]=wstaw.org +Name[fr]=wstaw.org +Name[ga]=wstaw.org +Name[gl]=wstaw.org +Name[gu]=wstaw.org +Name[he]=wstaw.org +Name[hi]=wstaw.org +Name[hr]=wstaw.org +Name[hu]=wstaw.org +Name[ia]=wstaw.org +Name[is]=wstaw.org +Name[it]=wstaw.org +Name[ja]=wstaw.org +Name[kk]=wstaw.org +Name[km]=wstaw.org +Name[ko]=wstaw.org +Name[lt]=wstaw.org +Name[lv]=wstaw.org +Name[mai]=wstaw.org +Name[mr]=wstaw.org +Name[nb]=wstaw.org +Name[nds]=wstaw.org +Name[nl]=wstaw.org +Name[pa]=wstaw.org +Name[pl]=wstaw.org +Name[pt]=wstaw.org +Name[pt_BR]=wstaw.org +Name[ro]=wstaw.org +Name[ru]=wstaw.org +Name[sk]=wstaw.org +Name[sl]=wstaw.org +Name[sr]=wstaw.org +Name[sr@ijekavian]=wstaw.org +Name[sr@ijekavianlatin]=wstaw.org +Name[sr@latin]=wstaw.org +Name[sv]=wstaw.org +Name[tg]=wstaw.org +Name[th]=wstaw.org +Name[tr]=wstaw.org +Name[ug]=wstaw.org +Name[uk]=wstaw.org +Name[wa]=wstaw.org +Name[x-test]=xxwstaw.orgxx +Name[zh_CN]=wstaw.org +Name[zh_TW]=wstaw.org +Comment=Allows images to be shared using the wstaw.org service +Comment[bg]=Позволява споделянето на изображения чрез wstaw.org +Comment[bs]=Dopušta dijeljenje slika preko servisa wstaw.org +Comment[ca]=Permet la compartició d'imatges utilitzant el servei wstaw.org +Comment[ca@valencia]=Permet la compartició d'imatges utilitzant el servei wstaw.org +Comment[cs]=Povolí sdílení obrázků pomocí služby wstaw.org +Comment[da]=Muliggør deling af billeder med tjenesten wstaw.org +Comment[de]=Ermöglicht die Veröffentlichung von Bildern über den wstaw.org-Dienst +Comment[el]=Επιτρέπει το μοίρασμα των εικόνων χρησιμοποιώντας την υπηρεσία wstaw.org +Comment[en_GB]=Allows images to be shared using the wstaw.org service +Comment[es]=Permite compartir imágenes a través del servicio de wstaw.org +Comment[et]=Piltide jagamine wstaw.org teenuse kaudu +Comment[eu]=Irudiak wstaw.org zerbitzuaren bidez partekatzeko aukera ematen du +Comment[fi]=Mahdollistaa kuvien jakamisen wstaw.org-palvelussa +Comment[fr]=Permet le partage d'images à l'aide du service « wstaw.org » +Comment[gl]=Permite compartir imaxes mediante o servizo wstaw.org +Comment[he]=מאפשר שיתוף תמונות באמצעות השירות wstaw.org +Comment[hr]=Omogućuje dijeljenje slika koristeći servis wstaw.org +Comment[hu]=Képek megosztása a wstaw.org szolgáltatás használatával +Comment[ia]=Il permitte images de esser compartite per usar le servicio wstaw.org +Comment[is]=Gerir kleift að deila myndum með wstaw.org þjónustunni +Comment[it]=Abilita la condivisione di immagini con il servizio wstaw.org +Comment[ja]=wstaw.org のサービスを用いた画像の共有を有効にする +Comment[kk]=wstaw.org қызметі көмегімен кескіндерді ортақ қылуды рұқсат ету +Comment[km]=បើក​ការ​ចែករំលែក​រូបភាព​ ដោយ​ប្រើ​សេវា wstaw.org +Comment[ko]=wstaw.org로 그림을 공유합니다 +Comment[lt]=Įjungia dalinimąsį nuotraukomis naudojant wstaw.org tarnybą +Comment[lv]=Ļauj kopīgot attēlus, izmantojot wstaw.org servisu +Comment[mr]=wstaw.org सेवा वापरुन प्रतिमा शेअर करतो +Comment[nb]=Gjør det mulig å dele bilder via tjenesten wstaw.org +Comment[nds]=Biller op "wstaw.org" praatstellen +Comment[nl]=Staat het delen van afbeeldingen toe met gebruik van de service wstaw.org +Comment[pa]=wstaw.org ਸਰਵਿਸ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਚਿੱਤਰ ਸਾਂਝੇ ਕਰਨ ਲਈ ਸਹਾਇਕ +Comment[pl]=Pozwala na udostępnianie obrazów przy użyciu usługi wstaw.org +Comment[pt]=Permite a partilha de imagens com o serviço do 'wstaw.org' +Comment[pt_BR]=Permite o compartilhamento de imagens usando o serviço do wstaw.org +Comment[ro]=Permite partajarea imaginilor cu serviciul wstaw.org +Comment[ru]=Позволяет публиковать изображения на сервере wstaw.org +Comment[sk]=Povolí zdieľanie obrázkov pomocou služby wstaw.org +Comment[sl]=Omogoča deljenje slik prek storitve wstaw.org +Comment[sr]=Дељење слика преко сервиса wstaw.org +Comment[sr@ijekavian]=Дијељење слика преко сервиса wstaw.org +Comment[sr@ijekavianlatin]=Dijeljenje slika preko servisa wstaw.org +Comment[sr@latin]=Deljenje slika preko servisa wstaw.org +Comment[sv]=Tillåter att bilder delas genom att använda tjänsten wstaw.org +Comment[tr]=wstaw.org servisi kullanarak resimleri paylaşmayı sağlar +Comment[ug]=رەسىملەرنى wstaw.org مۇلازىمىتىنى ئىشلىتىپ ھەمبەھىرلەشكە ئىجازەت +Comment[uk]=Уможливлює оприлюднення зображень за допомогою служби wstaw.org +Comment[vi]=Cho phép chia sẻ ảnh qua dịch vụ wstaw.org +Comment[wa]=Permete li pårtaedje d' imådjes e s' siervant do siervice wstaw.org +Comment[x-test]=xxAllows images to be shared using the wstaw.org servicexx +Comment[zh_CN]=用 wstaw.org 服务共享图片 +Comment[zh_TW]=允許使用 wstaw.org 服務分享影像 +Type=Service + +X-KDE-ServiceTypes=Plasma/ShareProvider +X-KDE-Library=plasma_engine_share +X-KDE-PlasmaShareProvider-MimeType=image/* + +X-KDE-PluginInfo-Name=wstaw +X-KDE-PluginInfo-Author=Artur de Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/generic/dataengines/share/data/plasma-dataengine-share.desktop b/plasma/generic/dataengines/share/data/plasma-dataengine-share.desktop new file mode 100644 index 00000000..42236bfc --- /dev/null +++ b/plasma/generic/dataengines/share/data/plasma-dataengine-share.desktop @@ -0,0 +1,127 @@ +[Desktop Entry] +Name=Share Services +Name[ast]=Compartir Servicios +Name[bg]=Услуги за споделяне +Name[bs]=Servisi dijeljenja +Name[ca]=Serveis de compartició +Name[ca@valencia]=Serveis de compartició +Name[cs]=Sdílené služby +Name[da]=Delingstjenester +Name[de]=Veröffentlichungsdienste +Name[el]=Υπηρεσίες κοινής χρήσης +Name[en_GB]=Share Services +Name[es]=Compartir servicios +Name[et]=Jagamisteenused +Name[eu]=Partekatze-zerbitzuak +Name[fi]=Jakamispalvelut +Name[fr]=Services de partage +Name[ga]=Seirbhísí Comhroinnt +Name[gl]=Compartir servizos +Name[he]=שירותי שיתוף +Name[hi]=साझा सेवाएँ +Name[hr]=Servisi za dijeljenje +Name[hu]=Megosztási szolgáltatások +Name[ia]=Servicios compartite +Name[is]=Deila þjónustum +Name[it]=Servizi di condivisione +Name[ja]=サービスの共有 +Name[kk]=Ортақтастыру қызметтер +Name[km]=ចែក​រំលែក​សេវា +Name[kn]=ಹಂಚಿಕೆ ಸೇವೆಗಳು +Name[ko]=공유 서비스 +Name[lt]=Dalinimosi tarnybos +Name[lv]=Kopīgot servisus +Name[mr]=शेअर सेवा +Name[nb]=Dele-tjenester +Name[nds]=Praatstell-Deensten +Name[nl]=Services voor delen +Name[pa]=ਸਾਂਝੀਆਂ ਸਰਵਿਸਾਂ +Name[pl]=Usługi współdzielenia +Name[pt]=Serviços de Partilha +Name[pt_BR]=Serviços de compartilhamento +Name[ro]=Servicii de partajare +Name[ru]=Обмен информацией +Name[sk]=Služby zdieľania +Name[sl]=Storitve za deljenje +Name[sr]=Сервиси дељења +Name[sr@ijekavian]=Сервиси дељења +Name[sr@ijekavianlatin]=Servisi deljenja +Name[sr@latin]=Servisi deljenja +Name[sv]=Delningstjänster +Name[th]=บริการที่ใช้งานร่วมกัน +Name[tr]=Paylaşım Servisleri +Name[ug]=مۇلازىمەتلەرنى ھەمبەھىرلە +Name[uk]=Служби оприлюднення +Name[wa]=Pårtaedjî siervices +Name[x-test]=xxShare Servicesxx +Name[zh_CN]=共享服务 +Name[zh_TW]=分享服務 +Comment=Engine to share content using different services +Comment[ast]=Motor pa compartir conteníos a traviés d'estremaos servicios +Comment[bg]=Споделяне на данни чрез различни услуги +Comment[bs]=Motor za dijeljenje sadržaja preko različitih servisa +Comment[ca]=Motor per compartir contingut utilitzant diferents serveis +Comment[ca@valencia]=Motor per compartir contingut utilitzant diferents serveis +Comment[cs]=Povolí sdílení obsahu pomocí různých služeb +Comment[da]=Motor til at dele indhold ved brug af forskellige tjenester +Comment[de]=Treiber für die Veröffentlichung von Inhalten über verschiedene Dienste +Comment[el]=Μηχανισμός για το μοίρασμα περιεχομένου χρησιμοποιώντας διαφορετικές υπηρεσίες +Comment[en_GB]=Engine to share content using different services +Comment[es]=Motor para compartir contenidos a través de diferentes servicios +Comment[et]=Eri teenuste kaudu sisu jagamise mootor +Comment[eu]=Hainbat zerbitzuren bidez edukia partekatzeko motorra +Comment[fi]=Moottori sisällön jakamiseen useissa palveluissa +Comment[fr]=Système de partage de contenus utilisant différents services +Comment[gl]=Motor para compartir contido mediante diversos servizos +Comment[he]=מנוע לשיתוף תוכן באמצעות שירותים שונים +Comment[hr]=Mehanizam za dijeljenje sadržaja koristeći razne servise +Comment[hu]=Adatmodul tartalommegosztáshoz különböző szolgáltatások használatával +Comment[ia]=Motor pro compartir contento usante differente servicios +Comment[is]=Kerfi til að deila efni með ýmsum þjónustum +Comment[it]=Motore per condividere del contenuto usando diversi servizi +Comment[ja]=様々なサービスを用いたコンテンツ共有エンジン +Comment[kk]=Түрлі қызметтер көмегімен мазмұның ортақ қылу тетігі +Comment[km]=ម៉ាស៊ីន​ដើម្បី​ចែករំលែក​មាតិកា​ ដោយ​ប្រើ​សេវា​ផ្សេងៗ​គ្នា +Comment[ko]=컨텐츠 공유 서비스 +Comment[lt]=Turinio dalinimosi, naudojant įvairias tarnybas, modulis +Comment[lv]=Dzinējs satura kopīgošanai, izmantojot atšķirīgus servisus +Comment[mr]=विविध सेवा वापरुन मजकूर शेअर करण्याचे इंजिन +Comment[nb]=Motor for å dele innhold ved bruk av forskjellige tjenester +Comment[nds]=Programmkarn för Deensten för't Praatstellen vun Inholden +Comment[nl]=Engine om inhoud te delen met gebruik van verschillende services +Comment[pa]=ਵੱਖ ਵੱਖ ਸਰਵਿਸਾਂ ਵਿੱਚ ਸਮਗੱਰੀ ਸਾਂਝੀ ਕਰਨ ਲਈ ਇੰਜਣ +Comment[pl]=Silnik do udostępniania zawartości przy użyciu rożnych usług +Comment[pt]=Um motor para partilhar conteúdos através de vários serviços +Comment[pt_BR]=Um mecanismo para compartilhar conteúdos usando diferentes serviços +Comment[ro]=Motor pentru partajarea conținutului folosind diferite servicii +Comment[ru]=Источник данных для обмена содержимым между людьми, используя различные интернет-службы +Comment[sk]=Nástroj na zdieľanie obsahu pomocou rôznych služieb +Comment[sl]=Pogon za deljenje vsebin prek različnih storitev +Comment[sr]=Мотор за дељење садржаја преко различитих сервиса +Comment[sr@ijekavian]=Мотор за дијељење садржаја преко различитих сервиса +Comment[sr@ijekavianlatin]=Motor za dijeljenje sadržaja preko različitih servisa +Comment[sr@latin]=Motor za deljenje sadržaja preko različitih servisa +Comment[sv]=Gränssnitt för att dela innehåll genom att använda olika tjänster +Comment[th]=กลไกการแลกเปลี่ยนเนื้อหาบนบริการที่แตกต่างกัน +Comment[tr]=Farklı servisleri kullanarak içerik paylaşmayı sağlayan motor +Comment[ug]=ئوخشىمىغان مۇلازىمەتلەرنى ئىشلىتىپ مەزمۇنلارنى ھەمبەھىرلەيدىغان ماتور +Comment[uk]=Рушій спільного використання даних різними службами +Comment[vi]=Cơ chế chia sẻ nội dung thông qua các dịch vụ +Comment[wa]=Moteur po pårtaedjî l' ådvins tot s' siervant d' diferins siervices +Comment[x-test]=xxEngine to share content using different servicesxx +Comment[zh_CN]=用不同服务共享内容的引擎 +Comment[zh_TW]=用不同的服務來分享內容的引擎 +Type=Service +X-KDE-ServiceTypes=Plasma/DataEngine +Icon=document-share + +X-KDE-Library=plasma_engine_share +X-KDE-PluginInfo-Author=Artur de Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Name=org.kde.plasma.dataengine.share +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Utilities +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/dataengines/share/data/plasma-packagestructure-share.desktop b/plasma/generic/dataengines/share/data/plasma-packagestructure-share.desktop new file mode 100644 index 00000000..f51a4360 --- /dev/null +++ b/plasma/generic/dataengines/share/data/plasma-packagestructure-share.desktop @@ -0,0 +1,121 @@ +[Desktop Entry] +Name=ShareProvider +Name[ast]=Fornidor de Servicios +Name[bg]=Доставчик на услуги за споделяне +Name[bs]=Dobavljač dijeljenja +Name[ca]=ShareProvider +Name[ca@valencia]=ShareProvider +Name[cs]=ShareProvider +Name[da]=Delingsudbyder +Name[de]=Veröffentlichungsanbieter +Name[el]=Πάροχος κοινής χρήσης +Name[en_GB]=ShareProvider +Name[es]=Compartir proveedor +Name[et]=ShareProvider +Name[eu]=Partekatze-hornitzailea +Name[fi]=ShareProvider +Name[fr]=Fournisseur de partages +Name[gl]=ShareProvider +Name[he]=ShareProvider +Name[hr]=ShareProvider +Name[hu]=ShareProvider +Name[ia]=Fornitor compartite +Name[is]=ShareProvider +Name[it]=Fornitore di condivisione +Name[ja]=ShareProvider +Name[kk]=Ортақтастыру қызметтер +Name[km]=ShareProvider +Name[ko]=ShareProvider +Name[lt]=ShareProvider +Name[lv]=ShareProvider +Name[mr]=सेवा पुरवठाकर्ता +Name[nb]=Dele-tjenester +Name[nds]=Apenmaakdeenstanbeder +Name[nl]=ShareProvider +Name[pa]=ShareProvider +Name[pl]=Dostawca udostępniania +Name[pt]=Fornecedor de Partilha +Name[pt_BR]=Provedor de compartilhamento +Name[ro]=FurnizorPartajare +Name[ru]=Служба обмена информацией +Name[sk]=Poskytovateľ zdieľania +Name[sl]=ShareProvider +Name[sr]=Добављач дељења +Name[sr@ijekavian]=Добављач дијељења +Name[sr@ijekavianlatin]=Dobavljač dijeljenja +Name[sr@latin]=Dobavljač deljenja +Name[sv]=Delningstjänst +Name[th]=ผู้ให้ใช้งานร่วมกัน +Name[tr]=SağlayıcıyıPaylaş +Name[ug]=ھەمبەھىر تەمىنلىگۈچى +Name[uk]=Служба оприлюднення +Name[wa]=Ahesseu d' pårtaedje +Name[x-test]=xxShareProviderxx +Name[zh_CN]=共享提供 +Name[zh_TW]=分享服務提供者 +Comment=Share Package Structure +Comment[ast]=Estructura Paquete Compartir +Comment[bs]=Struktura paketa dijeljenja +Comment[ca]=Estructura de paquet de compartició +Comment[ca@valencia]=Estructura de paquet de compartició +Comment[cs]=Struktura sdíleného balíčku +Comment[da]=Pakkestruktur for deling +Comment[de]=Paketstruktur bereitstellen +Comment[el]=Δομή πακέτου κοινής χρήσης +Comment[en_GB]=Share Package Structure +Comment[es]=Estructura del paquete de compartición +Comment[et]=Paketistruktuuri jagamine +Comment[eu]=Partekatze-paketearen egitura +Comment[fi]=Jaa pakettirakenne +Comment[fr]=Structure du paquet de partage +Comment[gl]=Estrutura de paquete Share +Comment[he]=Share Package Structure +Comment[hr]=Podijeli strukturu paketa +Comment[hu]=Csomagstruktúra megosztása +Comment[ia]=Share Package Structure (Structura de uso commun de pacchetto) +Comment[is]=Deila pakkauppbyggingu +Comment[it]=Struttura del pacchetto di condivisione +Comment[ja]=パッケージの構造を共有 +Comment[kk]=Ортақ дестелер құрылымы +Comment[km]=ចែករំលែក​រចនាសម្ព័ន្ធ​កញ្ចប់ +Comment[ko]=공유 패키지 구조 +Comment[lt]=Dalinimosi paketo struktūra +Comment[lv]=Kopīgot pakotnes struktūru +Comment[mr]=शेर पॅकेज संरचना +Comment[nb]=Del pakkestruktur +Comment[nds]=Paketstruktuur praatstellen +Comment[nl]=Structuur van delen van pakketten +Comment[pa]=ਪੈਕੇਜ ਢਾਂਚਾ ਸਾਂਝਾ ਕਰੋਪੈਕੇਜ ਢਾਂਚਾ ਸਾਪੈਕੇਜ ਫਪੈਕੇਜ ਟਾ +Comment[pl]=Struktura pakietu udostępniania +Comment[pt]=Estrutura do Pacote da Partilha +Comment[pt_BR]=Estrutura do pacote de compartilhamento +Comment[ro]=Partajează structura pachetului +Comment[ru]=Структура пакета с параметрами службы обмена информацией +Comment[sk]=Štruktúra balíčka pre zdieľanie +Comment[sl]=Zgradba paketa Share +Comment[sr]=Структура пакета дељења +Comment[sr@ijekavian]=Структура пакета дијељења +Comment[sr@ijekavianlatin]=Struktura paketa dijeljenja +Comment[sr@latin]=Struktura paketa deljenja +Comment[sv]=Dela paketstruktur +Comment[th]=โครงสร้างแพกเกจที่ใช้ร่วมกัน +Comment[tr]=Paket Yapısını Paylaş +Comment[ug]=ھەمبەھىر بوغچا قۇرۇلمىسى +Comment[uk]=Структура спільних пакунків +Comment[wa]=Tcherpinte do pacaedje di pårtaedje +Comment[x-test]=xxShare Package Structurexx +Comment[zh_CN]=共享包结构 +Comment[zh_TW]=分享套件結構 +Type=Service +X-KDE-ServiceTypes=Plasma/PackageStructure + +X-KDE-Library=plasma_packagestructure_share +X-KDE-PluginInfo-Author=Artur de Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Name=Plasma/ShareProvider +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-License=GPLv2+ +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-PackageFileFilter=*.share +X-Plasma-PackageFileMimetypes=application/zip diff --git a/plasma/generic/dataengines/share/data/plasma_shareprovider.desktop b/plasma/generic/dataengines/share/data/plasma_shareprovider.desktop new file mode 100644 index 00000000..a5b6bc4c --- /dev/null +++ b/plasma/generic/dataengines/share/data/plasma_shareprovider.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Plasma/ShareProvider +Comment=Plugin for Plasma Sharebin +Comment[ast]=Complementu pa Plasma Sharebin +Comment[bs]=Priključak za plazma korpu dijeljenja +Comment[ca]=Connector pel Sharebin del Plasma +Comment[ca@valencia]=Connector pel Sharebin del Plasma +Comment[cs]=Zásuvný modul pro Plasma Sharebin +Comment[da]=Plugin til Plasma Sharebin +Comment[de]=Modul für Plasma-Sharebin +Comment[el]=Πρόσθετο για το Plasma Sharebin +Comment[en_GB]=Plugin for Plasma Sharebin +Comment[es]=Complemento para Plasma Sharebin +Comment[et]=Plasma Sharebini plugin +Comment[eu]=Plasmaren Sharebin-erako plugina +Comment[fi]=Plasman Sharebin-liitännäinen +Comment[fr]=Module externe « Sharebin » pour Plasma +Comment[gl]=Extensión para o motor Sharebin de Plasma +Comment[he]=תוסף עבור Plasma Sharebin +Comment[hr]=Priključak za Plasma Sharebin +Comment[hu]=Bővítmény a Plasma Sharebinhez +Comment[ia]=Plugin pro Plasma Sharebin +Comment[is]=Íforrit fyrir Plasma Sharebin +Comment[it]=Estensione per Sharebin di Plasma +Comment[ja]=Plasma Sharebin プラグイン +Comment[kk]=Pasma ортақ дерегінің плагині +Comment[km]=កម្មវិធី​ជំនួយ​សម្រាប់​ Sharebin ប្លាស្មា +Comment[ko]=Plasma Sharebin 설정 +Comment[lt]=Plasma dalinimosi dėžės priedas +Comment[lv]=Spraudnis priekš Plasma Sharebin +Comment[mr]=प्लाज्मा शेअरबिन करिता प्लगइन +Comment[nb]=Programtillegg for Plasma Sharebin +Comment[nds]=Moduul för "Plasma-Sharebin" +Comment[nl]=Plugin voor Plasma Sharebin +Comment[pa]=ਪਲਾਜ਼ਮਾ ਸ਼ੇਅਰਬਿਨ ਲਈ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka dla Sharebin plazmy +Comment[pt]='Plugin' para o Sharebin do Plasma +Comment[pt_BR]=Plugin para o Sharebin do Plasma +Comment[ro]=Modul pentru Plasma Sharebin +Comment[ru]=Расширение для Plasma Sharebin +Comment[sk]=Modul pre Plasma Sharebin +Comment[sl]=Vstavek za Plasma Sharebin +Comment[sr]=Прикључак за плазма корпу дељења +Comment[sr@ijekavian]=Прикључак за плазма корпу дијељења +Comment[sr@ijekavianlatin]=Priključak za plasma korpu dijeljenja +Comment[sr@latin]=Priključak za plasma korpu deljenja +Comment[sv]=Insticksprogram för Plasma Sharebin +Comment[th]=ส่วนเสริมสำหรับถังขยะร่วมกันของพลาสมา +Comment[tr]=Plasma PaylaşımKutusu için Eklenti +Comment[ug]=پلازما Sharebin ئۈچۈن قىستۇرما +Comment[uk]=Додаток до спільного ресурсу Плазми +Comment[wa]=Tchôke-divins pol batch di pårtaedje di Plasma +Comment[x-test]=xxPlugin for Plasma Sharebinxx +Comment[zh_CN]=Plasma 共享插件 +Comment[zh_TW]=Plasma Sharebin 的外掛程式 + +[PropertyDef::X-KDE-PlasmaShareProvider-MimeType] +Type=QStringList + diff --git a/plasma/generic/dataengines/share/plugin_share_package.cpp b/plasma/generic/dataengines/share/plugin_share_package.cpp new file mode 100644 index 00000000..48e8745e --- /dev/null +++ b/plasma/generic/dataengines/share/plugin_share_package.cpp @@ -0,0 +1,23 @@ +/*************************************************************************** + * Copyright 2009 Artur Duque de Souza * + * * + * 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 "plasma/package.h" +#include "share_package.h" + +K_EXPORT_PLASMA_PACKAGESTRUCTURE(share, SharePackage) diff --git a/plasma/generic/dataengines/share/share.operations b/plasma/generic/dataengines/share/share.operations new file mode 100644 index 00000000..ed828444 --- /dev/null +++ b/plasma/generic/dataengines/share/share.operations @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/plasma/generic/dataengines/share/share_package.cpp b/plasma/generic/dataengines/share/share_package.cpp new file mode 100644 index 00000000..8b9d2c1d --- /dev/null +++ b/plasma/generic/dataengines/share/share_package.cpp @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright 2010 Artur Duque de Souza * + * * + * 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 "plasma/applet.h" +#include "plasma/package.h" + +#include "share_package.h" + + +SharePackage::SharePackage(QObject *parent, QVariantList args) + : Plasma::PackageStructure(parent, "Plasma/ShareProvider") +{ + Q_UNUSED(args) + + addDirectoryDefinition("scripts", "code", i18n("Executable Scripts")); + QStringList mimetypes; + mimetypes << "text/*"; + setMimetypes( "scripts", mimetypes ); + + addFileDefinition("mainscript", "code/main.js", i18n("Main Script File")); + setDefaultPackageRoot("plasma/shareprovider/"); + setServicePrefix("plasma-share-"); +} + diff --git a/plasma/generic/dataengines/share/share_package.h b/plasma/generic/dataengines/share/share_package.h new file mode 100644 index 00000000..821db4e4 --- /dev/null +++ b/plasma/generic/dataengines/share/share_package.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * Copyright 2010 Artur Duque de Souza * + * * + * 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 SHARE_PACKAGE_H +#define SHARE_PACKAGE_H + +#include + +class SharePackage : public Plasma::PackageStructure +{ +public: + explicit SharePackage(QObject *parent = 0, QVariantList args = QVariantList()); +}; + +#endif diff --git a/plasma/generic/dataengines/share/shareengine.cpp b/plasma/generic/dataengines/share/shareengine.cpp new file mode 100644 index 00000000..c60db1da --- /dev/null +++ b/plasma/generic/dataengines/share/shareengine.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright 2010 Artur Duque de Souza * + * * + * 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 + +#include "shareengine.h" +#include "shareservice.h" + + +ShareEngine::ShareEngine(QObject *parent, const QVariantList &args) + : Plasma::DataEngine(parent, args) +{ + Q_UNUSED(args); +} + +void ShareEngine::init() +{ + connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), + this, SLOT(updatePlugins(QStringList))); + updatePlugins(QStringList() << "services"); +} + +void ShareEngine::updatePlugins(const QStringList &changes) +{ + if (!changes.contains("services")) { + return; + } + + removeAllSources(); + + KService::List services = KServiceTypeTrader::self()->query("Plasma/ShareProvider"); + QMultiMap sortedServices; + foreach (KService::Ptr service, services) { + sortedServices.insert(service->property("X-KDE-Priority").toInt(), service); + } + + QMapIterator it(sortedServices); + it.toBack(); + QHash mimetypes; + while (it.hasPrevious()) { + it.previous(); + KService::Ptr service = it.value(); + const QString pluginName = + service->property("X-KDE-PluginInfo-Name", QVariant::String).toString(); + + const QStringList pluginMimeTypes = + service->property("X-KDE-PlasmaShareProvider-MimeType", QVariant::StringList).toStringList(); + + const QString storageId = service->storageId(); + + if (pluginName.isEmpty() || pluginMimeTypes.isEmpty()) { + continue; + } + + // create the list of providers + Plasma::DataEngine::Data data; + data.insert("Name", service->name()); + data.insert("Service Id", service->storageId()); + data.insert("Mimetypes", pluginMimeTypes); + setData(pluginName, data); + + // create the list of providers by type + foreach (const QString &pluginMimeType, pluginMimeTypes) { + mimetypes[pluginMimeType].append(pluginName); + } + } + + + QHashIterator it2(mimetypes); + while (it2.hasNext()) { + it2.next(); + setData("Mimetypes", it2.key(), it2.value()); + } +} + +Plasma::Service *ShareEngine::serviceForSource(const QString &source) +{ + Plasma::DataContainer *data = containerForSource(source); + + if (!data) { + return Plasma::DataEngine::serviceForSource(source); + } + + if (source.compare("mimetype", Qt::CaseInsensitive) == 0) { + return Plasma::DataEngine::serviceForSource(source); + } + + const QString id = data->data().value("Service Id").toString(); + if (id.isEmpty()) { + return Plasma::DataEngine::serviceForSource(source); + } + + ShareService *service = new ShareService(this); + service->setDestination(id); + return service; +} + +#include "shareengine.moc" + +K_EXPORT_PLASMA_DATAENGINE(share, ShareEngine) diff --git a/plasma/generic/dataengines/share/shareengine.h b/plasma/generic/dataengines/share/shareengine.h new file mode 100644 index 00000000..4cedc862 --- /dev/null +++ b/plasma/generic/dataengines/share/shareengine.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright 2010 Artur Duque de Souza * + * * + * 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 SHARE_ENGINE_H +#define SHARE_ENGINE_H + +#include +#include + +class ShareService; + +class ShareEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + ShareEngine(QObject *parent, const QVariantList &args); + void init(); + Plasma::Service *serviceForSource(const QString &source); + +private Q_SLOTS: + void updatePlugins(const QStringList &changes); + +private: + friend class ShareService; +}; + +#endif // SHARE_ENGINE diff --git a/plasma/generic/dataengines/share/shareprovider.cpp b/plasma/generic/dataengines/share/shareprovider.cpp new file mode 100644 index 00000000..b5e8f4d7 --- /dev/null +++ b/plasma/generic/dataengines/share/shareprovider.cpp @@ -0,0 +1,348 @@ +/*************************************************************************** + * Copyright 2010 Artur Duque de Souza * + * * + * 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 +#include +#include + +#include "shareprovider.h" +#include "share_package.h" + +Plasma::PackageStructure::Ptr ShareProvider::m_packageStructure(0); + + +ShareProvider::ShareProvider(QObject *parent) + : QObject(parent), m_isBlob(false), m_isPost(true) +{ + // Just make the boundary random part long enough to be sure + // it's not inside one of the arguments that we are sending + m_boundary = "----------"; + m_boundary += KRandom::randomString(55).toAscii(); +} + +QString ShareProvider::method() const +{ + if (!m_isPost) { + return QString("GET"); + } + return QString("POST"); +} + +void ShareProvider::setMethod(const QString &method) +{ + if (method == "GET") { + m_isPost = false; + } else { + m_isPost = true; + } +} + +KUrl ShareProvider::url() const +{ + // the url that is set in this provider + return m_url; +} + +void ShareProvider::setUrl(const QString &url) +{ + // set the provider's url + m_url = url; + m_service = url; +} + +QString ShareProvider::parseXML(const QString &key, const QString &data) +{ + // this method helps plugins to parse results from webpages + QXmlStreamReader xml(data); + if (xml.hasError()) { + return QString(); + } + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.name() == key) { + QString url = xml.readElementText(); + return url; + } + } + + return QString(); +} + +void ShareProvider::addPostItem(const QString &key, const QString &value, + const QString &contentType) +{ + if (!m_isPost) + return; + + // add a pair in a post form + QByteArray str; + QString length = QString("%1").arg(value.length()); + + str += "--"; + str += m_boundary; + str += "\r\n"; + + if (!key.isEmpty()) { + str += "Content-Disposition: form-data; name=\""; + str += key.toAscii(); + str += "\"\r\n"; + } + + if (!contentType.isEmpty()) { + str += "Content-Type: " + QByteArray(contentType.toAscii()); + str += "\r\n"; + str += "Mime-version: 1.0 "; + str += "\r\n"; + } + + str += "Content-Length: "; + str += length.toAscii(); + str += "\r\n\r\n"; + str += value.toUtf8(); + + m_buffer.append(str); + m_buffer.append("\r\n"); +} + +void ShareProvider::addPostFile(const QString &contentKey, const QString &content) +{ + // add a file in a post form (gets it using KIO) + m_contentKey = contentKey; + m_content = content; + + // we expect either text or an URL of a file. The file can be a text file + // that is an exception that we handle in this case. So we have basically + // three use cases: + // 1 - just text + // 2 - a file that is a text + // 3 - other kind of files (images, pdf, etc..) + // + // The applet using this engine must ensure that the provider selected + // supports the file format that is added here as a parameter, otherwise + // it will return as an error later in the process. + KUrl url(m_content); + + KIO::MimetypeJob *mjob = KIO::mimetype(url, KIO::HideProgressInfo); + connect(mjob, SIGNAL(finished(KJob*)), this, SLOT(mimetypeJobFinished(KJob*))); +} + +void ShareProvider::mimetypeJobFinished(KJob *job) +{ + KIO::MimetypeJob *mjob = qobject_cast(job); + if (!job) { + return; + } + + if (mjob->error()) { + // it's not a file - usually this happens when we are + // just sharing plain text, so add the content and publish it + addPostItem(m_contentKey, m_content, "text/plain"); + addQueryItem(m_contentKey, m_content); + emit readyToPublish(); + return; + } + + // It's a valid file because there were no errors + m_mimetype = mjob->mimetype(); + if (m_mimetype.isEmpty()) { + // if we ourselves can't determine the mime of the file, + // very unlikely the remote site will be able to identify it + error(i18n("Could not detect the file's mimetype")); + return; + } + + // If it's not text then we should handle it later + if (m_mimetype.indexOf("text/") != 0) + m_isBlob = true; + + // try to open the file + KIO::FileJob *fjob = KIO::open(KUrl(m_content), QIODevice::ReadOnly); + connect(fjob, SIGNAL(open(KIO::Job*)), this, SLOT(openFile(KIO::Job*))); +} + +void ShareProvider::openFile(KIO::Job *job) +{ + // finished opening the file, now try to read it's content + KIO::FileJob *fjob = static_cast(job); + fjob->read(fjob->size()); + connect(fjob, SIGNAL(data(KIO::Job*,QByteArray)), + this, SLOT(finishedContentData(KIO::Job*,QByteArray))); +} + +void ShareProvider::finishedContentData(KIO::Job *job, const QByteArray &data) +{ + // Close the job as we don't need it anymore. + // NOTE: this is essential to ensure the job gets de-scheduled and deleted! + job->disconnect(this); + static_cast(job)->close(); + + if (data.length() == 0) { + error(i18n("It was not possible to read the selected file")); + return; + } + + if (!m_isBlob) { + // it's just text and we can return here using data() + addPostItem(m_contentKey, QString::fromLocal8Bit(data), "text/plain"); + addQueryItem(m_contentKey, QString::fromLocal8Bit(data)); + emit readyToPublish(); + return; + } + + // Add the special http post stuff with the content of the file + QByteArray str; + const QString fileSize = QString("%1").arg(data.size()); + str += "--"; + str += m_boundary; + str += "\r\n"; + str += "Content-Disposition: form-data; name=\""; + str += m_contentKey.toAscii(); + str += "\"; "; + str += "filename=\""; + str += QFile::encodeName(KUrl(m_content).fileName()).replace(".tmp", ".jpg"); + str += "\"\r\n"; + str += "Content-Length: "; + str += fileSize.toAscii(); + str += "\r\n"; + str += "Content-Type: "; + str += m_mimetype.toAscii(); + str += "\r\n\r\n"; + + m_buffer.append(str); + m_buffer.append(data); + m_buffer.append("\r\n"); + + // tell the world that we are ready to publish + emit readyToPublish(); +} + +void ShareProvider::readPublishData(KIO::Job *job, const QByteArray &data) +{ + Q_UNUSED(job); + m_data.append(data); +} + +void ShareProvider::finishedPublish(KJob *job) +{ + Q_UNUSED(job); + if (m_data.length() == 0) { + error(i18n("Service was not available")); + return; + } + + // process data. should be interpreted by the plugin. + // plugin must call the right slots after processing the data. + emit handleResultData(QString(m_data)); +} + +void ShareProvider::finishHeader() +{ + QByteArray str; + str += "--"; + str += m_boundary; + str += "--"; + m_buffer.append(str); +} + +void ShareProvider::addQueryItem(const QString &key, const QString &value) +{ + // just add the item to the query's URL + m_url.addQueryItem(key, value); +} + +void ShareProvider::publish() +{ + if (m_url == "") { + emit finishedError(i18n("You must specify a URL for this service")); + } + + // clear the result data before publishing + m_data.clear(); + + // finish the http form + if (m_isBlob) { + finishHeader(); + } + + // Multipart is used to upload files + KIO::TransferJob *tf; + if (m_isBlob) { + tf = KIO::http_post(m_service, m_buffer, KIO::HideProgressInfo); + tf->addMetaData("content-type","Content-Type: multipart/form-data; boundary=" + m_boundary); + } else { + if (m_isPost) { + tf = KIO::http_post(m_service, + m_url.encodedQuery(), KIO::HideProgressInfo); + tf->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded"); + } else { + QString url = QString("%1?%2").arg(m_service.url(), QString(m_url.encodedQuery())); + tf = KIO::get(url); + } + } + + connect(tf, SIGNAL(data(KIO::Job*,QByteArray)), + this, SLOT(readPublishData(KIO::Job*,QByteArray))); + connect(tf, SIGNAL(result(KJob*)), this, SLOT(finishedPublish(KJob*))); + connect(tf, SIGNAL(redirection(KIO::Job*,KUrl)), + this, SLOT(redirected(KIO::Job*,KUrl))); +} + +void ShareProvider::redirected(KIO::Job *job, const KUrl &to) +{ + Q_UNUSED(job) + const QUrl toUrl(to); + const QUrl serviceUrl(m_service); + + const QString toString(toUrl.toString(QUrl::StripTrailingSlash)); + const QString serviceString(serviceUrl.toString(QUrl::StripTrailingSlash)); + + if (toString == serviceString) { + return; + } + + emit handleRedirection(toString); +} + +void ShareProvider::success(const QString &url) +{ + // notify the service that it worked and the result url + emit finished(url); +} + +void ShareProvider::error(const QString &msg) +{ + // notify the service that it didnt work and the error msg + emit finishedError(msg); +} + +Plasma::PackageStructure::Ptr ShareProvider::packageStructure() +{ + if (!m_packageStructure) { + m_packageStructure = new SharePackage(); + } + return m_packageStructure; +} + +#include "shareprovider.moc" diff --git a/plasma/generic/dataengines/share/shareprovider.h b/plasma/generic/dataengines/share/shareprovider.h new file mode 100644 index 00000000..319716c8 --- /dev/null +++ b/plasma/generic/dataengines/share/shareprovider.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright 2010 Artur Duque de Souza * + * * + * 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 SHAREPROVIDER_H +#define SHAREPROVIDER_H + +#include +#include +#include + +#include + + +class ShareProvider : public QObject +{ + Q_OBJECT + +public: + ShareProvider(QObject *parent =0); + static Plasma::PackageStructure::Ptr packageStructure(); + + QString method() const; + void setMethod(const QString &method); + + KUrl url() const; + void setUrl(const QString &url); + + void addPostFile(const QString &contentKey, const QString &content); + +Q_SIGNALS: + void handleResultData(QString data); + void handleRedirection(const QString &url); + void readyToPublish(); + void finished(const QString &url); + void finishedError(const QString &msg); + +public Q_SLOTS: + // ###: Function to return the content so the plugin can + // play with it before publishing? + + // helper methods + void publish(); + QString parseXML(const QString &key, const QString &data); + void addQueryItem(const QString &key, const QString &value); + void addPostItem(const QString &key, const QString &value, + const QString &contentType); + + // result methods + void success(const QString &url); + void error(const QString &msg); + void redirected(KIO::Job *job, const KUrl &from); + +protected Q_SLOTS: + // slots for kio + void mimetypeJobFinished(KJob *job); + void openFile(KIO::Job *job); + void finishedContentData(KIO::Job *job, const QByteArray &data); + void finishedPublish(KJob *job); + void readPublishData(KIO::Job *job, const QByteArray &data); + +protected: + void finishHeader(); + +private: + QString m_content; + QString m_contentKey; + QString m_mimetype; + + bool m_isBlob; + bool m_isPost; + + KUrl m_url; + KUrl m_service; + + QByteArray m_data; + QByteArray m_buffer; + QByteArray m_boundary; + + static Plasma::PackageStructure::Ptr m_packageStructure; +}; + +#endif // SHAREPROVIDER diff --git a/plasma/generic/dataengines/share/shareservice.cpp b/plasma/generic/dataengines/share/shareservice.cpp new file mode 100644 index 00000000..6aec7434 --- /dev/null +++ b/plasma/generic/dataengines/share/shareservice.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + * Copyright 2010 Artur Duque de Souza * + * * + * 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 +#include + +#include + +#include "shareservice.h" +#include "shareprovider.h" + + +ShareService::ShareService(ShareEngine *engine) + : Plasma::Service(engine) +{ + setName("share"); +} + +Plasma::ServiceJob *ShareService::createJob(const QString &operation, + QMap ¶meters) +{ + return new ShareJob(destination(), operation, parameters, this); +} + +ShareJob::ShareJob(const QString &destination, const QString &operation, + QMap ¶meters, QObject *parent) + : Plasma::ServiceJob(destination, operation, parameters, parent), + m_action(0), m_provider(0), m_package(0) +{ +} + +ShareJob::~ShareJob() +{ + delete m_action; + delete m_provider; + delete m_package; +} + +void ShareJob::start() +{ + //KService::Ptr service = KService::serviceByStorageId("plasma-share-pastebincom.desktop"); + KService::Ptr service = KService::serviceByStorageId(destination()); + if (!service) { + showError(i18n("Could not find the provider with the specified destination")); + return; + } + + QString pluginName = + service->property("X-KDE-PluginInfo-Name", QVariant::String).toString(); + + const QString path = + KStandardDirs::locate("data", "plasma/shareprovider/" + pluginName + '/' ); + + if (path.isEmpty()) { + showError(i18n("Invalid path for the requested provider")); + return; + } + + m_package = new Plasma::Package(path, ShareProvider::packageStructure()); + if (m_package->isValid()) { + const QString mainscript = + m_package->path() + m_package->structure()->contentsPrefixPaths().at(0) + + m_package->structure()->path("mainscript"); + + if (!QFile::exists(mainscript)) { + showError(i18n("Selected provider does not have a valid script file")); + return; + } + + const QString interpreter = + Kross::Manager::self().interpreternameForFile(mainscript); + + if (interpreter.isEmpty()) { + showError(i18n("Selected provider does not provide a supported script file")); + return; + } + + m_action = new Kross::Action(parent(), pluginName); + if (m_action) { + m_provider = new ShareProvider(this); + connect(m_provider, SIGNAL(readyToPublish()), this, SLOT(publish())); + connect(m_provider, SIGNAL(finished(QString)), + this, SLOT(showResult(QString))); + connect(m_provider, SIGNAL(finishedError(QString)), + this, SLOT(showError(QString))); + + // automatically connects signals and slots with the script + m_action->addObject(m_provider, "provider", + Kross::ChildrenInterface::AutoConnectSignals); + + // set the main script file and load it + m_action->setFile(mainscript); + m_action->trigger(); + + // check for any errors + if(m_action->hadError()) { + showError(i18n("Error trying to execute script")); + return; + } + + // do the work together with the loaded plugin + const QStringList functions = m_action->functionNames(); + if (!functions.contains("url") || !functions.contains("contentKey") || + !functions.contains("setup")) { + showError(i18n("Could not find all required functions")); + return; + } + + // call the methods from the plugin + const QString url = + m_action->callFunction("url", QVariantList()).toString(); + m_provider->setUrl(url); + + // setup the method (get/post) + QVariant vmethod; + if (functions.contains("method")) { + vmethod = + m_action->callFunction("method", QVariantList()).toString(); + } + + // default is POST (if the plugin does not specify one method) + const QString method = vmethod.isValid() ? vmethod.toString() : "POST"; + m_provider->setMethod(method); + + // setup the provider + QVariant setup = m_action->callFunction("setup", QVariantList()); + + // get the content from the parameters, set the url and add the file + // then we can wait the signal to publish the information + const QString contentKey = + m_action->callFunction("contentKey", QVariantList()).toString(); + + const QString content(parameters()["content"].toString()); + m_provider->addPostFile(contentKey, content); + } + } +} + +void ShareJob::publish() +{ + m_provider->publish(); +} + +void ShareJob::showResult(const QString &url) +{ + setResult(url); +} + +void ShareJob::showError(const QString &message) +{ + QString errorMsg = message; + if (errorMsg.isEmpty()) { + errorMsg = i18n("Unknown Error"); + } + + setError(1); + setErrorText(message); + emitResult(); +} + +#include "shareservice.moc" diff --git a/plasma/generic/dataengines/share/shareservice.h b/plasma/generic/dataengines/share/shareservice.h new file mode 100644 index 00000000..aa075911 --- /dev/null +++ b/plasma/generic/dataengines/share/shareservice.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright 2010 Artur Duque de Souza * + * * + * 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 SHARE_SERVICE_H +#define SHARE_SERVICE_H + +#include "shareengine.h" + +#include +#include + +class ShareProvider; + +namespace Plasma { + class ServiceJob; + class Package; +} + +namespace Kross { + class Action; +} + +class ShareService : public Plasma::Service +{ + Q_OBJECT + +public: + ShareService(ShareEngine *engine); + Plasma::ServiceJob *createJob(const QString &operation, + QMap ¶meters); +}; + +class ShareJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + ShareJob(const QString &destination, const QString &operation, + QMap ¶meters, QObject *parent = 0); + ~ShareJob(); + void start(); + +public slots: + void publish(); + void showResult(const QString &url); + void showError(const QString &msg); + +private: + Kross::Action *m_action; + ShareProvider *m_provider; + Plasma::Package *m_package; +}; + +#endif // SHARE_SERVICE diff --git a/plasma/generic/dataengines/soliddevice/CMakeLists.txt b/plasma/generic/dataengines/soliddevice/CMakeLists.txt new file mode 100644 index 00000000..7e0ff39b --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/CMakeLists.txt @@ -0,0 +1,16 @@ +set(soliddevice_engine_SRCS + soliddeviceengine.cpp + devicesignalmapper.cpp + devicesignalmapmanager.cpp + hddtemp.cpp + soliddeviceservice.cpp + soliddevicejob.cpp +) + +kde4_add_plugin(plasma_engine_soliddevice ${soliddevice_engine_SRCS}) +target_link_libraries(plasma_engine_soliddevice ${KDE4_KDECORE_LIBS} ${KDE4_SOLID_LIBS} ${QT_QTNETWORK_LIBRARY} ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBRARY}) + +install(TARGETS plasma_engine_soliddevice DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-soliddevice.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install(FILES soliddevice.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services ) + diff --git a/plasma/generic/dataengines/soliddevice/Messages.sh b/plasma/generic/dataengines/soliddevice/Messages.sh new file mode 100755 index 00000000..ea6e6f04 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT `find . -name \*.cpp` -o $podir/plasma_engine_soliddevice.pot diff --git a/plasma/generic/dataengines/soliddevice/devicesignalmapmanager.cpp b/plasma/generic/dataengines/soliddevice/devicesignalmapmanager.cpp new file mode 100644 index 00000000..102ce805 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/devicesignalmapmanager.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007 Christopher Blauvelt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "devicesignalmapmanager.h" + +DeviceSignalMapManager::DeviceSignalMapManager(QObject *parent) : QObject(parent) +{ + user = parent; +} + +DeviceSignalMapManager::~DeviceSignalMapManager() +{ +} + +void DeviceSignalMapManager::mapDevice(Solid::AcAdapter *ac, const QString &udi) +{ + AcAdapterSignalMapper *map=0; + if (!signalmap.contains(Solid::DeviceInterface::AcAdapter)) { + map = new AcAdapterSignalMapper(this); + signalmap[Solid::DeviceInterface::AcAdapter] = map; + connect(map, SIGNAL(deviceChanged(QString,QString,QVariant)), user, SLOT(deviceChanged(QString,QString,QVariant))); + } else { + map = (AcAdapterSignalMapper*)signalmap[Solid::DeviceInterface::AcAdapter]; + } + + connect(ac, SIGNAL(plugStateChanged(bool,QString)), map, SLOT(plugStateChanged(bool))); + map->setMapping(ac, udi); +} + +void DeviceSignalMapManager::mapDevice(Solid::Button *button, const QString &udi) +{ + ButtonSignalMapper *map=0; + if (!signalmap.contains(Solid::DeviceInterface::Button)) { + map = new ButtonSignalMapper(this); + signalmap[Solid::DeviceInterface::Button] = map; + connect(map, SIGNAL(deviceChanged(QString,QString,QVariant)), user, SLOT(deviceChanged(QString,QString,QVariant))); + } else { + map = (ButtonSignalMapper*)signalmap[Solid::DeviceInterface::Button]; + } + + connect(button, SIGNAL(pressed(Solid::Button::ButtonType,QString)), map, SLOT(pressed(Solid::Button::ButtonType))); + map->setMapping(button, udi); +} + +void DeviceSignalMapManager::mapDevice(Solid::Battery *battery, const QString &udi) +{ + BatterySignalMapper *map=0; + if (!signalmap.contains(Solid::DeviceInterface::Battery)) { + map = new BatterySignalMapper(this); + signalmap[Solid::DeviceInterface::Battery] = map; + connect(map, SIGNAL(deviceChanged(QString,QString,QVariant)), user, SLOT(deviceChanged(QString,QString,QVariant))); + } else { + map = (BatterySignalMapper*)signalmap[Solid::DeviceInterface::Battery]; + } + + connect(battery, SIGNAL(chargePercentChanged(int,QString)), map, SLOT(chargePercentChanged(int))); + connect(battery, SIGNAL(chargeStateChanged(int,QString)), map, SLOT(chargeStateChanged(int))); + connect(battery, SIGNAL(plugStateChanged(bool,QString)), map, SLOT(plugStateChanged(bool))); + map->setMapping(battery, udi); +} + +void DeviceSignalMapManager::mapDevice(Solid::StorageAccess *storageaccess, const QString &udi) +{ + StorageAccessSignalMapper *map=0; + if (!signalmap.contains(Solid::DeviceInterface::StorageAccess)) { + map = new StorageAccessSignalMapper(this); + signalmap[Solid::DeviceInterface::StorageAccess] = map; + connect(map, SIGNAL(deviceChanged(QString,QString,QVariant)), user, SLOT(deviceChanged(QString,QString,QVariant))); + } else { + map = (StorageAccessSignalMapper*)signalmap[Solid::DeviceInterface::StorageAccess]; + } + + connect(storageaccess, SIGNAL(accessibilityChanged(bool,QString)), map, SLOT(accessibilityChanged(bool))); + map->setMapping(storageaccess, udi); +} + +void DeviceSignalMapManager::unmapDevice(Solid::AcAdapter *ac) +{ + AcAdapterSignalMapper *map = (AcAdapterSignalMapper*)signalmap.value(Solid::DeviceInterface::AcAdapter); + if (!map) { + return; + } + + disconnect(ac, SIGNAL(plugStateChanged(bool,QString)), map, SLOT(plugStateChanged(bool))); + disconnect(map, SIGNAL(deviceChanged(QString,QString,QVariant)), user, SLOT(deviceChanged(QString,QString,QVariant))); +} + +void DeviceSignalMapManager::unmapDevice(Solid::Button *button) +{ + ButtonSignalMapper *map = (ButtonSignalMapper*)signalmap.value(Solid::DeviceInterface::Button); + if (!map) { + return; + } + + disconnect(button, SIGNAL(pressed(Solid::Button::ButtonType,QString)), map, SLOT(pressed(Solid::Button::ButtonType))); +} + +void DeviceSignalMapManager::unmapDevice(Solid::Battery *battery) +{ + BatterySignalMapper *map = (BatterySignalMapper*)signalmap.value(Solid::DeviceInterface::Battery); + if (!map) { + return; + } + + disconnect(battery, SIGNAL(chargePercentChanged(int,QString)), map, SLOT(chargePercentChanged(int))); + disconnect(battery, SIGNAL(chargeStateChanged(int,QString)), map, SLOT(chargeStateChanged(int))); + disconnect(battery, SIGNAL(plugStateChanged(bool,QString)), map, SLOT(plugStateChanged(bool))); +} + +void DeviceSignalMapManager::unmapDevice(Solid::StorageAccess *storageaccess) +{ + StorageAccessSignalMapper *map = (StorageAccessSignalMapper*)signalmap.value(Solid::DeviceInterface::StorageAccess); + if (!map) { + return; + } + + disconnect(storageaccess, SIGNAL(accessibilityChanged(bool,QString)), map, SLOT(accessibilityChanged(bool))); +} + +#include "devicesignalmapmanager.moc" diff --git a/plasma/generic/dataengines/soliddevice/devicesignalmapmanager.h b/plasma/generic/dataengines/soliddevice/devicesignalmapmanager.h new file mode 100644 index 00000000..5762a1fb --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/devicesignalmapmanager.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007 Christopher Blauvelt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DEVICE_SIGNALMAP_MANAGER_H +#define DEVICE_SIGNALMAP_MANAGER_H + +#include + +#include "devicesignalmapper.h" + +class DeviceSignalMapManager : public QObject +{ + Q_OBJECT + + public: + DeviceSignalMapManager(QObject *parent=0); + ~DeviceSignalMapManager(); + + void mapDevice(Solid::AcAdapter *ac, const QString &udi); + void mapDevice(Solid::Button *button, const QString &udi); + void mapDevice(Solid::Battery *battery, const QString &udi); + void mapDevice(Solid::StorageAccess *storageaccess, const QString &udi); + + void unmapDevice(Solid::AcAdapter *ac); + void unmapDevice(Solid::Button *button); + void unmapDevice(Solid::Battery *battery); + void unmapDevice(Solid::StorageAccess *storageaccess); + + private: + QMap signalmap; + QObject *user; +}; + +#endif diff --git a/plasma/generic/dataengines/soliddevice/devicesignalmapper.cpp b/plasma/generic/dataengines/soliddevice/devicesignalmapper.cpp new file mode 100644 index 00000000..fde7cc35 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/devicesignalmapper.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2007 Christopher Blauvelt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "devicesignalmapper.h" + +DeviceSignalMapper::DeviceSignalMapper(QObject *parent) : QSignalMapper(parent) +{ +} + +DeviceSignalMapper::~DeviceSignalMapper() +{ +} + +void DeviceSignalMapper::setMapping(QObject* device, const QString &udi) +{ + signalmap[device] = udi; +} + +AcAdapterSignalMapper::AcAdapterSignalMapper(QObject *parent) : DeviceSignalMapper(parent) +{ +} + +AcAdapterSignalMapper::~AcAdapterSignalMapper() +{ +} + +void AcAdapterSignalMapper::plugStateChanged(bool newState) +{ + emit(deviceChanged(signalmap[sender()], "Plugged In", newState)); +} + + +ButtonSignalMapper::ButtonSignalMapper(QObject *parent) : DeviceSignalMapper(parent) +{ +} + +ButtonSignalMapper::~ButtonSignalMapper() +{ +} + +void ButtonSignalMapper::pressed(Solid::Button::ButtonType type) +{ + Q_UNUSED(type) + emit(deviceChanged(signalmap[sender()], "Pressed", true)); +} + +BatterySignalMapper::BatterySignalMapper(QObject *parent) : DeviceSignalMapper(parent) +{ +} + +BatterySignalMapper::~BatterySignalMapper() +{ +} + +void BatterySignalMapper::chargePercentChanged(int value) +{ + emit(deviceChanged(signalmap[sender()], "Charge Percent", value)); +} + +void BatterySignalMapper::chargeStateChanged(int newState) +{ + QStringList chargestate; + chargestate << "Fully Charged" << "Charging" << "Discharging"; + emit(deviceChanged(signalmap[sender()], "Charge State", chargestate.at(newState))); +} + +void BatterySignalMapper::plugStateChanged(bool newState) +{ + emit(deviceChanged(signalmap[sender()], "Plugged In", newState)); +} + +StorageAccessSignalMapper::StorageAccessSignalMapper(QObject *parent) : DeviceSignalMapper(parent) +{ +} + +StorageAccessSignalMapper::~StorageAccessSignalMapper() +{ +} + +void StorageAccessSignalMapper::accessibilityChanged(bool accessible) +{ + emit(deviceChanged(signalmap[sender()], "Accessible", accessible)); +} + +#include "devicesignalmapper.moc" diff --git a/plasma/generic/dataengines/soliddevice/devicesignalmapper.h b/plasma/generic/dataengines/soliddevice/devicesignalmapper.h new file mode 100644 index 00000000..e7467474 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/devicesignalmapper.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2007 Christopher Blauvelt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DEVICE_SIGNAL_MAPPER_H +#define DEVICE_SIGNAL_MAPPER_H + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class DeviceSignalMapper : public QSignalMapper +{ + Q_OBJECT + + public: + DeviceSignalMapper(QObject *parent=0); + ~DeviceSignalMapper(); + + void setMapping(QObject* device, const QString &udi); + + Q_SIGNALS: + void deviceChanged(const QString& udi, const QString &property, QVariant value); + + protected: + QMap signalmap; +}; + +class AcAdapterSignalMapper : public DeviceSignalMapper +{ + Q_OBJECT + + public: + AcAdapterSignalMapper(QObject *parent=0); + ~AcAdapterSignalMapper(); + + public Q_SLOTS: + void plugStateChanged(bool newState); +}; + +class ButtonSignalMapper : public DeviceSignalMapper +{ + Q_OBJECT + + public: + ButtonSignalMapper(QObject *parent=0); + ~ButtonSignalMapper(); + + public Q_SLOTS: + void pressed(Solid::Button::ButtonType type); +}; + +class BatterySignalMapper : public DeviceSignalMapper +{ + Q_OBJECT + + public: + BatterySignalMapper(QObject *parent=0); + ~BatterySignalMapper(); + + public Q_SLOTS: + void chargePercentChanged(int value); + void chargeStateChanged(int newState); + void plugStateChanged(bool newState); +}; + +class StorageAccessSignalMapper : public DeviceSignalMapper +{ + Q_OBJECT + + public: + StorageAccessSignalMapper(QObject *parent=0); + ~StorageAccessSignalMapper(); + + public Q_SLOTS: + void accessibilityChanged(bool accessible); +}; + +#endif diff --git a/plasma/generic/dataengines/soliddevice/hddtemp.cpp b/plasma/generic/dataengines/soliddevice/hddtemp.cpp new file mode 100644 index 00000000..f2fee2f2 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/hddtemp.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007 Petri Damsten + * Copyright (C) 2007 Christopher Blauvelt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "hddtemp.h" + +#include + +#include + +#include + +HddTemp::HddTemp(QObject* parent) + : QObject(parent), + m_failCount(0), + m_cacheValid(false) +{ + updateData(); +} + +HddTemp::~HddTemp() +{ +} + +QStringList HddTemp::sources() +{ + updateData(); + return m_data.keys(); +} + +void HddTemp::timerEvent(QTimerEvent *event) +{ + killTimer(event->timerId()); + m_cacheValid = false; +} + +bool HddTemp::updateData() +{ + if (m_cacheValid) { + return true; + } + + if (m_failCount > 4) { + return false; + } + + QTcpSocket socket; + QString data; + + socket.connectToHost("localhost", 7634); + if (socket.waitForConnected(500)) { + while (data.length() < 1024) { + if (!socket.waitForReadyRead(500)) { + if (data.length() > 0) { + break; + } else { + //kDebug() << socket.errorString(); + return false; + } + } + data += QString(socket.readAll()); + } + socket.disconnectFromHost(); + //on success retry fail count + m_failCount = 0; + } else { + m_failCount++; + //kDebug() << socket.errorString(); + return false; + } + const QStringList list = data.split('|'); + int i = 1; + m_data.clear(); + while (i + 4 < list.size()) { + m_data[list[i]].append(list[i + 2]); + m_data[list[i]].append(list[i + 3]); + i += 5; + } + m_cacheValid = true; + startTimer(0); + + return true; +} + +QVariant HddTemp::data(const QString source, const DataType type) const +{ + return m_data[source][type]; +} + +#include "hddtemp.moc" diff --git a/plasma/generic/dataengines/soliddevice/hddtemp.h b/plasma/generic/dataengines/soliddevice/hddtemp.h new file mode 100644 index 00000000..ea372ea1 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/hddtemp.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007 Petri Damsten + * Copyright (C) 2007 Christopher Blauvelt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef HDDTEMP_H +#define HDDTEMP_H + +#include +#include +#include +#include +#include +#include + + +class HddTemp : public QObject +{ + Q_OBJECT + + public: + enum DataType {Temperature=0, Unit}; + + HddTemp(QObject *parent=0); + ~HddTemp(); + QStringList sources(); + QVariant data(const QString source, const DataType type) const; + + protected: + void timerEvent(QTimerEvent *event); + + private: + int m_failCount; + bool m_cacheValid; + QMap > m_data; + bool updateData(); +}; + + +#endif diff --git a/plasma/generic/dataengines/soliddevice/plasma-dataengine-soliddevice.desktop b/plasma/generic/dataengines/soliddevice/plasma-dataengine-soliddevice.desktop new file mode 100644 index 00000000..bbed0e6e --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/plasma-dataengine-soliddevice.desktop @@ -0,0 +1,159 @@ +[Desktop Entry] +Name=Device Information +Name[ar]=معلومات الأجهزة +Name[ast]=Información del preséu +Name[be@latin]=Źviestki z pryłady +Name[bg]=Данни за устройства +Name[bn]=ডিভাইস তথ্য +Name[bn_IN]=ডিভাইস সংক্রান্ত তথ্য +Name[bs]=podaci o uređajima +Name[ca]=Informació dels dispositius +Name[ca@valencia]=Informació dels dispositius +Name[cs]=Informace o zařízení +Name[csb]=Wëdowiédzô ò ùrządzeniach +Name[da]=Enhedsinformation +Name[de]=Geräteinformationen +Name[el]=Πληροφορίες συσκευής +Name[en_GB]=Device Information +Name[eo]=Aparataj Informoj +Name[es]=Información del dispositivo +Name[et]=Seadmete teave +Name[eu]=Gailuari buruzko informazioa +Name[fi]=Laitetiedot +Name[fr]=Informations sur les périphériques +Name[fy]=Apparaatynformaasje +Name[ga]=Eolas faoi Ghléas +Name[gl]=Información do dispositivo +Name[gu]=ઉપકરણ માહિતી +Name[he]=מידע על התקנים +Name[hi]=उपकरण जानकारी +Name[hne]=उपकरन जानकारी +Name[hr]=Podaci o uređaju +Name[hu]=Eszközjellemzők +Name[ia]=Information de dispositivo +Name[id]=Informasi Divais +Name[is]=Upplýsingar tækis +Name[it]=Informazioni sui dispositivi +Name[ja]=デバイス情報 +Name[kk]=Құрылғы мәліметі +Name[km]=ព័ត៌មាន​ឧបករណ៍ +Name[kn]=ಸಾಧನದ ಮಾಹಿತಿ +Name[ko]=장치 정보 +Name[ku]=Agahiya Cîhazê +Name[lt]=Informacija apie įrenginius +Name[lv]=Ierīču informācija +Name[mai]=डिवायस सूचना +Name[mk]=Информации за уреди +Name[ml]=ഉപകരണ വിവരം +Name[mr]=साधन माहिती +Name[nb]=Enhetsinformasjon +Name[nds]=Reedschap-Informatschonen +Name[nl]=Apparaatinformatie +Name[nn]=Einingsinformasjon +Name[or]=ଯନ୍ତ୍ର ସୂଚନା +Name[pa]=ਜੰਤਰ ਜਾਣਕਾਰੀ +Name[pl]=Informacje o urządzeniach +Name[pt]=Informação dos Dispositivos +Name[pt_BR]=Informações do dispositivo +Name[ro]=Informații dispozitiv +Name[ru]=Сведения об устройствах +Name[si]=මෙවලම් තොරතුරු +Name[sk]=Informácie o zariadení +Name[sl]=Podatki o napravah +Name[sr]=подаци о уређајима +Name[sr@ijekavian]=подаци о уређајима +Name[sr@ijekavianlatin]=podaci o uređajima +Name[sr@latin]=podaci o uređajima +Name[sv]=Enhetsinformation +Name[ta]=Device Information +Name[tg]=Иттилооти дастгоҳ +Name[th]=รายละเอียดอุปกรณ์ +Name[tr]=Aygıt Bilgileri +Name[ug]=ئۈسكۈنە ئۇچۇرى +Name[uk]=Інформація про пристрої +Name[vi]=Thông tin thiết bị +Name[wa]=Informåcions so l' éndjin +Name[x-test]=xxDevice Informationxx +Name[zh_CN]=设备信息 +Name[zh_TW]=裝置資訊 +Comment=Device data via Solid +Comment[ar]=بيانات الأجهزة عن طريق سوليد +Comment[ast]=Datos de preséu vía Solid +Comment[bg]=Данни за устройствата (чрез Solid) +Comment[bs]=Podaci o uređajima preko Solida +Comment[ca]=Dades dels dispositius via Solid +Comment[ca@valencia]=Dades dels dispositius via Solid +Comment[cs]=Data zařízení pomocí Solid +Comment[csb]=Pòdôwczi ùrządzeniów z pòmòcą Solid +Comment[da]=Enhedsdata via Solid +Comment[de]=Gerätedaten mittels Solid +Comment[el]=Δεδομένα συσκευών μέσω Solid +Comment[en_GB]=Device data via Solid +Comment[es]=Datos de dispositivo vía Solid +Comment[et]=Seadmete andmed Solidi vahendusel +Comment[eu]=Gailuen datuak Solid bidez +Comment[fi]=Laitetietoja Solid-rajapinnalta +Comment[fr]=Données de périphériques utilisant Solid +Comment[fy]=Àpparaatgegevens fia Solid +Comment[ga]=Eolas faoi ghléas trí Solid +Comment[gl]=Datos do dispositivo mediante Solid +Comment[gu]=સોલિડ વડે ઉપકરણ માહિતી +Comment[he]=מידע אודות התקן באמצעות Solid +Comment[hr]=Podaci o uređajima preko Solida +Comment[hu]=Eszközjellemzők a Solid alrendszerből +Comment[ia]=Datos de dispositivos via Solid +Comment[id]=Data divais via Solid +Comment[is]=Vélbúnaðarupplýsingar með Solid +Comment[it]=Dati sui dispositivi con Solid +Comment[ja]=Solid によるデバイスデータ +Comment[kk]=Solid құрылғы деректері +Comment[km]=ទិន្នន័យ​ឧបករណ៍តាម​រយៈ Solid​ +Comment[kn]=ಸಾಲಿಡ್‌ನ ಮೂಲಕ ಸಾಧನ ದತ್ತಾಂಶ +Comment[ko]=Solid를 통한 장치 데이터 +Comment[lt]=Solid įrenginių duomenys +Comment[lv]=Ierīču dati no Solid +Comment[mai]=सालिड सँ युक्ति आंकड़ा +Comment[mk]=Податоци за уреди преку Солид +Comment[ml]=സോളിഡ് നല്‍കുന്ന ഉപകരണങ്ങളെക്കുറിച്ചുള്ള ഡാറ്റ +Comment[mr]=सॉलिड कडून साधन माहिती +Comment[nb]=Enhetsdata via Solid +Comment[nds]=Reedschapdaten över Solid +Comment[nl]=Apparaatgegevens via Solid +Comment[nn]=SolidDevice-data +Comment[pa]=ਜੰਤਰ ਡਾਟਾ ਸਾਲਡ ਵਜੋਂ +Comment[pl]=Dane urządzenia przez Solid +Comment[pt]=Dados dos dispositivos através do Solid +Comment[pt_BR]=Dados do dispositivo através do Solid +Comment[ro]=Date despre dispozitive via Solid +Comment[ru]=Сведения об устройствах от Solid +Comment[si]=Solid වෙතින් උපකරණ දත්ත +Comment[sk]=Dáta zariadenia pomocou Solid +Comment[sl]=Podatki o napravah s pomočjo Solid +Comment[sr]=Подаци о уређајима преко Солида +Comment[sr@ijekavian]=Подаци о уређајима преко Солида +Comment[sr@ijekavianlatin]=Podaci o uređajima preko Solida +Comment[sr@latin]=Podaci o uređajima preko Solida +Comment[sv]=Enhetsdata via Solid +Comment[tg]=Данные SolidDevice для плазмоидов +Comment[th]=ข้อมูลของอุปกรณ์ผ่านทาง Solid +Comment[tr]=Solid üzerinden aygıt verisi +Comment[ug]=Solid ئارقىلىق ئۈسكۈنە سانلىق-مەلۇماتىغا ئېرىشىدۇ +Comment[uk]=Дані щодо пристроїв з Solid +Comment[vi]=Thiết bị dữ liệu qua Solid +Comment[wa]=Dinêyes di l' éndjin avou Solid +Comment[x-test]=xxDevice data via Solidxx +Comment[zh_CN]=通过 Solid 获得设备数据 +Comment[zh_TW]=透過 Solid 的裝置資料 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=drive-harddisk +X-KDE-Library=plasma_engine_soliddevice + +X-KDE-PluginInfo-Author=The Plasma Team +X-KDE-PluginInfo-Email=wilderkde@gmail.com +X-KDE-PluginInfo-Name=soliddevice +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/soliddevice/soliddevice.operations b/plasma/generic/dataengines/soliddevice/soliddevice.operations new file mode 100644 index 00000000..49d8c471 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/soliddevice.operations @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/soliddevice/soliddeviceengine.cpp b/plasma/generic/dataengines/soliddevice/soliddeviceengine.cpp new file mode 100644 index 00000000..b788fd66 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/soliddeviceengine.cpp @@ -0,0 +1,806 @@ +/* + * Copyright (C) 2007 Christopher Blauvelt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "soliddeviceengine.h" +#include "soliddeviceservice.h" + +#include +#include +#include + +#include +#include +#include + +#include + +//TODO: implement in libsolid2 +namespace +{ + template DevIface *getAncestorAs(const Solid::Device &device) + { + for (Solid::Device parent = device.parent(); + parent.isValid(); + parent = parent.parent()) { + if (parent.is()) { + return parent.as(); + } + } + return NULL; + } +} + +SolidDeviceEngine::SolidDeviceEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args), + m_temperature(0), + m_notifier(0) +{ + Q_UNUSED(args) + m_signalmanager = new DeviceSignalMapManager(this); + + listenForNewDevices(); + setMinimumPollingInterval(1000); + connect(this, SIGNAL(sourceRemoved(QString)), + this, SLOT(sourceWasRemoved(QString))); +} + +SolidDeviceEngine::~SolidDeviceEngine() +{ +} + +Plasma::Service* SolidDeviceEngine::serviceForSource(const QString& source) +{ + return new SolidDeviceService (this, source); +} + +void SolidDeviceEngine::listenForNewDevices() +{ + if (m_notifier) { + return; + } + + //detect when new devices are added + m_notifier = Solid::DeviceNotifier::instance(); + connect(m_notifier, SIGNAL(deviceAdded(QString)), + this, SLOT(deviceAdded(QString))); + connect(m_notifier, SIGNAL(deviceRemoved(QString)), + this, SLOT(deviceRemoved(QString))); +} + +bool SolidDeviceEngine::sourceRequestEvent(const QString &name) +{ + if (name.startsWith('/')) { + Solid::Device device = Solid::Device(name); + if (device.isValid()) { + if (m_devicemap.contains(name) ) { + return true; + } else { + m_devicemap[name] = device; + return populateDeviceData(name); + } + } + } else { + Solid::Predicate predicate = Solid::Predicate::fromString(name); + if (predicate.isValid() && !m_predicatemap.contains(name)) { + foreach (const Solid::Device &device, Solid::Device::listFromQuery(predicate)) { + m_predicatemap[name] << device.udi(); + } + + setData(name, m_predicatemap[name]); + return true; + } + } + + kDebug() << "Source is not a predicate or a device."; + return false; +} + +void SolidDeviceEngine::sourceWasRemoved(const QString &source) +{ + m_devicemap.remove(source); + m_predicatemap.remove(source); +} + +bool SolidDeviceEngine::populateDeviceData(const QString &name) +{ + Solid::Device device = m_devicemap.value(name); + if (!device.isValid()) { + return false; + } + + QStringList devicetypes; + setData(name, I18N_NOOP("Parent UDI"), device.parentUdi()); + setData(name, I18N_NOOP("Vendor"), device.vendor()); + setData(name, I18N_NOOP("Product"), device.product()); + setData(name, I18N_NOOP("Description"), device.description()); + setData(name, I18N_NOOP("Icon"), device.icon()); + setData(name, I18N_NOOP("Emblems"), device.emblems()); + setData(name, I18N_NOOP("State"), Idle); + setData(name, I18N_NOOP("Operation result"), Working); + setData(name, I18N_NOOP("Timestamp"), QDateTime::currentDateTime()); + + if (device.is()) { + Solid::Processor *processor = device.as(); + if (!processor) { + return false; + } + + devicetypes << I18N_NOOP("Processor"); + setData(name, I18N_NOOP("Number"), processor->number()); + setData(name, I18N_NOOP("Max Speed"), processor->maxSpeed()); + setData(name, I18N_NOOP("Can Change Frequency"), processor->canChangeFrequency()); + } + if (device.is()) { + Solid::Block *block = device.as(); + if (!block) { + return false; + } + + devicetypes << I18N_NOOP("Block"); + setData(name, I18N_NOOP("Major"), block->deviceMajor()); + setData(name, I18N_NOOP("Minor"), block->deviceMajor()); + setData(name, I18N_NOOP("Device"), block->device()); + } + if (device.is()) { + Solid::StorageAccess *storageaccess = device.as(); + if (!storageaccess) { + return false; + } + + devicetypes << I18N_NOOP("Storage Access"); + setData(name, I18N_NOOP("Accessible"), storageaccess->isAccessible()); + setData(name, I18N_NOOP("File Path"), storageaccess->filePath()); + + if (storageaccess->isAccessible()) { + QVariant freeDiskVar; + qulonglong freeDisk = freeDiskSpace(storageaccess->filePath()); + if ( freeDisk != (qulonglong)-1 ) { + freeDiskVar.setValue( freeDisk ); + } + if (!device.is()) { + setData(name, I18N_NOOP("Free Space"), freeDiskVar ); + setData(name, I18N_NOOP("Free Space Text"), KGlobal::locale()->formatByteSize(freeDisk)); + } + } + + m_signalmanager->mapDevice(storageaccess, device.udi()); + } + + if (device.is()) { + Solid::StorageDrive *storagedrive = device.as(); + if (!storagedrive) { + return false; + } + + devicetypes << I18N_NOOP("Storage Drive"); + + QStringList bus; + bus << I18N_NOOP("Ide") << I18N_NOOP("Usb") << I18N_NOOP("Ieee1394") << I18N_NOOP("Scsi") << I18N_NOOP("Sata") << I18N_NOOP("Platform"); + QStringList drivetype; + drivetype << I18N_NOOP("Hard Disk") << I18N_NOOP("Cdrom Drive") << I18N_NOOP("Floppy") << I18N_NOOP("Tape") << I18N_NOOP("Compact Flash") << I18N_NOOP("Memory Stick") << I18N_NOOP("Smart Media") << I18N_NOOP("SdMmc") << I18N_NOOP("Xd"); + + setData(name, I18N_NOOP("Bus"), bus.at((int)storagedrive->bus())); + setData(name, I18N_NOOP("Drive Type"), drivetype.at((int)storagedrive->driveType())); + setData(name, I18N_NOOP("Removable"), storagedrive->isRemovable()); + setData(name, I18N_NOOP("Hotpluggable"), storagedrive->isHotpluggable()); + + updateHardDiskTemperature(name); + } + else { + bool isRemovable = false; + bool isHotpluggable = false; + Solid::StorageDrive *drive = getAncestorAs(device); + if (drive) { + //remove check for isHotpluggable() when plasmoids are changed to check for both properties + isRemovable = (drive->isRemovable() || drive->isHotpluggable()); + isHotpluggable = drive->isHotpluggable(); + } + setData(name, I18N_NOOP("Removable"), isRemovable); + setData(name, I18N_NOOP("Hotpluggable"), isHotpluggable); + } + + + if (device.is()) { + Solid::OpticalDrive *opticaldrive = device.as(); + if (!opticaldrive) { + return false; + } + + devicetypes << I18N_NOOP("Optical Drive"); + + QStringList supportedtypes; + Solid::OpticalDrive::MediumTypes mediatypes = opticaldrive->supportedMedia(); + if (mediatypes & Solid::OpticalDrive::Cdr) { + supportedtypes << I18N_NOOP("CD-R"); + } + if (mediatypes & Solid::OpticalDrive::Cdrw) { + supportedtypes << I18N_NOOP("CD-RW"); + } + if (mediatypes & Solid::OpticalDrive::Dvd) { + supportedtypes << I18N_NOOP("DVD"); + } + if (mediatypes & Solid::OpticalDrive::Dvdr) { + supportedtypes << I18N_NOOP("DVD-R"); + } + if (mediatypes & Solid::OpticalDrive::Dvdrw) { + supportedtypes << I18N_NOOP("DVD-RW"); + } + if (mediatypes & Solid::OpticalDrive::Dvdram) { + supportedtypes << I18N_NOOP("DVD-RAM"); + } + if (mediatypes & Solid::OpticalDrive::Dvdplusr) { + supportedtypes << I18N_NOOP("DVD+R"); + } + if (mediatypes & Solid::OpticalDrive::Dvdplusrw) { + supportedtypes << I18N_NOOP("DVD+RW"); + } + if (mediatypes & Solid::OpticalDrive::Dvdplusdl) { + supportedtypes << I18N_NOOP("DVD+DL"); + } + if (mediatypes & Solid::OpticalDrive::Dvdplusdlrw) { + supportedtypes << I18N_NOOP("DVD+DLRW"); + } + if (mediatypes & Solid::OpticalDrive::Bd) { + supportedtypes << I18N_NOOP("BD"); + } + if (mediatypes & Solid::OpticalDrive::Bdr) { + supportedtypes << I18N_NOOP("BD-R"); + } + if (mediatypes & Solid::OpticalDrive::Bdre) { + supportedtypes << I18N_NOOP("BD-RE"); + } + if (mediatypes & Solid::OpticalDrive::HdDvd) { + supportedtypes << I18N_NOOP("HDDVD"); + } + if (mediatypes & Solid::OpticalDrive::HdDvdr) { + supportedtypes << I18N_NOOP("HDDVD-R"); + } + if (mediatypes & Solid::OpticalDrive::HdDvdrw) { + supportedtypes << I18N_NOOP("HDDVD-RW"); + } + setData(name, I18N_NOOP("Supported Media"), supportedtypes); + + setData(name, I18N_NOOP("Read Speed"), opticaldrive->readSpeed()); + setData(name, I18N_NOOP("Write Speed"), opticaldrive->writeSpeed()); + + //the following method return QList so we need to convert it to QList + QList writespeeds = opticaldrive->writeSpeeds(); + QList variantlist = QList(); + foreach(int num, writespeeds) { + variantlist << QVariant(num); + } + setData(name, I18N_NOOP("Write Speeds"), variantlist); + + } + if (device.is()) { + Solid::StorageVolume *storagevolume = device.as(); + if (!storagevolume) { + return false; + } + + devicetypes << I18N_NOOP("Storage Volume"); + + QStringList usagetypes; + usagetypes << i18n("Other") << i18n("Unused") << i18n("File System") + << i18n("Partition Table") << i18n("Raid") << i18n("Encrypted"); + + if (usagetypes.count() > storagevolume->usage()) { + setData(name, I18N_NOOP("Usage"), usagetypes.at((int)storagevolume->usage())); + } else { + setData(name, I18N_NOOP("Usage"), i18n("Unknown")); + } + + setData(name, I18N_NOOP("Ignored"), storagevolume->isIgnored()); + setData(name, I18N_NOOP("File System Type"), storagevolume->fsType()); + setData(name, I18N_NOOP("Label"), storagevolume->label()); + setData(name, I18N_NOOP("UUID"), storagevolume->uuid()); + setData(name, I18N_NOOP("Size"), storagevolume->size()); + updateInUse(name); + + //Check if the volume is part of an encrypted container + //This needs to trigger an update for the encrypted container volume since + //libsolid cannot notify us when the accessibility of the container changes + Solid::Device encryptedContainer = storagevolume->encryptedContainer(); + if (encryptedContainer.isValid()) { + QString containerUdi = encryptedContainer.udi(); + setData(name, I18N_NOOP("Encrypted Container"), containerUdi); + m_encryptedContainerMap[name] = containerUdi; + //TODO: compress the calls? + forceUpdateAccessibility(containerUdi); + } + } + if (device.is()) { + Solid::OpticalDisc *opticaldisc = device.as(); + if (!opticaldisc) { + return false; + } + + devicetypes << I18N_NOOP("OpticalDisc"); + + //get the content types + QStringList contenttypelist; + Solid::OpticalDisc::ContentTypes contenttypes = opticaldisc->availableContent(); + if (contenttypes & Solid::OpticalDisc::Audio) { + contenttypelist << I18N_NOOP("Audio"); + } + if (contenttypes & Solid::OpticalDisc::Audio) { + contenttypelist << I18N_NOOP("Data"); + } + if (contenttypes & Solid::OpticalDisc::Audio) { + contenttypelist << I18N_NOOP("Video CD"); + } + if (contenttypes & Solid::OpticalDisc::Audio) { + contenttypelist << I18N_NOOP("Super Video CD"); + } + if (contenttypes & Solid::OpticalDisc::Audio) { + contenttypelist << I18N_NOOP("Video DVD"); + } + setData(name, I18N_NOOP("Available Content"), contenttypelist); + + QStringList disctypes; + disctypes << I18N_NOOP("Unknown Disc Type") << I18N_NOOP("CD Rom") << I18N_NOOP("CD Recordable") + << I18N_NOOP("CD Rewritable") << I18N_NOOP("DVD Rom") << I18N_NOOP("DVD Ram") + << I18N_NOOP("DVD Recordable") << I18N_NOOP("DVD Rewritable") << I18N_NOOP("DVD Plus Recordable") + << I18N_NOOP("DVD Plus Rewritable") << I18N_NOOP("DVD Plus Recordable Duallayer") + << I18N_NOOP("DVD Plus Rewritable Duallayer") << I18N_NOOP("Blu Ray Rom") << I18N_NOOP("Blu Ray Recordable") + << I18N_NOOP("Blu Ray Rewritable") << I18N_NOOP("HD DVD Rom") << I18N_NOOP("HD DVD Recordable") + << I18N_NOOP("HD DVD Rewritable"); + //+1 because the enum starts at -1 + setData(name, I18N_NOOP("Disc Type"), disctypes.at((int)opticaldisc->discType() + 1)); + setData(name, I18N_NOOP("Appendable"), opticaldisc->isAppendable()); + setData(name, I18N_NOOP("Blank"), opticaldisc->isBlank()); + setData(name, I18N_NOOP("Rewritable"), opticaldisc->isRewritable()); + setData(name, I18N_NOOP("Capacity"), opticaldisc->capacity()); + } + if (device.is()) { + Solid::Camera *camera = device.as(); + if (!camera) { + return false; + } + + devicetypes << I18N_NOOP("Camera"); + + setData(name, I18N_NOOP("Supported Protocols"), camera->supportedProtocols()); + setData(name, I18N_NOOP("Supported Drivers"), camera->supportedDrivers()); + // Cameras are necessarily Removable and Hotpluggable + setData(name, I18N_NOOP("Removable"), true); + setData(name, I18N_NOOP("Hotpluggable"), true); + + } + if (device.is()) { + Solid::PortableMediaPlayer *mediaplayer = device.as(); + if (!mediaplayer) { + return false; + } + + devicetypes << I18N_NOOP("Portable Media Player"); + + setData(name, I18N_NOOP("Supported Protocols"), mediaplayer->supportedProtocols()); + setData(name, I18N_NOOP("Supported Drivers"), mediaplayer->supportedDrivers()); + // Portable Media Players are necessarily Removable and Hotpluggable + setData(name, I18N_NOOP("Removable"), true); + setData(name, I18N_NOOP("Hotpluggable"), true); + + } + if (device.is()) { + Solid::NetworkInterface *networkinterface = device.as(); + if (!networkinterface) { + return false; + } + + devicetypes << I18N_NOOP("Network Interface"); + + setData(name, I18N_NOOP("Interface Name"), networkinterface->ifaceName()); + setData(name, I18N_NOOP("Wireless"), networkinterface->isWireless()); + setData(name, I18N_NOOP("Hardware Address"), networkinterface->hwAddress()); + setData(name, I18N_NOOP("MAC Address"), networkinterface->macAddress()); + } + if (device.is()) { + Solid::AcAdapter *ac = device.as(); + if (!ac) { + return false; + } + + devicetypes << I18N_NOOP("AC Adapter"); + + setData(name, I18N_NOOP("Plugged In"), ac->isPlugged()); + m_signalmanager->mapDevice(ac, device.udi()); + } + if (device.is()) { + Solid::Battery *battery = device.as(); + if (!battery) { + return false; + } + + devicetypes << I18N_NOOP("Battery"); + + QStringList batterytype; + batterytype << I18N_NOOP("Unknown Battery") << I18N_NOOP("PDA Battery") << I18N_NOOP("UPS Battery") + << I18N_NOOP("Primary Battery") << I18N_NOOP("Mouse Battery") << I18N_NOOP("Keyboard Battery") + << I18N_NOOP("Keyboard Mouse Battery") << I18N_NOOP("Camera Battery"); + + QStringList chargestate; + chargestate << I18N_NOOP("Fully Charged") << I18N_NOOP("Charging") << I18N_NOOP("Discharging"); + + setData(name, I18N_NOOP("Plugged In"), battery->isPlugged()); + setData(name, I18N_NOOP("Type"), batterytype.at((int)battery->type())); + setData(name, I18N_NOOP("Charge Percent"), battery->chargePercent()); + setData(name, I18N_NOOP("Rechargeable"), battery->isRechargeable()); + setData(name, I18N_NOOP("Charge State"), chargestate.at((int)battery->chargeState())); + + m_signalmanager->mapDevice(battery, device.udi()); + } + if (device.is()) { + Solid::Button *button = device.as(); + if (!button) { + return false; + } + + devicetypes << I18N_NOOP("Button"); + + QStringList buttontype; + buttontype << I18N_NOOP("Lid Button") << I18N_NOOP("Power Button") << I18N_NOOP("Sleep Button") + << I18N_NOOP("Unknown Button Type"); + + setData(name, I18N_NOOP("Type"), buttontype.at((int)button->type())); + setData(name, I18N_NOOP("Has State"), button->hasState()); + setData(name, I18N_NOOP("State Value"), button->stateValue()); + setData(name, I18N_NOOP("Pressed"), false); //this is an extra value that is tracked by the button signals + + m_signalmanager->mapDevice(button, device.udi()); + } + if (device.is()) { + Solid::AudioInterface *audiointerface = device.as(); + if (!audiointerface) { + return false; + } + + devicetypes << I18N_NOOP("Audio Interface"); + + QStringList audiodriver; + audiodriver << I18N_NOOP("ALSA") << I18N_NOOP("Open Sound System") << I18N_NOOP("Unknown Audio Driver"); + + setData(name, I18N_NOOP("Driver"), audiodriver.at((int)audiointerface->driver())); + setData(name, I18N_NOOP("Driver Handle"), audiointerface->driverHandle()); + setData(name, I18N_NOOP("Name"), audiointerface->name()); + + //get AudioInterfaceTypes + QStringList audiointerfacetypes; + Solid::AudioInterface::AudioInterfaceTypes devicetypes = audiointerface->deviceType(); + if (devicetypes & Solid::AudioInterface::UnknownAudioInterfaceType) { + audiointerfacetypes << I18N_NOOP("Unknown Audio Interface Type"); + } + if (devicetypes & Solid::AudioInterface::AudioControl) { + audiointerfacetypes << I18N_NOOP("Audio Control"); + } + if (devicetypes & Solid::AudioInterface::AudioInput) { + audiointerfacetypes << I18N_NOOP("Audio Input"); + } + if (devicetypes & Solid::AudioInterface::AudioOutput) { + audiointerfacetypes << I18N_NOOP("Audio Output"); + } + setData(name, I18N_NOOP("Audio Device Type"), audiointerfacetypes); + + //get SoundCardTypes + QStringList soundcardtype; + soundcardtype << I18N_NOOP("Internal Soundcard") << I18N_NOOP("USB Soundcard") << I18N_NOOP("Firewire Soundcard") + << I18N_NOOP("Headset") << I18N_NOOP("Modem"); + setData(name, I18N_NOOP("Soundcard Type"), soundcardtype.at((int)audiointerface->soundcardType())); + } + if (device.is()) { + Solid::DvbInterface *dvbinterface = device.as(); + if (!dvbinterface) { + return false; + } + + devicetypes << I18N_NOOP("DVB Interface"); + + setData(name, I18N_NOOP("Device"), dvbinterface->device()); + setData(name, I18N_NOOP("Device Adapter"), dvbinterface->deviceAdapter()); + + //get devicetypes + QStringList dvbdevicetypes; + dvbdevicetypes << I18N_NOOP("DVB Unknown") << I18N_NOOP("DVB Audio") << I18N_NOOP("DVB Ca") + << I18N_NOOP("DVB Demux") << I18N_NOOP("DVB DVR") << I18N_NOOP("DVB Frontend") + << I18N_NOOP("DVB Net") << I18N_NOOP("DVB OSD") << I18N_NOOP("DVB Sec") << I18N_NOOP("DVB Video"); + + setData(name, I18N_NOOP("DVB Device Type"), dvbdevicetypes.at((int)dvbinterface->deviceType())); + setData(name, I18N_NOOP("Device Index"), dvbinterface->deviceIndex()); + } + if (device.is()) { + Solid::Video *video = device.as(); + if (!video) { + return false; + } + + devicetypes << I18N_NOOP("Video"); + + setData(name, I18N_NOOP("Supported Protocols"), video->supportedProtocols()); + setData(name, I18N_NOOP("Supported Drivers"), video->supportedDrivers()); + + QStringList handles; + foreach (const QString &driver, video->supportedDrivers()) { + handles << video->driverHandle(driver).toString(); + } + setData(name, I18N_NOOP("Driver Handles"), handles); + } + + int index = Solid::DeviceInterface::staticMetaObject.indexOfEnumerator("Type"); + QMetaEnum typeEnum = Solid::DeviceInterface::staticMetaObject.enumerator(index); + for (int i = typeEnum.keyCount() - 1 ; i > 0; i--) { + Solid::DeviceInterface::Type type = (Solid::DeviceInterface::Type)typeEnum.value(i); + const Solid::DeviceInterface *interface = device.asDeviceInterface(type); + if (interface) { + setData(name, I18N_NOOP("Type Description"), Solid::DeviceInterface::typeDescription(type)); + break; + } + } + + setData(name, I18N_NOOP("Device Types"), devicetypes); + return true; +} + +void SolidDeviceEngine::deviceAdded(const QString& udi) +{ + Solid::Device device(udi); + + foreach (const QString &query, m_predicatemap.keys()) { + Solid::Predicate predicate = Solid::Predicate::fromString(query); + if (predicate.matches(device)) { + m_predicatemap[query] << udi; + setData(query, m_predicatemap[query]); + } + } + + if (device.is()) { + Solid::OpticalDrive *drive = getAncestorAs(device); + if (drive) { + connect(drive, SIGNAL(ejectRequested(QString)), + this, SLOT(setUnmountingState(QString))); + connect(drive, SIGNAL(ejectDone(Solid::ErrorType,QVariant,QString)), + this, SLOT(setIdleState(Solid::ErrorType,QVariant,QString))); + } + } + else if (device.is()) { + // update the volume in case of 2-stage devices + if (m_devicemap.contains(udi) && query(udi).value(I18N_NOOP("Size")).toULongLong() == 0) { + Solid::GenericInterface * iface = device.as(); + if (iface) { + iface->setProperty("udi", udi); + connect(iface, SIGNAL(propertyChanged(QMap)), + this, SLOT(deviceChanged(QMap))); + } + } + + Solid::StorageAccess *access = device.as(); + if (access) { + connect(access, SIGNAL(setupRequested(QString)), + this, SLOT(setMountingState(QString))); + connect(access, SIGNAL(setupDone(Solid::ErrorType,QVariant,QString)), + this, SLOT(setIdleState(Solid::ErrorType,QVariant,QString))); + connect(access, SIGNAL(teardownRequested(QString)), + this, SLOT(setUnmountingState(QString))); + connect(access, SIGNAL(teardownDone(Solid::ErrorType,QVariant,QString)), + this, SLOT(setIdleState(Solid::ErrorType,QVariant,QString))); + } + } +} + +void SolidDeviceEngine::setMountingState(const QString &udi) +{ + setData(udi, I18N_NOOP("State"), Mounting); + setData(udi, I18N_NOOP("Operation result"), Working); +} + +void SolidDeviceEngine::setUnmountingState(const QString &udi) +{ + setData(udi, I18N_NOOP("State"), Unmounting); + setData(udi, I18N_NOOP("Operation result"), Working); +} + +void SolidDeviceEngine::setIdleState(Solid::ErrorType error, QVariant errorData, const QString &udi) +{ + Q_UNUSED(errorData) + + if (error == Solid::NoError) { + setData(udi, I18N_NOOP("Operation result"), Successful); + } else { + setData(udi, I18N_NOOP("Operation result"), Unsuccessful); + } + setData(udi, I18N_NOOP("State"), Idle); + + Solid::Device device = m_devicemap.value(udi); + if (!device.isValid()) { + return; + } + + Solid::StorageAccess *storageaccess = device.as(); + if (!storageaccess) { + return; + } + + setData(udi, I18N_NOOP("Accessible"), storageaccess->isAccessible()); + setData(udi, I18N_NOOP("File Path"), storageaccess->filePath()); +} + +void SolidDeviceEngine::deviceChanged(const QMap &props) +{ + Solid::GenericInterface * iface = qobject_cast(sender()); + if (iface && iface->isValid() && props.contains("Size") && iface->property("Size").toInt() > 0) { + const QString udi = qobject_cast(iface)->property("udi").toString(); + if (populateDeviceData(udi)) + forceImmediateUpdateOfAllVisualizations(); + } +} + +qulonglong SolidDeviceEngine::freeDiskSpace(const QString &mountPoint) +{ + KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); + if (info.isValid()) { + return info.available(); + } + return (qulonglong)-1; +} + +bool SolidDeviceEngine::updateFreeSpace(const QString &udi) +{ + Solid::Device device = m_devicemap.value(udi); + if (!device.is() || device.is()) { + return false; + } else if (!device.as()->isAccessible()) { + removeData(udi, I18N_NOOP("Free Space")); + removeData(udi, I18N_NOOP("Free Space Text")); + } + + Solid::StorageAccess *storageaccess = device.as(); + if (!storageaccess) { + return false; + } + + QVariant freeSpaceVar; + qulonglong freeSpace = freeDiskSpace(storageaccess->filePath()); + if (freeSpace != (qulonglong)-1) { + freeSpaceVar.setValue( freeSpace ); + } + setData(udi, I18N_NOOP("Free Space"), freeSpaceVar ); + setData(udi, I18N_NOOP("Free Space Text"), KGlobal::locale()->formatByteSize(freeSpace)); + return true; +} + +bool SolidDeviceEngine::updateHardDiskTemperature(const QString &udi) +{ + Solid::Device device = m_devicemap.value(udi); + Solid::Block *block = device.as(); + if (!block) { + return false; + } + + if (!m_temperature) { + m_temperature = new HddTemp(this); + } + + if (m_temperature->sources().contains(block->device())) { + setData(udi, I18N_NOOP("Temperature"), m_temperature->data(block->device(), HddTemp::Temperature)); + setData(udi, I18N_NOOP("Temperature Unit"), m_temperature->data(block->device(), HddTemp::Unit)); + return true; + } + + return false; +} + +bool SolidDeviceEngine::updateEmblems(const QString &udi) +{ + Solid::Device device = m_devicemap.value(udi); + + setData(udi, I18N_NOOP("Emblems"), device.emblems() ); + return true; +} + +bool SolidDeviceEngine::forceUpdateAccessibility(const QString &udi) +{ + Solid::Device device = m_devicemap.value(udi); + if (!device.isValid()) { + return false; + } + + updateEmblems(udi); + Solid::StorageAccess *storageaccess = device.as(); + if (storageaccess) { + setData(udi, I18N_NOOP("Accessible"), storageaccess->isAccessible()); + } + + return true; +} + +bool SolidDeviceEngine::updateInUse(const QString &udi) +{ + Solid::Device device = m_devicemap.value(udi); + if (!device.isValid()) { + return false; + } + + Solid::StorageAccess *storageaccess = device.as(); + if (!storageaccess) { + return false; + } + + if (storageaccess->isAccessible()) { + setData(udi, I18N_NOOP("In Use"), true); + } else { + Solid::StorageDrive *drive = getAncestorAs(Solid::Device(udi)); + if (drive) { + setData(udi, I18N_NOOP("In Use"), drive->isInUse()); + } + } + + return true; +} + +bool SolidDeviceEngine::updateSourceEvent(const QString& source) +{ + bool update1 = updateFreeSpace(source); + bool update2 = updateHardDiskTemperature(source); + bool update3 = updateEmblems(source); + bool update4 = updateInUse(source); + + return (update1 || update2 || update3 || update4); +} + +void SolidDeviceEngine::deviceRemoved(const QString& udi) +{ + //libsolid cannot notify us when an encrypted container is closed, + //hence we trigger an update when a device contained in an encrypted container device dies + QString containerUdi = m_encryptedContainerMap.value(udi, QString()); + + if (!containerUdi.isEmpty()) { + forceUpdateAccessibility(containerUdi); + m_encryptedContainerMap.remove(udi); + } + + foreach (const QString &query, m_predicatemap.keys()) { + m_predicatemap[query].removeAll(udi); + setData(query, m_predicatemap[query]); + } + + Solid::Device device(udi); + if (device.is()) { + Solid::StorageAccess *access = device.as(); + if (access) { + disconnect(access, 0, this, 0); + } + } + else if (device.is()) { + Solid::OpticalDrive *drive = getAncestorAs(device); + if (drive) { + disconnect(drive, 0, this, 0); + } + } + + m_devicemap.remove(udi); + removeSource(udi); +} + +void SolidDeviceEngine::deviceChanged(const QString& udi, const QString &property, const QVariant &value) +{ + setData(udi, property, value); + updateSourceEvent(udi); +} + +K_EXPORT_PLASMA_DATAENGINE(soliddevice, SolidDeviceEngine) + +#include "soliddeviceengine.moc" diff --git a/plasma/generic/dataengines/soliddevice/soliddeviceengine.h b/plasma/generic/dataengines/soliddevice/soliddeviceengine.h new file mode 100644 index 00000000..85bdc68d --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/soliddeviceengine.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2007 Christopher Blauvelt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SOLIDDEVICEENGINE_H +#define SOLIDDEVICEENGINE_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "devicesignalmapmanager.h" +#include "devicesignalmapper.h" +#include "hddtemp.h" + +enum State { + Idle = 0, + Mounting = 1, + Unmounting = 2 +}; + +enum OperationResult { + Working = 0, + Successful = 1, + Unsuccessful =2 +}; + +/** + * This class evaluates the basic expressions given in the interface. + */ +class SolidDeviceEngine : public Plasma::DataEngine +{ + Q_OBJECT + friend class SolidDeviceService; + +public: + SolidDeviceEngine( QObject* parent, const QVariantList& args); + ~SolidDeviceEngine(); + Plasma::Service *serviceForSource (const QString& source); + +protected: + bool sourceRequestEvent(const QString &name); + bool updateSourceEvent(const QString& source); + +private: + bool populateDeviceData(const QString &name); + qulonglong freeDiskSpace(const QString &mountPoint); + bool updateFreeSpace(const QString &udi); + bool updateHardDiskTemperature(const QString &udi); + bool updateEmblems(const QString &udi); + bool updateInUse(const QString &udi); + bool forceUpdateAccessibility(const QString &udi); + void listenForNewDevices(); + + //predicate in string form, list of devices by udi + QMap m_predicatemap; + //udi, corresponding device + QMap m_devicemap; + //udi, corresponding encrypted container udi; + QMap m_encryptedContainerMap; + DeviceSignalMapManager *m_signalmanager; + + HddTemp *m_temperature; + Solid::DeviceNotifier *m_notifier; + +private Q_SLOTS: + void deviceAdded(const QString &udi); + void deviceRemoved(const QString &udi); + void deviceChanged(const QString& udi, const QString &property, const QVariant &value); + void sourceWasRemoved(const QString &source); + void setMountingState(const QString &udi); + void setUnmountingState(const QString &udi); + void setIdleState(Solid::ErrorType error, QVariant errorData, const QString &udi); + void deviceChanged(const QMap & props); +}; + +#endif diff --git a/plasma/generic/dataengines/soliddevice/soliddevicejob.cpp b/plasma/generic/dataengines/soliddevice/soliddevicejob.cpp new file mode 100644 index 00000000..44817bb6 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/soliddevicejob.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 Viranch Mehta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "soliddevicejob.h" +#include "soliddeviceengine.h" + +#include +#include +#include +#include + +#include + +void SolidDeviceJob::start() +{ + Solid::Device device (m_dest); + QString operation = operationName(); + + if (operation == "mount") { + if (device.is()) { + Solid::StorageAccess *access = device.as(); + if (access && !access->isAccessible()) { + access->setup(); + } + } + } + else if (operation == "unmount") { + if (device.is()) { + Solid::OpticalDrive *drive = device.as(); + if (!drive) { + drive = device.parent().as(); + } + if (drive) { + drive->eject(); + } + } + else if (device.is()) { + Solid::StorageAccess *access = device.as(); + if (access && access->isAccessible()) { + access->teardown(); + } + } + } + + emitResult(); +} + +#include "soliddevicejob.moc" + diff --git a/plasma/generic/dataengines/soliddevice/soliddevicejob.h b/plasma/generic/dataengines/soliddevice/soliddevicejob.h new file mode 100644 index 00000000..873f15ca --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/soliddevicejob.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Viranch Mehta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SOLIDDEVICE_JOB_H +#define SOLIDDEVICE_JOB_H + +#include "soliddeviceengine.h" + +#include + +class SolidDeviceJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + SolidDeviceJob (SolidDeviceEngine* engine, + const QString& destination, + const QString& operation, + QMap& parameters, + QObject* parent = 0) + : ServiceJob (destination, operation, parameters, parent), + m_engine (engine), + m_dest (destination) + { + } + + void start(); + +private: + SolidDeviceEngine* m_engine; + QString m_dest; +}; + +#endif // SOLIDDEVICE_JOB_H + diff --git a/plasma/generic/dataengines/soliddevice/soliddeviceservice.cpp b/plasma/generic/dataengines/soliddevice/soliddeviceservice.cpp new file mode 100644 index 00000000..714dd1a9 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/soliddeviceservice.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Viranch Mehta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "soliddeviceservice.h" +#include "soliddevicejob.h" +#include "soliddeviceengine.h" + +SolidDeviceService::SolidDeviceService (SolidDeviceEngine* parent, const QString& source) + : Plasma::Service (parent), + m_engine(parent) +{ + setName ("soliddevice"); + setDestination (source); +} + +Plasma::ServiceJob* SolidDeviceService::createJob (const QString& operation, + QMap & parameters) +{ + if (operation == "updateFreespace") { + m_engine->updateFreeSpace(destination()); + return 0; + } + + return new SolidDeviceJob (m_engine, destination(), operation, parameters, this); +} + +#include "soliddeviceservice.moc" + diff --git a/plasma/generic/dataengines/soliddevice/soliddeviceservice.h b/plasma/generic/dataengines/soliddevice/soliddeviceservice.h new file mode 100644 index 00000000..12126494 --- /dev/null +++ b/plasma/generic/dataengines/soliddevice/soliddeviceservice.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Viranch Mehta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SOLIDDEVICE_SERVICE_H +#define SOLIDDEVICE_SERVICE_H + +#include + +class SolidDeviceEngine; + +class SolidDeviceService : public Plasma::Service +{ + Q_OBJECT + +public: + SolidDeviceService (SolidDeviceEngine* parent, const QString& source); + +protected: + Plasma::ServiceJob* createJob (const QString& operation, + QMap& parameters); + +private: + SolidDeviceEngine* m_engine; + QString m_dest; +}; + +#endif // SOLIDDEVICE_SERVICE_H + diff --git a/plasma/generic/dataengines/statusnotifieritem/CMakeLists.txt b/plasma/generic/dataengines/statusnotifieritem/CMakeLists.txt new file mode 100644 index 00000000..16887e9e --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/CMakeLists.txt @@ -0,0 +1,33 @@ +project(plasma-statusnotifieritem_engine) + +include_directories(${KDEBASE_WORKSPACE_SOURCE_DIR}/statusnotifierwatcher) +include_directories(${DBUSMENUQT_INCLUDE_DIR}) + +# We add our source code here +set(statusnotifieritem_engine_SRCS + statusnotifieritem_engine.cpp + statusnotifieritemsource.cpp + statusnotifieritemservice.cpp + statusnotifieritemjob.cpp + systemtraytypes.cpp +) + +set(statusnotifierwatcher_xml ${KDE4_DBUS_INTERFACES_DIR}/org.kde.StatusNotifierWatcher.xml) +QT4_ADD_DBUS_INTERFACE(statusnotifieritem_engine_SRCS ${statusnotifierwatcher_xml} statusnotifierwatcher_interface) + +set(statusnotifieritem_xml ${KDE4_DBUS_INTERFACES_DIR}/org.kde.StatusNotifierItem.xml) + +set_source_files_properties(${statusnotifieritem_xml} PROPERTIES + NO_NAMESPACE false + INCLUDE "systemtraytypes.h" + CLASSNAME OrgKdeStatusNotifierItem +) +QT4_ADD_DBUS_INTERFACE(statusnotifieritem_engine_SRCS ${statusnotifieritem_xml} statusnotifieritem_interface) + +kde4_add_plugin(plasma_engine_statusnotifieritem ${statusnotifieritem_engine_SRCS}) +target_link_libraries(plasma_engine_statusnotifieritem ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${DBUSMENUQT_LIBRARIES}) + +install(TARGETS plasma_engine_statusnotifieritem DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma_engine_statusnotifieritem.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES statusnotifieritem.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + diff --git a/plasma/generic/dataengines/statusnotifieritem/plasma_engine_statusnotifieritem.desktop b/plasma/generic/dataengines/statusnotifieritem/plasma_engine_statusnotifieritem.desktop new file mode 100644 index 00000000..49bbcd83 --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/plasma_engine_statusnotifieritem.desktop @@ -0,0 +1,127 @@ +[Desktop Entry] +Name=Status Notifier Information +Name[ar]=معلومات حالة النظام +Name[ast]=Información de notificación d'estáu +Name[bs]=Podaci izveštavača o stanju +Name[ca]=Informació del notificador d'estats +Name[ca@valencia]=Informació del notificador d'estats +Name[cs]=Informace o oznamovači stavu +Name[da]=Information om statusbekendtgørelse +Name[de]=Status-Informationen +Name[el]=Πληροφορίες για τις ειδοποιήσεις κατάστασης +Name[en_GB]=Status Notifier Information +Name[es]=Información de notificación de estado +Name[et]=Oleku märguandja teave +Name[eu]=Egoera-jakinarazleari buruzko informazioa +Name[fi]=Järjestelmäilmoittimen tiedot +Name[fr]=Informations sur le notificateur d'état +Name[gl]=Información do notificador do estado +Name[he]=מידע מ־Status Notifier +Name[hi]=तंत्र सूचक जानकारी +Name[hr]=Informacije glasnika stanja +Name[hu]=Állaportértesítési információk +Name[ia]=Informationes de notificator de stato +Name[id]=Informasi Notifikasi Status +Name[is]=Stöðutilkynningaþjónn +Name[it]=Informazioni sul notificatore di stato +Name[ja]=ステータス通知情報 +Name[kk]=Күй-жайы туралы құлақтандыру мәліметі +Name[km]=ព័ត៌មាន​កម្មវិធី​ជំនួន​ដំណឹង​ស្ថានភាព +Name[kn]=ಸ್ಥಿತಿ ಸೂಚನಾ ಮಾಹಿತಿ +Name[ko]=장치 알림이 정보 +Name[lt]=Būsenos pranešėjo informacija +Name[lv]=Statusa ziņotāja informācija +Name[mr]=स्थिती निदर्शक माहिती +Name[nb]=StatusNotifier-opplysninger +Name[nds]=Statusbescheed-Informatschonen +Name[nl]=Melding van statusinformatie +Name[pa]=ਹਾਲਤ ਨੋਟੀਫਾਇਰ ਜਾਣਕਾਰੀ +Name[pl]=Informacja o powiadomieniach stanu +Name[pt]=Informações do Item de Notificação do Estado +Name[pt_BR]=Informações do Notificador de Status +Name[ro]=Informații notificator de stare +Name[ru]=Сведения уведомлений о состоянии +Name[si]=තත්ව දැනුම්දෙන්නාගේ තොරතුරු +Name[sk]=Informácie o oznámení stavu +Name[sl]=Podatki obvestilnika o stanju +Name[sr]=Подаци извештавача о стању +Name[sr@ijekavian]=Подаци извјештавача о стању +Name[sr@ijekavianlatin]=Podaci izvještavača o stanju +Name[sr@latin]=Podaci izveštavača o stanju +Name[sv]=Information från statusunderrättelser +Name[th]=ข้อมูลการแจ้งสถานะ +Name[tr]=Durum Bildirici Bilgileri +Name[ug]=ھالەت بىلدۈرگۈ ئۇچۇرى +Name[uk]=Відомості сповіщення про стан +Name[wa]=Informåcion do notifieu d' sitatut +Name[x-test]=xxStatus Notifier Informationxx +Name[zh_CN]=状态通知信息 +Name[zh_TW]=狀態通知器資訊 +Comment=Engine for applications' status information, based on the Status Notifier protocol. +Comment[ar]=محرك للمعلومات عن حالة البرامج, مبني على بروتوكول Status Notifier +Comment[ast]=Motor pa informar del estáu d'aplicaciones, basáu nel protocolu Status Notifier. +Comment[bs]=Motor za podatke o stanju programa, na osnovu protokola izveštavača o stanju. +Comment[ca]=Motor d'informació d'estat de les aplicacions, basat en el protocol notificador d'estat. +Comment[ca@valencia]=Motor d'informació d'estat de les aplicacions, basat en el protocol notificador d'estat. +Comment[cs]=Stroj pro informace o stavu aplikací, založen na protokolu Status Notifier +Comment[da]=Motor til programmers statusinformation, baseret på protokollen til statusbekendtgørelser. +Comment[de]=Treiber für Anwendungs-Status-Informationen, basierend auf dem Status-Informations-Protokoll. +Comment[el]=Μηχανή για τις πληροφορίες κατάστασης της εφαρμογής, βασισμένη στο πρωτόκολλο ειδοποιήσεων κατάστασης. +Comment[en_GB]=Engine for applications' status information, based on the Status Notifier protocol. +Comment[es]=Motor para informar del estado de aplicaciones, basado en el protocolo Status Notifier. +Comment[et]=Rakenduse olekuteabe mootor Status Notifieri protokolli alusel. +Comment[eu]=Aplikazioen egoerari buruzko informazioa emateko motorra, egoera-jakinarazlearen protokoloan oinarritua. +Comment[fi]=Kone sovelusten tilatiedoille, perustuu tilailmoitinyhteyskäytäntöön. +Comment[fr]=Moteur d'informations sur l'état des applications utilisant le protocole de notification d'état. +Comment[gl]=Motor para información do estado dos programas, baseado no protocolo Status Notifier. +Comment[he]=מנוע עבור מידע אודות מצב של יישומים, המתבסס על הפרוטוקול של Status Notifier. +Comment[hr]=Mehanizam za statusne informacije aplikacija baziran na protokolu glasnika stanja. +Comment[hu]=Az állaporértesítés protokollon alapuló modul az alkalmazások állapotértesítési információihoz. +Comment[ia]=Motor pro information de stato de applicationes basate sur le protocollo de Notificator de Stato +Comment[id]=Mesin untuk informasi status aplikasi, berbasis protokol Notifikasi Status. +Comment[is]=Kerfi fyrir stöðuupplýsingar forrita, byggt á samskiptamáta stöðutilkynninga (Status Notifier protocol). +Comment[it]=Motore per le informazioni di stato delle applicazioni, basato sul protocollo del notificatore di stato. +Comment[ja]=ステータス通知プロトコルに基づくアプリケーションステータス情報エンジン +Comment[kk]=Күй-жайы туралы құлақтандыру (Status Notifier) протоколын негіздеген қолданбаларға арналған тетік. +Comment[km]=ម៉ាស៊ីន​សម្រាប់​ព័ត៌មាន​ស្ថានភាព​របស់​​កម្មវិធី ដែលមាន​មូលដ្ឋាន​លើ​ពិធីការ​កម្មវិធី​ជូនដំណឹង​ស្ថានភាព ។ +Comment[ko]=상태 알림 프로토콜을 사용하는 프로그램 상태 정보 엔진입니다. +Comment[lt]=Programų būsenos informacijos varikliukas, pagrįstas būsenos pranešėjo protokolu. +Comment[lv]=Programmas statusa informācijas dzinējs, kas ir bāzēts uz sistēmas paziņojumu protokolu. +Comment[mr]=अनुप्रयोग स्थिती माहिती साठी स्थिती निदर्शक शिष्टाचारावर आधारित इंजिन +Comment[nb]=Motor for programstatus-informasjon basert på Status Notifier-protokollen. +Comment[nds]=Karn för Programmstatus-Informatschonen, de dat Statusbescheed-Protokoll bruukt. +Comment[nl]=Engine voor statusinformatie van toepassingen gebaseerde op het statusnotificatieprotocol. +Comment[pa]=ਹਾਲਤ ਨੋਟੀਫਾਇਰ ਪਰੋਟੋਕਾਲ ਉੱਤੇ ਅਧਾਰਿਤ ਐਪਲੀਕੇਸ਼ਨ ਹਾਲਤ ਜਾਣਕਾਰੀ ਲਈ ਇੰਜਣ। +Comment[pl]=Silnik do przekazywania informacji o stanie programów, oparty o protokół powiadomień o stanie. +Comment[pt]=Motor para a informação do estado das aplicações, baseado no protocolo do Item de Notificação do Estado. +Comment[pt_BR]=Mecanismo para informação de status de aplicativos baseado no protocolo do Notificador de Status. +Comment[ro]=Motor pentru informațiile de stare ale aplicațiilor, bazat pe protocolul Notificator de Stare. +Comment[ru]=Движок данных о состоянии программ, основанный на протоколе уведомлений о состоянии. +Comment[si]=තත්ව දැනුම්දීම් නියමාවලිය මත පදනම් වූ යෙදුම්වල තත්ව තොරතුරු සඳහා එන්ජිම. +Comment[sk]=Nástroj pre informácie o stave aplikácie, založený na protokole o oznámení stavu. +Comment[sl]=Pogon za podatke o stanju programov, ki temelji na protokolu obvestilnika o stanju. +Comment[sr]=Мотор за податке о стању програма, на основу протокола извештавача о стању. +Comment[sr@ijekavian]=Мотор за податке о стању програма, на основу протокола извјештавача о стању. +Comment[sr@ijekavianlatin]=Motor za podatke o stanju programa, na osnovu protokola izvještavača o stanju. +Comment[sr@latin]=Motor za podatke o stanju programa, na osnovu protokola izveštavača o stanju. +Comment[sv]=Gränssnitt för statusinformation om program baserat på protokollet för statusunderrättelser. +Comment[th]=กลไกสำหรับข้อมูลสถานะแอพลิเคชัน โดยใช้โพรโทคอลตัวแจ้งสถานะ +Comment[tr]=Uygulamaların durum bilgisi için motor +Comment[ug]=ھالەت ئۇقتۇرۇش كېلىشىمى ئاساسىدا، پروگرامما ھالەت ئۇچۇرىغا ئېرىشىشتە ئىشلىتىلىدىغان ماتور. +Comment[uk]=Рушій даних щодо стану програм, заснований на протоколі сповіщення про стан. +Comment[vi]=Cơ chế cho thông tin trạng thái ứng dụng, dựa trên giao thức Trình thông báo trạng thái +Comment[wa]=Moteur po l' informacion so l' estat do programe, båzé sol protocole Status Notifier. +Comment[x-test]=xxEngine for applications' status information, based on the Status Notifier protocol.xx +Comment[zh_CN]=用于提供应用程序状态信息的引擎,急于状态通知协议。 +Comment[zh_TW]=基於狀態通知器協定的應用程式狀態資訊引擎。 +Icon=preferences-desktop-notification + +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +X-KDE-Library=plasma_engine_statusnotifieritem +X-KDE-PluginInfo-Author=Matthieu Gallien +X-KDE-PluginInfo-Email=matthieu_gallien@yahoo.fr +X-KDE-PluginInfo-Name=statusnotifieritem +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/dataengines/statusnotifieritem/statusnotifieritem.operations b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritem.operations new file mode 100644 index 00000000..4515850c --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritem.operations @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/statusnotifieritem/statusnotifieritem_engine.cpp b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritem_engine.cpp new file mode 100644 index 00000000..660f8d62 --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritem_engine.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * Copyright (C) 2009 Matthieu Gallien * + * * + * 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 "statusnotifieritem_engine.h" +#include "statusnotifieritemsource.h" + +#include +#include +#include + +static const QString s_watcherServiceName("org.kde.StatusNotifierWatcher"); + +StatusNotifierItemEngine::StatusNotifierItemEngine(QObject *parent, const QVariantList& args) + : Plasma::DataEngine(parent, args), + m_statusNotifierWatcher(0) +{ + Q_UNUSED(args); +} + +StatusNotifierItemEngine::~StatusNotifierItemEngine() +{ + QDBusConnection::sessionBus().unregisterService(m_serviceName); +} + +Plasma::Service* StatusNotifierItemEngine::serviceForSource(const QString &name) +{ + StatusNotifierItemSource *source = dynamic_cast(containerForSource(name)); + // if source does not exist, return null service + if (!source) { + return Plasma::DataEngine::serviceForSource(name); + } + + Plasma::Service *service = source->createService(); + service->setParent(this); + return service; +} + +void StatusNotifierItemEngine::init() +{ + if (QDBusConnection::sessionBus().isConnected()) { + m_serviceName = "org.kde.StatusNotifierHost-" + QString::number(QCoreApplication::applicationPid()); + QDBusConnection::sessionBus().registerService(m_serviceName); + + QDBusServiceWatcher *watcher = new QDBusServiceWatcher(s_watcherServiceName, QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForOwnerChange, this); + connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), + this, SLOT(serviceChange(QString,QString,QString))); + + registerWatcher(s_watcherServiceName); + } +} + +void StatusNotifierItemEngine::serviceChange(const QString& name, const QString& oldOwner, const QString& newOwner) +{ + kDebug()<< "Service" << name << "status change, old owner:" << oldOwner << "new:" << newOwner; + + if (newOwner.isEmpty()) { + //unregistered + unregisterWatcher(name); + } else if (oldOwner.isEmpty()) { + //registered + registerWatcher(name); + } +} + +void StatusNotifierItemEngine::registerWatcher(const QString& service) +{ + kDebug()<<"service appeared"<isValid() && + m_statusNotifierWatcher->property("ProtocolVersion").toBool() == s_protocolVersion) { + connect(m_statusNotifierWatcher, SIGNAL(StatusNotifierItemRegistered(QString)), this, SLOT(serviceRegistered(QString))); + connect(m_statusNotifierWatcher, SIGNAL(StatusNotifierItemUnregistered(QString)), this, SLOT(serviceUnregistered(QString))); + + m_statusNotifierWatcher->call(QDBus::NoBlock, "RegisterStatusNotifierHost", m_serviceName); + + QStringList registeredItems = m_statusNotifierWatcher->property("RegisteredStatusNotifierItems").value(); + foreach (const QString &service, registeredItems) { + newItem(service); + } + } else { + delete m_statusNotifierWatcher; + m_statusNotifierWatcher = 0; + kDebug()<<"System tray daemon not reachable"; + } + } +} + +void StatusNotifierItemEngine::unregisterWatcher(const QString& service) +{ + if (service == s_watcherServiceName) { + kDebug()<< s_watcherServiceName << "disappeared"; + + disconnect(m_statusNotifierWatcher, SIGNAL(StatusNotifierItemRegistered(QString)), this, SLOT(serviceRegistered(QString))); + disconnect(m_statusNotifierWatcher, SIGNAL(StatusNotifierItemUnregistered(QString)), this, SLOT(serviceUnregistered(QString))); + + removeAllSources(); + + delete m_statusNotifierWatcher; + m_statusNotifierWatcher = 0; + } +} + +void StatusNotifierItemEngine::serviceRegistered(const QString &service) +{ + kDebug() << "Registering"< * + * Copyright (C) 2009 Matthieu Gallien * + * * + * 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 STATUSNOTIFIERITEM_ENGINE_H +#define STATUSNOTIFIERITEM_ENGINE_H + +#include "statusnotifierwatcher_interface.h" +#include +#include +#include + +// Define our plasma Runner +class StatusNotifierItemEngine : public Plasma::DataEngine { + Q_OBJECT + +public: + // Basic Create/Destroy + StatusNotifierItemEngine( QObject *parent, const QVariantList& args ); + ~StatusNotifierItemEngine(); + Plasma::Service *serviceForSource(const QString &name); +protected: + + virtual void init(); + void newItem(const QString &service); + +protected Q_SLOTS: + void serviceChange(const QString& name, + const QString& oldOwner, + const QString& newOwner); + void registerWatcher(const QString& service); + void unregisterWatcher(const QString& service); + void serviceRegistered(const QString &service); + void serviceUnregistered(const QString &service); + +private: + org::kde::StatusNotifierWatcher *m_statusNotifierWatcher; + QString m_serviceName; + static const int s_protocolVersion = 0; +}; + +#endif diff --git a/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemjob.cpp b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemjob.cpp new file mode 100644 index 00000000..4b844355 --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemjob.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2008 Alain Boyer + * Copyright (C) 2009 Matthieu Gallien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "statusnotifieritemjob.h" +#include + +StatusNotifierItemJob::StatusNotifierItemJob(StatusNotifierItemSource *source, const QString &operation, QMap ¶meters, QObject *parent) : + ServiceJob(source->objectName(), operation, parameters, parent), + m_source(source) +{ + connect(source, SIGNAL(contextMenuReady(QMenu*)), this, SLOT(contextMenuReady(QMenu*))); +} + +StatusNotifierItemJob::~StatusNotifierItemJob() +{ +} + +void StatusNotifierItemJob::start() +{ + if (operationName() == QString::fromLatin1("Activate")) { + m_source->activate(parameters()["x"].toInt(), parameters()["y"].toInt()); + setResult(0); + } else if (operationName() == QString::fromLatin1("SecondaryActivate")) { + m_source->secondaryActivate(parameters()["x"].toInt(), parameters()["y"].toInt()); + setResult(0); + } else if (operationName() == QString::fromLatin1("ContextMenu")) { + m_source->contextMenu(parameters()["x"].toInt(), parameters()["y"].toInt()); + } else if (operationName() == QString::fromLatin1("Scroll")) { + m_source->scroll(parameters()["delta"].toInt(), parameters()["direction"].toString()); + setResult(0); + } +} + +void StatusNotifierItemJob::contextMenuReady(QMenu *menu) +{ + if (operationName() == QString::fromLatin1("ContextMenu")) { + setResult(qVariantFromValue((QObject*)menu)); + } +} + +#include "statusnotifieritemjob.moc" diff --git a/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemjob.h b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemjob.h new file mode 100644 index 00000000..5bd6b610 --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemjob.h @@ -0,0 +1,51 @@ +/* + * Copyright 2008 Alain Boyer + * Copyright (C) 2009 Matthieu Gallien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef STATUSNOTIFIERITEMJOB_H +#define STATUSNOTIFIERITEMJOB_H + +// own +#include "statusnotifieritemsource.h" + +// plasma +#include + +/** + * Task Job + */ +class StatusNotifierItemJob : public Plasma::ServiceJob +{ + Q_OBJECT + +public: + StatusNotifierItemJob(StatusNotifierItemSource *source, const QString &operation, QMap ¶meters, QObject *parent = NULL); + ~StatusNotifierItemJob(); + +protected: + void start(); + +private Q_SLOTS: + void contextMenuReady(QMenu *menu); + +private: + StatusNotifierItemSource *m_source; + +}; + +#endif // STATUSNOTIFIERITEMJOB_H diff --git a/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemservice.cpp b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemservice.cpp new file mode 100644 index 00000000..1db9437d --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemservice.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2008 Alain Boyer + * Copyright (C) 2009 Matthieu Gallien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "statusnotifieritemservice.h" + +// own +#include "statusnotifieritemjob.h" + +StatusNotifierItemService::StatusNotifierItemService(StatusNotifierItemSource *source) : + Plasma::Service(source), + m_source(source) +{ + setName("statusnotifieritem"); +} + +StatusNotifierItemService::~StatusNotifierItemService() +{ +} + +Plasma::ServiceJob* StatusNotifierItemService::createJob(const QString &operation, QMap ¶meters) +{ + return new StatusNotifierItemJob(m_source, operation, parameters, this); +} + +#include "statusnotifieritemservice.moc" diff --git a/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemservice.h b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemservice.h new file mode 100644 index 00000000..c7dcd5a7 --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemservice.h @@ -0,0 +1,49 @@ +/* + * Copyright 2008 Alain Boyer + * Copyright (C) 2009 Matthieu Gallien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef STATUSNOTIFIERITEMSERVICE_H +#define STATUSNOTIFIERITEMSERVICE_H + +// own +#include "statusnotifieritemsource.h" + +// plasma +#include +#include + +/** + * StatusNotifierItem Service + */ +class StatusNotifierItemService : public Plasma::Service +{ + + Q_OBJECT + + public: + StatusNotifierItemService(StatusNotifierItemSource *source); + ~StatusNotifierItemService(); + + protected: + Plasma::ServiceJob *createJob(const QString &operation, QMap ¶meters); + + private: + StatusNotifierItemSource *m_source; +}; + +#endif // STATUSNOTIFIERITEMSERVICE_H diff --git a/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemsource.cpp b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemsource.cpp new file mode 100644 index 00000000..8baec40f --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemsource.cpp @@ -0,0 +1,485 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * Copyright (C) 2009 Matthieu Gallien * + * * + * 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 "statusnotifieritemsource.h" +#include "systemtraytypes.h" +#include "statusnotifieritemservice.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#ifndef DBUSMENUQT_VERSION +// DBUSMENUQT_VERSION was introduced in DBusMenuQt 0.4.0 +#define DBUSMENUQT_VERSION 0x000305 +#endif + +class PlasmaDBusMenuImporter : public DBusMenuImporter +{ +public: + PlasmaDBusMenuImporter(const QString &service, const QString &path, KIconLoader *iconLoader, QObject *parent) + : DBusMenuImporter(service, path, parent) + , m_iconLoader(iconLoader) + {} + +protected: + virtual QIcon iconForName(const QString &name) + { + return KIcon(name, m_iconLoader); + } + +private: + KIconLoader *m_iconLoader; +}; + +StatusNotifierItemSource::StatusNotifierItemSource(const QString ¬ifierItemId, QObject *parent) + : Plasma::DataContainer(parent), + m_customIconLoader(0), + m_menuImporter(0), + m_refreshing(false), + m_needsReRefreshing(false), + m_titleUpdate(true), + m_iconUpdate(true), + m_tooltipUpdate(true), + m_statusUpdate(true) +{ + setObjectName(notifierItemId); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + + m_typeId = notifierItemId; + m_name = notifierItemId; + + int slash = notifierItemId.indexOf('/'); + if (slash == -1) { + kError() << "Invalid notifierItemId:" << notifierItemId; + m_valid = false; + m_statusNotifierItemInterface = 0; + return; + } + QString service = notifierItemId.left(slash); + QString path = notifierItemId.mid(slash); + + m_statusNotifierItemInterface = new org::kde::StatusNotifierItem(service, path, + QDBusConnection::sessionBus(), this); + + m_refreshTimer.setSingleShot(true); + m_refreshTimer.setInterval(10); + connect(&m_refreshTimer, SIGNAL(timeout()), this, SLOT(performRefresh())); + + m_valid = !service.isEmpty() && m_statusNotifierItemInterface->isValid(); + if (m_valid) { + connect(m_statusNotifierItemInterface, SIGNAL(NewTitle()), this, SLOT(refreshTitle())); + connect(m_statusNotifierItemInterface, SIGNAL(NewIcon()), this, SLOT(refreshIcons())); + connect(m_statusNotifierItemInterface, SIGNAL(NewAttentionIcon()), this, SLOT(refreshIcons())); + connect(m_statusNotifierItemInterface, SIGNAL(NewOverlayIcon()), this, SLOT(refreshIcons())); + connect(m_statusNotifierItemInterface, SIGNAL(NewToolTip()), this, SLOT(refreshToolTip())); + connect(m_statusNotifierItemInterface, SIGNAL(NewStatus(QString)), this, SLOT(syncStatus(QString))); + refresh(); + } +} + +StatusNotifierItemSource::~StatusNotifierItemSource() +{ + delete m_statusNotifierItemInterface; +} + +KIconLoader *StatusNotifierItemSource::iconLoader() const +{ + return m_customIconLoader ? m_customIconLoader : KIconLoader::global(); +} + +Plasma::Service *StatusNotifierItemSource::createService() +{ + return new StatusNotifierItemService(this); +} + +void StatusNotifierItemSource::syncStatus(QString status) +{ + setData("TitleChanged", false); + setData("IconsChanged", false); + setData("TooltipChanged", false); + setData("StatusChanged", true); + setData("Status", status); + checkForUpdate(); +} + +void StatusNotifierItemSource::refreshTitle() +{ + m_titleUpdate = true; + refresh(); +} + +void StatusNotifierItemSource::refreshIcons() +{ + m_iconUpdate = true; + refresh(); +} + +void StatusNotifierItemSource::refreshToolTip() +{ + m_tooltipUpdate = true; + refresh(); +} + +void StatusNotifierItemSource::refresh() +{ + if (!m_refreshTimer.isActive()) { + m_refreshTimer.start(); + } +} + +void StatusNotifierItemSource::performRefresh() +{ + if (m_refreshing) { + m_needsReRefreshing = true; + return; + } + + m_refreshing = true; + QDBusMessage message = QDBusMessage::createMethodCall(m_statusNotifierItemInterface->service(), + m_statusNotifierItemInterface->path(), "org.freedesktop.DBus.Properties", "GetAll"); + + message << m_statusNotifierItemInterface->interface(); + QDBusPendingCall call = m_statusNotifierItemInterface->connection().asyncCall(message); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(refreshCallback(QDBusPendingCallWatcher*))); +} + +/** + \todo add a smart pointer to guard call and to automatically delete it at the end of the function + */ +void StatusNotifierItemSource::refreshCallback(QDBusPendingCallWatcher *call) +{ + m_refreshing = false; + if (m_needsReRefreshing) { + m_needsReRefreshing = false; + performRefresh(); + call->deleteLater(); + return; + } + + QDBusPendingReply reply = *call; + if (reply.isError()) { + m_valid = false; + } else { + // record what has changed + setData("TitleChanged", m_titleUpdate); + m_titleUpdate = false; + setData("IconsChanged", m_iconUpdate); + m_iconUpdate = false; + setData("ToolTipChanged", m_tooltipUpdate); + m_tooltipUpdate = false; + setData("StatusChanged", m_statusUpdate); + m_statusUpdate = false; + + //IconThemePath (handle this one first, because it has an impact on + //others) + QVariantMap properties = reply.argumentAt<0>(); + if (!m_customIconLoader) { + QString path = properties["IconThemePath"].toString(); + if (!path.isEmpty()) { + // FIXME: If last part of path is not "icons", this won't work! + QStringList tokens = path.split('/', QString::SkipEmptyParts); + if (tokens.length() >= 3 && tokens.takeLast() == "icons") { + QString appName = tokens.takeLast(); + QString prefix = '/' + tokens.join("/"); + // FIXME: Fix KIconLoader and KIconTheme so that we can use + // our own instance of KStandardDirs + KGlobal::dirs()->addResourceDir("data", prefix); + // We use a separate instance of KIconLoader to avoid + // adding all application dirs to KIconLoader::global(), to + // avoid potential icon name clashes between application + // icons + m_customIconLoader = new KIconLoader(appName, 0 /* dirs */, this); + } else { + kWarning() << "Wrong IconThemePath" << path << ": too short or does not end with 'icons'"; + } + } + } + setData("IconThemePath", properties["IconThemePath"]); + + setData("Category", properties["Category"]); + setData("Status", properties["Status"]); + setData("Title", properties["Title"]); + setData("Id", properties["Id"]); + setData("WindowId", properties["WindowId"]); + setData("ItemIsMenu", properties["ItemIsMenu"]); + + //Attention Movie + setData("AttentionMovieName", properties["AttentionMovieName"]); + + QIcon overlay; + QStringList overlayNames; + + //Icon + { + KDbusImageVector image; + QIcon icon; + QString iconName; + + properties["OverlayIconPixmap"].value() >> image; + if (image.isEmpty()) { + QString iconName = properties["OverlayIconName"].toString(); + setData("OverlayIconName", iconName); + if (!iconName.isEmpty()) { + overlayNames << iconName; + overlay = KIcon(iconName, iconLoader()); + } + } else { + overlay = imageVectorToPixmap(image); + } + + properties["IconPixmap"].value() >> image; + if (image.isEmpty()) { + iconName = properties["IconName"].toString(); + if (!iconName.isEmpty()) { + icon = KIcon(iconName, iconLoader(), overlayNames); + + if (overlayNames.isEmpty() && !overlay.isNull()) { + overlayIcon(&icon, &overlay); + } + } + } else { + icon = imageVectorToPixmap(image); + if (!icon.isNull() && !overlay.isNull()) { + overlayIcon(&icon, &overlay); + } + } + setData("Icon", icon); + setData("IconName", iconName); + } + + //Attention icon + { + KDbusImageVector image; + QIcon attentionIcon; + + properties["AttentionIconPixmap"].value() >> image; + if (image.isEmpty()) { + QString iconName = properties["AttentionIconName"].toString(); + setData("AttentionIconName", iconName); + if (!iconName.isEmpty()) { + attentionIcon = KIcon(iconName, iconLoader(), overlayNames); + + if (overlayNames.isEmpty() && !overlay.isNull()) { + overlayIcon(&attentionIcon, &overlay); + } + } + } else { + attentionIcon = imageVectorToPixmap(image); + if (!attentionIcon.isNull() && !overlay.isNull()) { + overlayIcon(&attentionIcon, &overlay); + } + } + setData("AttentionIcon", attentionIcon); + } + + //ToolTip + { + KDbusToolTipStruct toolTip; + properties["ToolTip"].value() >> toolTip; + if (toolTip.title.isEmpty()) { + setData("ToolTipTitle", QVariant()); + setData("ToolTipSubTitle", QVariant()); + setData("ToolTipIcon", QVariant()); + } else { + QIcon toolTipIcon; + if (toolTip.image.size() == 0) { + toolTipIcon = KIcon(toolTip.icon, iconLoader()); + } else { + toolTipIcon = imageVectorToPixmap(toolTip.image); + } + setData("ToolTipTitle", toolTip.title); + setData("ToolTipSubTitle", toolTip.subTitle); + setData("ToolTipIcon", toolTipIcon); + } + } + + //Menu + if (!m_menuImporter) { + QString menuObjectPath = properties["Menu"].value().path(); + if (!menuObjectPath.isEmpty()) { + if (menuObjectPath == "/NO_DBUSMENU") { + // This is a hack to make it possible to disable DBusMenu in an + // application. The string "/NO_DBUSMENU" must be the same as in + // KStatusNotifierItem::setContextMenu(). + kWarning() << "DBusMenu disabled for this application"; + } else { + m_menuImporter = new PlasmaDBusMenuImporter(m_statusNotifierItemInterface->service(), menuObjectPath, iconLoader(), this); +#if DBUSMENUQT_VERSION >= 0x000400 + connect(m_menuImporter, SIGNAL(menuUpdated()), this, SLOT(contextMenuReady())); +#endif + } + } + } + } + + checkForUpdate(); + call->deleteLater(); +} + +void StatusNotifierItemSource::contextMenuReady() +{ +#if DBUSMENUQT_VERSION < 0x000400 + // Work around to avoid infinite recursion because menuReadyToBeShown() is emitted + // by DBusMenuImporter at the end of its slot connected to aboutToShow() + // (dbusmenu-qt 0.3.5) + disconnect(m_menuImporter, SIGNAL(menuReadyToBeShown()), this, SLOT(contextMenuReady())); +#endif + emit contextMenuReady(m_menuImporter->menu()); +} + +QPixmap StatusNotifierItemSource::KDbusImageStructToPixmap(const KDbusImageStruct &image) const +{ + //swap from network byte order if we are little endian + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { + uint *uintBuf = (uint *) image.data.data(); + for (uint i = 0; i < image.data.size()/sizeof(uint); ++i) { + *uintBuf = ntohl(*uintBuf); + ++uintBuf; + } + } + QImage iconImage(image.width, image.height, QImage::Format_ARGB32 ); + memcpy(iconImage.bits(), (uchar*)image.data.data(), iconImage.numBytes()); + + return QPixmap::fromImage(iconImage); +} + +QIcon StatusNotifierItemSource::imageVectorToPixmap(const KDbusImageVector &vector) const +{ + QIcon icon; + + for (int i = 0; ipixmap(KIconLoader::SizeSmall, KIconLoader::SizeSmall); + + QPainter p(&m_iconPixmap); + + const int size = KIconLoader::SizeSmall/2; + p.drawPixmap(QRect(size, size, size, size), overlay->pixmap(size, size), QRect(0,0,size,size)); + p.end(); + tmp.addPixmap(m_iconPixmap); + + //if an m_icon exactly that size wasn't found don't add it to the vector + m_iconPixmap = icon->pixmap(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium); + if (m_iconPixmap.width() == KIconLoader::SizeSmallMedium) { + const int size = KIconLoader::SizeSmall/2; + QPainter p(&m_iconPixmap); + p.drawPixmap(QRect(m_iconPixmap.width()-size, m_iconPixmap.height()-size, size, size), overlay->pixmap(size, size), QRect(0,0,size,size)); + p.end(); + tmp.addPixmap(m_iconPixmap); + } + + m_iconPixmap = icon->pixmap(KIconLoader::SizeMedium, KIconLoader::SizeMedium); + if (m_iconPixmap.width() == KIconLoader::SizeMedium) { + const int size = KIconLoader::SizeSmall/2; + QPainter p(&m_iconPixmap); + p.drawPixmap(QRect(m_iconPixmap.width()-size, m_iconPixmap.height()-size, size, size), overlay->pixmap(size, size), QRect(0,0,size,size)); + p.end(); + tmp.addPixmap(m_iconPixmap); + } + + m_iconPixmap = icon->pixmap(KIconLoader::SizeLarge, KIconLoader::SizeLarge); + if (m_iconPixmap.width() == KIconLoader::SizeLarge) { + const int size = KIconLoader::SizeSmall; + QPainter p(&m_iconPixmap); + p.drawPixmap(QRect(m_iconPixmap.width()-size, m_iconPixmap.height()-size, size, size), overlay->pixmap(size, size), QRect(0,0,size,size)); + p.end(); + tmp.addPixmap(m_iconPixmap); + } + + // We can't do 'm_icon->addPixmap()' because if 'm_icon' uses KIconEngine, + // it will ignore the added pixmaps. This is not a bug in KIconEngine, + // QIcon::addPixmap() doc says: "Custom m_icon engines are free to ignore + // additionally added pixmaps". + *icon = tmp; + //hopefully huge and enormous not necessary right now, since it's quite costly +} + +void StatusNotifierItemSource::activate(int x, int y) +{ + if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) { + m_statusNotifierItemInterface->call(QDBus::NoBlock, "Activate", x, y); + } +} + +void StatusNotifierItemSource::secondaryActivate(int x, int y) +{ + if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) { + m_statusNotifierItemInterface->call(QDBus::NoBlock, "SecondaryActivate", x, y); + } +} + +void StatusNotifierItemSource::scroll(int delta, const QString &direction) +{ + if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) { + m_statusNotifierItemInterface->call(QDBus::NoBlock, "Scroll", delta, direction); + } +} + +void StatusNotifierItemSource::contextMenu(int x, int y) +{ + if (m_menuImporter) { + #if DBUSMENUQT_VERSION >= 0x000400 + m_menuImporter->updateMenu(); + #else + QMenu *menu = m_menuImporter->menu(); + // Simulate an "aboutToShow" so that menu->sizeHint() is correct. Otherwise + // the menu may show up over the applet if new actions are added on the + // fly. + connect(m_menuImporter, SIGNAL(menuReadyToBeShown()), this, SLOT(contextMenuReady())); + QMetaObject::invokeMethod(menu, "aboutToShow"); + #endif + } else { + kWarning() << "Could not find DBusMenu interface, falling back to calling ContextMenu()"; + if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) { + m_statusNotifierItemInterface->call(QDBus::NoBlock, "ContextMenu", x, y); + } + } +} + +#include "statusnotifieritemsource.moc" diff --git a/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemsource.h b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemsource.h new file mode 100644 index 00000000..c60fb321 --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/statusnotifieritemsource.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * Copyright (C) 2009 Matthieu Gallien * + * * + * 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 STATUSNOTIFIERITEMSOURCE_H +#define STATUSNOTIFIERITEMSOURCE_H + +#include +#include +#include + +#include "statusnotifieritem_interface.h" + +class KIconLoader; + +class DBusMenuImporter; + +class StatusNotifierItemSource : public Plasma::DataContainer +{ + + Q_OBJECT + +public: + StatusNotifierItemSource(const QString &service, QObject *parent); + ~StatusNotifierItemSource(); + Plasma::Service *createService(); + + void activate(int x, int y); + void secondaryActivate(int x, int y); + void scroll(int delta, const QString &direction); + void contextMenu(int x, int y); + +Q_SIGNALS: + void contextMenuReady(QMenu *menu); + +private slots: + void contextMenuReady(); + void refreshTitle(); + void refreshIcons(); + void refreshToolTip(); + void refresh(); + void performRefresh(); + void syncStatus(QString); + void refreshCallback(QDBusPendingCallWatcher *); + +private: + + QPixmap KDbusImageStructToPixmap(const KDbusImageStruct &image) const; + QIcon imageVectorToPixmap(const KDbusImageVector &vector) const; + void overlayIcon(QIcon *icon, QIcon *overlay); + KIconLoader *iconLoader() const; + + bool m_valid; + QString m_typeId; + QString m_name; + QTimer m_refreshTimer; + KIconLoader *m_customIconLoader; + DBusMenuImporter *m_menuImporter; + org::kde::StatusNotifierItem *m_statusNotifierItemInterface; + bool m_refreshing : 1; + bool m_needsReRefreshing : 1; + bool m_titleUpdate : 1; + bool m_iconUpdate : 1; + bool m_tooltipUpdate : 1; + bool m_statusUpdate : 1; +}; + +#endif // STATUSNOTIFIERITEMSOURCE_H diff --git a/plasma/generic/dataengines/statusnotifieritem/systemtraytypes.cpp b/plasma/generic/dataengines/statusnotifieritem/systemtraytypes.cpp new file mode 100644 index 00000000..dab7f949 --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/systemtraytypes.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * * + * 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 "systemtraytypes.h" + + +// Marshall the ImageStruct data into a D-BUS argument +const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageStruct &icon) +{ + argument.beginStructure(); + argument << icon.width; + argument << icon.height; + argument << icon.data; + argument.endStructure(); + return argument; +} +#include + +// Retrieve the ImageStruct data from the D-BUS argument +const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageStruct &icon) +{ + qint32 width = 0; + qint32 height = 0; + QByteArray data; + + if (argument.currentType() == QDBusArgument::StructureType) { + argument.beginStructure(); + //kDebug() << "begun structure"; + argument >> width; + //kDebug() << width; + argument >> height; + //kDebug() << height; + argument >> data; + //kDebug() << data.size(); + argument.endStructure(); + } + + icon.width = width; + icon.height = height; + icon.data = data; + + return argument; +} + +// Marshall the ImageVector data into a D-BUS argument +const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageVector &iconVector) +{ + argument.beginArray(qMetaTypeId()); + for (int i=0; i>(const QDBusArgument &argument, KDbusImageVector &iconVector) +{ + iconVector.clear(); + + if (argument.currentType() == QDBusArgument::ArrayType) { + argument.beginArray(); + + while (!argument.atEnd()) { + KDbusImageStruct element; + argument >> element; + iconVector.append(element); + } + + argument.endArray(); + } + + return argument; +} + +// Marshall the ToolTipStruct data into a D-BUS argument +const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusToolTipStruct &toolTip) +{ + argument.beginStructure(); + argument << toolTip.icon; + argument << toolTip.image; + argument << toolTip.title; + argument << toolTip.subTitle; + argument.endStructure(); + + return argument; +} + +// Retrieve the ToolTipStruct data from the D-BUS argument +const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusToolTipStruct &toolTip) +{ + QString icon; + KDbusImageVector image; + QString title; + QString subTitle; + + if (argument.currentType() == QDBusArgument::StructureType) { + argument.beginStructure(); + argument >> icon; + argument >> image; + argument >> title; + argument >> subTitle; + argument.endStructure(); + } + + toolTip.icon = icon; + toolTip.image = image; + toolTip.title = title; + toolTip.subTitle = subTitle; + + return argument; +} diff --git a/plasma/generic/dataengines/statusnotifieritem/systemtraytypes.h b/plasma/generic/dataengines/statusnotifieritem/systemtraytypes.h new file mode 100644 index 00000000..95a77257 --- /dev/null +++ b/plasma/generic/dataengines/statusnotifieritem/systemtraytypes.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * * + * 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 SYSTEMTRAYTYPES_H +#define SYSTEMTRAYTYPES_H + +#include + +#include "systemtraytypedefs.h" + +const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageStruct &icon); +const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageStruct &icon); + + +const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageVector &iconVector); +const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageVector &iconVector); + +const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusToolTipStruct &toolTip); +const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusToolTipStruct &toolTip); + + +#endif diff --git a/plasma/generic/dataengines/systemmonitor/CMakeLists.txt b/plasma/generic/dataengines/systemmonitor/CMakeLists.txt new file mode 100644 index 00000000..b9bf5569 --- /dev/null +++ b/plasma/generic/dataengines/systemmonitor/CMakeLists.txt @@ -0,0 +1,14 @@ + +set(systemmonitor_engine_SRCS + systemmonitor.cpp +) + +kde4_add_plugin(plasma_engine_systemmonitor ${systemmonitor_engine_SRCS}) +target_link_libraries(plasma_engine_systemmonitor ${KDE4_PLASMA_LIBS} ${KDE4_KDECORE_LIBS} ${QT_QTNETWORK_LIBRARY} ksgrd) + +install(TARGETS plasma_engine_systemmonitor DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-systemmonitor.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + + + + diff --git a/plasma/generic/dataengines/systemmonitor/Messages.sh b/plasma/generic/dataengines/systemmonitor/Messages.sh new file mode 100755 index 00000000..73d19d81 --- /dev/null +++ b/plasma/generic/dataengines/systemmonitor/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_engine_systemmonitor.pot diff --git a/plasma/generic/dataengines/systemmonitor/plasma-dataengine-systemmonitor.desktop b/plasma/generic/dataengines/systemmonitor/plasma-dataengine-systemmonitor.desktop new file mode 100644 index 00000000..89548707 --- /dev/null +++ b/plasma/generic/dataengines/systemmonitor/plasma-dataengine-systemmonitor.desktop @@ -0,0 +1,166 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=System Monitor +Name[af]=Stelsel Monitor +Name[ar]=مراقب النظام +Name[ast]=Monitor del sistema +Name[be]=Сістэмны назіральнік +Name[be@latin]=Systemny nazirańnik +Name[bg]=Наблюдение на системата +Name[bn]=সিস্টেম মনিটর +Name[bn_IN]=সিস্টেম নিরীক্ষণ ব্যবস্থা +Name[bs]=Monitor sistema +Name[ca]=Monitor del sistema +Name[ca@valencia]=Monitor del sistema +Name[cs]=Monitor systému +Name[csb]=Mònitór systemë +Name[da]=Systemovervågning +Name[de]=Systemmonitor +Name[el]=Επόπτης συστήματος +Name[en_GB]=System Monitor +Name[eo]=Sistemstato-programo +Name[es]=Monitor del sistema +Name[et]=Süsteemi jälgija +Name[eu]=Sistema-monitorea +Name[fa]=نمایشگر سیستم +Name[fi]=Järjestelmän valvonta +Name[fr]=Surveillance du système +Name[fy]=Systeemmonitor +Name[ga]=Monatóir an Chórais +Name[gl]=Vixilante do sistema +Name[gu]=સિસ્ટમ દેખરેખ +Name[he]=מוניטור המערכת +Name[hi]=तंत्र मॉनीटर +Name[hne]=तंत्र मानीटर +Name[hr]=Nadzor sustava +Name[hsb]=Systemowy monitor +Name[hu]=Rendszermonitor +Name[ia]=Monitor de systema +Name[id]=Monitor Sistem +Name[is]=Kerfiseftirlit +Name[it]=Monitor di sistema +Name[ja]=システムモニタ +Name[kk]=Жүйе мониторы +Name[km]=កម្មវិធី​ត្រួត​​ពិនិត្យ​ប្រព័ន្ធ +Name[kn]=ವ್ಯವಸ್ಥೆಯ ಪ್ರದರ್ಶಕ +Name[ko]=시스템 모니터 +Name[ku]=Temaşekerê Pergalê +Name[lt]=Sistemos stebėtojas +Name[lv]=Sistēmas monitors +Name[mai]=सिस्टम मानीटर +Name[mk]=Системски монитор +Name[ml]=സിസ്റ്റം നിരീക്ഷകന്‍ +Name[mr]=प्रणाली मॉनिटर +Name[nb]=Systemovervåker +Name[nds]=Systeemkieker +Name[ne]=प्रणाली मनिटर +Name[nl]=Systeemmonitor +Name[nn]=Systemovervaking +Name[oc]=Monitor sistèma +Name[pa]=ਸਿਸਟਮ ਮਾਨੀਟਰ +Name[pl]=Monitor systemu +Name[pt]=Monitor do Sistema +Name[pt_BR]=Monitor do sistema +Name[ro]=Monitor de sistem +Name[ru]=Системный монитор +Name[se]=Vuogádatgoziheaddji +Name[si]=පද්ධති නිරීක්‍ෂකය +Name[sk]=Monitor systému +Name[sl]=Sistemski nadzornik +Name[sr]=надзорник система +Name[sr@ijekavian]=надзорник система +Name[sr@ijekavianlatin]=nadzornik sistema +Name[sr@latin]=nadzornik sistema +Name[sv]=Systemövervakare +Name[ta]=கணினி நோட்டம் +Name[te]=సిస్టమ్ మానిటర్ +Name[tg]=Назорати система +Name[th]=ติดตามการทำงานของระบบ +Name[tr]=Sistem İzleyici +Name[ug]=سىستېما كۆزەتكۈچ +Name[uk]=Монітор системи +Name[vi]=Bộ theo dõi hệ thống +Name[wa]=Corwaitoe do sistinme +Name[x-test]=xxSystem Monitorxx +Name[zh_CN]=系统监视器 +Name[zh_TW]=系統監視器 +Comment=System status information +Comment[ar]=معلومات حالة النظام +Comment[ast]=Información d'estáu del sistema +Comment[bg]=Данни за състоянието на системата +Comment[bn]=সিস্টেম স্ট্যাটাস তথ্য +Comment[bs]=Podaci o stanju sistema +Comment[ca]=Informació de l'estat del sistema +Comment[ca@valencia]=Informació de l'estat del sistema +Comment[cs]=Informace o stavu systému +Comment[csb]=Wëdowiédzô ò stónie systemë +Comment[da]=Information om systemstatus +Comment[de]=Systemstatus-Informationen +Comment[el]=Πληροφορίες κατάστασης συστήματος +Comment[en_GB]=System status information +Comment[eo]=Sistemstataj informoj +Comment[es]=Información de estado del sistema +Comment[et]=Süsteemi oleku teave +Comment[eu]=Sistemaren egoerari buruzko informazioa +Comment[fi]=Järjestelmätilatiedot +Comment[fr]=Informations sur l'état du système +Comment[fy]=Systeemtastân ynformaasje +Comment[ga]=Eolas faoi stádas an chórais +Comment[gl]=Información do estado do sistema +Comment[gu]=સિસ્ટમ સ્થિતિ માહિતી +Comment[he]=מידע אודות מצב המערכת +Comment[hi]=तंत्र स्थिति जानकारी +Comment[hr]=Podaci o stanju sustava +Comment[hu]=Rendszerjellemzők +Comment[ia]=Information de stato de systema +Comment[id]=Informasi status sistem +Comment[is]=Upplýsingar um kerfisforrit +Comment[it]=Informazioni sullo stato del sistema +Comment[ja]=システムのステータス情報 +Comment[kk]=Жүйе күй-жайы туралы мәлімет +Comment[km]=ព័ត៌មាន​ស្ថានភាព​របស់​ប្រព័ន្ធ +Comment[kn]=ವ್ಯವಸ್ಥೆಯ ಸ್ಥಿತಿಯ ಮಾಹಿತಿ +Comment[ko]=시스템 상태 정보 +Comment[lt]=Sistemos būklės informacija +Comment[lv]=Sistēmas statusa informācija +Comment[mk]=Информации за статусот на системот +Comment[ml]=സിസ്റ്റത്തിന്റെ അവസ്ഥാ വിവരം +Comment[mr]=प्रणाली स्थिती माहिती +Comment[nb]=Informasjon om systemstatus +Comment[nds]=Systeemstatus-Informatschonen +Comment[nl]=Informatie over systeemstatus +Comment[nn]=Informasjon om systemstatus +Comment[pa]=ਸਿਸਟਮ ਹਾਲਤ ਜਾਣਕਾਰੀ +Comment[pl]=Informacje o stanie systemu +Comment[pt]=Informações do estado do sistema +Comment[pt_BR]=Informação do status do sistema +Comment[ro]=Informații despre starea sistemului +Comment[ru]=Сведения о системе +Comment[si]=පද්ධති තත්ව තොරතුරු +Comment[sk]=Informácie o stave systému +Comment[sl]=Podatki o stanju sistema +Comment[sr]=Подаци о стању система +Comment[sr@ijekavian]=Подаци о стању система +Comment[sr@ijekavianlatin]=Podaci o stanju sistema +Comment[sr@latin]=Podaci o stanju sistema +Comment[sv]=Information om systemstatus +Comment[tg]=Барномаи маълумоти система +Comment[th]=ข้อมูลสถานะของระบบ +Comment[tr]=Sistem durumu bilgileri +Comment[ug]=سىستېما ھالەت ئۇچۇرى +Comment[uk]=Інформація про стан системи +Comment[wa]=Informåcion so l' estat do sistinme +Comment[x-test]=xxSystem status informationxx +Comment[zh_CN]=系统状态信息 +Comment[zh_TW]=系統狀態資訊 +ServiceTypes=Plasma/DataEngine +Icon=utilities-system-monitor +Type=Service +X-KDE-Library=plasma_engine_systemmonitor + +X-KDE-PluginInfo-Author= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-Name=systemmonitor +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category= diff --git a/plasma/generic/dataengines/systemmonitor/sensorclient.h b/plasma/generic/dataengines/systemmonitor/sensorclient.h new file mode 100644 index 00000000..074f59c2 --- /dev/null +++ b/plasma/generic/dataengines/systemmonitor/sensorclient.h @@ -0,0 +1,192 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger + Copyright (c) 2006 John Tapsell + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License 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; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef KSG_SENSORCLIENT_H +#define KSG_SENSORCLIENT_H + +#include +#include +#include + +namespace KSGRD { + +/** + Every object that should act as a client to a sensor must inherit from + this class. A pointer to the client object is passed as SensorClient* + to the SensorAgent. When the requested information is available or a + problem occurred one of the member functions is called. + */ +class SensorClient +{ + public: + explicit SensorClient() { } + virtual ~SensorClient() { } + + /** + This function is called whenever the information from the sensor has + been received by the sensor agent. This function must be reimplemented + by the sensor client to receive and process this information. + */ + virtual void answerReceived( const QString &, const QList& ) { } + + /** + In case of an unexpected fatal problem with the sensor the sensor + agent will call this function to notify the client about it. + */ + virtual void sensorLost( const QString &) { } +}; + +/** + The following classes are utility classes that provide a + convenient way to retrieve pieces of information from the sensor + answers. For each type of answer there is a separate class. + */ +class SensorTokenizer +{ + public: + SensorTokenizer( const QByteArray &info, char separator ) + { + if ( separator == '/' ) { + //This is a special case where we assume that info is a '\' escaped string + + int i=0; + int lastTokenAt = -1; + + for( ; i < info.length(); ++i ) { + if( info[i] == '\\' ) { + ++i; + } + else if ( info[i] == separator ) { + m_tokens.append( unEscapeString( info.mid( lastTokenAt + 1, i - lastTokenAt - 1 ) ) ); + lastTokenAt = i; + } + } + + //Add everything after the last token + m_tokens.append( unEscapeString( info.mid( lastTokenAt + 1, i - lastTokenAt - 1 ) ) ); + } + else { + m_tokens = info.split( separator ); + } + } + + ~SensorTokenizer() { } + + const QByteArray& operator[]( unsigned idx ) + { + Q_ASSERT(idx < (unsigned)(m_tokens.count())); + return m_tokens[ idx ]; + } + + uint count() + { + return m_tokens.count(); + } + + private: + QList m_tokens; + + QByteArray unEscapeString( QByteArray string ) { + + int i=0; + for( ; i < string.length(); ++i ) { + if( string[i] == '\\' ) { + string.remove( i, 1 ); + ++i; + } + } + + return string; + } +}; + +/** + An integer info contains 4 fields separated by TABS, a description + (name), the minimum and the maximum values and the unit. + e.g. Swap Memory 0 133885952 KB + */ +class SensorIntegerInfo : public SensorTokenizer +{ + public: + explicit SensorIntegerInfo( const QByteArray &info ) + : SensorTokenizer( info, '\t' ) { } + + ~SensorIntegerInfo() { } + + QString name() + { + return QString::fromUtf8((*this)[ 0 ]); + } + + long min() + { + return (*this)[ 1 ].toLong(); + } + + long max() + { + return (*this)[ 2 ].toLong(); + } + + QString unit() + { + return QString::fromUtf8((*this)[ 3 ]); + } +}; + +/** + An float info contains 4 fields separated by TABS, a description + (name), the minimum and the maximum values and the unit. + e.g. CPU Voltage 0.0 5.0 V + */ +class SensorFloatInfo : public SensorTokenizer +{ + public: + explicit SensorFloatInfo( const QByteArray &info ) + : SensorTokenizer( info, '\t' ) { } + + ~SensorFloatInfo() { } + + QString name() + { + return QString::fromUtf8((*this)[ 0 ]); + } + + double min() + { + return (*this)[ 1 ].toDouble(); + } + + double max() + { + return (*this)[ 2 ].toDouble(); + } + + QString unit() + { + return QString::fromUtf8((*this)[ 3 ]); + } +}; + + +} + +#endif diff --git a/plasma/generic/dataengines/systemmonitor/systemmonitor.cpp b/plasma/generic/dataengines/systemmonitor/systemmonitor.cpp new file mode 100644 index 00000000..81a8e67d --- /dev/null +++ b/plasma/generic/dataengines/systemmonitor/systemmonitor.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2007 John Tapsell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "systemmonitor.h" + +#include +#include + +#include +#include + +#include + +#include "ksysguard/ksgrd/SensorManager.h" + +SystemMonitorEngine::SystemMonitorEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent) +{ + Q_UNUSED(args) + + KSGRD::SensorMgr = new KSGRD::SensorManager(this); + KSGRD::SensorMgr->engage("localhost", "", "ksysguardd"); + + m_waitingFor= 0; + connect(KSGRD::SensorMgr, SIGNAL(update()), this, SLOT(updateMonitorsList())); + updateMonitorsList(); +} + +SystemMonitorEngine::~SystemMonitorEngine() +{ +} + +void SystemMonitorEngine::updateMonitorsList() +{ + KSGRD::SensorMgr->sendRequest("localhost", "monitors", (KSGRD::SensorClient*)this, -1); +} + +QStringList SystemMonitorEngine::sources() const +{ + return m_sensors; +} + +bool SystemMonitorEngine::sourceRequestEvent(const QString &name) +{ + // NB: do not follow this example in your own data engines! + // This is kept for backwards compatilibility. + // Visualizations should instead listen to sourceAdded() + if (m_sensors.isEmpty()) { + // we don't have our first data yet, so let's trust the requester, at least fo rnow + // when we get our list of sensors later, then we'll know for sure and remove + // this source if they were wrong + setData(name, DataEngine::Data()); + return true; + } + + return false; +} + +bool SystemMonitorEngine::updateSourceEvent(const QString &sensorName) +{ + const int index = m_sensors.indexOf(sensorName); + + if (index != -1) { + KSGRD::SensorMgr->sendRequest("localhost", sensorName, (KSGRD::SensorClient*)this, index); + KSGRD::SensorMgr->sendRequest("localhost", QString("%1?").arg(sensorName), (KSGRD::SensorClient*)this, -(index + 2)); + } + + return false; +} + +void SystemMonitorEngine::updateSensors() +{ + DataEngine::SourceDict sources = containerDict(); + DataEngine::SourceDict::iterator it = sources.begin(); + if (m_waitingFor != 0) { + scheduleSourcesUpdated(); + } + + m_waitingFor = 0; + + while (it != sources.end()) { + m_waitingFor++; + QString sensorName = it.key(); + KSGRD::SensorMgr->sendRequest( "localhost", sensorName, (KSGRD::SensorClient*)this, -1); + ++it; + } +} + +void SystemMonitorEngine::answerReceived(int id, const QList &answer) +{ + if (id < -1) { + if (answer.isEmpty() || m_sensors.count() <= (-id - 2)) { + kDebug() << "sensor info answer was empty, (" << answer.isEmpty() << ") or sensors does not exist to us (" + << (m_sensors.count() < (-id - 2)) << ") for index" << (-id - 2); + return; + } + + DataEngine::SourceDict sources = containerDict(); + DataEngine::SourceDict::const_iterator it = sources.constFind(m_sensors.value(-id - 2)); + + const QStringList newSensorInfo = QString::fromUtf8(answer[0]).split('\t'); + + if (newSensorInfo.count() < 4) { + kDebug() << "bad sensor info, only" << newSensorInfo.count() + << "entries, and we were expecting 4. Answer was " << answer; + if(it != sources.constEnd()) + kDebug() << "value =" << it.value()->data()["value"] << "type=" << it.value()->data()["type"]; + return; + } + + const QString sensorName = newSensorInfo[0]; + const QString min = newSensorInfo[1]; + const QString max = newSensorInfo[2]; + const QString unit = newSensorInfo[3]; + + if (it != sources.constEnd()) { + it.value()->setData("name", sensorName); + it.value()->setData("min", min); + it.value()->setData("max", max); + it.value()->setData("units", unit); + scheduleSourcesUpdated(); + } + + return; + } + + if (id == -1) { + QSet sensors; + m_sensors.clear(); + int count = 0; + + foreach (const QByteArray &sens, answer) { + const QStringList newSensorInfo = QString::fromUtf8(sens).split('\t'); + if (newSensorInfo.count() < 2) { + continue; + } + if(newSensorInfo.at(1) == "logfile") + continue; // logfile data type not currently supported + + const QString newSensor = newSensorInfo[0]; + sensors.insert(newSensor); + m_sensors.append(newSensor); + { + // HACK: for backwards compability + // in case this source was created in sourceRequestEvent, stop it being + // automagically removed when disconnected from + Plasma::DataContainer *s = containerForSource( newSensor ); + if ( s ) { + disconnect( s, SIGNAL(becameUnused(QString)), this, SLOT(removeSource(QString)) ); + } + } + DataEngine::Data d; + d.insert("value", QVariant()); + d.insert("type", newSensorInfo[1]); + setData(newSensor, d); + KSGRD::SensorMgr->sendRequest( "localhost", QString("%1?").arg(newSensor), (KSGRD::SensorClient*)this, -(count + 2)); + ++count; + } + + QHash sourceDict = containerDict(); + QHashIterator it(sourceDict); + while (it.hasNext()) { + it.next(); + if (!sensors.contains(it.key())) { + removeSource(it.key()); + } + } + + return; + } + + m_waitingFor--; + QString reply; + if (!answer.isEmpty()) { + reply = QString::fromUtf8(answer[0]); + } + + DataEngine::SourceDict sources = containerDict(); + DataEngine::SourceDict::const_iterator it = sources.constFind(m_sensors.value(id)); + if (it != sources.constEnd()) { + it.value()->setData("value", reply); + } + + if (m_waitingFor == 0) { + scheduleSourcesUpdated(); + } +} + +void SystemMonitorEngine::sensorLost( int ) +{ + m_waitingFor--; +} + +#include "systemmonitor.moc" + diff --git a/plasma/generic/dataengines/systemmonitor/systemmonitor.h b/plasma/generic/dataengines/systemmonitor/systemmonitor.h new file mode 100644 index 00000000..ddb4ab44 --- /dev/null +++ b/plasma/generic/dataengines/systemmonitor/systemmonitor.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 John Tapsell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SYSTEMMONITORENGINE_H +#define SYSTEMMONITORENGINE_H + +#include + +#include "ksysguard/ksgrd/SensorClient.h" + +#include + +class QTimer; + +/** + * This class evaluates the basic expressions given in the interface. + */ +class SystemMonitorEngine : public Plasma::DataEngine, public KSGRD::SensorClient +{ + Q_OBJECT + + public: + /** Inherited from Plasma::DataEngine. Returns a list of all the sensors that ksysguardd knows about. */ + virtual QStringList sources() const; + SystemMonitorEngine( QObject* parent, const QVariantList& args ); + ~SystemMonitorEngine(); + + protected: + bool sourceRequestEvent(const QString &name); + /** inherited from SensorClient */ + virtual void answerReceived( int id, const QList&answer ); + virtual void sensorLost( int ); + virtual bool updateSourceEvent(const QString &sensorName); + + protected slots: + void updateSensors(); + void updateMonitorsList(); + + private: + QStringList m_sensors; + QTimer* m_timer; + int m_waitingFor; +}; + +K_EXPORT_PLASMA_DATAENGINE(systemmonitor, SystemMonitorEngine) + +#endif + diff --git a/plasma/generic/dataengines/tasks/CMakeLists.txt b/plasma/generic/dataengines/tasks/CMakeLists.txt new file mode 100644 index 00000000..ac9465c5 --- /dev/null +++ b/plasma/generic/dataengines/tasks/CMakeLists.txt @@ -0,0 +1,14 @@ +set(tasks_engine_SRCS + tasksengine.cpp + tasksource.cpp + taskservice.cpp + taskjob.cpp + virtualdesktopssource.cpp +) + +kde4_add_plugin(plasma_engine_tasks ${tasks_engine_SRCS}) +target_link_libraries(plasma_engine_tasks ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} taskmanager) + +install(TARGETS plasma_engine_tasks DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-tasks.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES tasks.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) diff --git a/plasma/generic/dataengines/tasks/plasma-dataengine-tasks.desktop b/plasma/generic/dataengines/tasks/plasma-dataengine-tasks.desktop new file mode 100644 index 00000000..64239f1b --- /dev/null +++ b/plasma/generic/dataengines/tasks/plasma-dataengine-tasks.desktop @@ -0,0 +1,156 @@ +[Desktop Entry] +Name=Window Information +Name[ar]=معلومات النافذة +Name[ast]=Información de ventana +Name[be@latin]=Źviestki z akna +Name[bg]=Данни за прозорци +Name[bn]=উইণ্ডো তথ্য +Name[bn_IN]=উইন্ডো সংক্রান্ড তথ্য +Name[bs]=podaci o prozorima +Name[ca]=Informació de les finestres +Name[ca@valencia]=Informació de les finestres +Name[cs]=Informace o okně +Name[csb]=Wëdowiédzô òknów +Name[da]=Vinduesinformation +Name[de]=Fensterinformationen +Name[el]=Πληροφορίες παραθύρου +Name[en_GB]=Window Information +Name[eo]=Fenestra Informo +Name[es]=Información de ventana +Name[et]=Akende teave +Name[eu]=Leihoari buruzko informazioa +Name[fi]=Ikkunatiedot +Name[fr]=Informations sur la fenêtre +Name[fy]=Finster ynformaasje +Name[ga]=Eolas Faoin Fhuinneog +Name[gl]=Información de xanelas +Name[gu]=વિન્ડો માહિતી +Name[he]=מידע על חלון +Name[hi]=विंडो जानकारी +Name[hne]=विंडो जानकारी +Name[hr]=Podaci o prozorima +Name[hu]=Ablakjellemzők +Name[ia]=Information de fenestra +Name[id]=Informasi Jendela +Name[is]=Gluggaupplýsingar +Name[it]=Informazioni sulle finestre +Name[ja]=ウィンドウの情報 +Name[kk]=Терезенің мәліметі +Name[km]=ព័ត៌មាន​បង្អួច +Name[kn]=ಕಿಟಕಿ ಮಾಹಿತಿ +Name[ko]=창 정보 +Name[ku]=Agahiya Paceyê +Name[lt]=Lango informacija +Name[lv]=Logu informācija +Name[mk]=Информации за прозорец +Name[ml]=വിന്‍ഡോ വിവരം +Name[mr]=चौकट माहिती +Name[nb]=Vindusinformasjon +Name[nds]=Finster-Informatschonen +Name[nl]=Vensterinformatie +Name[nn]=Vindaugsinformasjon +Name[or]=ୱିଣ୍ଡୋ ସୂଚନା +Name[pa]=ਵਿੰਡੋ ਜਾਣਕਾਰੀ +Name[pl]=Informacje o oknie +Name[pt]=Informação das Janelas +Name[pt_BR]=Informações da janela +Name[ro]=Informații fereastră +Name[ru]=Сведения об окне +Name[si]=කවුළු තොරතුරු +Name[sk]=Informácie o oknách +Name[sl]=Podatki o oknih +Name[sr]=подаци о прозорима +Name[sr@ijekavian]=подаци о прозорима +Name[sr@ijekavianlatin]=podaci o prozorima +Name[sr@latin]=podaci o prozorima +Name[sv]=Fönsterinformation +Name[ta]=Window Information +Name[tg]=Сведения об окне +Name[th]=ข้อมูลของหน้าต่าง +Name[tr]=Pencere Bilgileri +Name[ug]=كۆزنەك ئۇچۇرى +Name[uk]=Інформація про вікна +Name[wa]=Informåcions sol finiesse +Name[x-test]=xxWindow Informationxx +Name[zh_CN]=窗口信息 +Name[zh_TW]=視窗資訊 +Comment=Information and management services for all available windows. +Comment[ar]=معلومات و خدمات الإدارة لجميع النوافذ المتاحة. +Comment[ast]=Información y servicios de xestión pa toles ventanes disponibles. +Comment[bg]=Данни и услуги за управление на всички налични прозорци. +Comment[bs]=Servisi za podatke i upravljanje svim dostupnim prozorima. +Comment[ca]=Serveis d'informació i gestió de totes les finestres disponibles. +Comment[ca@valencia]=Serveis d'informació i gestió de totes les finestres disponibles. +Comment[cs]=Informace a správa služeb pro všechna dostupná okna. +Comment[da]=Information og håndteringstjenester for alle tilgængelige vinduer. +Comment[de]=Informationen und Verwaltungsdienste für alle verfügbaren Fenster. +Comment[el]=Πληροφορίες υπηρεσιών διαχείρισης για όλα τα διαθέσιμα παράθυρα. +Comment[en_GB]=Information and management services for all available windows. +Comment[eo]=Informado kaj servmastrumado por ĉiuj disponeblaj fenestroj. +Comment[es]=Información y servicios de gestión para todas las ventanas disponibles. +Comment[et]=Teave kõikide akende kohta ja vastavad haldamisteenused. +Comment[eu]=Informazioa eta kudeaketa-zerbitzuak leiho erabilgarri guztientzat. +Comment[fi]=Tieto- ja hallintapalveluja kaikkille käytettävissä oleville ikkunoille. +Comment[fr]=Services d'informations et de gestion pour toutes les fenêtres disponibles. +Comment[fy]=Ynformaasje en behear tsjinsten foar alle beskikbere finsters. +Comment[gl]=Servizos de información e xestión de todas as xanelas dispoñíbeis. +Comment[he]=שירותי מידע וניהול עבור כל החלונות הזמינים. +Comment[hr]=Usluge informiranja i upravljanja za sve dostupne prozore +Comment[hu]=Jellemzők és kezelő szolgáltatások az összes elérhető ablakhoz. +Comment[ia]=Servicios de gestion e information pro omne fenestras disponibile. +Comment[id]=Layanan informasi dan manajemen untuk semua jendela yang tersedia. +Comment[is]=Upplýsinga- og stýringaþjónusta fyrir alla tiltæka glugga. +Comment[it]=Servizi di informazioni e gestione per tutte le finestre disponibili. +Comment[ja]=すべての利用可能なウィンドウ用の情報・管理サービスです。 +Comment[kk]=Бүкіл бар терезелерінің мәліметі мен басқару қызметтері. +Comment[km]=ព័ត៌មាន​អំពី​សេវា និង​ការ​គ្រប់គ្រង​សម្រាប់​វីនដូ​ដែល​អាច​ប្រើ​បានទាំង​អស់ ។ +Comment[kn]=ಲಭ್ಯವಿರುವ ಎಲ್ಲಾ ವಿಂಡೋಗಳಿಗಾಗಿನ ಮಾಹಿತಿ ಹಾಗು ನಿರ್ವಹಣಾ ಸೇವೆಗಳು. +Comment[ko]=사용 가능한 창에 대한 정보 및 관리 서비스입니다. +Comment[lt]=Informacija ir tvarkymo tarnybos visiems prieinamiems langams. +Comment[lv]=Informācija un pārvaldības servisi visiem pieejamajiem logiem. +Comment[mk]=Информации и менаџирање сервиси за сите достапни прозорци. +Comment[ml]=ലഭ്യമായ ജാലകങ്ങള്‍ക്കുള്ള വിവരണങ്ങളും നേതൃത്വ സേവനങ്ങളും. +Comment[mr]=सर्व उपलब्ध चौकटींकरिता माहिती व व्यवस्थापन सेवा +Comment[nb]=Informasjon og styringstjenester for alle tilgjengelige vinduer. +Comment[nds]=Informatschonen un Pleegdeensten för all verföögbor Finstern +Comment[nl]=Informatie- en beheerservices voor alle beschikbare vensters. +Comment[nn]=Informasjon om og handteringstenester for alle tilgjengelege vindauge. +Comment[pa]=ਸਭ ਉਪਲੱਬਧ ਵਿੰਡੋਜ਼ ਲਈ ਜਾਣਕਾਰੀ ਅਤੇ ਪਰਬੰਧ ਸਰਵਿਸਾਂ +Comment[pl]=Informacje i usługi zarządzania dla wszystkich dostępnych okien. +Comment[pt]=Serviços de informação e gestão dos serviços para todas as janelas disponíveis. +Comment[pt_BR]=Informação e gerenciamento de serviços para todas as janelas disponíveis. +Comment[ro]=Servicii de informare și gestiune pentru toate ferestrele disponibile. +Comment[ru]=Информация и управление всеми доступными окнами. +Comment[si]=පවතින සියළු කවුළු සඳහා තොරතුරු හා පරිපාලන සේවා +Comment[sk]=Informačné a riadiace služby pre všetky dostupné okná. +Comment[sl]=Podatki o vseh razpoložljivih oknih in storitve za upravljanje oken. +Comment[sr]=Сервиси за податке и управљање свим доступним прозорима. +Comment[sr@ijekavian]=Сервиси за податке и управљање свим доступним прозорима. +Comment[sr@ijekavianlatin]=Servisi za podatke i upravljanje svim dostupnim prozorima. +Comment[sr@latin]=Servisi za podatke i upravljanje svim dostupnim prozorima. +Comment[sv]=Information om och hanteringstjänster för alla tillgängliga fönster. +Comment[tg]=Иттилоот ва идоракунии хизматҳо барои ҳамаи тирезаҳои дастрас. +Comment[th]=ข้อมูลรายละเอียดและบริการการจัดการต่าง ๆ สำหรับหน้าต่างที่มีใช้งานทั้งหมด +Comment[tr]=Kullanılabilir tüm pencereler için bilgi ve yönetim servisleri. +Comment[ug]=ئىشلەتكىلى بولىدىغان ھەممە كۆزنەكلەرنىڭ ئۇچۇرى ۋە باشقۇرۇش مۇلازىمەتلىرى +Comment[uk]=Відомості щодо служб і керування ними для всіх доступних вікон. +Comment[vi]=Thông tin và các dịch vụ quản lý cho tất cả các cửa sổ hiện hữu. +Comment[wa]=Informåcions eyet siervices di manaedjmint po tos les purneas k' i gn a. +Comment[x-test]=xxInformation and management services for all available windows.xx +Comment[zh_CN]=全部可用窗口的信息和管理服务 +Comment[zh_TW]=所有可用的視窗的資訊與管理服務。 +Type=Service +Icon=user-desktop + +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-Library=plasma_engine_tasks + +X-KDE-PluginInfo-Author=Robert Knight +X-KDE-PluginInfo-Email=robertknight@gmail.com +X-KDE-PluginInfo-Name=tasks +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Windows and Tasks +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/dataengines/tasks/taskjob.cpp b/plasma/generic/dataengines/tasks/taskjob.cpp new file mode 100644 index 00000000..9145cfd7 --- /dev/null +++ b/plasma/generic/dataengines/tasks/taskjob.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2008 Alain Boyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "taskjob.h" + +TaskJob::TaskJob(TaskSource *source, const QString &operation, QMap ¶meters, QObject *parent) : + ServiceJob(source->objectName(), operation, parameters, parent), + m_source(source) +{ +} + +TaskJob::~TaskJob() +{ +} + +void TaskJob::start() +{ + if (!m_source->task()) { + return; + } + + // only a subset of task operations are exported + const QString operation = operationName(); + if (operation == "setMaximized") { + m_source->task()->setMaximized(parameters().value("maximized").toBool()); + setResult(true); + return; + } else if (operation == "setMinimized") { + m_source->task()->setIconified(parameters().value("minimized").toBool()); + setResult(true); + return; + } else if (operation == "setShaded") { + m_source->task()->setShaded(parameters().value("shaded").toBool()); + setResult(true); + return; + } else if (operation == "setFullScreen") { + m_source->task()->setFullScreen(parameters().value("fullScreen").toBool()); + setResult(true); + return; + } else if (operation == "setAlwaysOnTop") { + m_source->task()->setAlwaysOnTop(parameters().value("alwaysOnTop").toBool()); + setResult(true); + return; + } else if (operation == "setKeptBelowOthers") { + m_source->task()->setKeptBelowOthers(parameters().value("keptBelowOthers").toBool()); + setResult(true); + return; + } else if (operation == "toggleMaximized") { + m_source->task()->toggleMaximized(); + setResult(true); + return; + } else if (operation == "toggleMinimized") { + m_source->task()->toggleIconified(); + setResult(true); + return; + } else if (operation == "toggleShaded") { + m_source->task()->toggleShaded(); + setResult(true); + return; + } else if (operation == "toggleFullScreen") { + m_source->task()->toggleFullScreen(); + setResult(true); + return; + } else if (operation == "toggleAlwaysOnTop") { + m_source->task()->toggleAlwaysOnTop(); + setResult(true); + return; + } else if (operation == "toggleKeptBelowOthers") { + m_source->task()->toggleKeptBelowOthers(); + setResult(true); + return; + } else if (operation == "restore") { + m_source->task()->restore(); + setResult(true); + return; + } else if (operation == "resize") { + m_source->task()->resize(); + setResult(true); + return; + } else if (operation == "move") { + m_source->task()->move(); + setResult(true); + return; + } else if (operation == "raise") { + m_source->task()->raise(); + setResult(true); + return; + } else if (operation == "lower") { + m_source->task()->lower(); + setResult(true); + return; + } else if (operation == "activate") { + m_source->task()->activate(); + setResult(true); + return; + } else if (operation == "activateRaiseOrIconify") { + m_source->task()->activateRaiseOrIconify(); + setResult(true); + return; + } else if (operation == "close") { + m_source->task()->close(); + setResult(true); + return; + } else if (operation == "toDesktop") { + m_source->task()->toDesktop(parameters().value("desktop").toInt()); + setResult(true); + return; + } else if (operation == "toCurrentDesktop") { + m_source->task()->toCurrentDesktop(); + setResult(true); + return; + } else if (operation == "publishIconGeometry") { + m_source->task()->publishIconGeometry(parameters().value("geometry").toRect()); + setResult(true); + return; + } + + setResult(false); +} + +#include "taskjob.moc" diff --git a/plasma/generic/dataengines/tasks/taskjob.h b/plasma/generic/dataengines/tasks/taskjob.h new file mode 100644 index 00000000..147c3580 --- /dev/null +++ b/plasma/generic/dataengines/tasks/taskjob.h @@ -0,0 +1,48 @@ +/* + * Copyright 2008 Alain Boyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TASKJOB_H +#define TASKJOB_H + +// plasma +#include + +// own +#include "tasksource.h" + +/** + * Task Job + */ +class TaskJob : public Plasma::ServiceJob +{ + + Q_OBJECT + + public: + TaskJob(TaskSource *source, const QString &operation, QMap ¶meters, QObject *parent = NULL); + ~TaskJob(); + + protected: + void start(); + + private: + TaskSource *m_source; + +}; + +#endif // TASKJOB_H diff --git a/plasma/generic/dataengines/tasks/tasks.operations b/plasma/generic/dataengines/tasks/tasks.operations new file mode 100644 index 00000000..21b3de1b --- /dev/null +++ b/plasma/generic/dataengines/tasks/tasks.operations @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plasma/generic/dataengines/tasks/tasksengine.cpp b/plasma/generic/dataengines/tasks/tasksengine.cpp new file mode 100644 index 00000000..059bccbf --- /dev/null +++ b/plasma/generic/dataengines/tasks/tasksengine.cpp @@ -0,0 +1,129 @@ +/* + * Copyright 2007 Robert Knight + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "tasksengine.h" +#include "virtualdesktopssource.h" + +// own +#include "tasksource.h" + +TasksEngine::TasksEngine(QObject *parent, const QVariantList &args) : + Plasma::DataEngine(parent, args) +{ + Q_UNUSED(args); +} + +TasksEngine::~TasksEngine() +{ +} + +Plasma::Service *TasksEngine::serviceForSource(const QString &name) +{ + TaskSource *source = dynamic_cast(containerForSource(name)); + // if source does not exist or it represents a startup task, return a null service + if (!source || !source->task()) { + return Plasma::DataEngine::serviceForSource(name); + } + + // if source represent a proper task, return task service + Plasma::Service *service = source->createService(); + service->setParent(this); + return service; +} + +const QString TasksEngine::getStartupName(::TaskManager::Startup *startup) +{ + return startup->id().id(); +} + +const QString TasksEngine::getTaskName(::TaskManager::Task *task) +{ + return QString::number(task->window()); +} + +void TasksEngine::init() +{ + foreach (TaskManager::Task *task, TaskManager::TaskManager::self()->tasks()) { + Q_ASSERT(task); + taskAdded(task); + } + + TaskManager::TaskManager *manager = TaskManager::TaskManager::self(); + connect(manager, SIGNAL(startupAdded(::TaskManager::Startup*)), this, SLOT(startupAdded(::TaskManager::Startup*))); + connect(manager, SIGNAL(startupRemoved(::TaskManager::Startup*)), this, SLOT(startupRemoved(::TaskManager::Startup*))); + connect(manager, SIGNAL(taskAdded(::TaskManager::Task*)), this, SLOT(taskAdded(::TaskManager::Task*))); + connect(manager, SIGNAL(taskRemoved(::TaskManager::Task*)), this, SLOT(taskRemoved(::TaskManager::Task*))); +} + +void TasksEngine::startupRemoved(::TaskManager::Startup *startup) +{ + Q_ASSERT(startup); + // there is an event loop ref counting bug in Qt that prevents deleteLater() from working + // properly, so we need to remove the source our selves with a single shot + //removeSource(getStartupName(startup)); + if (Plasma::DataContainer *container = containerForSource(getStartupName(startup))) { + QTimer::singleShot(0, container, SLOT(deleteLater())); + } +} + +void TasksEngine::taskRemoved(::TaskManager::Task *task) +{ + Q_ASSERT(task); + // there is an event loop ref counting bug in Qt that prevents deleteLater() from working + // properly, so we need to remove the source our selves with a single shot + //removeSource(getTaskName(task)); + if (Plasma::DataContainer *container = containerForSource(getTaskName(task))) { + QTimer::singleShot(0, container, SLOT(deleteLater())); + } +} + +void TasksEngine::startupAdded(::TaskManager::Startup *startup) +{ + Q_ASSERT(startup); + if (!containerForSource(getStartupName(startup))) { + TaskSource *taskSource = new TaskSource(startup, this); + connect(startup, SIGNAL(changed(::TaskManager::TaskChanges)), taskSource, SLOT(updateStartup(::TaskManager::TaskChanges))); + addSource(taskSource); + } +} + +void TasksEngine::taskAdded(::TaskManager::Task *task) +{ + Q_ASSERT(task); + if (!containerForSource(getTaskName(task))) { + TaskSource *taskSource = new TaskSource(task, this); + connect(task, SIGNAL(changed(::TaskManager::TaskChanges)), taskSource, SLOT(updateTask(::TaskManager::TaskChanges))); + connect(TaskManager::TaskManager::self(), SIGNAL(desktopChanged(int)), taskSource, SLOT(updateDesktop())); + connect(TaskManager::TaskManager::self(), SIGNAL(activityChanged(QString)), taskSource, SLOT(updateActivity())); + addSource(taskSource); + } +} + +bool TasksEngine::sourceRequestEvent(const QString &source) +{ + if (source == "virtualDesktops") { + addSource(new VirtualDesktopsSource); + return true; + } + + return false; +} + +K_EXPORT_PLASMA_DATAENGINE(tasks, TasksEngine) + +#include "tasksengine.moc" diff --git a/plasma/generic/dataengines/tasks/tasksengine.h b/plasma/generic/dataengines/tasks/tasksengine.h new file mode 100644 index 00000000..982649f8 --- /dev/null +++ b/plasma/generic/dataengines/tasks/tasksengine.h @@ -0,0 +1,75 @@ +/* + * Copyright 2007 Robert Knight + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TASKSENGINE_H +#define TASKSENGINE_H + +// plasma +#include +#include + +// libtaskmanager +#include + +namespace TaskManager +{ + class Startup; + class Task; +} // namespace TaskManager + +/** + * Tasks Data Engine + * + * This engine provides information regarding tasks (windows that are currently open) + * as well as startup tasks (windows that are about to open). + * Each task and startup is represented by a unique source. Sources are added and removed + * as windows are opened and closed. You cannot request a customized source. + * + * A service is also provided for each task. It exposes some operations that can be + * performed on the windows (ex: maximize, minimize, activate). + * + * The data and operations are provided and handled by the taskmanager library. + * It should be noted that only a subset of data and operations are exposed. + */ +class TasksEngine : public Plasma::DataEngine +{ + + Q_OBJECT + + public: + TasksEngine(QObject *parent, const QVariantList &args); + ~TasksEngine(); + Plasma::Service *serviceForSource(const QString &name); + + protected: + static const QString getStartupName(::TaskManager::Startup *startup); + static const QString getTaskName(::TaskManager::Task *task); + virtual void init(); + bool sourceRequestEvent(const QString &source); + + private slots: + void startupAdded(::TaskManager::Startup *startup); + void startupRemoved(::TaskManager::Startup *startup); + void taskAdded(::TaskManager::Task *task); + void taskRemoved(::TaskManager::Task *task); + + private: + friend class TaskSource; +}; + +#endif // TASKSENGINE_H diff --git a/plasma/generic/dataengines/tasks/taskservice.cpp b/plasma/generic/dataengines/tasks/taskservice.cpp new file mode 100644 index 00000000..826c1ee0 --- /dev/null +++ b/plasma/generic/dataengines/tasks/taskservice.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2008 Alain Boyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "taskservice.h" + +// own +#include "taskjob.h" + +TaskService::TaskService(TaskSource *source) : + Plasma::Service(source), + m_source(source) +{ + setName("tasks"); +} + +TaskService::~TaskService() +{ +} + +Plasma::ServiceJob *TaskService::createJob(const QString &operation, QMap ¶meters) +{ + return new TaskJob(m_source, operation, parameters, this); +} + +#include "taskservice.moc" diff --git a/plasma/generic/dataengines/tasks/taskservice.h b/plasma/generic/dataengines/tasks/taskservice.h new file mode 100644 index 00000000..3ad92ab8 --- /dev/null +++ b/plasma/generic/dataengines/tasks/taskservice.h @@ -0,0 +1,48 @@ +/* + * Copyright 2008 Alain Boyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TASKSERVICE_H +#define TASKSERVICE_H + +// plasma +#include +#include + +// own +#include "tasksource.h" + +/** + * Task Service + */ +class TaskService : public Plasma::Service +{ + + Q_OBJECT + + public: + TaskService(TaskSource *source); + ~TaskService(); + + protected: + Plasma::ServiceJob *createJob(const QString &operation, QMap ¶meters); + + private: + TaskSource *m_source; +}; + +#endif // TASKSERVICE_H diff --git a/plasma/generic/dataengines/tasks/tasksource.cpp b/plasma/generic/dataengines/tasks/tasksource.cpp new file mode 100644 index 00000000..ff377c84 --- /dev/null +++ b/plasma/generic/dataengines/tasks/tasksource.cpp @@ -0,0 +1,184 @@ +/* + * Copyright 2008 Alain Boyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "tasksource.h" + +// own +#include "tasksengine.h" +#include "taskservice.h" + +TaskSource::TaskSource(::TaskManager::Startup *startup, QObject *parent) + : Plasma::DataContainer(parent), + m_startup(startup) +{ + setObjectName(TasksEngine::getStartupName(startup)); + setData("startup", true); + setData("task", false); + updateStartup(TaskManager::TaskUnchanged); +} + +TaskSource::TaskSource(::TaskManager::Task *task, QObject *parent) + : Plasma::DataContainer(parent), + m_task(task) +{ + setObjectName(TasksEngine::getTaskName(task)); + setData("startup", false); + setData("task", true); + setData("className", task->className()); + setData("classClass", task->classClass()); + updateTask(TaskManager::EverythingChanged); +} + +TaskSource::~TaskSource() +{ +} + +Plasma::Service *TaskSource::createService() +{ + return new TaskService(this); +} + +::TaskManager::Task *TaskSource::task() +{ + return m_task.data(); +} + +void TaskSource::updateStartup(::TaskManager::TaskChanges startupChanges) +{ + ::TaskManager::Startup *startup = m_startup.data(); + if (!startup) { + return; + } + + switch (startupChanges) { + case TaskManager::TaskUnchanged: + setData("text", startup->text()); + setData("bin", startup->bin()); + setData("icon", startup->icon()); + } + checkForUpdate(); +} + +void TaskSource::updateTask(::TaskManager::TaskChanges taskChanges) +{ + ::TaskManager::Task *taskPtr = m_task.data(); + if (!taskPtr) { + return; + } + + // only a subset of task information is exported + switch (taskChanges) { + case TaskManager::EverythingChanged: + setData("name", taskPtr->name()); + setData("visibleName", taskPtr->visibleName()); + setData("visibleNameWithState", taskPtr->visibleNameWithState()); + setData("maximized", taskPtr->isMaximized()); + setData("minimized", taskPtr->isMinimized()); + setData("shaded", taskPtr->isShaded()); + setData("fullScreen", taskPtr->isFullScreen()); + setData("alwaysOnTop", taskPtr->isAlwaysOnTop()); + setData("keptBelowOthers", taskPtr->isKeptBelowOthers()); + setData("active", taskPtr->isActive()); + setData("onTop", taskPtr->isOnTop()); + setData("onCurrentDesktop", taskPtr->isOnCurrentDesktop()); + setData("onAllDesktops", taskPtr->isOnAllDesktops()); + setData("desktop", taskPtr->desktop()); + setData("onCurrentActivity", taskPtr->isOnCurrentActivity()); + setData("onAllActivities", taskPtr->isOnAllActivities()); + setData("activities", taskPtr->activities()); + setData("icon", taskPtr->icon()); + setData("actionMinimize", taskPtr->info().actionSupported(NET::ActionMinimize)); + setData("actionMaximize", taskPtr->info().actionSupported(NET::ActionMax)); + setData("actionShade", taskPtr->info().actionSupported(NET::ActionShade)); + setData("actionResize", taskPtr->info().actionSupported(NET::ActionResize)); + setData("actionMove", taskPtr->info().actionSupported(NET::ActionMove)); + setData("actionClose", taskPtr->info().actionSupported(NET::ActionClose)); + setData("actionChangeDesktop", taskPtr->info().actionSupported(NET::ActionChangeDesktop)); + setData("actionFullScreen", taskPtr->info().actionSupported(NET::ActionFullScreen)); + break; + case TaskManager::IconChanged: + setData("icon", taskPtr->icon()); + break; + case TaskManager::NameChanged: + setData("name", taskPtr->name()); + setData("visibleName", taskPtr->visibleName()); + setData("visibleNameWithState", taskPtr->visibleNameWithState()); + break; + case TaskManager::StateChanged: + setData("maximized", taskPtr->isMaximized()); + setData("minimized", taskPtr->isMinimized()); + setData("shaded", taskPtr->isShaded()); + setData("fullScreen", taskPtr->isFullScreen()); + setData("alwaysOnTop", taskPtr->isAlwaysOnTop()); + setData("keptBelowOthers", taskPtr->isKeptBelowOthers()); + setData("active", taskPtr->isActive()); + setData("onTop", taskPtr->isOnTop()); + setData("visibleNameWithState", taskPtr->visibleNameWithState()); + break; + case TaskManager::DesktopChanged: + setData("onCurrentDesktop", taskPtr->isOnCurrentDesktop()); + setData("onAllDesktops", taskPtr->isOnAllDesktops()); + setData("desktop", taskPtr->desktop()); + break; + case TaskManager::ActivitiesChanged: + setData("onCurrentActivity", taskPtr->isOnCurrentActivity()); + setData("onAllActivities", taskPtr->isOnAllActivities()); + setData("activities", taskPtr->activities()); + case TaskManager::ActionsChanged: + setData("actionMinimize", taskPtr->info().actionSupported(NET::ActionMinimize)); + setData("actionMaximize", taskPtr->info().actionSupported(NET::ActionMax)); + setData("actionShade", taskPtr->info().actionSupported(NET::ActionShade)); + setData("actionResize", taskPtr->info().actionSupported(NET::ActionResize)); + setData("actionMove", taskPtr->info().actionSupported(NET::ActionMove)); + setData("actionClose", taskPtr->info().actionSupported(NET::ActionClose)); + setData("actionChangeDesktop", taskPtr->info().actionSupported(NET::ActionChangeDesktop)); + setData("actionFullScreen", taskPtr->info().actionSupported(NET::ActionFullScreen)); + break; + default: + break; + } + checkForUpdate(); +} + +void TaskSource::updateDesktop() +{ + if (!m_task) { + return; + } + + const bool onCurrentDesktop = m_task.data()->isOnCurrentDesktop(); + if (data()["onCurrentDesktop"].toBool() != onCurrentDesktop) { + setData("onCurrentDesktop", onCurrentDesktop); + checkForUpdate(); + } +} + +void TaskSource::updateActivity() +{ + if (!m_task) { + return; + } + + const bool onCurrentActivity = m_task.data()->isOnCurrentActivity(); + if (data()["onCurrentActivity"].toBool() != onCurrentActivity) { + setData("onCurrentActivity", onCurrentActivity); + checkForUpdate(); + } +} + +#include "tasksource.moc" diff --git a/plasma/generic/dataengines/tasks/tasksource.h b/plasma/generic/dataengines/tasks/tasksource.h new file mode 100644 index 00000000..6f4a0e80 --- /dev/null +++ b/plasma/generic/dataengines/tasks/tasksource.h @@ -0,0 +1,59 @@ +/* + * Copyright 2008 Alain Boyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TASKSOURCE_H +#define TASKSOURCE_H + +// plasma +#include + +// libtaskmanager +#include + +/** + * Task Source + * + * This custom DataContainer represents a task or startup task as a unique source. + * It holds a shared pointer to the task or startup task and is responsible for setting + * and updating the data exposed by the source. + */ +class TaskSource : public Plasma::DataContainer +{ + + Q_OBJECT + + public: + TaskSource(::TaskManager::Startup *startup, QObject *parent); + TaskSource(::TaskManager::Task *task, QObject *parent); + ~TaskSource(); + + Plasma::Service *createService(); + ::TaskManager::Task *task(); + + private slots: + void updateStartup(::TaskManager::TaskChanges startupChanges); + void updateTask(::TaskManager::TaskChanges taskChanges); + void updateDesktop(); + void updateActivity(); + + private: + QWeakPointer< ::TaskManager::Startup > m_startup; + QWeakPointer< ::TaskManager::Task > m_task; +}; + +#endif // TASKSOURCE_H diff --git a/plasma/generic/dataengines/tasks/virtualdesktopssource.cpp b/plasma/generic/dataengines/tasks/virtualdesktopssource.cpp new file mode 100644 index 00000000..163718fe --- /dev/null +++ b/plasma/generic/dataengines/tasks/virtualdesktopssource.cpp @@ -0,0 +1,51 @@ +/* + * Copyright 2010 Matthieu Gallien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License; 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 Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "virtualdesktopssource.h" + +#include + +VirtualDesktopsSource::VirtualDesktopsSource() : Plasma::DataContainer() +{ + setObjectName( QLatin1String("virtualDesktops" )); + connect(KWindowSystem::self(), SIGNAL(numberOfDesktopsChanged(int)), this, SLOT(updateDesktopNumber(int))); + connect(KWindowSystem::self(), SIGNAL(desktopNamesChanged()), this, SLOT(updateDesktopNames())); + updateDesktopNumber(KWindowSystem::self()->numberOfDesktops()); + updateDesktopNames(); +} + +VirtualDesktopsSource::~VirtualDesktopsSource() +{ + disconnect(KWindowSystem::self(), SIGNAL(numberOfDesktopsChanged(int)), this, SLOT(updateDesktopNumber(int))); +} + +void VirtualDesktopsSource::updateDesktopNumber(int desktop) +{ + setData("number", desktop); + checkForUpdate(); +} + +void VirtualDesktopsSource::updateDesktopNames() +{ + QList desktopNames; + for (int i = 0; i < KWindowSystem::self()->numberOfDesktops(); i++) { + desktopNames.append(KWindowSystem::self()->desktopName(i + 1)); + } + setData("names", desktopNames); + checkForUpdate(); +} diff --git a/plasma/generic/dataengines/tasks/virtualdesktopssource.h b/plasma/generic/dataengines/tasks/virtualdesktopssource.h new file mode 100644 index 00000000..3712d4b4 --- /dev/null +++ b/plasma/generic/dataengines/tasks/virtualdesktopssource.h @@ -0,0 +1,43 @@ +/* + * Copyright 2010 Matthieu Gallien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License; 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 Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef VIRTUALDESKTOPSSOURCE_H +#define VIRTUALDESKTOPSSOURCE_H + +// plasma +#include + +class VirtualDesktopsSource : public Plasma::DataContainer +{ + + Q_OBJECT + + public: + + VirtualDesktopsSource(); + + ~VirtualDesktopsSource(); + + private slots: + + void updateDesktopNumber(int desktop); + + void updateDesktopNames(); +}; + +#endif diff --git a/plasma/generic/dataengines/time/CMakeLists.txt b/plasma/generic/dataengines/time/CMakeLists.txt new file mode 100644 index 00000000..ebfc04c8 --- /dev/null +++ b/plasma/generic/dataengines/time/CMakeLists.txt @@ -0,0 +1,12 @@ +set(time_engine_SRCS + timeengine.cpp + timesource.cpp + solarsystem.cpp +) + +kde4_add_plugin(plasma_engine_time ${time_engine_SRCS}) +target_link_libraries(plasma_engine_time ${KDE4_KDECORE_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4_SOLID_LIBS}) + +install(TARGETS plasma_engine_time DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-dataengine-time.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) + diff --git a/plasma/generic/dataengines/time/plasma-dataengine-time.desktop b/plasma/generic/dataengines/time/plasma-dataengine-time.desktop new file mode 100644 index 00000000..d0dd521a --- /dev/null +++ b/plasma/generic/dataengines/time/plasma-dataengine-time.desktop @@ -0,0 +1,165 @@ +[Desktop Entry] +Name=Date and Time +Name[ar]=التاريخ و الوقت +Name[as]=তাৰিখ আৰু সময় +Name[ast]=Data y hora +Name[be@latin]=Data j čas +Name[bg]=Дата и час +Name[bn]=তারিখ এবং সময় +Name[bn_IN]=তারিখ ও সময় +Name[bs]=datum i vrijeme +Name[ca]=Data i hora +Name[ca@valencia]=Data i hora +Name[cs]=Datum a čas +Name[csb]=Datum ë czas +Name[da]=Dato og tid +Name[de]=Datum und Zeit +Name[el]=Ημερομηνία και ώρα +Name[en_GB]=Date and Time +Name[eo]=Dato kaj Tempo +Name[es]=Fecha y hora +Name[et]=Kuupäev ja kellaaeg +Name[eu]=Data eta ordua +Name[fa]=تاریخ و زمان +Name[fi]=Aika ja päiväys +Name[fr]=Date et heure +Name[fy]=Datum en tiid +Name[ga]=Dáta agus Am +Name[gl]=Data e hora +Name[gu]=તારીખ અને સમય +Name[he]=תאריך ושעה +Name[hi]=तारीख़ और समय +Name[hne]=तारीक अउ समय +Name[hr]=Datum i vrijeme +Name[hu]=Dátum és idő +Name[ia]=Data e Tempore +Name[id]=Tanggal dan Waktu +Name[is]=Dagur og tími +Name[it]=Data e ora +Name[ja]=日付と時刻 +Name[kk]=Күні мен уақыты +Name[km]=កាល​បរិច្ឆេទ និង​ពេលវេលា +Name[kn]=ದಿನಾಂಕ ಮತ್ತು ಸಮಯ +Name[ko]=날짜와 시간 +Name[ku]=Dîrok û Dem +Name[lt]=Data ir laikas +Name[lv]=Datums un laiks +Name[mai]=दिनाँक आ समय +Name[mk]=Датум и време +Name[ml]=തീയതിയും സമയവും +Name[mr]=दिनांक व वेळ +Name[nb]=Dato og klokkeslett +Name[nds]=Datum un Tiet +Name[nl]=Datum en tijd +Name[nn]=Dato og klokkeslett +Name[or]=ତାରିଖ ଏବଂ ସମୟ +Name[pa]=ਮਿਤੀ ਅਤੇ ਟਾਈਮ +Name[pl]=Data i czas +Name[pt]=Data e Hora +Name[pt_BR]=Data e hora +Name[ro]=Data și ora +Name[ru]=Дата и время +Name[si]=දිනය සහ වේලාව +Name[sk]=Dátum a čas +Name[sl]=Datum in čas +Name[sr]=датум и време +Name[sr@ijekavian]=датум и време +Name[sr@ijekavianlatin]=datum i vreme +Name[sr@latin]=datum i vreme +Name[sv]=Datum och tid +Name[ta]=Date and Time +Name[tg]=Сана ва вақт +Name[th]=วันและเวลา +Name[tr]=Tarih ve Saat +Name[ug]=چېسلا ۋە ۋاقىت +Name[uk]=Дата і час +Name[vi]=Ngày giờ +Name[wa]=Date eyet eure +Name[x-test]=xxDate and Timexx +Name[zh_CN]=日期和时间 +Name[zh_TW]=日期與時間 +Comment=Date and time by timezone +Comment[ar]=التاريخ و الوقت بواسطة المنطقة الزمنية +Comment[ast]=Data y hora por estaya horaria +Comment[bg]=Настройки на датата и часа +Comment[bn]=টাইম-জোন অনুসারে তারিখ এবং সময় +Comment[bs]=Datum i vrijeme po vremenskoj zoni +Comment[ca]=Data i l'hora per zona horària +Comment[ca@valencia]=Data i l'hora per zona horària +Comment[cs]=Datum a čas podle časového pásma +Comment[csb]=Datum ë czas wedle czasowich conów +Comment[da]=Dato og tid efter tidszone +Comment[de]=Datum und Zeit nach Zeitzone +Comment[el]=Ημερομηνία και ώρα ανά ωρολογιακή ζώνη +Comment[en_GB]=Date and time by timezone +Comment[eo]=Dato kaj tempo laŭ horzonoj +Comment[es]=Fecha y hora por zona horaria +Comment[et]=Kuupäev ja kellaaeg ajavööndi põhjal +Comment[eu]=Data eta ordua ordu-eremuaren arabera +Comment[fi]=Aika ja päiväys aikavyöhykkeittäin +Comment[fr]=Date et heure par fuseau horaire +Comment[fy]=Datum en tiid mei help fan tiidsône +Comment[ga]=Dáta agus am de réir creasa ama +Comment[gl]=Data e hora segundo o fuso horario +Comment[gu]=સમયવિસ્તાર વડે તારીખ અને સમય +Comment[he]=תאריך ושעה לפי אזור זמן +Comment[hi]=तारीख़ तथा समय समयक्षेत्र हिसाब से +Comment[hr]=Datum i vrijeme po vremenskoj zoni +Comment[hu]=Dátum és idő (időzónánként) +Comment[ia]=Data e tempore per fuso horari +Comment[id]=Tanggal dan waktu menurut zona waktu +Comment[is]=Stillingar dagssetningar og klukku eftir tímabeltum +Comment[it]=Data e ora per fuso orario +Comment[ja]=タイムゾーンの日付と時刻 +Comment[kk]=Уақыт белдеуінің күн мен уақыты +Comment[km]=កាលបរិច្ឆេទ និង​ពេលវេលា​តាម​តំបន់​ពេលវេលា +Comment[kn]=ಕಾಲವಲಯದಿಂದ ದಿನಾಂಕ ಮತ್ತು ಸಮಯ +Comment[ko]=시간대에 따른 날짜와 시간 +Comment[lt]=Data ir laikas pagal laiko juostas +Comment[lv]=Datums un laiks pa laika joslām +Comment[mk]=Датум и време според временска зона +Comment[ml]=തീയതിയും സമയവും സമയമേഖലയനുസരിച്ചു് +Comment[mr]=वेळक्षेत्रा प्रमाणे दिनांक व वेळ +Comment[nb]=Dato og klokkeslett ved tidssone +Comment[nds]=Datum un Tiet na Tietrebeet +Comment[nl]=Datum en tijd per tijdzone +Comment[nn]=Dato og klokkeslett i ulike tidssoner +Comment[pa]=ਮਿਤੀ ਅਤੇ ਟਾਈਮ ਸਮਾਂ-ਖੇਤਰ ਰਾਹੀਂ +Comment[pl]=Ustawienia daty i czasu na podstawie strefy czasowej +Comment[pt]=Data e hora pelo fuso-horário +Comment[pt_BR]=Data e hora por fuso horário +Comment[ro]=Data și ora după fusul orar +Comment[ru]=Дата и время в различных часовых поясах +Comment[si]=වේලා කලාපය අනුව දිනය සහ වේලාව +Comment[sk]=Dátum a čas podľa časového pásma +Comment[sl]=Datum in čas po časovnih pasovih +Comment[sr]=Датум и време по временској зони +Comment[sr@ijekavian]=Датум и вријеме по временској зони +Comment[sr@ijekavianlatin]=Datum i vrijeme po vremenskoj zoni +Comment[sr@latin]=Datum i vreme po vremenskoj zoni +Comment[sv]=Datum och tid enligt tidszon +Comment[tg]=Танзимоти сана ва вақт +Comment[th]=วันและเวลาตามเขตเวลา +Comment[tr]=Zaman dilimine göre tarih ve saat +Comment[ug]=ۋاقىت رايونىغا ئاساسەن چېسلا ۋە ۋاقىت تەمىنلەيدۇ +Comment[uk]=Дата і час за часовими поясами +Comment[vi]=Ngày giờ theo múi giờ +Comment[wa]=Date et eure pa coisse ås eures +Comment[x-test]=xxDate and time by timezonexx +Comment[zh_CN]=根据时区提供日期和时间 +Comment[zh_TW]=時區的日期和時間 +Type=Service +Icon=preferences-system-time + +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-Library=plasma_engine_time + +X-KDE-PluginInfo-Author=Aaron Seigo +X-KDE-PluginInfo-Email=aseigo@kde.org +X-KDE-PluginInfo-Name=time +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Date and Time +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/dataengines/time/solarsystem.cpp b/plasma/generic/dataengines/time/solarsystem.cpp new file mode 100644 index 00000000..82ca262e --- /dev/null +++ b/plasma/generic/dataengines/time/solarsystem.cpp @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2009 Petri Damsten + * + * 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, see . + */ + +#include "solarsystem.h" +#include +#include + +/* + * Mathematics, ideas, public domain code used for these classes from: + * http://www.stjarnhimlen.se/comp/tutorial.html + * http://www.stjarnhimlen.se/comp/riset.html + * http://www.srrb.noaa.gov/highlights/solarrise/azel.html + * http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html + * http://bodmas.org/astronomy/riset.html + * moontool.c by John Walker + * Wikipedia + */ + +Sun::Sun() + : SolarSystemObject() +{ +} + +void Sun::calcForDateTime(const QDateTime& local, int offset) +{ + SolarSystemObject::calcForDateTime(local, offset); + + N = 0.0; + i = 0.0; + w = rev(282.9404 + 4.70935E-5 * m_day); + a = 1.0; + e = rev(0.016709 - 1.151E-9 * m_day); + M = rev(356.0470 + 0.9856002585 * m_day); + + calc(); +} + +void Sun::rotate(double* y, double* z) +{ + *y *= cosd(m_obliquity); + *z *= sind(m_obliquity); +} + +Moon::Moon(Sun *sun) + : m_sun(sun) +{ +} + +void Moon::calcForDateTime(const QDateTime& local, int offset) +{ + if (m_sun->dateTime() != local) { + m_sun->calcForDateTime(local, offset); + } + + SolarSystemObject::calcForDateTime(local, offset); + + N = rev(125.1228 - 0.0529538083 * m_day); + i = 5.1454; + w = rev(318.0634 + 0.1643573223 * m_day); + a = 60.2666; + e = 0.054900; + M = rev(115.3654 + 13.0649929509 * m_day); + + calc(); +} + +bool Moon::calcPerturbations(double *lo, double *la, double *r) +{ + double Ms = m_sun->meanAnomaly(); + double D = L - m_sun->meanLongitude(); + double F = L - N; + + *lo += -1.274 * sind(M - 2 * D) + +0.658 * sind(2 * D) + -0.186 * sind(Ms) + -0.059 * sind(2 * M - 2 * D) + -0.057 * sind(M - 2 * D + Ms) + +0.053 * sind(M + 2 * D) + +0.046 * sind(2 * D - Ms) + +0.041 * sind(M - Ms) + -0.035 * sind(D) + -0.031 * sind(M + Ms) + -0.015 * sind(2 * F - 2 * D) + +0.011 * sind(M - 4 * D); + *la += -0.173 * sind(F - 2 * D) + -0.055 * sind(M - F - 2 * D) + -0.046 * sind(M + F - 2 * D) + +0.033 * sind(F + 2 * D) + +0.017 * sind(2 * M + F); + *r += -0.58 * cosd(M - 2 * D) + -0.46 * cosd(2 * D); + return true; +} + +void Moon::topocentricCorrection(double* RA, double* dec) +{ + double HA = rev(siderealTime() - *RA); + double gclat = m_latitude - 0.1924 * sind(2 * m_latitude); + double rho = 0.99833 + 0.00167 * cosd(2 * m_latitude); + double mpar = asind(1 / rad); + double g = atand(tand(gclat) / cosd(HA)); + + *RA -= mpar * rho * cosd(gclat) * sind(HA) / cosd(*dec); + *dec -= mpar * rho * sind(gclat) * sind(g - *dec) / sind(g); +} + +double Moon::phase() +{ + return rev(m_eclipticLongitude - m_sun->lambda()); +} + +void Moon::rotate(double* y, double* z) +{ + double t = *y; + *y = t * cosd(m_obliquity) - *z * sind(m_obliquity); + *z = t * sind(m_obliquity) + *z * cosd(m_obliquity); +} + +void SolarSystemObject::calc() +{ + double x, y, z; + double la, r; + + L = rev(N + w + M); + double E0 = 720.0; + double E = M + (180.0 / M_PI) * e * sind(M) * (1.0 + e * cosd(M)); + for (int j = 0; fabs(E0 - E) > 0.005 && j < 10; ++j) { + E0 = E; + E = E0 - (E0 - (180.0 / M_PI) * e * sind(E0) - M) / (1 - e * cosd(E0)); + } + x = a * (cosd(E) - e); + y = a * sind(E) * sqrt(1.0 - e * e); + r = sqrt(x * x + y * y); + double v = rev(atan2d(y, x)); + m_lambda = rev(v + w); + x = r * (cosd(N) * cosd(m_lambda) - sind(N) * sind(m_lambda) * cosd(i)); + y = r * (sind(N) * cosd(m_lambda) + cosd(N) * sind(m_lambda) * cosd(i)); + z = r * sind(m_lambda); + if (!qFuzzyCompare(i, 0.0)) { + z *= sind(i); + } + toSpherical(x, y, z, &m_eclipticLongitude, &la, &r); + if (calcPerturbations(&m_eclipticLongitude, &la, &r)) { + toRectangular(m_eclipticLongitude, la, r, &x, &y, &z); + } + rotate(&y, &z); + toSpherical(x, y, z, &RA, &dec, &rad); + topocentricCorrection(&RA, &dec); + + HA = rev(siderealTime() - RA); + x = cosd(HA) * cosd(dec) * sind(m_latitude) - sind(dec) * cosd(m_latitude); + y = sind(HA) * cosd(dec); + z = cosd(HA) * cosd(dec) * cosd(m_latitude) + sind(dec) * sind(m_latitude); + m_azimuth = atan2d(y, x) + 180.0; + m_altitude = asind(z); +} + +double SolarSystemObject::siderealTime() +{ + double UT = m_utc.time().hour() + m_utc.time().minute() / 60.0 + + m_utc.time().second() / 3600.0; + double GMST0 = rev(282.9404 + 4.70935E-5 * m_day + 356.0470 + 0.9856002585 * m_day + 180.0); + return GMST0 + UT * 15.0 + m_longitude; +} + +void SolarSystemObject::calcForDateTime(const QDateTime& local, int offset) +{ + m_local = local; + m_utc = local.addSecs(-offset); + m_day = 367 * m_utc.date().year() - (7 * (m_utc.date().year() + + ((m_utc.date().month() + 9) / 12))) / 4 + + (275 * m_utc.date().month()) / 9 + m_utc.date().day() - 730530; + m_day += m_utc.time().hour() / 24.0 + m_utc.time().minute() / (24.0 * 60.0) + + m_utc.time().second() / (24.0 * 60.0 * 60.0); + m_obliquity = 23.4393 - 3.563E-7 * m_day; +} + +SolarSystemObject::SolarSystemObject() + : m_latitude(0.0) + , m_longitude(0.0) +{ +} + +SolarSystemObject::~SolarSystemObject() +{ +} + +void SolarSystemObject::setPosition(double latitude, double longitude) +{ + m_latitude = latitude; + m_longitude = longitude; +} + +double SolarSystemObject::rev(double x) +{ + return x - floor(x / 360.0) * 360.0; +} + +double SolarSystemObject::asind(double x) +{ + return asin(x) * 180.0 / M_PI; +} + +double SolarSystemObject::sind(double x) +{ + return sin(x * M_PI / 180.0); +} + +double SolarSystemObject::cosd(double x) +{ + return cos(x * M_PI / 180.0); +} + +double SolarSystemObject::tand(double x) +{ + return tan(x * M_PI / 180.0); +} + +double SolarSystemObject::atan2d(double y, double x) +{ + return atan2(y, x) * 180.0 / M_PI; +} + +double SolarSystemObject::atand(double x) +{ + return atan(x) * 180.0 / M_PI; +} + +void SolarSystemObject::toRectangular(double lo, double la, double r, double *x, double *y, double *z) +{ + *x = r * cosd(lo) * cosd(la); + *y = r * sind(lo) * cosd(la); + *z = r * sind(la); +} + +void SolarSystemObject::toSpherical(double x, double y, double z, double *lo, double *la, double *r) +{ + *r = sqrt(x * x + y * y + z * z); + *la = asind(z / *r); + *lo = rev(atan2d(y, x)); +} + +QPair SolarSystemObject::zeroPoints(QPointF p1, QPointF p2, QPointF p3) +{ + double a = ((p2.y() - p1.y()) * (p1.x() - p3.x()) + (p3.y() - p1.y()) * (p2.x() - p1.x())) / + ((p1.x() - p3.x()) * (p2.x() * p2.x() - p1.x() * p1.x()) + (p2.x() - p1.x()) * + (p3.x() * p3.x() - p1.x() * p1.x())); + double b = ((p2.y() - p1.y()) - a * (p2.x() * p2.x() - p1.x() * p1.x())) / (p2.x() - p1.x()); + double c = p1.y() - a * p1.x() * p1.x() - b * p1.x(); + double discriminant = b * b - 4.0 * a * c; + double z1 = -1.0, z2 = -1.0; + + if (discriminant >= 0.0) { + z1 = (-b + sqrt(discriminant)) / (2 * a); + z2 = (-b - sqrt(discriminant)) / (2 * a); + } + return QPair(z1, z2); +} + +QList< QPair > SolarSystemObject::timesForAngles(const QList& angles, + const QDateTime& dt, + int offset) +{ + QList altitudes; + QDate d = dt.date(); + QDateTime local(d, QTime(0, 0)); + for (int j = 0; j <= 25; ++j) { + calcForDateTime(local, offset); + altitudes.append(altitude()); + local = local.addSecs(60 * 60); + } + QList< QPair > result; + QTime rise, set; + foreach (double angle, angles) { + for (int j = 3; j <= 25; j += 2) { + QPointF p1((j - 2) * 60 * 60, altitudes[j - 2] - angle); + QPointF p2((j - 1) * 60 * 60, altitudes[j - 1] - angle); + QPointF p3(j * 60 * 60, altitudes[j] - angle); + QPair z = zeroPoints(p1, p2, p3); + if (z.first > p1.x() && z.first < p3.x()) { + if (p1.y() < 0.0) { + rise = QTime(0, 0).addSecs(z.first); + } else { + set = QTime(0, 0).addSecs(z.first); + } + } + if (z.second > p1.x() && z.second < p3.x()) { + if (p3.y() < 0.0) { + set = QTime(0, 0).addSecs(z.second); + } else { + rise = QTime(0, 0).addSecs(z.second); + } + } + } + result.append(QPair(QDateTime(d, rise), QDateTime(d, set))); + } + return result; +} + +double SolarSystemObject::calcElevation() +{ + double refractionCorrection; + + if (m_altitude > 85.0) { + refractionCorrection = 0.0; + } else { + double te = tand(m_altitude); + if (m_altitude > 5.0) { + refractionCorrection = 58.1 / te - 0.07 / (te * te * te) + + 0.000086 / (te * te * te * te * te); + } else if (m_altitude > -0.575) { + refractionCorrection = 1735.0 + m_altitude * + (-518.2 + m_altitude * (103.4 + m_altitude * + (-12.79 + m_altitude * 0.711) ) ); + } else { + refractionCorrection = -20.774 / te; + } + refractionCorrection = refractionCorrection / 3600.0; + } + return m_altitude + refractionCorrection; +} diff --git a/plasma/generic/dataengines/time/solarsystem.h b/plasma/generic/dataengines/time/solarsystem.h new file mode 100644 index 00000000..5ffdb5e1 --- /dev/null +++ b/plasma/generic/dataengines/time/solarsystem.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2009 Petri Damsten + * + * 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, see . + */ + +#ifndef SOLARSYSTEM_H +#define SOLARSYSTEM_H + +#include +#include +#include + +/* + * Mathematics, ideas, public domain code used for these classes from: + * http://www.stjarnhimlen.se/comp/tutorial.html + * http://www.stjarnhimlen.se/comp/riset.html + * http://www.srrb.noaa.gov/highlights/solarrise/azel.html + * http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html + * http://bodmas.org/astronomy/riset.html + * moontool.c by John Walker + * Wikipedia + */ + +class SolarSystemObject +{ + public: + SolarSystemObject(); + virtual ~SolarSystemObject(); + + double meanLongitude() const { return L; }; + double meanAnomaly() const { return M; }; + double siderealTime(); + double altitude() const { return m_altitude; }; + double azimuth() const { return m_azimuth; }; + double calcElevation(); + QDateTime dateTime() const { return m_local; }; + double lambda() const { return m_lambda; }; + double eclipticLongitude() const { return m_eclipticLongitude; }; + void setPosition(double latitude, double longitude); + + virtual void calcForDateTime(const QDateTime& local, int offset); + QList< QPair > timesForAngles(const QList& angles, + const QDateTime& dt, + int offset); + + protected: + void calc(); + virtual bool calcPerturbations(double*, double*, double*) { return false; }; + virtual void rotate(double*, double*) { }; + virtual void topocentricCorrection(double*, double*) { }; + + inline double rev(double x); + inline double asind(double x); + inline double sind(double x); + inline double cosd(double x); + inline double atand(double x); + inline double tand(double x); + inline double atan2d(double y, double x); + void toRectangular(double lo, double la, double r, double *x, double *y, double *z); + void toSpherical(double x, double y, double z, double *lo, double *la, double *r); + QPair zeroPoints(QPointF p1, QPointF p2, QPointF p3); + + double N; + double i; + double w; + double a; + double e; + double M; + double m_obliquity; + + QDateTime m_utc; + QDateTime m_local; + double m_day; + double m_latitude; + double m_longitude; + + double L; + double rad; + double RA; + double dec; + double HA; + double m_altitude; + double m_azimuth; + double m_eclipticLongitude; + double m_lambda; +}; + +class Sun : public SolarSystemObject +{ + public: + Sun(); + virtual void calcForDateTime(const QDateTime& local, int offset); + + protected: + virtual void rotate(double*, double*); +}; + +class Moon : public SolarSystemObject +{ + public: + Moon(Sun *sun); + virtual ~Moon() {}; // to not delete the Sun + + virtual void calcForDateTime(const QDateTime& local, int offset); + double phase(); + + protected: + virtual bool calcPerturbations(double *RA, double *dec, double *r); + virtual void rotate(double*, double*); + virtual void topocentricCorrection(double*, double*); + + private: + Sun *m_sun; +}; + +#endif diff --git a/plasma/generic/dataengines/time/timeengine.cpp b/plasma/generic/dataengines/time/timeengine.cpp new file mode 100644 index 00000000..a59fc424 --- /dev/null +++ b/plasma/generic/dataengines/time/timeengine.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2007 Aaron Seigo + * Copyright 2008 Alex Merry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "timeengine.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "timesource.h" + +//timezone is defined in msvc +#ifdef timezone +#undef timezone +#endif + +TimeEngine::TimeEngine(QObject *parent, const QVariantList &args) + : Plasma::DataEngine(parent, args) +{ + Q_UNUSED(args) + setMinimumPollingInterval(333); + + // To have translated timezone names + // (effectively a noop if the catalog is already present). + KGlobal::locale()->insertCatalog("timezones4"); +} + +TimeEngine::~TimeEngine() +{ +} + +void TimeEngine::init() +{ + //QDBusInterface *ktimezoned = new QDBusInterface("org.kde.kded", "/modules/ktimezoned", "org.kde.KTimeZoned"); + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.connect(QString(), QString(), "org.kde.KTimeZoned", "configChanged", this, SLOT(tzConfigChanged())); + dbus.connect(QString(), "/org/kde/kcmshell_clock", "org.kde.kcmshell_clock", "clockUpdated", this, SLOT(clockSkewed())); + + connect( Solid::PowerManagement::notifier(), SIGNAL(resumingFromSuspend()), this , SLOT(clockSkewed()) ); +} + +void TimeEngine::clockSkewed() +{ + kDebug() << "Time engine Clock skew signaled"; + updateAllSources(); + forceImmediateUpdateOfAllVisualizations(); +} + +void TimeEngine::tzConfigChanged() +{ + TimeSource *s = qobject_cast(containerForSource("Local")); + + if (s) { + s->setTimeZone("Local"); + } + + updateAllSources(); +} + +QStringList TimeEngine::sources() const +{ + QStringList timezones(KSystemTimeZones::zones().keys()); + timezones << "Local"; + return timezones; +} + +bool TimeEngine::sourceRequestEvent(const QString &name) +{ + addSource(new TimeSource(name, this)); + return true; +} + +bool TimeEngine::updateSourceEvent(const QString &tz) +{ + TimeSource *s = qobject_cast(containerForSource(tz)); + + if (s) { + s->updateTime(); + scheduleSourcesUpdated(); + return true; + } + + return false; +} + +K_EXPORT_PLASMA_DATAENGINE(time, TimeEngine) + +#include "timeengine.moc" diff --git a/plasma/generic/dataengines/time/timeengine.h b/plasma/generic/dataengines/time/timeengine.h new file mode 100644 index 00000000..f2e1e469 --- /dev/null +++ b/plasma/generic/dataengines/time/timeengine.h @@ -0,0 +1,52 @@ +/* + * Copyright 2007 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TIMEENGINE_H +#define TIMEENGINE_H + +#include + +/** + * This engine provides the current date and time for a given + * timezone. Optionally it can also provide solar position info. + * + * "Local" is a special source that is an alias for the current + * timezone. + */ +class TimeEngine : public Plasma::DataEngine +{ + Q_OBJECT + + public: + TimeEngine(QObject *parent, const QVariantList &args); + ~TimeEngine(); + + void init(); + QStringList sources() const; + + protected: + bool sourceRequestEvent(const QString &name); + bool updateSourceEvent(const QString &source); + + protected Q_SLOTS: + void clockSkewed(); // call when system time changed and all clocks should be updated + void tzConfigChanged(); +}; + +#endif // TIMEENGINE_H diff --git a/plasma/generic/dataengines/time/timesource.cpp b/plasma/generic/dataengines/time/timesource.cpp new file mode 100644 index 00000000..fb3339ba --- /dev/null +++ b/plasma/generic/dataengines/time/timesource.cpp @@ -0,0 +1,259 @@ +/* + * Copyright 2009 Aaron Seigo + * + * Moon Phase: + * Copyright 1998,2000 Stephan Kulow + * Copyright 2009 by Davide Bettio + * + * Solar position: + * Copyright (C) 2009 Petri Damsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "timesource.h" + +#include + +#include +#include + +#include "solarsystem.h" + +//timezone is defined in msvc +#ifdef timezone +#undef timezone +#endif + +TimeSource::TimeSource(const QString &name, QObject *parent) + : Plasma::DataContainer(parent), + m_offset(0), + m_latitude(0), + m_longitude(0), + m_sun(0), + m_moon(0), + m_moonPosition(false), + m_solarPosition(false), + m_local(false) +{ + setObjectName(name); + setTimeZone(parseName(name)); +} + +void TimeSource::setTimeZone(const QString &tz) +{ + m_tzName = tz; + m_local = m_tzName == I18N_NOOP("Local"); + if (m_local) { + m_tzName = KSystemTimeZones::local().name(); + } + + const QString trTimezone = i18n(m_tzName.toUtf8()); + setData(I18N_NOOP("Timezone"), trTimezone); + + const QStringList tzParts = trTimezone.split('/', QString::SkipEmptyParts); + if (tzParts.count() == 1) { + // no '/' so just set it as the city + setData(I18N_NOOP("Timezone City"), trTimezone); + } else { + setData(I18N_NOOP("Timezone Continent"), tzParts.value(0)); + setData(I18N_NOOP("Timezone City"), tzParts.value(1)); + } + + updateTime(); +} + +TimeSource::~TimeSource() +{ + // First delete the moon, that does not delete the Sun, and then the Sun + // If the Sun is deleted before the moon, the moon has a invalid pointer + // to where the Sun was pointing. + delete m_moon; + delete m_sun; +} + +void TimeSource::updateTime() +{ + KTimeZone tz; + if (m_local) { + tz = KSystemTimeZones::local(); + } else { + tz = KSystemTimeZones::zone(m_tzName); + if (!tz.isValid()) { + tz = KSystemTimeZones::local(); + } + } + + int offset = tz.currentOffset(); + if (m_offset != offset) { + m_offset = offset; + setData(I18N_NOOP("Offset"), m_offset); + } + + QDateTime dt = m_userDateTime ? data()["DateTime"].toDateTime() + : KDateTime::currentDateTime(tz).dateTime(); + + if (m_solarPosition || m_moonPosition) { + const QDate prev = data()["Date"].toDate(); + const bool updateDailies = prev != dt.date(); + + if (m_solarPosition) { + if (updateDailies) { + addDailySolarPositionData(dt); + } + + addSolarPositionData(dt); + } + + if (m_moonPosition) { + if (updateDailies) { + addDailyMoonPositionData(dt); + } + + addMoonPositionData(dt); + } + } + + if (!m_userDateTime) { + setData(I18N_NOOP("Time"), dt.time()); + setData(I18N_NOOP("Date"), dt.date()); + setData(I18N_NOOP("DateTime"), dt); + } +} + +QString TimeSource::parseName(const QString &name) +{ + m_userDateTime = false; + if (!name.contains('|')) { + // the simple case where it's just a timezone request + return name; + } + + // the various keys we recognize + static const QString latitude = I18N_NOOP("Latitude"); + static const QString longitude = I18N_NOOP("Longitude"); + static const QString solar = I18N_NOOP("Solar"); + static const QString moon = I18N_NOOP("Moon"); + static const QString datetime = I18N_NOOP("DateTime"); + + // now parse out what we got handed in + const QStringList list = name.split('|', QString::SkipEmptyParts); + + // set initial values for latitude and longitude, if available + const KTimeZone timezone = ((list.at(0) == I18N_NOOP("Local")) ? KSystemTimeZones::local() : KSystemTimeZones::zone(list.at(0))); + + if (timezone.isValid() && timezone.latitude() != KTimeZone::UNKNOWN) { + m_latitude = timezone.latitude(); + m_longitude = timezone.longitude(); + } + + const int listSize = list.size(); + for (int i = 1; i < listSize; ++i) { + const QString arg = list[i]; + const int n = arg.indexOf('='); + + if (n != -1) { + const QString key = arg.mid(0, n); + const QString value = arg.mid(n + 1); + + if (key == latitude) { + m_latitude = value.toDouble(); + } else if (key == longitude) { + m_longitude = value.toDouble(); + } else if (key == datetime) { + QDateTime dt = QDateTime::fromString(value, Qt::ISODate); + if (dt.isValid()) { + setData(I18N_NOOP("DateTime"), dt); + setData(I18N_NOOP("Date"), dt.date()); + setData(I18N_NOOP("Time"), dt.time()); + m_userDateTime = true; + } + } + } else if (arg == solar) { + m_solarPosition = true; + } else if (arg == moon) { + m_moonPosition = true; + } + } + + // timezone is first item ... + return list.at(0); +} + +Sun* TimeSource::sun() +{ + if (!m_sun) { + m_sun = new Sun(); + } + m_sun->setPosition(m_latitude, m_longitude); + return m_sun; +} + +Moon* TimeSource::moon() +{ + if (!m_moon) { + m_moon = new Moon(sun()); + } + m_moon->setPosition(m_latitude, m_longitude); + return m_moon; +} + +void TimeSource::addMoonPositionData(const QDateTime &dt) +{ + Moon* m = moon(); + m->calcForDateTime(dt, m_offset); + setData("Moon Azimuth", m->azimuth()); + setData("Moon Zenith", 90 - m->altitude()); + setData("Moon Corrected Elevation", m->calcElevation()); + setData("MoonPhaseAngle", m->phase()); +} + +void TimeSource::addDailyMoonPositionData(const QDateTime &dt) +{ + Moon* m = moon(); + QList< QPair > times = m->timesForAngles( + QList() << -0.833, dt, m_offset); + setData("Moonrise", times[0].first); + setData("Moonset", times[0].second); + m->calcForDateTime(QDateTime(dt.date(), QTime(12,0)), m_offset); + setData("MoonPhase", int(m->phase() / 360.0 * 29.0)); +} + +void TimeSource::addSolarPositionData(const QDateTime &dt) +{ + Sun* s = sun(); + s->calcForDateTime(dt, m_offset); + setData("Azimuth", s->azimuth()); + setData("Zenith", 90.0 - s->altitude()); + setData("Corrected Elevation", s->calcElevation()); +} + +void TimeSource::addDailySolarPositionData(const QDateTime &dt) +{ + Sun* s = sun(); + QList< QPair > times = s->timesForAngles( + QList() << -0.833 << -6.0 << -12.0 << -18.0, dt, m_offset); + + setData("Sunrise", times[0].first); + setData("Sunset", times[0].second); + setData("Civil Dawn", times[1].first); + setData("Civil Dusk", times[1].second); + setData("Nautical Dawn", times[2].first); + setData("Nautical Dusk", times[2].second); + setData("Astronomical Dawn", times[3].first); + setData("Astronomical Dusk", times[3].second); +} + diff --git a/plasma/generic/dataengines/time/timesource.h b/plasma/generic/dataengines/time/timesource.h new file mode 100644 index 00000000..e733e45a --- /dev/null +++ b/plasma/generic/dataengines/time/timesource.h @@ -0,0 +1,62 @@ +/* + * Copyright 2009 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TIMESOURCE_H +#define TIMESOURCE_H + +#include + +#include + +class Sun; +class Moon; + +class TimeSource : public Plasma::DataContainer +{ + Q_OBJECT + +public: + explicit TimeSource(const QString &name, QObject *parent = 0); + ~TimeSource(); + void setTimeZone(const QString &name); + void updateTime(); + +private: + QString parseName(const QString &name); + void addMoonPositionData(const QDateTime &dt); + void addDailyMoonPositionData(const QDateTime &dt); + void addSolarPositionData(const QDateTime &dt); + void addDailySolarPositionData(const QDateTime &dt); + Sun* sun(); + Moon* moon(); + + QString m_tzName; + int m_offset; + double m_latitude; + double m_longitude; + Sun *m_sun; + Moon *m_moon; + bool m_moonPosition : 1; + bool m_solarPosition : 1; + bool m_userDateTime : 1; + bool m_local : 1; +}; + +#endif + diff --git a/plasma/generic/dataengines/weather/CMakeLists.txt b/plasma/generic/dataengines/weather/CMakeLists.txt new file mode 100644 index 00000000..57038a51 --- /dev/null +++ b/plasma/generic/dataengines/weather/CMakeLists.txt @@ -0,0 +1,7 @@ +ADD_SUBDIRECTORY(ions) + +SET(weather_SRCS weatherengine.cpp) +kde4_add_plugin(plasma_engine_weather ${weather_SRCS}) +TARGET_LINK_LIBRARIES (plasma_engine_weather ${KDE4_KIO_LIBS} ${KDE4_SOLID_LIBS} ${KDE4_PLASMA_LIBS} weather_ion) +INSTALL (TARGETS plasma_engine_weather DESTINATION ${PLUGIN_INSTALL_DIR}) +INSTALL (FILES plasma-dataengine-weather.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/dataengines/weather/Messages.sh b/plasma/generic/dataengines/weather/Messages.sh new file mode 100755 index 00000000..a0b026d9 --- /dev/null +++ b/plasma/generic/dataengines/weather/Messages.sh @@ -0,0 +1,10 @@ +#! /usr/bin/env bash +for file in ions/data/*.dat +do + awk -F'|' '$0 ~ /\|/ { + print "// i18n: file: '`basename $file`':"NR; + printf("i18nc(\"%s\", \"%s\");\n", $1, $2) + }' $file >> rc.cpp +done + +$XGETTEXT `find . -name \*.cpp` -o $podir/plasma_engine_weather.pot diff --git a/plasma/generic/dataengines/weather/ions/CMakeLists.txt b/plasma/generic/dataengines/weather/ions/CMakeLists.txt new file mode 100644 index 00000000..5e2a4ff3 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/CMakeLists.txt @@ -0,0 +1,27 @@ +# the Ion shared library +set (ionlib_SRCS ion.cpp) +kde4_add_library (weather_ion SHARED ${ionlib_SRCS}) +target_link_libraries (weather_ion ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) +target_link_libraries (weather_ion LINK_INTERFACE_LIBRARIES ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) + +set_target_properties(weather_ion PROPERTIES + VERSION 6.0.0 + SOVERSION 6 +) + +install (TARGETS weather_ion EXPORT kdeworkspaceLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) + +INSTALL (FILES ion.h + ion_export.h + DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/weather COMPONENT Devel) + +INSTALL (FILES includes/Ion + DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Plasma/Weather COMPONENT Devel) + +# the individual ion plugins +add_subdirectory(bbcukmet) +add_subdirectory(envcan) +add_subdirectory(noaa) +add_subdirectory(wetter.com) +add_subdirectory(debianweather) + diff --git a/plasma/generic/dataengines/weather/ions/bbcukmet/CMakeLists.txt b/plasma/generic/dataengines/weather/ions/bbcukmet/CMakeLists.txt new file mode 100644 index 00000000..476260c0 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/bbcukmet/CMakeLists.txt @@ -0,0 +1,8 @@ +SET (ion_bbcukmet_SRCS ion_bbcukmet.cpp) +kde4_add_plugin(ion_bbcukmet ${ion_bbcukmet_SRCS}) +target_link_libraries (ion_bbcukmet ${KDE4_SOLID_LIBS} weather_ion) + +INSTALL (FILES ion-bbcukmet.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + +INSTALL (TARGETS ion_bbcukmet DESTINATION ${PLUGIN_INSTALL_DIR}) + diff --git a/plasma/generic/dataengines/weather/ions/bbcukmet/ion-bbcukmet.desktop b/plasma/generic/dataengines/weather/ions/bbcukmet/ion-bbcukmet.desktop new file mode 100644 index 00000000..05b234b6 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/bbcukmet/ion-bbcukmet.desktop @@ -0,0 +1,158 @@ +[Desktop Entry] +Name=BBC Weather from UK MET Office +Name[ar]=الطقس BBC من مكتب الأرصاد الجوية البريطاني +Name[ast]=Meteoroloxía de la BBC de la Oficina meteorolóxica del Reinu Xuníu +Name[be@latin]=Nadvorje „BBC” ad „UK MET Office” +Name[bg]=Време от BBC (офис UK MET) +Name[bs]=Meteouslovi po Bi‑bi‑siju +Name[ca]=Meteorologia de la BBC des d'UK MET Office +Name[ca@valencia]=Meteorologia de la BBC des d'UK MET Office +Name[cs]=Počasí BBC z britského meteorologického úřadu +Name[csb]=Wiodro BBC z bura UK-MET +Name[da]=BBC Weather fra UK MET-kontoret +Name[de]=BBC-Wetter aus dem UK-MET-Büro +Name[el]=Καιρός του BBC από το γραφείο UK MET +Name[en_GB]=BBC Weather from UK MET Office +Name[eo]=BBC-vetero el UK-MET-oficejo +Name[es]=Meteorología de la BBC de la Oficina meteorológica del Reino Unido +Name[et]=BBC ilmateade Briti ilmateenistusest +Name[eu]=BBCren eguraldia UK MET Office-tik +Name[fi]=BBC:n säätiedot UK MET -toimistolta +Name[fr]=Météo de la BBC venant du « UK MET Office » +Name[fy]=BBC Weather fan UK MET kantoor +Name[ga]=Aimsir BBC ó Oifig UK MET +Name[gl]=Tempo da BBC desde a Oficina meteorolóxica do UK +Name[gu]=UK MET ઓફિસ તરફથી BBC હવામાન +Name[he]=BBC Weather מ־UK MET Office +Name[hi]=यूके एमईटी ऑफ़िस से बीबीसी मौसम +Name[hne]=यूके एमईटी आफिस से बीबीसी मौसम +Name[hr]=BBC vremenska prognoza iz UK MET ureda +Name[hu]=BBC időjárási adatok (UK MET) +Name[ia]=BBC Weather ex Officio UK MET +Name[id]=BBC Weather dari UK MET Office +Name[is]=BBC veður frá UK MET stofnuninni +Name[it]=Meteo BBC dall'ufficio meteorologico UK MET +Name[ja]=英国 Met Office の BBC Weather +Name[kk]=UK MET Оффистің BBC ауа райы болжамы +Name[km]=អាកាសធាតុ BBC ពី​ការិយាល័យ UK MET +Name[kn]=ಬಿಬಿಸಿ ಹವಾಮಾನ ವರದಿ (ಯುಕೆ ಪವನಶಾಸ್ತ್ರ (MET) ಕಛೇರಿಯಿಂದ) +Name[ko]=영국 MET 사무소의 BBC 날씨 +Name[lt]=BBC orai iš UK MET Office +Name[lv]=BBC Weather no UK MET Office +Name[mk]=BBC-временска прогноза од канцеларијата на UK MET +Name[ml]=യു കെ മെറ്റ് ഓഫീസില്‍ നിന്നുമുള്ള ബിബിസി കാലാവസ്ഥ +Name[mr]=UK MET ऑफिस पासून BBC हवामान +Name[nb]=BBC vær fra det britiske meteorologi-kontoret +Name[nds]=BBC-Weder vun't engelsche Wederkunn-Kontoor +Name[ne]=यूके एमइटी कार्यालयबाट बीबीसी मौसम +Name[nl]=BBC Weather van UK MET Office +Name[nn]=BBC-vêr frå UK MET Office +Name[or]=UK MET କାର୍ଯ୍ୟାଳୟରୁ BBC ପାଣିପାଗ +Name[pa]=UK MET ਆਫਿਸ ਤੋਂ BBC ਮੌਸਮ +Name[pl]=Pogoda BBC z biura UK MET +Name[pt]=Meteorologia da BBC do Escritório MET na GB +Name[pt_BR]=BBC Weather do escritório MET no Reino Unido +Name[ro]=Vremea BBC de la Biroul meteorologic britanic +Name[ru]=BBC Weather от UK MET Office +Name[se]=BBC-dálki UK MET Offices +Name[si]=UK MET කාර්‍යාලය වෙතින් BBC කාලගුණය +Name[sk]=Počasie BBC - UK MET Office +Name[sl]=BBC Weather iz UK MET Office +Name[sr]=Метеоуслови по Би‑би‑сију +Name[sr@ijekavian]=Метеоуслови по Би‑би‑сију +Name[sr@ijekavianlatin]=Meteouslovi po BBC‑u +Name[sr@latin]=Meteouslovi po BBC‑u +Name[sv]=BBC-väder från brittiska meteorologiska departementet +Name[ta]=BBC Weather from UK MET Office +Name[te]=UK MET కార్యాలయం నుండి BBC వాతావరణం +Name[tg]=BBC Weather от UK MET Office +Name[th]=พยากรณ์อากาศของ BBC จากสำนักงาน UK MET +Name[tr]=İngiltere MET Ofisi'nden BBC Hava Durumu +Name[ug]=UK MET ئىشخانىسى تەمىنلىگەن BBC ھاۋارايى ئۇچۇرى +Name[uk]=Погода BBC з метеорологічного офісу UK +Name[vi]=Thời tiết BBC từ Cơ quan MET UK +Name[wa]=Tins ki fwait BBC do UK MET Office +Name[x-test]=xxBBC Weather from UK MET Officexx +Name[zh_CN]=英国 MET 办公室提供的 BBC 天气报告 +Name[zh_TW]=BBC 天氣報告,從 UK MET 辦公室來 +Comment=XML Data from the UK MET Office +Comment[ar]=معلومات XML من مكتب الأرصاد الجوية البريطاني +Comment[ast]=Datos XML de la Oficina Meteorolóxica del Reinu Xuníu +Comment[be@latin]=Źviestki ŭ farmacie „XML” ad „UK MET Office” +Comment[bg]=XML данни от UK MET +Comment[bs]=IksML podaci Britanskog meteorološkog ofisa +Comment[ca]=Dades XML des d'UK MET Office +Comment[ca@valencia]=Dades XML des d'UK MET Office +Comment[cs]=XML data z britského meteorologického úřadu +Comment[csb]=XML-pòdôwczi z bura UK-MET +Comment[da]=XML-data fra UK MET-kontoret +Comment[de]=XML-Daten aus dem UK-MET-Büro +Comment[el]=Δεδομένα XML από το γραφείο UK MET +Comment[en_GB]=XML Data from the UK MET Office +Comment[eo]=XML-datumoj el la UK-MET-oficejo +Comment[es]=Datos XML de la Oficina Meteorológica del Reino Unido +Comment[et]=Briti ilmateenistuse XML-andmed +Comment[eu]=XML datuak UK MET Office-tik +Comment[fi]=XML-tietoa UK MET -toimistolta +Comment[fr]=Données météo au format XML provenant du « UK MET Office » +Comment[fy]=XML Data fan de UK MET kantoor +Comment[ga]=Sonraí XML ó Oifig UK MET +Comment[gl]=Datos XML da oficina meteorolóxica do UK +Comment[gu]=UK MET ઓફિસ તરફથી XML માહિતી +Comment[he]=מידע ב־XML מ־UK MET Office +Comment[hi]=यूके एमईटी ऑफ़िस से एक्सएमएल डाटा +Comment[hne]=यूके एमईटी आफिस से एक्सएमएल डाटा +Comment[hr]=XML podaci iz UK MET ureda +Comment[hu]=XML adatok a UK MET intézettől +Comment[ia]=Datos XML ex le Officio UK MET +Comment[id]=Data XML dari UK MET Office +Comment[is]=XML veðurgögn frá UK MET stofnuninni +Comment[it]=Dati XML dall'ufficio meteorologico UK MET +Comment[ja]=英国 Met Office の XML データ +Comment[kk]=UK MET Оффистің XML дерегі +Comment[km]=ទិន្នន័យ XML ពី​ការិយាល័យ UK MET +Comment[kn]=ಯುಕೆ ಪವನಶಾಸ್ತ್ರ ಕಛೇರಿ (MET) ಇಂದ XML ದತ್ತ +Comment[ko]=영국 MET 사무소의 XML 데이터 +Comment[lt]=XML duomenys iš UK MET Office +Comment[lv]=XML dati no UK MET Office +Comment[mk]=XML-податоци од канцеларијата на UK MET +Comment[ml]=യുകെ മെറ്റ് ഓഫീസില്‍ നിന്നുമുള്ള എക്സ്എംഎല്‍ ഡേറ്റാ +Comment[mr]=UK MET ऑफिस पासून XML माहिती +Comment[nb]=XML-data fra det britiske meteorologi-kontoret +Comment[nds]=XML-Daten vun't engelsche Wederkunn-Kontoor +Comment[ne]=यूके एमईटी कार्यालयबाट एक्सएमएल डेटा +Comment[nl]=XML-gegevens van UK MET Office +Comment[nn]=XML-data frå UK MET Office +Comment[or]=UK MET କାର୍ଯ୍ୟାଳୟରୁ XML ତଥ୍ୟ +Comment[pa]=UK MET ਆਫਿਸ ਤੋਂ XML ਡਾਟਾ +Comment[pl]=Dane XML z biura UK MET +Comment[pt]=Dados em XML do Escritório MET na GB +Comment[pt_BR]=Dados em XML do escritório MET no Reino Unido +Comment[ro]=Date XML de la Biroul meteorologic britanic +Comment[ru]=Данные в формате XML от UK MET Office +Comment[se]=XML-dáhtat UK MET Offices +Comment[si]=UK MET කාර්‍යාලය වෙතින් XML දත්ත +Comment[sk]=XML dáta z UK MET Office +Comment[sl]=Podatki XML iz UK MET Office +Comment[sr]=ИксМЛ подаци Британског метеоролошког офиса +Comment[sr@ijekavian]=ИксМЛ подаци Британског метеоролошког офиса +Comment[sr@ijekavianlatin]=XML podaci Britanskog meteorološkog ofisa +Comment[sr@latin]=XML podaci Britanskog meteorološkog ofisa +Comment[sv]=XML-data från brittiska meteorologiska departementet +Comment[ta]=XML Data from the UK MET Office +Comment[te]=UK MET కార్యాలయం నుండి XML డాటా +Comment[tg]=Маълумоти XML аз UK MET Office +Comment[th]=ข้อมูล XML จากสำนักงาน UK MET +Comment[tr]=İngiltere MET Ofisi'nden XML Verisi +Comment[ug]=UK MET ئىشخانىسى تەمىنلىگەن XML سانلىق-مەلۇمات ئۇچۇرى +Comment[uk]=Дані XML з метеорологічного офісу UK +Comment[wa]=Dinêyes XML då UK MET Office +Comment[x-test]=xxXML Data from the UK MET Officexx +Comment[zh_CN]=英国 MET 办公室提供的 XML 数据 +Comment[zh_TW]=從 UK MET 辦公室來的 XML 資料 +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-ParentApp=weatherengine +Type=Service +Icon=noneyet +X-KDE-Library=ion_bbcukmet +X-KDE-PluginInfo-Name=bbcukmet diff --git a/plasma/generic/dataengines/weather/ions/bbcukmet/ion_bbcukmet.cpp b/plasma/generic/dataengines/weather/ions/bbcukmet/ion_bbcukmet.cpp new file mode 100644 index 00000000..0db0e3a2 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/bbcukmet/ion_bbcukmet.cpp @@ -0,0 +1,964 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 * + ***************************************************************************/ + +/* Ion for BBC's Weather from the UK Met Office */ + +#include "ion_bbcukmet.h" + +#include +#include + +// ctor, dtor +UKMETIon::UKMETIon(QObject *parent, const QVariantList &args) + : IonInterface(parent, args) + +{ + Q_UNUSED(args) +} + +UKMETIon::~UKMETIon() +{ + deleteForecasts(); +} + +void UKMETIon::reset() +{ + deleteForecasts(); + m_sourcesToReset = sources(); + updateAllSources(); +} + +void UKMETIon::deleteForecasts() +{ + // Destroy each forecast stored in a QVector + QHash::iterator + it = m_weatherData.begin(), + end = m_weatherData.end(); + for (; it != end; ++it) { + qDeleteAll(it.value().forecasts); + it.value().forecasts.clear(); + } +} + + +// Get the master list of locations to be parsed +void UKMETIon::init() +{ + m_timeEngine = dataEngine("time"); + setInitialized(true); +} + +QMap UKMETIon::setupDayIconMappings(void) const +{ +// ClearDay, FewCloudsDay, PartlyCloudyDay, Overcast, +// Showers, ScatteredShowers, Thunderstorm, Snow, +// FewCloudsNight, PartlyCloudyNight, ClearNight, +// Mist, NotAvailable + + QMap dayList; + dayList["sunny"] = ClearDay; + //dayList["sunny night"] = ClearNight; + dayList["clear"] = ClearDay; + dayList["clar sky"] = ClearDay; + dayList["sunny intervals"] = PartlyCloudyDay; + //dayList["sunny intervals night"] = ClearNight; + dayList["partly cloudy"] = PartlyCloudyDay; + dayList["cloudy"] = Overcast; + dayList["white cloud"] = Overcast; + dayList["grey cloud"] = Overcast; + //dayList["low level cloud"] = NotAvailable; + //dayList["medium level cloud"] = NotAvailable; + //dayList["sandstorm"] = NotAvailable; + dayList["drizzle"] = LightRain; + dayList["misty"] = Mist; + dayList["mist"] = Mist; + dayList["fog"] = Mist; + dayList["foggy"] = Mist; + dayList["tropical storm"] = Thunderstorm; + dayList["hazy"] = NotAvailable; + dayList["light shower"] = Showers; + dayList["light rain shower"] = Showers; + dayList["light showers"] = Showers; + dayList["light rain"] = Showers; + dayList["heavy rain"] = Rain; + dayList["heavy showers"] = Rain; + dayList["heavy shower"] = Rain; + dayList["heavy rain shower"] = Rain; + dayList["thundery shower"] = Thunderstorm; + dayList["thunder storm"] = Thunderstorm; + dayList["cloudy with sleet"] = RainSnow; + dayList["sleet shower"] = RainSnow; + dayList["sleet showers"] = RainSnow; + dayList["sleet"] = RainSnow; + dayList["cloudy with hail"] = Hail; + dayList["hail shower"] = Hail; + dayList["hail showers"] = Hail; + dayList["hail"] = Hail; + dayList["light snow"] = LightSnow; + dayList["light snow shower"] = Flurries; + dayList["light snow showers"] = Flurries; + dayList["cloudy with light snow"] = LightSnow; + dayList["heavy snow"] = Snow; + dayList["heavy snow shower"] = Snow; + dayList["heavy snow showers"] = Snow; + dayList["cloudy with heavy snow"] = Snow; + dayList["na"] = NotAvailable; + return dayList; +} + +QMap UKMETIon::setupNightIconMappings(void) const +{ + QMap nightList; + nightList["clear"] = ClearNight; + nightList["clear sky"] = ClearNight; + nightList["clear intervals"] = PartlyCloudyNight; + nightList["sunny intervals"] = PartlyCloudyDay; // it's not really sunny + nightList["sunny"] = ClearDay; + nightList["cloudy"] = Overcast; + nightList["white cloud"] = Overcast; + nightList["grey cloud"] = Overcast; + nightList["partly cloudy"] = PartlyCloudyNight; + nightList["drizzle"] = LightRain; + nightList["misty"] = Mist; + nightList["mist"] = Mist; + nightList["fog"] = Mist; + nightList["foggy"] = Mist; + nightList["tropical storm"] = Thunderstorm; + nightList["hazy"] = NotAvailable; + nightList["light shower"] = Showers; + nightList["light rain shower"] = Showers; + nightList["light showers"] = Showers; + nightList["light rain"] = Showers; + nightList["heavy rain"] = Rain; + nightList["heavy showers"] = Rain; + nightList["heavy shower"] = Rain; + nightList["heavy rain shower"] = Rain; + nightList["thundery shower"] = Thunderstorm; + nightList["thunder storm"] = Thunderstorm; + nightList["cloudy with sleet"] = NotAvailable; + nightList["sleet shower"] = NotAvailable; + nightList["sleet showers"] = NotAvailable; + nightList["sleet"] = NotAvailable; + nightList["cloudy with hail"] = Hail; + nightList["hail shower"] = Hail; + nightList["hail showers"] = Hail; + nightList["hail"] = Hail; + nightList["light snow"] = LightSnow; + nightList["light snow shower"] = Flurries; + nightList["light snow showers"] = Flurries; + nightList["cloudy with light snow"] = LightSnow; + nightList["heavy snow"] = Snow; + nightList["heavy snow shower"] = Snow; + nightList["heavy snow showers"] = Snow; + nightList["cloudy with heavy snow"] = Snow; + nightList["na"] = NotAvailable; + + return nightList; +} + +QMap const& UKMETIon::dayIcons(void) const +{ + static QMap const dval = setupDayIconMappings(); + return dval; +} + +QMap const& UKMETIon::nightIcons(void) const +{ + static QMap const nval = setupNightIconMappings(); + return nval; +} + +// Get a specific Ion's data +bool UKMETIon::updateIonSource(const QString& source) +{ + // We expect the applet to send the source in the following tokenization: + // ionname|validate|place_name - Triggers validation of place + // ionname|weather|place_name - Triggers receiving weather of place + + QStringList sourceAction = source.split('|'); + + // Guard: if the size of array is not 3 then we have bad data, return an error + if (sourceAction.size() < 3) { + setData(source, "validate", "bbcukmet|malformed"); + return true; + } + + if (sourceAction[1] == "validate" && sourceAction.size() >= 3) { + // Look for places to match + findPlace(sourceAction[2], source); + return true; + } else if (sourceAction[1] == "weather" && sourceAction.size() >= 3) { + if (sourceAction.count() >= 3) { + if (sourceAction[2].isEmpty()) { + setData(source, "validate", "bbcukmet|malformed"); + return true; + } + m_place[QString("bbcukmet|%1").arg(sourceAction[2])].XMLurl = sourceAction[3]; + getXMLData(QString("%1|%2").arg(sourceAction[0]).arg(sourceAction[2])); + return true; + } else { + return false; + } + } else { + setData(source, "validate", "bbcukmet|malformed"); + return true; + } + + return false; +} + +// Gets specific city XML data +void UKMETIon::getXMLData(const QString& source) +{ + foreach (const QString &fetching, m_obsJobList) { + if (fetching == source) { + // already getting this source and awaiting the data + return; + } + } + + KUrl url; + url = m_place[source].XMLurl; + + m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); + m_job->addMetaData("cookies", "none"); // Disable displaying cookies + m_obsJobXml.insert(m_job, new QXmlStreamReader); + m_obsJobList.insert(m_job, source); + + if (m_job) { + connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(observation_slotDataArrived(KIO::Job*,QByteArray))); + connect(m_job, SIGNAL(result(KJob*)), this, SLOT(observation_slotJobFinished(KJob*))); + } +} + +// Parses city list and gets the correct city based on ID number +void UKMETIon::findPlace(const QString& place, const QString& source) +{ + KUrl url; + url = "http://news.bbc.co.uk/weather/util/search/SearchResultsNode.xhtml?&search=" + place + "®ion=world&startIndex=0&count=500"; + + m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); + m_job->addMetaData("cookies", "none"); // Disable displaying cookies + m_jobHtml.insert(m_job, new QByteArray()); + m_jobList.insert(m_job, source); + + if (m_job) { + connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(setup_slotDataArrived(KIO::Job*,QByteArray))); + connect(m_job, SIGNAL(result(KJob*)), this, SLOT(setup_slotJobFinished(KJob*))); + +/* + // Handle redirects for direct hit places. + connect(m_job, SIGNAL(redirection(KIO::Job*,KUrl)), this, + SLOT(setup_slotRedirected(KIO::Job*,KUrl))); +*/ + } +} + +void UKMETIon::getFiveDayForecast(const QString& source) +{ + + KUrl xmlMap(m_place[source].forecastHTMLUrl); + + QString xmlPath = xmlMap.path(); + + int splitIDPos = xmlPath.lastIndexOf('/'); + QString stationID = xmlPath.midRef(splitIDPos + 1).toString(); + m_place[source].XMLforecastURL = "http://newsrss.bbc.co.uk/weather/forecast/" + stationID + "/Next3DaysRSS.xml" + xmlMap.query(); + KUrl url(m_place[source].XMLforecastURL); + + m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); + m_job->addMetaData("cookies", "none"); // Disable displaying cookies + m_forecastJobXml.insert(m_job, new QXmlStreamReader); + m_forecastJobList.insert(m_job, source); + + if (m_job) { + connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(forecast_slotDataArrived(KIO::Job*,QByteArray))); + connect(m_job, SIGNAL(result(KJob*)), this, SLOT(forecast_slotJobFinished(KJob*))); + } +} + +void UKMETIon::readSearchHTMLData(const QString& source, const QByteArray& html) +{ + QTextStream stream(html.data()); + QString line; + QStringList tokens; + QString url; + QString tmp; + int flag = 0; + int counter = 2; + + // "

Vitoria, Brazil

" + QRegExp grabURL("/[a-z]+/[a-z]+/([0-9]+)(\\?[^\"]+)?"); + QRegExp grabPlace(">([^<]*[a-z()])"); // FIXME: It would be better to strip away the extra '>' + + while (!stream.atEnd()) { + line = stream.readLine(); + if (line.contains("

") > 0) { + flag = 1; + } + + if (line.contains("There are no forecasts matching") > 0) { + break; + } + + if (flag) { + + if (grabURL.indexIn(line.trimmed()) > 0) { + url = "http://newsrss.bbc.co.uk/weather/forecast/" + grabURL.cap(1) + "/ObservationsRSS.xml"; + if (grabURL.captureCount() > 1) { + url += grabURL.cap(2); + } + grabPlace.indexIn(line.trimmed()); + tmp = QString("bbcukmet|").append(grabPlace.cap(1)); + + // Duplicate places can exist + if (m_locations.contains(tmp)) { + tmp = QString("bbcukmet|").append(QString("%1 (#%2)").arg(grabPlace.cap(1)).arg(counter)); + counter++; + } + + m_place[tmp].XMLurl = url; + m_place[tmp].place = grabPlace.cap(1); + m_locations.append(tmp); + } + } + + if (line.contains("

") > 0) { + flag = 0; + } + } + + // I stream ok? + //if (stream.status() == QTextStream::Ok) { + //return true; + //} + + validate(source); +} + +// handle when no XML tag is found +void UKMETIon::parseUnknownElement(QXmlStreamReader& xml) const +{ + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + parseUnknownElement(xml); + } + } +} + +void UKMETIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + if (data.isEmpty() || !m_jobHtml.contains(job)) { + return; + } + + m_jobHtml[job]->append(data); +} + +void UKMETIon::setup_slotJobFinished(KJob *job) +{ + if (job->error() == 149) { + setData(m_jobList[job], "validate", QString("bbcukmet|timeout")); + disconnectSource(m_jobList[job], this); + m_jobList.remove(job); + delete m_jobHtml[job]; + m_jobHtml.remove(job); + return; + } + + // If Redirected, don't go to this routine + if (!m_locations.contains(QString("bbcukmet|%1").arg(m_jobList[job]))) { + QByteArray *reader = m_jobHtml.value(job); + if (reader) { + readSearchHTMLData(m_jobList[job], *reader); + } + } + m_jobList.remove(job); + delete m_jobHtml[job]; + m_jobHtml.remove(job); +} + +void UKMETIon::observation_slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + QByteArray local = data; + if (data.isEmpty() || !m_obsJobXml.contains(job)) { + return; + } + + // Send to xml. + m_obsJobXml[job]->addData(local); +} + +void UKMETIon::observation_slotJobFinished(KJob *job) +{ + const QString source = m_obsJobList.value(job); + setData(source, Data()); + + QXmlStreamReader *reader = m_obsJobXml.value(job); + if (reader) { + readObservationXMLData(m_obsJobList[job], *reader); + } + + m_obsJobList.remove(job); + delete m_obsJobXml[job]; + m_obsJobXml.remove(job); + + if (m_sourcesToReset.contains(source)) { + m_sourcesToReset.removeAll(source); + emit forceUpdate(this, source); + } +} + +void UKMETIon::forecast_slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + QByteArray local = data; + if (data.isEmpty() || !m_forecastJobXml.contains(job)) { + return; + } + + // Send to xml. + m_forecastJobXml[job]->addData(local); +} + +void UKMETIon::forecast_slotJobFinished(KJob *job) +{ + setData(m_forecastJobList[job], Data()); + QXmlStreamReader *reader = m_forecastJobXml.value(job); + if (reader) { + readFiveDayForecastXMLData(m_forecastJobList[job], *reader); + } + + m_forecastJobList.remove(job); + delete m_forecastJobXml[job]; + m_forecastJobXml.remove(job); +} + +void UKMETIon::parsePlaceObservation(const QString &source, WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "rss"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "rss") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "channel") { + parseWeatherChannel(source, data, xml); + } + } + } +} + +void UKMETIon::parsePlaceForecast(const QString &source, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "rss"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement() && xml.name() == "channel") { + parseWeatherForecast(source, xml); + } + } +} + +void UKMETIon::parseWeatherChannel(const QString& source, WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "channel"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "channel") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "title") { + data.stationName = xml.readElementText().split("Observations for")[1].trimmed(); + data.stationName.replace("United Kingdom", i18n("UK")); + data.stationName.replace("United States of America", i18n("USA")); + + } else if (xml.name() == "item") { + parseWeatherObservation(source, data, xml); + } else { + parseUnknownElement(xml); + } + } + } +} + +void UKMETIon::parseWeatherForecast(const QString& source, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "channel"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "channel") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "item") { + parseFiveDayForecast(source, xml); + } else { + parseUnknownElement(xml); + } + } + } +} + +void UKMETIon::parseWeatherObservation(const QString& source, WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "item"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "item") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "title") { + QString conditionString = xml.readElementText(); + + // Get the observation time and condition + int splitIndex = conditionString.lastIndexOf(':'); + QStringRef conditionData = conditionString.midRef(splitIndex + 1); // Include ':' + data.obsTime = conditionString.midRef(0, splitIndex).toString(); + + // Friday at 0200 GMT + m_dateFormat = QDateTime::fromString(data.obsTime.split("at")[1].trimmed(), "hhmm 'GMT'"); + data.iconPeriodHour = m_dateFormat.toString("hh").toInt(); + data.iconPeriodMinute = m_dateFormat.toString("mm").toInt(); + + data.condition = conditionData.toString().split('.')[0].trimmed(); + + } else if (xml.name() == "link") { + m_place[source].forecastHTMLUrl = xml.readElementText(); + + } else if (xml.name() == "description") { + QString observeString = xml.readElementText(); + QStringList observeData = observeString.split(':'); +#ifdef __GNUC__ +#warning FIXME: We should make this use a QRegExp but I need some help here :) -spstarr +#endif + + data.temperature_C = observeData[1].split(QChar(176))[0].trimmed(); + + // Temperature might be not available + if (data.temperature_C.contains("N/A")) { + data.temperature_C = i18n("N/A"); + } + + data.windDirection = observeData[2].split(',')[0].trimmed(); + data.windSpeed_miles = observeData[3].split(',')[0].split(' ')[1].remove("mph"); + + data.humidity = observeData[4].split(',')[0].split(' ')[1]; + if (data.humidity.endsWith('%')) { + data.humidity.chop(1); + } + + data.pressure = observeData[5].split(',')[0].split(' ')[1].split("mb")[0]; + data.pressureTendency = observeData[5].split(',')[1].trimmed(); + + data.visibilityStr = observeData[6].trimmed(); + + } else if (xml.name() == "lat") { + const QString ordinate = xml.readElementText(); + data.latitude = ordinate.toDouble(); + } else if (xml.name() == "long") { + const QString ordinate = xml.readElementText(); + data.longitude = ordinate.toDouble(); + } else { + parseUnknownElement(xml); + } + } + } +} + +bool UKMETIon::readObservationXMLData(const QString& source, QXmlStreamReader& xml) +{ + WeatherData data; + bool haveObservation = false; + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "rss") { + parsePlaceObservation(source, data, xml); + haveObservation = true; + } else { + parseUnknownElement(xml); + } + } + + } + + if (!haveObservation) { + return false; + } + m_weatherData[source] = data; + + // Get the 5 day forecast info next. + getFiveDayForecast(source); + + return !xml.error(); +} + +bool UKMETIon::readFiveDayForecastXMLData(const QString& source, QXmlStreamReader& xml) +{ + bool haveFiveDay = false; + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "rss") { + parsePlaceForecast(source, xml); + haveFiveDay = true; + } else { + parseUnknownElement(xml); + } + } + } + if (!haveFiveDay) return false; + updateWeather(source); + return !xml.error(); +} + +void UKMETIon::parseFiveDayForecast(const QString& source, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "item"); + + // Flush out the old forecasts when updating. + m_weatherData[source].forecasts.clear(); + + WeatherData::ForecastInfo *forecast = new WeatherData::ForecastInfo; + QString line; + QString period; + QString summary; + QRegExp high("-?\\d+"); + QRegExp low("-?\\d+"); + while (!xml.atEnd()) { + xml.readNext(); + if (xml.name() == "title") { + line = xml.readElementText().trimmed(); +#ifdef __GNUC__ +#warning FIXME: We should make this all use QRegExps in UKMETIon::parseFiveDayForecast() for forecast -spstarr +#endif + + period = line.split(',')[0].split(':')[0]; + summary = line.split(',')[0].split(':')[1].trimmed(); + high.indexIn(line.split(',')[1]); + low.indexIn(line.split(',')[2]); + + forecast->period = period; + forecast->iconName = getWeatherIcon(dayIcons(), summary.toLower()); + forecast->summary = i18nc("weather forecast", summary.toUtf8()); + kDebug() << "i18n summary string: " << qPrintable(forecast->summary); + forecast->tempHigh = high.cap(0).toInt(); + forecast->tempLow = low.cap(0).toInt(); + m_weatherData[source].forecasts.append(forecast); + forecast = new WeatherData::ForecastInfo; + } + } + delete forecast; +} + +void UKMETIon::validate(const QString& source) +{ + bool beginflag = true; + + if (!m_locations.count()) { + QStringList invalidPlace = source.split('|'); + if (m_place[QString("bbcukmet|%1").arg(invalidPlace[2])].place.isEmpty()) { + setData(source, "validate", QString("bbcukmet|invalid|multiple|%1").arg(invalidPlace[2])); + } + m_locations.clear(); + return; + } else { + QString placeList; + foreach(const QString &place, m_locations) { + if (beginflag) { + placeList.append(QString("%1|extra|%2").arg(place.split('|')[1]).arg(m_place[place].XMLurl)); + beginflag = false; + } else { + placeList.append(QString("|place|%1|extra|%2").arg(place.split('|')[1]).arg(m_place[place].XMLurl)); + } + } + if (m_locations.count() > 1) { + setData(source, "validate", QString("bbcukmet|valid|multiple|place|%1").arg(placeList)); + } else { + placeList[0] = placeList[0].toUpper(); + setData(source, "validate", QString("bbcukmet|valid|single|place|%1").arg(placeList)); + } + } + m_locations.clear(); +} + +void UKMETIon::updateWeather(const QString& source) +{ + QString weatherSource = source; + weatherSource.replace("bbcukmet|", "bbcukmet|weather|"); + weatherSource.append(QString("|%1").arg(m_place[source].XMLurl)); + + QMap dataFields; + QStringList fieldList; + QVector forecastList; + int i = 0; + + Plasma::DataEngine::Data data; + + data.insert("Place", place(source)); + data.insert("Station", station(source)); + data.insert("Observation Period", observationTime(source)); + data.insert("Current Conditions", i18nc("weather condition", condition(source).toUtf8())); + kDebug() << "i18n condition string: " << qPrintable(i18nc("weather condition", condition(source).toUtf8())); + + const double lati = periodLatitude(source); + const double longi = periodLongitude(source); + const Plasma::DataEngine::Data timeData = m_timeEngine->query( + QString("Local|Solar|Latitude=%1|Longitude=%2|DateTime=%3") + .arg(lati).arg(longi).arg(m_dateFormat.toString(Qt::ISODate))); + + // Tell applet which icon to use for conditions and provide mapping for condition type to the icons to display + if (timeData["Corrected Elevation"].toDouble() >= 0.0) { + //kDebug() << "Using daytime icons\n"; + data.insert("Condition Icon", getWeatherIcon(dayIcons(), condition(source))); + } else { + data.insert("Condition Icon", getWeatherIcon(nightIcons(), condition(source))); + } + + data.insert("Latitude", lati); + data.insert("Longitude", longi); + + dataFields = humidity(source); + data.insert("Humidity", dataFields["humidity"]); + data.insert("Humidity Field", dataFields["humidityUnit"]); + + data.insert("Visibility", visibility(source)); + + dataFields = temperature(source); + data.insert("Temperature", dataFields["temperature"]); + data.insert("Temperature Unit", dataFields["temperatureUnit"]); + + dataFields = pressure(source); + data.insert("Pressure", dataFields["pressure"]); + data.insert("Pressure Unit", dataFields["pressureUnit"]); + data.insert("Pressure Tendency", dataFields["pressureTendency"]); + + dataFields = wind(source); + data.insert("Wind Speed", dataFields["windSpeed"]); + data.insert("Wind Speed Unit", dataFields["windUnit"]); + data.insert("Wind Direction", dataFields["windDirection"]); + + // 5 Day forecast info + forecastList = forecasts(source); + + // Set number of forecasts per day/night supported + data.insert("Total Weather Days", m_weatherData[source].forecasts.size()); + + foreach(const QString &forecastItem, forecastList) { + fieldList = forecastItem.split('|'); + + data.insert(QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6") \ + .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[2]).arg(fieldList[3]) \ + .arg(fieldList[4]).arg(fieldList[5])); + i++; + } + + data.insert("Credit", i18n("Supported by backstage.bbc.co.uk / Data from UK MET Office")); + data.insert("Credit Url", m_place[source].forecastHTMLUrl); + + setData(weatherSource, data); +} + +QString UKMETIon::place(const QString& source) const +{ + return m_weatherData[source].stationName; +} + +QString UKMETIon::station(const QString& source) const +{ + return m_weatherData[source].stationName; +} + +QString UKMETIon::observationTime(const QString& source) const +{ + return m_weatherData[source].obsTime; +} + +int UKMETIon::periodHour(const QString& source) const +{ + return m_weatherData[source].iconPeriodHour; +} + +int UKMETIon::periodMinute(const QString& source) const +{ + return m_weatherData[source].iconPeriodMinute; +} + +double UKMETIon::periodLatitude(const QString& source) const +{ + return m_weatherData[source].latitude; +} + +double UKMETIon::periodLongitude(const QString& source) const +{ + return m_weatherData[source].longitude; +} + +QString UKMETIon::condition(const QString& source) const +{ + return (m_weatherData[source].condition); +} + +QMap UKMETIon::temperature(const QString& source) const +{ + QMap temperatureInfo; + + temperatureInfo.insert("temperature", QString(m_weatherData[source].temperature_C)); + temperatureInfo.insert("temperatureUnit", QString::number(KUnitConversion::Celsius)); + return temperatureInfo; +} + +QMap UKMETIon::wind(const QString& source) const +{ + QMap windInfo; + if (m_weatherData[source].windSpeed_miles == "N/A") { + windInfo.insert("windSpeed", i18n("N/A")); + windInfo.insert("windUnit", QString::number(KUnitConversion::NoUnit)); + } else { + windInfo.insert("windSpeed", QString(m_weatherData[source].windSpeed_miles)); + windInfo.insert("windUnit", QString::number(KUnitConversion::MilePerHour)); + } + if (m_weatherData[source].windDirection.isEmpty()) { + windInfo.insert("windDirection", i18n("N/A")); + } else { + windInfo.insert("windDirection", i18nc("wind direction", m_weatherData[source].windDirection.toUtf8())); + } + return windInfo; +} + +QMap UKMETIon::humidity(const QString& source) const +{ + QMap humidityInfo; + if (m_weatherData[source].humidity != "N/A") { + humidityInfo.insert("humidity", m_weatherData[source].humidity); + humidityInfo.insert("humidityUnit", QString::number(KUnitConversion::Percent)); + } else { + humidityInfo.insert("humidity", i18n("N/A")); + humidityInfo.insert("humidityUnit", QString::number(KUnitConversion::NoUnit)); + } + + return humidityInfo; +} + +QString UKMETIon::visibility(const QString& source) const +{ + return i18nc("visibility", m_weatherData[source].visibilityStr.toUtf8()); +} + +QMap UKMETIon::pressure(const QString& source) const +{ + QMap pressureInfo; + if (m_weatherData[source].pressure == "N/A") { + pressureInfo.insert("pressure", i18n("N/A")); + pressureInfo.insert("pressureUnit", QString::number(KUnitConversion::NoUnit)); + pressureInfo.insert("pressureTendency", i18n("N/A")); + return pressureInfo; + } + + pressureInfo.insert("pressure", QString(m_weatherData[source].pressure)); + pressureInfo.insert("pressureUnit", QString::number(KUnitConversion::Millibar)); + + pressureInfo.insert("pressureTendency", i18nc("pressure tendency", m_weatherData[source].pressureTendency.toUtf8())); + return pressureInfo; +} + +QVector UKMETIon::forecasts(const QString& source) +{ + QVector forecastData; + + for (int i = 0; i < m_weatherData[source].forecasts.size(); ++i) { + + if (m_weatherData[source].forecasts[i]->period.contains("Saturday")) { + m_weatherData[source].forecasts[i]->period.replace("Saturday", i18nc("Short for Saturday", "Sat")); + } + + if (m_weatherData[source].forecasts[i]->period.contains("Sunday")) { + m_weatherData[source].forecasts[i]->period.replace("Sunday", i18nc("Short for Sunday", "Sun")); + } + + if (m_weatherData[source].forecasts[i]->period.contains("Monday")) { + m_weatherData[source].forecasts[i]->period.replace("Monday", i18nc("Short for Monday", "Mon")); + } + + if (m_weatherData[source].forecasts[i]->period.contains("Tuesday")) { + m_weatherData[source].forecasts[i]->period.replace("Tuesday", i18nc("Short for Tuesday", "Tue")); + } + + if (m_weatherData[source].forecasts[i]->period.contains("Wednesday")) { + m_weatherData[source].forecasts[i]->period.replace("Wednesday", i18nc("Short for Wednesday", "Wed")); + } + + if (m_weatherData[source].forecasts[i]->period.contains("Thursday")) { + m_weatherData[source].forecasts[i]->period.replace("Thursday", i18nc("Short for Thursday", "Thu")); + } + if (m_weatherData[source].forecasts[i]->period.contains("Friday")) { + m_weatherData[source].forecasts[i]->period.replace("Friday", i18nc("Short for Friday", "Fri")); + } + + forecastData.append(QString("%1|%2|%3|%4|%5|%6") \ + .arg(m_weatherData[source].forecasts[i]->period) \ + .arg(m_weatherData[source].forecasts[i]->iconName) \ + .arg(m_weatherData[source].forecasts[i]->summary) \ + .arg(m_weatherData[source].forecasts[i]->tempHigh) \ + .arg(m_weatherData[source].forecasts[i]->tempLow) \ + .arg("N/U")); + //.arg(m_weatherData[source].forecasts[i]->windSpeed) + //arg(m_weatherData[source].forecasts[i]->windDirection)); + } + + return forecastData; +} + +#include "ion_bbcukmet.moc" diff --git a/plasma/generic/dataengines/weather/ions/bbcukmet/ion_bbcukmet.h b/plasma/generic/dataengines/weather/ions/bbcukmet/ion_bbcukmet.h new file mode 100644 index 00000000..11dce328 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/bbcukmet/ion_bbcukmet.h @@ -0,0 +1,178 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 * + ***************************************************************************/ + +/* Ion for BBC Weather from UKMET Office */ + +#ifndef ION_BBCUKMET_H +#define ION_BBCUKMET_H + +#include +#include + +#include "../ion.h" +#include "../dataengineconsumer.h" + +class KJob; +namespace KIO +{ + class Job; + class TransferJob; +} + +class WeatherData +{ + +public: + QString place; + QString stationName; + // Current observation information. + QString obsTime; + int iconPeriodHour; + int iconPeriodMinute; + double longitude; + double latitude; + + QString condition; + QString conditionIcon; + QString temperature_C; + QString windDirection; + QString windSpeed_miles; + QString humidity; + QString pressure; + QString pressureTendency; + QString visibilityStr; + + // Five day forecast + struct ForecastInfo { + QString period; + QString iconName; + QString summary; + int tempHigh; + int tempLow; + int windSpeed; + QString windDirection; + }; + + // 5 day Forecast + QVector forecasts; +}; + +class KDE_EXPORT UKMETIon : public IonInterface, public Plasma::DataEngineConsumer +{ + Q_OBJECT + +public: + UKMETIon(QObject *parent, const QVariantList &args); + ~UKMETIon(); + void init(); // Setup the city location, fetching the correct URL name. + bool updateIonSource(const QString& source); + void updateWeather(const QString& source); + + QString place(const QString& source) const; + QString station(const QString& source) const; + QString observationTime(const QString& source) const; + //bool night(const QString& source) const; + int periodHour(const QString& source) const; + int periodMinute(const QString& source) const; + double periodLatitude(const QString& source) const; + double periodLongitude(const QString& source) const; + QString condition(const QString& source) const; + QMap temperature(const QString& source) const; + QMap wind(const QString& source) const; + QMap humidity(const QString& source) const; + QString visibility(const QString& source) const; + QMap pressure(const QString& source) const; + QVector forecasts(const QString& source); + +public Q_SLOTS: + virtual void reset(); + +protected Q_SLOTS: + void setup_slotDataArrived(KIO::Job *, const QByteArray &); + void setup_slotJobFinished(KJob *); + //void setup_slotRedirected(KIO::Job *, const KUrl &url); + void observation_slotDataArrived(KIO::Job *, const QByteArray &); + void observation_slotJobFinished(KJob *); + void forecast_slotDataArrived(KIO::Job *, const QByteArray &); + void forecast_slotJobFinished(KJob *); + +private: + /* UKMET Methods - Internal for Ion */ + + QMap setupDayIconMappings(void) const; + QMap setupNightIconMappings(void) const; + + QMap const& nightIcons(void) const; + QMap const& dayIcons(void) const; + + // Load and Parse the place search XML listings + void findPlace(const QString& place, const QString& source); + void validate(const QString& source); // Sync data source with Applet + void getFiveDayForecast(const QString& source); + void getXMLData(const QString& source); + void readSearchHTMLData(const QString& source, const QByteArray& html); + bool readFiveDayForecastXMLData(const QString& source, QXmlStreamReader& xml); + void parseSearchLocations(const QString& source, QXmlStreamReader& xml); + + // Observation parsing methods + bool readObservationXMLData(const QString& source, QXmlStreamReader& xml); + void parsePlaceObservation(const QString& source, WeatherData& data, QXmlStreamReader& xml); + void parseWeatherChannel(const QString& source, WeatherData& data, QXmlStreamReader& xml); + void parseWeatherObservation(const QString& source, WeatherData& data, QXmlStreamReader& xml); + void parseFiveDayForecast(const QString& source, QXmlStreamReader& xml); + void parsePlaceForecast(const QString& source, QXmlStreamReader& xml); + void parseWeatherForecast(const QString& source, QXmlStreamReader& xml); + void parseUnknownElement(QXmlStreamReader& xml) const; + + void deleteForecasts(); + + struct XMLMapInfo { + QString place; + QString XMLurl; + QString forecastHTMLUrl; + QString XMLforecastURL; + }; + + // Key dicts + QHash m_place; + QVector m_locations; + + // Weather information + QHash m_weatherData; + + // Store KIO jobs - Search list + QMap m_jobHtml; + QMap m_jobList; + + QMap m_obsJobXml; + QMap m_obsJobList; + + QMap m_forecastJobXml; + QMap m_forecastJobList; + + KIO::TransferJob *m_job; + Plasma::DataEngine *m_timeEngine; + + QDateTime m_dateFormat; + QStringList m_sourcesToReset; +}; + +K_EXPORT_PLASMA_DATAENGINE(bbcukmet, UKMETIon) + +#endif diff --git a/plasma/generic/dataengines/weather/ions/data/bbcukmet_i18n.dat b/plasma/generic/dataengines/weather/ions/data/bbcukmet_i18n.dat new file mode 100644 index 00000000..27a4103c --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/data/bbcukmet_i18n.dat @@ -0,0 +1,118 @@ +weather condition|clear sky +weather condition|clear +weather condition|clear intervals +weather condition|clear sky +weather condition|cloudy +weather condition|cloudy with hail +weather condition|cloudy with heavy snow +weather condition|cloudy with light snow +weather condition|cloudy with sleet +weather condition|drizzle +weather condition|fog +weather condition|foggy +weather condition|grey cloud +weather condition|hail +weather condition|hail shower +weather condition|hail showers +weather condition|hazy +weather condition|heavy rain +weather condition|heavy rain shower +weather condition|heavy shower +weather condition|heavy showers +weather condition|heavy snow +weather condition|heavy snow shower +weather condition|heavy snow showers +weather condition|light rain +weather condition|light rain shower +weather condition|light shower +weather condition|light showers +weather condition|light snow +weather condition|light snow shower +weather condition|light snow showers +weather condition|mist +weather condition|misty +weather condition|N/A +weather condition|na +weather condition|partly cloudy +weather condition|sandstorm +weather condition|weather condition|sleet +weather condition|sleet +weather condition|sleet shower +weather condition|sleet showers +weather condition|sunny +weather condition|sunny intervals +weather condition|thunder storm +weather condition|thundery shower +weather condition|tropical storm +weather condition|white cloud +weather forecast|clear sky +weather forecast|clear +weather forecast|clear intervals +weather forecast|clear sky +weather forecast|cloudy +weather forecast|cloudy with hail +weather forecast|cloudy with heavy snow +weather forecast|cloudy with light snow +weather forecast|cloudy with sleet +weather forecast|drizzle +weather forecast|fog +weather forecast|foggy +weather forecast|grey cloud +weather forecast|hail +weather forecast|hail shower +weather forecast|hail showers +weather forecast|hazy +weather forecast|heavy rain +weather forecast|heavy rain shower +weather forecast|heavy shower +weather forecast|heavy showers +weather forecast|heavy snow +weather forecast|heavy snow shower +weather forecast|heavy snow showers +weather forecast|light rain +weather forecast|light rain shower +weather forecast|light shower +weather forecast|light showers +weather forecast|light snow +weather forecast|light snow shower +weather forecast|light snow showers +weather forecast|mist +weather forecast|misty +weather forecast|na +weather forecast|partly cloudy +weather forecast|sandstorm +weather forecast|sleet +weather forecast|sleet +weather forecast|sleet shower +weather forecast|sleet showers +weather forecast|sunny +weather forecast|sunny intervals +weather forecast|thunder storm +weather forecast|thundery shower +weather forecast|tropical storm +weather forecast|white cloud +wind direction|N +wind direction|NNE +wind direction|NE +wind direction|ENE +wind direction|E +wind direction|SSE +wind direction|SE +wind direction|ESE +wind direction|S +wind direction|NNW +wind direction|NW +wind direction|WNW +wind direction|W +wind direction|SSW +wind direction|SW +wind direction|WSW +wind direction|VR +visibility|Very good +visibility|Good +visibility|Moderate +visibility|Poor +visibility|Very poor +pressure tendency|rising +pressure tendency|falling +pressure tendency|no change diff --git a/plasma/generic/dataengines/weather/ions/data/envcan_i18n.dat b/plasma/generic/dataengines/weather/ions/data/envcan_i18n.dat new file mode 100644 index 00000000..28d9f913 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/data/envcan_i18n.dat @@ -0,0 +1,361 @@ +weather condition|N/A +weather condition|Blowing Snow +weather condition|Clear +weather condition|Cloudy +weather condition|Decreasing Cloud +weather condition|Distant Precipitation +weather condition|Drifting Snow +weather condition|Drizzle +weather condition|Dust +weather condition|Dust Devils +weather condition|Fog +weather condition|Fog Bank Near Station +weather condition|Fog Depositing Ice +weather condition|Fog Patches +weather condition|Freezing drizzle +weather condition|Freezing rain +weather condition|Funnel Cloud +weather condition|Hail +weather condition|Haze +weather condition|Heavy Blowing Snow +weather condition|Heavy Drifting Snow +weather condition|Heavy Drizzle +weather condition|Heavy Hail +weather condition|Heavy Mixed Rain and Drizzle +weather condition|Heavy Mixed Rain and Snow Shower +weather condition|Heavy Rain +weather condition|Heavy Rain and Snow +weather condition|Heavy Rainshower +weather condition|Heavy Snow +weather condition|Heavy Snow Pellets +weather condition|Heavy Snowshower +weather condition|Heavy Thunderstorm with Hail +weather condition|Heavy Thunderstorm with Rain +weather condition|Ice Crystals +weather condition|Ice Pellets +weather condition|Increasing Cloud +weather condition|Light Drizzle +weather condition|Light Freezing Drizzle +weather condition|Light Freezing Rain +weather condition|Light Rain +weather condition|Light Rainshower +weather condition|Light Snow +weather condition|Light Snow Pellets +weather condition|Light Snowshower +weather condition|Lightning Visible +weather condition|Mainly Clear +weather condition|Mainly Sunny +weather condition|Mist +weather condition|Mixed Rain and Drizzle +weather condition|Mixed Rain and Snow Shower +weather condition|Mostly Cloudy +weather condition|Not Reported +weather condition|Partly Cloudy +weather condition|Rain +weather condition|Rain and Snow +weather condition|Rainshower +weather condition|Recent Drizzle +weather condition|Recent Dust or Sand Storm +weather condition|Recent Fog +weather condition|Recent Freezing Precipitation +weather condition|Recent Hail +weather condition|Recent Rain +weather condition|Recent Rain and Snow +weather condition|Recent Rainshower +weather condition|Recent Snow +weather condition|Recent Snowshower +weather condition|Recent Thunderstorm +weather condition|Recent Thunderstorm with Hail +weather condition|Recent Thunderstorm with Heavy Hail +weather condition|Recent Thunderstorm with Heavy Rain +weather condition|Recent Thunderstorm with Rain +weather condition|Sand or Dust Storm +weather condition|Severe Sand or Dust Storm +weather condition|Shallow Fog +weather condition|Smoke +weather condition|Snow +weather condition|Snow Crystals +weather condition|Snow Grains +weather condition|Squalls +weather condition|Sunny +weather condition|Mainly Sunny +weather condition|Partly Cloudy +weather condition|Thunderstorm with Hail +weather condition|Thunderstorm with Rain +weather condition|Thunderstorm with Sand or Dust Storm +weather condition|Thunderstorm without Precipitation +weather condition|Tornado +weather forecast|A few clouds +weather forecast|A few flurries +weather forecast|A few flurries mixed with ice pellets +weather forecast|A few flurries or rain showers +weather forecast|A few flurries or thundershowers +weather forecast|A few rain showers or flurries +weather forecast|A few rain showers or wet flurries +weather forecast|A few showers +weather forecast|A few showers or drizzle +weather forecast|A few showers or thundershowers +weather forecast|A few showers or thunderstorms +weather forecast|A few thundershowers +weather forecast|A few thunderstorms +weather forecast|A few wet flurries +weather forecast|A few wet flurries or rain showers +weather forecast|A mix of sun and cloud +weather forecast|Blizzard +weather forecast|Chance of drizzle +weather forecast|Chance of drizzle mixed with freezing drizzle +weather forecast|Chance of drizzle mixed with rain +weather forecast|Chance of drizzle or rain +weather forecast|Chance of flurries +weather forecast|Chance of flurries at times heavy +weather forecast|Chance of flurries mixed with ice pellets +weather forecast|Chance of flurries or ice pellets +weather forecast|Chance of flurries or rain showers +weather forecast|Chance of flurries or thundershowers +weather forecast|Chance of freezing drizzle +weather forecast|Chance of freezing rain +weather forecast|Chance of freezing rain mixed with snow +weather forecast|Chance of freezing rain or rain +weather forecast|Chance of freezing rain or snow +weather forecast|Chance of light snow +weather forecast|Chance of light snow and blowing snow +weather forecast|Chance of light snow mixed with freezing drizzle +weather forecast|Chance of light snow mixed with ice pellets +weather forecast|Chance of light snow mixed with rain +weather forecast|Chance of light snow or freezing rain +weather forecast|Chance of light snow or ice pellets +weather forecast|Chance of light snow or rain +weather forecast|Chance of light wet snow +weather forecast|Chance of rain +weather forecast|Chance of rain at times heavy +weather forecast|Chance of rain mixed with snow +weather forecast|Chance of rain or drizzle +weather forecast|Chance of rain or freezing rain +weather forecast|Chance of rain or snow +weather forecast|Chance of rain showers or flurries +weather forecast|Chance of rain showers or wet flurries +weather forecast|Chance of severe thunderstorms +weather forecast|Chance of showers +weather forecast|Chance of showers at times heavy +weather forecast|Chance of showers at times heavy or thundershowers +weather forecast|Chance of showers at times heavy or thunderstorms +weather forecast|Chance of showers or drizzle +weather forecast|Chance of showers or thundershowers +weather forecast|Chance of showers or thunderstorms +weather forecast|Chance of snow +weather forecast|Chance of snow and blizzard +weather forecast|Chance of snow mixed with freezing drizzle +weather forecast|Chance of snow mixed with freezing rain +weather forecast|Chance of snow mixed with rain +weather forecast|Chance of snow or rain +weather forecast|Chance of snow squalls +weather forecast|Chance of thundershowers +weather forecast|Chance of thunderstorms +weather forecast|Chance of thunderstorms and possible hail +weather forecast|Chance of wet flurries +weather forecast|Chance of wet flurries at times heavy +weather forecast|Chance of wet flurries or rain showers +weather forecast|Chance of wet snow +weather forecast|Chance of wet snow mixed with rain +weather forecast|Chance of wet snow or rain +weather forecast|Clear +weather forecast|Clearing +weather forecast|Cloudy +weather forecast|Cloudy periods +weather forecast|Cloudy with sunny periods +weather forecast|Drizzle +weather forecast|Drizzle mixed with freezing drizzle +weather forecast|Drizzle mixed with rain +weather forecast|Drizzle or freezing drizzle +weather forecast|Drizzle or rain +weather forecast|Flurries +weather forecast|Flurries at times heavy +weather forecast|Flurries at times heavy or rain showers +weather forecast|Flurries mixed with ice pellets +weather forecast|Flurries or ice pellets +weather forecast|Flurries or rain showers +weather forecast|Flurries or thundershowers +weather forecast|Fog +weather forecast|Fog developing +weather forecast|Fog dissipating +weather forecast|Fog patches +weather forecast|Freezing drizzle +weather forecast|Freezing rain +weather forecast|Freezing rain mixed with ice pellets +weather forecast|Freezing rain mixed with rain +weather forecast|Freezing rain mixed with snow +weather forecast|Freezing rain or ice pellets +weather forecast|Freezing rain or rain +weather forecast|Freezing rain or snow +weather forecast|Ice fog +weather forecast|Ice fog developing +weather forecast|Ice fog dissipating +weather forecast|Ice pellet +weather forecast|Ice pellet mixed with freezing rain +weather forecast|Ice pellet mixed with snow +weather forecast|Ice pellet or freezing rain +weather forecast|Ice pellet or snow +weather forecast|Increasing cloudiness +weather forecast|Increasing clouds +weather forecast|Light snow +weather forecast|Light snow and blizzard +weather forecast|Light snow and blizzard and blowing snow +weather forecast|Light snow and blowing snow +weather forecast|Light snow mixed with freezing drizzle +weather forecast|Light snow mixed with freezing rain +weather forecast|Light snow mixed with ice pellets +weather forecast|Light snow mixed with rain +weather forecast|Light snow or freezing drizzle +weather forecast|Light snow or freezing rain +weather forecast|Light snow or ice pellets +weather forecast|Light snow or rain +weather forecast|Light wet snow +weather forecast|Light wet snow or rain +weather forecast|Local snow squalls +weather forecast|Near blizzard +weather forecast|Overcast +weather forecast|Periods of drizzle +weather forecast|Periods of drizzle mixed with freezing drizzle +weather forecast|Periods of drizzle mixed with rain +weather forecast|Periods of drizzle or freezing drizzle +weather forecast|Periods of drizzle or rain +weather forecast|Periods of freezing drizzle +weather forecast|Periods of freezing drizzle or drizzle +weather forecast|Periods of freezing drizzle or rain +weather forecast|Periods of freezing rain +weather forecast|Periods of freezing rain mixed with ice pellets +weather forecast|Periods of freezing rain mixed with rain +weather forecast|Periods of freezing rain mixed with snow +weather forecast|Periods of freezing rain or ice pellets +weather forecast|Periods of freezing rain or rain +weather forecast|Periods of freezing rain or snow +weather forecast|Periods of ice pellet +weather forecast|Periods of ice pellet mixed with freezing rain +weather forecast|Periods of ice pellet mixed with snow +weather forecast|Periods of ice pellet or freezing rain +weather forecast|Periods of ice pellet or snow +weather forecast|Periods of light snow +weather forecast|Periods of light snow and blizzard +weather forecast|Periods of light snow and blizzard and blowing snow +weather forecast|Periods of light snow and blowing snow +weather forecast|Periods of light snow mixed with freezing drizzle +weather forecast|Periods of light snow mixed with freezing rain +weather forecast|Periods of light snow mixed with ice pellets +weather forecast|Periods of light snow mixed with rain +weather forecast|Periods of light snow or freezing drizzle +weather forecast|Periods of light snow or freezing rain +weather forecast|Periods of light snow or ice pellets +weather forecast|Periods of light snow or rain +weather forecast|Periods of light wet snow +weather forecast|Periods of light wet snow mixed with rain +weather forecast|Periods of light wet snow or rain +weather forecast|Periods of rain +weather forecast|Periods of rain mixed with freezing rain +weather forecast|Periods of rain mixed with snow +weather forecast|Periods of rain or drizzle +weather forecast|Periods of rain or freezing rain +weather forecast|Periods of rain or snow +weather forecast|Periods of rain or thundershowers +weather forecast|Periods of rain or thunderstorms +weather forecast|Periods of snow +weather forecast|Periods of snow and blizzard +weather forecast|Periods of snow and blizzard and blowing snow +weather forecast|Periods of snow and blowing snow +weather forecast|Periods of snow mixed with freezing drizzle +weather forecast|Periods of snow mixed with freezing rain +weather forecast|Periods of snow mixed with ice pellets +weather forecast|Periods of snow mixed with rain +weather forecast|Periods of snow or freezing drizzle +weather forecast|Periods of snow or freezing rain +weather forecast|Periods of snow or ice pellets +weather forecast|Periods of snow or rain +weather forecast|Periods of wet snow +weather forecast|Periods of wet snow mixed with rain +weather forecast|Periods of wet snow or rain +weather forecast|Rain +weather forecast|Rain at times heavy +weather forecast|Rain at times heavy mixed with freezing rain +weather forecast|Rain at times heavy mixed with snow +weather forecast|Rain at times heavy or drizzle +weather forecast|Rain at times heavy or freezing rain +weather forecast|Rain at times heavy or snow +weather forecast|Rain at times heavy or thundershowers +weather forecast|Rain at times heavy or thunderstorms +weather forecast|Rain mixed with freezing rain +weather forecast|Rain mixed with snow +weather forecast|Rain or drizzle +weather forecast|Rain or freezing rain +weather forecast|Rain or snow +weather forecast|Rain or thundershowers +weather forecast|Rain or thunderstorms +weather forecast|Rain showers or flurries +weather forecast|Rain showers or wet flurries +weather forecast|Showers +weather forecast|Showers at times heavy +weather forecast|Showers at times heavy or thundershowers +weather forecast|Showers at times heavy or thunderstorms +weather forecast|Showers or drizzle +weather forecast|Showers or thundershowers +weather forecast|Showers or thunderstorms +weather forecast|Smoke +weather forecast|Snow +weather forecast|Snow and blizzard +weather forecast|Snow and blizzard and blowing snow +weather forecast|Snow and blowing snow +weather forecast|Snow at times heavy +weather forecast|Snow at times heavy and blizzard +weather forecast|Snow at times heavy and blowing snow +weather forecast|Snow at times heavy mixed with freezing drizzle +weather forecast|Snow at times heavy mixed with freezing rain +weather forecast|Snow at times heavy mixed with ice pellets +weather forecast|Snow at times heavy mixed with rain +weather forecast|Snow at times heavy or freezing rain +weather forecast|Snow at times heavy or ice pellets +weather forecast|Snow at times heavy or rain +weather forecast|Snow mixed with freezing drizzle +weather forecast|Snow mixed with freezing rain +weather forecast|Snow mixed with ice pellets +weather forecast|Snow mixed with rain +weather forecast|Snow or freezing drizzle +weather forecast|Snow or freezing rain +weather forecast|Snow or ice pellets +weather forecast|Snow or rain +weather forecast|Snow squalls +weather forecast|Sunny +weather forecast|Mainly Sunny +weather forecast|Sunny with cloudy periods +weather forecast|Thunderstorms +weather forecast|Thunderstorms and possible hail +weather forecast|Wet flurries +weather forecast|Wet flurries at times heavy +weather forecast|Wet flurries at times heavy or rain showers +weather forecast|Wet flurries or rain showers +weather forecast|Wet snow +weather forecast|Wet snow at times heavy +weather forecast|Wet snow at times heavy mixed with rain +weather forecast|Wet snow mixed with rain +weather forecast|Wet snow or rain +weather forecast|Windy +wind direction|N +wind direction|NNE +wind direction|NE +wind direction|ENE +wind direction|E +wind direction|SSE +wind direction|SE +wind direction|ESE +wind direction|S +wind direction|NNW +wind direction|NW +wind direction|WNW +wind direction|W +wind direction|SSW +wind direction|SW +wind direction|WSW +wind direction|VR +wind speed|Calm +wind speed|N/A +pressure tendency|rising +pressure tendency|falling +pressure tendency|steady +Trace diff --git a/plasma/generic/dataengines/weather/ions/data/noaa_i18n.dat b/plasma/generic/dataengines/weather/ions/data/noaa_i18n.dat new file mode 100644 index 00000000..db64ed9a --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/data/noaa_i18n.dat @@ -0,0 +1,359 @@ +weather condition|A Few Clouds +weather condition|A Few Clouds and Breezy +weather condition|A Few Clouds and Windy +weather condition|A Few Clouds with Haze +weather condition|Blowing Dust +weather condition|Blowing Sand +weather condition|Blowing Snow +weather condition|Blowing Snow in Vicinity +weather condition|Breezy +weather condition|Clear +weather condition|Clear and Breezy +weather condition|Clear with Haze +weather condition|Drizzle +weather condition|Drizzle Fog +weather condition|Drizzle Fog/Mist +weather condition|Drizzle Ice Pellets +weather condition|Drizzle Snow +weather condition|Dust +weather condition|Dust/Sand Whirls +weather condition|Dust/Sand Whirls in Vicinity +weather condition|Dust Storm +weather condition|Dust Storm in Vicinity +weather condition|Fair +weather condition|Fair and Breezy +weather condition|Fair and Windy +weather condition|Fair with Haze +weather condition|Fog +weather condition|Fog in Vicinity +weather condition|Fog/Mist +weather condition|Freezing Drizzle +weather condition|Freezing Drizzle in Vicinity +weather condition|Freezing Drizzle Rain +weather condition|Freezing Drizzle Snow +weather condition|Freezing Fog +weather condition|Freezing Fog in Vicinity +weather condition|Freezing Rain +weather condition|Freezing Rain in Vicinity +weather condition|Freezing Rain Rain +weather condition|Freezing Rain Snow +weather condition|Funnel Cloud +weather condition|Funnel Cloud in Vicinity +weather condition|Hail +weather condition|Hail Showers +weather condition|Haze +weather condition|Heavy Blowing Snow +weather condition|Heavy Drizzle +weather condition|Heavy Drizzle Fog +weather condition|Heavy Drizzle Fog/Mist +weather condition|Heavy Drizzle Ice Pellets +weather condition|Heavy Drizzle Snow +weather condition|Heavy Drizzle Snow +weather condition|Heavy Dust Storm +weather condition|Heavy Freezing Drizzle +weather condition|Heavy Freezing Drizzle Rain +weather condition|Heavy Freezing Drizzle Snow +weather condition|Heavy Freezing Fog +weather condition|Heavy Freezing Rain +weather condition|Heavy Freezing Rain Rain +weather condition|Heavy Freezing Rain Snow +weather condition|Heavy Ice Pellets +weather condition|Heavy Ice Pellets Drizzle +weather condition|Heavy Ice Pellets Rain +weather condition|Heavy Rain +weather condition|Heavy Rain Fog +weather condition|Heavy Rain Fog/Mist +weather condition|Heavy Rain Freezing Drizzle +weather condition|Heavy Rain Freezing Rain +weather condition|Heavy Rain Ice Pellets +weather condition|Heavy Rain Showers +weather condition|Heavy Rain Showers Fog/Mist +weather condition|Heavy Rain Snow +weather condition|Heavy Sand Storm +weather condition|Heavy Showers Rain +weather condition|Heavy Showers Rain Fog/Mist +weather condition|Heavy Showers Snow +weather condition|Heavy Showers Snow Fog +weather condition|Heavy Showers Snow Fog/Mist +weather condition|Heavy small Hail/Snow Pellets +weather condition|Heavy Snow +weather condition|Heavy Snow Blowing Snow +weather condition|Heavy Snow Fog +weather condition|Heavy Snow Fog/Mist +weather condition|Heavy Snow Freezing Drizzle +weather condition|Heavy Snow Freezing Rain +weather condition|Heavy Snow Grains +weather condition|Heavy Snow Low Drifting Snow +weather condition|Heavy Snow Rain +weather condition|Heavy Snow Showers +weather condition|Heavy Snow Showers Fog +weather condition|Heavy Snow Showers Fog/Mist +weather condition|Heavy Thunderstorm Rain +weather condition|Heavy Thunderstorm Rain Fog +weather condition|Heavy Thunderstorm Rain Fog and Windy +weather condition|Heavy Thunderstorm Rain Fog/Mist +weather condition|Heavy Thunderstorm Rain Hail +weather condition|Heavy Thunderstorm Rain Hail Fog +weather condition|Heavy Thunderstorm Rain Hail Fog/Hail +weather condition|Heavy Thunderstorm Rain Hail Haze +weather condition|Heavy Thunderstorm Rain Haze +weather condition|Heavy Thunderstorm Rain Small Hail/Snow Pellets +weather condition|Heavy Thunderstorm Snow +weather condition|Ice Crystals +weather condition|Ice Pellets +weather condition|Ice Pellets Drizzle +weather condition|Ice Pellets in Vicinity +weather condition|Ice Pellets Rain +weather condition|Light Drizzle +weather condition|Light Drizzle Fog +weather condition|Light Drizzle Fog/Mist +weather condition|Light Drizzle Ice Pellets +weather condition|Light Drizzle Snow +weather condition|Light Freezing Drizzle +weather condition|Light Freezing Drizzle Rain +weather condition|Light Freezing Drizzle Snow +weather condition|Light Freezing Fog +weather condition|Light Freezing Rain +weather condition|Light Freezing Rain Rain +weather condition|Light Freezing Rain Snow +weather condition|Light Ice Pellets +weather condition|Light Ice Pellets Drizzle +weather condition|Light Ice Pellets Rain +weather condition|Light Rain +weather condition|Light Rain and Breezy +weather condition|Light Rain Fog +weather condition|Light Rain Fog/Mist +weather condition|Light Rain Freezing Drizzle +weather condition|Light Rain Freezing Rain +weather condition|Light Rain Ice Pellets +weather condition|Light Rain Showers +weather condition|Light Rain Showers Fog/Mist +weather condition|Light Rain Snow +weather condition|Light Showers Rain +weather condition|Light Showers Rain Fog/Mist +weather condition|Light Showers Snow +weather condition|Light Showers Snow Fog +weather condition|Light Showers Snow Fog/Mist +weather condition|Light Small Hail/Snow Pellets +weather condition|Light Snow +weather condition|Light Snow Blowing Snow +weather condition|Light Snow Blowing Snow Fog/Mist +weather condition|Light Snow Drizzle +weather condition|Light Snow Fog +weather condition|Light Snow Fog/Mist +weather condition|Light Snow Freezing Drizzle +weather condition|Light Snow Freezing Rain +weather condition|Light Snow Grains +weather condition|Light Snow Low Drifting Snow +weather condition|Light Snow Rain +weather condition|Light Snow Showers +weather condition|Light Snow Showers Fog +weather condition|Light Snow Showers Fog/Mist +weather condition|Light Thunderstorm Rain +weather condition|Light Thunderstorm Rain Fog +weather condition|Light Thunderstorm Rain Fog/Mist +weather condition|Light Thunderstorm Rain Hail +weather condition|Light Thunderstorm Rain Hail Fog +weather condition|Light Thunderstorm Rain Hail Fog/Mist +weather condition|Light Thunderstorm Rain Hail Haze +weather condition|Light Thunderstorm Rain Haze +weather condition|Light Thunderstorm Rain Small Hail/Snow Pellets +weather condition|Light Thunderstorm Snow +weather condition|Low Drifting Dust +weather condition|Low Drifting Sand +weather condition|Low Drifting Snow +weather condition|Mostly Cloudy +weather condition|Mostly Cloudy and Breezy +weather condition|Mostly Cloudy and Windy +weather condition|Mostly Cloudy with Haze +weather condition|Overcast +weather condition|Overcast and Breezy +weather condition|Overcast and Windy +weather condition|Overcast with Haze +weather condition|Partial Fog +weather condition|Partial Fog in Vicinity +weather condition|Partly Cloudy +weather condition|Partly Cloudy and Breezy +weather condition|Partly Cloudy and Windy +weather condition|Partly Cloudy with Haze +weather condition|Patches of Fog +weather condition|Patches of Fog in Vicinity +weather condition|Rain Fog +weather condition|Rain Fog/Mist +weather condition|Rain Freezing Drizzle +weather condition|Rain Freezing Rain +weather condition|Rain Ice Pellets +weather condition|Rain Showers +weather condition|Rain Showers Fog/Mist +weather condition|Rain Showers in Vicinity +weather condition|Rain Showers in Vicinity Fog/Mist +weather condition|Rain Snow +weather condition|Sand +weather condition|Sand Storm +weather condition|Sand Storm in Vicinity +weather condition|Shallow Fog +weather condition|Shallow Fog in Vicinity +weather condition|Showers Hail +weather condition|Showers Ice Pellets +weather condition|Showers in Vicinity Fog +weather condition|Showers in Vicinity Snow +weather condition|Showers Rain +weather condition|Showers Rain Fog/Mist +weather condition|Showers Rain in Vicinity +weather condition|Showers Rain in Vicinity Fog/Mist +weather condition|Showers Snow +weather condition|Showers Snow Fog +weather condition|Showers Snow Fog/Mist +weather condition|Small Hail/Snow Pellets +weather condition|Smoke +weather condition|Snow +weather condition|Snow Blowing Snow +weather condition|Snow Drizzle +weather condition|Snow Fog +weather condition|Snow Fog/Mist +weather condition|Snow Freezing Drizzle +weather condition|Snow Freezing Rain +weather condition|Snow Grains +weather condition|Snow Low Drifting Snow +weather condition|Snow Rain +weather condition|Snow Showers +weather condition|Snow Showers Fog +weather condition|Snow Showers Fog/Mist +weather condition|Snow Showers in Vicinity +weather condition|Snow Showers in Vicinity Fog +weather condition|Snow Showers in Vicinity Fog/Mist +weather condition|Thunderstorm +weather condition|Thunderstorm Fog +weather condition|Thunderstorm Hail +weather condition|Thunderstorm Hail Fog +weather condition|Thunderstorm Haze in Vicinity +weather condition|Thunderstorm Haze in Vicinity Hail +weather condition|Thunderstorm Heavy Rain +weather condition|Thunderstorm Heavy Rain Fog +weather condition|Thunderstorm Heavy Rain Fog/Mist +weather condition|Thunderstorm Heavy Rain Hail +weather condition|Thunderstorm Heavy Rain Hail Fog +weather condition|Thunderstorm Heavy Rain Hail Fog/Mist +weather condition|Thunderstorm Heavy Rain Hail Haze +weather condition|Thunderstorm Heavy Rain Haze +weather condition|Thunderstorm Ice Pellets +weather condition|Thunderstorm in Vicinity +weather condition|Thunderstorm in Vicinity Fog +weather condition|Thunderstorm in Vicinity Fog/Mist +weather condition|Thunderstorm in Vicinity Hail +weather condition|Thunderstorm in Vicinity Hail Haze +weather condition|Thunderstorm in Vicinity Haze +weather condition|Thunderstorm Light Rain +weather condition|Thunderstorm Light Rain Fog +weather condition|Thunderstorm Light Rain Fog/Mist +weather condition|Thunderstorm Light Rain Hail +weather condition|Thunderstorm Light Rain Hail Fog +weather condition|Thunderstorm Light Rain Hail Fog/Mist +weather condition|Thunderstorm Light Rain Hail Haze +weather condition|Thunderstorm Light Rain Haze +weather condition|Thunderstorm Rain +weather condition|Thunderstorm Rain Fog/Mist +weather condition|Thunderstorm Rain Hail Fog/Mist +weather condition|Thunderstorm Rain Small Hail/Snow Pellets +weather condition|Thunderstorm Showers in Vicinity +weather condition|Thunderstorm Showers in Vicinity Hail +weather condition|Thunderstorm Small Hail/Snow Pellets +weather condition|Thunderstorm Snow +weather condition|Tornado/Water Spout +weather condition|Windy +weather condition|N/A +weather forecast|Ice Crystals +weather forecast|Volcanic Ash +weather forecast|Water Spout +weather forecast|Freezing Spray +weather forecast|Frost +weather forecast|Chance Thunderstorms +weather forecast|Thunderstorms Likely +weather forecast|Thunderstorms +weather forecast|Severe Tstms +weather forecast|Chance Snow/Sleet +weather forecast|Snow/Sleet Likely +weather forecast|Snow/Sleet +weather forecast|Chance Rain/Sleet +weather forecast|Rain/Sleet Likely +weather forecast|Rain/Sleet +weather forecast|Chance Rain/Freezing Rain +weather forecast|Rain/Freezing Rain Likely +weather forecast|Rain/Freezing Rain +weather forecast|Wintry Mix +weather forecast|Chance Freezing Drizzle +weather forecast|Freezing Drizzle Likely +weather forecast|Freezing Drizzle +weather forecast|Chance Freezing Rain +weather forecast|Freezing Rain Likely +weather forecast|Freezing Rain +weather forecast|Chance Rain/Snow +weather forecast|Rain/Snow Likely +weather forecast|Rain/Snow +weather forecast|Chance Snow +weather forecast|Snow Likely +weather forecast|Snow +weather forecast|Heavy Snow +weather forecast|Chance Flurries +weather forecast|Flurries Likely +weather forecast|Flurries +weather forecast|Chance Snow Showers +weather forecast|Snow Showers Likely +weather forecast|Snow Showers +weather forecast|Chance Snow Showers +weather forecast|Snow Showers Likely +weather forecast|Snow Showers +weather forecast|Chance Drizzle +weather forecast|Drizzle Likely +weather forecast|Drizzle +weather forecast|Chance Rain +weather forecast|Rain Likely +weather forecast|Rain +weather forecast|Heavy Rain +weather forecast|Chance Rain Showers +weather forecast|Rain Showers Likely +weather forecast|Rain Showers +weather forecast|Chance Rain Showers +weather forecast|Rain Showers Likely +weather forecast|Rain Showers +weather forecast|Sleet +weather forecast|Smoke +weather forecast|Freezing Fog +weather forecast|Ice Fog +weather forecast|Haze +weather forecast|Blowing Sand +weather forecast|Blowing Dust +weather forecast|Blowing Snow +weather forecast|Dense Fog +weather forecast|Fog +weather forecast|Windy +weather forecast|Blustery +weather forecast|Breezy +weather forecast|Cold +weather forecast|Hot +weather forecast|Cloudy +weather forecast|Mostly Cloudy +weather forecast|Partly Cloudy +weather forecast|Mostly Sunny +weather forecast|Sunny +weather forecast|Increasing Clouds +weather forecast|Becoming Cloudy +weather forecast|Clearing +weather forecast|Gradual Clearing +weather forecast|Clearing Late +weather forecast|Decreasing Clouds +weather forecast|Becoming Sunny +weather forecast|Clear +weather forecast|Mostly Clear +weather forecast|Chance Thunderstorms +weather forecast|Slight Chance Thunderstorms +wind direction|N +wind direction|NE +wind direction|S +wind direction|SW +wind direction|E +wind direction|SE +wind direction|W +wind direction|N +wind direction|VR +wind speed|Calm diff --git a/plasma/generic/dataengines/weather/ions/dataengineconsumer.h b/plasma/generic/dataengines/weather/ions/dataengineconsumer.h new file mode 100644 index 00000000..97b5358a --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/dataengineconsumer.h @@ -0,0 +1,66 @@ +/* + * Copyright 2005 by Aaron Seigo + * Copyright 2007 by Riccardo Iaconelli + * Copyright 2008 by Ménard Alexis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLASMA_DATAENGINECONSUMER_H +#define PLASMA_DATAENGINECONSUMER_H + +#include + +#include + +#include "plasma/dataenginemanager.h" + +namespace Plasma +{ + +class DataEngineConsumer +{ +public: + ~DataEngineConsumer() + { + foreach (const QString &engine, m_loadedEngines) { + DataEngineManager::self()->unloadEngine(engine); + } + } + + DataEngine *dataEngine(const QString &name) + { + if (m_loadedEngines.contains(name)) { + return DataEngineManager::self()->engine(name); + } + + DataEngine *engine = DataEngineManager::self()->loadEngine(name); + if (engine->isValid()) { + m_loadedEngines.insert(name); + } + + return engine; + } + +private: + QSet m_loadedEngines; +}; + +} // namespace Plasma + +#endif + + diff --git a/plasma/generic/dataengines/weather/ions/debianweather/CMakeLists.txt b/plasma/generic/dataengines/weather/ions/debianweather/CMakeLists.txt new file mode 100644 index 00000000..5a36888c --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/debianweather/CMakeLists.txt @@ -0,0 +1,16 @@ +# Project Needs a name ofcourse +project(iondebianweather) + +# We add our source code here +set(karaboudjan_SRCS iondebianweather.cpp) + +# Now make sure all files get to the right place +kde4_add_plugin(ion_debianweather ${karaboudjan_SRCS}) +target_link_libraries(ion_debianweather weather_ion + ${QT_QTCORE_LIBRARY}) + +install(TARGETS ion_debianweather + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES ion-debianweather.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/dataengines/weather/ions/debianweather/ion-debianweather.desktop b/plasma/generic/dataengines/weather/ions/debianweather/ion-debianweather.desktop new file mode 100644 index 00000000..e1ffa57a --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/debianweather/ion-debianweather.desktop @@ -0,0 +1,110 @@ +[Desktop Entry] +Name=Debian Weather Service +Name[bg]=Метеорологична услуга на Debian +Name[bs]=NOAA‑ova nacionalna meteorološka služba +Name[ca]=Servei meteorològic de Debian +Name[ca@valencia]=Servei meteorològic de Debian +Name[cs]=Informační služba Debianu o počasí +Name[da]=Debian vejrtjeneste +Name[de]=Debian-Wetterdienst +Name[el]=Υπηρεσία καιρού Debian +Name[en_GB]=Debian Weather Service +Name[es]=Servicio de meteorología de Debian +Name[et]=Debiani ilmateenistus +Name[eu]=Debian-en eguraldi-zerbitzua +Name[fi]=Debianin sääpalvelu +Name[fr]=Service météo de Debian +Name[ga]=Seirbhís na hAimsire de chuid Debian +Name[gl]=Servizo meteorolóxico da Debian +Name[he]=שירות מזג האוויר של דביאן +Name[hr]=Debian Weather Service +Name[hu]=Debian időjárásjelző szolgálat +Name[ia]=Servicio Meteorologic de Debian +Name[is]=Debian veðurþjónusta +Name[it]=Servizio meteorologico Debian +Name[kk]=Debian ауа райы қызметі +Name[km]=សេវា​អាកាសធាតុ​របស់​ដេបៀន +Name[ko]=Debian 날씨 서비스 +Name[lt]=Debian orų tarnyba +Name[lv]=Debian laikapstākļu serviss +Name[mr]=डेबिअन हवामान सेवा +Name[nb]=Debian værtjeneste +Name[nds]=Debian-Wederdeenst +Name[nl]=Weerdienst van Debian +Name[pa]=ਡੇਬੀਅਨ ਮੌਸਮ ਸਰਵਿਸ +Name[pl]=Usługa pogody z Debiana +Name[pt]=Serviço Meteorológico da Debian +Name[pt_BR]=Serviço Meteorológico do Debian +Name[ro]=Servici meteo Debian +Name[ru]=Служба погоды Debian +Name[sk]=Debian Weather Service +Name[sl]=Debian Weather Service +Name[sr]=Дебијанова метеоролошка служба +Name[sr@ijekavian]=Дебијанова метеоролошка служба +Name[sr@ijekavianlatin]=Debianova meteorološka služba +Name[sr@latin]=Debianova meteorološka služba +Name[sv]=Debian vädertjänst +Name[tr]=Debian Hava Durumu Servisi +Name[ug]=Debian ھاۋارايى مۇلازىمىتى +Name[uk]=Служба погоди Debian +Name[vi]=Dịch vụ thời tiết Debian +Name[wa]=Siervice meteyo di Debian +Name[x-test]=xxDebian Weather Servicexx +Name[zh_CN]=Debian 天气服务 +Name[zh_TW]=Debian 天氣服務 +Comment=XML Data from edos.debian.net +Comment[bg]=XML данни от edos.debian.net +Comment[bs]=XML podaci sa edos.debian.net +Comment[ca]=Dades XML d'edos.debian.net +Comment[ca@valencia]=Dades XML d'edos.debian.net +Comment[cs]=XML data z edos.debian.net +Comment[da]=XML-data fra edos.debian.net +Comment[de]=XML-Daten von edos.debian.net +Comment[el]=XML δεδομένα από edos.debian.net +Comment[en_GB]=XML Data from edos.debian.net +Comment[es]=Datos XML de edos.debian.net +Comment[et]=XML-andmed edos.debian.net-ist +Comment[eu]=XML datuak edos.debian.net-etik +Comment[fi]=XML-tietoa osoitteesta edos.denian.net +Comment[fr]=Données XML provenant de « edos.debian.net » +Comment[ga]=Sonraí XML ó edos.debian.net +Comment[gl]=Datos XML de edos.debian.net +Comment[hr]=XML-podaci s edos.debian.net +Comment[hu]=XML-adatok az edos.debian.net-ről +Comment[ia]=Datos XML ex edos.debian.net +Comment[is]=XML gögn frá edos.debian.net +Comment[it]=Dati XML da edos.debian.net +Comment[kk]=edos.debian.net XML дерегі +Comment[km]=ទិន្ននិយ XML ពី edos.debian.net +Comment[ko]=edos.debian.net의 XML 데이터 +Comment[lt]=XML duomenys iš edos.debian.net +Comment[lv]=XML dati no edos.debian.net +Comment[mr]=edos.debian.net पासून XML डेटा +Comment[nb]=XML-data fra edos.debian.net +Comment[nds]=XML-Daten vun edos.debian.net +Comment[nl]=XML-gegevens van edos.debian.net +Comment[pl]=Dane XML z edos.debian.net +Comment[pt]=Dados em XML do edos.debian.net +Comment[pt_BR]=Dados em XML do edos.debian.net +Comment[ro]=Date XML de la edos.debian.net +Comment[ru]=Данные в формате XML от edos.debian.net +Comment[sk]=XML dáta z edos.debian.net +Comment[sl]=Podatki XML iz edos.debian.net +Comment[sr]=ИксМЛ подаци са edos.debian.net +Comment[sr@ijekavian]=ИксМЛ подаци са edos.debian.net +Comment[sr@ijekavianlatin]=XML podaci sa edos.debian.net +Comment[sr@latin]=XML podaci sa edos.debian.net +Comment[sv]=XML-data från edos.debian.net +Comment[tr]=edos.debian.net adresinden gelen XML Verisi +Comment[ug]=edos.debian.net تەمىنلىگەن XML سانلىق-مەلۇماتى +Comment[uk]=Дані XML з edos.debian.net +Comment[wa]=Dinêyes XML da edos.debian.net +Comment[x-test]=xxXML Data from edos.debian.netxx +Comment[zh_CN]=edos.debian.net 的 XML 数据 +Comment[zh_TW]=從 edos.debian.net 來的 XML 資料 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=debian +X-KDE-Library=ion_debianweather +X-KDE-PluginInfo-Name=DebianWeather +X-KDE-ParentApp=weatherengine diff --git a/plasma/generic/dataengines/weather/ions/debianweather/iondebianweather.cpp b/plasma/generic/dataengines/weather/ions/debianweather/iondebianweather.cpp new file mode 100644 index 00000000..9589d1c4 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/debianweather/iondebianweather.cpp @@ -0,0 +1,293 @@ +/* + Copyright (c) 2011 Sune Vuorela + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + +*/ +#define QT_NO_CAST_FROM_ASCII + +#include "iondebianweather.h" + +#include +#include + +#include + +#include + +IonDebianWeather::IonDebianWeather(QObject*, const QVariantList&) : IonInterface(), m_ionname(QLatin1String("DebianWeather")) { + +} + +void IonDebianWeather::init() { + setInitialized(true); +} + +IonDebianWeather::~IonDebianWeather() { + cleanup(); +} + +void IonDebianWeather::reset() { + cleanup(); +} + +void IonDebianWeather::cleanup() { + Q_FOREACH(KJob* job, m_jobs.keys()) { + delete job; + } + m_jobs.clear(); +} + +IonDebianWeather::jobtype IonDebianWeather::toJobType(const QString& data) { + if(data==QLatin1String("validate")) { + return validate; + } + if(data==QLatin1String("weather")) { + return weather; + } + return unknown; +} + +QString IonDebianWeather::toString(IonDebianWeather::jobtype type) { + switch(type) { + case validate: + return QLatin1String("validate"); + break; + ;; + case weather: + return QLatin1String("weather"); + break; + ;; + case unknown: + ;; + } + return QLatin1String("unknown"); +} + +bool IonDebianWeather::updateIonSource(const QString& source) { + // We expect the applet to send the source in the following tokenization: + // ionname|validate|place_name - Triggers validation of place + // ionname|weather|place_name - Triggers receiving weather of place + QStringList tokens = source.split(QLatin1Char('|')); + + if(tokens.count()==3 && toJobType(tokens.at(1)) == validate) { + //validate, whatever that is. + QSharedPointer p(new locationdata()); + if (tokens.at(2).simplified().startsWith(QLatin1String("Debian"), Qt::CaseInsensitive)){ + p->source = source; + p->type = validate; + p->valid = true; + QStringList searchparts = tokens.at(2).simplified().split(QLatin1Char(' ')); + if(searchparts.size() > 1) { + QStringList components(searchparts); + components.pop_front(); + p->searchstring = components.join(QLatin1String(" ")); + } + findAllPlaces(p); + return true; + }else { + setData(source, + toString(validate), + QString::fromLatin1("%1|invalid|single|%2").arg(m_ionname).arg(tokens.at(2).simplified())); + return true; + } + return true; + } else if(tokens.count()==3 && toJobType(tokens.at(1))==weather) { + QSharedPointer p(new locationdata()); + parseLocation(tokens.at(2).simplified(),p); + if(p->valid) { + p->source = source; + p->type = weather; + startFetchData(p); + return true; + } else { + setData(source, toString(validate),QString::fromLatin1("%1|invalid|single|%2").arg(m_ionname).arg(tokens.at(2).simplified())); + return true; + } + } else { + setData(source,toString(validate),QString::fromLatin1("%1|malformed").arg(m_ionname)); + return true; + } + return false; +} + +void IonDebianWeather::parseLocation(QString location,QSharedPointer data) { + QStringList parts = location.split(QLatin1Char(' ')); + if(parts.size()==3 && parts.at(0)==QLatin1String("Debian")) { + data->suite=parts.at(1); + data->arch=parts.at(2); + data->valid=true; + } +} + +void IonDebianWeather::findAllPlaces(QSharedPointer< IonDebianWeather::locationdata > data) { + Q_ASSERT(data->type==validate); + QUrl url (QLatin1String("http://edos.debian.net/edos-debcheck/results/available.xml")); + KIO::TransferJob* job = KIO::get(url,KIO::NoReload,KIO::HideProgressInfo); + if(job) { + m_jobs[job]=data; + connect(job,SIGNAL(result(KJob*)),this,SLOT(jobDone(KJob*))); + connect(job,SIGNAL(data(KIO::Job*,QByteArray)),this,SLOT(dataReceived(KIO::Job*,QByteArray))); + } +} + +void IonDebianWeather::startFetchData(QSharedPointer data) { + Q_ASSERT(data->valid); + Q_ASSERT(data->type==weather); + QUrl url(QString::fromLatin1("http://edos.debian.net/edos-debcheck/results/%1/latest/%2/weather.xml").arg(data->suite).arg(data->arch)); + KIO::TransferJob* job = KIO::get(url,KIO::NoReload,KIO::HideProgressInfo); + if(job) { + m_jobs[job]=data; + connect(job,SIGNAL(result(KJob*)),this,SLOT(jobDone(KJob*))); + connect(job,SIGNAL(data(KIO::Job*,QByteArray)),this,SLOT(dataReceived(KIO::Job*,QByteArray))); + } +} + +void IonDebianWeather::jobDone(KJob* job) { + if(KIO::TransferJob* kiojob = qobject_cast(job)) { + QSharedPointer locdata = m_jobs.value(job); + if(locdata->valid && locdata->type==weather) { + if(kiojob->error() != 0 || kiojob->isErrorPage()) { + setData(locdata->source, toString(validate), QString::fromLatin1("%1|timeout").arg(m_ionname)); + } else { + xmlresult result = parseWeatherXml(locdata); + ConditionIcons cond = toCondition(result); + Plasma::DataEngine::Data data; + data.insert( QLatin1String("Condition Icon"), getWeatherIcon(cond) ); + data.insert( QLatin1String("Place"), result.nicename ); + data.insert( QLatin1String("Temperature"), QString::number(result.broken) ); + data.insert( QLatin1String("Temperature Unit"), QString::number(KUnitConversion::Celsius) ); + data.insert( QLatin1String("Total Weather Days"), 0 ); + data.insert( QLatin1String("Current Conditions"), result.architecture ); + data.insert( QLatin1String("Credit"), QString::fromLatin1("Data from http://edos.debian.net")); + data.insert( QLatin1String("Credit Url"), QString::fromLatin1("http://edos.debian.net")); + setData( locdata->source,data); + } + } else if( locdata->type == validate ) { + if(kiojob->error()!=0 || kiojob->isErrorPage()) { + setData(locdata->source, toString(validate),QString::fromLatin1("%1|invalid|single|Debian %2").arg(m_ionname).arg(locdata->searchstring).simplified()); + } else { + QStringList archsuitelist = parseLocationXml(locdata); + QString places; + if(archsuitelist.size()==0) { + setData(locdata->source, toString(validate),QString::fromLatin1("%1|invalid|single|Debian %2").arg(m_ionname).arg(locdata->searchstring).simplified()); + } else if(archsuitelist.size()==1) { + setData(locdata->source, toString(validate), QString::fromLatin1("%1|valid|single|place|Debian %2").arg(m_ionname).arg(locdata->searchstring).simplified()); + } else { + Q_FOREACH(QString place, archsuitelist) { + places += QLatin1String("|place|"); + places += place; + } + setData(locdata->source, toString(validate), QString::fromLatin1("%1|valid|multiple%2").arg(m_ionname).arg(places)); + } + } + } else { + kError() << "something went horribly wrong with this locdata"; + } + m_jobs.remove(kiojob); + kiojob->deleteLater(); + } +} + +void IonDebianWeather::dataReceived(KIO::Job* job, QByteArray data) { + QSharedPointer locdata = m_jobs.value(job); + if(!locdata.isNull() && locdata->valid) { + locdata->data.append(data); + } else { + kError() << "wtf"; + } +} + +IonDebianWeather::xmlresult IonDebianWeather::parseWeatherXml(QSharedPointer< IonDebianWeather::locationdata > locdata) { + QXmlStreamReader reader(locdata->data); + xmlresult result; + while(!reader.atEnd()) { + reader.readNextStartElement(); + if( reader.name() == QLatin1String("total")) { + result.total = reader.readElementText().trimmed().toInt(); + } else if( reader.name() == QLatin1String("broken") ) { + result.broken = reader.readElementText().trimmed().toInt(); + } else if(reader.name() == QLatin1String("description") ) { + result.nicename = reader.readElementText(); + } else if(reader.name() == QLatin1String("architecture") ) { + result.architecture = reader.readElementText(); + } + } + return result; +} + +QStringList IonDebianWeather::parseLocationXml(QSharedPointer< IonDebianWeather::locationdata > locdata) { + QXmlStreamReader reader(locdata->data); + QStringList rv; + while (!reader.atEnd()) { + reader.readNext(); + while(!reader.atEnd() && !(reader.isEndElement() && reader.name() == QLatin1String("weathers"))) { + reader.readNext(); + QString suite; + while(!reader.atEnd() && !(reader.isEndElement() && reader.name()==QLatin1String("weather"))) { + reader.readNext(); + if(reader.isStartElement() && reader.name() == QLatin1String("name")) { + suite = reader.readElementText().trimmed(); + continue; + } + if(reader.isStartElement() && reader.name() == QLatin1String("title")) { + // qDebug() << reader.readElementText(); + continue; + } + if(reader.isStartElement() && reader.name() == QLatin1String("archs")) { + while (!reader.atEnd() && !(reader.isEndElement() && reader.name() == QLatin1String("archs"))) { + reader.readNext(); + if(reader.isStartElement() && reader.name()== QLatin1String("arch")) { + QString arch = reader.readElementText(); + QString locstring = QString::fromLatin1("Debian %1 %2").arg(suite).arg(arch); + if(locstring.contains(locdata->searchstring)) { + rv << locstring; + } + } + } + } + } + } + } + return rv; +} + +IonInterface::ConditionIcons IonDebianWeather::toCondition(IonDebianWeather::xmlresult result ) { + qreal percentage=101; //magicvalue ! + if(result.total!=0) { + percentage = result.broken*qreal(100.0)/result.total; + } + if(percentage <= 1) { + return ClearDay; + } else if(percentage <=2) { + return FewCloudsDay; + } else if(percentage <=3) { + return Overcast; + } else if(percentage <=4) { + return Showers; + } else if(percentage <=100) { + return Thunderstorm; + } + return NotAvailable; +} + +#include "iondebianweather.moc" diff --git a/plasma/generic/dataengines/weather/ions/debianweather/iondebianweather.h b/plasma/generic/dataengines/weather/ions/debianweather/iondebianweather.h new file mode 100644 index 00000000..a3ca1101 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/debianweather/iondebianweather.h @@ -0,0 +1,89 @@ +/* + Copyright (c) 2011 Sune Vuorela + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#ifndef IONDEBIANWEATHER_H +#define IONDEBIANWEATHER_H + +#include "../ion.h" +#include + +class KJob; +namespace KIO { + class Job; +} +class IonDebianWeather : public IonInterface { + Q_OBJECT + public: + IonDebianWeather(QObject*, const QVariantList&); + virtual ~IonDebianWeather(); + virtual bool updateIonSource(const QString& source); + virtual void init(); + public Q_SLOTS: + virtual void reset(); + private: + enum jobtype { + validate, + weather, + unknown + }; + struct xmlresult { + int total; + int broken; + QString nicename; + QString architecture; + xmlresult() : total(0), broken(0) {} + }; + struct locationdata { + QString suite; + QString arch; + bool valid; + QString source; + QByteArray data; + jobtype type; + QString searchstring; + locationdata() : valid(false),type(unknown) {} + }; + void tryFindPlace(QSharedPointer data); + void startFetchData(QSharedPointer data); + void findAllPlaces(QSharedPointer< IonDebianWeather::locationdata > data); + void parseLocation(QString sourcedata, QSharedPointer location); + QString m_ionname; + QHash > m_jobs; + xmlresult parseWeatherXml(QSharedPointer locdata); + QStringList parseLocationXml(QSharedPointer< IonDebianWeather::locationdata > locdata); + + jobtype toJobType(const QString& data); + QString toString(jobtype type); + ConditionIcons toCondition(xmlresult); + void cleanup(); + private Q_SLOTS: + void jobDone(KJob*); + void dataReceived(KIO::Job* job,QByteArray data); +}; + +K_EXPORT_PLASMA_DATAENGINE(debianweather, IonDebianWeather) + +#endif // IONDEBIANWEATHER_H diff --git a/plasma/generic/dataengines/weather/ions/envcan/CMakeLists.txt b/plasma/generic/dataengines/weather/ions/envcan/CMakeLists.txt new file mode 100644 index 00000000..cb10a30d --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/envcan/CMakeLists.txt @@ -0,0 +1,8 @@ +SET (ion_envcan_SRCS ion_envcan.cpp) +kde4_add_plugin(ion_envcan ${ion_envcan_SRCS}) +target_link_libraries (ion_envcan ${KDE4_SOLID_LIBS} weather_ion) + +INSTALL (FILES ion-envcan.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + +INSTALL (TARGETS ion_envcan DESTINATION ${PLUGIN_INSTALL_DIR}) + diff --git a/plasma/generic/dataengines/weather/ions/envcan/ion-envcan.desktop b/plasma/generic/dataengines/weather/ions/envcan/ion-envcan.desktop new file mode 100644 index 00000000..9c94bba0 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/envcan/ion-envcan.desktop @@ -0,0 +1,153 @@ +[Desktop Entry] +Name=Environment Canada +Name[ar]=وزارة البيئة الكندية +Name[ast]=Medioambiente de Canadá +Name[be@latin]=Environment Canada +Name[bg]=Environment Canada +Name[bs]=Prirodna sredina Kanada +Name[ca]=Medi ambient del Canadà +Name[ca@valencia]=Medi ambient del Canadà +Name[cs]=Meteorologický úřad Kanady (EC) +Name[da]=Environment Canada +Name[de]=Environment Canada +Name[el]=Περιβάλλον Καναδά +Name[en_GB]=Environment Canada +Name[eo]=Environment Canada +Name[es]=Medio ambiente de Canada +Name[et]=Environment Canada +Name[eu]=Kanadako Ingurumen Ministerioa +Name[fi]=Environment Canada -palvelu +Name[fr]=Météorologie du Canada +Name[fy]=Omjouwing Kanada +Name[ga]=Environment Canada +Name[gl]=Environment Canada +Name[gu]=એન્વાર્યમેન્ટ કેનેડા +Name[he]=Environment Canada +Name[hi]=एनवायरनमेंट कनाडा +Name[hne]=कनाडा मौसम +Name[hr]=Okoliš Kanade +Name[hu]=Environment Canada +Name[ia]=Environment Canada +Name[id]=Environment Canada +Name[is]=Environment Canada +Name[it]=Environment Canada +Name[ja]=Environment Canada +Name[kk]=Environment Canada +Name[km]=បរិស្ថាន​ប្រទេស​កាណាដា +Name[kn]=ಎನ್ವಯರನ್ಮೆಂಟ್ ಕೆನಡಾ +Name[ko]=캐나다 환경부 +Name[lt]=Environment Canada +Name[lv]=Environment Canada +Name[mk]=Environment Canada +Name[ml]=കാനഡയുടെ പരിസ്ഥിതി +Name[mr]=हवामान कॅनडा +Name[nb]=Environment Canada +Name[nds]=Ümwelt Kanada +Name[ne]=वातावरण क्यानाडा +Name[nl]=Environment Canada +Name[nn]=Environment Canada +Name[pa]=ਇੰਨਵਾਇਰਮੈਂਟ ਕੇਨੈਡਾ +Name[pl]=Environment Canada +Name[pt]=Environment Canada +Name[pt_BR]=Environment Canada +Name[ro]=Environment Canada +Name[ru]=Environment Canada +Name[se]=Environment Canada +Name[si]=කැනඩා පාරිසරිකය +Name[sk]=Počasie - Environment Canada +Name[sl]=Environment Canada +Name[sr]=Природна средина Канада +Name[sr@ijekavian]=Природна средина Канада +Name[sr@ijekavianlatin]=Prirodna sredina Kanada +Name[sr@latin]=Prirodna sredina Kanada +Name[sv]=Environment Canada +Name[ta]=Environment Canada +Name[te]=కెనడా వాతావరణం +Name[tg]=Environment Canada +Name[th]=Environment Canada +Name[tr]=Environment Canada +Name[ug]=كانادا مۇھىتى +Name[uk]=Погода в Канаді +Name[wa]=Evironmint Canada +Name[x-test]=xxEnvironment Canadaxx +Name[zh_CN]=加拿大环境 +Name[zh_TW]=Environment Canada +Comment=XML Data from Environment Canada +Comment[ar]=بيانات XML من وزارة البيئة الكندية +Comment[ast]=Datos XML de Medioambiente de Canadá +Comment[be@latin]=Źviestki ŭ farmacie „XML” ad „Environment Canada” +Comment[bg]=XML данни от Environment Canada +Comment[bs]=IksML podaci Prirodne sredine Kanada +Comment[ca]=Dades XML des de Medi ambient del Canadà +Comment[ca@valencia]=Dades XML des de Medi ambient del Canadà +Comment[cs]=XML data z meteorologického úřadu Kanady (EC) +Comment[da]=XML-data fra Environment Canada +Comment[de]=XML-Daten von Environment Canada +Comment[el]=Δεδομένα XML για το περιβάλλον του Καναδά +Comment[en_GB]=XML Data from Environment Canada +Comment[eo]=XML-datumoj el Environment Canada +Comment[es]=Datos XML de medio ambiente de Canada +Comment[et]=Environment Canada XML-andmed +Comment[eu]=XML datuak Kanadako Ingurumen Ministeriotik +Comment[fi]=XML-tietoa Environment Canada -palvelusta +Comment[fr]=Données au format XML de la météorologie du Canada +Comment[fy]=XML Data fan omjouwing Kanada +Comment[ga]=Sonraí XML ó Environment Canada +Comment[gl]=Datos XML de Environment Canada +Comment[gu]=એન્વાર્યમેન્ટ કેનેડા તરફથી XML માહિતી +Comment[he]=מידע ב־XML מ־Environment Canada +Comment[hi]=एनवायरनमेंट कनाडा से एक्सएमएल डाटा +Comment[hne]=कनाडा मौसम से एक्सएमएल डाटा +Comment[hr]=XML podaci iz Okoliša Kanade +Comment[hu]=XML-adatok az Environment Canada szervezettől +Comment[ia]=Datos XML ex Environment Canada +Comment[id]=Data XML dari Environment Canada +Comment[is]=XML gögn frá Umhverfisstofnun Kanada +Comment[it]=Dati XML da Environment Canada +Comment[ja]=Environment Canada の XML データ +Comment[kk]=Environment Canada-ның XML дерегі +Comment[km]=ទិន្នន័យ XML ពី​បរិស្ថាន​ប្រទេស​កាណាដា +Comment[kn]=ಎನ್ವಯರನ್ಮೆಂಟ್ ಕೆನಡಾ ದಿಂದ XML ದತ್ತ +Comment[ko]=캐나다 환경부의 XML 데이터 +Comment[lt]=XML duomenys iš Environment Canada +Comment[lv]=XML dati no Environment Canada +Comment[mk]=XML-податоци од „Environment Canada“ +Comment[ml]=കാനഡയുടെ പരിസ്ഥിതിയില്‍ നിന്നുമുള്ള എക്സ്എംഎല്‍ ഡേറ്റാ +Comment[mr]=हवामान कॅनडा पासून XML माहिती +Comment[nb]=XML-data fra Environment Canada +Comment[nds]=XML-Daten vun Ümwelt Kanada +Comment[ne]=वातावरण क्यानाडाबाट एक्सएमएल डेटा +Comment[nl]=XML-gegevens van Environment Canada +Comment[nn]=XML-data frå Environment Canada +Comment[pa]=ਇੰਨਵਾਇਰਨਮੈਂਟ ਕੇਨੈਡਾ ਤੋਂ XML ਡਾਟਾ +Comment[pl]=Dane XML z Environment Canada +Comment[pt]=Dados em XML do Environment Canada +Comment[pt_BR]=Dados em XML do Environment Canada +Comment[ro]=Date XML de la Environment Canada +Comment[ru]=Данные в формате XML от Environment Canada +Comment[se]=XML-dáhtat Environment Canadas +Comment[si]=කැනඩා පාරිසරිකය වෙතින් XML දත්ත +Comment[sk]=XML dáta z Environment Canada +Comment[sl]=Podatki XML od Environment Canada +Comment[sr]=ИксМЛ подаци Природне средине Канада +Comment[sr@ijekavian]=ИксМЛ подаци Природне средине Канада +Comment[sr@ijekavianlatin]=XML podaci Prirodne sredine Kanada +Comment[sr@latin]=XML podaci Prirodne sredine Kanada +Comment[sv]=XML-data från Environment Canada +Comment[ta]=XML Data from Environment Canada +Comment[te]=కెనడా వాతావరణం నుండి XML డాటా +Comment[tg]=Маълумоти XML аз Environment Canada +Comment[th]=ข้อมูล XML จาก Environment Canada +Comment[tr]=Environment Canada'dan XML Verisi +Comment[ug]=كانادا مۇھىتى تەمىنلىگەن XML سانلىق-مەلۇماتى +Comment[uk]=Дані XML з метеорологічного відділу Канади +Comment[wa]=Dinêyes XML da Evironmint Canada +Comment[x-test]=xxXML Data from Environment Canadaxx +Comment[zh_CN]=加拿大环境提供的 XML 数据 +Comment[zh_TW]=從 Environment Canada 來的 XML 資料 +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-ParentApp=weatherengine +Type=Service +Icon=noneyet +X-KDE-Library=ion_envcan +X-KDE-PluginInfo-Name=envcan diff --git a/plasma/generic/dataengines/weather/ions/envcan/ion_envcan.cpp b/plasma/generic/dataengines/weather/ions/envcan/ion_envcan.cpp new file mode 100644 index 00000000..51946fd9 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/envcan/ion_envcan.cpp @@ -0,0 +1,1922 @@ +/*************************************************************************** + * Copyright (C) 2007-2011 by Shawn Starr * + * * + * 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 * + ***************************************************************************/ + +/* Ion for Environment Canada XML data */ + +#include "ion_envcan.h" + +#include +#include +#include +#include + + +// ctor, dtor +EnvCanadaIon::EnvCanadaIon(QObject *parent, const QVariantList &args) + : IonInterface(parent, args) +{ +} + +void EnvCanadaIon::deleteForecasts() +{ + QMutableHashIterator it(m_weatherData); + while (it.hasNext()) { + it.next(); + WeatherData &item = it.value(); + qDeleteAll(item.warnings); + item.warnings.clear(); + + qDeleteAll(item.watches); + item.watches.clear(); + + qDeleteAll(item.forecasts); + item.forecasts.clear(); + } +} + +void EnvCanadaIon::reset() +{ + deleteForecasts(); + emitWhenSetup = true; + m_sourcesToReset = sources(); + getXMLSetup(); +} + +EnvCanadaIon::~EnvCanadaIon() +{ + // Destroy each watch/warning stored in a QVector + deleteForecasts(); +} + +// Get the master list of locations to be parsed +void EnvCanadaIon::init() +{ + // Get the real city XML URL so we can parse this + getXMLSetup(); + m_timeEngine = dataEngine("time"); +} + +QMap EnvCanadaIon::setupConditionIconMappings(void) const +{ + QMap conditionList; + + // Explicit periods + conditionList["mainly sunny"] = FewCloudsDay; + conditionList["mainly clear"] = FewCloudsNight; + conditionList["sunny"] = ClearDay; + conditionList["clear"] = ClearNight; + + // Available conditions + conditionList["blowing snow"] = Snow; + conditionList["cloudy"] = Overcast; + conditionList["distant precipitation"] = LightRain; + conditionList["drifting snow"] = Flurries; + conditionList["drizzle"] = LightRain; + conditionList["dust"] = NotAvailable; + conditionList["dust devils"] = NotAvailable; + conditionList["fog"] = Mist; + conditionList["fog bank near station"] = Mist; + conditionList["fog depositing ice"] = Mist; + conditionList["fog patches"] = Mist; + conditionList["freezing drizzle"] = FreezingDrizzle; + conditionList["freezing rain"] = FreezingRain; + conditionList["funnel cloud"] = NotAvailable; + conditionList["hail"] = Hail; + conditionList["haze"] = Haze; + conditionList["heavy blowing snow"] = Snow; + conditionList["heavy drifting snow"] = Snow; + conditionList["heavy drizzle"] = LightRain; + conditionList["heavy hail"] = Hail; + conditionList["heavy mixed rain and drizzle"] = LightRain; + conditionList["heavy mixed rain and snow shower"] = RainSnow; + conditionList["heavy rain"] = Rain; + conditionList["heavy rain and snow"] = RainSnow; + conditionList["heavy rainshower"] = Rain; + conditionList["heavy snow"] = Snow; + conditionList["heavy snow pellets"] = Snow; + conditionList["heavy snowshower"] = Snow; + conditionList["heavy thunderstorm with hail"] = Thunderstorm; + conditionList["heavy thunderstorm with rain"] = Thunderstorm; + conditionList["ice crystals"] = Flurries; + conditionList["ice pellets"] = Hail; + conditionList["increasing cloud"] = Overcast; + conditionList["light drizzle"] = LightRain; + conditionList["light freezing drizzle"] = FreezingRain; + conditionList["light freezing rain"] = FreezingRain; + conditionList["light rain"] = LightRain; + conditionList["light rainshower"] = LightRain; + conditionList["light snow"] = LightSnow; + conditionList["light snow pellets"] = LightSnow; + conditionList["light snowshower"] = Flurries; + conditionList["lightning visible"] = Thunderstorm; + conditionList["mist"] = Mist; + conditionList["mixed rain and drizzle"] = LightRain; + conditionList["mixed rain and snow shower"] = RainSnow; + conditionList["not reported"] = NotAvailable; + conditionList["rain"] = Rain; + conditionList["rain and snow"] = RainSnow; + conditionList["rainshower"] = LightRain; + conditionList["recent drizzle"] = LightRain; + conditionList["recent dust or sand storm"] = NotAvailable; + conditionList["recent fog"] = Mist; + conditionList["recent freezing precipitation"] = FreezingDrizzle; + conditionList["recent hail"] = Hail; + conditionList["recent rain"] = Rain; + conditionList["recent rain and snow"] = RainSnow; + conditionList["recent rainshower"] = Rain; + conditionList["recent snow"] = Snow; + conditionList["recent snowshower"] = Flurries; + conditionList["recent thunderstorm"] = Thunderstorm; + conditionList["recent thunderstorm with hail"] = Thunderstorm; + conditionList["recent thunderstorm with heavy hail"] = Thunderstorm; + conditionList["recent thunderstorm with heavy rain"] = Thunderstorm; + conditionList["recent thunderstorm with rain"] = Thunderstorm; + conditionList["sand or dust storm"] = NotAvailable; + conditionList["severe sand or dust storm"] = NotAvailable; + conditionList["shallow fog"] = Mist; + conditionList["smoke"] = NotAvailable; + conditionList["snow"] = Snow; + conditionList["snow crystals"] = Flurries; + conditionList["snow grains"] = Flurries; + conditionList["squalls"] = Snow; + conditionList["thunderstorm with hail"] = Thunderstorm; + conditionList["thunderstorm with rain"] = Thunderstorm; + conditionList["thunderstorm with sand or dust storm"] = Thunderstorm; + conditionList["thunderstorm without precipitation"] = Thunderstorm; + conditionList["tornado"] = NotAvailable; + return conditionList; +} + + +QMap EnvCanadaIon::setupForecastIconMappings(void) const +{ + QMap forecastList; + + // Abbreviated forecast descriptions + forecastList["a few flurries"] = Flurries; + forecastList["a few flurries mixed with ice pellets"] = RainSnow; + forecastList["a few flurries or rain showers"] = RainSnow; + forecastList["a few flurries or thundershowers"] = RainSnow; + forecastList["a few rain showers or flurries"] = RainSnow; + forecastList["a few rain showers or wet flurries"] = RainSnow; + forecastList["a few showers"] = LightRain; + forecastList["a few showers or drizzle"] = LightRain; + forecastList["a few showers or thundershowers"] = Thunderstorm; + forecastList["a few showers or thunderstorms"] = Thunderstorm; + forecastList["a few thundershowers"] = Thunderstorm; + forecastList["a few thunderstorms"] = Thunderstorm; + forecastList["a few wet flurries"] = RainSnow; + forecastList["a few wet flurries or rain showers"] = RainSnow; + forecastList["a mix of sun and cloud"] = PartlyCloudyDay; + forecastList["cloudy with sunny periods"] = PartlyCloudyDay; + forecastList["partly cloudy"] = PartlyCloudyDay; + forecastList["mainly sunny"] = FewCloudsDay; + forecastList["sunny"] = ClearDay; + forecastList["blizzard"] = Snow; + forecastList["clear"] = ClearNight; + forecastList["cloudy"] = Overcast; + forecastList["drizzle"] = LightRain; + forecastList["drizzle mixed with freezing drizzle"] = FreezingDrizzle; + forecastList["drizzle mixed with rain"] = LightRain; + forecastList["drizzle or freezing drizzle"] = LightRain; + forecastList["drizzle or rain"] = LightRain; + forecastList["flurries"] = Flurries; + forecastList["flurries at times heavy"] = Flurries; + forecastList["flurries at times heavy or rain snowers"] = RainSnow; + forecastList["flurries mixed with ice pellets"] = FreezingRain; + forecastList["flurries or ice pellets"] = FreezingRain; + forecastList["flurries or rain showers"] = RainSnow; + forecastList["flurries or thundershowers"] = Flurries; + forecastList["fog"] = Mist; + forecastList["fog developing"] = Mist; + forecastList["fog dissipating"] = Mist; + forecastList["fog patches"] = Mist; + forecastList["freezing drizzle"] = FreezingDrizzle; + forecastList["freezing rain"] = FreezingRain; + forecastList["freezing rain mixed with rain"] = FreezingRain; + forecastList["freezing rain mixed with snow"] = FreezingRain; + forecastList["freezing rain or ice pellets"] = FreezingRain; + forecastList["freezing rain or rain"] = FreezingRain; + forecastList["freezing rain or snow"] = FreezingRain; + forecastList["ice fog"] = Mist; + forecastList["ice fog developing"] = Mist; + forecastList["ice fog dissipating"] = Mist; + forecastList["ice pellet"] = Hail; + forecastList["ice pellet mixed with freezing rain"] = Hail; + forecastList["ice pellet mixed with snow"] = Hail; + forecastList["ice pellet or snow"] = RainSnow; + forecastList["light snow"] = LightSnow; + forecastList["light snow and blizzard"] = LightSnow; + forecastList["light snow and blizzard and blowing snow"] = Snow; + forecastList["light snow and blowing snow"] = LightSnow; + forecastList["light snow mixed with freezing drizzle"] = FreezingDrizzle; + forecastList["light snow mixed with freezing rain"] = FreezingRain; + forecastList["light snow or ice pellets"] = LightSnow; + forecastList["light snow or rain"] = RainSnow; + forecastList["light wet snow"] = RainSnow; + forecastList["light wet snow or rain"] = RainSnow; + forecastList["local snow squalls"] = Snow; + forecastList["near blizzard"] = Snow; + forecastList["overcast"] = Overcast; + forecastList["increasing cloudiness"] = Overcast; + forecastList["increasing clouds"] = Overcast; + forecastList["periods of drizzle"] = LightRain; + forecastList["periods of drizzle mixed with freezing drizzle"] = FreezingDrizzle; + forecastList["periods of drizzle mixed with rain"] = LightRain; + forecastList["periods of drizzle or freezing drizzle"] = FreezingDrizzle; + forecastList["periods of drizzle or rain"] = LightRain; + forecastList["periods of freezing drizzle"] = FreezingDrizzle; + forecastList["periods of freezing drizzle or drizzle"] = FreezingDrizzle; + forecastList["periods of freezing drizzle or rain"] = FreezingDrizzle; + forecastList["periods of freezing rain"] = FreezingRain; + forecastList["periods of freezing rain mixed with ice pellets"] = FreezingRain; + forecastList["periods of freezing rain mixed with rain"] = FreezingRain; + forecastList["periods of freezing rain mixed with snow"] = FreezingRain; + forecastList["periods of freezing rain mixed with freezing drizzle"] = FreezingRain; + forecastList["periods of freezing rain or ice pellets"] = FreezingRain; + forecastList["periods of freezing rain or rain"] = FreezingRain; + forecastList["periods of freezing rain or snow"] = FreezingRain; + forecastList["periods of ice pellet"] = Hail; + forecastList["periods of ice pellet mixed with freezing rain"] = Hail; + forecastList["periods of ice pellet mixed with snow"] = Hail; + forecastList["periods of ice pellet or freezing rain"] = Hail; + forecastList["periods of ice pellet or snow"] = Hail; + forecastList["periods of light snow"] = LightSnow; + forecastList["periods of light snow and blizzard"] = Snow; + forecastList["periods of light snow and blizzard and blowing snow"] = Snow; + forecastList["periods of light snow and blowing snow"] = LightSnow; + forecastList["periods of light snow mixed with freezing drizzle"] = RainSnow; + forecastList["periods of light snow mixed with freezing rain"] = RainSnow; + forecastList["periods of light snow mixed with ice pelletS"] = LightSnow; + forecastList["periods of light snow mixed with rain"] = RainSnow; + forecastList["periods of light snow or freezing drizzle"] = RainSnow; + forecastList["periods of light snow or freezing rain"] = RainSnow; + forecastList["periods of light snow or ice pellets"] = LightSnow; + forecastList["periods of light snow or rain"] = RainSnow; + forecastList["periods of light wet snow"] = LightSnow; + forecastList["periods of light wet snow mixed with rain"] = RainSnow; + forecastList["periods of light wet snow or rain"] = RainSnow; + forecastList["periods of rain"] = Rain; + forecastList["periods of rain mixed with freezing rain"] = Rain; + forecastList["periods of rain mixed with snow"] = RainSnow; + forecastList["periods of rain or drizzle"] = Rain; + forecastList["periods of rain or freezing rain"] = Rain; + forecastList["periods of rain or thundershowers"] = Showers; + forecastList["periods of rain or thunderstorms"] = Thunderstorm; + forecastList["periods of rain or snow"] = RainSnow; + forecastList["periods of snow"] = Snow; + forecastList["periods of snow and blizzard"] = Snow; + forecastList["periods of snow and blizzard and blowing snow"] = Snow; + forecastList["periods of snow and blowing snow"] = Snow; + forecastList["periods of snow mixed with freezing drizzle"] = RainSnow; + forecastList["periods of snow mixed with freezing rain"] = RainSnow; + forecastList["periods of snow mixed with ice pellets"] = Snow; + forecastList["periods of snow mixed with rain"] = RainSnow; + forecastList["periods of snow or freezing drizzle"] = RainSnow; + forecastList["periods of snow or freezing rain"] = RainSnow; + forecastList["periods of snow or ice pellets"] = Snow; + forecastList["periods of snow or rain"] = RainSnow; + forecastList["periods of rain or snow"] = RainSnow; + forecastList["periods of wet snow"] = Snow; + forecastList["periods of wet snow mixed with rain"] = RainSnow; + forecastList["periods of wet snow or rain"] = RainSnow; + forecastList["rain"] = Rain; + forecastList["rain at times heavy"] = Rain; + forecastList["rain at times heavy mixed with freezing rain"] = FreezingRain; + forecastList["rain at times heavy mixed with snow"] = RainSnow; + forecastList["rain at times heavy or drizzle"] = Rain; + forecastList["rain at times heavy or freezing rain"] = Rain; + forecastList["rain at times heavy or snow"] = RainSnow; + forecastList["rain at times heavy or thundershowers"] = Showers; + forecastList["rain at times heavy or thunderstorms"] = Thunderstorm; + forecastList["rain mixed with freezing rain"] = FreezingRain; + forecastList["rain mixed with snow"] = RainSnow; + forecastList["rain or drizzle"] = Rain; + forecastList["rain or freezing rain"] = Rain; + forecastList["rain or snow"] = RainSnow; + forecastList["rain or thundershowers"] = Showers; + forecastList["rain or thunderstorms"] = Thunderstorm; + forecastList["rain showers or flurries"] = RainSnow; + forecastList["rain showers or wet flurries"] = RainSnow; + forecastList["showers"] = Showers; + forecastList["showers at times heavy"] = Showers; + forecastList["showers at times heavy or thundershowers"] = Showers; + forecastList["showers at times heavy or thunderstorms"] = Thunderstorm; + forecastList["showers or drizzle"] = Showers; + forecastList["showers or thundershowers"] = Thunderstorm; + forecastList["showers or thunderstorms"] = Thunderstorm; + forecastList["smoke"] = NotAvailable; + forecastList["snow"] = Snow; + forecastList["snow and blizzard"] = Snow; + forecastList["snow and blizzard and blowing snow"] = Snow; + forecastList["snow and blowing snow"] = Snow; + forecastList["snow at times heavy"] = Snow; + forecastList["snow at times heavy and blizzard"] = Snow; + forecastList["snow at times heavy and blowing snow"] = Snow; + forecastList["snow at times heavy mixed with freezing drizzle"] = RainSnow; + forecastList["snow at times heavy mixed with freezing rain"] = RainSnow; + forecastList["snow at times heavy mixed with ice pellets"] = Snow; + forecastList["snow at times heavy mixed with rain"] = RainSnow; + forecastList["snow at times heavy or freezing rain"] = RainSnow; + forecastList["snow at times heavy or ice pellets"] = Snow; + forecastList["snow at times heavy or rain"] = RainSnow; + forecastList["snow mixed with freezing drizzle"] = RainSnow; + forecastList["snow mixed with freezing rain"] = RainSnow; + forecastList["snow mixed with ice pellets"] = Snow; + forecastList["snow mixed with rain"] = RainSnow; + forecastList["snow or freezing drizzle"] = RainSnow; + forecastList["snow or freezing rain"] = RainSnow; + forecastList["snow or ice pellets"] = Snow; + forecastList["snow or rain"] = RainSnow; + forecastList["snow squalls"] = Snow; + forecastList["sunny"] = ClearDay; + forecastList["sunny with cloudy periods"] = PartlyCloudyDay; + forecastList["thunderstorms"] = Thunderstorm; + forecastList["thunderstorms and possible hail"] = Thunderstorm; + forecastList["wet flurries"] = Flurries; + forecastList["wet flurries at times heavy"] = Flurries; + forecastList["wet flurries at times heavy or rain snowers"] = RainSnow; + forecastList["wet flurries or rain showers"] = RainSnow; + forecastList["wet snow"] = Snow; + forecastList["wet snow at times heavy"] = Snow; + forecastList["wet snow at times heavy mixed with rain"] = RainSnow; + forecastList["wet snow mixed with rain"] = RainSnow; + forecastList["wet snow or rain"] = RainSnow; + forecastList["windy"] = NotAvailable; + + forecastList["chance of drizzle mixed with freezing drizzle"] = LightRain; + forecastList["chance of flurries mixed with ice pellets"] = Flurries; + forecastList["chance of flurries or ice pellets"] = Flurries; + forecastList["chance of flurries or rain showers"] = RainSnow; + forecastList["chance of flurries or thundershowers"] = RainSnow; + forecastList["chance of freezing drizzle"] = FreezingDrizzle; + forecastList["chance of freezing rain"] = FreezingRain; + forecastList["chance of freezing rain mixed with snow"] = RainSnow; + forecastList["chance of freezing rain or rain"] = FreezingRain; + forecastList["chance of freezing rain or snow"] = RainSnow; + forecastList["chance of light snow and blowing snow"] = LightSnow; + forecastList["chance of light snow mixed with freezing drizzle"] = LightSnow; + forecastList["chance of light snow mixed with ice pellets"] = LightSnow; + forecastList["chance of light snow mixed with rain"] = RainSnow; + forecastList["chance of light snow or freezing rain"] = RainSnow; + forecastList["chance of light snow or ice pellets"] = LightSnow; + forecastList["chance of light snow or rain"] = RainSnow; + forecastList["chance of light wet snow"] = Snow; + forecastList["chance of rain"] = Rain; + forecastList["chance of rain at times heavy"] = Rain; + forecastList["chance of rain mixed with snow"] = RainSnow; + forecastList["chance of rain or drizzle"] = Rain; + forecastList["chance of rain or freezing rain"] = Rain; + forecastList["chance of rain or snow"] = RainSnow; + forecastList["chance of rain showers or flurries"] = RainSnow; + forecastList["chance of rain showers or wet flurries"] = RainSnow; + forecastList["chance of severe thunderstorms"] = Thunderstorm; + forecastList["chance of showers at times heavy"] = Rain; + forecastList["chance of showers at times heavy or thundershowers"] = Thunderstorm; + forecastList["chance of showers at times heavy or thunderstorms"] = Thunderstorm; + forecastList["chance of showers or thundershowers"] = Thunderstorm; + forecastList["chance of showers or thunderstorms"] = Thunderstorm; + forecastList["chance of snow"] = Snow; + forecastList["chance of snow and blizzard"] = Snow; + forecastList["chance of snow mixed with freezing drizzle"] = Snow; + forecastList["chance of snow mixed with freezing rain"] = RainSnow; + forecastList["chance of snow mixed with rain"] = RainSnow; + forecastList["chance of snow or rain"] = RainSnow; + forecastList["chance of snow squalls"] = Snow; + forecastList["chance of thundershowers"] = Showers; + forecastList["chance of thunderstorms"] = Thunderstorm; + forecastList["chance of thunderstorms and possible hail"] = Thunderstorm; + forecastList["chance of wet flurries"] = Flurries; + forecastList["chance of wet flurries at times heavy"] = Flurries; + forecastList["chance of wet flurries or rain showers"] = RainSnow; + forecastList["chance of wet snow"] = Snow; + forecastList["chance of wet snow mixed with rain"] = RainSnow; + forecastList["chance of wet snow or rain"] = RainSnow; + + return forecastList; +} + +QMap const& EnvCanadaIon::conditionIcons(void) const +{ + static QMap const condval = setupConditionIconMappings(); + return condval; +} + +QMap const& EnvCanadaIon::forecastIcons(void) const +{ + static QMap const foreval = setupForecastIconMappings(); + return foreval; +} + +QStringList EnvCanadaIon::validate(const QString& source) const +{ + QStringList placeList; + QString sourceNormalized = source.toUpper(); + QHash::const_iterator it = m_places.constBegin(); + while (it != m_places.constEnd()) { + if (it.key().toUpper().contains(sourceNormalized)) { + placeList.append(QString("place|").append(it.key())); + } + ++it; + } + + // Check if placeList is empty if so, return nothing. + if (placeList.isEmpty()) { + return QStringList(); + } + placeList.sort(); + return placeList; +} + +// Get a specific Ion's data +bool EnvCanadaIon::updateIonSource(const QString& source) +{ + //kDebug() << "updateIonSource()" << source; + + // We expect the applet to send the source in the following tokenization: + // ionname|validate|place_name - Triggers validation of place + // ionname|weather|place_name - Triggers receiving weather of place + + QStringList sourceAction = source.split('|'); + + // Guard: if the size of array is not 2 then we have bad data, return an error + if (sourceAction.size() < 2) { + setData(source, "validate", "envcan|malformed"); + return true; + } + + if (sourceAction[1] == "validate" && sourceAction.size() > 2) { + QStringList result = validate(sourceAction[2]); + + if (result.size() == 1) { + setData(source, "validate", QString("envcan|valid|single|").append(result.join("|"))); + return true; + } else if (result.size() > 1) { + setData(source, "validate", QString("envcan|valid|multiple|").append(result.join("|"))); + return true; + } else if (result.size() == 0) { + setData(source, "validate", QString("envcan|invalid|single|").append(sourceAction[2])); + return true; + } + + } else if (sourceAction[1] == "weather" && sourceAction.size() > 2) { + getXMLData(source); + return true; + } else { + setData(source, "validate", "envcan|malformed"); + return true; + } + return false; +} + +// Parses city list and gets the correct city based on ID number +void EnvCanadaIon::getXMLSetup() +{ + //kDebug() << "getXMLSetup()"; + + // If network is down, we need to spin and wait + + KIO::TransferJob *job = KIO::get(KUrl("http://dd.weatheroffice.ec.gc.ca/citypage_weather/xml/siteList.xml"), KIO::NoReload, KIO::HideProgressInfo); + + m_xmlSetup.clear(); + connect(job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(setup_slotDataArrived(KIO::Job*,QByteArray))); + connect(job, SIGNAL(result(KJob*)), this, SLOT(setup_slotJobFinished(KJob*))); +} + +// Gets specific city XML data +void EnvCanadaIon::getXMLData(const QString& source) +{ + foreach (const QString &fetching, m_jobList) { + if (fetching == source) { + // already getting this source and awaiting the data + return; + } + } + + //kDebug() << source; + + // Demunge source name for key only. + QString dataKey = source; + dataKey.remove("envcan|weather|"); + + KUrl url = QString("http://dd.weatheroffice.ec.gc.ca/citypage_weather/xml/" + m_places[dataKey].territoryName + "/" + m_places[dataKey].cityCode + "_e.xml"); + //url="file:///home/spstarr/Desktop/s0000649_e.xml"; + //kDebug() << "Will Try URL: " << url; + + if (m_places[dataKey].territoryName.isEmpty() && m_places[dataKey].cityCode.isEmpty()) { + setData(source, "validate", QString("envcan|malformed")); + return; + } + + KIO::TransferJob* const newJob = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); + + m_jobXml.insert(newJob, new QXmlStreamReader); + m_jobList.insert(newJob, source); + + connect(newJob, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(slotDataArrived(KIO::Job*,QByteArray))); + connect(newJob, SIGNAL(result(KJob*)), this, SLOT(slotJobFinished(KJob*))); +} + +void EnvCanadaIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + Q_UNUSED(job) + + if (data.isEmpty()) { + //kDebug() << "done!"; + return; + } + + // Send to xml. + //kDebug() << data; + m_xmlSetup.addData(data); +} + +void EnvCanadaIon::slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + + if (data.isEmpty() || !m_jobXml.contains(job)) { + return; + } + + // Send to xml. + m_jobXml[job]->addData(data); +} + +void EnvCanadaIon::slotJobFinished(KJob *job) +{ + // Dual use method, if we're fetching location data to parse we need to do this first + const QString source = m_jobList.value(job); + //kDebug() << source << m_sourcesToReset.contains(source); + setData(source, Data()); + QXmlStreamReader *reader = m_jobXml.value(job); + if (reader) { + readXMLData(m_jobList[job], *reader); + } + + m_jobList.remove(job); + delete m_jobXml[job]; + m_jobXml.remove(job); + + if (m_sourcesToReset.contains(source)) { + m_sourcesToReset.removeAll(source); + + // so the weather engine updates it's data + forceImmediateUpdateOfAllVisualizations(); + + // update the clients of our engine + emit forceUpdate(this, source); + } +} + +void EnvCanadaIon::setup_slotJobFinished(KJob *job) +{ + Q_UNUSED(job) + const bool success = readXMLSetup(); + m_xmlSetup.clear(); + //kDebug() << success << m_sourcesToReset; + setInitialized(success); +} + +// Parse the city list and store into a QMap +bool EnvCanadaIon::readXMLSetup() +{ + bool success = false; + QString territory; + QString code; + QString cityName; + + //kDebug() << "readXMLSetup()"; + + while (!m_xmlSetup.atEnd()) { + m_xmlSetup.readNext(); + + if (m_xmlSetup.isStartElement()) { + + // XML ID code to match filename + if (m_xmlSetup.name() == "site") { + code = m_xmlSetup.attributes().value("code").toString(); + } + + if (m_xmlSetup.name() == "nameEn") { + cityName = m_xmlSetup.readElementText(); // Name of cities + } + + if (m_xmlSetup.name() == "provinceCode") { + territory = m_xmlSetup.readElementText(); // Provinces/Territory list + } + } + + if (m_xmlSetup.isEndElement() && m_xmlSetup.name() == "site") { + EnvCanadaIon::XMLMapInfo info; + QString tmp = cityName + ", " + territory; // Build the key name. + + // Set the mappings + info.cityCode = code; + info.territoryName = territory; + info.cityName = cityName; + + // Set the string list, we will use for the applet to display the available cities. + m_places[tmp] = info; + success = true; + } + + } + + return (success && !m_xmlSetup.error()); +} + +void EnvCanadaIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml) +{ + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + if (xml.name() == "license") { + xml.readElementText(); + } else if (xml.name() == "location") { + parseLocations(data, xml); + } else if (xml.name() == "warnings") { + // Cleanup warning list on update + data.warnings.clear(); + data.watches.clear(); + parseWarnings(data, xml); + } else if (xml.name() == "currentConditions") { + parseConditions(data, xml); + } else if (xml.name() == "forecastGroup") { + // Clean up forecast list on update + data.forecasts.clear(); + parseWeatherForecast(data, xml); + } else if (xml.name() == "yesterdayConditions") { + parseYesterdayWeather(data, xml); + } else if (xml.name() == "riseSet") { + parseAstronomicals(data, xml); + } else if (xml.name() == "almanac") { + parseWeatherRecords(data, xml); + } else { + parseUnknownElement(xml); + } + } + } +} + +// Parse Weather data main loop, from here we have to decend into each tag pair +bool EnvCanadaIon::readXMLData(const QString& source, QXmlStreamReader& xml) +{ + WeatherData data; + data.comforttemp = i18n("N/A"); + data.recordHigh = 0.0; + data.recordLow = 0.0; + + //kDebug() << "readXMLData()"; + + QString dataKey = source; + dataKey.remove("envcan|weather|"); + data.shortTerritoryName = m_places[dataKey].territoryName; + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "siteData") { + parseWeatherSite(data, xml); + } else { + parseUnknownElement(xml); + } + } + } + + m_weatherData[source] = data; + updateWeather(source); + return !xml.error(); +} + +void EnvCanadaIon::parseDateTime(WeatherData& data, QXmlStreamReader& xml, WeatherData::WeatherEvent *event) +{ + + Q_ASSERT(xml.isStartElement() && xml.name() == "dateTime"); + + // What kind of date info is this? + QString dateType = xml.attributes().value("name").toString(); + QString dateZone = xml.attributes().value("zone").toString(); + + QString selectTimeStamp; + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (dateType == "xmlCreation") { + return; + } + if (dateZone == "UTC") { + return; + } + if (xml.name() == "year") { + xml.readElementText(); + } else if (xml.name() == "month") { + xml.readElementText(); + } else if (xml.name() == "day") { + xml.readElementText(); + } else if (xml.name() == "hour") + xml.readElementText(); + else if (xml.name() == "minute") + xml.readElementText(); + else if (xml.name() == "timeStamp") + selectTimeStamp = xml.readElementText(); + else if (xml.name() == "textSummary") { + if (dateType == "eventIssue") { + if (event) { + event->timestamp = xml.readElementText(); + } + } else if (dateType == "observation") { + xml.readElementText(); + m_dateFormat = QDateTime::fromString(selectTimeStamp, "yyyyMMddHHmmss"); + data.obsTimestamp = m_dateFormat.toString("dd.MM.yyyy @ hh:mm"); + data.iconPeriodHour = m_dateFormat.toString("hh").toInt(); + data.iconPeriodMinute = m_dateFormat.toString("mm").toInt(); + } else if (dateType == "forecastIssue") { + data.forecastTimestamp = xml.readElementText(); + } else if (dateType == "sunrise") { + data.sunriseTimestamp = xml.readElementText(); + } else if (dateType == "sunset") { + data.sunsetTimestamp = xml.readElementText(); + } else if (dateType == "moonrise") { + data.moonriseTimestamp = xml.readElementText(); + } else if (dateType == "moonset") { + data.moonsetTimestamp = xml.readElementText(); + } + } + } + } +} + +void EnvCanadaIon::parseLocations(WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "location"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "country") { + data.countryName = xml.readElementText(); + } else if (xml.name() == "province" || xml.name() == "territory") { + data.longTerritoryName = xml.readElementText(); + } else if (xml.name() == "name") { + data.cityName = xml.readElementText(); + } else if (xml.name() == "region") { + data.regionName = xml.readElementText(); + } else { + parseUnknownElement(xml); + } + } + } +} + +void EnvCanadaIon::parseWindInfo(WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "wind"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "speed") { + data.windSpeed = xml.readElementText(); + } else if (xml.name() == "gust") { + data.windGust = xml.readElementText(); + } else if (xml.name() == "direction") { + data.windDirection = xml.readElementText(); + } else if (xml.name() == "bearing") { + data.windDegrees = xml.attributes().value("degrees").toString(); + } else { + parseUnknownElement(xml); + } + } + } +} + +void EnvCanadaIon::parseConditions(WeatherData& data, QXmlStreamReader& xml) +{ + + Q_ASSERT(xml.isStartElement() && xml.name() == "currentConditions"); + data.temperature = i18n("N/A"); + data.dewpoint = i18n("N/A"); + data.condition = i18n("N/A"); + data.comforttemp = i18n("N/A"); + data.stationID = i18n("N/A"); + data.stationLat = i18n("N/A"); + data.stationLon = i18n("N/A"); + data.pressure = 0.0; + data.pressureTendency = i18n("N/A"); + data.visibility = 0; + data.humidity = i18n("N/A"); + data.windSpeed = i18n("N/A"); + data.windGust = i18n("N/A"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "currentConditions") + break; + + if (xml.isStartElement()) { + if (xml.name() == "station") { + data.stationID = xml.attributes().value("code").toString(); + data.stationLat = xml.attributes().value("lat").toString(); + data.stationLon = xml.attributes().value("lon").toString(); + } else if (xml.name() == "dateTime") { + parseDateTime(data, xml); + } else if (xml.name() == "condition") { + data.condition = xml.readElementText(); + } else if (xml.name() == "temperature") { + data.temperature = xml.readElementText(); + } else if (xml.name() == "dewpoint") { + data.dewpoint = xml.readElementText(); + } else if (xml.name() == "humidex" || xml.name() == "windChill") { + data.comforttemp = xml.readElementText(); + } else if (xml.name() == "pressure") { + data.pressureTendency = xml.attributes().value("tendency").toString(); + if (data.pressureTendency.isEmpty()) { + data.pressureTendency = "steady"; + } + data.pressure = xml.readElementText().toFloat(); + } else if (xml.name() == "visibility") { + data.visibility = xml.readElementText().toFloat(); + } else if (xml.name() == "relativeHumidity") { + data.humidity = xml.readElementText(); + } else if (xml.name() == "wind") { + parseWindInfo(data, xml); + } + //} else { + // parseUnknownElement(xml); + //} + } + } + if (data.temperature.isEmpty()) { + data.temperature = i18n("N/A"); + } +} + +void EnvCanadaIon::parseWarnings(WeatherData &data, QXmlStreamReader& xml) +{ + WeatherData::WeatherEvent *watch = new WeatherData::WeatherEvent; + WeatherData::WeatherEvent *warning = new WeatherData::WeatherEvent; + + Q_ASSERT(xml.isStartElement() && xml.name() == "warnings"); + QString eventURL = xml.attributes().value("url").toString(); + int flag = 0; + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "warnings") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "dateTime") { + if (flag == 1) { + parseDateTime(data, xml, watch); + } + if (flag == 2) { + parseDateTime(data, xml, warning); + } + + if (!warning->timestamp.isEmpty() && !warning->url.isEmpty()) { + data.warnings.append(warning); + warning = new WeatherData::WeatherEvent; + } + if (!watch->timestamp.isEmpty() && !watch->url.isEmpty()) { + data.watches.append(watch); + watch = new WeatherData::WeatherEvent; + } + + } else if (xml.name() == "event") { + // Append new event to list. + QString eventType = xml.attributes().value("type").toString(); + if (eventType == "watch") { + watch->url = eventURL; + watch->type = eventType; + watch->priority = xml.attributes().value("priority").toString(); + watch->description = xml.attributes().value("description").toString(); + flag = 1; + } + + if (eventType == "warning") { + warning->url = eventURL; + warning->type = eventType; + warning->priority = xml.attributes().value("priority").toString(); + warning->description = xml.attributes().value("description").toString(); + flag = 2; + } + } else { + if (xml.name() != "dateTime") { + parseUnknownElement(xml); + } + } + } + } + delete watch; + delete warning; +} + + +void EnvCanadaIon::parseWeatherForecast(WeatherData& data, QXmlStreamReader& xml) +{ + WeatherData::ForecastInfo* forecast = new WeatherData::ForecastInfo; + Q_ASSERT(xml.isStartElement() && xml.name() == "forecastGroup"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "forecastGroup") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "dateTime") { + parseDateTime(data, xml); + } else if (xml.name() == "regionalNormals") { + parseRegionalNormals(data, xml); + } else if (xml.name() == "forecast") { + parseForecast(data, xml, forecast); + forecast = new WeatherData::ForecastInfo; + } else { + parseUnknownElement(xml); + } + } + } + delete forecast; +} + +void EnvCanadaIon::parseRegionalNormals(WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "regionalNormals"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "textSummary") { + xml.readElementText(); + } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") { + data.normalHigh = xml.readElementText(); + } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") { + data.normalLow = xml.readElementText(); + } + } + } +} + +void EnvCanadaIon::parseForecast(WeatherData& data, QXmlStreamReader& xml, WeatherData::ForecastInfo *forecast) +{ + + Q_ASSERT(xml.isStartElement() && xml.name() == "forecast"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "forecast") { + data.forecasts.append(forecast); + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "period") { + forecast->forecastPeriod = xml.attributes().value("textForecastName").toString(); + } else if (xml.name() == "textSummary") { + forecast->forecastSummary = xml.readElementText(); + } else if (xml.name() == "abbreviatedForecast") { + parseShortForecast(forecast, xml); + } else if (xml.name() == "temperatures") { + parseForecastTemperatures(forecast, xml); + } else if (xml.name() == "winds") { + parseWindForecast(forecast, xml); + } else if (xml.name() == "precipitation") { + parsePrecipitationForecast(forecast, xml); + } else if (xml.name() == "uv") { + data.UVRating = xml.attributes().value("category").toString(); + parseUVIndex(data, xml); + // else if (xml.name() == "frost") { FIXME: Wait until winter to see what this looks like. + // parseFrost(xml, forecast); + } else { + if (xml.name() != "forecast") { + parseUnknownElement(xml); + } + } + } + } +} + +void EnvCanadaIon::parseShortForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "abbreviatedForecast"); + + QString shortText; + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "abbreviatedForecast") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "pop") { + forecast->popPrecent = xml.readElementText(); + } + if (xml.name() == "textSummary") { + shortText = xml.readElementText(); + QMap forecastList; + forecastList = forecastIcons(); + if ((forecast->forecastPeriod == "tonight") || (forecast->forecastPeriod.contains("night"))) { + forecastList["a few clouds"] = FewCloudsNight; + forecastList["cloudy periods"] = PartlyCloudyNight; + forecastList["chance of drizzle mixed with rain"] = ChanceShowersNight; + forecastList["chance of drizzle"] = ChanceShowersNight; + forecastList["chance of drizzle or rain"] = ChanceShowersNight; + forecastList["chance of flurries"] = ChanceSnowNight; + forecastList["chance of light snow"] = ChanceSnowNight; + forecastList["chance of flurries at times heavy"] = ChanceSnowNight; + forecastList["chance of showers or drizzle"] = ChanceShowersNight; + forecastList["chance of showers"] = ChanceShowersNight; + forecastList["clearing"] = ClearNight; + } else { + forecastList["a few clouds"] = FewCloudsDay; + forecastList["cloudy periods"] = PartlyCloudyDay; + forecastList["chance of drizzle mixed with rain"] = ChanceShowersDay; + forecastList["chance of drizzle"] = ChanceShowersDay; + forecastList["chance of drizzle or rain"] = ChanceShowersDay; + forecastList["chance of flurries"] = ChanceSnowDay; + forecastList["chance of light snow"] = ChanceSnowDay; + forecastList["chance of flurries at times heavy"] = ChanceSnowDay; + forecastList["chance of showers or drizzle"] = ChanceShowersDay; + forecastList["chance of showers"] = ChanceShowersDay; + forecastList["clearing"] = ClearDay; + } + forecast->shortForecast = shortText; + forecast->iconName = getWeatherIcon(forecastList, shortText.toLower()); + } + } + } +} + +void EnvCanadaIon::parseUVIndex(WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "uv"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "uv") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "index") { + data.UVIndex = xml.readElementText(); + } + if (xml.name() == "textSummary") { + xml.readElementText(); + } + } + } +} + +void EnvCanadaIon::parseForecastTemperatures(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "temperatures"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "temperatures") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "temperature" && xml.attributes().value("class") == "low") { + forecast->forecastTempLow = xml.readElementText(); + } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") { + forecast->forecastTempHigh = xml.readElementText(); + } else if (xml.name() == "textSummary") { + xml.readElementText(); + } + } + } +} + +void EnvCanadaIon::parsePrecipitationForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "precipitation"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "precipitation") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "textSummary") { + forecast->precipForecast = xml.readElementText(); + } else if (xml.name() == "precipType") { + forecast->precipType = xml.readElementText(); + } else if (xml.name() == "accumulation") { + parsePrecipTotals(forecast, xml); + } + } + } +} + +void EnvCanadaIon::parsePrecipTotals(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "accumulation"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "accumulation") { + break; + } + + if (xml.name() == "name") { + xml.readElementText(); + } else if (xml.name() == "amount") { + forecast->precipTotalExpected = xml.readElementText(); + } + } +} + +void EnvCanadaIon::parseWindForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "winds"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "winds") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "textSummary") { + forecast->windForecast = xml.readElementText(); + } else { + if (xml.name() != "winds") { + parseUnknownElement(xml); + } + } + } + } +} + +void EnvCanadaIon::parseYesterdayWeather(WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "yesterdayConditions"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "temperature" && xml.attributes().value("class") == "high") { + data.prevHigh = xml.readElementText(); + } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") { + data.prevLow = xml.readElementText(); + } else if (xml.name() == "precip") { + data.prevPrecipType = xml.attributes().value("units").toString(); + if (data.prevPrecipType.isEmpty()) { + data.prevPrecipType = QString::number(KUnitConversion::NoUnit); + } + data.prevPrecipTotal = xml.readElementText(); + } + } + } +} + +void EnvCanadaIon::parseWeatherRecords(WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "almanac"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "almanac") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMax") { + data.recordHigh = xml.readElementText().toFloat(); + } else if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMin") { + data.recordLow = xml.readElementText().toFloat(); + } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeRainfall") { + data.recordRain = xml.readElementText().toFloat(); + } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeSnowfall") { + data.recordSnow = xml.readElementText().toFloat(); + } + } + } +} + +void EnvCanadaIon::parseAstronomicals(WeatherData& data, QXmlStreamReader& xml) +{ + Q_ASSERT(xml.isStartElement() && xml.name() == "riseSet"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement() && xml.name() == "riseSet") { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "disclaimer") { + xml.readElementText(); + } else if (xml.name() == "dateTime") { + parseDateTime(data, xml); + } + } + } +} + +// handle when no XML tag is found +void EnvCanadaIon::parseUnknownElement(QXmlStreamReader& xml) const +{ + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + parseUnknownElement(xml); + } + } +} + +void EnvCanadaIon::updateWeather(const QString& source) +{ + //kDebug() << "updateWeather()"; + + QMap dataFields; + Plasma::DataEngine::Data data; + QStringList fieldList; + QVector forecastList; + int i = 0; + + data.insert("Country", country(source)); + data.insert("Place", QString("%1, %2").arg(city(source)).arg(territory(source))); + data.insert("Region", region(source)); + data.insert("Station", station(source)); + + data.insert("Latitude", latitude(source)); + data.insert("Longitude", longitude(source)); + + // Real weather - Current conditions + data.insert("Observation Period", observationTime(source)); + data.insert("Current Conditions", i18nc("weather condition", condition(source).toUtf8())); + //kDebug() << "i18n condition string: " << qPrintable(condition(source)); + + // Tell applet which icon to use for conditions and provide mapping for condition type to the icons to display + QMap conditionList; + conditionList = conditionIcons(); + + const double lati = latitude(source).replace(QRegExp("[^0-9.]"), NULL).toDouble(); + const double longi = longitude(source).replace(QRegExp("[^0-9.]"), NULL).toDouble(); + const Plasma::DataEngine::Data timeData = m_timeEngine->query( + QString("Local|Solar|Latitude=%1|Longitude=%2") + .arg(lati).arg(-1 * longi)); + + if (timeData["Corrected Elevation"].toDouble() < 0.0) { + conditionList["decreasing cloud"] = FewCloudsNight; + conditionList["mostly cloudy"] = PartlyCloudyNight; + conditionList["partly cloudy"] = PartlyCloudyNight; + conditionList["fair"] = FewCloudsNight; + //kDebug() << "Before sunrise/After sunset - using night icons\n"; + } else { + conditionList["decreasing cloud"] = FewCloudsDay; + conditionList["mostly cloudy"] = PartlyCloudyDay; + conditionList["partly cloudy"] = PartlyCloudyDay; + conditionList["fair"] = FewCloudsDay; + //kDebug() << "Using daytime icons\n"; + } + + data.insert("Condition Icon", getWeatherIcon(conditionList, condition(source))); + + dataFields = temperature(source); + data.insert("Temperature", dataFields["temperature"]); + + // Do we have a comfort temperature? if so display it + if (dataFields["comfortTemperature"] != "N/A" && !dataFields["comfortTemperature"].isEmpty()) { + if (dataFields["comfortTemperature"].toFloat() <= 0) { + data.insert("Windchill", QString("%1").arg(dataFields["comfortTemperature"])); + data.insert("Humidex", i18n("N/A")); + } else { + data.insert("Humidex", QString("%1").arg(dataFields["comfortTemperature"])); + data.insert("Windchill", i18n("N/A")); + } + } else { + data.insert("Windchill", i18n("N/A")); + data.insert("Humidex", i18n("N/A")); + } + + // Used for all temperatures + data.insert("Temperature Unit", dataFields["temperatureUnit"]); + + data.insert("Dewpoint", dewpoint(source)); + + dataFields = pressure(source); + data.insert("Pressure", dataFields["pressure"]); + data.insert("Pressure Unit", dataFields["pressureUnit"]); + data.insert("Pressure Tendency", dataFields["pressureTendency"]); + + dataFields = visibility(source); + data.insert("Visibility", dataFields["visibility"]); + data.insert("Visibility Unit", dataFields["visibilityUnit"]); + + dataFields = humidity(source); + data.insert("Humidity", dataFields["humidity"]); + data.insert("Humidity Unit", dataFields["humidityUnit"]); + + dataFields = wind(source); + data.insert("Wind Speed", dataFields["windSpeed"]); + data.insert("Wind Speed Unit", dataFields["windUnit"]); + + data.insert("Wind Gust", dataFields["windGust"]); + data.insert("Wind Direction", dataFields["windDirection"]); + data.insert("Wind Degrees", dataFields["windDegrees"]); + data.insert("Wind Gust Unit", dataFields["windGustUnit"]); + + dataFields = regionalTemperatures(source); + data.insert("Normal High", dataFields["normalHigh"]); + data.insert("Normal Low", dataFields["normalLow"]); + + // Check if UV index is available for the location + dataFields = uvIndex(source); + data.insert("UV Index", dataFields["uvIndex"]); + data.insert("UV Rating", dataFields["uvRating"]); + + dataFields = watches(source); + + // Set number of forecasts per day/night supported + data.insert("Total Watches Issued", m_weatherData[source].watches.size()); + + // Check if we have warnings or watches + for (int i = 0; i < m_weatherData[source].watches.size(); i++) { + fieldList = dataFields[QString("watch %1").arg(i)].split('|'); + data.insert(QString("Watch Priority %1").arg(i), fieldList[0]); + data.insert(QString("Watch Description %1").arg(i), fieldList[1]); + data.insert(QString("Watch Info %1").arg(i), fieldList[2]); + data.insert(QString("Watch Timestamp %1").arg(i), fieldList[3]); + } + + dataFields = warnings(source); + + data.insert("Total Warnings Issued", m_weatherData[source].warnings.size()); + + for (int k = 0; k < m_weatherData[source].warnings.size(); k++) { + fieldList = dataFields[QString("warning %1").arg(k)].split('|'); + data.insert(QString("Warning Priority %1").arg(k), fieldList[0]); + data.insert(QString("Warning Description %1").arg(k), fieldList[1]); + data.insert(QString("Warning Info %1").arg(k), fieldList[2]); + data.insert(QString("Warning Timestamp %1").arg(k), fieldList[3]); + } + + forecastList = forecasts(source); + + // Set number of forecasts per day/night supported + data.insert("Total Weather Days", m_weatherData[source].forecasts.size()); + + foreach(const QString &forecastItem, forecastList) { + fieldList = forecastItem.split('|'); + + data.insert(QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6") \ + .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[5])); + + /* + data.insert(QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \ + .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[6]) \ + .arg(fieldList[7]).arg(fieldList[8]).arg(fieldList[9])); + */ + i++; + } + + dataFields = yesterdayWeather(source); + data.insert("Yesterday High", dataFields["prevHigh"]); + data.insert("Yesterday Low", dataFields["prevLow"]); + + data.insert("Yesterday Precip Total", dataFields["prevPrecip"]); + data.insert("Yesterday Precip Unit", dataFields["prevPrecipUnit"]); + + dataFields = sunriseSet(source); + data.insert("Sunrise At", dataFields["sunrise"]); + data.insert("Sunset At", dataFields["sunset"]); + + dataFields = moonriseSet(source); + data.insert("Moonrise At", dataFields["moonrise"]); + data.insert("Moonset At", dataFields["moonset"]); + + dataFields = weatherRecords(source); + data.insert("Record High Temperature", dataFields["recordHigh"]); + data.insert("Record Low Temperature", dataFields["recordLow"]); + + data.insert("Record Rainfall", dataFields["recordRain"]); + data.insert("Record Rainfall Unit", dataFields["recordRainUnit"]); + data.insert("Record Snowfall", dataFields["recordSnow"]); + data.insert("Record Snowfall Unit", dataFields["recordSnowUnit"]); + + data.insert("Credit", i18n("Meteorological data is provided by Environment Canada")); + setData(source, data); +} + +QString const EnvCanadaIon::country(const QString& source) const +{ + // This will always return Canada + return m_weatherData[source].countryName; +} + +QString EnvCanadaIon::territory(const QString& source) const +{ + return m_weatherData[source].shortTerritoryName; +} + +QString EnvCanadaIon::city(const QString& source) const +{ + return m_weatherData[source].cityName; +} + +QString EnvCanadaIon::region(const QString& source) const +{ + return m_weatherData[source].regionName; +} + +QString EnvCanadaIon::station(const QString& source) const +{ + if (!m_weatherData[source].stationID.isEmpty()) { + return m_weatherData[source].stationID.toUpper(); + } + + return i18n("N/A"); +} + +QString EnvCanadaIon::latitude(const QString& source) const +{ + return m_weatherData[source].stationLat; +} + +QString EnvCanadaIon::longitude(const QString& source) const +{ + return m_weatherData[source].stationLon; +} + +QString EnvCanadaIon::observationTime(const QString& source) const +{ + return m_weatherData[source].obsTimestamp; +} + +int EnvCanadaIon::periodHour(const QString& source) const +{ + return m_weatherData[source].iconPeriodHour; +} + +int EnvCanadaIon::periodMinute(const QString& source) const +{ + return m_weatherData[source].iconPeriodMinute; +} + +QString EnvCanadaIon::condition(const QString& source) +{ + if (m_weatherData[source].condition.isEmpty()) { + m_weatherData[source].condition = i18n("N/A"); + } + return (m_weatherData[source].condition.toUtf8()); +} + +QString EnvCanadaIon::dewpoint(const QString& source) const +{ + if (!m_weatherData[source].dewpoint.isEmpty()) { + return (QString::number(m_weatherData[source].dewpoint.toFloat(), 'f', 1)); + } + return i18n("N/A"); +} + +QMap EnvCanadaIon::humidity(const QString& source) const +{ + QMap humidityInfo; + if (!m_weatherData[source].humidity.isEmpty()) { + humidityInfo.insert("humidity", m_weatherData[source].humidity); + humidityInfo.insert("humidityUnit", QString::number(KUnitConversion::Percent)); + } else { + humidityInfo.insert("humidity", i18n("N/A")); + humidityInfo.insert("humidityUnit", QString::number(KUnitConversion::NoUnit)); + } + return humidityInfo; +} + +QMap EnvCanadaIon::visibility(const QString& source) const +{ + QMap visibilityInfo; + + if (m_weatherData[source].visibility != 0) { + visibilityInfo.insert("visibility", QString::number(m_weatherData[source].visibility, 'f', 1)); + visibilityInfo.insert("visibilityUnit", QString::number(KUnitConversion::Kilometer)); + } else { + visibilityInfo.insert("visibility", i18n("N/A")); + visibilityInfo.insert("visibilityUnit", QString::number(KUnitConversion::NoUnit)); + } + return visibilityInfo; +} + +QMap EnvCanadaIon::temperature(const QString& source) const +{ + QMap temperatureInfo; + if (!m_weatherData[source].temperature.isEmpty()) { + temperatureInfo.insert("temperature", QString::number(m_weatherData[source].temperature.toFloat(), 'f', 1)); + } + + if (m_weatherData[source].temperature == i18n("N/A")) { + temperatureInfo.insert("temperature", i18n("N/A")); + } + + temperatureInfo.insert("comfortTemperature", i18n("N/A")); + + if (m_weatherData[source].comforttemp != i18n("N/A")) { + temperatureInfo.insert("comfortTemperature", m_weatherData[source].comforttemp); + } + + // This is used for not just current temperature but also 8 days. Cannot be NoUnit. + temperatureInfo.insert("temperatureUnit", QString::number(KUnitConversion::Celsius)); + return temperatureInfo; +} + +QMap EnvCanadaIon::watches(const QString& source) const +{ + QMap watchData; + QString watchType; + for (int i = 0; i < m_weatherData[source].watches.size(); ++i) { + watchType = QString("watch %1").arg(i); + watchData[watchType] = QString("%1|%2|%3|%4").arg(m_weatherData[source].watches[i]->priority) \ + .arg(m_weatherData[source].watches[i]->description) \ + .arg(m_weatherData[source].watches[i]->url) \ + .arg(m_weatherData[source].watches[i]->timestamp); + } + return watchData; +} + +QMap EnvCanadaIon::warnings(const QString& source) const +{ + QMap warningData; + QString warnType; + for (int i = 0; i < m_weatherData[source].warnings.size(); ++i) { + warnType = QString("warning %1").arg(i); + warningData[warnType] = QString("%1|%2|%3|%4").arg(m_weatherData[source].warnings[i]->priority) \ + .arg(m_weatherData[source].warnings[i]->description) \ + .arg(m_weatherData[source].warnings[i]->url) \ + .arg(m_weatherData[source].warnings[i]->timestamp); + } + return warningData; +} + +QVector EnvCanadaIon::forecasts(const QString& source) +{ + QVector forecastData; + + // Do some checks for empty data + for (int i = 0; i < m_weatherData[source].forecasts.size(); ++i) { + if (m_weatherData[source].forecasts[i]->forecastPeriod.isEmpty()) { + m_weatherData[source].forecasts[i]->forecastPeriod = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->shortForecast.isEmpty()) { + m_weatherData[source].forecasts[i]->shortForecast = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->iconName.isEmpty()) { + m_weatherData[source].forecasts[i]->iconName = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->forecastSummary.isEmpty()) { + m_weatherData[source].forecasts[i]->forecastSummary = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->forecastTempHigh.isEmpty()) { + m_weatherData[source].forecasts[i]->forecastTempHigh = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->forecastTempLow.isEmpty()) { + m_weatherData[source].forecasts[i]->forecastTempLow = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->popPrecent.isEmpty()) { + m_weatherData[source].forecasts[i]->popPrecent = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->windForecast.isEmpty()) { + m_weatherData[source].forecasts[i]->windForecast = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->precipForecast.isEmpty()) { + m_weatherData[source].forecasts[i]->precipForecast = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->precipType.isEmpty()) { + m_weatherData[source].forecasts[i]->precipType = i18n("N/A"); + } + if (m_weatherData[source].forecasts[i]->precipTotalExpected.isEmpty()) { + m_weatherData[source].forecasts[i]->precipTotalExpected = i18n("N/A"); + } + } + + for (int i = 0; i < m_weatherData[source].forecasts.size(); ++i) { + // We need to shortform the day/night strings. + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Today")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Today", i18n("day")); + } + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Tonight")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Tonight", i18nc("Short for tonight", "nite")); + } + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("night")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("night", i18nc("Short for night, appended to the end of the weekday", "nt")); + } + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Saturday")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Saturday", i18nc("Short for Saturday", "Sat")); + } + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Sunday")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Sunday", i18nc("Short for Sunday", "Sun")); + } + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Monday")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Monday", i18nc("Short for Monday", "Mon")); + } + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Tuesday")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Tuesday", i18nc("Short for Tuesday", "Tue")); + } + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Wednesday")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Wednesday", i18nc("Short for Wednesday", "Wed")); + } + + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Thursday")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Thursday", i18nc("Short for Thursday", "Thu")); + } + if (m_weatherData[source].forecasts[i]->forecastPeriod.contains("Friday")) { + m_weatherData[source].forecasts[i]->forecastPeriod.replace("Friday", i18nc("Short for Friday", "Fri")); + } + + forecastData.append(QString("%1|%2|%3|%4|%5|%6") \ + .arg(m_weatherData[source].forecasts[i]->forecastPeriod) \ + .arg(m_weatherData[source].forecasts[i]->iconName) \ + .arg(i18nc("weather forecast", m_weatherData[source].forecasts[i]->shortForecast.toUtf8())) \ + .arg(m_weatherData[source].forecasts[i]->forecastTempHigh) \ + .arg(m_weatherData[source].forecasts[i]->forecastTempLow) \ + .arg(m_weatherData[source].forecasts[i]->popPrecent)); + //kDebug() << "i18n summary string: " << qPrintable(i18n(m_weatherData[source].forecasts[i]->shortForecast.toUtf8())); + } + return forecastData; +} + +QMap EnvCanadaIon::pressure(const QString& source) const +{ + QMap pressureInfo; + + if (m_weatherData[source].pressure == 0) { + pressureInfo.insert("pressure", i18n("N/A")); + pressureInfo.insert("pressureUnit", QString::number(KUnitConversion::NoUnit)); + pressureInfo.insert("pressureTendency", "N/A"); + } else { + pressureInfo.insert("pressure", QString::number(m_weatherData[source].pressure, 'f', 1)); + pressureInfo.insert("pressureUnit", QString::number(KUnitConversion::Kilopascal)); + pressureInfo.insert("pressureTendency", i18nc("pressure tendency", m_weatherData[source].pressureTendency.toUtf8())); + } + return pressureInfo; +} + +QMap EnvCanadaIon::wind(const QString& source) const +{ + QMap windInfo; + + // May not have any winds + if (m_weatherData[source].windSpeed.isEmpty()) { + windInfo.insert("windSpeed", i18n("N/A")); + windInfo.insert("windUnit", QString::number(KUnitConversion::NoUnit)); + } else if (m_weatherData[source].windSpeed.toInt() == 0) { + windInfo.insert("windSpeed", i18nc("wind speed", "Calm")); + windInfo.insert("windUnit", QString::number(KUnitConversion::NoUnit)); + } else { + windInfo.insert("windSpeed", QString::number(m_weatherData[source].windSpeed.toInt())); + windInfo.insert("windUnit", QString::number(KUnitConversion::KilometerPerHour)); + } + + // May not always have gusty winds + if (m_weatherData[source].windGust.isEmpty() || m_weatherData[source].windGust == 0) { + windInfo.insert("windGust", i18n("N/A")); + windInfo.insert("windGustUnit", QString::number(KUnitConversion::NoUnit)); + } else { + windInfo.insert("windGust", QString::number(m_weatherData[source].windGust.toInt())); + windInfo.insert("windGustUnit", QString::number(KUnitConversion::KilometerPerHour)); + } + + if (m_weatherData[source].windDirection.isEmpty() && m_weatherData[source].windSpeed.isEmpty()) { + windInfo.insert("windDirection", i18n("N/A")); + windInfo.insert("windDegrees", i18n("N/A")); + } else if (m_weatherData[source].windSpeed.toInt() == 0) { + windInfo.insert("windDirection", i18nc("wind direction - wind speed is too low to measure", "VR")); // Variable/calm + } else { + windInfo.insert("windDirection", i18nc("wind direction", m_weatherData[source].windDirection.toUtf8())); + windInfo.insert("windDegrees", m_weatherData[source].windDegrees); + } + return windInfo; +} + +QMap EnvCanadaIon::uvIndex(const QString& source) const +{ + QMap uvInfo; + + if (m_weatherData[source].UVRating.isEmpty()) { + uvInfo.insert("uvRating", i18n("N/A")); + } else { + uvInfo.insert("uvRating", m_weatherData[source].UVRating); + } + + if (m_weatherData[source].UVIndex.isEmpty()) { + uvInfo.insert("uvIndex", i18n("N/A")); + } else { + uvInfo.insert("uvIndex", m_weatherData[source].UVIndex); + } + + return uvInfo; +} + +QMap EnvCanadaIon::regionalTemperatures(const QString& source) const +{ + QMap regionalTempInfo; + + if (m_weatherData[source].normalHigh.isEmpty()) { + regionalTempInfo.insert("normalHigh", i18n("N/A")); + } else { + regionalTempInfo.insert("normalHigh", m_weatherData[source].normalHigh); + } + + if (m_weatherData[source].normalLow.isEmpty()) { + regionalTempInfo.insert("normalLow", i18n("N/A")); + } else { + regionalTempInfo.insert("normalLow", m_weatherData[source].normalLow); + } + + return regionalTempInfo; +} + +QMap EnvCanadaIon::yesterdayWeather(const QString& source) const +{ + QMap yesterdayInfo; + + if (m_weatherData[source].prevHigh.isEmpty()) { + yesterdayInfo.insert("prevHigh", i18n("N/A")); + } else { + yesterdayInfo.insert("prevHigh", m_weatherData[source].prevHigh); + } + + if (m_weatherData[source].prevLow.isEmpty()) { + yesterdayInfo.insert("prevLow", i18n("N/A")); + } else { + yesterdayInfo.insert("prevLow", m_weatherData[source].prevLow); + } + + if (m_weatherData[source].prevPrecipTotal == "Trace") { + yesterdayInfo.insert("prevPrecip", i18nc("precipitation total, very little", "Trace")); + return yesterdayInfo; + } + + if (m_weatherData[source].prevPrecipTotal.isEmpty()) { + yesterdayInfo.insert("prevPrecip", i18n("N/A")); + yesterdayInfo.insert("prevPrecipUnit", QString::number(KUnitConversion::NoUnit)); + } else { + yesterdayInfo.insert("prevPrecipTotal", m_weatherData[source].prevPrecipTotal); + if (m_weatherData[source].prevPrecipType == "mm") { + yesterdayInfo.insert("prevPrecipUnit", QString::number(KUnitConversion::Millimeter)); + } else if (m_weatherData[source].prevPrecipType == "cm") { + yesterdayInfo.insert("prevPrecipUnit", QString::number(KUnitConversion::Centimeter)); + } else { + yesterdayInfo.insert("prevPrecipUnit", QString::number(KUnitConversion::NoUnit)); + } + } + + return yesterdayInfo; +} + +QMap EnvCanadaIon::sunriseSet(const QString& source) const +{ + QMap sunInfo; + + if (m_weatherData[source].sunriseTimestamp.isEmpty()) { + sunInfo.insert("sunrise", i18n("N/A")); + } else { + sunInfo.insert("sunrise", m_weatherData[source].sunriseTimestamp); + } + + if (m_weatherData[source].sunsetTimestamp.isEmpty()) { + sunInfo.insert("sunset", i18n("N/A")); + } else { + sunInfo.insert("sunset", m_weatherData[source].sunsetTimestamp); + } + + return sunInfo; +} + +QMap EnvCanadaIon::moonriseSet(const QString& source) const +{ + QMap moonInfo; + + if (m_weatherData[source].moonriseTimestamp.isEmpty()) { + moonInfo.insert("moonrise", i18n("N/A")); + } else { + moonInfo.insert("moonrise", m_weatherData[source].moonriseTimestamp); + } + + if (m_weatherData[source].moonsetTimestamp.isEmpty()) { + moonInfo.insert("moonset", i18n("N/A")); + } else { + moonInfo.insert("moonset", m_weatherData[source].moonsetTimestamp); + } + + return moonInfo; +} + +QMap EnvCanadaIon::weatherRecords(const QString& source) const +{ + QMap recordInfo; + + if (m_weatherData[source].recordHigh == 0) { + recordInfo.insert("recordHigh", i18n("N/A")); + } else { + recordInfo.insert("recordHigh", QString("%1").arg(m_weatherData[source].recordHigh)); + } + + if (m_weatherData[source].recordLow == 0) { + recordInfo.insert("recordLow", i18n("N/A")); + } else { + recordInfo.insert("recordLow", QString("%1").arg(m_weatherData[source].recordLow)); + } + + if (m_weatherData[source].recordRain == 0) { + recordInfo.insert("recordRain", i18n("N/A")); + recordInfo.insert("recordRainUnit", QString::number(KUnitConversion::NoUnit)); + } else { + recordInfo.insert("recordRain", QString("%1").arg(m_weatherData[source].recordRain)); + recordInfo.insert("recordRainUnit", QString::number(KUnitConversion::Millimeter)); + } + + if (m_weatherData[source].recordSnow == 0) { + recordInfo.insert("recordSnow", i18n("N/A")); + recordInfo.insert("recordSnowUnit", QString::number(KUnitConversion::NoUnit)); + } else { + recordInfo.insert("recordSnow", QString("%1").arg(m_weatherData[source].recordSnow)); + recordInfo.insert("recordSnowUnit", QString::number(KUnitConversion::Centimeter)); + } + + return recordInfo; +} + +#include "ion_envcan.moc" diff --git a/plasma/generic/dataengines/weather/ions/envcan/ion_envcan.h b/plasma/generic/dataengines/weather/ions/envcan/ion_envcan.h new file mode 100644 index 00000000..3e17d60c --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/envcan/ion_envcan.h @@ -0,0 +1,261 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 * + ***************************************************************************/ + +/* Ion for Environment Canada XML data */ + +#ifndef ION_ENVCAN_H +#define ION_ENVCAN_H + +#include +#include + +#include +#include + +#include "../ion.h" +#include "../dataengineconsumer.h" + +class KJob; +namespace KIO +{ + class Job; +} // namespace KIO + +class WeatherData +{ + +public: + // WeatherEvent can have more than one, especially in Canada, eh? :) + struct WeatherEvent { + QString url; + QString type; + QString priority; + QString description; + QString timestamp; + }; + + // Five day forecast + struct ForecastInfo { + QString forecastPeriod; + QString forecastSummary; + QString iconName; + QString shortForecast; + + QString forecastTempHigh; + QString forecastTempLow; + QString popPrecent; + QString windForecast; + + QString precipForecast; + QString precipType; + QString precipTotalExpected; + int forecastHumidity; + }; + + QString countryName; + QString longTerritoryName; + QString shortTerritoryName; + QString cityName; + QString regionName; + QString stationID; + QString stationLat; + QString stationLon; + + // Current observation information. + QString obsTimestamp; + + // Icon info to aproximate periods + int iconPeriodHour; + int iconPeriodMinute; + + QString condition; + QString temperature; + QString dewpoint; + + // In winter windchill, in summer, humidex + QString comforttemp; + + float pressure; + QString pressureTendency; + + float visibility; + QString humidity; + + QString windSpeed; + QString windGust; + QString windDirection; + QString windDegrees; + + QVector watches; + QVector warnings; + + QString normalHigh; + QString normalLow; + + QString forecastTimestamp; + + QString UVIndex; + QString UVRating; + + // 5 day Forecast + QVector forecasts; + + // Historical data from previous day. + QString prevHigh; + QString prevLow; + QString prevPrecipType; + QString prevPrecipTotal; + + // Almanac info + QString sunriseTimestamp; + QString sunsetTimestamp; + QString moonriseTimestamp; + QString moonsetTimestamp; + + // Historical Records + float recordHigh; + float recordLow; + float recordRain; + float recordSnow; +}; + +class KDE_EXPORT EnvCanadaIon : public IonInterface, public Plasma::DataEngineConsumer +{ + Q_OBJECT + +public: + EnvCanadaIon(QObject *parent, const QVariantList &args); + ~EnvCanadaIon(); + bool updateIonSource(const QString& source); // Sync data source with Applet + void updateWeather(const QString& source); + +public Q_SLOTS: + virtual void reset(); + +protected: + void init(); // Setup the city location, fetching the correct URL name. + +protected Q_SLOTS: + void setup_slotDataArrived(KIO::Job *, const QByteArray &); + void setup_slotJobFinished(KJob *); + + void slotDataArrived(KIO::Job *, const QByteArray &); + void slotJobFinished(KJob *); + +private: + /* Environment Canada Methods - Internal for Ion */ + void deleteForecasts(); + + QMap setupConditionIconMappings(void) const; + QMap setupForecastIconMappings(void) const; + + QMap const& conditionIcons(void) const; + QMap const& forecastIcons(void) const; + + // Place information + QString const country(const QString& source) const; + QString territory(const QString& source) const; + QString city(const QString& source) const; + QString region(const QString& source) const; + QString station(const QString& source) const; + QString latitude(const QString& source) const; + QString longitude(const QString& source) const; + + // Current Conditions Weather info + QString observationTime(const QString& source) const; + int periodHour(const QString& source) const; + int periodMinute(const QString& source) const; + QMap watches(const QString& source) const; + QMap warnings(const QString& source) const; + QString condition(const QString& source); + QMap temperature(const QString& source) const; + QString dewpoint(const QString& source) const; + QMap humidity(const QString& source) const; + QMap visibility(const QString& source) const; + QMap pressure(const QString& source) const; + QMap wind(const QString& source) const; + QMap regionalTemperatures(const QString& source) const; + QMap uvIndex(const QString& source) const; + QVector forecasts(const QString& source); + QMap yesterdayWeather(const QString& source) const; + QMap sunriseSet(const QString& source) const; + QMap moonriseSet(const QString& source) const; + QMap weatherRecords(const QString& source) const; + + // Load and Parse the place XML listing + void getXMLSetup(void); + bool readXMLSetup(void); + + // Load and parse the specific place(s) + void getXMLData(const QString& source); + bool readXMLData(const QString& source, QXmlStreamReader& xml); + + // Check if place specified is valid or not + QStringList validate(const QString& source) const; + + // Catchall for unknown XML tags + void parseUnknownElement(QXmlStreamReader& xml) const; + + // Parse weather XML data + void parseWeatherSite(WeatherData& data, QXmlStreamReader& xml); + void parseDateTime(WeatherData& data, QXmlStreamReader& xml, WeatherData::WeatherEvent* event = NULL); + void parseLocations(WeatherData& data, QXmlStreamReader& xml); + void parseConditions(WeatherData& data, QXmlStreamReader& xml); + void parseWarnings(WeatherData& data, QXmlStreamReader& xml); + void parseWindInfo(WeatherData& data, QXmlStreamReader& xml); + void parseWeatherForecast(WeatherData& data, QXmlStreamReader& xml); + void parseRegionalNormals(WeatherData& data, QXmlStreamReader& xml); + void parseForecast(WeatherData& data, QXmlStreamReader& xml, WeatherData::ForecastInfo* forecast); + void parseShortForecast(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml); + void parseForecastTemperatures(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml); + void parseWindForecast(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml); + void parsePrecipitationForecast(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml); + void parsePrecipTotals(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml); + void parseUVIndex(WeatherData& data, QXmlStreamReader& xml); + void parseYesterdayWeather(WeatherData& data, QXmlStreamReader& xml); + void parseAstronomicals(WeatherData& data, QXmlStreamReader& xml); + void parseWeatherRecords(WeatherData& data, QXmlStreamReader& xml); + + struct XMLMapInfo { + QString cityName; + QString territoryName; + QString cityCode; + }; + + // Key dicts + QHash m_places; + + // Weather information + QHash m_weatherData; + + // Store KIO jobs + QHash m_jobXml; + QHash m_jobList; + QStringList m_sourcesToReset; + QXmlStreamReader m_xmlSetup; + Plasma::DataEngine *m_timeEngine; + + QDateTime m_dateFormat; + bool emitWhenSetup; + +}; + +K_EXPORT_PLASMA_DATAENGINE(envcan, EnvCanadaIon) + +#endif diff --git a/plasma/generic/dataengines/weather/ions/includes/Ion b/plasma/generic/dataengines/weather/ions/includes/Ion new file mode 100644 index 00000000..4ebf1cf7 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/includes/Ion @@ -0,0 +1 @@ +#include "../../../plasma/weather/ion.h" diff --git a/plasma/generic/dataengines/weather/ions/ion.cpp b/plasma/generic/dataengines/weather/ions/ion.cpp new file mode 100644 index 00000000..4715bc1d --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/ion.cpp @@ -0,0 +1,210 @@ +/***************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 "ion.h" +#include "ion.moc" + +#include + +class IonInterface::Private +{ +public: + Private(IonInterface *i) + : ion(i), + initialized(false) {} + + IonInterface *ion; + bool initialized; +}; + +IonInterface::IonInterface(QObject *parent, const QVariantList &args) + : Plasma::DataEngine(parent, args), + d(new Private(this)) +{ +} + +IonInterface::~IonInterface() +{ + delete d; +} + +/** + * If the ion is not initialized just set the initial data source up even if it's empty, we'll retry once the initialization is done + */ +bool IonInterface::sourceRequestEvent(const QString &source) +{ + kDebug() << "sourceRequested(): " << source; + + // init anyway the data as it's going to be used + // sooner or later (doesnt depend upon initialization + // this will avoid problems if updateIonSource() fails for any reason + // but later it's able to retrieve the data + setData(source, Plasma::DataEngine::Data()); + + // if initialized, then we can try to grab the data + if (d->initialized) { + return updateIonSource(source); + } + + return true; +} + +/** + * Update the ion's datasource. Triggered when a Plasma::DataEngine::connectSource() timeout occurs. + */ +bool IonInterface::updateSourceEvent(const QString& source) +{ + kDebug() << "updateSource(" << source << ")"; + if (d->initialized) { + kDebug() << "Calling updateIonSource(" << source << ")"; + return updateIonSource(source); + } + + return false; +} + +/** + * Set the ion to make sure it is ready to get real data. + */ +void IonInterface::setInitialized(bool initialized) +{ + d->initialized = initialized; + + if (d->initialized) { + updateAllSources(); + } +} + +/** + * Return wind direction svg element to display in applet when given a wind direction. + */ +QString IonInterface::getWindDirectionIcon(const QMap &windDirList, const QString& windDirection) const +{ + switch (windDirList[windDirection.toLower()]) { + case N: + return i18n("N"); + case NNE: + return i18n("NNE"); + case NE: + return i18n("NE"); + case ENE: + return i18n("ENE"); + case E: + return i18n("E"); + case SSE: + return i18n("SSE"); + case SE: + return i18n("SE"); + case ESE: + return i18n("ESE"); + case S: + return i18n("S"); + case NNW: + return i18n("NNW"); + case NW: + return i18n("NW"); + case WNW: + return i18n("WNW"); + case W: + return i18n("W"); + case SSW: + return i18n("SSW"); + case SW: + return i18n("SW"); + case WSW: + return i18n("WSW"); + case VR: + return i18n("N/A"); // For now, we'll make a variable wind icon later on + } + + // No icon available, use 'X' + return i18n("N/A"); +} + +/** + * Return weather icon to display in an applet when given a condition. + */ +QString IonInterface::getWeatherIcon(ConditionIcons condition) const +{ + switch (condition) { + case ClearDay: + return "weather-clear"; + case FewCloudsDay: + return "weather-few-clouds"; + case PartlyCloudyDay: + return "weather-clouds"; + case Overcast: + return "weather-many-clouds"; + case Rain: + return "weather-showers"; + case LightRain: + return "weather-showers-scattered"; + case Showers: + return "weather-showers-scattered"; + case ChanceShowersDay: + return "weather-showers-scattered-day"; + case ChanceShowersNight: + return "weather-showers-scattered-night"; + case ChanceSnowDay: + return "weather-snow-scattered-day"; + case ChanceSnowNight: + return "weather-snow-scattered-night"; + case Thunderstorm: + return "weather-storm"; + case Hail: + return "weather-hail"; + case Snow: + return "weather-snow"; + case LightSnow: + return "weather-snow-scattered"; + case Flurries: + return "weather-snow-scattered"; + case RainSnow: + return "weather-snow-rain"; + case FewCloudsNight: + return "weather-few-clouds-night"; + case PartlyCloudyNight: + return "weather-clouds-night"; + case ClearNight: + return "weather-clear-night"; + case Mist: + return "weather-mist"; + case Haze: + return "weather-mist"; + case FreezingRain: + return "weather-freezing-rain"; + case FreezingDrizzle: + return "weather-freezing-rain"; + case ChanceThunderstormDay: + return "weather-storm-day"; + case ChanceThunderstormNight: + return "weather-storm-night"; + case NotAvailable: + return "weather-none-available"; + } + return "weather-none-available"; +} + +/** + * Return weather icon to display in an applet when given a condition. + */ +QString IonInterface::getWeatherIcon(const QMap &conditionList, const QString& condition) const +{ + return getWeatherIcon(conditionList[condition.toLower()]); +} diff --git a/plasma/generic/dataengines/weather/ions/ion.h b/plasma/generic/dataengines/weather/ions/ion.h new file mode 100644 index 00000000..d7316235 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/ion.h @@ -0,0 +1,132 @@ +/***************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 ION_H +#define ION_H + +#include +#include + +#include "ion_export.h" + +/** +* @author Shawn Starr +* This is the base class to be used to implement new ions for the WeatherEngine. +* The idea is that you can have multiple ions which provide weather information from different services to the engine from which an applet will request the data from. +* +* Basically an ion is a Plasma::DataEngine, which is queried by the WeatherEngine instead of some applet. +*/ +class ION_EXPORT IonInterface : public Plasma::DataEngine +{ + Q_OBJECT + +public: + + enum ConditionIcons { ClearDay = 1, FewCloudsDay, PartlyCloudyDay, Overcast, + Rain, LightRain, Showers, ChanceShowersDay, Thunderstorm, Hail, + Snow, LightSnow, Flurries, FewCloudsNight, ChanceShowersNight, + PartlyCloudyNight, ClearNight, Mist, Haze, FreezingRain, + RainSnow, FreezingDrizzle, ChanceThunderstormDay, ChanceThunderstormNight, + ChanceSnowDay, ChanceSnowNight, NotAvailable + }; + + enum WindDirections { N, NNE, NE, ENE, E, SSE, SE, ESE, S, NNW, NW, WNW, W, SSW, SW, WSW, VR }; + + /** + * Constructor for the ion + * @param parent The parent object. + * @Param args The argument list. + */ + explicit IonInterface(QObject *parent = 0, const QVariantList &args = QVariantList()); + /** + * Destructor for the ion + */ + virtual ~IonInterface(); + + /** + * Returns weather icon filename to display in applet. + * @param condition the current condition being reported. + * @return icon name + */ + QString getWeatherIcon(ConditionIcons condition) const; + + /** + * Returns weather icon filename to display in applet. + * @param conditionList a QList map pair of icons mapped to a enumeration of conditions. + * @param condition the current condition being reported. + * @return icon name + */ + QString getWeatherIcon(const QMap &conditionList, const QString& condition) const; + + /** + * Returns wind icon element to display in applet. + * @param windDirList a QList map pair of wind directions mapped to a enumeration of directions. + * @param windDirection the current wind direction. + * @return svg element for wind direction + */ + QString getWindDirectionIcon(const QMap &windDirList, const QString& windDirection) const; + +public Q_SLOTS: + + /** + * Reimplemented from Plasma::DataEngine + * @param source the name of the datasource to be updated + */ + bool updateSourceEvent(const QString& source); + + /** + * Reimplement for ion to reload data if network status comes back up + */ + virtual void reset() = 0; + +Q_SIGNALS: + void forceUpdate(IonInterface *ion, const QString &source); + +protected: + + /** + * Call this method to flush waiting source requests that may be pending + * initialization + * + * @arg initialized whether or not the ion is currently ready to fetch data + */ + void setInitialized(bool initialized); + + /** + * Reimplemented from Plasma::DataEngine + * @param source The datasource being requested + */ + bool sourceRequestEvent(const QString &source); + + /** + * Reimplement to fetch the data from the ion. + * @arg source the name of the datasource. + * @return true if update was successful, false if failed + */ + virtual bool updateIonSource(const QString &source) = 0; + + friend class WeatherEngine; + +private: + class Private; + Private* const d; +}; + +#endif + diff --git a/plasma/generic/dataengines/weather/ions/ion_export.h b/plasma/generic/dataengines/weather/ions/ion_export.h new file mode 100644 index 00000000..d7f201af --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/ion_export.h @@ -0,0 +1,40 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + + 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 ION_EXPORT_H +#define ION_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include + +#ifndef ION_EXPORT +# if defined(MAKE_WEATHER_ION_LIB) +/* We are building this library */ +# define ION_EXPORT KDE_EXPORT +# else +/* We are using this library */ +# define ION_EXPORT KDE_IMPORT +# endif +#endif + +# ifndef ION_EXPORT_DEPRECATED +# define ION_EXPORT_DEPRECATED KDE_DEPRECATED ION_EXPORT +# endif + +#endif diff --git a/plasma/generic/dataengines/weather/ions/noaa/CMakeLists.txt b/plasma/generic/dataengines/weather/ions/noaa/CMakeLists.txt new file mode 100644 index 00000000..72dd2cf0 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/noaa/CMakeLists.txt @@ -0,0 +1,8 @@ +SET (ion_noaa_SRCS ion_noaa.cpp) +kde4_add_plugin(ion_noaa ${ion_noaa_SRCS}) +target_link_libraries (ion_noaa ${KDE4_SOLID_LIBS} weather_ion) + +INSTALL (FILES ion-noaa.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + +INSTALL (TARGETS ion_noaa DESTINATION ${PLUGIN_INSTALL_DIR}) + diff --git a/plasma/generic/dataengines/weather/ions/noaa/ion-noaa.desktop b/plasma/generic/dataengines/weather/ions/noaa/ion-noaa.desktop new file mode 100644 index 00000000..d364f2e1 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/noaa/ion-noaa.desktop @@ -0,0 +1,153 @@ +[Desktop Entry] +Name=NOAA's National Weather Service +Name[ar]=خدمة الطقس الوطني الأمريكي من NOAA +Name[ast]=Serviciu nacional norteamericanu NOAA +Name[be@latin]=Nacyjanalnaja słužba nadvorja „NOAA” +Name[bg]=Метеорологична станция NOAA +Name[bs]=NOAA‑ova nacionalna meteorološka služba +Name[ca]=Servei meteorològic nacional de NOAA +Name[ca@valencia]=Servei meteorològic nacional de NOAA +Name[cs]=Informační služba o počasí agentury NOAA +Name[da]=NOAAs nationale vejrtjeneste +Name[de]=NOAA's nationaler Wetterdienst +Name[el]=Υπηρεσία καιρού NOAA +Name[en_GB]=NOAA's National Weather Service +Name[eo]=Nacia veterservo de NOAA +Name[es]=Servicio nacional norteamericano NOAA +Name[et]=NOAA riiklik ilmateenistus +Name[eu]=NOAA Eguraldi Zerbitzu Nazionala +Name[fi]=NOAA:n kansallinen sääpalvelu +Name[fr]=Service météo national du NOAA +Name[fy]=NOAA's nasjonale waar tsjinst +Name[ga]=Seirbhís Náisiúnta na hAimsire de chuid NOAA +Name[gl]=Servizo meteorolóxico nacional da NOAA +Name[gu]=NOAA ની નેશનલ વેધર સર્વિસ +Name[he]=NOAA's National Weather Service +Name[hi]=एनओएए के राष्ट्रीय मौसम सेवा +Name[hne]=एनओएए के रास्ट्रीय मौसम सेवा +Name[hr]=NOAA-ova usluga nacionalne vremenske proznoze +Name[hu]=NOAA időjárásjelző szolgálat +Name[ia]=Servicio Meteorologic National NOAA +Name[id]=NOAA's National Weather Service +Name[is]=NOAA veðurþjónustan +Name[it]=Servizio meteorologico nazionale del NOAA +Name[ja]=NOAA (アメリカ海洋大気圏局) National Weather Service +Name[kk]=NOAA Ұлттық ауа райы қызметі +Name[km]=សេវា​អាកាសធាតុ​ជាតិ​របស់ NOAA +Name[kn]=NOAA ದ ರಾಷ್ಟ್ರೀಯ ಹವಾಮಾನ ಸೇವೆ +Name[ko]=NOAA 미국 기상 서비스 +Name[lt]=NOAA's National Weather Service +Name[lv]=NOAA's Nacionālais Laikapstākļu Serviss +Name[mk]=Национален сервис за време на NOAA +Name[ml]=നോആ-യുടെ ദേശീയ കാലവസ്ഥാ സേവനം +Name[mr]=NOAA ची राष्ट्रीय हवामान सेवा +Name[nb]=NOAAs nasjonale værtjeneste +Name[nds]=Wederdeenst vun't US-Ozeaankunn- un Wederamt +Name[ne]=NOAA को राष्ट्रिय मौसम सेवा +Name[nl]=NOAA's nationale weerdienst +Name[nn]=NOAAs amerikanske vêrteneste +Name[pa]=NOAA ਦੀ ਕੌਮੀ ਮੌਸਮ ਸਰਵਿਸ +Name[pl]=Narodowa Usługa Pogodowa NOAA +Name[pt]=Serviço Meteorológico Nacional da NOAA +Name[pt_BR]=Serviço Meteorológico Nacional da NOAA +Name[ro]=NOAA's National Weather Service +Name[ru]=Национальная служба погоды США +Name[se]=NOAA amerihkálaš dálkebálvalus +Name[si]=NOAA's ජාතික කාලගුණ සේවාව +Name[sk]=Počasie - NOAA National Weather Service +Name[sl]=NOAA's National Weather Service +Name[sr]=НОАА‑ова национална метеоролошка служба +Name[sr@ijekavian]=НОАА‑ова национална метеоролошка служба +Name[sr@ijekavianlatin]=NOAA‑ova nacionalna meteorološka služba +Name[sr@latin]=NOAA‑ova nacionalna meteorološka služba +Name[sv]=NOAA:s nationella vädertjänst +Name[ta]=NOAA's National Weather Service +Name[te]=NOAA యొక్క జాతీయ వాతావరణ సేవ +Name[tg]=Национальная служба погоды NOAA +Name[th]=บริการพยากรณ์อากาศสากล NOAA +Name[tr]=NOAA Ulusal Hava Durumu Servisi +Name[ug]=NOAA تەمىنلىگەن دۆلەت ھاۋارايى مۇلازىمىتى +Name[uk]=Національна служба погоди NOAA +Name[wa]=NOAA's National Weather Service +Name[x-test]=xxNOAA's National Weather Servicexx +Name[zh_CN]=NOAA 提供的国家天气服务 +Name[zh_TW]=NOAA 的國家天氣服務 +Comment=XML Data from NOAA's National Weather Service +Comment[ar]=معلومات XML من خدمة الطقس الوطني الأمريكي من NOAA +Comment[ast]=Datos XML del serviciu nacional meteorolóxicu norteamericanu NOAA +Comment[be@latin]=Źviestki ŭ farmacie „XML” ad Nacyjanalnaj słužby nadvorja „NOAA” +Comment[bg]=XML данни от метеорологична станция NOAA +Comment[bs]=IksML podaci NOAA‑ove nacionalne meteorološke službe +Comment[ca]=Dades XML del servei meteorològic nacional de NOAA +Comment[ca@valencia]=Dades XML del servei meteorològic nacional de NOAA +Comment[cs]=XML data služby o počasí agentury NOAA +Comment[da]=XML-data fra NOAAs nationale vejrtjeneste +Comment[de]=XML-Daten von NOAA's nationalem Wetterdienst +Comment[el]=Δεδομένα XML από την υπηρεσία καιρού NOAA +Comment[en_GB]=XML Data from NOAA's National Weather Service +Comment[eo]=XML-datumoj el la NOAA nacia vetera servo +Comment[es]=Datos XML del servicio nacional meteorológico norteamericano NOAA +Comment[et]=NOAA riikliku ilmateenistuse XML-andmed +Comment[eu]=XML datuak NOAA Eguraldi Zerbitzu Nazionaletik +Comment[fi]=XML-tietoa NOAA:n kansallisesti sääpalvelusta +Comment[fr]=Données XML du service météo national du NOAA +Comment[fy]=XML Data fan NOAA's nasjonale waar tsjinst +Comment[ga]=Sonraí XML ó Sheirbhís Náisiúnta na hAimsire de chuid NOAA +Comment[gl]=Datos XML do Servizo meteorolóxico nacional da NOAA +Comment[gu]=NOAA ની નેશનલ વેધર સર્વિસ તરફથી XML માહિતી +Comment[he]=מידע ב־XML מ־NOAA's National Weather Service +Comment[hi]=एनओएए के राष्ट्रीय मौसम सेवा से एक्सएमएल डाटा +Comment[hne]=एनओएए के रास्ट्रीय मौसम सेवा से एक्सएमएल डाटा +Comment[hr]=XML podaci iz NOAA-ove usluge nacionalne vremenske prognoze +Comment[hu]=XML adatok a NOAA időjárásjelző szolgálattól +Comment[ia]=Datos XML ex Servicio National Meteorologic NOAA +Comment[id]=Data XML dari NOAA's National Weather Service +Comment[is]=XML gögn frá NOAA veðurþjónustunni +Comment[it]=Dati XML dal servizio meteorologico nazionale del NOAA +Comment[ja]=NOAA (アメリカ海洋大気圏局) National Weather Service の XML データ +Comment[kk]=NOAA Ұлттық ауа райы қызметінің XML дерегі +Comment[km]=ទិន្នន័យ XML ពី​សេវា​អាកាសធាតុ​ជាតិ​របស់ NOAA +Comment[kn]=NOAA ದ ರಾಷ್ಟ್ರೀಯ ಹವಾಮಾನ ಸೇವೆಯಿಂದ XML ದತ್ತ +Comment[ko]=NOAA 미국 기상 서비스의 XML 데이터 +Comment[lt]=XML duomenys iš NOAA's National Weather Service +Comment[lv]=XML dati no NOAA Nacionālā Laikapstākļu Servisa (ASV) +Comment[mk]=XML-податоци од Националниот сервис за време на NOAA +Comment[ml]=നോആ-യുടെ ദേശീയി കാലവസ്ഥാ സേവനത്തില്‍ നിന്നുമുള്ള എക്സ്എംഎല്‍ ഡേറ്റാ +Comment[mr]=NOAA च्या राष्ट्रीय हवामान सेवा पासून XML माहिती +Comment[nb]=XML-data fra NOAAs nasjonale værtjeneste +Comment[nds]=XML-Daten vun't US-Ozeaankunn- un Wederamt +Comment[ne]=NOAA को राष्ट्रिय मौसम सेवाबाट एक्षएमएल डेटा +Comment[nl]=XML-gegevens van NOAA's nationale weerdienst +Comment[nn]=XML-data frå NOAAs amerikanske vêrteneste +Comment[pa]=NOAA ਦੀ ਕੌਮੀ ਮੌਸਮ ਸਰਵਿਸ ਤੋਂ XML ਡਾਟਾ +Comment[pl]=Dane XML z Narodowej Usługi Pogodowej NOAA +Comment[pt]=Dados em XML do Serviço Meteorológico Nacional da NOAA +Comment[pt_BR]=Dados em XML do Serviço Meteorológico Nacional da NOAA +Comment[ro]=Date XML de la „NOAA's National Weather Service” +Comment[ru]=Данные в формате XML от NOAA +Comment[se]=XML-dáhtat NOAA amerihkálaš dálkebálvalusas +Comment[si]=NOAA හී ජාතික කාලගුණ සේවාව වෙතින් XML දත්ත +Comment[sk]=XML dáta z NOAA National Weather Service +Comment[sl]=Podatki XML od NOAA's National Weather Service +Comment[sr]=ИксМЛ подаци НОАА‑ове националне метеоролошке службе +Comment[sr@ijekavian]=ИксМЛ подаци НОАА‑ове националне метеоролошке службе +Comment[sr@ijekavianlatin]=XML podaci NOAA‑ove nacionalne meteorološke službe +Comment[sr@latin]=XML podaci NOAA‑ove nacionalne meteorološke službe +Comment[sv]=XML-data från NOAA:s nationella vädertjänst +Comment[ta]=XML Data from NOAA's National Weather Service +Comment[te]=NOAA యొక్క జాతీయ వాతావరణ సేవనుండి XML డాటా +Comment[tg]=Маълумоти XML аз NOAA's National Weather Service +Comment[th]=ข้อมูล XML จากบริการพยากรณ์อากาศสากล NOAA +Comment[tr]=NOAA Ulusal Hava Durumu Servisi'nden XML Verisi +Comment[ug]=NOAA دۆلەت ھاۋارايى مۇلازىمىتى تەمىنلىگەن XML سانلىق-مەلۇماتى +Comment[uk]=Дані XML з національної служби погоди NOAA +Comment[wa]=Dinêyes XML då NOAA's National Weather Service +Comment[x-test]=xxXML Data from NOAA's National Weather Servicexx +Comment[zh_CN]=NOAA 国家天气服务提供的 XML 数据 +Comment[zh_TW]=從 NOAA 的國家天氣服務來的 XML 資料 +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-ParentApp=weatherengine +Type=Service +Icon=noneyet +X-KDE-Library=ion_noaa +X-KDE-PluginInfo-Name=noaa diff --git a/plasma/generic/dataengines/weather/ions/noaa/ion_noaa.cpp b/plasma/generic/dataengines/weather/ions/noaa/ion_noaa.cpp new file mode 100644 index 00000000..c5b899cb --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/noaa/ion_noaa.cpp @@ -0,0 +1,967 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 * + ***************************************************************************/ + +/* Ion for NOAA's National Weather Service XML data */ + +#include "ion_noaa.h" + +#include +#include + +#include + +QMap NOAAIon::setupWindIconMappings(void) const +{ + QMap windDir; + windDir["north"] = N; + windDir["northeast"] = NE; + windDir["south"] = S; + windDir["southwest"] = SW; + windDir["east"] = E; + windDir["southeast"] = SE; + windDir["west"] = W; + windDir["northwest"] = NW; + windDir["calm"] = VR; + return windDir; +} + +QMap NOAAIon::setupConditionIconMappings(void) const +{ + + QMap conditionList; + return conditionList; +} + +QMap const& NOAAIon::conditionIcons(void) const +{ + static QMap const condval = setupConditionIconMappings(); + return condval; +} + +QMap const& NOAAIon::windIcons(void) const +{ + static QMap const wval = setupWindIconMappings(); + return wval; +} + +// ctor, dtor +NOAAIon::NOAAIon(QObject *parent, const QVariantList &args) + : IonInterface(parent, args) +{ + Q_UNUSED(args) +} + +void NOAAIon::reset() +{ + m_sourcesToReset = sources(); + getXMLSetup(); +} + +NOAAIon::~NOAAIon() +{ +} + +// Get the master list of locations to be parsed +void NOAAIon::init() +{ + // Get the real city XML URL so we can parse this + getXMLSetup(); + + m_timeEngine = dataEngine("time"); +} + +QStringList NOAAIon::validate(const QString& source) const +{ + QStringList placeList; + QString station; + QString sourceNormalized = source.toUpper(); + + QHash::const_iterator it = m_places.constBegin(); + // If the source name might look like a station ID, check these too and return the name + bool checkState = source.count() == 2; + + while (it != m_places.constEnd()) { + if (checkState) { + if (it.value().stateName == source) { + placeList.append(QString("place|").append(it.key())); + } + } else if (it.key().toUpper().contains(sourceNormalized)) { + placeList.append(QString("place|").append(it.key())); + } else if (it.value().stationID == sourceNormalized) { + station = QString("place|").append(it.key()); + } + + ++it; + } + + placeList.sort(); + if (!station.isEmpty()) { + placeList.prepend(station); + } + + return placeList; +} + +bool NOAAIon::updateIonSource(const QString& source) +{ + // We expect the applet to send the source in the following tokenization: + // ionname:validate:place_name - Triggers validation of place + // ionname:weather:place_name - Triggers receiving weather of place + + QStringList sourceAction = source.split('|'); + + // Guard: if the size of array is not 2 then we have bad data, return an error + if (sourceAction.size() < 2) { + setData(source, "validate", "noaa|malformed"); + return true; + } + + if (sourceAction[1] == "validate" && sourceAction.size() > 2) { + QStringList result = validate(sourceAction[2]); + + if (result.size() == 1) { + setData(source, "validate", QString("noaa|valid|single|").append(result.join("|"))); + return true; + } else if (result.size() > 1) { + setData(source, "validate", QString("noaa|valid|multiple|").append(result.join("|"))); + return true; + } else if (result.size() == 0) { + setData(source, "validate", QString("noaa|invalid|single|").append(sourceAction[2])); + return true; + } + } else if (sourceAction[1] == "weather" && sourceAction.size() > 2) { + getXMLData(source); + return true; + } else { + setData(source, "validate", "noaa|malformed"); + return true; + } + + return false; +} + +// Parses city list and gets the correct city based on ID number +void NOAAIon::getXMLSetup() const +{ + KIO::TransferJob *job = KIO::get(KUrl("http://www.weather.gov/data/current_obs/index.xml"), KIO::NoReload, KIO::HideProgressInfo); + + if (job) { + connect(job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(setup_slotDataArrived(KIO::Job*,QByteArray))); + connect(job, SIGNAL(result(KJob*)), this, SLOT(setup_slotJobFinished(KJob*))); + } else { + kDebug() << "Could not create place name list transfer job"; + } +} + +// Gets specific city XML data +void NOAAIon::getXMLData(const QString& source) +{ + foreach (const QString &fetching, m_jobList) { + if (fetching == source) { + // already getting this source and awaiting the data + return; + } + } + + QString dataKey = source; + dataKey.remove("noaa|weather|"); + KUrl url = m_places[dataKey].XMLurl; + + // If this is empty we have no valid data, send out an error and abort. + if (url.url().isEmpty()) { + setData(source, "validate", QString("noaa|malformed")); + return; + } + + KIO::TransferJob * const m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); + m_jobXml.insert(m_job, new QXmlStreamReader); + m_jobList.insert(m_job, source); + + if (m_job) { + connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(slotDataArrived(KIO::Job*,QByteArray))); + connect(m_job, SIGNAL(result(KJob*)), this, SLOT(slotJobFinished(KJob*))); + } +} + +void NOAAIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + Q_UNUSED(job) + + if (data.isEmpty()) { + return; + } + + // Send to xml. + m_xmlSetup.addData(data); +} + +void NOAAIon::slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + if (data.isEmpty() || !m_jobXml.contains(job)) { + return; + } + + // Send to xml. + m_jobXml[job]->addData(data); +} + +void NOAAIon::slotJobFinished(KJob *job) +{ + // Dual use method, if we're fetching location data to parse we need to do this first + const QString source(m_jobList.value(job)); + removeAllData(source); + QXmlStreamReader *reader = m_jobXml.value(job); + if (reader) { + readXMLData(m_jobList[job], *reader); + } + + // Now that we have the longitude and latitude, fetch the seven day forecast. + getForecast(m_jobList[job]); + + m_jobList.remove(job); + m_jobXml.remove(job); + delete reader; +} + +void NOAAIon::setup_slotJobFinished(KJob *job) +{ + Q_UNUSED(job) + const bool success = readXMLSetup(); + setInitialized(success); + + foreach (const QString &source, m_sourcesToReset) { + updateSourceEvent(source); + } +} + +void NOAAIon::parseStationID() +{ + QString state; + QString stationName; + QString stationID; + QString xmlurl; + + while (!m_xmlSetup.atEnd()) { + m_xmlSetup.readNext(); + + if (m_xmlSetup.isEndElement() && m_xmlSetup.name() == "station") { + if (!xmlurl.isEmpty()) { + NOAAIon::XMLMapInfo info; + info.stateName = state; + info.stationName = stationName; + info.stationID = stationID; + info.XMLurl = xmlurl; + + QString tmp = stationName + ", " + state; // Build the key name. + m_places[tmp] = info; + } + break; + } + + if (m_xmlSetup.isStartElement()) { + if (m_xmlSetup.name() == "station_id") { + stationID = m_xmlSetup.readElementText(); + } else if (m_xmlSetup.name() == "state") { + state = m_xmlSetup.readElementText(); + } else if (m_xmlSetup.name() == "station_name") { + stationName = m_xmlSetup.readElementText(); + } else if (m_xmlSetup.name() == "xml_url") { + xmlurl = m_xmlSetup.readElementText().replace("http://", "http://www."); + } else { + parseUnknownElement(m_xmlSetup); + } + } + } +} + +void NOAAIon::parseStationList() +{ + while (!m_xmlSetup.atEnd()) { + m_xmlSetup.readNext(); + + if (m_xmlSetup.isEndElement()) { + break; + } + + if (m_xmlSetup.isStartElement()) { + if (m_xmlSetup.name() == "station") { + parseStationID(); + } else { + parseUnknownElement(m_xmlSetup); + } + } + } +} + +// Parse the city list and store into a QMap +bool NOAAIon::readXMLSetup() +{ + bool success = false; + while (!m_xmlSetup.atEnd()) { + m_xmlSetup.readNext(); + + if (m_xmlSetup.isStartElement()) { + if (m_xmlSetup.name() == "wx_station_index") { + parseStationList(); + success = true; + } + } + } + return (!m_xmlSetup.error() && success); +} + +void NOAAIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml) +{ + data.temperature_C = i18n("N/A"); + data.temperature_F = i18n("N/A"); + data.dewpoint_C = i18n("N/A"); + data.dewpoint_F = i18n("N/A"); + data.weather = i18n("N/A"); + data.stationID = i18n("N/A"); + data.pressure = i18n("N/A"); + data.visibility = i18n("N/A"); + data.humidity = i18n("N/A"); + data.windSpeed = i18n("N/A"); + data.windGust = i18n("N/A"); + data.windchill_F = i18n("N/A"); + data.windchill_C = i18n("N/A"); + data.heatindex_F = i18n("N/A"); + data.heatindex_C = i18n("N/A"); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + if (xml.name() == "location") { + data.locationName = xml.readElementText(); + } else if (xml.name() == "station_id") { + data.stationID = xml.readElementText(); + } else if (xml.name() == "latitude") { + data.stationLat = xml.readElementText(); + } else if (xml.name() == "longitude") { + data.stationLon = xml.readElementText(); + } else if (xml.name() == "observation_time") { + data.observationTime = xml.readElementText(); + QStringList tmpDateStr = data.observationTime.split(' '); + data.observationTime = QString("%1 %2").arg(tmpDateStr[6]).arg(tmpDateStr[7]); + m_dateFormat = QDateTime::fromString(data.observationTime, "h:mm ap"); + data.iconPeriodHour = m_dateFormat.toString("HH"); + data.iconPeriodAP = m_dateFormat.toString("ap"); + + } else if (xml.name() == "weather") { + data.weather = xml.readElementText(); + // Pick which icon set depending on period of day + } else if (xml.name() == "temp_f") { + data.temperature_F = xml.readElementText(); + } else if (xml.name() == "temp_c") { + data.temperature_C = xml.readElementText(); + } else if (xml.name() == "relative_humidity") { + data.humidity = xml.readElementText(); + } else if (xml.name() == "wind_dir") { + data.windDirection = xml.readElementText(); + } else if (xml.name() == "wind_mph") { + data.windSpeed = xml.readElementText(); + } else if (xml.name() == "wind_gust_mph") { + data.windGust = xml.readElementText(); + } else if (xml.name() == "pressure_in") { + data.pressure = xml.readElementText(); + } else if (xml.name() == "dewpoint_f") { + data.dewpoint_F = xml.readElementText(); + } else if (xml.name() == "dewpoint_c") { + data.dewpoint_C = xml.readElementText(); + } else if (xml.name() == "heat_index_f") { + data.heatindex_F = xml.readElementText(); + } else if (xml.name() == "heat_index_c") { + data.heatindex_C = xml.readElementText(); + } else if (xml.name() == "windchill_f") { + data.windchill_F = xml.readElementText(); + } else if (xml.name() == "windchill_c") { + data.windchill_C = xml.readElementText(); + } else if (xml.name() == "visibility_mi") { + data.visibility = xml.readElementText(); + } else { + parseUnknownElement(xml); + } + } + } +} + +// Parse Weather data main loop, from here we have to decend into each tag pair +bool NOAAIon::readXMLData(const QString& source, QXmlStreamReader& xml) +{ + WeatherData data; + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + if (xml.name() == "current_observation") { + parseWeatherSite(data, xml); + } else { + parseUnknownElement(xml); + } + } + } + + m_weatherData[source] = data; + return !xml.error(); +} + +// handle when no XML tag is found +void NOAAIon::parseUnknownElement(QXmlStreamReader& xml) const +{ + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + break; + } + + if (xml.isStartElement()) { + parseUnknownElement(xml); + } + } +} + +void NOAAIon::updateWeather(const QString& source) +{ + QMap dataFields; + Plasma::DataEngine::Data data; + + data.insert("Country", country(source)); + data.insert("Place", place(source)); + data.insert("Station", station(source)); + + data.insert("Latitude", latitude(source)); + data.insert("Longitude", longitude(source)); + + // Real weather - Current conditions + data.insert("Observation Period", observationTime(source)); + data.insert("Current Conditions", conditionI18n(source)); + kDebug() << "i18n condition string: " << qPrintable(conditionI18n(source)); + + // Determine the weather icon based on the current time and computed sunrise/sunset time. + const Plasma::DataEngine::Data timeData = m_timeEngine->query( + QString("Local|Solar|Latitude=%1|Longitude=%2") + .arg(latitude(source)).arg(longitude(source))); + + QTime sunriseTime = timeData["Sunrise"].toDateTime().time(); + QTime sunsetTime = timeData["Sunset"].toDateTime().time(); + QTime currentTime = QDateTime::currentDateTime().time(); + + // Provide mapping for the condition-type to the icons to display + if (currentTime > sunriseTime && currentTime < sunsetTime) { + // Day + QString weather = condition(source).toLower(); + ConditionIcons condition = getConditionIcon(weather, true); + data.insert("Condition Icon", getWeatherIcon(condition)); + kDebug() << "Using daytime icons\n"; + } else { + // Night + QString weather = condition(source).toLower(); + ConditionIcons condition = getConditionIcon(weather, false); + data.insert("Condition Icon", getWeatherIcon(condition)); + kDebug() << "Using nighttime icons\n"; + } + + dataFields = temperature(source); + data.insert("Temperature", dataFields["temperature"]); + data.insert("Temperature Unit", dataFields["temperatureUnit"]); + + // Do we have a comfort temperature? if so display it + if (dataFields["comfortTemperature"] != "N/A") { + if (m_weatherData[source].windchill_F != "NA") { + data.insert("Windchill", QString("%1").arg(dataFields["comfortTemperature"])); + data.insert("Humidex", i18n("N/A")); + } + if (m_weatherData[source].heatindex_F != "NA" && m_weatherData[source].temperature_F.toInt() != m_weatherData[source].heatindex_F.toInt()) { + data.insert("Humidex", QString("%1").arg(dataFields["comfortTemperature"])); + data.insert("Windchill", i18n("N/A")); + } + } else { + data.insert("Windchill", i18n("N/A")); + data.insert("Humidex", i18n("N/A")); + } + + data.insert("Dewpoint", dewpoint(source)); + dataFields = pressure(source); + data.insert("Pressure", dataFields["pressure"]); + data.insert("Pressure Unit", dataFields["pressureUnit"]); + + dataFields = visibility(source); + data.insert("Visibility", dataFields["visibility"]); + data.insert("Visibility Unit", dataFields["visibilityUnit"]); + + dataFields = humidity(source); + data.insert("Humidity", dataFields["humidity"]); + data.insert("Humidity Unit", dataFields["humidityUnit"]); + + // Set number of forecasts per day/night supported, none for this ion right now + data.insert(QString("Total Weather Days"), 0); + + dataFields = wind(source); + data.insert("Wind Speed", dataFields["windSpeed"]); + data.insert("Wind Speed Unit", dataFields["windUnit"]); + + data.insert("Wind Gust", dataFields["windGust"]); + data.insert("Wind Gust Unit", dataFields["windGustUnit"]); + data.insert("Wind Direction", getWindDirectionIcon(windIcons(), dataFields["windDirection"].toLower())); + data.insert("Credit", i18n("Data provided by NOAA National Weather Service")); + + int dayIndex = 0; + foreach(const WeatherData::Forecast &forecast, m_weatherData[source].forecasts) { + + ConditionIcons icon = getConditionIcon(forecast.summary.toLower(), true); + QString iconName = getWeatherIcon(icon); + + /* Sometimes the forecast for the later days is unavailable, if so skip remianing days + * since their forecast data is probably unavailable. + */ + if (forecast.low.isEmpty() || forecast.high.isEmpty()) { + break; + } + + // Get the short day name for the forecast + data.insert(QString("Short Forecast Day %1").arg(dayIndex), QString("%1|%2|%3|%4|%5|%6") + .arg(forecast.day).arg(iconName) + .arg(i18nc("weather forecast", forecast.summary.toUtf8())) + .arg(forecast.high).arg(forecast.low).arg("N/U")); + dayIndex++; + } + + // Set number of forecasts per day/night supported + data.insert("Total Weather Days", dayIndex); + + + + setData(source, data); +} + +QString const NOAAIon::country(const QString& source) const +{ + Q_UNUSED(source); + return QString("USA"); +} + +QString NOAAIon::place(const QString& source) const +{ + return m_weatherData[source].locationName; +} + +QString NOAAIon::station(const QString& source) const +{ + return m_weatherData[source].stationID; +} + +QString NOAAIon::latitude(const QString& source) const +{ + return m_weatherData[source].stationLat; +} + +QString NOAAIon::longitude(const QString& source) const +{ + return m_weatherData[source].stationLon; +} + +QString NOAAIon::observationTime(const QString& source) const +{ + return m_weatherData[source].observationTime; +} + +int NOAAIon::periodHour(const QString& source) const +{ + return m_weatherData[source].iconPeriodHour.toInt(); +} + +QString NOAAIon::condition(const QString& source) +{ + if (m_weatherData[source].weather.isEmpty() || m_weatherData[source].weather == "NA") { + m_weatherData[source].weather = "N/A"; + } + return m_weatherData[source].weather; +} + +QString NOAAIon::conditionI18n(const QString& source) +{ + if (condition(source) == "N/A") { + return i18n("N/A"); + } else { + return i18nc("weather condition", condition(source).toUtf8()); + } +} + +QString NOAAIon::dewpoint(const QString& source) const +{ + return m_weatherData[source].dewpoint_F; +} + +QMap NOAAIon::humidity(const QString& source) const +{ + QMap humidityInfo; + if (m_weatherData[source].humidity == "NA") { + humidityInfo.insert("humidity", QString(i18n("N/A"))); + humidityInfo.insert("humidityUnit", QString::number(KUnitConversion::NoUnit)); + return humidityInfo; + } else { + humidityInfo.insert("humidity", m_weatherData[source].humidity); + humidityInfo.insert("humidityUnit", QString::number(KUnitConversion::Percent)); + } + + return humidityInfo; +} + +QMap NOAAIon::visibility(const QString& source) const +{ + QMap visibilityInfo; + if (m_weatherData[source].visibility.isEmpty()) { + visibilityInfo.insert("visibility", QString(i18n("N/A"))); + visibilityInfo.insert("visibilityUnit", QString::number(KUnitConversion::NoUnit)); + return visibilityInfo; + } + if (m_weatherData[source].visibility == "NA") { + visibilityInfo.insert("visibility", QString(i18n("N/A"))); + visibilityInfo.insert("visibilityUnit", QString::number(KUnitConversion::NoUnit)); + } else { + visibilityInfo.insert("visibility", m_weatherData[source].visibility); + visibilityInfo.insert("visibilityUnit", QString::number(KUnitConversion::Mile)); + } + return visibilityInfo; +} + +QMap NOAAIon::temperature(const QString& source) const +{ + QMap temperatureInfo; + temperatureInfo.insert("temperature", m_weatherData[source].temperature_F); + temperatureInfo.insert("temperatureUnit", QString::number(KUnitConversion::Fahrenheit)); + temperatureInfo.insert("comfortTemperature", i18n("N/A")); + + if (m_weatherData[source].heatindex_F != "NA" && m_weatherData[source].windchill_F == "NA") { + temperatureInfo.insert("comfortTemperature", m_weatherData[source].heatindex_F); + } + + if (m_weatherData[source].windchill_F != "NA" && m_weatherData[source].heatindex_F == "NA") { + temperatureInfo.insert("comfortTemperature", m_weatherData[source].windchill_F); + } + + return temperatureInfo; +} + +QMap NOAAIon::pressure(const QString& source) const +{ + QMap pressureInfo; + if (m_weatherData[source].pressure.isEmpty()) { + pressureInfo.insert("pressure", i18n("N/A")); + pressureInfo.insert("pressureUnit", QString::number(KUnitConversion::NoUnit)); + return pressureInfo; + } + + if (m_weatherData[source].pressure == "NA") { + pressureInfo.insert("pressure", i18n("N/A")); + pressureInfo.insert("visibilityUnit", QString::number(KUnitConversion::NoUnit)); + } else { + pressureInfo.insert("pressure", m_weatherData[source].pressure); + pressureInfo.insert("pressureUnit", QString::number(KUnitConversion::InchesOfMercury)); + } + return pressureInfo; +} + +QMap NOAAIon::wind(const QString& source) const +{ + QMap windInfo; + + // May not have any winds + if (m_weatherData[source].windSpeed == "NA") { + windInfo.insert("windSpeed", i18nc("wind speed", "Calm")); + windInfo.insert("windUnit", QString::number(KUnitConversion::NoUnit)); + } else { + windInfo.insert("windSpeed", QString::number(m_weatherData[source].windSpeed.toFloat(), 'f', 1)); + windInfo.insert("windUnit", QString::number(KUnitConversion::MilePerHour)); + } + + // May not always have gusty winds + if (m_weatherData[source].windGust == "NA" || m_weatherData[source].windGust == "N/A") { + windInfo.insert("windGust", i18n("N/A")); + windInfo.insert("windGustUnit", QString::number(KUnitConversion::NoUnit)); + } else { + windInfo.insert("windGust", QString::number(m_weatherData[source].windGust.toFloat(), 'f', 1)); + windInfo.insert("windGustUnit", QString::number(KUnitConversion::MilePerHour)); + } + + if (m_weatherData[source].windDirection.isEmpty()) { + windInfo.insert("windDirection", i18n("N/A")); + } else { + windInfo.insert("windDirection", i18nc("wind direction", m_weatherData[source].windDirection.toUtf8())); + } + return windInfo; +} + +/** + * Determine the condition icon based on the list of possible NOAA weather conditions as defined at + * and + * Since the number of NOAA weather conditions need to be fitted into the narowly defined groups in IonInterface::ConditionIcons, we + * try to group the NOAA conditions as best as we can based on their priorities/severity. + */ +IonInterface::ConditionIcons NOAAIon::getConditionIcon(const QString& weather, bool isDayTime) const +{ + // Consider any type of storm, tornado or funnel to be a thunderstorm. + if (weather.contains("thunderstorm") || weather.contains("funnel") || + weather.contains("tornado") || weather.contains("storm") || weather.contains("tstms")) { + + if (weather.contains("vicinity") || weather.contains("chance")) { + if (isDayTime) { + return IonInterface::ChanceThunderstormDay; + } else { + return IonInterface::ChanceThunderstormNight; + } + } + return IonInterface::Thunderstorm; + + } else if (weather.contains("pellets") || weather.contains("crystals") || + weather.contains("hail")) { + return IonInterface::Hail; + + } else if (((weather.contains("rain") || weather.contains("drizzle") || + weather.contains("showers")) && weather.contains("snow")) || weather.contains("wintry mix")) { + return IonInterface::RainSnow; + + } else if (weather.contains("snow") && weather.contains("light")) { + return IonInterface::LightSnow; + + } else if (weather.contains("snow")) { + + if (weather.contains("vicinity") || weather.contains("chance")) { + if (isDayTime) { + return IonInterface::ChanceSnowDay; + } else { + return IonInterface::ChanceSnowNight; + } + } + return IonInterface::Snow; + + } else if (weather.contains("freezing rain")) { + return IonInterface::FreezingRain; + + } else if (weather.contains("freezing drizzle")) { + return IonInterface::FreezingDrizzle; + + } else if (weather.contains("showers")) { + + if (weather.contains("vicinity") || weather.contains("chance")) { + if (isDayTime) { + return IonInterface::ChanceShowersDay; + } else { + return IonInterface::ChanceShowersNight; + } + } + return IonInterface::Showers; + + } else if (weather.contains("light rain") || weather.contains("drizzle")) { + return IonInterface::LightRain; + + } else if (weather.contains("rain")) { + return IonInterface::Rain; + + } else if (weather.contains("few clouds") || weather.contains("mostly sunny") || + weather.contains("mostly clear") || weather.contains("increasing clouds") || + weather.contains("becoming cloudy") || weather.contains("clearing") || + weather.contains("decreasing clouds") || weather.contains("becoming sunny")) { + if(isDayTime) { + return IonInterface::FewCloudsDay; + } else { + return IonInterface::FewCloudsNight; + } + } else if (weather.contains("partly cloudy") || weather.contains("partly sunny") || + weather.contains("partly clear")) { + if(isDayTime) { + return IonInterface::PartlyCloudyDay; + } else { + return IonInterface::PartlyCloudyNight; + } + } else if (weather.contains("overcast") || weather.contains("cloudy")) { + return IonInterface::Overcast; + + } else if (weather.contains("haze") || weather.contains("smoke") || + weather.contains("dust") || weather.contains("sand")) { + return IonInterface::Haze; + + } else if (weather.contains("fair") || weather.contains("clear") || weather.contains("sunny")) { + if (isDayTime) { + return IonInterface::ClearDay; + } else { + return IonInterface::ClearNight; + } + } else if (weather.contains("fog")) { + return IonInterface::Mist; + + } else { + return IonInterface::NotAvailable; + + } +} + +void NOAAIon::getForecast(const QString& source) +{ + /* Assuming that we have the latitude and longitude data at this point, get the 7-day + * forecast. + */ + KUrl url = QString("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/" + "ndfdBrowserClientByDay.php?lat=%1&lon=%2&format=24+hourly&numDays=7") + .arg(latitude(source)).arg(longitude(source)); + + KIO::TransferJob * const m_job = KIO::get(url, KIO::Reload, KIO::HideProgressInfo); + m_jobXml.insert(m_job, new QXmlStreamReader); + m_jobList.insert(m_job, source); + + if (m_job) { + connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(forecast_slotDataArrived(KIO::Job*,QByteArray))); + connect(m_job, SIGNAL(result(KJob*)), this, SLOT(forecast_slotJobFinished(KJob*))); + } +} + +void NOAAIon::forecast_slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + if (data.isEmpty() || !m_jobXml.contains(job)) { + return; + } + + // Send to xml. + m_jobXml[job]->addData(data); +} + +void NOAAIon::forecast_slotJobFinished(KJob *job) +{ + QXmlStreamReader *reader = m_jobXml.value(job); + const QString source = m_jobList.value(job); + + if (reader) { + readForecast(source, *reader); + updateWeather(source); + } + + m_jobList.remove(job); + delete m_jobXml[job]; + m_jobXml.remove(job); + + if (m_sourcesToReset.contains(source)) { + m_sourcesToReset.removeAll(source); + + // so the weather engine updates it's data + forceImmediateUpdateOfAllVisualizations(); + + // update the clients of our engine + emit forceUpdate(this, source); + } +} + +void NOAAIon::readForecast(const QString& source, QXmlStreamReader& xml) +{ + QList& forecasts = m_weatherData[source].forecasts; + + // Clear the current forecasts + forecasts.clear(); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + + /* Read all reported days from . We check for existence of a specific + * which indicates the separate day listings. The schema defines it to be + * the first item before the day listings. + */ + if (xml.name() == "layout-key" && xml.readElementText() == "k-p24h-n7-1") { + + // Read days until we get to end of parent ()tag + while (! (xml.isEndElement() && xml.name() == "time-layout")) { + + xml.readNext(); + + if (xml.name() == "start-valid-time") { + QString data = xml.readElementText(); + QDateTime date = QDateTime::fromString(data, Qt::ISODate); + + WeatherData::Forecast forecast; + forecast.day = KLocalizedDate(date.date()).formatDate(KLocale::DayName, KLocale::ShortName); + forecasts.append(forecast); + //kDebug() << forecast.day; + } + } + + } else if (xml.name() == "temperature" && xml.attributes().value("type") == "maximum") { + + // Read max temps until we get to end tag + int i = 0; + while (! (xml.isEndElement() && xml.name() == "temperature") && + i < forecasts.count()) { + + xml.readNext(); + + if (xml.name() == "value") { + forecasts[i].high = xml.readElementText(); + //kDebug() << forecasts[i].high; + i++; + } + } + } else if (xml.name() == "temperature" && xml.attributes().value("type") == "minimum") { + + // Read min temps until we get to end tag + int i = 0; + while (! (xml.isEndElement() && xml.name() == "temperature") && + i < forecasts.count()) { + + xml.readNext(); + + if (xml.name() == "value") { + forecasts[i].low = xml.readElementText(); + //kDebug() << forecasts[i].low; + i++; + } + } + } else if (xml.name() == "weather") { + + // Read weather conditions until we get to end tag + int i = 0; + while (! (xml.isEndElement() && xml.name() == "weather") && + i < forecasts.count()) { + + xml.readNext(); + + if (xml.name() == "weather-conditions" && xml.isStartElement()) { + QString summary = xml.attributes().value("weather-summary").toString(); + forecasts[i].summary = summary; + //kDebug() << forecasts[i].summary; + kDebug() << "i18n summary string: " + << qPrintable(i18nc("weather forecast", forecasts[i].summary.toUtf8())); + i++; + } + } + } + } + } +} + +#include "ion_noaa.moc" diff --git a/plasma/generic/dataengines/weather/ions/noaa/ion_noaa.h b/plasma/generic/dataengines/weather/ions/noaa/ion_noaa.h new file mode 100644 index 00000000..660a79d9 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/noaa/ion_noaa.h @@ -0,0 +1,185 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 * + ***************************************************************************/ + +/* Ion for NOAA's National Weather Service XML data */ + +#ifndef ION_NOAA_H +#define ION_NOAA_H + +#include +#include +#include + +class KJob; +namespace KIO +{ + class Job; +} // namespace KIO +#include + +#include + +#include "../dataengineconsumer.h" +#include "../ion.h" + +class WeatherData +{ + +public: + //QString countryName; // USA + QString locationName; + QString stationID; + QString stationLat; + QString stationLon; + QString stateName; + + // Current observation information. + QString observationTime; + QString iconPeriodHour; + QString iconPeriodAP; + QString weather; + + QString temperature_F; + QString temperature_C; + QString humidity; + QString windString; + QString windDirection; + QString windSpeed; // Float value + QString windGust; // Float value + QString pressure; + QString dewpoint_F; + QString dewpoint_C; + QString heatindex_F; + QString heatindex_C; + QString windchill_F; + QString windchill_C; + QString visibility; + + struct Forecast + { + QString day; + QString summary; + QString low; + QString high; + }; + QList forecasts; +}; + +class KDE_EXPORT NOAAIon : public IonInterface, public Plasma::DataEngineConsumer +{ + Q_OBJECT + +public: + NOAAIon(QObject *parent, const QVariantList &args); + ~NOAAIon(); + void init(void); // Setup the city location, fetching the correct URL name. + bool updateIonSource(const QString& source); // Sync data source with Applet + void updateWeather(const QString& source); + +public Q_SLOTS: + virtual void reset(); + +protected Q_SLOTS: + void setup_slotDataArrived(KIO::Job *, const QByteArray &); + void setup_slotJobFinished(KJob *); + + void slotDataArrived(KIO::Job *, const QByteArray &); + void slotJobFinished(KJob *); + + void forecast_slotDataArrived(KIO::Job *, const QByteArray &); + void forecast_slotJobFinished(KJob *); + +private: + /* NOAA Methods - Internal for Ion */ + QMap setupConditionIconMappings(void) const; + QMap const & conditionIcons(void) const; + QMap setupWindIconMappings(void) const; + QMap const& windIcons(void) const; + + // Place information + QString const country(const QString& source) const; + QString place(const QString& source) const; + QString station(const QString& source) const; + QString latitude(const QString& source) const; + QString longitude(const QString& source) const; + + // Current Conditions Weather info + QString observationTime(const QString& source) const; + //bool night(const QString& source); + int periodHour(const QString& source) const; + QString condition(const QString& source); + QString conditionI18n(const QString& source); + QMap temperature(const QString& source) const; + QString dewpoint(const QString& source) const; + QMap humidity(const QString& source) const; + QMap visibility(const QString& source) const; + QMap pressure(const QString& source) const; + QMap wind(const QString& source) const; + IonInterface::ConditionIcons getConditionIcon(const QString& weather, bool isDayTime) const; + + // Load and Parse the place XML listing + void getXMLSetup(void) const; + bool readXMLSetup(void); + + // Load and parse the specific place(s) + void getXMLData(const QString& source); + bool readXMLData(const QString& source, QXmlStreamReader& xml); + + // Load and parse upcoming forecast for the next N days + void getForecast(const QString& source); + void readForecast(const QString& source, QXmlStreamReader& xml); + + // Check if place specified is valid or not + QStringList validate(const QString& source) const; + + // Catchall for unknown XML tags + void parseUnknownElement(QXmlStreamReader& xml) const; + + // Parse weather XML data + void parseWeatherSite(WeatherData& data, QXmlStreamReader& xml); + void parseStationID(void); + void parseStationList(void); + + struct XMLMapInfo { + QString stateName; + QString stationName; + QString stationID; + QString XMLurl; + }; + + // Key dicts + QHash m_places; + + // Weather information + QHash m_weatherData; + + // Store KIO jobs + QMap m_jobXml; + QMap m_jobList; + QXmlStreamReader m_xmlSetup; + + Plasma::DataEngine *m_timeEngine; + QDateTime m_dateFormat; + bool emitWhenSetup; + QStringList m_sourcesToReset; +}; + +K_EXPORT_PLASMA_DATAENGINE(noaa, NOAAIon) + +#endif diff --git a/plasma/generic/dataengines/weather/ions/wetter.com/CMakeLists.txt b/plasma/generic/dataengines/weather/ions/wetter.com/CMakeLists.txt new file mode 100644 index 00000000..87383810 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/wetter.com/CMakeLists.txt @@ -0,0 +1,7 @@ +set(ion_wettercom_SRCS ion_wettercom.cpp) +kde4_add_plugin(ion_wettercom ${ion_wettercom_SRCS}) +target_link_libraries(ion_wettercom weather_ion ${KDE4_KDECORE_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KUNITCONVERSION_LIBS}) + +install(FILES ion-wettercom.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(TARGETS ion_wettercom DESTINATION ${PLUGIN_INSTALL_DIR}) + diff --git a/plasma/generic/dataengines/weather/ions/wetter.com/ion-wettercom.desktop b/plasma/generic/dataengines/weather/ions/wetter.com/ion-wettercom.desktop new file mode 100644 index 00000000..fbbc99a1 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/wetter.com/ion-wettercom.desktop @@ -0,0 +1,141 @@ +[Desktop Entry] +Name=wetter.com +Name[ar]=wetter.com +Name[ast]=wetter.com +Name[bg]=wetter.com +Name[bn]=wetter.com +Name[bs]=wetter.com +Name[ca]=wetter.com +Name[ca@valencia]=wetter.com +Name[cs]=wetter.com +Name[da]=wetter.com +Name[de]=wetter.com +Name[el]=wetter.com +Name[en_GB]=wetter.com +Name[eo]=wetter.com +Name[es]=wetter.com +Name[et]=wetter.com +Name[eu]=wetter.com +Name[fi]=wetter.com +Name[fr]=wetter.com +Name[fy]=wetter.com +Name[ga]=wetter.com +Name[gl]=wetter.com +Name[gu]=wetter.com +Name[he]=wetter.com +Name[hi]=wetter.com +Name[hr]=wetter.com +Name[hu]=wetter.com +Name[ia]=wetter.com +Name[id]=wetter.com +Name[is]=wetter.com +Name[it]=wetter.com +Name[ja]=wetter.com +Name[ka]=wetter.com +Name[kk]=wetter.com +Name[km]=wetter.com +Name[kn]=wetter.com +Name[ko]=wetter.com +Name[lt]=wetter.com +Name[lv]=wetter.com +Name[mk]=wetter.com +Name[ml]=വെറ്റര്‍.കൊം +Name[mr]=wetter.com +Name[nb]=wetter.com +Name[nds]=wetter.com +Name[nl]=wetter.com +Name[nn]=wetter.com +Name[pa]=wetter.com +Name[pl]=wetter.com +Name[pt]=wetter.com +Name[pt_BR]=wetter.com +Name[ro]=wetter.com +Name[ru]=wetter.com +Name[si]=wetter.com +Name[sk]=wetter.com +Name[sl]=wetter.com +Name[sr]=wetter.com +Name[sr@ijekavian]=wetter.com +Name[sr@ijekavianlatin]=wetter.com +Name[sr@latin]=wetter.com +Name[sv]=wetter.com +Name[tg]=wetter.com +Name[th]=wetter.com +Name[tr]=wetter.com +Name[ug]=wetter.com +Name[uk]=wetter.com +Name[wa]=wetter.com +Name[x-test]=xxwetter.comxx +Name[zh_CN]=wetter.com +Name[zh_TW]=wetter.com +Comment=Weather forecast by wetter.com +Comment[ar]=نشرة الأحوال الجوية من wetter.com +Comment[ast]=Previsión meteorolóxica de wetter.com +Comment[bg]=Прогноза за времето от wetter.com +Comment[bs]=Prognoza vremena sa wetter.com +Comment[ca]=Previsió meteorològica per wetter.com +Comment[ca@valencia]=Previsió meteorològica per wetter.com +Comment[cs]=Předpověď počasí od wetter.com +Comment[da]=Vejrudsigt fra wetter.com +Comment[de]=Wettervorhersage von wetter.com +Comment[el]=Πρόγνωση καιρού από το wetter.com +Comment[en_GB]=Weather forecast by wetter.com +Comment[es]=Previsión meteorológica de wetter.com +Comment[et]=Wetter.com-i ilmateade +Comment[eu]=wetter.com-en eguraldi-iragarpena +Comment[fi]=Sääennustus osoitteesta wetter.com +Comment[fr]=Prévisions météorologiques par « wetter.com » +Comment[fy]=Waarberjocht fan wetter.com +Comment[ga]=Réamhaisnéis aimsire ó wetterm.com +Comment[gl]=Prognóstico meteorolóxico de wetter.com +Comment[he]=תחזית מזג אוויר על־ידי wetter.com +Comment[hi]=wetter.com द्वारा मोसम पूर्वानुमान +Comment[hr]=Prognoza vremena s wetter.com +Comment[hu]=Időjárás-előrejelzés a wetter.com-ról +Comment[ia]=Prevision Meteorologic per wetter.com +Comment[id]=Ramalan cuaca oleh wetter.com +Comment[is]=Veðurspá frá wetter.com +Comment[it]=Previsioni del tempo di wetter.com +Comment[ja]=wetter.com による天気予報 +Comment[kk]=wetter.com дегеннің ауа райы болжамы. +Comment[km]=ព្យាករណ៍​អាកាស​ធាតុ​ដោយ wetter.com +Comment[kn]=wetter.com ನಿಂದ ಹವಾಮಾನ ಮುನ್ಸೂಚನೆ +Comment[ko]=wetter.com 일기예보 +Comment[lt]=Orų prognozės iš wetter.com +Comment[lv]=wetter.com laikapstākļu prognoze +Comment[mk]=Временска прогноза од wetter.com +Comment[ml]=വെറ്റര്‍.കോമിന്റെ കാലാവസ്ഥാ പ്രവചനം +Comment[mr]=wetter.com वरील हवामान पूर्वानुमान +Comment[nb]=Værmelding fra wetter.com +Comment[nds]=Wederutsichten vun "wetter.com" +Comment[nl]=Weersvoorspelling door wetter.com +Comment[nn]=Vêrmelding +Comment[pa]=wetter.com ਤੋਂ ਮੌਸਮ ਭਵਿੱਖਬਾਣੀ +Comment[pl]=Prognoza pogody z wetter.com +Comment[pt]=Previsão meteorológica da wetter.com +Comment[pt_BR]=Previsão do tempo por wetter.com +Comment[ro]=Prognoza vremii de la wetter.com +Comment[ru]=Прогноз погоды с wetter.com +Comment[si]=wetter.com මඟින් කාළගුණ අනාවැකිය +Comment[sk]=Predpoveď počasia z wetter.com +Comment[sl]=Vremenska napoved iz wetter.com +Comment[sr]=Прогноза времена са wetter.com +Comment[sr@ijekavian]=Прогноза времена са wetter.com +Comment[sr@ijekavianlatin]=Prognoza vremena sa wetter.com +Comment[sr@latin]=Prognoza vremena sa wetter.com +Comment[sv]=Väderprognos av wetter.com +Comment[tg]=Обу ҳаво аз wetter.com +Comment[th]=พยากรณ์อากาศ โดย wetter.com +Comment[tr]=wetter.com'dan hava tahmini +Comment[ug]=wetter.com تەمىنلىگەن ھاۋارايىدىن ئالدىن مەلۇمات +Comment[uk]=Прогноз погоди з wetter.com +Comment[wa]=Prédijhaedjes del meteyo pa wetter.com +Comment[x-test]=xxWeather forecast by wetter.comxx +Comment[zh_CN]=wetter.com 网站提供的天气预报 +Comment[zh_TW]=氣象預報,由 wetter.com 提供 +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-ParentApp=weatherengine +Type=Service +Icon=noneyet +X-KDE-Library=ion_wettercom +X-KDE-PluginInfo-Name=wettercom diff --git a/plasma/generic/dataengines/weather/ions/wetter.com/ion_wettercom.cpp b/plasma/generic/dataengines/weather/ions/wetter.com/ion_wettercom.cpp new file mode 100644 index 00000000..9c304a76 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/wetter.com/ion_wettercom.cpp @@ -0,0 +1,823 @@ +/*************************************************************************** + * Copyright (C) 2009 by Thilo-Alexander Ginkel * + * * + * Based upon BBC Weather Ion by Shawn Starr * + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 * + ***************************************************************************/ + +/* Ion for weather data from wetter.com */ + +// Sample URLs: +// http://api.wetter.com/location/index/search/Heidelberg/project/weatherion/cs/9090dec6e783b96bd6a6ca9d451f3fee +// http://api.wetter.com/forecast/weather/city/DE0004329/project/weatherion/cs/89f1264869cce5c6fd5a2db80051f3d8 + +#include "ion_wettercom.h" +#include +#include +#include + +/* + * Initialization + */ + +WetterComIon::WetterComIon(QObject *parent, const QVariantList &args) + : IonInterface(parent, args) + +{ + Q_UNUSED(args) + +#if defined(MIN_POLL_INTERVAL) + setMinimumPollingInterval(MIN_POLL_INTERVAL); +#endif +} + +WetterComIon::~WetterComIon() +{ + cleanup(); +} + +void WetterComIon::cleanup() +{ + // Clean up dynamically allocated forecasts + QMutableHashIterator it(m_weatherData); + while (it.hasNext()) { + it.next(); + WeatherData &item = it.value(); + qDeleteAll(item.forecasts); + item.forecasts.clear(); + } +} + +void WetterComIon::reset() +{ + cleanup(); + m_sourcesToReset = sources(); + updateAllSources(); +} + +void WetterComIon::init() +{ + setInitialized(true); +} + +QMap WetterComIon::setupCommonIconMappings(void) const +{ + QMap conditionList; + + conditionList["3"] = Overcast; + conditionList["30"] = Overcast; + conditionList["4"] = Haze; + conditionList["40"] = Haze; + conditionList["45"] = Haze; + conditionList["48"] = Haze; + conditionList["49"] = Haze; + conditionList["5"] = Mist; + conditionList["50"] = Mist; + conditionList["51"] = Mist; + conditionList["53"] = Mist; + conditionList["55"] = Mist; + conditionList["56"] = FreezingDrizzle; + conditionList["57"] = FreezingDrizzle; + conditionList["6"] = Rain; + conditionList["60"] = LightRain; + conditionList["61"] = LightRain; + conditionList["63"] = Rain; + conditionList["65"] = Rain; + conditionList["66"] = FreezingRain; + conditionList["67"] = FreezingRain; + conditionList["68"] = RainSnow; + conditionList["69"] = RainSnow; + conditionList["7"] = Snow; + conditionList["70"] = LightSnow; + conditionList["71"] = LightSnow; + conditionList["73"] = Snow; + conditionList["75"] = Flurries; + conditionList["8"] = Showers; + conditionList["81"] = Showers; + conditionList["82"] = Showers; + conditionList["83"] = RainSnow; + conditionList["84"] = RainSnow; + conditionList["85"] = Snow; + conditionList["86"] = Snow; + conditionList["9"] = Thunderstorm; + conditionList["90"] = Thunderstorm; + conditionList["96"] = Thunderstorm; + conditionList["999"] = NotAvailable; + + return conditionList; +} + +QMap WetterComIon::setupDayIconMappings(void) const +{ + QMap conditionList = setupCommonIconMappings(); + + conditionList["0"] = ClearDay; + conditionList["1"] = FewCloudsDay; + conditionList["10"] = FewCloudsDay; + conditionList["2"] = PartlyCloudyDay; + conditionList["20"] = PartlyCloudyDay; + conditionList["80"] = ChanceShowersDay; + conditionList["95"] = ChanceThunderstormDay; + + return conditionList; +} + +QMap const& WetterComIon::dayIcons(void) const +{ + static QMap const val = setupDayIconMappings(); + return val; +} + +QMap WetterComIon::setupNightIconMappings(void) const +{ + QMap conditionList = setupCommonIconMappings(); + + conditionList["0"] = ClearNight; + conditionList["1"] = FewCloudsNight; + conditionList["10"] = FewCloudsNight; + conditionList["2"] = PartlyCloudyNight; + conditionList["20"] = PartlyCloudyNight; + conditionList["80"] = ChanceShowersNight; + conditionList["95"] = ChanceThunderstormNight; + + return conditionList; +} + +QMap const& WetterComIon::nightIcons(void) const +{ + static QMap const val = setupNightIconMappings(); + return val; +} + +QMap WetterComIon::setupCommonConditionMappings(void) const +{ + QMap conditionList; + conditionList["1"] = i18nc("weather condition", "few clouds"); + conditionList["10"] = i18nc("weather condition", "few clouds"); + conditionList["2"] = i18nc("weather condition", "cloudy"); + conditionList["20"] = i18nc("weather condition", "cloudy"); + conditionList["3"] = i18nc("weather condition", "overcast"); + conditionList["30"] = i18nc("weather condition", "overcast"); + conditionList["4"] = i18nc("weather condition", "haze"); + conditionList["40"] = i18nc("weather condition", "haze"); + conditionList["45"] = i18nc("weather condition", "haze"); + conditionList["48"] = i18nc("weather condition", "fog with icing"); + conditionList["49"] = i18nc("weather condition", "fog with icing"); + conditionList["5"] = i18nc("weather condition", "drizzle"); + conditionList["50"] = i18nc("weather condition", "drizzle"); + conditionList["51"] = i18nc("weather condition", "light drizzle"); + conditionList["53"] = i18nc("weather condition", "drizzle"); + conditionList["55"] = i18nc("weather condition", "heavy drizzle"); + conditionList["56"] = i18nc("weather condition", "freezing drizzle"); + conditionList["57"] = i18nc("weather condition", "heavy freezing drizzle"); + conditionList["6"] = i18nc("weather condition", "rain"); + conditionList["60"] = i18nc("weather condition", "light rain"); + conditionList["61"] = i18nc("weather condition", "light rain"); + conditionList["63"] = i18nc("weather condition", "moderate rain"); + conditionList["65"] = i18nc("weather condition", "heavy rain"); + conditionList["66"] = i18nc("weather condition", "light freezing rain"); + conditionList["67"] = i18nc("weather condition", "freezing rain"); + conditionList["68"] = i18nc("weather condition", "light rain snow"); + conditionList["69"] = i18nc("weather condition", "heavy rain snow"); + conditionList["7"] = i18nc("weather condition", "snow"); + conditionList["70"] = i18nc("weather condition", "light snow"); + conditionList["71"] = i18nc("weather condition", "light snow"); + conditionList["73"] = i18nc("weather condition", "moderate snow"); + conditionList["75"] = i18nc("weather condition", "heavy snow"); + conditionList["8"] = i18nc("weather condition", "showers"); + conditionList["80"] = i18nc("weather condition", "light showers"); + conditionList["81"] = i18nc("weather condition", "showers"); + conditionList["82"] = i18nc("weather condition", "heavy showers"); + conditionList["83"] = i18nc("weather condition", "light snow rain showers"); + conditionList["84"] = i18nc("weather condition", "heavy snow rain showers"); + conditionList["85"] = i18nc("weather condition", "light snow showers"); + conditionList["86"] = i18nc("weather condition", "snow showers"); + conditionList["9"] = i18nc("weather condition", "thunderstorm"); + conditionList["90"] = i18nc("weather condition", "thunderstorm"); + conditionList["95"] = i18nc("weather condition", "light thunderstorm"); + conditionList["96"] = i18nc("weather condition", "heavy thunderstorm"); + conditionList["999"] = i18nc("weather condition", "n/a"); + + return conditionList; +} + +QMap WetterComIon::setupDayConditionMappings(void) const +{ + QMap conditionList = setupCommonConditionMappings(); + conditionList["0"] = i18nc("weather condition", "sunny"); + return conditionList; +} + +QMap const& WetterComIon::dayConditions(void) const +{ + static QMap const val = setupDayConditionMappings(); + return val; +} + +QMap WetterComIon::setupNightConditionMappings(void) const +{ + QMap conditionList = setupCommonConditionMappings(); + conditionList["0"] = i18nc("weather condition", "clear sky"); + return conditionList; +} + +QMap const& WetterComIon::nightConditions(void) const +{ + static QMap const val = setupNightConditionMappings(); + return val; +} + +QString WetterComIon::getWeatherCondition(const QMap &conditionList, const QString& condition) const +{ + return conditionList[condition]; +} + +bool WetterComIon::updateIonSource(const QString& source) +{ + // We expect the applet to send the source in the following tokenization: + // ionname|validate|place_name|extra - Triggers validation of place + // ionname|weather|place_name|extra - Triggers receiving weather of place + + QStringList sourceAction = source.split('|'); + + if (sourceAction.size() < 3) { + setData(source, "validate", "wettercom|malformed"); + return true; + } + + if (sourceAction[1] == "validate" && sourceAction.size() >= 3) { + // Look for places to match + findPlace(sourceAction[2], source); + return true; + } else if (sourceAction[1] == "weather" && sourceAction.size() >= 3) { + if (sourceAction.count() >= 4) { + if (sourceAction[2].isEmpty()) { + setData(source, "validate", "wettercom|malformed"); + return true; + } + + // Extra data format: placeCode;displayName + QStringList extraData = sourceAction[3].split(';'); + + if (extraData.count() != 2) { + setData(source, "validate", "wettercom|malformed"); + return true; + } + + m_place[sourceAction[2]].placeCode = extraData[0]; + + m_place[sourceAction[2]].displayName = extraData[1]; + + kDebug() << "About to retrieve forecast for source: " << sourceAction[2]; + + fetchForecast(sourceAction[2]); + + return true; + } else { + return false; + } + } else { + setData(source, "validate", "wettercom|malformed"); + return true; + } + + return false; +} + + +/* + * Handling of place searches + */ + +void WetterComIon::findPlace(const QString& place, const QString& source) +{ + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(QString::fromLatin1(PROJECTNAME).toUtf8()); + md5.addData(QString::fromLatin1(APIKEY).toUtf8()); + md5.addData(place.toUtf8()); + + KUrl url = QString::fromLatin1(SEARCH_URL).arg(place).arg(md5.result().toHex().data()); + + m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); + m_job->addMetaData("cookies", "none"); // Disable displaying cookies + m_searchJobXml.insert(m_job, new QXmlStreamReader); + m_searchJobList.insert(m_job, source); + + if (m_job) { + connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(setup_slotDataArrived(KIO::Job*,QByteArray))); + connect(m_job, SIGNAL(result(KJob*)), this, + SLOT(setup_slotJobFinished(KJob*))); + } +} + +void WetterComIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + QByteArray local = data; + + if (data.isEmpty() || !m_searchJobXml.contains(job)) { + return; + } + + m_searchJobXml[job]->addData(local); +} + +void WetterComIon::setup_slotJobFinished(KJob *job) +{ + if (job->error() == 149) { + setData(m_searchJobList[job], "validate", + QString::fromLatin1("wettercom|timeout")); + disconnectSource(m_searchJobList[job], this); + m_searchJobList.remove(job); + delete m_searchJobXml[job]; + m_searchJobXml.remove(job); + return; + } + + QXmlStreamReader *reader = m_searchJobXml.value(job); + + if (reader) { + parseSearchResults(m_searchJobList[job], *reader); + } + + m_searchJobList.remove(job); + + delete m_searchJobXml[job]; + m_searchJobXml.remove(job); +} + +void WetterComIon::parseSearchResults(const QString& source, QXmlStreamReader& xml) +{ + QString name, code, quarter, state, country; + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isEndElement()) { + if (xml.name() == "search") { + break; + } else if (xml.name() == "item") { + // we parsed a place from the search result + QString placeName; + + if (quarter.isEmpty()) { + placeName = i18nc("Geographical location: city, state, ISO-country-code", "%1, %2, %3", + name, state, country); + } else { + placeName = i18nc("Geographical location: quarter (city), state, ISO-country-code", + "%1 (%2), %3, %4", quarter, name, state, country); + } + + kDebug() << "Storing place data for place:" << placeName; + + m_place[placeName].name = placeName; + m_place[placeName].displayName = name; + m_place[placeName].placeCode = code; + m_locations.append(placeName); + + name = ""; + code = ""; + quarter = ""; + country = ""; + state = ""; + } + } + + if (xml.isStartElement()) { + if (xml.name() == "name") { + name = xml.readElementText(); + } else if (xml.name() == "city_code") { + code = xml.readElementText(); + } else if (xml.name() == "quarter") { + quarter = xml.readElementText(); + } else if (xml.name() == "adm_1_code") { + country = xml.readElementText(); + } else if (xml.name() == "adm_2_name") { + state = xml.readElementText(); + } + } + } + + validate(source, xml.error() != QXmlStreamReader::NoError); +} + +void WetterComIon::validate(const QString& source, bool parseError) +{ + bool beginflag = true; + + if (!m_locations.count() || parseError) { + QStringList invalidPlace = source.split('|'); + + if (m_place[invalidPlace[2]].name.isEmpty()) { + setData(source, "validate", + QString::fromLatin1("wettercom|invalid|multiple|%1") + .arg(invalidPlace[2])); + } + + m_locations.clear(); + + return; + } else { + QString placeList; + foreach(const QString &place, m_locations) { + // Extra data format: placeCode;displayName + if (beginflag) { + placeList.append(QString::fromLatin1("%1|extra|%2;%3") + .arg(place).arg(m_place[place].placeCode) + .arg(m_place[place].displayName)); + beginflag = false; + } else { + placeList.append(QString::fromLatin1("|place|%1|extra|%2;%3") + .arg(place).arg(m_place[place].placeCode) + .arg(m_place[place].displayName)); + } + } + + kDebug() << "Returning place list:" << placeList; + + if (m_locations.count() > 1) { + setData(source, "validate", + QString::fromLatin1("wettercom|valid|multiple|place|%1") + .arg(placeList)); + } else { + placeList[0] = placeList[0].toUpper(); + setData(source, "validate", + QString::fromLatin1("wettercom|valid|single|place|%1") + .arg(placeList)); + } + } + + m_locations.clear(); +} + + +/* + * Handling of forecasts + */ + +void WetterComIon::fetchForecast(const QString& source) +{ + foreach (const QString &fetching, m_forecastJobList) { + if (fetching == source) { + // already fetching! + return; + } + } + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(QString::fromLatin1(PROJECTNAME).toUtf8()); + md5.addData(QString::fromLatin1(APIKEY).toUtf8()); + md5.addData(m_place[source].placeCode.toUtf8()); + + KUrl url = QString::fromLatin1(FORECAST_URL) + .arg(m_place[source].placeCode).arg(md5.result().toHex().data()); + + m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo); + m_job->addMetaData("cookies", "none"); + m_forecastJobXml.insert(m_job, new QXmlStreamReader); + m_forecastJobList.insert(m_job, source); + + if (m_job) { + connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), this, + SLOT(forecast_slotDataArrived(KIO::Job*,QByteArray))); + connect(m_job, SIGNAL(result(KJob*)), this, + SLOT(forecast_slotJobFinished(KJob*))); + } +} + +void WetterComIon::forecast_slotDataArrived(KIO::Job *job, const QByteArray &data) +{ + QByteArray local = data; + + if (data.isEmpty() || !m_forecastJobXml.contains(job)) { + return; + } + + m_forecastJobXml[job]->addData(local); +} + +void WetterComIon::forecast_slotJobFinished(KJob *job) +{ + const QString source(m_forecastJobList.value(job)); + setData(source, Data()); + QXmlStreamReader *reader = m_forecastJobXml.value(job); + + if (reader) { + parseWeatherForecast(source, *reader); + } + + m_forecastJobList.remove(job); + + delete m_forecastJobXml[job]; + m_forecastJobXml.remove(job); + + if (m_sourcesToReset.contains(source)) { + m_sourcesToReset.removeAll(source); + const QString weatherSource = QString::fromLatin1("wettercom|weather|%1|%2;%3") + .arg(source).arg(m_place[source].placeCode) + .arg(m_place[source].displayName); + + // so the weather engine updates it's data + forceImmediateUpdateOfAllVisualizations(); + + // update the clients of our engine + emit forceUpdate(this, weatherSource); + } +} + +void WetterComIon::parseWeatherForecast(const QString& source, QXmlStreamReader& xml) +{ + kDebug() << "About to parse forecast for source:" << source; + + // Clear old forecasts when updating + m_weatherData[source].forecasts.clear(); + + WeatherData::ForecastPeriod *forecastPeriod = new WeatherData::ForecastPeriod; + WeatherData::ForecastInfo *forecast = new WeatherData::ForecastInfo; + int summaryWeather = -1, summaryProbability = 0; + int tempMax = -273, tempMin = 100, weather = -1, probability = 0; + uint summaryUtcTime = 0, utcTime = 0, localTime = 0; + QString date, time; + + m_weatherData[source].place = source; + + while (!xml.atEnd()) { + xml.readNext(); + + kDebug() << "parsing xml elem: " << xml.name(); + + if (xml.isEndElement()) { + if (xml.name() == "city") { + break; + } else if (xml.name() == "date") { + // we have parsed a complete day + + forecastPeriod->period = QDateTime::fromTime_t(summaryUtcTime); + QString weatherString = QString::number(summaryWeather); + forecastPeriod->iconName = getWeatherIcon(dayIcons(), + weatherString); + forecastPeriod->summary = getWeatherCondition(dayConditions(), + weatherString); + forecastPeriod->probability = summaryProbability; + + m_weatherData[source].forecasts.append(forecastPeriod); + forecastPeriod = new WeatherData::ForecastPeriod; + + date = ""; + summaryWeather = -1; + summaryProbability = 0; + summaryUtcTime = 0; + } else if (xml.name() == "time") { + // we have parsed one forecast + + kDebug() << "Parsed a forecast interval:" << date << time; + + // yep, that field is written to more often than needed... + m_weatherData[source].timeDifference = localTime - utcTime; + + forecast->period = QDateTime::fromTime_t(utcTime); + QString weatherString = QString::number(weather); + forecast->tempHigh = tempMax; + forecast->tempLow = tempMin; + forecast->probability = probability; + + QTime localWeatherTime = QDateTime::fromTime_t(utcTime).time(); + localWeatherTime.addSecs(m_weatherData[source].timeDifference); + + kDebug() << "localWeatherTime =" << localWeatherTime; + + // TODO use local sunset/sunrise time + + if (localWeatherTime.hour() < 20 && localWeatherTime.hour() > 6) { + forecast->iconName = getWeatherIcon(dayIcons(), + weatherString); + forecast->summary = getWeatherCondition(dayConditions(), + weatherString); + forecastPeriod->dayForecasts.append(forecast); + } else { + forecast->iconName = getWeatherIcon(nightIcons(), + weatherString); + forecast->summary = getWeatherCondition(nightConditions(), + weatherString); + forecastPeriod->nightForecasts.append(forecast); + } + + forecast = new WeatherData::ForecastInfo; + + tempMax = -273; + tempMin = 100; + weather = -1; + probability = 0; + utcTime = localTime = 0; + time = ""; + } + } + + if (xml.isStartElement()) { + if (xml.name() == "date") { + date = xml.attributes().value("value").toString(); + } else if (xml.name() == "time") { + time = xml.attributes().value("value").toString(); + } else if (xml.name() == "tx") { + tempMax = qRound(xml.readElementText().toDouble()); + kDebug() << "parsed t_max:" << tempMax; + } else if (xml.name() == "tn") { + tempMin = qRound(xml.readElementText().toDouble()); + kDebug() << "parsed t_min:" << tempMin; + } else if (xml.name() == "w") { + int tmp = xml.readElementText().toInt(); + + if (!time.isEmpty()) + weather = tmp; + else + summaryWeather = tmp; + + kDebug() << "parsed weather condition:" << tmp; + } else if (xml.name() == "name") { + m_weatherData[source].stationName = xml.readElementText(); + kDebug() << "parsed station name:" << m_weatherData[source].stationName; + } else if (xml.name() == "pc") { + int tmp = xml.readElementText().toInt(); + + if (!time.isEmpty()) + probability = tmp; + else + summaryProbability = tmp; + + kDebug() << "parsed probability:" << probability; + } else if (xml.name() == "text") { + m_weatherData[source].credits = xml.readElementText(); + kDebug() << "parsed credits:" << m_weatherData[source].credits; + } else if (xml.name() == "link") { + m_weatherData[source].creditsUrl = xml.readElementText(); + kDebug() << "parsed credits url:" << m_weatherData[source].creditsUrl; + } else if (xml.name() == "d") { + localTime = xml.readElementText().toInt(); + kDebug() << "parsed local time:" << localTime; + } else if (xml.name() == "du") { + int tmp = xml.readElementText().toInt(); + + if (!time.isEmpty()) + utcTime = tmp; + else + summaryUtcTime = tmp; + + kDebug() << "parsed UTC time:" << tmp; + } + } + } + + delete forecast; + delete forecastPeriod; + + updateWeather(source, xml.error() != QXmlStreamReader::NoError); +} + +void WetterComIon::updateWeather(const QString& source, bool parseError) +{ + kDebug() << "Source:" << source; + + QString weatherSource = QString::fromLatin1("wettercom|weather|%1|%2;%3") + .arg(source).arg(m_place[source].placeCode) + .arg(m_place[source].displayName); + + Plasma::DataEngine::Data data; + data.insert("Place", m_place[source].displayName); + + if (!parseError && !m_weatherData[source].forecasts.isEmpty()) { + data.insert("Station", m_place[source].displayName); + //data.insert("Condition Icon", "N/A"); + //data.insert("Temperature", "N/A"); + data.insert("Temperature Unit", QString::number(KUnitConversion::Celsius)); + + int i = 0; + foreach(WeatherData::ForecastPeriod * forecastPeriod, m_weatherData[source].forecasts) { + if (i > 0) { + WeatherData::ForecastInfo weather = forecastPeriod->getWeather(); + + data.insert(QString::fromLatin1("Short Forecast Day %1").arg(i), + QString::fromLatin1("%1|%2|%3|%4|%5|%6") + .arg(KLocalizedDate(weather.period.date()).formatDate(KLocale::DayName, KLocale::ShortName)) + .arg(weather.iconName).arg(weather.summary) + .arg(weather.tempHigh).arg(weather.tempLow) + .arg(weather.probability)); + i++; + } else { + WeatherData::ForecastInfo dayWeather = forecastPeriod->getDayWeather(); + + data.insert(QString::fromLatin1("Short Forecast Day %1").arg(i), + QString::fromLatin1("%1|%2|%3|%4|%5|%6") + .arg(i18n("Day")).arg(dayWeather.iconName) + .arg(dayWeather.summary).arg(dayWeather.tempHigh) + .arg(dayWeather.tempLow).arg(dayWeather.probability)); + i++; + + if (forecastPeriod->hasNightWeather()) { + WeatherData::ForecastInfo nightWeather = forecastPeriod->getNightWeather(); + data.insert(QString::fromLatin1("Short Forecast Day %1").arg(i), + QString::fromLatin1("%1 nt|%2|%3|%4|%5|%6") + .arg(i18n("Night")).arg(nightWeather.iconName) + .arg(nightWeather.summary) + .arg(nightWeather.tempHigh) + .arg(nightWeather.tempLow) + .arg(nightWeather.probability)); + i++; + } + } + } + + // Set number of forecasts per day/night supported + data.insert("Total Weather Days", i); + + data.insert("Credit", m_weatherData[source].credits); // FIXME i18n? + data.insert("Credit Url", m_weatherData[source].creditsUrl); + + kDebug() << "updated weather data:" << data; + } else { + kDebug() << "Something went wrong when parsing weather data for source:" << source; + } + + setData(weatherSource, data); +} + + +/* + * WeatherData::ForecastPeriod convenience methods + */ + +WeatherData::ForecastPeriod::~ForecastPeriod() +{ + qDeleteAll(dayForecasts); + qDeleteAll(nightForecasts); +} + +WeatherData::ForecastInfo WeatherData::ForecastPeriod::getDayWeather() const +{ + WeatherData::ForecastInfo result; + result.period = period; + result.iconName = iconName; + result.summary = summary; + result.tempHigh = getMaxTemp(dayForecasts); + result.tempLow = getMinTemp(dayForecasts); + result.probability = probability; + return result; +} + +WeatherData::ForecastInfo WeatherData::ForecastPeriod::getNightWeather() const +{ + kDebug() << "nightForecasts.size() =" << nightForecasts.size(); + + // TODO do not just pick the first night forecast + return *(nightForecasts.at(0)); +} + +bool WeatherData::ForecastPeriod::hasNightWeather() const +{ + return !nightForecasts.isEmpty(); +} + +WeatherData::ForecastInfo WeatherData::ForecastPeriod::getWeather() const +{ + WeatherData::ForecastInfo result = getDayWeather(); + result.tempHigh = std::max(result.tempHigh, getMaxTemp(nightForecasts)); + result.tempLow = std::min(result.tempLow, getMinTemp(nightForecasts)); + return result; +} + +int WeatherData::ForecastPeriod::getMaxTemp(QVector forecastInfos) const +{ + int result = -273; + foreach(const WeatherData::ForecastInfo * forecast, forecastInfos) { + result = std::max(result, forecast->tempHigh); + } + + return result; +} + +int WeatherData::ForecastPeriod::getMinTemp(QVector forecastInfos) const +{ + int result = 100; + foreach(const WeatherData::ForecastInfo * forecast, forecastInfos) { + result = std::min(result, forecast->tempLow); + } + + return result; +} + +#include "ion_wettercom.moc" +// kate: indent-mode cstyle; space-indent on; indent-width 4; diff --git a/plasma/generic/dataengines/weather/ions/wetter.com/ion_wettercom.h b/plasma/generic/dataengines/weather/ions/wetter.com/ion_wettercom.h new file mode 100644 index 00000000..11205298 --- /dev/null +++ b/plasma/generic/dataengines/weather/ions/wetter.com/ion_wettercom.h @@ -0,0 +1,173 @@ +/*************************************************************************** + * Copyright (C) 2009 by Thilo-Alexander Ginkel * + * * + * Based upon BBC Weather Ion by Shawn Starr * + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 * + ***************************************************************************/ + +/* Ion for weather data from wetter.com */ + +#ifndef ION_WETTERCOM_H +#define ION_WETTERCOM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../ion.h" + +// wetter.com API project data +#define PROJECTNAME "weatherion" +#define SEARCH_URL "http://api.wetter.com/location/index/search/%1/project/" PROJECTNAME "/cs/%2" +#define FORECAST_URL "http://api.wetter.com/forecast/weather/city/%1/project/" PROJECTNAME "/cs/%2" +#define APIKEY "07025b9a22b4febcf8e8ec3e6f1140e8" +#define MIN_POLL_INTERVAL 3600000L // 1 h + +class WeatherData +{ +public: + QString place; + QString stationName; + + // time difference to UTC + int timeDifference; + + // credits as returned from API request + QString credits; + QString creditsUrl; + + class ForecastBase + { + public: + QDateTime period; + QString iconName; + QString summary; + int probability; + }; + + class ForecastInfo : public ForecastBase + { + public: + int tempHigh; + int tempLow; + }; + + class ForecastPeriod : public ForecastInfo + { + public: + ~ForecastPeriod(); + + WeatherData::ForecastInfo getDayWeather() const; + WeatherData::ForecastInfo getNightWeather() const; + WeatherData::ForecastInfo getWeather() const; + + bool hasNightWeather() const; + + QVector dayForecasts; + QVector nightForecasts; + private: + int getMaxTemp(QVector forecastInfos) const; + int getMinTemp(QVector forecastInfos) const; + }; + + QVector forecasts; +}; + +class KDE_EXPORT WetterComIon : public IonInterface +{ + Q_OBJECT + +public: + WetterComIon(QObject *parent, const QVariantList &args); + ~WetterComIon(); + + bool updateIonSource(const QString& source); + +public Q_SLOTS: + virtual void reset(); + +protected Q_SLOTS: + void setup_slotDataArrived(KIO::Job *, const QByteArray &); + void setup_slotJobFinished(KJob *); + void forecast_slotDataArrived(KIO::Job *, const QByteArray &); + void forecast_slotJobFinished(KJob *); + +private: + void init(); + void cleanup(); + + // Set up the mapping from the wetter.com condition code to the respective icon / condition name + QMap setupCommonIconMappings(void) const; + QMap setupDayIconMappings(void) const; + QMap setupNightIconMappings(void) const; + QMap setupCommonConditionMappings(void) const; + QMap setupDayConditionMappings(void) const; + QMap setupNightConditionMappings(void) const; + + // Retrieve the mapping from the wetter.com condition code to the respective icon / condition name + QMap const& nightIcons(void) const; + QMap const& dayIcons(void) const; + QMap const& dayConditions(void) const; + QMap const& nightConditions(void) const; + + QString getWeatherCondition(const QMap &conditionList, const QString& condition) const; + + // Find place + void findPlace(const QString& place, const QString& source); + void parseSearchResults(const QString& source, QXmlStreamReader& xml); + void validate(const QString& source, bool parseError); + + // Retrieve and parse forecast + void fetchForecast(const QString& source); + void parseWeatherForecast(const QString& source, QXmlStreamReader& xml); + void updateWeather(const QString& source, bool parseError); + + struct PlaceInfo { + QString name; + QString displayName; + QString placeCode; + }; + + // Key dicts + QHash m_place; + QVector m_locations; + + // Weather information + QHash m_weatherData; + + // Store KIO jobs - Search list + QMap m_searchJobXml; + QMap m_searchJobList; + + // Store KIO jobs - Forecast retrieval + QMap m_forecastJobXml; + QMap m_forecastJobList; + + KIO::TransferJob *m_job; + QStringList m_sourcesToReset; +}; + +K_EXPORT_PLASMA_DATAENGINE(wettercom, WetterComIon) + +#endif +// kate: indent-mode cstyle; space-indent on; indent-width 4; diff --git a/plasma/generic/dataengines/weather/plasma-dataengine-weather.desktop b/plasma/generic/dataengines/weather/plasma-dataengine-weather.desktop new file mode 100644 index 00000000..4d2897d1 --- /dev/null +++ b/plasma/generic/dataengines/weather/plasma-dataengine-weather.desktop @@ -0,0 +1,157 @@ +[Desktop Entry] +Name=Weather +Name[ar]=الطقس +Name[ast]=Tiempu meteorolóxicu +Name[be@latin]=Nadvorje +Name[bg]=Метеорологично време +Name[bn]=আবহাওয়া +Name[bn_IN]=আবহাওয়া +Name[bs]=vrijeme +Name[ca]=Meteorologia +Name[ca@valencia]=Meteorologia +Name[cs]=Počasí +Name[da]=Vejr +Name[de]=Wetter +Name[el]=Καιρός +Name[en_GB]=Weather +Name[eo]=Vetero +Name[es]=Tiempo meteorológico +Name[et]=Ilmateade +Name[eu]=Eguraldia +Name[fi]=Sää +Name[fr]=Météo +Name[fy]=It Waar +Name[ga]=Aimsir +Name[gl]=O tempo +Name[gu]=હવામાન +Name[he]=מזג אוויר +Name[hi]=मौसम +Name[hne]=मौसम +Name[hr]=Vrijeme +Name[hu]=Időjárás +Name[ia]=Tempore meteorologic +Name[id]=Cuaca +Name[is]=Veður +Name[it]=Tempo +Name[ja]=気象 +Name[kk]=Ауа райы +Name[km]=អាកាសធាតុ +Name[kn]=ಹವಾಮಾನ +Name[ko]=날씨 +Name[ku]=Hewa +Name[lt]=Orai +Name[lv]=Laikapstākļi +Name[mai]=मौसम +Name[mk]=Време +Name[ml]=കാലാവസ്ഥ +Name[mr]=हवामान +Name[nb]=Været +Name[nds]=Weder +Name[nl]=Het weer +Name[nn]=Vêr +Name[or]=ପାଣିପାଗ +Name[pa]=ਮੌਸਮ +Name[pl]=Pogoda +Name[pt]=Meteorologia +Name[pt_BR]=Meteorologia +Name[ro]=Vremea +Name[ru]=Погода +Name[si]=කාලගුණය +Name[sk]=Počasie +Name[sl]=Vreme +Name[sr]=време +Name[sr@ijekavian]=време +Name[sr@ijekavianlatin]=vreme +Name[sr@latin]=vreme +Name[sv]=Väder +Name[ta]= +Name[te]=వాతావరణము +Name[tg]=Обу Ҳаво +Name[th]=พยากรณ์อากาศ +Name[tr]=Hava Durumu +Name[ug]=ھاۋا رايى +Name[uk]=Погода +Name[wa]=Meteyo +Name[x-test]=xxWeatherxx +Name[zh_CN]=天气 +Name[zh_TW]=天氣 +Comment=Weather data from multiple online sources +Comment[ar]=معلومات الطقس من مصادر انترنت مختلفة +Comment[ast]=Datos meteorolóxicos dende múltiples fontes. +Comment[bg]=Данни за метеорологичното време +Comment[bs]=Meteorološki podaci iz više izvora na vezi +Comment[ca]=Dades meteorològiques de múltiples fonts en línia +Comment[ca@valencia]=Dades meteorològiques de múltiples fonts en línia +Comment[cs]=Data o počasí z různých online zdrojů +Comment[da]=Vejrdata fra flere online-kilder +Comment[de]=Wetterdaten aus verschiedenen Online-Quellen +Comment[el]=Δεδομένα καιρού από πολλαπλές δικτυακές πηγές +Comment[en_GB]=Weather data from multiple online sources +Comment[eo]=Veteraj datumoj el diversaj interretaj fontoj +Comment[es]=Datos meteorológicos desde múltiples fuentes. +Comment[et]=Ilmaandmed mitmest internetiallikast +Comment[eu]=Eguraldiari buruzko informazioa hainbat iturritatik +Comment[fi]=Säätietoja useasta lähteestä +Comment[fr]=Données météorologiques depuis des sources multiples en ligne +Comment[fy]=Waar gegevens fan ferskate ynternetboarnen +Comment[ga]=Sonraí aimsire ó fhoinsí éagsúla ar líne +Comment[gl]=Información meteorolóxica de varias fontes de internet +Comment[he]=מידע על מזג האוויר ממגוון מקורות מקוונים +Comment[hi]=मोसम जानकारी अनेक ऑनलाईन स्रोतों से +Comment[hr]=Podaci o vremenu iz raznih online izvora +Comment[hu]=Időjárás-jelentés több forrásból +Comment[ia]=Datos meteorologic ex multiple fontes in linea +Comment[id]=Data cuaca dari berbagai sumber daring +Comment[is]=Veðurgögn frá ýmsum gagnabönkum á netinu +Comment[it]=Dati meteorologici da varie fonti in rete +Comment[ja]=複数のオンライン情報源からの気象データ +Comment[kk]=Түрлі онлайн көздерден алынған ауа-райы +Comment[km]=ទិន្នន័យ​អាកាសធាតុ​ពី​ប្រភព​លើបណ្ដាញ​ជា​ច្រើន +Comment[kn]=ಅನೇಕ ಆನ್‌ಲೈನ್ ಮೂಲಗಳಿಂದ ಹವಾಮಾನ ಮಾಹಿತಿ +Comment[ko]=온라인에서 온 다양한 날씨 데이터 +Comment[lt]=Orų informacija iš įvairių žiniatinklio šaltinių +Comment[lv]=Laikapstākļu dati no vairākiem tiešsaistes avotiem +Comment[mk]=Метеоролошки податоци од разни интернет-извори +Comment[ml]=പല സ്രോതസ്സുകളില്‍നിന്നുമുള്ള കാലാവസ്ഥാ സ്ഥിതിവിവരങ്ങള്‍ +Comment[mr]=अनेक ऑनलाइन स्रोतांकडून हवामान माहिती +Comment[nb]=Værdata fra mange nettverkskilder +Comment[nds]=Wederdaten vun verscheden Tokoppelborns +Comment[nl]=Weergegevens voor meervoudige online bronnen +Comment[nn]=Vêrdata frå ulike nettkjelder +Comment[pa]=ਕਈ ਆਨਲਾਈਨ ਸਰੋਤਾਂ ਤੋਂ ਮੌਸਮ ਡਾਟਾ +Comment[pl]=Dane pogodowe z wielu internetowych źródeł +Comment[pt]=Dados meteorológicos de várias fontes 'online' +Comment[pt_BR]=Dados meteorológicos de múltiplas fontes on-line +Comment[ro]=Date meteorologice din diferite surse online +Comment[ru]=Информация о погоде из разных источников в Интернете +Comment[si]=විවිධ මාර්‍ගගත මූල වලින් කාලගුණ දත්ත +Comment[sk]=Dáta o počasí z rôznych online zdrojov +Comment[sl]=Podatki o vremenu iz več spletnih virov +Comment[sr]=Метеоролошки подаци из више извора на вези +Comment[sr@ijekavian]=Метеоролошки подаци из више извора на вези +Comment[sr@ijekavianlatin]=Meteorološki podaci iz više izvora na vezi +Comment[sr@latin]=Meteorološki podaci iz više izvora na vezi +Comment[sv]=Väderdata från flera olika nättjänster +Comment[tg]=Иттилооти обу ҳаво аз манбаъҳои гуногун +Comment[th]=ข้อมูลพยากรณ์อากาศจากแหล่งข้อมูลออนไลน์ต่าง ๆ +Comment[tr]=Birden fazla çevrim içi kaynaktan hava durumu verisi +Comment[ug]=توردىكى كۆپ مەنبەدىن كەلگەن ھاۋارايى سانلىق-مەلۇماتى +Comment[uk]=Дані щодо погоди з декількох мережевих джерел +Comment[wa]=Li meteyo a pårti di sacwants sourdants so fyis +Comment[x-test]=xxWeather data from multiple online sourcesxx +Comment[zh_CN]=来自多个在线信息源的天气数据 +Comment[zh_TW]=不同線上來源的天氣資料 +X-KDE-ServiceTypes=Plasma/DataEngine +Type=Service +Icon=weather-clear +X-KDE-Library=plasma_engine_weather + +X-KDE-PluginInfo-Author=Shawn Starr +X-KDE-PluginInfo-Email=shawn.starr@rogers.com +X-KDE-PluginInfo-Name=weather +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://www.kde.org +X-KDE-PluginInfo-License=GPLv2+ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= + diff --git a/plasma/generic/dataengines/weather/weatherengine.cpp b/plasma/generic/dataengines/weather/weatherengine.cpp new file mode 100644 index 00000000..4ac23b70 --- /dev/null +++ b/plasma/generic/dataengines/weather/weatherengine.cpp @@ -0,0 +1,275 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * Copyright (C) 2009 by Aaron Seigo * + * * + * 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 "weatherengine.h" + +#include +#include + +#include +#include +#include + +#include +#include + +#include "ions/ion.h" + +// Constructor +WeatherEngine::WeatherEngine(QObject *parent, const QVariantList& args) + : Plasma::DataEngine(parent, args), + m_networkAvailable(false) +{ + Q_UNUSED(args) + + m_reconnectTimer.setSingleShot(true); + connect(&m_reconnectTimer, SIGNAL(timeout()), this, SLOT(startReconnect())); + + // Globally notify all plugins to remove their sources (and unload plugin) + connect(this, SIGNAL(sourceRemoved(QString)), this, SLOT(removeIonSource(QString))); + connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(unloadIons())); +} + +// Destructor +WeatherEngine::~WeatherEngine() +{ + // Cleanup all private data. + unloadIons(); +} + +/** + * Loads an ion plugin given a plugin name found via KService. + */ +Plasma::DataEngine *WeatherEngine::loadIon(const QString& plugName) +{ + KPluginInfo foundPlugin; + + foreach(const KPluginInfo &info, Plasma::DataEngineManager::listEngineInfo("weatherengine")) { + if (info.pluginName() == plugName) { + foundPlugin = info; + break; + } + } + + if (!foundPlugin.isValid()) { + return NULL; + } + + // Load the Ion plugin, store it into a QMap to handle multiple ions. + Plasma::DataEngine *ion = Plasma::DataEngineManager::self()->loadEngine(foundPlugin.pluginName()); + ion->setObjectName(plugName); + connect(ion, SIGNAL(sourceAdded(QString)), this, SLOT(newIonSource(QString))); + connect(ion, SIGNAL(forceUpdate(IonInterface*,QString)), this, SLOT(forceUpdate(IonInterface*,QString))); + + m_ions << plugName; + + return ion; +} + +/* FIXME: Q_PROPERTY functions to update the list of available plugins */ + +/** + * Unload an Ion plugin given a Ion plugin name. + */ +void WeatherEngine::unloadIon(const QString &name) +{ + Plasma::DataEngineManager::self()->unloadEngine(name); + m_ions.removeOne(name); +} + +void WeatherEngine::init() +{ + // Get the list of available plugins but don't load them + Solid::Networking::Status status = Solid::Networking::status(); + m_networkAvailable = (status == Solid::Networking::Connected || + status == Solid::Networking::Unknown); + connect(Solid::Networking::notifier(), SIGNAL(statusChanged(Solid::Networking::Status)), + this, SLOT(networkStatusChanged(Solid::Networking::Status))); + connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), this, SLOT(updateIonList())); + + updateIonList(); + kDebug() << "init()"; +} + +void WeatherEngine::updateIonList(const QStringList &changedResources) +{ + if (changedResources.isEmpty() || changedResources.contains("services")) { + removeAllData("ions"); + foreach (const KPluginInfo &info, Plasma::DataEngineManager::listEngineInfo("weatherengine")) { + setData("ions", info.pluginName(), + QString("%1|%2").arg(info.property("Name").toString()).arg(info.pluginName())); + } + } +} + +/** + * SLOT: Get data from a new source + */ +void WeatherEngine::newIonSource(const QString& source) +{ + IonInterface *ion = qobject_cast(sender()); + + if (!ion) { + return; + } + + kDebug() << "newIonSource()"; + ion->connectSource(source, this); +} + +/** + * SLOT: Remove the datasource from the ion and unload plugin if needed + */ +void WeatherEngine::removeIonSource(const QString& source) +{ + IonInterface *ion = ionForSource(source); + if (ion) { + ion->removeSource(source); + // If plugin has no more sources let's unload the plugin + if (ion->isEmpty()) { + unloadIon(ionNameForSource(source)); + } + } + kDebug() << "removeIonSource()"; +} + +/** + * SLOT: Push out new data to applet + */ +void WeatherEngine::dataUpdated(const QString& source, Plasma::DataEngine::Data data) +{ + kDebug() << "dataUpdated()"; + setData(source, data); +} + +void WeatherEngine::unloadIons() +{ + foreach (const QString &ion, m_ions) { + Plasma::DataEngineManager::self()->unloadEngine(ion); + } + + m_ions.clear(); +} + +/** + * SLOT: Set up each Ion for the first time and get any data + */ +bool WeatherEngine::sourceRequestEvent(const QString &source) +{ + Plasma::DataEngine *ion = ionForSource(source); + + if (!ion) { + ion = loadIon(ionNameForSource(source)); + if (!ion) { + return false; + } + } + + // we should connect to the ion anyway, even if the network + // is down. when it comes up again, then it will be refreshed + ion->connectSource(source, this); + + kDebug() << "sourceRequestEvent(): Network is: " << m_networkAvailable; + if (!m_networkAvailable) { + setData(source, Data()); + return true; + } + + if (!containerForSource(source)) { + // it is an async reply, we need to set up the data anyways + setData(source, Data()); + } + return true; +} + +/** + * SLOT: update the Applet with new data from all ions loaded. + */ +bool WeatherEngine::updateSourceEvent(const QString& source) +{ + IonInterface *ion = ionForSource(source); + if (!ion) { + return false; + } + + kDebug() << "updateSourceEvent(): Network is: " << m_networkAvailable; + if (!m_networkAvailable) { + return false; + } + + return ion->updateSourceEvent(source); +} + +void WeatherEngine::networkStatusChanged(Solid::Networking::Status status) +{ + kDebug(); + m_networkAvailable = status == Solid::Networking::Connected || status == Solid::Networking::Unknown; + if (m_networkAvailable) { + // allow the network to settle down and actually come up + m_reconnectTimer.start(5000); + } +} + +void WeatherEngine::startReconnect() +{ + foreach (const QString &i, m_ions) { + IonInterface * ion = qobject_cast(Plasma::DataEngineManager::self()->engine(i)); + kDebug() << "resetting" << ion; + if (ion) { + ion->reset(); + } + } +} + +void WeatherEngine::forceUpdate(IonInterface *i, const QString &source) +{ + const QString actualSource(i->pluginName() + '|' + source); + Plasma::DataContainer *container = containerForSource(source); + if (container) { + kDebug() << "immediate update of" << source; + container->forceImmediateUpdate(); + } else { + kDebug() << "innexplicable failure of" << source; + } +} + +IonInterface* WeatherEngine::ionForSource(const QString& name) const +{ + int offset = name.indexOf('|'); + + if (offset < 1) { + return NULL; + } + + QString ionName = name.left(offset); + return qobject_cast(Plasma::DataEngineManager::self()->engine(ionName)); +} + +QString WeatherEngine::ionNameForSource(const QString& source) const +{ + int offset = source.indexOf('|'); + if (offset < 1) { + return QString(); + } + + return QString(source.left(offset)); +} + +#include "weatherengine.moc" diff --git a/plasma/generic/dataengines/weather/weatherengine.h b/plasma/generic/dataengines/weather/weatherengine.h new file mode 100644 index 00000000..5ef9f7a8 --- /dev/null +++ b/plasma/generic/dataengines/weather/weatherengine.h @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (C) 2007-2009 by Shawn Starr * + * * + * 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 WEATHERENGINE_H +#define WEATHERENGINE_H + +#include + +#include + +#include + +#include "ions/ion.h" + + +/** + * @author Shawn Starr + * This class is DataEngine. It handles loading, unloading, updating any data the ions wish to send. It is a gateway for datasources (ions) to + * communicate with the WeatherEngine. + */ + +class WeatherEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + /** Constructor + * @param parent The parent object. + * @param args Argument list, unused. + */ + WeatherEngine(QObject *parent, const QVariantList &args); + + // Destructor + ~WeatherEngine(); + + // initialization + void init(); + + /** + * Load a plugin + * @arg pluginName Name of the plugin + * @return IonInterface returns an instance of the loaded plugin + */ + DataEngine* loadIon(const QString& pluginName); + + /** + * Unload a plugin. + * @arg name Name of the plugin. + */ + void unloadIon(const QString& name); + +protected: + /** + * Reimplemented from Plasma::DataEngine. We use it to communicate to the Ion plugins to set the data sources. + * @param source The datasource name. + */ + bool sourceRequestEvent(const QString &source); + +protected Q_SLOTS: + /** + * Reimplemented from Plasma::DataEngine. + * @param source The datasource to be updated. + * @param data The new data updated. + */ + void dataUpdated(const QString& source, Plasma::DataEngine::Data data); + + void forceUpdate(IonInterface *ion, const QString &source); + + /** + * Notify WeatherEngine a new ion has data sources. + * @arg source datasource name. + */ + void newIonSource(const QString& source); + /** + * Notify WeatherEngine a datasource is being removed. + * @arg source datasource name. + */ + void removeIonSource(const QString& source); + /** + * Reimplemented from Plasma::DataEngine. + * @param source The datasource to update. + */ + bool updateSourceEvent(const QString& source); + + /** + * Whenever networking changes, take action + */ + void networkStatusChanged(Solid::Networking::Status); + void startReconnect(); + + /** + * Cleans up the ions that are currently loaded + */ + void unloadIons(void); + + /** + * updates the list of ions whenever KSycoca changes (as well as on init + */ + void updateIonList(const QStringList &changedResources = QStringList()); + +private: + /** + * Get instance of a loaded ion. + * @returns a IonInterface instance of a loaded plugin. + */ + IonInterface* ionForSource(const QString& name) const; + + /** + * Get plugin name from datasource. + * @returns The plugin name given a datasource. + */ + QString ionNameForSource(const QString& source) const; + + QStringList m_ions; + bool m_networkAvailable; + QTimer m_reconnectTimer; +}; + +K_EXPORT_PLASMA_DATAENGINE(weather, WeatherEngine) + +#endif diff --git a/plasma/generic/runners/CMakeLists.txt b/plasma/generic/runners/CMakeLists.txt new file mode 100644 index 00000000..6831ac0b --- /dev/null +++ b/plasma/generic/runners/CMakeLists.txt @@ -0,0 +1,23 @@ +add_subdirectory(activities) +add_subdirectory(bookmarks) +add_subdirectory(calculator) +add_subdirectory(locations) +add_subdirectory(places) +add_subdirectory(services) +add_subdirectory(recentdocuments) +add_subdirectory(shell) +add_subdirectory(solid) +add_subdirectory(webshortcuts) +add_subdirectory(windowedwidgets) + +if(NepomukCore_FOUND) + add_subdirectory(nepomuksearch) +endif(NepomukCore_FOUND) + +if(NOT WIN32) +add_subdirectory(powerdevil) +add_subdirectory(sessions) +add_subdirectory(windows) +add_subdirectory(kill) +endif(NOT WIN32) + diff --git a/plasma/generic/runners/activities/CMakeLists.txt b/plasma/generic/runners/activities/CMakeLists.txt new file mode 100644 index 00000000..e630c36c --- /dev/null +++ b/plasma/generic/runners/activities/CMakeLists.txt @@ -0,0 +1,12 @@ +include_directories(${KDEBASE_WORKSPACE_SOURCE_DIR}/libs) + +set(krunner_activities_SRCS + activityrunner.cpp +) + +kde4_add_plugin(krunner_activities ${krunner_activities_SRCS}) +target_link_libraries(krunner_activities ${KDE4_PLASMA_LIBS} ${KACTIVITIES_LIBRARY}) + +install(TARGETS krunner_activities DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-runner-activityrunner.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/activities/Messages.sh b/plasma/generic/runners/activities/Messages.sh new file mode 100755 index 00000000..7d7bb1ca --- /dev/null +++ b/plasma/generic/runners/activities/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma_runner_activities.pot +rm -f rc.cpp diff --git a/plasma/generic/runners/activities/activityrunner.cpp b/plasma/generic/runners/activities/activityrunner.cpp new file mode 100644 index 00000000..728e155a --- /dev/null +++ b/plasma/generic/runners/activities/activityrunner.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2011 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "activityrunner.h" + +#include +#include +#include + +ActivityRunner::ActivityRunner(QObject *parent, const QVariantList &args) + : Plasma::AbstractRunner(parent, args), + m_activities(0), + m_keywordi18n(i18nc("KRunner keyword", "activity")), + m_keyword("activity"), + m_enabled(false) +{ + setObjectName(QLatin1String("Activities")); + setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File | + Plasma::RunnerContext::NetworkLocation | Plasma::RunnerContext::Help); + + connect(this, SIGNAL(prepare()), this, SLOT(prep())); + connect(this, SIGNAL(teardown()), this, SLOT(down())); + + serviceStatusChanged(KActivities::Consumer::FullFunctionality); +} + +void ActivityRunner::prep() +{ + if (!m_activities) { + m_activities = new KActivities::Controller(this); + connect(m_activities, SIGNAL(serviceStatusChanged(KActivities::Consumer::ServiceStatus)), + this, SLOT(serviceStatusChanged(KActivities::Consumer::ServiceStatus))); + serviceStatusChanged(m_activities->serviceStatus()); + } +} + +void ActivityRunner::down() +{ + delete m_activities; + m_activities = 0; +} + +void ActivityRunner::serviceStatusChanged(KActivities::Consumer::ServiceStatus status) +{ + const bool active = status != KActivities::Consumer::NotRunning; + if (m_enabled == active) { + return; + } + + m_enabled = active; + QList syntaxes; + if (m_enabled) { + setDefaultSyntax(Plasma::RunnerSyntax(m_keywordi18n, i18n("Lists all activities currently available to be run."))); + addSyntax(Plasma::RunnerSyntax(i18nc("KRunner keyword", "activity :q:"), i18n("Switches to activity :q:."))); + } +} + +ActivityRunner::~ActivityRunner() +{ +} + +void ActivityRunner::match(Plasma::RunnerContext &context) +{ + if (!m_enabled) { + return; + } + + const QString term = context.query().trimmed(); + bool list = false; + QString name; + + if (term.startsWith(m_keywordi18n, Qt::CaseInsensitive)) { + if (term.size() == m_keywordi18n.size()) { + list = true; + } else { + name = term.right(term.size() - m_keywordi18n.size()).trimmed(); + list = name.isEmpty(); + } + } else if (term.startsWith(m_keyword, Qt::CaseInsensitive)) { + if (term.size() == m_keyword.size()) { + list = true; + } else { + name = term.right(term.size() - m_keyword.size()).trimmed(); + list = name.isEmpty(); + } + } else if (context.singleRunnerQueryMode()) { + name = term; + } else { + return; + } + + QList matches; + QStringList activities = m_activities->listActivities(); + qSort(activities); + + const QString current = m_activities->currentActivity(); + + if (!context.isValid()) { + return; + } + + if (list) { + foreach (const QString &activity, activities) { + if (current == activity) { + continue; + } + + KActivities::Info info(activity); + addMatch(info, matches); + + if (!context.isValid()) { + return; + } + } + } else { + foreach (const QString &activity, activities) { + if (current == activity) { + continue; + } + + KActivities::Info info(activity); + if (info.name().startsWith(name, Qt::CaseInsensitive)) { + addMatch(info, matches); + } + + if (!context.isValid()) { + return; + } + } + } + + context.addMatches(context.query(), matches); +} + +void ActivityRunner::addMatch(const KActivities::Info &activity, QList &matches) +{ + Plasma::QueryMatch match(this); + match.setData(activity.id()); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setIcon(activity.icon().isEmpty() ? KIcon("preferences-activities") : KIcon(activity.icon())); + match.setText(i18n("Switch to \"%1\"", activity.name())); + match.setRelevance(0.7 + ((activity.state() == KActivities::Info::Running || + activity.state() == KActivities::Info::Starting) ? 0.1 : 0)); + matches << match; +} + +void ActivityRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(context) + + if (!m_enabled || !m_activities) { + return; + } + + m_activities->setCurrentActivity(match.data().toString()); +} + +#include "activityrunner.moc" diff --git a/plasma/generic/runners/activities/activityrunner.h b/plasma/generic/runners/activities/activityrunner.h new file mode 100644 index 00000000..7fef7492 --- /dev/null +++ b/plasma/generic/runners/activities/activityrunner.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ACTIVITYRUNNER_H +#define ACTIVITYRUNNER_H + +#include + +#include + +class ActivityRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + ActivityRunner(QObject *parent, const QVariantList &args); + ~ActivityRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + + private Q_SLOTS: + void prep(); + void down(); + void serviceStatusChanged(KActivities::Consumer::ServiceStatus status); + + private: + void addMatch(const KActivities::Info &activity, QList &matches); + + KActivities::Controller *m_activities; + const QString m_keywordi18n; + const QString m_keyword; + bool m_enabled; +}; + +K_EXPORT_PLASMA_RUNNER(activities, ActivityRunner) + +#endif diff --git a/plasma/generic/runners/activities/plasma-runner-activityrunner.desktop b/plasma/generic/runners/activities/plasma-runner-activityrunner.desktop new file mode 100644 index 00000000..f1ecde23 --- /dev/null +++ b/plasma/generic/runners/activities/plasma-runner-activityrunner.desktop @@ -0,0 +1,121 @@ +[Desktop Entry] +Name=Activities +Name[ar]=الأنشطة +Name[bg]=Дейности +Name[bs]=motor aktivnosti +Name[ca]=Activitats +Name[ca@valencia]=Activitats +Name[cs]=Aktivity +Name[da]=Aktiviteter +Name[de]=Aktivitäten +Name[el]=Δραστηριότητες +Name[en_GB]=Activities +Name[es]=Actividades +Name[et]=Tegevused +Name[eu]=Jarduerak +Name[fa]=فعالیتها +Name[fi]=Aktiviteetit +Name[fr]=Activités +Name[ga]=Gníomhaíochtaí +Name[gl]=Actividades +Name[he]=עילויות +Name[hr]=Aktivnosti +Name[hu]=Aktivitások +Name[ia]=Activitates +Name[is]=Virknistjóri +Name[it]=Attività +Name[ja]=アクティビティ +Name[kk]=Белсенділіктер +Name[km]=សកម្មភាព +Name[ko]=활동 +Name[lt]=Veiklos +Name[lv]=Aktivitātes +Name[mr]=कार्यपध्दती +Name[nb]=Aktiviteter +Name[nds]=Aktiviteten +Name[nl]=Activiteiten +Name[pa]=ਸਰਗਰਮੀਆਂ +Name[pl]=Działania +Name[pt]=Actividades +Name[pt_BR]=Atividades +Name[ro]=Activități +Name[ru]=Комнаты +Name[sk]=Aktivity +Name[sl]=Dejavnosti +Name[sr]=активности +Name[sr@ijekavian]=активности +Name[sr@ijekavianlatin]=aktivnosti +Name[sr@latin]=aktivnosti +Name[sv]=Aktiviteter +Name[tr]=Etkinlikler +Name[ug]=پائالىيەتلەر +Name[uk]=Простори дій +Name[vi]=Hoạt động +Name[wa]=Activités +Name[x-test]=xxActivitiesxx +Name[zh_CN]=活动 +Name[zh_TW]=活動 +Comment=List and switch between desktop activities +Comment[bg]=Списък и превключване между дейностите +Comment[bs]=Prikaz i prebacivanje između aktivnosti radne površine +Comment[ca]=Llista i commuta entre activitats d'escriptori +Comment[ca@valencia]=Llista i commuta entre activitats d'escriptori +Comment[cs]=Zobrazení a přepínač aktivit pracovní plochy +Comment[da]=Vis og skift mellem skrivebordsaktiviteter +Comment[de]=Aktivitäten anzeigen und zwischen ihnen umschalten +Comment[el]=Εμφάνιση και εναλλαγή μεταξύ των δραστηριοτήτων της επιφάνειας εργασίας +Comment[en_GB]=List and switch between desktop activities +Comment[es]=Ver y cambiar entre las actividades de escritorio +Comment[et]=Töölauategevuste näitamine ja nende vahel lülitamine +Comment[eu]=Zerrendatu mahaigaineko jarduerak eta batetik bestera aldatu +Comment[fi]=Luettele aktiviteetit ja vaihda niiden välillä +Comment[fr]=Affiche les activités du bureau et permet d'en changer +Comment[gl]=Lista e troca entre actividades o escritorio +Comment[he]=הצגה והחלפה בין פעילויות שולחן עבודה +Comment[hr]=Izlistaj i prebacuj između aktivnosti radne površine +Comment[hu]=Asztali aktivitások listázása és váltás közöttük +Comment[ia]=Lista e commuta inter activitates de scriptorio +Comment[is]=Telur upp og skiptir milli skjáborðsvirkni +Comment[it]=Visualizza e cambia le attività del desktop +Comment[ja]=デスクトップアクティビティを一覧表示して切り替える +Comment[kk]=Белсенділіктерді тізімдеу және ауыстыру +Comment[km]=មើល ហើយ​ប្ដូរ​ប្លង់​ផ្ទៃតុ​សកម្ម​ +Comment[ko]=데스크톱 활동을 보거나 바꾸기 +Comment[lt]=Peržiūrėti ir persijungti tarp darbastalio veiklų +Comment[lv]=Parādīt un pārslēgties starp virtuālajām darbvirsmām +Comment[mr]=वेगळ्या डेस्कटॉप कार्यपध्दतीवर जाण्यासाठी यादी दर्शवा व बदला +Comment[nb]=Vis og bytt mellom skrivebordsaktiviteter +Comment[nds]=Aktiv Schriefdischakschonen ankieken un wesseln +Comment[nl]=Bureaubladactiviteiten laten zien en er tussen schakelen +Comment[pa]=ਡੈਸਕਟਾਪ ਸਰਗਰਮੀਆਂ ਵੇਖੋ ਅਤੇ ਉਹਨਾਂ ਵਿੱਚ ਜਾਉ +Comment[pl]=Tworzenie listy i przełączanie się pomiędzy działaniami pulpitu +Comment[pt]=Ver e mudar de actividades no ambiente de trabalho +Comment[pt_BR]=Lista e alterna entre as atividades da área de trabalho +Comment[ro]=Vizualizează și schimbă între activitățile biroului +Comment[ru]=Просмотр и переключение между комнатами +Comment[sk]=Vypísať a prepínať medzi aktivitami pracovnej plochy +Comment[sl]=Oglejte si namizne dejavnosti in preklopite med njimi +Comment[sr]=Приказ и пребацивање између активности површи +Comment[sr@ijekavian]=Приказ и пребацивање између активности површи +Comment[sr@ijekavianlatin]=Prikaz i prebacivanje između aktivnosti površi +Comment[sr@latin]=Prikaz i prebacivanje između aktivnosti površi +Comment[sv]=Visa och byt mellan skrivbordsaktiviteter +Comment[tr]=Listele ve masaüstü eylemleri arasında değiştir +Comment[ug]=ئۈستەلئۈستى پائالىيەتلىرى ئارىسىدىكى تىزىم ۋە ئالماشتۇرۇش +Comment[uk]=Перегляд і перемикання між просторами дій стільниці +Comment[vi]=Liệt kê và chuyển đổi giữa các Hoạt động màn hình làm việc +Comment[wa]=Fé l' djivêye eyet passer d' ene activité do scribanne a ene ôte +Comment[x-test]=xxList and switch between desktop activitiesxx +Comment[zh_CN]=显示和切换桌面活动 +Comment[zh_TW]=列出並在桌面活動間切換 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=preferences-activities +X-KDE-Library=krunner_activities +X-KDE-PluginInfo-Author=Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=org.kde.activities +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-AdvertiseSingleRunnerQueryMode=true diff --git a/plasma/generic/runners/bookmarks/.gitignore b/plasma/generic/runners/bookmarks/.gitignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/plasma/generic/runners/bookmarks/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/plasma/generic/runners/bookmarks/CMakeLists.txt b/plasma/generic/runners/bookmarks/CMakeLists.txt new file mode 100644 index 00000000..173866bf --- /dev/null +++ b/plasma/generic/runners/bookmarks/CMakeLists.txt @@ -0,0 +1,45 @@ +########### next target ############### +set(EXTERNAL_LIBS ${KDE4_KIO_LIBS} ${QT_QTSCRIPT_LIBRARY} ${KDE4_PLASMA_LIBS} ${QT_QTSQL_LIBRARY}) +if(QJSON_FOUND) + add_definitions(-DHAVE_QJSON=1) + # Some distributions (e.g. Debian or Ubuntu 12.10) seem to install a QJSONConfig.cmake with lower-case variables, + # which is preferred to our FindQJSON.cmake. Make sure this does not break the build. + set(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${QJSON_LIBRARIES} ${qjson_LIBRARIES} ) + include_directories(${QJSON_INCLUDE_DIR} ${qjson_INCLUDE_DIR}) +endif(QJSON_FOUND) + +set(krunner_bookmarksrunner_SRCS + browserfactory.cpp + bookmarkmatch.cpp + faviconfromblob.cpp + favicon.cpp + fetchsqlite.cpp + browsers/opera.cpp + bookmarksrunner.cpp + browsers/kdebrowser.cpp + browsers/firefox.cpp +) + +if(QJSON_FOUND) +set(krunner_bookmarksrunner_SRCS + ${krunner_bookmarksrunner_SRCS} + browsers/chromefindprofile.cpp + browsers/chrome.cpp +) +endif(QJSON_FOUND) + + +kde4_add_plugin(krunner_bookmarksrunner ${krunner_bookmarksrunner_SRCS}) +target_link_libraries(krunner_bookmarksrunner ${EXTERNAL_LIBS}) + +install(TARGETS krunner_bookmarksrunner DESTINATION ${PLUGIN_INSTALL_DIR} ) + + +########### install files ############### + +install(FILES plasma-runner-bookmarks.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + +# Currently tests include only chrome, so no need to get include them if json is not found +if(QJSON_FOUND) + add_subdirectory(tests) +endif(QJSON_FOUND) diff --git a/plasma/generic/runners/bookmarks/Messages.sh b/plasma/generic/runners/bookmarks/Messages.sh new file mode 100755 index 00000000..25d9792d --- /dev/null +++ b/plasma/generic/runners/bookmarks/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_bookmarksrunner.pot diff --git a/plasma/generic/runners/bookmarks/bookmarkmatch.cpp b/plasma/generic/runners/bookmarks/bookmarkmatch.cpp new file mode 100644 index 00000000..31eb0637 --- /dev/null +++ b/plasma/generic/runners/bookmarks/bookmarkmatch.cpp @@ -0,0 +1,94 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include "bookmarkmatch.h" +#include +#include "favicon.h" + +// TODO: test + +BookmarkMatch::BookmarkMatch(Favicon *favicon, const QString& searchTerm, const QString& bookmarkTitle, const QString& bookmarkURL, const QString& description ) + : m_favicon(favicon), m_searchTerm(searchTerm), m_bookmarkTitle(bookmarkTitle), m_bookmarkURL(bookmarkURL), m_description(description) +{ +} + +Plasma::QueryMatch BookmarkMatch::asQueryMatch( Plasma::AbstractRunner* runner ) +{ + Plasma::QueryMatch::Type type = Plasma::QueryMatch::NoMatch; + qreal relevance = 0; + + if (m_bookmarkTitle.compare(m_searchTerm, Qt::CaseInsensitive) == 0 || + (!m_description.isEmpty() && m_description.compare(m_searchTerm, Qt::CaseInsensitive) == 0) + ) { + type = Plasma::QueryMatch::ExactMatch; + relevance = 1.0; + } else if (m_bookmarkTitle.contains(m_searchTerm, Qt::CaseInsensitive)) { + type = Plasma::QueryMatch::PossibleMatch; + relevance = 0.45; + } else if (!m_description.isEmpty() && m_description.contains(m_searchTerm, Qt::CaseInsensitive)) { + type = Plasma::QueryMatch::PossibleMatch; + relevance = 0.3; + } else if (m_bookmarkURL.contains(m_searchTerm, Qt::CaseInsensitive)) { + type = Plasma::QueryMatch::PossibleMatch; + relevance = 0.2; + } else { + type = Plasma::QueryMatch::PossibleMatch; + relevance = 0.18; + } + + bool isNameEmpty = m_bookmarkTitle.isEmpty(); + bool isDescriptionEmpty = m_description.isEmpty(); + + Plasma::QueryMatch match(runner); + match.setType(type); + match.setRelevance(relevance); + match.setIcon(m_favicon->iconFor(m_bookmarkURL)); + match.setSubtext(m_bookmarkURL); + + // Try to set the following as text in this order: name, description, url + match.setText( isNameEmpty + ? + (!isDescriptionEmpty ? m_description : m_bookmarkURL) + : + m_bookmarkTitle ); + + match.setData(m_bookmarkURL); + return match; +} + +void BookmarkMatch::addTo(QList< BookmarkMatch >& listOfResults, bool addEvenOnNoMatch) +{ + if(!addEvenOnNoMatch && ! ( + matches(m_searchTerm, m_bookmarkTitle) || + matches(m_searchTerm, m_description) || + matches(m_searchTerm, m_bookmarkURL) + )) { + return; + } + listOfResults << *this; +} + +bool BookmarkMatch::matches(const QString &search, const QString &matchingField) +{ + return !matchingField.simplified().isEmpty() && matchingField.contains(search, Qt::CaseInsensitive); +} + + diff --git a/plasma/generic/runners/bookmarks/bookmarkmatch.h b/plasma/generic/runners/bookmarks/bookmarkmatch.h new file mode 100644 index 00000000..54ac19d7 --- /dev/null +++ b/plasma/generic/runners/bookmarks/bookmarkmatch.h @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef BOOKMARKMATCH_H +#define BOOKMARKMATCH_H + +#include +#include +#include +#include + +class Favicon; +class BookmarkMatch +{ +public: + BookmarkMatch(Favicon *favicon, const QString &searchTerm, const QString &bookmarkTitle, const QString &bookmarkURL, const QString &description = QString()); + void addTo(QList< BookmarkMatch >& listOfResults, bool addEvenOnNoMatch); + Plasma::QueryMatch asQueryMatch(Plasma::AbstractRunner *runner); +private: + bool matches(const QString &search, const QString &matchingField); +private: + Favicon * m_favicon; + QString m_searchTerm; + QString m_bookmarkTitle; + QString m_bookmarkURL; + QString m_description; +}; + +#endif // BOOKMARKMATCH_H diff --git a/plasma/generic/runners/bookmarks/bookmarksrunner.cpp b/plasma/generic/runners/bookmarks/bookmarksrunner.cpp new file mode 100644 index 00000000..45093af1 --- /dev/null +++ b/plasma/generic/runners/bookmarks/bookmarksrunner.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "bookmarksrunner.h" +#include "browser.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "bookmarkmatch.h" +#include "browserfactory.h" +#include "bookmarksrunner_defs.h" + +BookmarksRunner::BookmarksRunner( QObject* parent, const QVariantList &args ) + : Plasma::AbstractRunner(parent, args), m_browser(0), m_browserFactory(new BrowserFactory(this)) +{ + Q_UNUSED(args) + kDebug(kdbg_code) << "Creating BookmarksRunner"; + setObjectName( QLatin1String("Bookmarks" )); + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds web browser bookmarks matching :q:."))); + setDefaultSyntax(Plasma::RunnerSyntax(i18nc("list of all web browser bookmarks", "bookmarks"), + i18n("List all web browser bookmarks"))); + + connect(this, SIGNAL(prepare()), this, SLOT(prep())); +} + +BookmarksRunner::~BookmarksRunner() +{ +} + + +void BookmarksRunner::prep() +{ + m_browser = m_browserFactory->find(findBrowserName(), this); + connect(this, SIGNAL(teardown()), dynamic_cast(m_browser), SLOT(teardown())); + m_browser->prepare(); +} + + + +void BookmarksRunner::match(Plasma::RunnerContext &context) +{ + if(! m_browser) return; + const QString term = context.query(); + if ((term.length() < 3) && (!context.singleRunnerQueryMode())) { + return; + } + + bool allBookmarks = term.compare(i18nc("list of all konqueror bookmarks", "bookmarks"), + Qt::CaseInsensitive) == 0; + + QList matches = m_browser->match(term, allBookmarks); + foreach(BookmarkMatch match, matches) { + if(!context.isValid()) + return; + context.addMatch(term, match.asQueryMatch(this)); + } +} + +QString BookmarksRunner::findBrowserName() +{ + //HACK find the default browser + KConfigGroup config(KSharedConfig::openConfig("kdeglobals"), QLatin1String("General") ); + QString exec = config.readPathEntry(QLatin1String("BrowserApplication"), QString()); + kDebug(kdbg_code) << "Found exec string: " << exec; + if (exec.isEmpty()) { + KService::Ptr service = KMimeTypeTrader::self()->preferredService("text/html"); + if (service) { + exec = service->exec(); + } + } + + kDebug(kdbg_code) << "KRunner::Bookmarks: found executable " << exec << " as default browser"; + return exec; + +} + +void BookmarksRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action) +{ + Q_UNUSED(context); + const QString term = action.data().toString(); + KUrl url = KUrl(term); + + //support urls like "kde.org" by transforming them to http://kde.org + if (url.protocol().isEmpty()) { + const int idx = term.indexOf('/'); + + url.clear(); + url.setHost(term.left(idx)); + if (idx != -1) { + //allow queries + const int queryStart = term.indexOf('?', idx); + int pathLength = -1; + if ((queryStart > -1) && (idx < queryStart)) { + pathLength = queryStart - idx; + url.setQuery(term.mid(queryStart)); + } + + url.setPath(term.mid(idx, pathLength)); + } + url.setProtocol("http"); + } + + KToolInvocation::invokeBrowser(url.url()); +} + +QMimeData * BookmarksRunner::mimeDataForMatch(const Plasma::QueryMatch * match) +{ + QMimeData * result = new QMimeData(); + QList urls; + urls << QUrl(match->data().toString()); + result->setUrls(urls); + + result->setText(match->data().toString()); + + return result; +} + +#include "bookmarksrunner.moc" diff --git a/plasma/generic/runners/bookmarks/bookmarksrunner.h b/plasma/generic/runners/bookmarks/bookmarksrunner.h new file mode 100644 index 00000000..ef0b1ea0 --- /dev/null +++ b/plasma/generic/runners/bookmarks/bookmarksrunner.h @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef BOOKMARKSRUNNER_H +#define BOOKMARKSRUNNER_H + +#include +#include + + +class KBookmark; +class Browser; +class BrowserFactory; +class KJob; + +/** This runner searchs for bookmarks in browsers like Konqueror, Firefox and Opera */ +class BookmarksRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + BookmarksRunner(QObject* parent, const QVariantList &args); + ~BookmarksRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + + private: + + /** @returns the browser to get the bookmarks from + * @see Browser + */ + QString findBrowserName(); + + private: + Browser *m_browser; + BrowserFactory * const m_browserFactory; + protected Q_SLOTS: + QMimeData * mimeDataForMatch(const Plasma::QueryMatch *match); + + private Q_SLOTS: + void prep(); +}; + +K_EXPORT_PLASMA_RUNNER(bookmarksrunner, BookmarksRunner) + +#endif diff --git a/plasma/generic/runners/bookmarks/bookmarksrunner_defs.h b/plasma/generic/runners/bookmarks/bookmarksrunner_defs.h new file mode 100644 index 00000000..211925af --- /dev/null +++ b/plasma/generic/runners/bookmarks/bookmarksrunner_defs.h @@ -0,0 +1,26 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BOOKMARKS_RUNNER_DEFS +#define BOOKMARKS_RUNNER_DEFS + +#define kdbg_code 1207 + +#endif \ No newline at end of file diff --git a/plasma/generic/runners/bookmarks/browser.h b/plasma/generic/runners/bookmarks/browser.h new file mode 100644 index 00000000..300e646d --- /dev/null +++ b/plasma/generic/runners/bookmarks/browser.h @@ -0,0 +1,39 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BROWSER_H +#define BROWSER_H +#include +#include +#include "bookmarkmatch.h" + +class Browser +{ +public: + virtual ~Browser() {} + virtual QList match(const QString& term, bool addEveryThing) = 0; + virtual void prepare() {} + +public Q_SLOTS: + virtual void teardown() {} +}; + + +#endif // BROWSER_H diff --git a/plasma/generic/runners/bookmarks/browserfactory.cpp b/plasma/generic/runners/bookmarks/browserfactory.cpp new file mode 100644 index 00000000..8abeb6fd --- /dev/null +++ b/plasma/generic/runners/bookmarks/browserfactory.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "browserfactory.h" +#include "browser.h" +#include "browsers/kdebrowser.h" +#include "browsers/firefox.h" +#include "browsers/opera.h" +#include "browsers/chromefindprofile.h" +#include "browsers/chrome.h" + +Browser *BrowserFactory::find(const QString& browserName, QObject* parent) +{ + if(m_previousBrowserName == browserName) { + return m_previousBrowser; + } + delete m_previousBrowser; + m_previousBrowserName = browserName; + if (browserName.contains("firefox", Qt::CaseInsensitive) || browserName.contains("iceweasel", Qt::CaseInsensitive)) { + m_previousBrowser = new Firefox(parent); + } else if (browserName.contains("opera", Qt::CaseInsensitive)) { + m_previousBrowser = new Opera(parent); +#ifdef HAVE_QJSON + } else if (browserName.contains("chrome", Qt::CaseInsensitive)) { + m_previousBrowser = new Chrome(new FindChromeProfile("google-chrome", QDir::homePath(), parent), parent); + } else if (browserName.contains("chromium", Qt::CaseInsensitive)) { + m_previousBrowser = new Chrome(new FindChromeProfile("chromium", QDir::homePath(), parent), parent); +#endif // HAVE_QJSON + } else { + m_previousBrowser = new KDEBrowser(parent); + } + + return m_previousBrowser; +} + + +BrowserFactory::BrowserFactory(QObject *parent) + : QObject(parent), m_previousBrowser(0), m_previousBrowserName("invalid") +{ +} + diff --git a/plasma/generic/runners/bookmarks/browserfactory.h b/plasma/generic/runners/bookmarks/browserfactory.h new file mode 100644 index 00000000..1f15f223 --- /dev/null +++ b/plasma/generic/runners/bookmarks/browserfactory.h @@ -0,0 +1,38 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BROWSERFACTORY_H +#define BROWSERFACTORY_H +#include +#include + +class Browser; +class BrowserFactory : public QObject +{ + Q_OBJECT +public: + BrowserFactory(QObject *parent =0); + Browser *find(const QString &browserName, QObject *parent = 0); +private: + Browser *m_previousBrowser; + QString m_previousBrowserName; +}; + +#endif // BROWSERFACTORY_H diff --git a/plasma/generic/runners/bookmarks/browsers/chrome.cpp b/plasma/generic/runners/bookmarks/browsers/chrome.cpp new file mode 100644 index 00000000..f1f004ea --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/chrome.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include "chrome.h" +#include "faviconfromblob.h" +#include "browsers/findprofile.h" +#include +#include +#include +#include "bookmarksrunner_defs.h" +#include +#include + +class ProfileBookmarks { +public: + ProfileBookmarks(Profile &profile) : m_profile(profile) {} + inline QList bookmarks() { return m_bookmarks; } + inline Profile profile() { return m_profile; } + void tearDown() { m_profile.favicon()->teardown(); m_bookmarks.clear(); } + void add(QVariantMap &bookmarkEntry) { m_bookmarks << bookmarkEntry; } +private: + Profile m_profile; + QList m_bookmarks; +}; + +Chrome::Chrome( FindProfile* findProfile, QObject* parent ) + : QObject(parent) +{ + foreach(Profile profile, findProfile->find()) { + m_profileBookmarks << new ProfileBookmarks(profile); + } +} + +Chrome::~Chrome() +{ + foreach(ProfileBookmarks *profileBookmark, m_profileBookmarks) { + delete profileBookmark; + } +} + +QList Chrome::match(const QString &term, bool addEveryThing) +{ + QList results; + foreach(ProfileBookmarks *profileBookmarks, m_profileBookmarks) { + results << match(term, addEveryThing, profileBookmarks); + } + return results; +} + +QList Chrome::match(const QString &term, bool addEveryThing, ProfileBookmarks *profileBookmarks) +{ + QList results; + foreach(QVariantMap bookmark, profileBookmarks->bookmarks()) { + QString url = bookmark.value("url").toString(); + + BookmarkMatch bookmarkMatch(profileBookmarks->profile().favicon(), term, bookmark.value("name").toString(), url); + bookmarkMatch.addTo(results, addEveryThing); + } + return results; +} + +void Chrome::prepare() +{ + QJson::Parser parser; + bool ok; + foreach(ProfileBookmarks *profileBookmarks, m_profileBookmarks) { + Profile profile = profileBookmarks->profile(); + QFile bookmarksFile(profile.path()); + QVariant result = parser.parse(&bookmarksFile, &ok); + if(!ok || !result.toMap().contains("roots")) { + return; + } + QVariantMap entries = result.toMap().value("roots").toMap(); + foreach(QVariant folder, entries.values()) { + parseFolder(folder.toMap(), profileBookmarks); + } + profile.favicon()->prepare(); + } +} + +void Chrome::teardown() +{ + foreach(ProfileBookmarks *profileBookmarks, m_profileBookmarks) { + profileBookmarks->tearDown(); + } +} + +void Chrome::parseFolder(const QVariantMap &entry, ProfileBookmarks *profile) +{ + QVariantList children = entry.value("children").toList(); + foreach(QVariant child, children) { + QVariantMap entry = child.toMap(); + if(entry.value("type").toString() == "folder") + parseFolder(entry, profile); + else { + profile->add(entry); + } + } +} diff --git a/plasma/generic/runners/bookmarks/browsers/chrome.h b/plasma/generic/runners/bookmarks/browsers/chrome.h new file mode 100644 index 00000000..44bde2e9 --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/chrome.h @@ -0,0 +1,49 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef CHROME_H +#define CHROME_H + +#include "browser.h" +#include "findprofile.h" +#include +#include +#include + +class FaviconFromBlob; +class ProfileBookmarks; +class Chrome : public QObject, public Browser +{ + Q_OBJECT +public: + Chrome(FindProfile *findProfile, QObject* parent = 0); + ~Chrome(); + virtual QList match(const QString &term, bool addEveryThing); +public slots: + virtual void prepare(); + virtual void teardown(); +private: + void parseFolder(const QVariantMap &entry, ProfileBookmarks *profile); + virtual QList match(const QString &term, bool addEveryThing, ProfileBookmarks *profileBookmarks); + QList m_profileBookmarks; +}; + +#endif // CHROME_H diff --git a/plasma/generic/runners/bookmarks/browsers/chromefindprofile.cpp b/plasma/generic/runners/bookmarks/browsers/chromefindprofile.cpp new file mode 100644 index 00000000..5983697f --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/chromefindprofile.cpp @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include "chromefindprofile.h" +#include +#include +#include +#include +#include "bookmarksrunner_defs.h" +#include "faviconfromblob.h" +#include + +FindChromeProfile::FindChromeProfile (const QString &applicationName, const QString &homeDirectory, QObject* parent ) + : QObject(parent), m_applicationName(applicationName), m_homeDirectory(homeDirectory) +{ +} + +QList FindChromeProfile::find() +{ + QString configDirectory = QString("%1/.config/%2") + .arg(m_homeDirectory).arg(m_applicationName); + QString localStateFileName = QString("%1/Local State") + .arg(configDirectory); + + QList profiles; + QJson::Parser parser; + bool ok; + QFile localStateFile(localStateFileName); + + QVariantMap localState = parser.parse(&localStateFile, &ok).toMap(); + if(!ok) { + kDebug(kdbg_code) << "error opening " << QFileInfo(localStateFile).absoluteFilePath(); + return profiles; + } + + QVariantMap profilesConfig = localState.value("profile").toMap().value("info_cache").toMap(); + + foreach(QString profile, profilesConfig.keys()) { + QString profilePath = QString("%1/%2").arg(configDirectory).arg(profile); + QString profileBookmarksPath = QString("%1/%2").arg(profilePath).arg("Bookmarks"); + profiles << Profile(profileBookmarksPath, FaviconFromBlob::chrome(profilePath, this)); + } + + return profiles; +} diff --git a/plasma/generic/runners/bookmarks/browsers/chromefindprofile.h b/plasma/generic/runners/bookmarks/browsers/chromefindprofile.h new file mode 100644 index 00000000..890c6e31 --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/chromefindprofile.h @@ -0,0 +1,40 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef CHROMEFINDPROFILE_H +#define CHROMEFINDPROFILE_H + +#include +#include +#include "browsers/findprofile.h" + +class FindChromeProfile : public QObject, public FindProfile +{ + +public: + explicit FindChromeProfile (const QString& applicationName, const QString &homeDirectory = QDir::homePath(), QObject* parent = 0 ); + virtual QList find(); +private: + QString const m_applicationName; + QString const m_homeDirectory; +}; + +#endif // CHROMEFINDPROFILE_H diff --git a/plasma/generic/runners/bookmarks/browsers/findprofile.h b/plasma/generic/runners/bookmarks/browsers/findprofile.h new file mode 100644 index 00000000..8d3b23ac --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/findprofile.h @@ -0,0 +1,42 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef FIND_PROFILE_H +#define FIND_PROFILE_H +#include +#include + +class Favicon; +class Profile { +public: + Profile(const QString &path, Favicon *favicon) : m_path(path), m_favicon(favicon) {} + inline QString path() const { return m_path; } + inline Favicon *favicon() const { return m_favicon; } +private: + QString m_path; + Favicon *m_favicon; +}; + +class FindProfile { +public: + virtual QList find() = 0; + virtual ~FindProfile() {} +}; + +#endif diff --git a/plasma/generic/runners/bookmarks/browsers/firefox.cpp b/plasma/generic/runners/bookmarks/browsers/firefox.cpp new file mode 100644 index 00000000..4cbe6d02 --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/firefox.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "firefox.h" +#include +#include +#include +#include "bookmarksrunner_defs.h" +#include +#include +#include +#include +#include "bookmarkmatch.h" +#include "favicon.h" +#include "fetchsqlite.h" +#include "faviconfromblob.h" + +Firefox::Firefox(QObject *parent) : + QObject(parent), + m_favicon(new FallbackFavicon(this)), + m_fetchsqlite(0) +{ + reloadConfiguration(); + kDebug(kdbg_code) << "Loading Firefox Bookmarks Browser"; +} + + +Firefox::~Firefox() +{ + if (!m_dbCacheFile.isEmpty()) { + QFile db_CacheFile(m_dbCacheFile); + if (db_CacheFile.exists()) { + kDebug(kdbg_code) << "Cache file was removed: " << db_CacheFile.remove(); + } + } + kDebug(kdbg_code) << "Deleted Firefox Bookmarks Browser"; +} + +void Firefox::prepare() +{ + if (m_dbCacheFile.isEmpty()) { + m_dbCacheFile = KStandardDirs::locateLocal("cache", "") + "bookmarkrunnerfirefoxdbfile.sqlite"; + } + if (!m_dbFile.isEmpty()) { + m_fetchsqlite = new FetchSqlite(m_dbFile, m_dbCacheFile); + m_fetchsqlite->prepare(); + + delete m_favicon; + m_favicon = 0; + + m_favicon = FaviconFromBlob::firefox(m_fetchsqlite, this); + } +} + +QList< BookmarkMatch > Firefox::match(const QString& term, bool addEverything) +{ + QList< BookmarkMatch > matches; + if (!m_fetchsqlite) { + return matches; + } + kDebug(kdbg_code) << "Firefox bookmark: match " << term; + + QString tmpTerm = term; + QString query; + if (addEverything) { + query = QString("SELECT moz_bookmarks.fk, moz_bookmarks.title, moz_places.url," \ + "moz_places.favicon_id FROM moz_bookmarks, moz_places WHERE " \ + "moz_bookmarks.type = 1 AND moz_bookmarks.fk = moz_places.id"); + } else { + const QString escapedTerm = tmpTerm.replace('\'', "\\'"); + query = QString("SELECT moz_bookmarks.fk, moz_bookmarks.title, moz_places.url," \ + "moz_places.favicon_id FROM moz_bookmarks, moz_places WHERE " \ + "moz_bookmarks.type = 1 AND moz_bookmarks.fk = moz_places.id AND " \ + "(moz_bookmarks.title LIKE '%" + escapedTerm + "%' or moz_places.url LIKE '%" + + escapedTerm + "%')"); + } + QList results = m_fetchsqlite->query(query, QMap()); + foreach(QVariantMap result, results) { + const QString title = result.value("title").toString(); + const QUrl url = result.value("url").toUrl(); + if (url.scheme().contains("place")) { + //Don't use bookmarks with empty title, url or Firefox intern url + kDebug(kdbg_code) << "element " << url << " was not added"; + continue; + } + + BookmarkMatch bookmarkMatch( m_favicon, term, title, url.toString()); + bookmarkMatch.addTo(matches, addEverything); + } + + return matches; +} + + +void Firefox::teardown() +{ + if(m_fetchsqlite) { + m_fetchsqlite->teardown(); + delete m_favicon; + m_favicon = 0; + } +} + + + +void Firefox::reloadConfiguration() +{ + KConfigGroup config(KSharedConfig::openConfig("kdeglobals"), QLatin1String("General") ); + if (QSqlDatabase::isDriverAvailable("QSQLITE")) { + KConfigGroup grp = config; + /* This allows the user to specify a profile database */ + m_dbFile = grp.readEntry("dbfile", ""); + if (m_dbFile.isEmpty() || QFile::exists(m_dbFile)) { + //Try to get the right database file, the default profile is used + KConfig firefoxProfile(QDir::homePath() + "/.mozilla/firefox/profiles.ini", + KConfig::SimpleConfig); + QStringList profilesList = firefoxProfile.groupList(); + profilesList = profilesList.filter(QRegExp("^Profile\\d+$")); + int size = profilesList.size(); + + QString profilePath; + if (size == 1) { + // There is only 1 profile so we select it + KConfigGroup fGrp = firefoxProfile.group(profilesList.first()); + profilePath = fGrp.readEntry("Path", ""); + } else { + // There are multiple profiles, find the default one + foreach(const QString & profileName, profilesList) { + KConfigGroup fGrp = firefoxProfile.group(profileName); + if (fGrp.readEntry("Default", 0)) { + profilePath = fGrp.readEntry("Path", ""); + break; + } + } + } + + if (profilePath.isEmpty()) { + kDebug(kdbg_code) << "No default firefox profile found"; + return; + } + kDebug(kdbg_code) << "Profile " << profilePath << " found"; + profilePath.prepend(QString("%1/.mozilla/firefox/").arg(QDir::homePath())); + m_dbFile = profilePath + "/places.sqlite"; + grp.writeEntry("dbfile", m_dbFile); + } + } else { + kDebug(kdbg_code) << "SQLITE driver isn't available"; + } +} diff --git a/plasma/generic/runners/bookmarks/browsers/firefox.h b/plasma/generic/runners/bookmarks/browsers/firefox.h new file mode 100644 index 00000000..551954a1 --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/firefox.h @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef FIREFOX_H +#define FIREFOX_H + +#include +#include "browser.h" + +class KJob; +class Favicon; +class FetchSqlite; +class Firefox : public QObject, public Browser +{ + Q_OBJECT +public: + explicit Firefox(QObject *parent = 0); + virtual ~Firefox(); + virtual QList match(const QString& term, bool addEverything); +public slots: + virtual void teardown(); + virtual void prepare(); +private: + virtual void reloadConfiguration(); + QString m_dbFile; + QString m_dbCacheFile; + Favicon * m_favicon; + FetchSqlite *m_fetchsqlite; +}; + +#endif // FIREFOX_H diff --git a/plasma/generic/runners/bookmarks/browsers/kdebrowser.cpp b/plasma/generic/runners/bookmarks/browsers/kdebrowser.cpp new file mode 100644 index 00000000..ff329096 --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/kdebrowser.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kdebrowser.h" +#include +#include +#include +#include "bookmarkmatch.h" +#include +#include +#include "favicon.h" + + +QIcon KDEFavicon::iconFor(const QString &url) { + const QString iconFile = KMimeType::favIconForUrl(KUrl(url)); + if (iconFile.isEmpty()) { + return defaultIcon(); + } + return KIcon(iconFile); +} + + +KDEFavicon::KDEFavicon(QObject *parent) : Favicon(parent) {} + + +KDEBrowser::KDEBrowser(QObject *parent) : + QObject(parent), m_bookmarkManager(KBookmarkManager::userBookmarksManager()), m_favicon(new KDEFavicon(this)) +{ +} + + +QList< BookmarkMatch > KDEBrowser::match(const QString& term, bool addEverything) +{ + KBookmarkGroup bookmarkGroup = m_bookmarkManager->root(); + + QList< BookmarkMatch > matches; + QStack groups; + + KBookmark bookmark = bookmarkGroup.first(); + while (!bookmark.isNull()) { +// if (!context.isValid()) { +// return; +// } TODO: restore? + + if (bookmark.isSeparator()) { + bookmark = bookmarkGroup.next(bookmark); + continue; + } + + if (bookmark.isGroup()) { // descend + //kDebug (kdbg_code) << "descending into" << bookmark.text(); + groups.push(bookmarkGroup); + bookmarkGroup = bookmark.toGroup(); + bookmark = bookmarkGroup.first(); + + while (bookmark.isNull() && !groups.isEmpty()) { +// if (!context.isValid()) { +// return; +// } TODO: restore? + + bookmark = bookmarkGroup; + bookmarkGroup = groups.pop(); + bookmark = bookmarkGroup.next(bookmark); + } + + continue; + } + + BookmarkMatch bookmarkMatch(m_favicon, term, bookmark.text(), bookmark.url().url() ); + bookmarkMatch.addTo(matches, addEverything); + + bookmark = bookmarkGroup.next(bookmark); + while (bookmark.isNull() && !groups.isEmpty()) { +// if (!context.isValid()) { +// return; +// } // TODO: restore? + + bookmark = bookmarkGroup; + bookmarkGroup = groups.pop(); + //kDebug(kdbg_code) << "ascending from" << bookmark.text() << "to" << bookmarkGroup.text(); + bookmark = bookmarkGroup.next(bookmark); + } + } + return matches; +} + diff --git a/plasma/generic/runners/bookmarks/browsers/kdebrowser.h b/plasma/generic/runners/bookmarks/browsers/kdebrowser.h new file mode 100644 index 00000000..c23f3610 --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/kdebrowser.h @@ -0,0 +1,52 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KDEBROWSER_H +#define KDEBROWSER_H + +#include "browser.h" +#include "favicon.h" +class KBookmarkManager; +class Favicon; + +class KDEFavicon : public Favicon { + Q_OBJECT +public: + KDEFavicon(QObject *parent = 0); + virtual QIcon iconFor(const QString &url); + +}; + +class KDEBrowser : public QObject, public Browser +{ + Q_OBJECT +public: + explicit KDEBrowser(QObject *parent = 0); + virtual QList match(const QString& term, bool addEverything); + +public Q_SLOTS: + virtual void teardown() {} + +private: + KBookmarkManager * const m_bookmarkManager; + Favicon * const m_favicon; +}; + +#endif // KDEBROWSER_H diff --git a/plasma/generic/runners/bookmarks/browsers/opera.cpp b/plasma/generic/runners/bookmarks/browsers/opera.cpp new file mode 100644 index 00000000..965b051a --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/opera.cpp @@ -0,0 +1,101 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "opera.h" +#include +#include "bookmarksrunner_defs.h" +#include +#include +#include "favicon.h" + + +Opera::Opera(QObject* parent): QObject(parent), m_favicon(new FallbackFavicon(this)) +{ +} + +QList Opera::match( const QString& term, bool addEverything ) +{ + QList matches; + + QLatin1String nameStart("\tNAME="); + QLatin1String urlStart("\tURL="); + QLatin1String descriptionStart("\tDESCRIPTION="); + + // search + foreach (const QString & entry, m_operaBookmarkEntries) { + QStringList entryLines = entry.split("\n"); + if (!entryLines.first().startsWith(QString("#URL"))) { + continue; // skip folder entries + } + entryLines.pop_front(); + + QString name; + QString url; + QString description; + + foreach (const QString & line, entryLines) { + if (line.startsWith(nameStart)) { + name = line.mid( QString(nameStart).length() ).simplified(); + } else if (line.startsWith(urlStart)) { + url = line.mid( QString(urlStart).length() ).simplified(); + } else if (line.startsWith(descriptionStart)) { + description = line.mid(QString(descriptionStart).length()) + .simplified(); + } + } + + BookmarkMatch bookmarkMatch(m_favicon, term, name, url, description); + bookmarkMatch.addTo(matches, addEverything); + } + return matches; +} + + +void Opera::prepare() +{ + // open bookmarks file + QString operaBookmarksFilePath = QDir::homePath() + "/.opera/bookmarks.adr"; + QFile operaBookmarksFile(operaBookmarksFilePath); + if (!operaBookmarksFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + kDebug(kdbg_code) << "Could not open Operas Bookmark File " + operaBookmarksFilePath; + return; + } + + // check format + QString firstLine = operaBookmarksFile.readLine(); + if (firstLine.compare("Opera Hotlist version 2.0\n")) { + kDebug(kdbg_code) << "Format of Opera Bookmarks File might have changed."; + } + operaBookmarksFile.readLine(); // skip options line ("Options: encoding = utf8, version=3") + operaBookmarksFile.readLine(); // skip empty line + + // load contents + QString contents = operaBookmarksFile.readAll(); + m_operaBookmarkEntries = contents.split("\n\n", QString::SkipEmptyParts); + + // close file + operaBookmarksFile.close(); +} + +void Opera::teardown() +{ + m_operaBookmarkEntries.clear(); +} + diff --git a/plasma/generic/runners/bookmarks/browsers/opera.h b/plasma/generic/runners/bookmarks/browsers/opera.h new file mode 100644 index 00000000..f5fa4074 --- /dev/null +++ b/plasma/generic/runners/bookmarks/browsers/opera.h @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + + +#ifndef OPERA_H +#define OPERA_H + +#include "browser.h" +#include + +class Favicon; + +class Opera : public QObject, public Browser +{ +Q_OBJECT +public: + Opera(QObject* parent = 0); + virtual QList match(const QString& term, bool addEverything); +public slots: + virtual void prepare(); + virtual void teardown(); +private: + QStringList m_operaBookmarkEntries; + Favicon * const m_favicon; +}; + +#endif // OPERA_H diff --git a/plasma/generic/runners/bookmarks/favicon.cpp b/plasma/generic/runners/bookmarks/favicon.cpp new file mode 100644 index 00000000..0fee8bc0 --- /dev/null +++ b/plasma/generic/runners/bookmarks/favicon.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "favicon.h" + +Favicon::Favicon(QObject *parent) : + QObject(parent), m_default_icon(KIcon("bookmarks")) +{ +} diff --git a/plasma/generic/runners/bookmarks/favicon.h b/plasma/generic/runners/bookmarks/favicon.h new file mode 100644 index 00000000..3cc42620 --- /dev/null +++ b/plasma/generic/runners/bookmarks/favicon.h @@ -0,0 +1,55 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef FAVICON_H +#define FAVICON_H + +#include +#include + +class Favicon : public QObject +{ + Q_OBJECT +public: + explicit Favicon(QObject *parent = 0); + virtual QIcon iconFor(const QString &url) = 0; + +protected: + inline KIcon defaultIcon() const { return m_default_icon; } +private: + KIcon const m_default_icon; + +public slots: + virtual void prepare() {} + virtual void teardown() {} + +}; + + +class FallbackFavicon : public Favicon { + Q_OBJECT +public: + FallbackFavicon(QObject *parent = 0) : Favicon(parent) {} + virtual QIcon iconFor(const QString &) { return defaultIcon(); } +}; + + +#endif // FAVICON_H diff --git a/plasma/generic/runners/bookmarks/faviconfromblob.cpp b/plasma/generic/runners/bookmarks/faviconfromblob.cpp new file mode 100644 index 00000000..dc0010eb --- /dev/null +++ b/plasma/generic/runners/bookmarks/faviconfromblob.cpp @@ -0,0 +1,148 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "faviconfromblob.h" + +#include +#include +#include +#include +#include +#include +#include +#include "bookmarksrunner_defs.h" +#include "fetchsqlite.h" + +#include +#include +#include +#include + +#define dbFileName m_profileCacheDirectory + QDir::separator() + "Favicons.sqlite" + + +class StaticQuery : public BuildQuery { +public: + StaticQuery(const QString &query) : m_query(query) {} + virtual QString query(QSqlDatabase *database) const { + Q_UNUSED(database); + return m_query; + } +private: + const QString m_query; +}; + +class ChromeQuery : public BuildQuery { +public: + ChromeQuery() {} + virtual QString query(QSqlDatabase *database) const { + kDebug(kdbg_code) << "tables: " << database->tables(); + if(database->tables().contains("favicon_bitmaps")) + return "SELECT * FROM favicons " \ + "inner join icon_mapping on icon_mapping.icon_id = favicons.id " \ + "inner join favicon_bitmaps on icon_mapping.icon_id = favicon_bitmaps.icon_id " \ + "WHERE page_url = :url ORDER BY height desc LIMIT 1;"; + return "SELECT * FROM favicons inner join icon_mapping " \ + "on icon_mapping.icon_id = favicons.id " \ + "WHERE page_url = :url LIMIT 1;"; + } +}; + +FaviconFromBlob *FaviconFromBlob::chrome(const QString &profileDirectory, QObject *parent) +{ + QString profileName = QFileInfo(profileDirectory).fileName(); + QString faviconCache = QString("%1/KRunner-Chrome-Favicons-%2.sqlite") + .arg(KStandardDirs::locateLocal("cache", "")) + .arg(profileName); + FetchSqlite *fetchSqlite = new FetchSqlite(profileDirectory + "/Favicons", faviconCache, parent); + return new FaviconFromBlob(profileName, new ChromeQuery(), "image_data", fetchSqlite, parent); +} + +FaviconFromBlob *FaviconFromBlob::firefox(FetchSqlite *fetchSqlite, QObject *parent) +{ + + QString faviconQuery = QString("SELECT moz_favicons.data FROM moz_favicons" \ + " inner join moz_places ON moz_places.favicon_id = moz_favicons.id" \ + " WHERE moz_places.url = :url LIMIT 1;"); + return new FaviconFromBlob("firefox-default", new StaticQuery(faviconQuery), "data", fetchSqlite, parent); +} + + +FaviconFromBlob::FaviconFromBlob(const QString &profileName, BuildQuery *buildQuery, const QString &blobColumn, FetchSqlite *fetchSqlite, QObject *parent) + : Favicon(parent), m_buildQuery(buildQuery), m_blobcolumn(blobColumn), m_fetchsqlite(fetchSqlite) +{ + m_profileCacheDirectory = QString("%1/KRunner-Favicons-%2") + .arg(KStandardDirs::locateLocal("cache", "")) + .arg(profileName); + kDebug(kdbg_code) << "got cache directory: " << m_profileCacheDirectory; + cleanCacheDirectory(); + QDir().mkpath(m_profileCacheDirectory); +} + +FaviconFromBlob::~FaviconFromBlob() +{ + cleanCacheDirectory(); + delete m_buildQuery; +} + +void FaviconFromBlob::prepare() +{ + m_fetchsqlite->prepare(); +} + +void FaviconFromBlob::teardown() +{ + m_fetchsqlite->teardown(); +} + +void FaviconFromBlob::cleanCacheDirectory() +{ + foreach(QFileInfo file, QDir(m_profileCacheDirectory).entryInfoList(QDir::NoDotAndDotDot)) { + kDebug(kdbg_code) << "Removing file " << file.absoluteFilePath() << ": " << + QFile(file.absoluteFilePath()).remove(); + } + QDir().rmdir(m_profileCacheDirectory); +} + +QIcon FaviconFromBlob::iconFor(const QString &url) +{ + kDebug(kdbg_code) << "got url: " << url; + QString fileChecksum = QString("%1").arg(qChecksum(url.toAscii(), url.toAscii().size())); + QFile iconFile( m_profileCacheDirectory + QDir::separator() + fileChecksum + "_favicon" ); + if(iconFile.size() == 0) + iconFile.remove(); + if(!iconFile.exists()) { + QMap bindVariables; + bindVariables.insert("url", url); + QList faviconFound = m_fetchsqlite->query(m_buildQuery, bindVariables); + if(faviconFound.isEmpty()) return defaultIcon(); + + QByteArray iconData = faviconFound.first().value(m_blobcolumn).toByteArray(); + kDebug(kdbg_code) << "Favicon found: " << iconData.size() << " bytes"; + if(iconData.size() <=0) + return defaultIcon(); + + iconFile.open(QFile::WriteOnly); + iconFile.write(iconData); + iconFile.close(); + } + return QIcon(iconFile.fileName()); +} + diff --git a/plasma/generic/runners/bookmarks/faviconfromblob.h b/plasma/generic/runners/bookmarks/faviconfromblob.h new file mode 100644 index 00000000..df520933 --- /dev/null +++ b/plasma/generic/runners/bookmarks/faviconfromblob.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CHROMEFAVICON_H +#define CHROMEFAVICON_H + +#include +#include "favicon.h" +#include "fetchsqlite.h" + +class FaviconFromBlob : public Favicon +{ + Q_OBJECT +public: + static FaviconFromBlob *chrome(const QString &profileDirectory, QObject *parent = 0); + static FaviconFromBlob *firefox(FetchSqlite *fetchSqlite, QObject *parent = 0); + ~FaviconFromBlob(); + virtual QIcon iconFor(const QString &url); + +public slots: + virtual void prepare(); + virtual void teardown(); + +private: + FaviconFromBlob(const QString &profileName, BuildQuery *buildQuery, const QString &blobColumn, FetchSqlite *fetchSqlite, QObject *parent = 0); + QString m_profileCacheDirectory; + BuildQuery *m_buildQuery; + QString const m_blobcolumn; + FetchSqlite *m_fetchsqlite; + void cleanCacheDirectory(); +}; + +#endif // CHROMEFAVICON_H diff --git a/plasma/generic/runners/bookmarks/fetchsqlite.cpp b/plasma/generic/runners/bookmarks/fetchsqlite.cpp new file mode 100644 index 00000000..c732d873 --- /dev/null +++ b/plasma/generic/runners/bookmarks/fetchsqlite.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "fetchsqlite.h" +#include +#include +#include "bookmarksrunner_defs.h" +#include +#include +#include + +FetchSqlite::FetchSqlite(const QString &originalFilePath, const QString ©To, QObject *parent) : + QObject(parent), m_databaseFile(copyTo) +{ + m_db = QSqlDatabase::addDatabase("QSQLITE", originalFilePath); + m_db.setHostName("localhost"); + + QFile originalFile(originalFilePath); + QFile(copyTo).remove(); + bool couldCopy = originalFile.copy(copyTo); + if(!couldCopy) { + kDebug(kdbg_code) << "error copying favicon database from " << originalFile.fileName() << " to " << copyTo; + kDebug(kdbg_code) << originalFile.errorString(); + } +} + +FetchSqlite::~FetchSqlite() +{ + if(m_db.isOpen()) m_db.close(); + QFile(m_databaseFile).remove(); +} + +void FetchSqlite::prepare() +{ + m_db.setDatabaseName(m_databaseFile); + bool ok = m_db.open(); + kDebug(kdbg_code) << "Sqlite Database " << m_databaseFile << " was opened: " << ok; + if(!ok) { + kDebug(kdbg_code) << "Error: " << m_db.lastError().text(); + } +} + +void FetchSqlite::teardown() +{ + m_db.close(); +} + +QList FetchSqlite::query(BuildQuery *buildQuery, QMap bindObjects) +{ + return query(buildQuery->query(&m_db), bindObjects); +} + +QList FetchSqlite::query(const QString &sql, QMap bindObjects) +{ + kDebug(kdbg_code) << "query: " << sql; + QSqlQuery query(m_db); + query.prepare(sql); + foreach(const QString &variableName, bindObjects.keys()) { + query.bindValue(variableName, bindObjects.value(variableName)); + kDebug(kdbg_code) << "* Bound " << variableName << " to " << query.boundValue(variableName); + } + + if(!query.exec()) { + QSqlError error = m_db.lastError(); + kDebug(kdbg_code) << "query failed: " << error.text() << " (" << error.type() << ", " << error.number() << ")"; + kDebug(kdbg_code) << query.lastQuery(); + } + + QList result; + while(query.next()) { + QVariantMap recordValues; + QSqlRecord record = query.record(); + for(int field=0; field + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef FETCHSQLITE_H +#define FETCHSQLITE_H +#include +#include +#include + +#include +#include + +#include + + +class BuildQuery { +public: + virtual QString query(QSqlDatabase *database) const = 0; + virtual ~BuildQuery() {} +}; + +class FetchSqlite : public QObject +{ + Q_OBJECT +public: + explicit FetchSqlite(const QString &originalFile, const QString ©To, QObject *parent = 0); + ~FetchSqlite(); + void prepare(); + void teardown(); + QList query(const QString &sql, QMap bindObjects); + QList query(BuildQuery *buildQuery, QMap bindObjects); + QList query(const QString &sql); + +private: + QString const m_databaseFile; + QSqlDatabase m_db; +}; + +#endif // FETCHSQLITE_H diff --git a/plasma/generic/runners/bookmarks/plasma-runner-bookmarks.desktop b/plasma/generic/runners/bookmarks/plasma-runner-bookmarks.desktop new file mode 100644 index 00000000..f3c0231c --- /dev/null +++ b/plasma/generic/runners/bookmarks/plasma-runner-bookmarks.desktop @@ -0,0 +1,160 @@ +[Desktop Entry] +# ctxt: plasma runner +Name=Bookmarks +Name[ar]=العلامات +Name[ast]=Marcadores +Name[bg]=Отметки +Name[bn]=বুকমার্ক +Name[bs]=Zabilješke +Name[ca]=Adreces d'interès +Name[ca@valencia]=Adreces d'interés +Name[cs]=Záložky +Name[csb]=Załóżczi +Name[da]=Bogmærker +Name[de]=Lesezeichen +Name[el]=Σελιδοδείκτες +Name[en_GB]=Bookmarks +Name[eo]=Legosignoj +Name[es]=Marcadores +Name[et]=Järjehoidjad +Name[eu]=Laster-markak +Name[fi]=Kirjanmerkit +Name[fr]=Signets +Name[fy]=Blêdwizers +Name[ga]=Leabharmharcanna +Name[gl]=Marcadores +Name[gu]=બુકમાર્કો +Name[he]=סימניות +Name[hi]=पसंदीदा +Name[hr]=Oznake +Name[hu]=Könyvjelzők +Name[ia]=Marcatores de libro +Name[id]=Penanda +Name[is]=Bókamerki +Name[it]=Segnalibri +Name[ja]=ブックマーク +Name[kk]=Бетбелгілер +Name[km]=ចំណាំ​ +Name[kn]=ಅಂಕನಗಳು (ಬುಕ್ ಮಾರ್ಕ್) +Name[ko]=책갈피 +Name[lt]=Žymelės +Name[lv]=Grāmatzīmes +Name[mk]=Обележувачи +Name[ml]=അടയാളക്കുറിപ്പുകള്‍ +Name[mr]=ओळखचिन्ह +Name[nb]=Bokmerker +Name[nds]=Leestekens +Name[nl]=Bladwijzers +Name[nn]=Bokmerke +Name[pa]=ਬੁੱਕਮਾਰਕ +Name[pl]=Zakładki +Name[pt]=Favoritos +Name[pt_BR]=Favoritos +Name[ro]=Semne de carte +Name[ru]=Закладки +Name[si]=පොත්සලකුණු +Name[sk]=Záložky +Name[sl]=Zaznamki +Name[sr]=обележивачи +Name[sr@ijekavian]=обележивачи +Name[sr@ijekavianlatin]=obeleživači +Name[sr@latin]=obeleživači +Name[sv]=Bokmärken +Name[tg]=Хатчӯбмонӣ +Name[th]=ที่คั่นหน้า +Name[tr]=Yer İmleri +Name[ug]=خەتكۈشلەر +Name[uk]=Закладки +Name[vi]=Dấu trang +Name[wa]=Rimarkes +Name[x-test]=xxBookmarksxx +Name[zh_CN]=书签 +Name[zh_TW]=書籤 +Comment=Find and open bookmarks +Comment[ar]=اعثر على وافتح علامات +Comment[ast]=Guetar y abrir marcadores +Comment[be@latin]=Pošuk i adčynieńnie zakładak. +Comment[bg]=Търсене и зареждане на отметки +Comment[bn]=বুকমার্ক খোঁজো এবং খোলো +Comment[bn_IN]=বুকমার্ক অনুসন্ধান করুন ও খুলুন +Comment[bs]=Nađite i otvorite zabilješku +Comment[ca]=Cerca i obre adreces d'interès +Comment[ca@valencia]=Cerca i obri adreces d'interés +Comment[cs]=Najít a otevřít záložku +Comment[csb]=Malézë ë òtemkni załóżczi +Comment[da]=Find og åbn bogmærker +Comment[de]=Lesezeichen finden und aufrufen +Comment[el]=Αναζήτηση και άνοιγμα σελιδοδεικτών +Comment[en_GB]=Find and open bookmarks +Comment[eo]=Trovi kaj malfermi legosignon +Comment[es]=Buscar y abrir marcadores +Comment[et]=Järjehoidjate otsimine ja avamine +Comment[eu]=Bilatu eta ireki laster-markak +Comment[fi]=Etsi ja avaa kirjanmerkkejä +Comment[fr]=Trouver et ouvrir les signets +Comment[fy]=Sykje en iepenje blêdwizers +Comment[ga]=Aimsigh agus oscail leabharmharcanna +Comment[gl]=Busca e abre marcadores +Comment[gu]=બુકમાર્ક્સ શોધો અને ખોલો +Comment[he]=חיפוש ופתיחת סימניות +Comment[hi]=पसंदीदा ढूंढें व खोलें +Comment[hne]=निसानी खोजो अउ खोलो +Comment[hr]=Pronađi i otvori oznake +Comment[hu]=Könyvjelzőmegnyitó +Comment[ia]=Trova e aperi marcatores de libro +Comment[id]=Cari dan buka penanda +Comment[is]=Finna og opna bókamerki +Comment[it]=Trova e apri segnalibri +Comment[ja]=ブックマークを探して開きます +Comment[kk]=Бетбелгілерді тауып ашу +Comment[km]=រក​ និង​បើក​ចំណាំ +Comment[kn]=ಅಂಕನಗಳನ್ನು (ಬುಕ್ ಮಾರ್ಕ್) ಹುಡುಕಿ ತೆರೆ +Comment[ko]=책갈피를 탐색하고 열기 +Comment[ku]=Bijareyan bibîne û veke +Comment[lt]=Rasti ir atverti žymelę +Comment[lv]=Meklēt un atvērt grāmatzīmes +Comment[mk]=Пронајдете и отворете обележувачи +Comment[ml]=അടയാളക്കുറിപ്പുകള്‍ കണ്ടെത്തി തുറക്കുക +Comment[mr]=ओळखचिन्ह शोधा व उघडा +Comment[nb]=Søk etter og åpne bokmerker +Comment[nds]=Leestekens söken un opmaken +Comment[nl]=Bladwijzers vinden en openen +Comment[nn]=Finn og opna bokmerke +Comment[or]=ଚିହ୍ନିତ ସ୍ଥାନଗୁଡ଼ିକୁ ଖୋଜନ୍ତୁ ଏବଂ ଖୋଲନ୍ତୁ +Comment[pa]=ਬੁੱਕਮਾਰਕ ਖੋਜੋ ਅਤੇ ਖੋਲ੍ਹੋ +Comment[pl]=Znajdowanie i otwieranie zakładek +Comment[pt]=Descobrir e abrir os favoritos +Comment[pt_BR]=Localiza e abre favoritos +Comment[ro]=Caută și deschide semne de carte +Comment[ru]=Закладки +Comment[si]=පොත්සලකුණු සොයා විවෘත කරන්න +Comment[sk]=Nájsť a otvoriť záložky +Comment[sl]=Najdi in odpri zaznamke +Comment[sr]=Нађите и отворите обележивач +Comment[sr@ijekavian]=Нађите и отворите обиљеживач +Comment[sr@ijekavianlatin]=Nađite i otvorite obilježivač +Comment[sr@latin]=Nađite i otvorite obeleživač +Comment[sv]=Sök efter och öppna bokmärken +Comment[ta]=Find and open bookmarks +Comment[te]=పేజిగుర్తులను కనుగొనుము మరియు తెరువుము +Comment[tg]=Ҷустуҷӯи замимаҳо +Comment[th]=ค้นหาและเปิดคั่นหน้า +Comment[tr]=Yer imlerini bul ve aç +Comment[ug]=خەتكۈشلەرنى ئىزدە ۋە ئاچ +Comment[uk]=Знайти і відкрити закладки +Comment[vi]=Tìm và mở đánh dấu trang +Comment[wa]=Trover eyet drovi des rmarkes +Comment[x-test]=xxFind and open bookmarksxx +Comment[zh_CN]=查找并打开书签 +Comment[zh_TW]=尋找並開啟書籤 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=bookmarks +X-KDE-Library=krunner_bookmarksrunner +X-KDE-PluginInfo-Author=Glenn Ergeerts, Marco Gulino +X-KDE-PluginInfo-Email=glenn.ergeerts@telenet.be, marco.gulino@gmail.com +X-KDE-PluginInfo-Name=bookmarks +X-KDE-PluginInfo-Version=1.1 +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-AdvertiseSingleRunnerQueryMode=true diff --git a/plasma/generic/runners/bookmarks/tests/CMakeLists.txt b/plasma/generic/runners/bookmarks/tests/CMakeLists.txt new file mode 100644 index 00000000..1325ffdf --- /dev/null +++ b/plasma/generic/runners/bookmarks/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +set( testChromeBookmarks_SRCS testchromebookmarks.cpp + ../browsers/chrome.cpp + ../faviconfromblob.cpp + ../browsers/chromefindprofile.cpp + ../bookmarkmatch.cpp + ../favicon.cpp + ../fetchsqlite.cpp +) +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ) +kde4_add_unit_test( testChromeBookmarks TESTNAME plasma-runner-bookmarks-TestChromeBookmarks ${testChromeBookmarks_SRCS} ) + +target_link_libraries( testChromeBookmarks ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY} ${QT_QTSQL_LIBRARY} ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} qjson) + +file(COPY chrome-config-home DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/plasma/generic/runners/bookmarks/tests/chrome-config-home/.config/chromium/Local State b/plasma/generic/runners/bookmarks/tests/chrome-config-home/.config/chromium/Local State new file mode 100644 index 00000000..711eaa90 --- /dev/null +++ b/plasma/generic/runners/bookmarks/tests/chrome-config-home/.config/chromium/Local State @@ -0,0 +1,65 @@ +{ + "browser": { + "last_redirect_origin": "" + }, + "local_state": { + "multiple_profile_prefs_version": 7 + }, + "ntp": { + "intro_display_count": 11, + "promo_locale": "en-US", + "promo_version": 7 + }, + "profile": { + "info_cache": { + "Default": { + "avatar_icon": "chrome://theme/IDR_PROFILE_AVATAR_0", + "background_apps": false, + "name": "First user", + "user_name": "" + }, + "Profile 1": { + "avatar_icon": "chrome://theme/IDR_PROFILE_AVATAR_14", + "background_apps": false, + "name": "Awesome", + "user_name": "" + } + }, + "last_used": "Default", + "profiles_created": 2 + }, + "show-first-run-bubble": false, + "shutdown": { + "num_processes": 3, + "num_processes_slow": 1, + "type": 1 + }, + "uninstall_metrics": { + "installation_date2": "1342779510", + "launch_count": "1" + }, + "user_experience_metrics": { + "session_id": 0, + "stability": { + "breakpad_registration_fail": 1, + "breakpad_registration_ok": 0, + "crash_count": 0, + "debugger_not_present": 1, + "debugger_present": 0, + "exited_cleanly": true, + "incomplete_session_end_count": 0, + "last_timestamp_sec": "1342779635", + "launch_count": 1, + "launch_time_sec": "1342779510", + "page_load_count": 0, + "renderer_crash_count": 0, + "renderer_hang_count": 0, + "session_end_completed": true, + "stats_buildtime": "1342149434", + "stats_version": "20.0.1132.47-64-devel" + } + }, + "was": { + "restarted": false + } +} diff --git a/plasma/generic/runners/bookmarks/tests/chrome-config-home/Chrome-Bookmarks-Sample.json b/plasma/generic/runners/bookmarks/tests/chrome-config-home/Chrome-Bookmarks-Sample.json new file mode 100644 index 00000000..092ac37d --- /dev/null +++ b/plasma/generic/runners/bookmarks/tests/chrome-config-home/Chrome-Bookmarks-Sample.json @@ -0,0 +1,55 @@ +{ + "checksum": "191d94e91bec51787ab07c82e94c396f", + "roots": { + "bookmark_bar": { + "children": [ { + "date_added": "12987182320843562", + "id": "4", + "name": "some bookmark in bookmark bar", + "type": "url", + "url": "http://somehost.com/" + } ], + "date_added": "12987182274941985", + "date_modified": "12987182320843562", + "id": "1", + "name": "Bookmarks Bar", + "type": "folder" + }, + "other": { + "children": [ { + "date_added": "12987182348211072", + "id": "5", + "name": "bookmark in other bookmarks", + "type": "url", + "url": "http://otherbookmarks.com/" + }, { + "children": [ { + "date_added": "12987182366305763", + "id": "7", + "name": "bookmark in somefolder", + "type": "url", + "url": "http://somefolder.com/" + } ], + "date_added": "12987182352136671", + "date_modified": "12987182366305763", + "id": "6", + "name": "somefolder", + "type": "folder" + } ], + "date_added": "12987182274941996", + "date_modified": "12987182348211072", + "id": "2", + "name": "Other Bookmarks", + "type": "folder" + }, + "synced": { + "children": [ ], + "date_added": "12987182274941997", + "date_modified": "0", + "id": "3", + "name": "Mobile Bookmarks", + "type": "folder" + } + }, + "version": 1 +} diff --git a/plasma/generic/runners/bookmarks/tests/chrome-config-home/Chrome-Bookmarks-SecondProfile.json b/plasma/generic/runners/bookmarks/tests/chrome-config-home/Chrome-Bookmarks-SecondProfile.json new file mode 100644 index 00000000..6087568f --- /dev/null +++ b/plasma/generic/runners/bookmarks/tests/chrome-config-home/Chrome-Bookmarks-SecondProfile.json @@ -0,0 +1,20 @@ +{ + "checksum": "191d94e91bec51787ab07c82e94c396f", + "roots": { + "bookmark_bar": { + "children": [ ], + "date_added": "12987182274941985", + "date_modified": "12987182320843562", + "id": "1", + "name": "Bookmarks Bar", + "type": "folder" + }, + "other": { + "children": [{ + "date_added": "12987182366305763", + "id": "7", + "name": "bookmark in secondProfile", + "type": "url", + "url": "http://secondprofile.com/" + } ] } } +} diff --git a/plasma/generic/runners/bookmarks/tests/testchromebookmarks.cpp b/plasma/generic/runners/bookmarks/tests/testchromebookmarks.cpp new file mode 100644 index 00000000..5c42eed9 --- /dev/null +++ b/plasma/generic/runners/bookmarks/tests/testchromebookmarks.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "testchromebookmarks.h" +#include +#include +#include "browsers/chrome.h" +#include "browsers/chromefindprofile.h" +#include "favicon.h" + +using namespace Plasma; + +FakeFindProfile findBookmarksInCurrentDirectory(QList() + << Profile("chrome-config-home/Chrome-Bookmarks-Sample.json", new FallbackFavicon())); + + +void TestChromeBookmarks::bookmarkFinderShouldFindEachProfileDirectory() +{ + FindChromeProfile findChrome("chromium", "./chrome-config-home"); + QString profileTemplate = QString("./chrome-config-home/.config/%1/%2/Bookmarks"); + + QList profiles = findChrome.find(); + QCOMPARE(profiles.size(), 2); + QCOMPARE(profiles[0].path(), profileTemplate.arg("chromium").arg("Default")); + QCOMPARE(profiles[1].path(), profileTemplate.arg("chromium").arg("Profile 1")); +} + +void TestChromeBookmarks::bookmarkFinderShouldReportNoProfilesOnErrors() +{ + FindChromeProfile findChrome("chromium", "./no-config-directory"); + + QList profiles = findChrome.find(); + QCOMPARE(profiles.size(), 0); +} + + +void TestChromeBookmarks::itShouldFindNothingWhenPrepareIsNotCalled() +{ + Chrome *chrome = new Chrome(&findBookmarksInCurrentDirectory, this); + QCOMPARE(chrome->match("any", true).size(), 0); +} + +void TestChromeBookmarks::itShouldGracefullyExitWhenFileIsNotFound() +{ + FakeFindProfile finder(QList() << Profile("FileNotExisting.json", NULL)); + Chrome *chrome = new Chrome(&finder, this); + chrome->prepare(); + QCOMPARE(chrome->match("any", true).size(), 0); +} + + +void verifyMatch(BookmarkMatch &match, const QString &title, const QString &url, qreal relevance, QueryMatch::Type type) { + QueryMatch queryMatch = match.asQueryMatch(NULL); + QCOMPARE(queryMatch.text(), title); + QCOMPARE(queryMatch.data().toString(), url); + QCOMPARE(queryMatch.relevance(), relevance); + QVERIFY2(queryMatch.type() == type, + QString("Wrong query match type: expecting %1 but was %2").arg(type).arg(queryMatch.type() ).toAscii()); +} + +void TestChromeBookmarks::itShouldFindAllBookmarks() +{ + Chrome *chrome = new Chrome(&findBookmarksInCurrentDirectory, this); + chrome->prepare(); + QList matches = chrome->match("any", true); + QCOMPARE(matches.size(), 3); + verifyMatch(matches[0], "some bookmark in bookmark bar", "http://somehost.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[1], "bookmark in other bookmarks", "http://otherbookmarks.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[2], "bookmark in somefolder", "http://somefolder.com/", 0.18, QueryMatch::PossibleMatch); +} + +void TestChromeBookmarks::itShouldFindOnlyMatches() +{ + Chrome *chrome = new Chrome(&findBookmarksInCurrentDirectory, this); + chrome->prepare(); + QList matches = chrome->match("other", false); + QCOMPARE(matches.size(), 1); + verifyMatch(matches[0], "bookmark in other bookmarks", "http://otherbookmarks.com/", 0.45, QueryMatch::PossibleMatch); +} + +void TestChromeBookmarks::itShouldClearResultAfterCallingTeardown() +{ + Chrome *chrome = new Chrome(&findBookmarksInCurrentDirectory, this); + chrome->prepare(); + QCOMPARE(chrome->match("any", true).size(), 3); + chrome->teardown(); + QCOMPARE(chrome->match("any", true).size(), 0); + +} + +void TestChromeBookmarks::itShouldFindBookmarksFromAllProfiles() +{ + FakeFindProfile findBookmarksFromAllProfiles(QList() + << Profile("chrome-config-home/Chrome-Bookmarks-Sample.json", new FallbackFavicon(this)) + << Profile("chrome-config-home/Chrome-Bookmarks-SecondProfile.json", new FallbackFavicon(this)) ); + Chrome *chrome = new Chrome(&findBookmarksFromAllProfiles, this); + chrome->prepare(); + QList matches = chrome->match("any", true); + QCOMPARE(matches.size(), 4); + verifyMatch(matches[0], "some bookmark in bookmark bar", "http://somehost.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[1], "bookmark in other bookmarks", "http://otherbookmarks.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[2], "bookmark in somefolder", "http://somefolder.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[3], "bookmark in secondProfile", "http://secondprofile.com/", 0.18, QueryMatch::PossibleMatch); +} + +#include "testchromebookmarks.moc" + +QTEST_MAIN(TestChromeBookmarks); diff --git a/plasma/generic/runners/bookmarks/tests/testchromebookmarks.h b/plasma/generic/runners/bookmarks/tests/testchromebookmarks.h new file mode 100644 index 00000000..12a77067 --- /dev/null +++ b/plasma/generic/runners/bookmarks/tests/testchromebookmarks.h @@ -0,0 +1,53 @@ +/* + * Copyright 2007 Glenn Ergeerts + * Copyright 2012 Glenn Ergeerts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef TESTCHROMEBOOKMARKS_H +#define TESTCHROMEBOOKMARKS_H + +#include +#include "browsers/findprofile.h" + +class FakeFindProfile : public FindProfile { +public: + FakeFindProfile(const QList &profiles) : m_profiles(profiles) {} + virtual QList find() { return m_profiles; } +private: + QList m_profiles; +}; + +class TestChromeBookmarks : public QObject +{ +Q_OBJECT +public: + explicit TestChromeBookmarks(QObject* parent = 0) : QObject(parent) {} +private slots: + void bookmarkFinderShouldFindEachProfileDirectory(); + void bookmarkFinderShouldReportNoProfilesOnErrors(); + void itShouldFindNothingWhenPrepareIsNotCalled(); + void itShouldGracefullyExitWhenFileIsNotFound(); + void itShouldFindAllBookmarks(); + void itShouldFindOnlyMatches(); + void itShouldClearResultAfterCallingTeardown(); + void itShouldFindBookmarksFromAllProfiles(); + +}; + +#endif // TESTCHROMEBOOKMARKS_H diff --git a/plasma/generic/runners/calculator/CMakeLists.txt b/plasma/generic/runners/calculator/CMakeLists.txt new file mode 100644 index 00000000..79e13705 --- /dev/null +++ b/plasma/generic/runners/calculator/CMakeLists.txt @@ -0,0 +1,35 @@ + +########### next target ############### + +macro_optional_find_package(Qalculate) +set_package_properties(Qalculate PROPERTIES DESCRIPTION "Qalculate Library" + URL "http://qalculate.sourceforge.net" + TYPE OPTIONAL + PURPOSE "Needed to enable advanced features of the calculator runner" + ) +if ( QALCULATE_FOUND ) + add_definitions(-DENABLE_QALCULATE) + + set(qalculate_engine_SRCS + qalculate_engine.cpp + ) + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS} -Wno-deprecated") +endif( QALCULATE_FOUND ) + +set(krunner_calculatorrunner_SRCS + calculatorrunner.cpp +) + +if ( QALCULATE_FOUND ) + kde4_add_plugin(krunner_calculatorrunner ${qalculate_engine_SRCS} ${krunner_calculatorrunner_SRCS}) + target_link_libraries(krunner_calculatorrunner ${QALCULATE_LIBRARIES} ${CLN_LIBRARIES} ${KDE4_SOLID_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ) +else ( QALCULATE_FOUND ) + kde4_add_plugin(krunner_calculatorrunner ${krunner_calculatorrunner_SRCS}) + target_link_libraries(krunner_calculatorrunner ${KDE4_KDEUI_LIBS} ${QT_QTSCRIPT_LIBRARY} ${KDE4_PLASMA_LIBS}) +endif ( QALCULATE_FOUND ) + +install(TARGETS krunner_calculatorrunner DESTINATION ${PLUGIN_INSTALL_DIR} ) + +########### install files ############### +install(FILES plasma-runner-calculator.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/runners/calculator/Messages.sh b/plasma/generic/runners/calculator/Messages.sh new file mode 100755 index 00000000..fa74f055 --- /dev/null +++ b/plasma/generic/runners/calculator/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_calculatorrunner.pot diff --git a/plasma/generic/runners/calculator/calculatorrunner.cpp b/plasma/generic/runners/calculator/calculatorrunner.cpp new file mode 100644 index 00000000..cb911a83 --- /dev/null +++ b/plasma/generic/runners/calculator/calculatorrunner.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2007 Barış Metin + * Copyright (C) 2006 David Faure + * Copyright (C) 2007 Richard Moore + * Copyright (C) 2010 Matteo Agostinelli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "calculatorrunner.h" + +#ifdef ENABLE_QALCULATE +#include "qalculate_engine.h" +#else +#include +#endif + +#include +#include + +#include + +CalculatorRunner::CalculatorRunner( QObject* parent, const QVariantList &args ) + : Plasma::AbstractRunner(parent, args) +{ + Q_UNUSED(args) + + #ifdef ENABLE_QALCULATE + m_engine = new QalculateEngine; + setSpeed(SlowSpeed); + #endif + + setObjectName( QLatin1String("Calculator" )); + setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File | + Plasma::RunnerContext::NetworkLocation | Plasma::RunnerContext::Executable | + Plasma::RunnerContext::ShellCommand); + + QString description = i18n("Calculates the value of :q: when :q: is made up of numbers and " + "mathematical symbols such as +, -, /, * and ^."); + addSyntax(Plasma::RunnerSyntax(":q:", description)); + addSyntax(Plasma::RunnerSyntax("=:q:", description)); + addSyntax(Plasma::RunnerSyntax(":q:=", description)); +} + +CalculatorRunner::~CalculatorRunner() +{ + #ifdef ENABLE_QALCULATE + delete m_engine; + #endif +} + +void CalculatorRunner::powSubstitutions(QString& cmd) +{ + if (cmd.contains("e+", Qt::CaseInsensitive)) { + cmd = cmd.replace("e+", "*10^", Qt::CaseInsensitive); + } + + if (cmd.contains("e-", Qt::CaseInsensitive)) { + cmd = cmd.replace("e-", "*10^-", Qt::CaseInsensitive); + } + + // the below code is scary mainly because we have to honor priority + // honor decimal numbers and parenthesis. + while (cmd.contains('^')) { + int where = cmd.indexOf('^'); + cmd = cmd.replace(where, 1, ','); + int preIndex = where - 1; + int postIndex = where + 1; + int count = 0; + + QChar decimalSymbol = KGlobal::locale()->decimalSymbol().at(0); + //avoid out of range on weird commands + preIndex = qMax(0, preIndex); + postIndex = qMin(postIndex, cmd.length()-1); + + //go backwards looking for the beginning of the number or expression + while (preIndex != 0) { + QChar current = cmd.at(preIndex); + QChar next = cmd.at(preIndex-1); + //kDebug() << "index " << preIndex << " char " << current; + if (current == ')') { + count++; + } else if (current == '(') { + count--; + } else { + if (((next <= '9' ) && (next >= '0')) || next == decimalSymbol) { + preIndex--; + continue; + } + } + if (count == 0) { + //check for functions + if (!((next <= 'z' ) && (next >= 'a'))) { + break; + } + } + preIndex--; + } + + //go forwards looking for the end of the number or expression + count = 0; + while (postIndex != cmd.size() - 1) { + QChar current=cmd.at(postIndex); + QChar next=cmd.at(postIndex + 1); + + //check for functions + if ((count == 0) && (current <= 'z') && (current >= 'a')) { + postIndex++; + continue; + } + + if (current == '(') { + count++; + } else if (current == ')') { + count--; + } else { + if (((next <= '9' ) && (next >= '0')) || next == decimalSymbol) { + postIndex++; + continue; + } + } + if (count == 0) { + break; + } + postIndex++; + } + + preIndex = qMax(0, preIndex); + postIndex = qMin(postIndex, cmd.length()); + + cmd.insert(preIndex,"pow("); + // +1 +4 == next position to the last number after we add 4 new characters pow( + cmd.insert(postIndex + 1 + 4, ')'); + //kDebug() << "from" << preIndex << " to " << postIndex << " got: " << cmd; + } +} + +void CalculatorRunner::hexSubstitutions(QString& cmd) +{ + if (cmd.contains("0x")) { + //Append +0 so that the calculator can serve also as a hex converter + cmd.append("+0"); + bool ok; + int pos = 0; + QString hex; + + while (cmd.contains("0x")) { + hex.clear(); + pos = cmd.indexOf("0x", pos); + + for (int q = 0; q < cmd.size(); q++) {//find end of hex number + QChar current = cmd[pos+q+2]; + if (((current <= '9' ) && (current >= '0')) || ((current <= 'F' ) && (current >= 'A')) || ((current <= 'f' ) && (current >= 'a'))) { //Check if valid hex sign + hex[q] = current; + } else { + break; + } + } + cmd = cmd.replace(pos, 2+hex.length(), QString::number(hex.toInt(&ok,16))); //replace hex with decimal + } + } +} + +void CalculatorRunner::userFriendlySubstitutions(QString& cmd) +{ + if (cmd.contains(KGlobal::locale()->decimalSymbol(), Qt::CaseInsensitive)) { + cmd=cmd.replace(KGlobal::locale()->decimalSymbol(), QChar('.'), Qt::CaseInsensitive); + } + + // the following substitutions are not needed with libqalculate + #ifndef ENABLE_QALCULATE + hexSubstitutions(cmd); + powSubstitutions(cmd); + + if (cmd.contains(QRegExp("\\d+and\\d+"))) { + cmd = cmd.replace(QRegExp("(\\d+)and(\\d+)"), "\\1&\\2"); + } + if (cmd.contains(QRegExp("\\d+or\\d+"))) { + cmd = cmd.replace(QRegExp("(\\d+)or(\\d+)"), "\\1|\\2"); + } + if (cmd.contains(QRegExp("\\d+xor\\d+"))) { + cmd = cmd.replace(QRegExp("(\\d+)xor(\\d+)"), "\\1^\\2"); + } + #endif +} + + +void CalculatorRunner::match(Plasma::RunnerContext &context) +{ + const QString term = context.query(); + QString cmd = term; + + //no meanless space between friendly guys: helps simplify code + cmd = cmd.trimmed().remove(' '); + + if (cmd.length() < 3) { + return; + } + + if (cmd.toLower() == "universe" || cmd.toLower() == "life") { + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::InformationalMatch); + match.setIcon(KIcon("accessories-calculator")); + match.setText("42"); + match.setData("42"); + match.setId(term); + context.addMatch(term, match); + return; + } + + bool toHex = cmd.startsWith(QLatin1String("hex=")); + bool startsWithEquals = !toHex && cmd[0] == '='; + + if (toHex || startsWithEquals) { + cmd.remove(0, cmd.indexOf('=') + 1); + } else if (cmd.endsWith('=')) { + cmd.chop(1); + } else { + bool foundDigit = false; + for (int i = 0; i < cmd.length(); ++i) { + QChar c = cmd.at(i); + if (c.isLetter()) { + // not just numbers and symbols, so we return + return; + } + if (c.isDigit()) { + foundDigit = true; + } + } + if (!foundDigit) { + return; + } + } + + if (cmd.isEmpty()) { + return; + } + + userFriendlySubstitutions(cmd); + #ifndef ENABLE_QALCULATE + cmd.replace(QRegExp("([a-zA-Z]+)"), "Math.\\1"); //needed for accessing math funktions like sin(),.... + #endif + + QString result = calculate(cmd); + if (!result.isEmpty() && result != cmd) { + if (toHex) { + result = "0x" + QString::number(result.toInt(), 16).toUpper(); + } + + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::InformationalMatch); + match.setIcon(KIcon("accessories-calculator")); + match.setText(result); + match.setData(result); + match.setId(term); + context.addMatch(term, match); + } +} + +QString CalculatorRunner::calculate(const QString& term) +{ + #ifdef ENABLE_QALCULATE + QString result; + + try { + result = m_engine->evaluate(term); + } catch(std::exception& e) { + kDebug() << "qalculate error: " << e.what(); + } + + return result.replace('.', KGlobal::locale()->decimalSymbol(), Qt::CaseInsensitive); + #else + //kDebug() << "calculating" << term; + QScriptEngine eng; + QScriptValue result = eng.evaluate(" var result ="+term+"; result"); + + if (result.isError()) { + return QString(); + } + + const QString resultString = result.toString(); + if (resultString.isEmpty()) { + return QString(); + } + + if (!resultString.contains('.')) { + return resultString; + } + + //ECMAScript has issues with the last digit in simple rational computations + //This script rounds off the last digit; see bug 167986 + QString roundedResultString = eng.evaluate("var exponent = 14-(1+Math.floor(Math.log(Math.abs(result))/Math.log(10)));\ + var order=Math.pow(10,exponent);\ + (order > 0? Math.round(result*order)/order : 0)").toString(); + + roundedResultString.replace('.', KGlobal::locale()->decimalSymbol(), Qt::CaseInsensitive); + + return roundedResultString; + #endif +} + +QMimeData * CalculatorRunner::mimeDataForMatch(const Plasma::QueryMatch *match) +{ + //kDebug(); + QMimeData *result = new QMimeData(); + result->setText(match->text()); + return result; +} + +#include "calculatorrunner.moc" diff --git a/plasma/generic/runners/calculator/calculatorrunner.h b/plasma/generic/runners/calculator/calculatorrunner.h new file mode 100644 index 00000000..f01e5288 --- /dev/null +++ b/plasma/generic/runners/calculator/calculatorrunner.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2007 Barış Metin + * Copyright (C) 2010 Matteo Agostinelli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CALCULATORRUNNER_H +#define CALCULATORRUNNER_H + +#include + +#ifdef ENABLE_QALCULATE +class QalculateEngine; +#endif + +#include + +/** + * This class evaluates the basic expressions given in the interface. + */ +class CalculatorRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + CalculatorRunner(QObject* parent, const QVariantList &args); + ~CalculatorRunner(); + + void match(Plasma::RunnerContext &context); + + protected slots: + QMimeData * mimeDataForMatch(const Plasma::QueryMatch *match); + + private: + QString calculate(const QString& term); + void userFriendlySubstitutions(QString& cmd); + void powSubstitutions(QString& cmd); + void hexSubstitutions(QString& cmd); + + #ifdef ENABLE_QALCULATE + QalculateEngine* m_engine; + #endif +}; + +K_EXPORT_PLASMA_RUNNER(calculatorrunner, CalculatorRunner) + +#endif diff --git a/plasma/generic/runners/calculator/plasma-runner-calculator.desktop b/plasma/generic/runners/calculator/plasma-runner-calculator.desktop new file mode 100644 index 00000000..84956108 --- /dev/null +++ b/plasma/generic/runners/calculator/plasma-runner-calculator.desktop @@ -0,0 +1,171 @@ +[Desktop Entry] +Name=Calculator +Name[ar]=آلة حاسبة +Name[ast]=Calculadora +Name[be@latin]=Kalkulatar +Name[bg]=Калкулатор +Name[bn]=ক্যালকুলেটর +Name[bn_IN]=ক্যালকুলেটর +Name[bs]=kalkulator +Name[ca]=Calculadora +Name[ca@valencia]=Calculadora +Name[cs]=Kalkulátor +Name[csb]=Kalkùlator +Name[da]=Regnemaskine +Name[de]=Rechner +Name[el]=Αριθμομηχανή +Name[en_GB]=Calculator +Name[eo]=Kalkulilo +Name[es]=Calculadora +Name[et]=Kalkulaator +Name[eu]=Kalkulagailua +Name[fi]=Laskin +Name[fr]=Calculatrice +Name[fy]=Rekkenmasine +Name[ga]=Áireamhán +Name[gl]=Calculadora +Name[gu]=કેલ્ક્યુલેટર +Name[he]=מחשבון +Name[hi]=गणक +Name[hne]=केलकुलेटर +Name[hr]=Kalkulator +Name[hu]=Számológép +Name[ia]=Calculator +Name[id]=Kalkulator +Name[is]=Reiknivél +Name[it]=Calcolatrice +Name[ja]=計算機 +Name[kk]=Калькулятор +Name[km]=ម៉ាស៊ីន​គិត​លេខ +Name[kn]=ಲೆಕ್ಕಿಗ (ಕಾಲ್ಕುಲೇಟರ್) +Name[ko]=계산기 +Name[ku]=Makîneya Hesaban +Name[lt]=Skaičiuotuvas +Name[lv]=Kalkulators +Name[mai]=कैलकुलेटर +Name[mk]=Калкулатор +Name[ml]=കാല്‍ക്കുലേറ്റര്‍ +Name[mr]=गणनायंत्र +Name[nb]=Kalkulator +Name[nds]=Taschenreekner +Name[nl]=Rekenmachine +Name[nn]=Kalkulator +Name[or]=କାଲକୁଲେଟର +Name[pa]=ਕੈਲਕੂਲੇਟਰ +Name[pl]=Kalkulator +Name[pt]=Calculadora +Name[pt_BR]=Calculadora +Name[ro]=Calculator +Name[ru]=Калькулятор +Name[se]=Kalkuláhtor +Name[si]=ගණනය +Name[sk]=Kalkulačka +Name[sl]=Računalo +Name[sr]=калкулатор +Name[sr@ijekavian]=калкулатор +Name[sr@ijekavianlatin]=kalkulator +Name[sr@latin]=kalkulator +Name[sv]=Miniräknare +Name[ta]=Calculator +Name[te]=గణనపరికరం +Name[tg]=Калкулятор +Name[th]=เครื่องคิดเลข +Name[tr]=Hesap Makinesi +Name[ug]=ھېسابلىغۇچ +Name[uk]=Калькулятор +Name[uz]=Kalkulyator +Name[uz@cyrillic]=Калкулятор +Name[vi]=Máy tính +Name[wa]=Carculete +Name[x-test]=xxCalculatorxx +Name[zh_CN]=计算器 +Name[zh_TW]=計算機 +Comment=Calculate expressions +Comment[ar]=احسب تعبيرات +Comment[ast]=Calcular espresiones +Comment[be@latin]=Padlik vyrazaŭ. +Comment[bg]=Изчисления +Comment[bs]=Računajte izraze +Comment[ca]=Calcula expressions +Comment[ca@valencia]=Calcula expressions +Comment[cs]=Výpočet vzorců +Comment[csb]=Przeprowôdzanié rechòwaniô +Comment[da]=Beregn udtryk +Comment[de]=Berechnungen durchführen +Comment[el]=Υπολογισμός εκφράσεων +Comment[en_GB]=Calculate expressions +Comment[eo]=Kalkuli esprimojn +Comment[es]=Calcular expresiones +Comment[et]=Avaldiste arvutamine +Comment[eu]=Kalkulatu adierazpenak +Comment[fa]=محاسبه عبارات +Comment[fi]=Suorittaa laskutoimituksia +Comment[fr]=Calcule des expressions +Comment[fy]=Utdrukkings berekkenje +Comment[ga]=Áirigh sloinn +Comment[gl]=Calcula expresións +Comment[gu]=સૂત્રોની ગણતરી કરો +Comment[he]=חישוב ביטויים +Comment[hi]=एक्सप्रेशन्स गणना करें +Comment[hne]=एक्सप्रेसन्स गनना करव +Comment[hr]=Izračunaj izraze +Comment[hu]=Kifejezéseket kezelni tudó számológép +Comment[ia]=Calcula expressiones +Comment[id]=Kalkukasi ekspresi +Comment[is]=Reikna segðir +Comment[it]=Calcola espressioni +Comment[ja]=数式を計算します +Comment[kk]=Өрнектерді есептеу +Comment[km]=គណនា​កន្សោម​​ +Comment[kn]=ಕ್ರಮೋಕ್ತಿಗಳನ್ನು (ಎಕ್ಸ್ಪ್ರೆಶನ್) ಬಿಡಿಸು +Comment[ko]=수식 계산기 +Comment[ku]=ravekirinên Hesabkirinê +Comment[lt]=Skaičiuoti išraiškas +Comment[lv]=Rēķina izteiksmes +Comment[mai]=एक्सप्रेशन्स गणना करू +Comment[mk]=Пресметувајте изрази +Comment[ml]=എക്സ്പ്രെഷനുകള്‍ കണക്കുകൂട്ടുക +Comment[mr]=एक्सप्रेशन्स गणना करा +Comment[nb]=Beregn uttrykk +Comment[nds]=Utdrück utreken +Comment[ne]=अभिव्यक्ति गणना गर्नुहोस् +Comment[nl]=Expressies berekenen +Comment[nn]=Grafisk kalkulator +Comment[or]=ଅଭିବ୍ୟକ୍ତିଗୁଡ଼ିକୁ ଗଣନା କରନ୍ତୁ +Comment[pa]=ਸਮੀਕਰਨ ਕੱਢੋ +Comment[pl]=Obliczanie wyrażeń +Comment[pt]=Calcular expressões +Comment[pt_BR]=Calcula expressões +Comment[ro]=Calculează expresii +Comment[ru]=Вычисление выражений +Comment[se]=Rehkenastte mattebihtáid +Comment[si]=ප්‍රකාශන ගණනය කරන්න +Comment[sk]=Výpočty na kalkulačke +Comment[sl]=Izračunaj izraze +Comment[sr]=Рачунајте изразе +Comment[sr@ijekavian]=Рачунајте изразе +Comment[sr@ijekavianlatin]=Računajte izraze +Comment[sr@latin]=Računajte izraze +Comment[sv]=Beräkna uttryck +Comment[ta]=Calculate expressions +Comment[te]=సమాసాలను గణించుము +Comment[tg]=Вычисление выражений +Comment[th]=คำนวณนิพจน์ +Comment[tr]=İfadeleri hesapla +Comment[ug]=ئىپادىنى ھېسابلا +Comment[uk]=Обчислення виразів +Comment[vi]=Tính biểu thức +Comment[wa]=Carcule des ratourneures +Comment[x-test]=xxCalculate expressionsxx +Comment[zh_CN]=计算表达式 +Comment[zh_TW]=計算機表示式 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=accessories-calculator +X-KDE-Library=krunner_calculatorrunner +X-KDE-PluginInfo-Author=Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=calculator +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/runners/calculator/qalculate_engine.cpp b/plasma/generic/runners/calculator/qalculate_engine.cpp new file mode 100644 index 00000000..74975267 --- /dev/null +++ b/plasma/generic/runners/calculator/qalculate_engine.cpp @@ -0,0 +1,127 @@ +/* +* Copyright 2010 Matteo Agostinelli +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2 or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "qalculate_engine.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +QAtomicInt QalculateEngine::s_counter; + +QalculateEngine::QalculateEngine(QObject* parent): + QObject(parent) +{ + m_lastResult = ""; + s_counter.ref(); + if (!CALCULATOR) { + new Calculator(); + CALCULATOR->terminateThreads(); + CALCULATOR->loadGlobalDefinitions(); + CALCULATOR->loadLocalDefinitions(); + CALCULATOR->loadGlobalCurrencies(); + CALCULATOR->loadExchangeRates(); + } +} + +QalculateEngine::~QalculateEngine() +{ + if (s_counter.deref()) { + delete CALCULATOR; + CALCULATOR = NULL; + } +} + +void QalculateEngine::updateExchangeRates() +{ + KUrl source = KUrl("http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml"); + KUrl dest = KUrl(CALCULATOR->getExchangeRatesFileName().c_str()); + + KIO::Job* getJob = KIO::file_copy(source, dest, -1, KIO::Overwrite | KIO::HideProgressInfo); + connect( getJob, SIGNAL(result(KJob*)), this, SLOT(updateResult(KJob*)) ); +} + +void QalculateEngine::updateResult(KJob* job) +{ + if (job->error()) { + kDebug() << i18n("The exchange rates could not be updated. The following error has been reported: %1",job->errorString()); + } else { + // the exchange rates have been successfully updated, now load them + CALCULATOR->loadExchangeRates(); + } +} + +QString QalculateEngine::evaluate(const QString& expression) +{ + if (expression.isEmpty()) { + return ""; + } + + QString input = expression; + QByteArray ba = input.replace(QChar(0xA3), "GBP").replace(QChar(0xA5), "JPY").replace('$', "USD").replace(QChar(0x20AC), "EUR").toLatin1(); + const char *ctext = ba.data(); + + CALCULATOR->terminateThreads(); + EvaluationOptions eo; + + eo.auto_post_conversion = POST_CONVERSION_BEST; + eo.keep_zero_units = false; + + eo.parse_options.angle_unit = ANGLE_UNIT_RADIANS; + eo.structuring = STRUCTURING_SIMPLIFY; + + MathStructure result = CALCULATOR->calculate(ctext, eo); + + PrintOptions po; + po.number_fraction_format = FRACTION_DECIMAL; + po.indicate_infinite_series = false; + po.use_all_prefixes = false; + po.use_denominator_prefix = true; + po.negative_exponents = false; + po.lower_case_e = true; + po.base_display = BASE_DISPLAY_NORMAL; + + result.format(po); + + m_lastResult = result.print(po).c_str(); + + return m_lastResult; +} + +void QalculateEngine::copyToClipboard(bool flag) +{ + Q_UNUSED(flag); + + QApplication::clipboard()->setText(m_lastResult); +} + diff --git a/plasma/generic/runners/calculator/qalculate_engine.h b/plasma/generic/runners/calculator/qalculate_engine.h new file mode 100644 index 00000000..a2264738 --- /dev/null +++ b/plasma/generic/runners/calculator/qalculate_engine.h @@ -0,0 +1,55 @@ +/* +* Copyright 2010 Matteo Agostinelli +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2 or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef QALCULATEENGINE_H +#define QALCULATEENGINE_H + +#include +#include + +class KJob; + +class QalculateEngine : public QObject +{ + Q_OBJECT +public: + QalculateEngine(QObject* parent = 0); + ~QalculateEngine(); + + QString lastResult() const { return m_lastResult; } + +public slots: + QString evaluate(const QString& expression); + void updateExchangeRates(); + + void copyToClipboard(bool flag = true); + +protected slots: + void updateResult(KJob*); + +signals: + void resultReady(const QString&); + void formattedResultReady(const QString&); + +private: + QString m_lastResult; + static QAtomicInt s_counter; +}; + +#endif // QALCULATEENGINE_H diff --git a/plasma/generic/runners/kill/CMakeLists.txt b/plasma/generic/runners/kill/CMakeLists.txt new file mode 100644 index 00000000..20d300cb --- /dev/null +++ b/plasma/generic/runners/kill/CMakeLists.txt @@ -0,0 +1,28 @@ +project(plasma-runner-kill) + +set(krunner_kill_SRCS killrunner.cpp) + +set(kcm_krunner_kill_SRCS + killrunner_config.cpp +) + +kde4_add_ui_files(kcm_krunner_kill_SRCS killrunner_config.ui) +kde4_add_plugin(kcm_krunner_kill ${kcm_krunner_kill_SRCS}) +target_link_libraries(kcm_krunner_kill + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KCMUTILS_LIBS} + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + ) + +kde4_add_plugin(krunner_kill ${krunner_kill_SRCS}) +target_link_libraries(krunner_kill + ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} processcore) +add_dependencies(krunner_kill kcm_krunner_kill) + +install(TARGETS krunner_kill kcm_krunner_kill + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-runner-kill.desktop plasma-runner-kill_config.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/runners/kill/Messages.sh b/plasma/generic/runners/kill/Messages.sh new file mode 100644 index 00000000..e405d4f6 --- /dev/null +++ b/plasma/generic/runners/kill/Messages.sh @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma_runner_kill.pot diff --git a/plasma/generic/runners/kill/TODO b/plasma/generic/runners/kill/TODO new file mode 100644 index 00000000..e69de29b diff --git a/plasma/generic/runners/kill/killrunner.cpp b/plasma/generic/runners/kill/killrunner.cpp new file mode 100644 index 00000000..f9d9badb --- /dev/null +++ b/plasma/generic/runners/kill/killrunner.cpp @@ -0,0 +1,223 @@ +/* Copyright 2009 Jan Gerrit Marker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "killrunner.h" + +#include + +#include +#include +#include +#include +#include + +#include "ksysguard/processcore/processes.h" +#include "ksysguard/processcore/process.h" + +#include "killrunner_config.h" + +KillRunner::KillRunner(QObject *parent, const QVariantList& args) + : Plasma::AbstractRunner(parent, args), + m_processes(0) +{ + Q_UNUSED(args); + setObjectName( QLatin1String("Kill Runner") ); + reloadConfiguration(); + + connect(this, SIGNAL(prepare()), this, SLOT(prep())); + connect(this, SIGNAL(teardown()), this, SLOT(cleanup())); + + m_delayedCleanupTimer.setInterval(50); + m_delayedCleanupTimer.setSingleShot(true); + connect(&m_delayedCleanupTimer, SIGNAL(timeout()), this, SLOT(cleanup())); +} + +KillRunner::~KillRunner() +{ +} + + +void KillRunner::reloadConfiguration() +{ + KConfigGroup grp = config(); + m_triggerWord.clear(); + if (grp.readEntry(CONFIG_USE_TRIGGERWORD, true)) { + m_triggerWord = grp.readEntry(CONFIG_TRIGGERWORD, i18n("kill")) + ' '; + } + + m_sorting = (KillRunnerConfig::Sort) grp.readEntry(CONFIG_SORTING, 0); + QList syntaxes; + syntaxes << Plasma::RunnerSyntax(m_triggerWord + ":q:", + i18n("Terminate running applications whose names match the query.")); + setSyntaxes(syntaxes); +} + +void KillRunner::prep() +{ + m_delayedCleanupTimer.stop(); +} + +void KillRunner::cleanup() +{ + if (!m_processes) { + return; + } + + if (m_prepLock.tryLockForWrite()) { + delete m_processes; + m_processes = 0; + + m_prepLock.unlock(); + } else { + m_delayedCleanupTimer.stop(); + } +} + +void KillRunner::match(Plasma::RunnerContext &context) +{ + QString term = context.query(); + const bool hasTrigger = !m_triggerWord.isEmpty(); + if (hasTrigger && !term.startsWith(m_triggerWord, Qt::CaseInsensitive)) { + return; + } + + m_prepLock.lockForRead(); + if (!m_processes) { + m_prepLock.unlock(); + m_prepLock.lockForWrite(); + if (!m_processes) { + suspendMatching(true); + m_processes = new KSysGuard::Processes(); + m_processes->updateAllProcesses(); + suspendMatching(false); + } + } + m_prepLock.unlock(); + + term = term.right(term.length() - m_triggerWord.length()); + + if (term.length() < 2) { + return; + } + + QList matches; + const QList processlist = m_processes->getAllProcesses(); + foreach (const KSysGuard::Process *process, processlist) { + if (!context.isValid()) { + return; + } + + const QString name = process->name; + if (!name.contains(term, Qt::CaseInsensitive)) { + //Process doesn't match the search term + continue; + } + + const quint64 pid = process->pid; + const qlonglong uid = process->uid; + const QString user = getUserName(uid); + + QVariantList data; + data << pid << user; + + Plasma::QueryMatch match(this); + match.setText(i18n("Terminate %1", name)); + match.setSubtext(i18n("Process ID: %1\nRunning as user: %2", QString::number(pid), user)); + match.setIcon(KIcon("application-exit")); + match.setData(data); + match.setId(name); + + // Set the relevance + switch (m_sorting) { + case KillRunnerConfig::CPU: + match.setRelevance((process->userUsage + process->sysUsage) / 100); + break; + case KillRunnerConfig::CPUI: + match.setRelevance(1 - (process->userUsage + process->sysUsage) / 100); + break; + case KillRunnerConfig::NONE: + match.setRelevance(name.compare(term, Qt::CaseInsensitive) == 0 ? 1 : 9); + break; + } + + matches << match; + } + + kDebug() << "match count is" << matches.count(); + context.addMatches(term, matches); +} + +void KillRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(context) + + QVariantList data = match.data().value(); + quint64 pid = data[0].toUInt(); + QString user = data[1].toString(); + + int signal; + if (match.selectedAction() != NULL) { + signal = match.selectedAction()->data().toInt(); + } else { + signal = 9; //default: SIGKILL + } + + QStringList args; + args << QString("-%1").arg(signal) << QString("%1").arg(pid); + KProcess *process = new KProcess(this); + int returnCode = process->execute("kill", args); + + if (returnCode == 0) + { + return; + } + + KAuth::Action killAction = QString("org.kde.ksysguard.processlisthelper.sendsignal"); + killAction.setHelperID("org.kde.ksysguard.processlisthelper"); + killAction.addArgument("pid0", pid); + killAction.addArgument("pidcount", 1); + killAction.addArgument("signal", signal); + killAction.execute(); +} + +QList KillRunner::actionsForMatch(const Plasma::QueryMatch &match) +{ + Q_UNUSED(match) + + QList ret; + + if (!action("SIGTERM")) { + (addAction("SIGTERM", KIcon("application-exit"), i18n("Send SIGTERM")))->setData(15); + (addAction("SIGKILL", KIcon("process-stop"), i18n("Send SIGKILL")))->setData(9); + } + ret << action("SIGTERM") << action("SIGKILL"); + return ret; +} + +QString KillRunner::getUserName(qlonglong uid) +{ + KUser user(uid); + if (user.isValid()) { + return user.loginName(); + } + kDebug() << QString("No user with UID %1 was found").arg(uid); + return "root";//No user with UID uid was found, so root is used +} + +#include "killrunner.moc" diff --git a/plasma/generic/runners/kill/killrunner.h b/plasma/generic/runners/kill/killrunner.h new file mode 100644 index 00000000..e843be05 --- /dev/null +++ b/plasma/generic/runners/kill/killrunner.h @@ -0,0 +1,77 @@ +/* Copyright 2009 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef KILLRUNNER_H +#define KILLRUNNER_H + +#include +#include + +#include + +#include "killrunner_config.h" +class QAction; + +namespace KSysGuard +{ + class Processes; + class Process; +} + +class KillRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + +public: + KillRunner(QObject *parent, const QVariantList& args); + ~KillRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match); + QList actionsForMatch(const Plasma::QueryMatch &match); + void reloadConfiguration(); + +private Q_SLOTS: + void prep(); + void cleanup(); + +private: + /** @param uid the uid of the user + * @return the username of the user with the UID uid + */ + QString getUserName(qlonglong uid); + + /** The trigger word */ + QString m_triggerWord; + + /** How to sort */ + KillRunnerConfig::Sort m_sorting; + + /** process lister */ + KSysGuard::Processes *m_processes; + + /** lock for initializing m_processes */ + QReadWriteLock m_prepLock; + + /** timer for retrying the cleanup due to lock contention */ + QTimer m_delayedCleanupTimer; +}; +K_EXPORT_PLASMA_RUNNER(kill, KillRunner) + +#endif diff --git a/plasma/generic/runners/kill/killrunner_config.cpp b/plasma/generic/runners/kill/killrunner_config.cpp new file mode 100644 index 00000000..94fe7a74 --- /dev/null +++ b/plasma/generic/runners/kill/killrunner_config.cpp @@ -0,0 +1,90 @@ +/* Copyright 2009 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +//Project-Includes +#include "killrunner_config.h" +//KDE-Includes +#include + +K_EXPORT_RUNNER_CONFIG(kill, KillRunnerConfig) + +KillRunnerConfigForm::KillRunnerConfigForm(QWidget* parent) : QWidget(parent) +{ + setupUi(this); +} + +KillRunnerConfig::KillRunnerConfig(QWidget* parent, const QVariantList& args) : + KCModule(ConfigFactory::componentData(), parent, args) +{ + m_ui = new KillRunnerConfigForm(this); + + QGridLayout* layout = new QGridLayout(this); + layout->addWidget(m_ui, 0, 0); + + m_ui->sorting->addItem(i18n("CPU usage"), CPU); + m_ui->sorting->addItem(i18n("inverted CPU usage"), CPUI); + m_ui->sorting->addItem(i18n("nothing"), NONE); + + connect(m_ui->useTriggerWord,SIGNAL(stateChanged(int)),this,SLOT(changed())); + connect(m_ui->triggerWord,SIGNAL(textChanged(QString)),this,SLOT(changed())); + connect(m_ui->sorting,SIGNAL(currentIndexChanged(int)),this,SLOT(changed())); + + load(); +} + +void KillRunnerConfig::load() +{ + KCModule::load(); + + KSharedConfig::Ptr cfg = KSharedConfig::openConfig("krunnerrc"); + KConfigGroup grp = cfg->group("Runners"); + grp = KConfigGroup(&grp, "Kill Runner"); + + m_ui->useTriggerWord->setChecked(grp.readEntry(CONFIG_USE_TRIGGERWORD,true)); + m_ui->triggerWord->setText(grp.readEntry(CONFIG_TRIGGERWORD,i18n("kill"))); + m_ui->sorting->setCurrentIndex(m_ui->sorting->findData(grp.readEntry(CONFIG_SORTING, (int) NONE))); + + emit changed(false); +} + +void KillRunnerConfig::save() +{ + KCModule::save(); + + KSharedConfig::Ptr cfg = KSharedConfig::openConfig("krunnerrc"); + KConfigGroup grp = cfg->group("Runners"); + grp = KConfigGroup(&grp, "Kill Runner"); + + grp.writeEntry(CONFIG_USE_TRIGGERWORD,m_ui->useTriggerWord->isChecked()); + grp.writeEntry(CONFIG_TRIGGERWORD,m_ui->triggerWord->text()); + grp.writeEntry(CONFIG_SORTING,m_ui->sorting->itemData(m_ui->sorting->currentIndex())); + + emit changed(false); +} + +void KillRunnerConfig::defaults() +{ + KCModule::defaults(); + + m_ui->useTriggerWord->setChecked(true); + m_ui->triggerWord->setText(i18n("kill")); + m_ui->sorting->setCurrentIndex(m_ui->sorting->findData((int) NONE)); + + emit changed(true); +} diff --git a/plasma/generic/runners/kill/killrunner_config.h b/plasma/generic/runners/kill/killrunner_config.h new file mode 100644 index 00000000..3e015c2f --- /dev/null +++ b/plasma/generic/runners/kill/killrunner_config.h @@ -0,0 +1,59 @@ +/* Copyright 2009 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef KILLRUNNERCONFIG_H +#define KILLRUNNERCONFIG_H + +//Project-Includes +#include "ui_killrunner_config.h" +//KDE-Includes +#include +//Qt + +static const char CONFIG_USE_TRIGGERWORD[] = "useTriggerWord"; +static const char CONFIG_TRIGGERWORD[] = "triggerWord"; +static const char CONFIG_SORTING[] = "sorting"; + +class KillRunnerConfigForm : public QWidget, public Ui::KillRunnerConfigUi +{ + Q_OBJECT + +public: + explicit KillRunnerConfigForm(QWidget* parent); +}; + +class KillRunnerConfig : public KCModule +{ + Q_OBJECT + +public: + explicit KillRunnerConfig(QWidget* parent = 0, const QVariantList& args = QVariantList()); + + /** Possibilities to sort */ + enum Sort {NONE = 0, CPU, CPUI}; + +public slots: + void save(); + void load(); + void defaults(); + +private: + KillRunnerConfigForm* m_ui; +}; +#endif diff --git a/plasma/generic/runners/kill/killrunner_config.ui b/plasma/generic/runners/kill/killrunner_config.ui new file mode 100644 index 00000000..2eda8bac --- /dev/null +++ b/plasma/generic/runners/kill/killrunner_config.ui @@ -0,0 +1,129 @@ + + + Jan Gerrit Marker + KillRunnerConfigUi + + + + 0 + 0 + 308 + 252 + + + + + + + Kill Applications Config + + + + + + true + + + &Use trigger word + + + true + + + + + + + + + &Trigger word: + + + triggerWord + + + + + + + true + + + + + + + + + + + &Sort by + + + sorting + + + + + + + It is not sure, that this will take effect + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+ + KComboBox + QComboBox +
kcombobox.h
+
+
+ + useTriggerWord + triggerWord + + + + + useTriggerWord + toggled(bool) + triggerWord + setEnabled(bool) + + + 97 + 49 + + + 122 + 79 + + + + +
diff --git a/plasma/generic/runners/kill/plasma-runner-kill.desktop b/plasma/generic/runners/kill/plasma-runner-kill.desktop new file mode 100644 index 00000000..1f6f9ffb --- /dev/null +++ b/plasma/generic/runners/kill/plasma-runner-kill.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +Name=Terminate Applications +Name[ar]=أنهِ تطبيقات +Name[ast]=Zarrar aplicaciones +Name[bg]=Прекъсване на програми +Name[bn]=অ্যাপলিকেশন থামাও +Name[bs]=obustavljanje programa +Name[ca]=Finalitza aplicacions +Name[ca@valencia]=Finalitza aplicacions +Name[cs]=Ukončit aplikace +Name[csb]=Zamëkô apliakcëje +Name[da]=Afslut programmer +Name[de]=Programme beenden +Name[el]=Τερματισμός εφαρμογών +Name[en_GB]=Terminate Applications +Name[eo]=Terminalaj Aplikaĵoj +Name[es]=Cerrar aplicaciones +Name[et]=Rakenduste töö lõpetamine +Name[eu]=Amaitu aplikazioak +Name[fa]=پایان دادن به برنامه‌ها +Name[fi]=Lopeta sovellukset +Name[fr]=Terminer des applications +Name[fy]=Programma's ôfbrekke +Name[ga]=Scoir ó Fheidhmchláir +Name[gl]=Terminar programas +Name[gu]=કાર્યક્રમો બંધ કરો +Name[he]=סיום פעולת יישומים +Name[hi]=अनुप्रयोग खतम करो +Name[hr]=Prekini aplikacije +Name[hu]=Program félbeszakítása +Name[ia]=Termina applicationes +Name[id]=Hentikan Aplikasi +Name[is]=Loka forritum +Name[it]=Termina applicazioni +Name[ja]=アプリケーションを終了 +Name[kk]=Қолданбалары аяқтау +Name[km]=កម្មវិធី​ស្ថានីយ +Name[kn]=ಅನ್ವಯಗಳನ್ನು ಅಂತ್ಯಗೊಳಿಸು +Name[ko]=프로그램 끝내기 +Name[lt]=Nutraukti programas +Name[lv]=Pārtraukt programmas +Name[mk]=Запирање на апликации +Name[ml]=പ്രയോഗങ്ങളെ ഇല്ലാതാക്കുക +Name[mr]=अनुप्रयोग बंद करा +Name[nb]=Avslutt programmer +Name[nds]=Programmen utmaken +Name[nl]=Toepassingen afsluiten +Name[nn]=Avslutt program +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਖਤਮ ਕਰੋ +Name[pl]=Zakańczanie programów +Name[pt]=Terminar as Aplicações +Name[pt_BR]=Terminar aplicativos +Name[ro]=Termină aplicații +Name[ru]=Завершение приложений +Name[si]=යෙදුම් මර්‍ධනය +Name[sk]=Ukončenie aplikácií +Name[sl]=Uničenje programov +Name[sr]=обустављање програма +Name[sr@ijekavian]=обустављање програма +Name[sr@ijekavianlatin]=obustavljanje programa +Name[sr@latin]=obustavljanje programa +Name[sv]=Avsluta program +Name[tg]=Барномаҳои терминал +Name[th]=ยุติการทำงานของโปรแกรม +Name[tr]=Uygulamaları Bitir +Name[ug]=پروگراممىلارنى توختات +Name[uk]=Переривання програм +Name[wa]=Fé fini des programes +Name[x-test]=xxTerminate Applicationsxx +Name[zh_CN]=终止程序 +Name[zh_TW]=終端機應用程式 +Comment=Stop applications that are currently running +Comment[ar]=أوقف برامجاً قيد الشغيل حالياً +Comment[ast]=Parar aplicaciones que tan executándose +Comment[bg]=Спиране на работещи в момента програми +Comment[bs]=Zaustavlja programe trenutno u pogonu +Comment[ca]=Atura aplicacions que estan actualment en execució +Comment[ca@valencia]=Para aplicacions que estan actualment en execució +Comment[cs]=Ukončit aktuálně spuštěné aplikace +Comment[csb]=Zamëkô prawie robiącé aplikacëje +Comment[da]=Stop programmer der kører i øjeblikket +Comment[de]=Gerade laufende Anwendungen beenden +Comment[el]=Σταμάτημα των εκτελούμενων εργασιών +Comment[en_GB]=Stop applications that are currently running +Comment[es]=Parar aplicaciones que se están ejecutando +Comment[et]=Töötavate rakenduste töö lõpetamine +Comment[eu]=Gelditu une honetan exekutatzen ari diren aplikazioak +Comment[fi]=Pysäytä sovellukset, joita parhaillaan suoritetaan +Comment[fr]=Arrête des applications en cours d'exécution +Comment[fy]=Lit applikaasje dy't no rinne ophâlde +Comment[ga]=Scoir ó fheidhmchláir atá ag rith faoi láthair +Comment[gl]=Detén programas que están a executarse +Comment[he]=עצירת יישומים הפועלים כעת +Comment[hr]=Zaustavi aplikacije koje su trenutno pokrenute +Comment[hu]=Jelenleg futó alkalmazások leállítása +Comment[ia]=Stoppa applicationes que il es currentemente executante +Comment[id]=Stop aplikasi yang saat ini tengah berjalan +Comment[is]=Stöðva forrit sem eru keyrandi +Comment[it]=Ferma le applicazioni attualmente in esecuzione +Comment[ja]=実行中のアプリケーションを停止します +Comment[kk]=Орындалып жатқан қолданбаларды тоқтату +Comment[km]=បញ្ឈប់​កម្មវិធី​ដែលបច្ចុប្បន្ន​កំពុង​តែ​រត់ +Comment[kn]=ಪ್ರಸ್ತುತ ಚಾಲನೆಯಲ್ಲಿರುವ ಅನ್ವಯಗಳನ್ನು ನಿಲ್ಲಿಸು +Comment[ko]=현재 실행 중인 프로그램을 끝냅니다 +Comment[lt]=Sustabdo programas, kurios šiuo metu veikia +Comment[lv]=Apturēt šobrīd darbojošās programmas +Comment[mk]=Ги запира апликациите што моментално се активни +Comment[ml]=ഇപ്പോള്‍ പ്രവര്‍ത്തിയ്ക്കുന്ന പ്രയോഗങ്ങള്‍ നിര്‍ത്തുക +Comment[mr]=चालू असणारे अनुप्रयोग बंद करा +Comment[nb]=Stopp programmer som kjører nå +Comment[nds]=Opstunns lopen Programmen utmaken +Comment[nl]=Beëindig toepassingen die momenteel draaien +Comment[nn]=Stop program som køyrer +Comment[pa]=ਐਪਲੀਕੇਸ਼ਨਾਂ ਰੋਕੋ, ਜੋ ਇਸ ਸਮੇਂ ਚੱਲ ਰਹੀਆਂ ਹਨ +Comment[pl]=Zatrzymanie programów, które są obecnie uruchomione +Comment[pt]=Parar as aplicações actualmente em execução +Comment[pt_BR]=Interrompe aplicativos em execução +Comment[ro]=Oprește aplicații ce rulează momentan +Comment[ru]=Завершение работы запущенных в данный момент приложений +Comment[si]=දැනට ක්‍රියාකරන යෙදුම් නැවතීම +Comment[sk]=Zastavenie práve bežiacich aplikácií +Comment[sl]=Zaustavite trenutno zagnane programe +Comment[sr]=Зауставља програме тренутно у погону +Comment[sr@ijekavian]=Зауставља програме тренутно у погону +Comment[sr@ijekavianlatin]=Zaustavlja programe trenutno u pogonu +Comment[sr@latin]=Zaustavlja programe trenutno u pogonu +Comment[sv]=Stoppa program som för närvarande kör +Comment[tg]=Қатъ кардани барномаҳои ҷорӣ +Comment[th]=หยุดการทำงานของโปรแกรมที่กำลังทำงานอยู่ในปัจจุบัน +Comment[tr]=Şu anda çalışan uygulamaları durdur +Comment[ug]=نۆۋەتتە ئىجرا بولۇۋاتقان پروگراممىلارنى توختىتىدۇ +Comment[uk]=Завершує роботу запущених програм +Comment[wa]=Arester des programes k' ovrèt pol moumint +Comment[x-test]=xxStop applications that are currently runningxx +Comment[zh_CN]=停止正在运行的应用程序 +Comment[zh_TW]=停止目前執行中的應用程式 +Icon=application-exit + +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +X-KDE-Library=krunner_kill +X-KDE-PluginInfo-Author=Jan Gerrit Marker +X-KDE-PluginInfo-Email=jangerrit@weiler-marker.com +X-KDE-PluginInfo-Name=Kill Runner +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/runners/kill/plasma-runner-kill_config.desktop b/plasma/generic/runners/kill/plasma-runner-kill_config.desktop new file mode 100644 index 00000000..b78523a3 --- /dev/null +++ b/plasma/generic/runners/kill/plasma-runner-kill_config.desktop @@ -0,0 +1,78 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KCModule + +X-KDE-Library=kcm_krunner_kill +X-KDE-ParentComponents=Kill Runner +X-KDE-PluginKeyword=kcm_krunner_kill + +Name=Kill Applications +Name[ar]=اقتل تطبيقات +Name[ast]=Matar aplicaciones +Name[bg]=Убиване на програми +Name[bn]=অ্যাপলিকেশন বন্ধ করো +Name[bs]=Obustavljanje programa +Name[ca]=Mata aplicacions +Name[ca@valencia]=Mata aplicacions +Name[cs]=Zabít aplikace +Name[csb]=Zamkni apliakcëjã +Name[da]=Dræb programmer +Name[de]=Programme abschießen +Name[el]=Τερματισμός εφαρμογών +Name[en_GB]=Kill Applications +Name[eo]=Mortigi aplikaĵon +Name[es]=Matar aplicaciones +Name[et]=Rakenduste tapmine +Name[eu]=Hil aplikazioak +Name[fi]=Tuhoa sovellukset +Name[fr]=Tuer des applications +Name[fy]=Programma's ôfbrekke +Name[ga]=Maraigh Feidhmchláir +Name[gl]=Matar programas +Name[gu]=કાર્યક્રમો બંધ કરો +Name[he]=הריגת יישומים +Name[hi]=अनुप्रयोग खतम करो +Name[hr]=Uništi aplikacije +Name[hu]=Alkalmazás kilövése +Name[ia]=Occide applicationes +Name[id]=Matikan Aplikasi +Name[is]=Drepa forrit +Name[it]=Termina applicazioni +Name[ja]=アプリケーションを強制終了 +Name[kk]=Қолданбалары құрту +Name[km]=បញ្ឈប់​កម្មវិធី +Name[kn]=ಅನ್ವಯಗಳನ್ನು ಅಂತ್ಯಗೊಳಿಸು +Name[ko]=프로그램 죽이기 +Name[lt]=Užverti programas +Name[lv]=Nokaut programmas +Name[mk]=Запирање на апликации +Name[ml]=പ്രയോഗങ്ങളെ കൊല്ലുക +Name[mr]=केडीई अनुप्रयोग +Name[nb]=Drep programmer +Name[nds]=Programmen afscheten +Name[nl]=Programma's afbreken +Name[nn]=Drep program +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਖਤਮ ਕਰੋ +Name[pl]=Niszczenie programów +Name[pt]=Matar as Aplicações +Name[pt_BR]=Matar aplicativos +Name[ro]=Omoară aplicații +Name[ru]=Завершение приложений +Name[si]=KDE යෙදුම් +Name[sk]=Zabiť aplikácie +Name[sl]=Uniči programe +Name[sr]=Обустављање програма +Name[sr@ijekavian]=Обустављање програма +Name[sr@ijekavianlatin]=Obustavljanje programa +Name[sr@latin]=Obustavljanje programa +Name[sv]=Döda program +Name[tg]=Барномаҳои KDE +Name[th]=ฆ่าโพรเซสของโปรแกรม +Name[tr]=Uygulamaları Sonlandır +Name[ug]=پروگراممىنى ئاخىرلاشتۇر +Name[uk]=Припинення роботи програм +Name[vi]=Tắt ứng dụng +Name[wa]=Touwer des programes +Name[x-test]=xxKill Applicationsxx +Name[zh_CN]=杀死程序 +Name[zh_TW]=砍掉應用程式 diff --git a/plasma/generic/runners/locations/CMakeLists.txt b/plasma/generic/runners/locations/CMakeLists.txt new file mode 100644 index 00000000..4cb3d2a5 --- /dev/null +++ b/plasma/generic/runners/locations/CMakeLists.txt @@ -0,0 +1,11 @@ +set(krunner_locations_SRCS + locationrunner.cpp +) + +kde4_add_plugin(krunner_locations ${krunner_locations_SRCS}) +target_link_libraries(krunner_locations ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) + +install(TARGETS krunner_locations DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install(FILES plasma-runner-locations.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/locations/Messages.sh b/plasma/generic/runners/locations/Messages.sh new file mode 100755 index 00000000..68cd7205 --- /dev/null +++ b/plasma/generic/runners/locations/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_locations.pot diff --git a/plasma/generic/runners/locations/locationrunner.cpp b/plasma/generic/runners/locations/locationrunner.cpp new file mode 100644 index 00000000..c13dfc18 --- /dev/null +++ b/plasma/generic/runners/locations/locationrunner.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2007 Teemu Rytilahti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "locationrunner.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +LocationsRunner::LocationsRunner(QObject *parent, const QVariantList& args) + : Plasma::AbstractRunner(parent, args) +{ + Q_UNUSED(args); + // set the name shown after the result in krunner window + setObjectName(QLatin1String("Locations")); + setIgnoredTypes(Plasma::RunnerContext::Executable | Plasma::RunnerContext::ShellCommand); + addSyntax(Plasma::RunnerSyntax(":q:", + i18n("Finds local directories and files, network locations and Internet sites with paths matching :q:."))); +} + +LocationsRunner::~LocationsRunner() +{ +} + +void LocationsRunner::match(Plasma::RunnerContext &context) +{ + QString term = context.query(); + Plasma::RunnerContext::Type type = context.type(); + + if (type == Plasma::RunnerContext::Directory || type == Plasma::RunnerContext::File) { + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setText(i18n("Open %1", term)); + + if (type == Plasma::RunnerContext::File) { + match.setIcon(KIcon(KMimeType::iconNameForUrl(KUrl(term)))); + } else { + match.setIcon(KIcon("system-file-manager")); + } + + match.setRelevance(1); + match.setData(term); + match.setType(Plasma::QueryMatch::ExactMatch); + + if (type == Plasma::RunnerContext::Directory) { + match.setId("opendir"); + } else { + match.setId("openfile"); + } + context.addMatch(term, match); + } else if (type == Plasma::RunnerContext::Help) { + //kDebug() << "Locations matching because of" << type; + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setText(i18n("Open %1", term)); + match.setIcon(KIcon("system-help")); + match.setRelevance(1); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setId("help"); + context.addMatch(term, match); + } else if (type == Plasma::RunnerContext::NetworkLocation || type == Plasma::RunnerContext::UnknownType) { + const bool filtered = KUriFilter::self()->filterUri(term, QStringList() << QLatin1String("kshorturifilter")); + + if (!filtered) { + return; + } + + KUrl url(term); + + if (!KProtocolInfo::isKnownProtocol(url.protocol())) { + return; + } + + Plasma::QueryMatch match(this); + match.setText(i18n("Go to %1", url.prettyUrl())); + match.setIcon(KIcon(KProtocolInfo::icon(url.protocol()))); + match.setData(url.url()); + + if (KProtocolInfo::isHelperProtocol(url.protocol())) { + //kDebug() << "helper protocol" << url.protocol() <<"call external application" ; + if (url.protocol() == "mailto") { + match.setText(i18n("Send email to %1",url.path())); + } else { + match.setText(i18n("Launch with %1", KProtocolInfo::exec(url.protocol()))); + } + } else { + //kDebug() << "protocol managed by browser" << url.protocol(); + match.setText(i18n("Go to %1", url.prettyUrl())); + } + + if (type == Plasma::RunnerContext::UnknownType) { + match.setId("openunknown"); + match.setRelevance(0.5); + match.setType(Plasma::QueryMatch::PossibleMatch); + } else { + match.setId("opennetwork"); + match.setRelevance(0.7); + match.setType(Plasma::QueryMatch::ExactMatch); + } + + context.addMatch(term, match); + } +} + +void LocationsRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(match) + + QString location = context.query(); + + if (location.isEmpty()) { + return; + } + + //kDebug() << "command: " << context.query(); + //kDebug() << "url: " << location << data; + + KUrl urlToRun(KUriFilter::self()->filteredUri(location, QStringList() << QLatin1String("kshorturifilter"))); + + new KRun(urlToRun, 0); +} + +QMimeData * LocationsRunner::mimeDataForMatch(const Plasma::QueryMatch *match) +{ + const QString data = match->data().toString(); + if (!data.isEmpty()) { + KUrl url(data); + QList list; + list << url; + QMimeData *result = new QMimeData(); + result->setUrls(list); + result->setText(data); + return result; + } + + return 0; +} + + +#include "locationrunner.moc" diff --git a/plasma/generic/runners/locations/locationrunner.h b/plasma/generic/runners/locations/locationrunner.h new file mode 100644 index 00000000..8ab35954 --- /dev/null +++ b/plasma/generic/runners/locations/locationrunner.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef LOCATIONRUNNER_H +#define LOCATIONRUNNER_H + +#include + +class LocationsRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + LocationsRunner(QObject *parent, const QVariantList& args); + ~LocationsRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + + protected Q_SLOTS: + QMimeData * mimeDataForMatch(const Plasma::QueryMatch *match); +}; + +K_EXPORT_PLASMA_RUNNER(locations, LocationsRunner) + +#endif diff --git a/plasma/generic/runners/locations/plasma-runner-locations.desktop b/plasma/generic/runners/locations/plasma-runner-locations.desktop new file mode 100644 index 00000000..88afd224 --- /dev/null +++ b/plasma/generic/runners/locations/plasma-runner-locations.desktop @@ -0,0 +1,165 @@ +[Desktop Entry] +Name=Locations +Name[ar]=مواقع +Name[ast]=Llugares +Name[be@latin]=Miescy +Name[bg]=Местоположения +Name[bn]=অবস্থান +Name[bn_IN]=অবস্থান +Name[bs]=lokacije +Name[ca]=Ubicacions +Name[ca@valencia]=Ubicacions +Name[cs]=Umístění +Name[csb]=Dzejania +Name[da]=Placeringer +Name[de]=Orte +Name[el]=Τοποθεσίες +Name[en_GB]=Locations +Name[eo]=Lokoj +Name[es]=Ubicaciones +Name[et]=Asukohad +Name[eu]=Kokalekuak +Name[fi]=Sijainnit +Name[fr]=Emplacements +Name[fy]=Lokaasjes +Name[ga]=Áiteanna +Name[gl]=Lugares +Name[gu]=સ્થળો +Name[he]=מיקומים +Name[hi]=स्थान +Name[hne]=जगह +Name[hr]=Lokacije +Name[hu]=Helyek +Name[ia]=Locationes +Name[id]=Lokasi +Name[is]=Staðsetningar +Name[it]=Posizioni +Name[ja]=場所 +Name[kk]=Адрестер +Name[km]=ទីតាំង +Name[kn]=ಸ್ಥಳಗಳು +Name[ko]=위치 +Name[ku]=Cih +Name[lt]=Vietos +Name[lv]=Vietas +Name[mk]=Локации +Name[ml]=സ്ഥാനങ്ങള്‍ +Name[mr]=स्थान +Name[nb]=Steder +Name[nds]=Steden +Name[nl]=Locaties +Name[nn]=Adresser +Name[or]=ସ୍ଥାନଗୁଡ଼ିକ +Name[pa]=ਟਿਕਾਣੇ +Name[pl]=Położenia +Name[pt]=Locais +Name[pt_BR]=Localizações +Name[ro]=Locații +Name[ru]=Расположения +Name[si]=පිහිටුම +Name[sk]=Miesta +Name[sl]=Mesta +Name[sr]=локације +Name[sr@ijekavian]=локације +Name[sr@ijekavianlatin]=lokacije +Name[sr@latin]=lokacije +Name[sv]=Platser +Name[ta]=Locations +Name[te]=స్థానములు +Name[tg]=Ҷойгиршавӣ +Name[th]=ตำแหน่งที่อยู่ +Name[tr]=Konumlar +Name[ug]=ئورنى +Name[uk]=Адреси +Name[vi]=Vị trí +Name[wa]=Eplaeçmints +Name[x-test]=xxLocationsxx +Name[zh_CN]=位置 +Name[zh_TW]=位置 +Comment=File and URL opener +Comment[ar]=فاتح الملفات و العناوين +Comment[ast]=Visor de ficheros y URL +Comment[be@latin]=Adčynieńnie fajłaŭ i adrasoŭ +Comment[bg]=Отваряне на файлове и адреси +Comment[bn_IN]=ফাইল ও URL প্রদর্শক +Comment[bs]=Otvarač datoteka i URL‑ova +Comment[ca]=Obre fitxers i URL +Comment[ca@valencia]=Obri fitxers i URL +Comment[cs]=Otvírač souborů a URL +Comment[csb]=Òtmëkôcz lopków ë adresół URL +Comment[da]=Fil- og URL-åbner +Comment[de]=Öffnet Dateien und Adressen +Comment[el]=Άνοιγμα αρχείων και URL +Comment[en_GB]=File and URL opener +Comment[eo]=Malfermas dosierojn kaj adresojn +Comment[es]=Visor de archivos y URL +Comment[et]=Faili ja URL-i avaja +Comment[eu]=Fitxategiak eta URLak irekitzea +Comment[fi]=Tiedostojen ja osoitteiden avaaja +Comment[fr]=Ouverture de fichiers et d'URL +Comment[fy]=Triem en URL-adres iepener +Comment[ga]=Osclóir Comhad agus URLanna +Comment[gl]=Abre ficheiros e URL +Comment[gu]=ફાઇલ અને URL ખોલનાર +Comment[he]=פותח קבצים וכתובות +Comment[hi]=फ़ाइल व यूआरएल खोलने वाला +Comment[hne]=फाइल अउ यूआरएल खोलइया +Comment[hr]=Otvarač datoteka i URL-ova +Comment[hu]=Fájlmegnyitó +Comment[ia]=Aperitor de file e de URL +Comment[id]=Pembuka Berkas dan URL +Comment[is]=Skráa og slóða opnun +Comment[it]=Apertura di file e URL +Comment[ja]=ファイルと URL を開きます +Comment[kk]=Файл мен URL ашқышы +Comment[km]=កម្មវិធី​បើក ឯកសារ និង URL +Comment[kn]=ಕಡತ ಮತ್ತು URL ತೆರೆಯುಗ +Comment[ko]=파일과 URL을 여는 도구 +Comment[ku]=Vekera pel û URL'an +Comment[lt]=Failų ir URL atvėriklis +Comment[lv]=Failu un URL atvērējs +Comment[mk]=Отворач на датотеки и адреси +Comment[ml]=ഫയല്‍, യുആര്‍എല്‍ തുറക്കുന്നതിനുള്ള സംവിധാനം +Comment[mr]=फाईल व URL ओपनर +Comment[nb]=Fil- og URL-åpner +Comment[nds]=Opmaker för Dateien un URLs +Comment[nl]=Openen van bestanden en URL-adressen +Comment[nn]=Opna filer og nettadresser +Comment[or]=ଫାଇଲ ଏବଂ URL ଖୋଲା +Comment[pa]=ਫਾਇਲ ਅਤੇ URL ਖੋਲ੍ਹਣ ਵਾਲਾ +Comment[pl]=Otwieranie plików i adresów URL +Comment[pt]=Abertura de ficheiros e URL's +Comment[pt_BR]=Abertura de arquivos e URLs +Comment[ro]=Deschizător de fișiere și URL-uri +Comment[ru]=Открытие файлов и ссылок +Comment[si]=ගොනු සහ URL විවෘතකරණය +Comment[sk]=Otváranie súborov a URL +Comment[sl]=Odpri datoteke in naslove URL +Comment[sr]=Отварач фајлова и УРЛ‑ова +Comment[sr@ijekavian]=Отварач фајлова и УРЛ‑ова +Comment[sr@ijekavianlatin]=Otvarač fajlova i URL‑ova +Comment[sr@latin]=Otvarač fajlova i URL‑ova +Comment[sv]=Öppna filer och webbadresser +Comment[ta]=File and URL opener +Comment[te]=ఫైల్ మరియు URL తెరువునది +Comment[tg]=Кушодани файлҳо ва URL +Comment[th]=ตัวเปิดแฟ้มและที่อยู่ URL +Comment[tr]=Dosya ve Adres açıcı +Comment[ug]=ھۆججەت ۋە URL ئاچقۇچ +Comment[uk]=Відкривання файлів і адрес URL +Comment[vi]=Trình mở tập tin và URL +Comment[wa]=Droveu d' fitchî eyet d' adresses +Comment[x-test]=xxFile and URL openerxx +Comment[zh_CN]=文件和 URL 打开器 +Comment[zh_TW]=檔案與網址開啟器 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=system-file-manager +X-KDE-Library=krunner_locations +X-KDE-PluginInfo-Author=Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=locations +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-Plasma-AdvertiseSingleRunnerQueryMode=true +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/runners/nepomuksearch/CMakeLists.txt b/plasma/generic/runners/nepomuksearch/CMakeLists.txt new file mode 100644 index 00000000..051741b0 --- /dev/null +++ b/plasma/generic/runners/nepomuksearch/CMakeLists.txt @@ -0,0 +1,34 @@ +project(nepomuksearchrunner) + +include_directories( + ${QT_INCLUDES} + ${KDE4_INCLUDES} + ${SOPRANO_INCLUDE_DIR} + ${NEPOMUK_CORE_INCLUDE_DIR} +) + +SET(nepomuksearchrunner_SRCS + nepomuksearchrunner.cpp +) + +kde4_add_plugin(krunner_nepomuksearchrunner ${nepomuksearchrunner_SRCS}) + +target_link_libraries(krunner_nepomuksearchrunner + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KIO_LIBS} + ${NEPOMUK_CORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + ${SOPRANO_LIBRARIES} + ${KDE4_PLASMA_LIBS} +) + +install( + TARGETS krunner_nepomuksearchrunner + DESTINATION ${PLUGIN_INSTALL_DIR} + ) + +install( + FILES plasma-runner-nepomuksearch.desktop + DESTINATION ${SERVICES_INSTALL_DIR} +) diff --git a/plasma/generic/runners/nepomuksearch/Messages.sh b/plasma/generic/runners/nepomuksearch/Messages.sh new file mode 100755 index 00000000..5e7cef84 --- /dev/null +++ b/plasma/generic/runners/nepomuksearch/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_nepomuksearchrunner.pot diff --git a/plasma/generic/runners/nepomuksearch/nepomuksearchrunner.cpp b/plasma/generic/runners/nepomuksearch/nepomuksearchrunner.cpp new file mode 100644 index 00000000..fd532847 --- /dev/null +++ b/plasma/generic/runners/nepomuksearch/nepomuksearchrunner.cpp @@ -0,0 +1,386 @@ +/* This file is part of the Nepomuk Project + Copyright (c) 2008 Sebastian Trueg + Copyright (c) 2012-13 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "nepomuksearchrunner.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace Nepomuk2::Vocabulary; +using namespace Soprano::Vocabulary; + +namespace { + /** + * Milliseconds to wait before issuing the next query. + * This timeout is intended to prevent us from starting + * a query after each key press by the user. So it should + * roughly equal the time between key presses of an average user. + */ + const int s_userActionTimeout = 400; + const int s_maxResults = 10; +} + + +Nepomuk2::SearchRunner::SearchRunner( QObject* parent, const QVariantList& args ) + : Plasma::AbstractRunner( parent, args ) +{ +} + + +Nepomuk2::SearchRunner::SearchRunner( QObject* parent, const QString& serviceId ) + : Plasma::AbstractRunner( parent, serviceId ) +{ +} + + +void Nepomuk2::SearchRunner::init() +{ + // Just constructing the instance initializes the ResourceManager + Nepomuk2::ResourceManager::instance(); + + // we are pretty slow at times and use DBus calls + setSpeed(SlowSpeed); + + // we are way less important than others, mostly because we are slow + setPriority(LowPriority); + + m_actions = new KFileItemActions(this); + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds files, documents and other content that matches :q: using the desktop search system."))); +} + + +Nepomuk2::SearchRunner::~SearchRunner() +{ + qDeleteAll(m_konqActions); +} + + +void Nepomuk2::SearchRunner::match( Plasma::RunnerContext& context ) +{ + //kDebug() << &context << context.query(); + + if( ResourceManager::instance()->initialized() ) { + // This method needs to be thread-safe since KRunner does simply start new threads whenever + // the query term changes. + m_mutex.lock(); + + // we do not want to restart a query on each key-press. That would result + // in way too many queries for the rather sluggy Nepomuk query service + // Thus, we use a little timeout to make sure we do not query too often + + m_waiter.wait(&m_mutex, s_userActionTimeout); + m_mutex.unlock(); + + if (!context.isValid()) { + //kDebug() << "deprecated search:" << context.query(); + // we are no longer the latest call + return; + } + + // no queries on very short strings + // We use a default length of 4 characters cause virtuoso has a min length requirement of 4 + // leading characters. This way we avoid using the expensive regex search + if( context.query().length() >= 4 ) { + //kDebug() << "got through" << context.query(); + Query::Query query = Query::QueryParser::parseQuery(context.query()); + query.setLimit(s_maxResults); + + Query::ResultIterator it(query); + while (context.isValid() && it.next()) { + Plasma::QueryMatch match = convertToQueryMatch(it.result()); + if (match.isValid()) { + context.addMatch(context.query(), match); + } + } + } + } +} + +namespace { + // Copied from kde-runtime/nepomuk/kioslaves/kio_nepomuk.cpp + /** + * This function constructs the url the nepomuk kioslave would redirect to. + * We use this instead of just supplying the nepomuk kioslave with the url because + * applications like Dolphin display the url on the title bar even though the + * 'display name' would be set cause that would involve stating the file. + * + * Therefore, in order to avoid showing an ugly 'nepomuk:/res/uuid' to the user we + * redirect the url ourselves so we have a pretty representation. + */ + KUrl redirectionUrl(const Nepomuk2::Resource& res) { + using namespace Nepomuk2; + + // list tags by listing everything tagged with that tag + if (res.hasType(NAO::Tag())) { + Query::ComparisonTerm term(NAO::hasTag(), Query::ResourceTerm( res ), Query::ComparisonTerm::Equal); + KUrl url = Query::Query(term).toSearchUrl(i18n( "Things tagged '%1'", res.genericLabel())); + url.addQueryItem(QLatin1String("resource"), KUrl(res.uri()).url()); + return url; + } + + // list everything else besides files by querying things related to the resource in some way + // this works for music albums or artists but it would also work for tags + else if (!res.hasType(NFO::FileDataObject())) { + Query::ComparisonTerm term(QUrl(), Query::ResourceTerm(res), Query::ComparisonTerm::Equal); + KUrl url = Query::Query(term).toSearchUrl(res.genericLabel()); + url.addQueryItem(QLatin1String("resource"), KUrl(res.uri()).url()); + return url; + } + + // no forwarding done + return KUrl(); + } +} + +void Nepomuk2::SearchRunner::run( const Plasma::RunnerContext&, const Plasma::QueryMatch& match ) +{ + // If no action was selected, the interface doesn't support multiple + // actions so we simply open the file + if (QAction *a = match.selectedAction()) { + if (a != action("open")) { + match.selectedAction()->trigger(); + return; + } + } + + Nepomuk2::Resource res = match.data().value(); + KUrl url = res.uri(); + KUrl nieUrl = res.property( NIE::url() ).toUrl(); + if( !nieUrl.isEmpty() ) + url = nieUrl; + + // Redirect it in order to avoid showing the user an ugly URL + if(url.scheme() == QLatin1String("nepomuk")) { + KUrl newUrl = redirectionUrl(res); + if(newUrl.isValid()) + url = newUrl; + } + + KService::Ptr preferredServicePtr; + if (res.hasProperty(Nepomuk2::Vocabulary::NIE::mimeType()) && + KUrl(res.property(Nepomuk2::Vocabulary::NIE::url()).toUrl()).isLocalFile()) { + preferredServicePtr = KMimeTypeTrader::self()->preferredService(res.property(Nepomuk2::Vocabulary::NIE::mimeType()).toString()); + } + + if (preferredServicePtr.isNull() || !KRun::run(*preferredServicePtr.constData(), KUrl::List(url), 0)) { + (void)new KRun(url, 0); + } +} + +QList Nepomuk2::SearchRunner::actionsFromMenu(QMenu *menu, const QString &prefix, QObject *parent) +{ + Q_ASSERT(menu); + + QList ret; + foreach (QAction *action, menu->actions()) { + if (QMenu *submenu = action->menu()) { + //Flatten hierarchy and prefix submenu text to all actions in submenu + ret << actionsFromMenu(submenu, action->text(), parent); + } else if (!action->isSeparator() && action->isEnabled()) { + QString text = action->text(); + if (action->isCheckable()) { + if (action->isChecked()) { + text = QString("(%1) %2").arg(QChar(0x2613)).arg(text); + } else { + text = QString("( ) %1").arg(text); + } + } + + if (!prefix.isEmpty()) { + text = QString("%1: %2").arg(prefix).arg(text); + } + text = text.replace(QRegExp("&([\\S])"), "\\1"); + + QAction *a = new QAction(action->icon(), text, parent); + + QObject::connect(a, SIGNAL(triggered(bool)), action, SIGNAL(triggered(bool))); + ret << a; + } + } + return ret; +} + + +QList Nepomuk2::SearchRunner::actionsForMatch(const Plasma::QueryMatch &match) +{ + //Unlike other runners, the actions generated here are likely to see + //little reuse. Hence, we will clear the actions then generate new + //ones per iteration to avoid excessive memory consumption. + qDeleteAll(m_konqActions); + m_konqActions.clear(); + + QList ret; + if (!action("open")) { + addAction("open", KIcon("document-open"), i18n("Open")); + } + ret << action("open"); + + Nepomuk2::Resource res = match.data().value(); + + KUrl url(res.uri()); + KIO::UDSEntry entry; + if (!KIO::NetAccess::stat(url.path(), entry, 0)) { + return QList(); + } + + KFileItemList list; + list << KFileItem(entry, url); + + KFileItemListProperties prop; + prop.setItems(list); + + QMenu dummy; + m_actions->setItemListProperties(prop); + m_actions->addOpenWithActionsTo(&dummy, QString()); + //Add user defined actions + m_actions->addServiceActionsTo(&dummy); + + m_konqActions = actionsFromMenu(&dummy); + + ret << m_konqActions; + + return ret; +} + +QMimeData * Nepomuk2::SearchRunner::mimeDataForMatch(const Plasma::QueryMatch *match) +{ + Nepomuk2::Resource res = match->data().value(); + + QUrl url = res.property(NIE::url()).toUrl(); + + if (!url.isValid()) { + return 0; + } + + QMimeData *result = new QMimeData(); + QList urls; + urls << url; + kDebug() << urls; + result->setUrls(urls); + return result; +} + +namespace { + qreal normalizeScore(double score) { + // no search result is ever a perfect match, NEVER. And mostly, when typing a URL + // the users wants to open that url instead of using the search result. Thus, all + // search results need to have a lower score than URLs which can drop to 0.5 + // And in the end, for 10 results, the score is not that important at the moment. + // This can be improved in the future. + // We go the easy way here and simply cut the score at 0.4 + return qMin(0.4, score); + } +} + +// FIXME: Avoid using the Resource class. Request the extra properties from the query +Plasma::QueryMatch Nepomuk2::SearchRunner::convertToQueryMatch(const Nepomuk2::Query::Result& result) +{ + Plasma::QueryMatch match( this ); + match.setType(Plasma::QueryMatch::PossibleMatch); + match.setRelevance(normalizeScore(result.score())); + + Nepomuk2::Resource res = result.resource(); + + QString type; + QString iconName; + + KMimeType::Ptr mimetype; + if (res.hasProperty(NIE::mimeType())) { + mimetype = KMimeType::mimeType(res.property(NIE::mimeType()).toString()); + } + + const QUrl fileUrl = res.toFile().url(); + if (!mimetype && res.isFile() && fileUrl.isLocalFile() ) { + mimetype = KMimeType::findByUrl(fileUrl); + } + + if (mimetype) { + type = mimetype->comment(); + iconName = mimetype->iconName(); + } + + if(type.isEmpty()) { + type = Nepomuk2::Types::Class(res.type()).label(); + + // The Query engine should typically never return properties, classes or graphs. + // But this doesn't seem to be the case cause of certain bugs in virtuoso + // Earlier versions of Nepomuk avoided this by complex queries which resulted in many + // "Virtuoso is crazy" reports. + // For 4.10, we just try to cover it up and not show the results. + // See nepomuk-core/libnepomukcore/query/query.cpp for more details + // + if(type.contains(QLatin1String("property"), Qt::CaseInsensitive) || + type.contains(QLatin1String("class"), Qt::CaseInsensitive) || + type.contains(QLatin1String("graph"), Qt::CaseInsensitive)) { + return Plasma::QueryMatch( 0 ); + } + iconName = res.genericIcon(); + } + + // HACK: Do not show non-existing files + if( fileUrl.isLocalFile() && !QFile::exists( fileUrl.toLocalFile() ) ) + return Plasma::QueryMatch( 0 ); + + // HACK: Do not show resources which do not have a label + QString label = res.genericLabel(); + if( label.startsWith(QLatin1String("nepomuk:/res")) ) + return Plasma::QueryMatch( 0 ); + + match.setText(res.genericLabel()); + match.setSubtext(type); + match.setIcon(KIcon(iconName.isEmpty() ? QString::fromLatin1("nepomuk") : iconName)); + + match.setData(qVariantFromValue(res)); + match.setId(KUrl(res.uri()).url()); + + return match; +} + + +K_EXPORT_PLASMA_RUNNER(nepomuksearchrunner, Nepomuk2::SearchRunner) + +#include "nepomuksearchrunner.moc" diff --git a/plasma/generic/runners/nepomuksearch/nepomuksearchrunner.h b/plasma/generic/runners/nepomuksearch/nepomuksearchrunner.h new file mode 100644 index 00000000..5a430b27 --- /dev/null +++ b/plasma/generic/runners/nepomuksearch/nepomuksearchrunner.h @@ -0,0 +1,82 @@ +/* This file is part of the Nepomuk Project + Copyright (c) 2008 Sebastian Trueg + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _NEPOMUK_SEARCH_RUNNER_H_ +#define _NEPOMUK_SEARCH_RUNNER_H_ + +#include + +#include +#include +#include + +#include + +class KFileItemActions; + +class QAction; + +namespace Nepomuk2 { + + class SearchRunner : public Plasma::AbstractRunner + { + Q_OBJECT + + public: + SearchRunner( QObject* parent, const QVariantList& args ); + SearchRunner( QObject* parent, const QString& serviceId = QString() ); + ~SearchRunner(); + + void match( Plasma::RunnerContext& context ); + void run( const Plasma::RunnerContext& context, const Plasma::QueryMatch& action ); + + QList actionsForMatch(const Plasma::QueryMatch &match); + + protected Q_SLOTS: + void init(); + QMimeData *mimeDataForMatch(const Plasma::QueryMatch *match); + + private: + /** + * Returns a list of all actions in the given QMenu + * This method flattens the hierarchy of the menu by prefixing the + * text of all actions in a submenu with the submenu title. + * + * @param menu the QMenu storing the actions + * @param prefix text to display before the text of all actions in the menu + * @param parent QObject to be passed as parent of all the actions in the list + * + * @since 4.4 + */ + QList actionsFromMenu(QMenu *menu, const QString &prefix = QString(), QObject *parent = 0); + + /** + * Converts a Nepomuk Query Result to a Plasma::QueryMatch, which can be used + * in the runner context + */ + Plasma::QueryMatch convertToQueryMatch( const Query::Result& result ); + + QMutex m_mutex; + QWaitCondition m_waiter; + + KFileItemActions *m_actions; + QList m_konqActions; + }; +} + +#endif diff --git a/plasma/generic/runners/nepomuksearch/plasma-runner-nepomuksearch.desktop b/plasma/generic/runners/nepomuksearch/plasma-runner-nepomuksearch.desktop new file mode 100644 index 00000000..2261719c --- /dev/null +++ b/plasma/generic/runners/nepomuksearch/plasma-runner-nepomuksearch.desktop @@ -0,0 +1,125 @@ +[Desktop Entry] +Name=Nepomuk Desktop Search +Name[bs]=Nepomuk pretraga desktopa +Name[ca]=Cerca d'escriptori del Nepomuk +Name[ca@valencia]=Cerca d'escriptori del Nepomuk +Name[cs]=Vyhledávání v počítači pomocí Nepomuku +Name[da]=Nepomuk skrivebordssøgning +Name[de]=Nepomuk-Desktop-Suche +Name[el]=Αναζήτηση επιφάνειας εργασίας Nepomuk +Name[en_GB]=Nepomuk Desktop Search +Name[es]=Buscador para escritorio Nepomuk +Name[et]=Nepomuki töölauaotsing +Name[eu]=Nepomuk mahaigainaren bilatzailea +Name[fi]=Nepomuk-työpöytähaku +Name[fr]=Rechercher sur le bureau avec Nepomuk +Name[ga]=Cuardach Deisce Nepomuk +Name[gl]=Buscas no escritorio con Nepomuk +Name[he]=חיפוש בשולחן עבודה באמצעות Nepomuk +Name[hu]=Nepomuk asztali keresés +Name[ia]=Cerca de scriptorio de Nepomuk +Name[kk]=Nepomuk іздеуі +Name[km]=ស្វែងរក​ផ្ទៃតុ Nepomuk +Name[ko]=Nepomuk 데스크톱 검색 +Name[lt]=Nepomuk darbastalio paieška +Name[mr]=निपोमुक डेस्कटॉप शोध +Name[nb]=Nepomuk skrivebordssøk +Name[nds]=Nepomuk-Schriefdischsöök +Name[nl]=Nepomuk Bureaublad-zoekopdracht +Name[pa]=ਨਿਮੁਪੂਕ ਡੈਸਕਟਾਪ ਖੋਜ +Name[pl]=Wyszukiwanie na pulpicie Nepomuk +Name[pt]=Pesquisa no Ambiente de Trabalho Nepomuk +Name[pt_BR]=Pesquisa no desktop do Nepomuk +Name[ro]=Căutare de birou Nepomuk +Name[ru]=Служба поиска Nepomuk +Name[sk]=Hľadanie na ploche Nepomuk +Name[sl]=Namizno iskanje Nepomuk +Name[sr]=Непомукова претрага површи +Name[sr@ijekavian]=Непомукова претрага површи +Name[sr@ijekavianlatin]=Nepomukova pretraga površi +Name[sr@latin]=Nepomukova pretraga površi +Name[sv]=Nepomuk skrivbordssökning +Name[tr]=Nepomuk Masaüstü Araması +Name[uk]=Стільничний пошук Nepomuk +Name[x-test]=xxNepomuk Desktop Searchxx +Name[zh_CN]=Nepomuk 桌面搜索 +Name[zh_TW]=Nepomuk 桌面搜尋 +Comment=KRunner which performs desktop searches via Nepomuk +Comment[ar]=مشغل لـKRunner ينفذ البحث لسطح المكتب بواسطة نبومك +Comment[ast]=Krunner executa guetes nel escritoriu vía Nepomuk +Comment[be@latin]=Modul „KRunner”, jaki šukaje ŭ kamputary praz systemu „Nepomuk” +Comment[bg]=KRunner търси с помощта на Nepomuk +Comment[bs]=Izvođač za pretraživanje radne površi putem Nepomuka +Comment[ca]=El KRunner executa cerques d'escriptori via el Nepomuk +Comment[ca@valencia]=El KRunner executa cerques d'escriptori via el Nepomuk +Comment[cs]=KRunner vyhledává v počítači prostřednictvím Nepomuku +Comment[da]=KRunner som udfører skrivebordssøgning via Nepomuk +Comment[de]=Starter, der eine Desktop-Suche mit Nepomuk ausführt. +Comment[el]=KRunner που εκτελεί αναζητήσεις επιφάνειας εργασίας μέσω του Nepomuk +Comment[en_GB]=KRunner which performs desktop searches via Nepomuk +Comment[es]=Krunner que ejecuta búsquedas en el escritorio vía Nepomuk +Comment[et]=KRunner, mis sooritab töölauaotsinguid Nepomuki vahendusel +Comment[eu]=KRunner, Nepomuk bidez mahaigain-bilaketak egiten dituena +Comment[fi]=KRunner, joka suorittaa työpöytähakuja Nepomuk-ohjelman kautta +Comment[fr]=Krunner qui réalise des recherches sur le bureau grâce à Nepomuk +Comment[fy]=KRunner dy sykopdrachten fia Nepomuk útfiert +Comment[ga]=KRunner a chuardaíonn an deasc le Nepomuk +Comment[gl]=Un KRunner que fai buscas no escritorio mediante Nepomuk +Comment[gu]=KRunner જે નેપોમુક વડે ડેસ્કટોપ શોધ કરે છે +Comment[he]=‏KRunner אשר מבצע חיפוש בשולחן העבודה באמצעות Nepomuk +Comment[hi]=के-रनर जो नेपोमक के जरिए डेस्कटॉप खोज करता है +Comment[hne]=के-रनर जउन हर नेपोमक के साथ डेस्कटाप सर्च करथे +Comment[hr]=KRunner koji izvodi pretragu računala preko Nepomuka +Comment[hu]=Kezelőelem kereséshez a Nepomukon keresztül +Comment[ia]=KRunner que il exeque cercas de scriptorio via Nepomuk +Comment[id]=KRunner yang melakukan pencarian desktop via Nepomuk +Comment[is]=KRunner keyrsluforrit fyrir skjáborðsleit með Nemopuk +Comment[ja]=Nepomuk を介してデスクトップ検索を行う KRunner +Comment[kk]=Nepomuk арқылы іздеуді орындайтын KRunner бағдарламасы +Comment[km]=KRunner ដែល​​អនុវត្ត​ការ​ស្វែងរក​ផ្ទៃតុ​តាមរយៈ Nepomuk +Comment[kn]=ನೆಪೋಮುಕ್ ಮೂಲಕ KRunner ಗಣಕತೆರೆಯಲ್ಲಿ ಹುಡುಕುವ ಕೆಲಸವನ್ನು ಮಾಡುತ್ತದೆ +Comment[ko]=Nepomuk을 통해 데스크톱을 검색하는 KRunner +Comment[lt]=KRunner atliekantis darbastalio paiešką per Nepomuk +Comment[lv]=KRunner, kas veic meklēšanu ar Nepomuk +Comment[ml]=നെപ്പോമുക്ക് വഴി പണിയിടത്തില്‍ തെരച്ചില്‍ നടത്തുന്ന കെറണ്ണര്‍ +Comment[mr]=नेपोमुक द्वारे डेस्कटॉप शोध कार्यान्वित करणारे के-रनर +Comment[nb]=KRunner som utfører skrivebordssøk via Nepomuk +Comment[nds]=KRunner-Moduul, mit dat sik Schriefdischsöken över Nepomuk utföhren laat +Comment[nl]=KRunner die zoekopdrachten via Nepomuk uitvoert +Comment[nn]=KRunner-program som utfører skrivebordssøk gjennom Nepomuk +Comment[pa]=ਕੇ-ਰਨਰ, ਜੋ ਕਿ ਨਿਪੁਮੂਕ ਰਾਹੀਂ ਡੈਸਕਟਾਪ ਖੋਜ ਕਰਦਾ ਹੈ +Comment[pl]=KRunner, który dokonuje wyszukiwania za pomocą Nepomuka +Comment[pt]=Um KRunner que efectua pesquisas no ambiente de trabalho com o Nepomuk +Comment[pt_BR]=KRunner que faz pesquisas no desktop com o Nepomuk +Comment[ro]=Un KRunner ce execută căutări de birou prin Nepomuk +Comment[ru]=Поиск данных с помощью Nepomuk +Comment[si]=Nepomuk යොදාගෙන වැඩතල සෙවුම් ඉටුකරන KRunner +Comment[sk]=KRunner, ktorý prehľadáva plochu pomocou Nepomuku +Comment[sl]=Zaganjalnik, ki prek Nepomuka opravi iskanje po namizju +Comment[sr]=Извођач за претраживање радне површи путем Непомука +Comment[sr@ijekavian]=Извођач за претраживање радне површи путем Непомука +Comment[sr@ijekavianlatin]=Izvođač za pretraživanje radne površi putem Nepomuka +Comment[sr@latin]=Izvođač za pretraživanje radne površi putem Nepomuka +Comment[sv]=Programkörning som utför skrivbordssökningar via Nepomuk +Comment[ta]=KRunner which performs desktop searches via Nepomuk +Comment[te]=నెపోమక్ ద్వారా రంగస్థల శోధనలను జరిపే KRunner +Comment[th]=KRunner สามารถค้นหาบนพื้นที่ทำงานผ่าน Nepomuk +Comment[tr]=Nepomuk üzerinden masaüstü araması yapan KRunner +Comment[ug]=KRunner ئارقىلىق KRunner ئۈستەلئۈستى ئىزدەش ئىجراچىسى +Comment[uk]=KRunner, який виконуватиме стільничний пошук за допомогою Nepomuk +Comment[vi]=KRunner thực hiện tìm kiếm máy tính qua Nepomuk +Comment[wa]=KRunner ki fwait des cweraedjes sol sicribanne avou Nepomuk +Comment[x-test]=xxKRunner which performs desktop searches via Nepomukxx +Comment[zh_CN]=通过 Nepomuk 执行桌面搜索的运行器 +Comment[zh_TW]=透過 Nepomuk 執行桌面搜尋的 KRunner 程式。 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=nepomuk +X-KDE-Library=krunner_nepomuksearchrunner +X-KDE-PluginInfo-Author=Sebastian Trueg +X-KDE-PluginInfo-Email=trueg@kde.org +X-KDE-PluginInfo-Name=nepomuksearch +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-Plasma-AdvertiseSingleRunnerQueryMode=true +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/runners/places/CMakeLists.txt b/plasma/generic/runners/places/CMakeLists.txt new file mode 100644 index 00000000..8b0960e0 --- /dev/null +++ b/plasma/generic/runners/places/CMakeLists.txt @@ -0,0 +1,18 @@ + +set(krunner_placesrunner_SRCS + placesrunner.cpp +) + +kde4_add_plugin(krunner_placesrunner ${krunner_placesrunner_SRCS}) +target_link_libraries( + krunner_placesrunner + ${KDE4_KFILE_LIBS} + ${KDE4_SOLID_LIBS} + ${KDE4_KIO_LIBS} + ${KDE4_PLASMA_LIBS} + ) + +install(TARGETS krunner_placesrunner DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install(FILES plasma-runner-places.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/places/Messages.sh b/plasma/generic/runners/places/Messages.sh new file mode 100755 index 00000000..1ef74d99 --- /dev/null +++ b/plasma/generic/runners/places/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_placesrunner.pot diff --git a/plasma/generic/runners/places/placesrunner.cpp b/plasma/generic/runners/places/placesrunner.cpp new file mode 100644 index 00000000..7fca5cd3 --- /dev/null +++ b/plasma/generic/runners/places/placesrunner.cpp @@ -0,0 +1,170 @@ +/* + * Copyright 2008 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "placesrunner.h" + +#include +#include +#include + +#include +#include +#include +#include + +//Q_DECLARE_METATYPE(Plasma::RunnerContext) +PlacesRunner::PlacesRunner(QObject* parent, const QVariantList &args) + : Plasma::AbstractRunner(parent, args) +{ +// qRegisterMetaType + Q_UNUSED(args) + setObjectName( QLatin1String("Places" )); + Plasma::RunnerSyntax defaultSyntax(i18n("places"), i18n("Lists all file manager locations")); + setDefaultSyntax(defaultSyntax); + addSyntax(defaultSyntax); + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds file manager locations that match :q:"))); + + // ensure the bookmarkmanager, etc. in the places model gets creates created in the main thread + // otherwise crashes ensue + m_helper = new PlacesRunnerHelper(this); +} + +PlacesRunner::~PlacesRunner() +{ +} + +void PlacesRunner::match(Plasma::RunnerContext &context) +{ + if (QThread::currentThread() == QCoreApplication::instance()->thread()) { + // from the main thread + //kDebug() << "calling"; + m_helper->match(&context); + } else { + // from the non-gui thread + //kDebug() << "emitting"; + emit doMatch(&context); + } + //m_helper->match(c); +} + +PlacesRunnerHelper::PlacesRunnerHelper(PlacesRunner *runner) + : QObject(runner) +{ + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + connect(runner, SIGNAL(doMatch(Plasma::RunnerContext*)), + this, SLOT(match(Plasma::RunnerContext*)), + Qt::BlockingQueuedConnection); +} + +void PlacesRunnerHelper::match(Plasma::RunnerContext *c) +{ + Plasma::RunnerContext &context = *c; + if (!context.isValid()) { + return; + } + + const QString term = context.query(); + + if (term.length() < 3) { + return; + } + + QList matches; + const bool all = term.compare(i18n("places"), Qt::CaseInsensitive) == 0; + for (int i = 0; i <= m_places.rowCount(); i++) { + QModelIndex current_index = m_places.index(i, 0); + Plasma::QueryMatch::Type type = Plasma::QueryMatch::NoMatch; + qreal relevance = 0; + + const QString text = m_places.text(current_index); + if ((all && !text.isEmpty()) || text.compare(term, Qt::CaseInsensitive) == 0) { + type = Plasma::QueryMatch::ExactMatch; + relevance = all ? 0.9 : 1.0; + } else if (text.contains(term, Qt::CaseInsensitive)) { + type = Plasma::QueryMatch::PossibleMatch; + relevance = 0.7; + } + + if (type != Plasma::QueryMatch::NoMatch) { + Plasma::QueryMatch match(static_cast(parent())); + match.setType(type); + match.setRelevance(relevance); + match.setIcon(KIcon(m_places.icon(current_index))); + match.setText(text); + + //if we have to mount it set the device udi instead of the URL, as we can't open it directly + KUrl url; + if (m_places.isDevice(current_index) && m_places.setupNeeded(current_index)) { + url = m_places.deviceForIndex(current_index).udi(); + } else { + url = m_places.url(current_index); + } + + match.setData(url); + match.setId(url.prettyUrl()); + matches << match; + } + } + + context.addMatches(term, matches); +} + + +void PlacesRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action) +{ + Q_UNUSED(context); + //I don't just pass the model index because the list could change before the user clicks on it, which would make everything go wrong. Ideally we don't want things to go wrong. + if (action.data().canConvert()) { + new KRun(action.data().value().url(), 0); + } else if (action.data().canConvert()) { + //search our list for the device with the same udi, then set it up (mount it). + QString deviceUdi = action.data().toString(); + + // gets deleted in setupComplete + KFilePlacesModel *places = new KFilePlacesModel(this); + connect(places, SIGNAL(setupDone(QModelIndex,bool)), SLOT(setupComplete(QModelIndex,bool))); + bool found = false; + + for (int i = 0; i <= places->rowCount();i++) { + QModelIndex current_index = places->index(i, 0); + if (places->isDevice(current_index) && places->deviceForIndex(current_index).udi() == deviceUdi) { + places->requestSetup(current_index); + found = true; + break; + } + } + + if (!found) { + delete places; + } + } +} + +//if a device needed mounting, this slot gets called when it's finished. +void PlacesRunner::setupComplete(QModelIndex index, bool success) +{ + KFilePlacesModel *places = qobject_cast(sender()); + //kDebug() << "setup complete" << places << sender(); + if (success && places) { + new KRun(places->url(index), 0); + places->deleteLater(); + } +} + +#include "placesrunner.moc" diff --git a/plasma/generic/runners/places/placesrunner.h b/plasma/generic/runners/places/placesrunner.h new file mode 100644 index 00000000..94efd3ec --- /dev/null +++ b/plasma/generic/runners/places/placesrunner.h @@ -0,0 +1,66 @@ +/* + * Copyright 2008 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLACESRUNNER_H +#define PLACESRUNNER_H + + +#include +#include + +class PlacesRunner; + +class PlacesRunnerHelper : public QObject +{ + Q_OBJECT + +public: + PlacesRunnerHelper(PlacesRunner *runner); + +public Q_SLOTS: + void match(Plasma::RunnerContext *context); + +private: + KFilePlacesModel m_places; +}; + +class PlacesRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + +public: + PlacesRunner(QObject* parent, const QVariantList &args); + ~PlacesRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + +Q_SIGNALS: + void doMatch(Plasma::RunnerContext *context); + +private slots: + void setupComplete(QModelIndex, bool); + +private: + PlacesRunnerHelper *m_helper; +}; + +K_EXPORT_PLASMA_RUNNER(placesrunner, PlacesRunner) + +#endif diff --git a/plasma/generic/runners/places/plasma-runner-places.desktop b/plasma/generic/runners/places/plasma-runner-places.desktop new file mode 100644 index 00000000..ddec1629 --- /dev/null +++ b/plasma/generic/runners/places/plasma-runner-places.desktop @@ -0,0 +1,133 @@ +[Desktop Entry] +Name=Places +Name[ar]=الأماكن +Name[ast]=Llugares +Name[be@latin]=Miescy +Name[bg]=Места +Name[bn]=স্থান +Name[bs]=mjesta +Name[ca]=Llocs +Name[ca@valencia]=Llocs +Name[cs]=Místa +Name[csb]=Place +Name[da]=Steder +Name[de]=Orte +Name[el]=Τοποθεσίες +Name[en_GB]=Places +Name[eo]=Lokoj +Name[es]=Lugares +Name[et]=Asukohad +Name[eu]=Tokiak +Name[fi]=Sijainnit +Name[fr]=Emplacements +Name[fy]=Places +Name[ga]=Áiteanna +Name[gl]=Lugares +Name[gu]=જગ્યાઓ +Name[he]=מקומות +Name[hi]=स्थान +Name[hne]=प्लेसेस +Name[hr]=Mjesta +Name[hu]=Helyek +Name[ia]=Placias +Name[id]=Tempat +Name[is]=Staðir +Name[it]=Risorse +Name[ja]=場所 +Name[ka]=ადგილები +Name[kk]=Орындар +Name[km]=កន្លែង +Name[kn]=ಸ್ಥಳಗಳು +Name[ko]=위치 +Name[ku]=Cih +Name[lt]=Vietos +Name[lv]=Vietas +Name[mai]=स्थान +Name[mk]=Места +Name[ml]=സ്ഥലങ്ങള്‍ +Name[mr]=जागा +Name[nb]=Steder +Name[nds]=Steden +Name[nl]=Locaties +Name[nn]=Stader +Name[or]=ସ୍ଥାନଗୁଡ଼ିକ +Name[pa]=ਥਾਵਾਂ +Name[pl]=Miejsca +Name[pt]=Locais +Name[pt_BR]=Locais +Name[ro]=Locuri +Name[ru]=Точки входа +Name[si]=ස්ථාන +Name[sk]=Miesta +Name[sl]=Mesta +Name[sr]=места +Name[sr@ijekavian]=мјеста +Name[sr@ijekavianlatin]=mjesta +Name[sr@latin]=mesta +Name[sv]=Platser +Name[ta]=Places +Name[tg]=Ҷойҳо +Name[th]=ที่หลัก ๆ +Name[tr]=Konumlar +Name[ug]=ئورۇنلار +Name[uk]=Місця +Name[wa]=Plaeces +Name[x-test]=xxPlacesxx +Name[zh_CN]=位置 +Name[zh_TW]=地方 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=user-home +Comment=Open devices and folder bookmarks +Comment[bs]=Otvoreni uređaji i mape favorita +Comment[ca]=Obre els punts dels dispositius i dels preferits +Comment[ca@valencia]=Obri els punts dels dispositius i dels preferits +Comment[cs]=Otevřít záložky zařízení a složek +Comment[da]=Åbn enheder og mappebogmærker +Comment[de]=Geräte und Lesezeichen für Ordner öffnen +Comment[el]=Άνοιγμα σελιδοδεικτών συσκευών και φακέλων +Comment[en_GB]=Open devices and folder bookmarks +Comment[es]=Abrir dispositivos y marcadores de carpetas +Comment[et]=Seadmete ja kataloogide järjehoidjate avamine +Comment[eu]=Ireki gailuen eta karpeten laster-markak +Comment[fi]=Avaa laitteita ja kansiokirjanmerkkejä +Comment[fr]=Ouvrir les signets de périphériques et de dossiers +Comment[ga]=Oscail gléasanna agus leabharmharcanna fillteáin +Comment[gl]=Abre dispositivos e cartafoles de marcadores +Comment[he]=פותח סימניות התקנים ותיקיות +Comment[hu]=Eszközökre és mappákra mutató könyvjelzők megnyitása +Comment[ia]=Aperi dispositivos e marcatores de libros de dossieres +Comment[it]=Apre segnalibri di dispositivi e cartelle +Comment[kk]=Құрылғы мен қапшықтардың бетбелгілерін ашу +Comment[km]=បើក​ឧបករណ៍ និង​ចំណាំ​ថត +Comment[ko]=장치와 폴더 책갈피 열기 +Comment[lt]=Atverti įrenginių ir aplankų žymeles +Comment[mr]=साधने व संचयीका ओळखचिन्ह उघडा +Comment[nb]=Åpne bokmerker for enheter og mapper +Comment[nds]=Reedschappen un Orner-Leestekens opmaken +Comment[nl]=Apparaten- en mappenbladwijzers openen +Comment[pa]=ਜੰਤਰ ਅਤੇ ਫੋਲਡਰ ਬੁੱਕਮਾਰਕ ਖੋਲ੍ਹੋ +Comment[pl]=Otwieranie urządzeń i zakładek katalogów +Comment[pt]=Abrir os favoritos dos dispositivos e pastas +Comment[pt_BR]=Abre os favoritos dos dispositivos e pastas +Comment[ro]=Deschide semne de carte pentru dispozitive și dosare +Comment[ru]=Переход по закладкам для устройств и папок +Comment[sk]=Otváranie záložiek priečinkov a zariadení +Comment[sl]=Odpiranje naprav in map, ki so med zaznamki +Comment[sr]=Отварајте обележиваче уређаја и фасцикли +Comment[sr@ijekavian]=Отварајте обиљеживаче уређаја и фасцикли +Comment[sr@ijekavianlatin]=Otvarajte obilježivače uređaja i fascikli +Comment[sr@latin]=Otvarajte obeleživače uređaja i fascikli +Comment[sv]=Öppna enhets- och katalogbokmärken +Comment[tr]=Aygıt ve dizin yer imlerini aç +Comment[uk]=Відкриття пристроїв та закладок на теки +Comment[x-test]=xxOpen devices and folder bookmarksxx +Comment[zh_CN]=打开设备和文件夹书签 +Comment[zh_TW]=開啟裝置與資料夾書籤 +X-KDE-Library=krunner_placesrunner +X-KDE-PluginInfo-Author=David Edmundson +X-KDE-PluginInfo-Email=kde@davidedmundson.co.uk +X-KDE-PluginInfo-Name=places +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/runners/powerdevil/CMakeLists.txt b/plasma/generic/runners/powerdevil/CMakeLists.txt new file mode 100644 index 00000000..d1901be5 --- /dev/null +++ b/plasma/generic/runners/powerdevil/CMakeLists.txt @@ -0,0 +1,15 @@ +INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} +) + +set(krunner_powerdevil_SRCS + PowerDevilRunner.cpp +) + +kde4_add_plugin(krunner_powerdevil ${krunner_powerdevil_SRCS}) +target_link_libraries(krunner_powerdevil ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4_SOLID_LIBS}) + +install(TARGETS krunner_powerdevil DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-runner-powerdevil.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/powerdevil/Messages.sh b/plasma/generic/runners/powerdevil/Messages.sh new file mode 100755 index 00000000..99ae5dce --- /dev/null +++ b/plasma/generic/runners/powerdevil/Messages.sh @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_powerdevil.pot + diff --git a/plasma/generic/runners/powerdevil/PowerDevilRunner.cpp b/plasma/generic/runners/powerdevil/PowerDevilRunner.cpp new file mode 100644 index 00000000..4085a0fd --- /dev/null +++ b/plasma/generic/runners/powerdevil/PowerDevilRunner.cpp @@ -0,0 +1,329 @@ +/*************************************************************************** + * Copyright 2008 by Dario Freddi * + * Copyright 2008 by Sebastian Kügler * + * * + * 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 "PowerDevilRunner.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +PowerDevilRunner::PowerDevilRunner(QObject *parent, const QVariantList &args) + : Plasma::AbstractRunner(parent, args), + m_shortestCommand(1000) +{ + Q_UNUSED(args) + qDBusRegisterMetaType< StringStringMap >(); + + setObjectName( QLatin1String("PowerDevil" )); + setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File | + Plasma::RunnerContext::NetworkLocation | Plasma::RunnerContext::Help); + updateStatus(); + initUpdateTriggers(); + + /* Let's define all the words here. m_words contains all the words that + * will eventually trigger a match in the runner. + */ + + QStringList commands; + commands << i18nc("Note this is a KRunner keyword", "power profile") + << i18nc("Note this is a KRunner keyword", "suspend") + << i18nc("Note this is a KRunner keyword", "sleep") + << i18nc("Note this is a KRunner keyword", "hibernate") + << i18nc("Note this is a KRunner keyword", "to disk") + << i18nc("Note this is a KRunner keyword", "to ram") + << i18nc("Note this is a KRunner keyword", "screen brightness") + << i18nc("Note this is a KRunner keyword", "dim screen"); + + foreach (const QString &command, commands) { + if (command.length() < m_shortestCommand) { + m_shortestCommand = command.length(); + } + } +} + +void PowerDevilRunner::updateSyntaxes() +{ + QList syntaxes; + syntaxes.append(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "power profile"), + i18n("Lists all power profiles and allows them to be activated"))); + syntaxes.append(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "suspend"), + i18n("Lists system suspend (e.g. sleep, hibernate) options " + "and allows them to be activated"))); + + QSet< Solid::PowerManagement::SleepState > states = Solid::PowerManagement::supportedSleepStates(); + + if (states.contains(Solid::PowerManagement::SuspendState)) { + Plasma::RunnerSyntax sleepSyntax(i18nc("Note this is a KRunner keyword", "sleep"), + i18n("Suspends the system to RAM")); + sleepSyntax.addExampleQuery(i18nc("Note this is a KRunner keyword", "to ram")); + syntaxes.append(sleepSyntax); + } + + if (states.contains(Solid::PowerManagement::HibernateState)) { + Plasma::RunnerSyntax hibernateSyntax(i18nc("Note this is a KRunner keyword", "hibernate"), + i18n("Suspends the system to disk")); + hibernateSyntax.addExampleQuery(i18nc("Note this is a KRunner keyword", "to disk")); + syntaxes.append(hibernateSyntax); + } + + Plasma::RunnerSyntax brightnessSyntax(i18nc("Note this is a KRunner keyword", "screen brightness"), + // xgettext:no-c-format + i18n("Lists screen brightness options or sets it to the brightness defined by :q:; " + "e.g. screen brightness 50 would dim the screen to 50% maximum brightness")); + brightnessSyntax.addExampleQuery(i18nc("Note this is a KRunner keyword", "dim screen")); + syntaxes.append(brightnessSyntax); + setSyntaxes(syntaxes); +} + +PowerDevilRunner::~PowerDevilRunner() +{ +} + +void PowerDevilRunner::initUpdateTriggers() +{ + // Also receive updates triggered through the DBus + QDBusConnection dbus = QDBusConnection::sessionBus(); + if (dbus.interface()->isServiceRegistered("org.kde.Solid.PowerManagement")) { + if (!dbus.connect("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", + "profileChanged", this, SLOT(updateStatus()))) { + kDebug() << "error!"; + } + if (!dbus.connect("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", + "configurationReloaded", this, SLOT(updateStatus()))) { + kDebug() << "error!"; + } + } +} + +void PowerDevilRunner::updateStatus() +{ + // Profiles and their icons + { + KSharedConfigPtr profilesConfig = KSharedConfig::openConfig("powerdevil2profilesrc", KConfig::SimpleConfig); + // Request profiles to the daemon + QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", "availableProfiles"); + QDBusPendingReply< StringStringMap > reply = QDBusConnection::sessionBus().asyncCall(call); + reply.waitForFinished(); + + if (!reply.isValid()) { + kDebug() << "Error contacting the daemon!"; + return; + } + + m_availableProfiles = reply.value(); + + if (m_availableProfiles.isEmpty()) { + kDebug() << "No available profiles!"; + return; + } + + for (StringStringMap::const_iterator i = m_availableProfiles.constBegin(); i != m_availableProfiles.constEnd(); ++i) { + KConfigGroup settings(profilesConfig, i.key()); + if (settings.readEntry< QString >("icon", QString()).isEmpty()) { + m_profileIcon[i.key()] = "preferences-system-power-management"; + } else { + m_profileIcon[i.key()] = settings.readEntry< QString >("icon", QString()); + } + } + } + + updateSyntaxes(); +} + + +bool PowerDevilRunner::parseQuery(const QString& query, const QList& rxList, QString& parameter) const +{ + foreach (const QRegExp& rx, rxList) { + if (rx.exactMatch(query)) { + parameter = rx.cap(1).trimmed(); + return true; + } + } + return false; +} + +void PowerDevilRunner::match(Plasma::RunnerContext &context) +{ + const QString term = context.query(); + if (term.length() < m_shortestCommand) { + return; + } + + QList matches; + + QString parameter; + + if (parseQuery(term, + QList() << QRegExp(i18nc("Note this is a KRunner keyword; %1 is a parameter", "power profile %1", "(.*)"), Qt::CaseInsensitive) + << QRegExp(i18nc("Note this is a KRunner keyword", "power profile"), Qt::CaseInsensitive), + parameter)) { + for (StringStringMap::const_iterator i = m_availableProfiles.constBegin(); i != m_availableProfiles.constEnd(); ++i) { + if (!parameter.isEmpty()) { + if (!i.value().startsWith(parameter, Qt::CaseInsensitive)) { + continue; + } + } + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setIcon(KIcon(m_profileIcon[i.key()])); + match.setText(i18n("Set Profile to '%1'", i.value())); + match.setData(i.key()); + match.setRelevance(1); + match.setId("ProfileChange "+ i.key()); + matches.append(match); + } + } else if (parseQuery(term, + QList() << QRegExp(i18nc("Note this is a KRunner keyword; %1 is a parameter", "screen brightness %1", "(.*)"), Qt::CaseInsensitive) + << QRegExp(i18nc("Note this is a KRunner keyword", "screen brightness"), Qt::CaseInsensitive) + << QRegExp(i18nc("Note this is a KRunner keyword; %1 is a parameter", "dim screen %1", "(.*)"), Qt::CaseInsensitive) + << QRegExp(i18nc("Note this is a KRunner keyword", "dim screen"), Qt::CaseInsensitive), + parameter)) { + if (!parameter.isEmpty()) { + bool test; + int b = parameter.toInt(&test); + if (test) { + int brightness = qBound(0, b, 100); + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setIcon(KIcon("preferences-system-power-management")); + match.setText(i18n("Set Brightness to %1", brightness)); + match.setData(brightness); + match.setRelevance(1); + match.setId("BrightnessChange"); + matches.append(match); + } + } else { + Plasma::QueryMatch match1(this); + match1.setType(Plasma::QueryMatch::ExactMatch); + match1.setIcon(KIcon("preferences-system-power-management")); + match1.setText(i18n("Dim screen totally")); + match1.setRelevance(1); + match1.setId("DimTotal"); + matches.append(match1); + + Plasma::QueryMatch match2(this); + match2.setType(Plasma::QueryMatch::ExactMatch); + match2.setIcon(KIcon("preferences-system-power-management")); + match2.setText(i18n("Dim screen by half")); + match2.setRelevance(1); + match2.setId("DimHalf"); + matches.append(match2); + + Plasma::QueryMatch match3(this); + match3.setType(Plasma::QueryMatch::ExactMatch); + match3.setIcon(KIcon("video-display")); + match3.setText(i18n("Turn off screen")); + match3.setRelevance(1); + match3.setId("TurnOffScreen"); + matches.append(match3); + } + } else if (term.compare(i18nc("Note this is a KRunner keyword", "suspend"), Qt::CaseInsensitive) == 0) { + QSet< Solid::PowerManagement::SleepState > states = Solid::PowerManagement::supportedSleepStates(); + + if (states.contains(Solid::PowerManagement::SuspendState)) { + addSuspendMatch(Solid::PowerManagement::SuspendState, matches); + } + + if (states.contains(Solid::PowerManagement::HibernateState)) { + addSuspendMatch(Solid::PowerManagement::HibernateState, matches); + } + } else if (term.compare(i18nc("Note this is a KRunner keyword", "sleep"), Qt::CaseInsensitive) == 0 || + term.compare(i18nc("Note this is a KRunner keyword", "to ram"), Qt::CaseInsensitive) == 0) { + addSuspendMatch(Solid::PowerManagement::SuspendState, matches); + } else if (term.compare(i18nc("Note this is a KRunner keyword", "hibernate"), Qt::CaseInsensitive) == 0 || + term.compare(i18nc("Note this is a KRunner keyword", "to disk"), Qt::CaseInsensitive) == 0) { + addSuspendMatch(Solid::PowerManagement::HibernateState, matches); + } + + if (!matches.isEmpty()) { + context.addMatches(term, matches); + } +} + +void PowerDevilRunner::addSuspendMatch(int value, QList &matches) +{ + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::ExactMatch); + + switch ((Solid::PowerManagement::SleepState)value) { + case Solid::PowerManagement::SuspendState: + case Solid::PowerManagement::StandbyState: + match.setIcon(KIcon("system-suspend")); + match.setText(i18n("Suspend to RAM")); + match.setRelevance(1); + break; + case Solid::PowerManagement::HibernateState: + match.setIcon(KIcon("system-suspend-hibernate")); + match.setText(i18n("Suspend to Disk")); + match.setRelevance(0.99); + break; + } + + match.setData(value); + match.setId("Suspend"); + matches.append(match); +} + +void PowerDevilRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(context) + + QDBusInterface iface("org.kde.Solid.PowerManagement", + "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement"); + if (match.id().startsWith("PowerDevil_ProfileChange")) { + iface.asyncCall("loadProfile", match.data().toString()); + } else if (match.id() == "PowerDevil_BrightnessChange") { + iface.asyncCall("setBrightness", match.data().toInt()); + } else if (match.id() == "PowerDevil_DimTotal") { + iface.asyncCall("setBrightness", 0); + } else if (match.id() == "PowerDevil_DimHalf") { + iface.asyncCall("setBrightness", -2); + } else if (match.id() == "PowerDevil_TurnOffScreen") { + // FIXME: Maybe this should be even removed + // iface.asyncCall("turnOffScreen"); + } else if (match.id().startsWith("PowerDevil_Suspend")) { + switch ((Solid::PowerManagement::SleepState)match.data().toInt()) { + case Solid::PowerManagement::SuspendState: + case Solid::PowerManagement::StandbyState: + Solid::PowerManagement::requestSleep(Solid::PowerManagement::SuspendState, 0, 0); + break; + case Solid::PowerManagement::HibernateState: + Solid::PowerManagement::requestSleep(Solid::PowerManagement::HibernateState, 0, 0); + break; + } + } +} + +#include "PowerDevilRunner.moc" diff --git a/plasma/generic/runners/powerdevil/PowerDevilRunner.h b/plasma/generic/runners/powerdevil/PowerDevilRunner.h new file mode 100644 index 00000000..90cce613 --- /dev/null +++ b/plasma/generic/runners/powerdevil/PowerDevilRunner.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2008 by Dario Freddi * + * * + * 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 POWERDEVILRUNNER_H +#define POWERDEVILRUNNER_H + +#include +#include + +typedef QMap< QString, QString > StringStringMap; + +class PowerDevilRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + PowerDevilRunner( QObject *parent, const QVariantList &args ); + ~PowerDevilRunner(); + + void match( Plasma::RunnerContext &context ); + void run( const Plasma::RunnerContext &context, const Plasma::QueryMatch &action ); + + private slots: + void updateStatus(); + + private: + void initUpdateTriggers(); + void updateSyntaxes(); + void addSuspendMatch(int value, QList &matches); + bool parseQuery(const QString& query, const QList& rxList, QString& parameter) const; + + StringStringMap m_availableProfiles; + QHash m_profileIcon; + QHash m_suspendMethods; + QHash m_synonyms; + + int m_shortestCommand; +}; + +Q_DECLARE_METATYPE(StringStringMap) +K_EXPORT_PLASMA_RUNNER( powerdevil, PowerDevilRunner ) + +#endif diff --git a/plasma/generic/runners/powerdevil/plasma-runner-powerdevil.desktop b/plasma/generic/runners/powerdevil/plasma-runner-powerdevil.desktop new file mode 100644 index 00000000..e0269f9a --- /dev/null +++ b/plasma/generic/runners/powerdevil/plasma-runner-powerdevil.desktop @@ -0,0 +1,159 @@ +[Desktop Entry] +Comment=Basic Power Management Operations +Comment[ar]=عمليات إدارة الطاقة الأساسية +Comment[ast]=Operaciones básiques de xestión de la batería +Comment[be@latin]=Prostyja aperacyi dla kiravańnia enerhijaj +Comment[bg]=Основни операции по захранването +Comment[bs]=Osnovni postupci upravljanja napajanjem +Comment[ca]=Operacions bàsiques de gestió d'energia +Comment[ca@valencia]=Operacions bàsiques de gestió d'energia +Comment[cs]=Základní úkony týkající se správy napájení +Comment[csb]=Spòdlowé òperacejë sprôwiania mòcą +Comment[da]=Grundlæggende strømstyringsoperationer +Comment[de]=Grundlegende Operationen zur Energieverwaltung +Comment[el]=Βασικές λειτουργίες διαχείρισης ενέργειας +Comment[en_GB]=Basic Power Management Operations +Comment[es]=Operaciones básicas de gestión de la batería +Comment[et]=Peamised toitehalduse toimingud +Comment[eu]=Energia-kudeaketako oinarrizko eragiketak +Comment[fi]=Yksinkertaiset virranhallintaoperaatiot +Comment[fr]=Opérations basiques de gestion de l'énergie +Comment[fy]=Basis enerzjybehear aksjes +Comment[ga]=Bunoibríochtaí Bainisteoireachta Cumhachta +Comment[gl]=Operacións básicas de xestión da enerxía +Comment[gu]=સામાન્ય પાવર વ્યવસ્થાપક પ્રક્રિયાઓ +Comment[he]=פעולות בסיסיות לניהול צריכת חשמל +Comment[hi]=आधारभूत बिज़ली प्रबंधन ऑपरेशन +Comment[hne]=मूल पावर प्रबंधन आपरेसन +Comment[hr]=Osnovne operacije upravljanja potrošnjom energije +Comment[hu]=Energiakezelési funkciók +Comment[ia]=Operationes basic de gestion de energia +Comment[id]=Operasi Manajemen Daya Dasar +Comment[is]=Grunnaðgerðir orkustýringarkerfis +Comment[it]=Operazioni di base per la gestione energetica +Comment[ja]=基本的な電源管理操作 +Comment[kk]=Негізгі қуаттандыруды басқару амалдары +Comment[km]=ប្រតិបត្តិការ​គ្រប់គ្រង​ថាមពល​ជា​មូលដ្ឋាន +Comment[kn]=ಮೂಲಭೂತ ವಿದ್ಯುಚ್ಛಕ್ತಿ ವ್ಯವಸ್ಥಾಪನಾ ಕಾರ್ಯಾಚರಣೆಗಳು +Comment[ko]=기본 전원 관리 작업 +Comment[ku]=Çalakiyên Rêveberiya Hêzê yê Bingehîn +Comment[lt]=Elementarios maitinimo valdymo operacijos +Comment[lv]=Pamata energokontroles darbības +Comment[mk]=Основни операции за менаџмент на енергија +Comment[ml]=അടിസ്ഥാനപരമായ പവര്‍ മാനേജ്മെന്റ് ബാക്കെന്‍ഡ് നടപടികള്‍ +Comment[mr]=मूळ पावर व्यवस्थापन कार्ये +Comment[nb]=Enkle strømstyringshandlinger +Comment[nds]=Eenfache Stroomkuntrull-Funkschonen +Comment[nl]=Basis energiebeheeroperaties +Comment[nn]=Grunnleggjande straumstyringsfunksjonar +Comment[or]=ମୌଳିକ ଶକ୍ତି ପରିଚାଳନା ପ୍ରୟୋଗଗୁଡ଼ିକ +Comment[pa]=ਬੇਸਿਕ ਪਾਵਰ ਮੈਨਿਜਮੈਂਟ ਓਪਰੇਸ਼ਨ +Comment[pl]=Podstawowe operacje zarządzania energią +Comment[pt]=Operações Básicas de Gestão da Energia +Comment[pt_BR]=Operações básicas de gerenciamento de energia +Comment[ro]=Operații de bază pentru gestiunea energiei +Comment[ru]=Управление питанием +Comment[si]=මූලික බල පරිපාලන ක්‍රියාකාරකම් +Comment[sk]=Základné operácie správy napájania +Comment[sl]=Osnovna dejanja upravljanja z energijo +Comment[sr]=Основни поступци управљања напајањем +Comment[sr@ijekavian]=Основни поступци управљања напајањем +Comment[sr@ijekavianlatin]=Osnovni postupci upravljanja napajanjem +Comment[sr@latin]=Osnovni postupci upravljanja napajanjem +Comment[sv]=Grundläggande strömsparfunktioner +Comment[ta]=Basic Power Management Operations +Comment[tg]=Служба управления питанием ноутбука +Comment[th]=ปฏิบัติการจัดการพลังงานขั้นพื้นฐาน +Comment[tr]=Temel Güç Yönetimi İşlemleri +Comment[ug]=ئاساسىي توك مەنبە باشقۇرۇش مەشغۇلاتى +Comment[uk]=Керування базовими операціями з керування живленням +Comment[vi]=Thao tác quản lý năng lượng cơ bản +Comment[wa]=Operåcions di båze do manaedjmint di l' enerdjeye +Comment[x-test]=xxBasic Power Management Operationsxx +Comment[zh_CN]=基本电源管理操作 +Comment[zh_TW]=基本的電源管理操作 +Icon=preferences-system-power-management +Name=PowerDevil +Name[ar]=عفريت الطاقة +Name[ast]=PowerDevil +Name[be@latin]=PowerDevil +Name[bg]=PowerDevil +Name[bn]=পাওয়ার-ডেভিল +Name[bn_IN]=PowerDevil +Name[bs]=PowerDevil +Name[ca]=PowerDevil +Name[ca@valencia]=PowerDevil +Name[cs]=PowerDevil +Name[da]=PowerDevil +Name[de]=PowerDevil +Name[el]=PowerDevil +Name[en_GB]=PowerDevil +Name[eo]=PowerDevil +Name[es]=PowerDevil +Name[et]=PowerDevil +Name[eu]=PowerDevil +Name[fi]=PowerDevil +Name[fr]=PowerDevil +Name[fy]=PowerDevil +Name[ga]=PowerDevil +Name[gl]=PowerDevil +Name[gu]=પાવરડેવિલ +Name[he]=PowerDevil +Name[hi]=पावर-डेविल +Name[hne]=पावर-डेविल +Name[hr]=PowerDevil +Name[hu]=Power Devil +Name[ia]=PowerDevil +Name[id]=PowerDevil +Name[is]=OrkuPúki +Name[it]=PowerDevil +Name[ja]=PowerDevil +Name[kk]=PowerDevil +Name[km]=PowerDevil +Name[kn]=ಪವರ್ ಡೆವಿಲ್ +Name[ko]=PowerDevil +Name[lt]=PowerDevil +Name[lv]=PowerDevil +Name[mai]=पावर-डेविल +Name[ml]=പവര്‍ഡെവിള്‍ +Name[mr]=पॉवरडेव्हिल +Name[nb]=PowerDevil +Name[nds]=Stroomdüvel +Name[nl]=PowerDevil +Name[nn]=PowerDevil +Name[or]=PowerDevil +Name[pa]=ਪਾਵਰ-ਡੀਵਿਲ +Name[pl]=PowerDevil +Name[pt]=PowerDevil +Name[pt_BR]=PowerDevil +Name[ro]=PowerDevil +Name[ru]=PowerDevil +Name[si]=PowerDevil +Name[sk]=PowerDevil +Name[sl]=PowerDevil +Name[sr]=Струјни ђаво +Name[sr@ijekavian]=Струјни ђаво +Name[sr@ijekavianlatin]=Strujni đavo +Name[sr@latin]=Strujni đavo +Name[sv]=Powerdevil +Name[ta]=PowerDevil +Name[te]=PowerDevil +Name[tg]=PowerDevil +Name[th]=PowerDevil +Name[tr]=PowerDevil +Name[ug]=PowerDevil +Name[uk]=PowerDevil +Name[wa]=Li Diâle d' Enerdjeye +Name[x-test]=xxPowerDevilxx +Name[zh_CN]=PowerDevil +Name[zh_TW]=PowerDevil +Type=Service +X-KDE-Library=krunner_powerdevil +X-KDE-PluginInfo-Author=Dario Freddi +X-KDE-PluginInfo-Email=drf@kdemod.ath.cx +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-Name=PowerDevil +X-KDE-PluginInfo-Version=1.0 +X-Plasma-AdvertiseSingleRunnerQueryMode=true +X-KDE-ServiceTypes=Plasma/Runner diff --git a/plasma/generic/runners/recentdocuments/CMakeLists.txt b/plasma/generic/runners/recentdocuments/CMakeLists.txt new file mode 100644 index 00000000..df24f655 --- /dev/null +++ b/plasma/generic/runners/recentdocuments/CMakeLists.txt @@ -0,0 +1,11 @@ +set(krunner_recentdocuments_SRCS + recentdocuments.cpp +) + +kde4_add_plugin(krunner_recentdocuments ${krunner_recentdocuments_SRCS}) +target_link_libraries(krunner_recentdocuments ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS krunner_recentdocuments DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install(FILES recentdocuments.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/recentdocuments/Messages.sh b/plasma/generic/runners/recentdocuments/Messages.sh new file mode 100755 index 00000000..9bed7616 --- /dev/null +++ b/plasma/generic/runners/recentdocuments/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_recentdocuments.pot diff --git a/plasma/generic/runners/recentdocuments/README b/plasma/generic/runners/recentdocuments/README new file mode 100644 index 00000000..2a809d1e --- /dev/null +++ b/plasma/generic/runners/recentdocuments/README @@ -0,0 +1,7 @@ +Kate Session Runner +======================== +This Runner loads a list of recent documents and matches +KRunner's queries against it. + +-- +sebas@kde.org diff --git a/plasma/generic/runners/recentdocuments/recentdocuments.cpp b/plasma/generic/runners/recentdocuments/recentdocuments.cpp new file mode 100644 index 00000000..57185f89 --- /dev/null +++ b/plasma/generic/runners/recentdocuments/recentdocuments.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2008 Sebastian Kügler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "recentdocuments.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + + +RecentDocuments::RecentDocuments(QObject *parent, const QVariantList& args) + : Plasma::AbstractRunner(parent, args) +{ + Q_UNUSED(args); + setObjectName( QLatin1String("Recent Documents" )); + m_icon = KIcon("document-open-recent"); + loadRecentDocuments(); + // listen for changes to the list of recent documents + KDirWatch *recentDocWatch = new KDirWatch(this); + recentDocWatch->addDir(KRecentDocument::recentDocumentDirectory(), KDirWatch::WatchFiles); + connect(recentDocWatch,SIGNAL(created(QString)),this,SLOT(loadRecentDocuments())); + connect(recentDocWatch,SIGNAL(deleted(QString)),this,SLOT(loadRecentDocuments())); + connect(recentDocWatch,SIGNAL(dirty(QString)),this,SLOT(loadRecentDocuments())); + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Looks for documents recently used with names matching :q:."))); +} + +RecentDocuments::~RecentDocuments() +{ +} + +void RecentDocuments::loadRecentDocuments() +{ + //kDebug() << "Refreshing recent documents."; + m_recentdocuments = KRecentDocument::recentDocuments(); +} + + +void RecentDocuments::match(Plasma::RunnerContext &context) +{ + if (m_recentdocuments.isEmpty()) { + return; + } + + const QString term = context.query(); + if (term.length() < 3) { + return; + } + + foreach (const QString &document, m_recentdocuments) { + if (!context.isValid()) { + return; + } + + if (document.contains(term, Qt::CaseInsensitive)) { + KConfig _config( document, KConfig::SimpleConfig ); + KConfigGroup config(&_config, "Desktop Entry" ); + QString niceName = config.readEntry( "Name" ); + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::PossibleMatch); + match.setRelevance(1.0); + match.setIcon(KIcon(config.readEntry("Icon"))); + match.setData(document); // TODO: Read URL[$e], or can we just pass the path to the .desktop file? + match.setText(niceName); + match.setSubtext(i18n("Recent Document")); + context.addMatch(term, match); + } + } +} + +void RecentDocuments::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(context) + QString url = match.data().toString(); + kDebug() << "Opening Recent Document" << url; + new KRun(url, 0); +} + +QMimeData * RecentDocuments::mimeDataForMatch(const Plasma::QueryMatch * match) +{ + QMimeData * result = new QMimeData(); + QList urls; + urls << QUrl(match->data().toString()); + result->setUrls(urls); + + result->setText(match->data().toString()); + return result; +} + +#include "recentdocuments.moc" diff --git a/plasma/generic/runners/recentdocuments/recentdocuments.desktop b/plasma/generic/runners/recentdocuments/recentdocuments.desktop new file mode 100644 index 00000000..0e240340 --- /dev/null +++ b/plasma/generic/runners/recentdocuments/recentdocuments.desktop @@ -0,0 +1,97 @@ +[Desktop Entry] +Name=Recent Documents +Name[ar]=المسندات الحديثة +Name[ast]=Documentos recientes +Name[be]=Нядаўнія дакументы +Name[be@latin]=Niadaŭnyja dakumenty +Name[bg]=Последно използвани +Name[bn]=সম্প্রতি ব্যবহৃত নথী +Name[br]=Teulioù nevez +Name[bs]=nedavnii dokumenti +Name[ca]=Documents recents +Name[ca@valencia]=Documents recents +Name[cs]=Nedávné dokumenty +Name[cy]=Dogfenni Diweddar +Name[da]=Nylige dokumenter +Name[de]=Zuletzt geöffnete Dokumente +Name[el]=Πρόσφατα έγγραφα +Name[en_GB]=Recent Documents +Name[eo]=Lastlaboritaj dokumentoj +Name[es]=Documentos recientes +Name[et]=Viimati kasutatud dokumendid +Name[eu]=Azken dokumentuak +Name[fa]=سندهای اخیر +Name[fi]=Viimeksi käytetyt tiedostot +Name[fr]=Documents récents +Name[fy]=Koatlyn brûkte dokuminten +Name[ga]=Cáipéisí is Déanaí +Name[gl]=Documentos recentes +Name[gu]=હાલનાં દસ્તાવેજો +Name[he]=מסמכים שהיו בשימוש לאחרונה +Name[hi]=हाल ही में प्रयुक्त दस्तावेज़ +Name[hne]=हाल ही मं प्रयुक्त कागद +Name[hr]=Nedavno pristupljeni dokumenti +Name[hu]=Nemrég használt dokumentumok +Name[ia]=Documentos recente +Name[id]=Dokumen Terkini +Name[is]=Nýleg skjöl +Name[it]=Documenti recenti +Name[ja]=最近の文書 +Name[ka]=ბოლო დოკუმენტები +Name[kk]=Жуырда ашылғандар +Name[km]=ឯកសារ​បច្ចុប្បន្ន +Name[kn]=ಇತ್ತೀಚಿನ ದಸ್ತಾವೇಜುಗಳು +Name[ko]=최근 문서 +Name[ku]=Pelgeyên Hatine Bikaranîn +Name[lt]=Neseni dokumentai +Name[lv]=Nesenie dokumenti +Name[mai]=हालक दस्ताबेज +Name[mk]=Скорешни документи +Name[ml]=ഈയിടെ തുറന്ന രേഖകള്‍ +Name[mr]=अलिकडील दस्तऐवज +Name[nb]=Nylig brukte dokumenter +Name[nds]=Tolest bruukt Dokmenten +Name[nl]=Recente documenten +Name[nn]=Nyleg brukte dokument +Name[or]=ପ୍ରଚଳିତ ଦଲିଲଗୁଡ଼ିକ +Name[pa]=ਤਾਜ਼ਾ ਡੌਕੂਮੈਂਟ +Name[pl]=Ostatnie dokumenty +Name[pt]=Documentos Recentes +Name[pt_BR]=Documentos recentes +Name[ro]=Documente recente +Name[ru]=Последние документы +Name[si]=මෑතකදි භාවිත කළ ලේඛන +Name[sk]=Nedávne dokumenty +Name[sl]=Nedavni dokumenti +Name[sr]=недавни документи +Name[sr@ijekavian]=недавни документи +Name[sr@ijekavianlatin]=nedavni dokumenti +Name[sr@latin]=nedavni dokumenti +Name[sv]=Senaste dokument +Name[ta]=Recent Documents +Name[te]=ఇటీవలి పత్రములు +Name[tg]=Ҳуҷҷатҳои кушодашуда +Name[th]=เอกสารที่เรียกใช้ไม่นานนี้ +Name[tr]=Son Kullanılan Belgeler +Name[ug]=يېقىنقى پۈتۈكلەر +Name[uk]=Недавні документи +Name[uz]=Yaqinda ochilgan hujjatlar +Name[uz@cyrillic]=Яқинда очилган ҳужжатлар +Name[vi]=Tài liệu gần đây +Name[wa]=Documints d' enawaire +Name[xh]=Uxwebhu Olusandukusebenziswa +Name[x-test]=xxRecent Documentsxx +Name[zh_CN]=最近的文档 +Name[zh_TW]=最近的文件 +Icon=document-open-recent + +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +X-KDE-Library=krunner_recentdocuments +X-KDE-PluginInfo-Author=Sebastian Kügler +X-KDE-PluginInfo-Email=sebas@kde.org +X-KDE-PluginInfo-Name=recentdocuments +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-Plasma-AdvertiseSingleRunnerQueryMode=true +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/runners/recentdocuments/recentdocuments.h b/plasma/generic/runners/recentdocuments/recentdocuments.h new file mode 100644 index 00000000..e16949da --- /dev/null +++ b/plasma/generic/runners/recentdocuments/recentdocuments.h @@ -0,0 +1,50 @@ +/* + * Copyright 2008 Sebastian Kügler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef RECENTDOCUMENTS_H +#define RECENTDOCUMENTS_H + +#include + +#include + +class RecentDocuments : public Plasma::AbstractRunner { + Q_OBJECT + + public: + RecentDocuments( QObject *parent, const QVariantList& args ); + ~RecentDocuments(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match); + + private Q_SLOTS: + QMimeData * mimeDataForMatch(const Plasma::QueryMatch *match); + + private Q_SLOTS: + void loadRecentDocuments(); + + private: + KIcon m_icon; + QStringList m_recentdocuments; +}; + +K_EXPORT_PLASMA_RUNNER(recentdocuments, RecentDocuments) + +#endif diff --git a/plasma/generic/runners/services/CMakeLists.txt b/plasma/generic/runners/services/CMakeLists.txt new file mode 100644 index 00000000..052cc2c0 --- /dev/null +++ b/plasma/generic/runners/services/CMakeLists.txt @@ -0,0 +1,11 @@ +set(krunner_services_SRCS + servicerunner.cpp +) + +kde4_add_plugin(krunner_services ${krunner_services_SRCS}) +target_link_libraries(krunner_services ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) + +install(TARGETS krunner_services DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install(FILES plasma-runner-services.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/services/Messages.sh b/plasma/generic/runners/services/Messages.sh new file mode 100755 index 00000000..e81fc20f --- /dev/null +++ b/plasma/generic/runners/services/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_services.pot diff --git a/plasma/generic/runners/services/plasma-runner-services.desktop b/plasma/generic/runners/services/plasma-runner-services.desktop new file mode 100644 index 00000000..4bdd62d2 --- /dev/null +++ b/plasma/generic/runners/services/plasma-runner-services.desktop @@ -0,0 +1,179 @@ +[Desktop Entry] +Name=Applications +Name[af]=Programme +Name[ar]=تطبيقات +Name[as]=অনুপ্ৰয়োগ +Name[ast]=Aplicaciones +Name[be]=Праграмы +Name[be@latin]=Aplikacyi +Name[bg]=Програми +Name[bn]=অ্যাপলিকেশন +Name[bn_IN]=অ্যাপ্লিকেশন তালিকা +Name[br]=Arloadoù +Name[bs]=programi +Name[ca]=Aplicacions +Name[ca@valencia]=Aplicacions +Name[cs]=Aplikace +Name[csb]=Programë +Name[cy]=Cymhwysiadau +Name[da]=Programmer +Name[de]=Programme +Name[el]=Εφαρμογές +Name[en_GB]=Applications +Name[eo]=Aplikaĵoj +Name[es]=Aplicaciones +Name[et]=Rakendused +Name[eu]=Aplikazioak +Name[fa]=برنامه‌ها +Name[fi]=Sovellukset +Name[fr]=Applications +Name[fy]=Programma's +Name[ga]=Feidhmchláir +Name[gl]=Programas +Name[gu]=કાર્યક્રમો +Name[he]=תוכניות +Name[hi]=अनुप्रयोग +Name[hne]=अनुपरयोग +Name[hr]=Aplikacije +Name[hsb]=Aplikacija +Name[hu]=Alkalmazások +Name[ia]=Applicationes +Name[id]=Aplikasi +Name[is]=Forrit +Name[it]=Applicazioni +Name[ja]=アプリケーション +Name[ka]=პროგრამები +Name[kk]=Қолданбалар +Name[km]=កម្មវិធី +Name[kn]=ಅನ್ವಯಗಳು +Name[ko]=응용 프로그램 +Name[ku]=Sepan +Name[lt]=Programos +Name[lv]=Programmas +Name[mai]=अनुप्रयोग +Name[mk]=Апликации +Name[ml]=പ്രയോഗങ്ങള്‍ +Name[mr]=अनुप्रयोग +Name[ms]=Aplikasi +Name[nb]=Programmer +Name[nds]=Programmen +Name[ne]=अनुप्रयोग +Name[nl]=Programma's +Name[nn]=Program +Name[oc]=Aplicacions +Name[or]=ପ୍ରୟୋଗଗୁଡ଼ିକ +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ +Name[pl]=Programy +Name[pt]=Aplicações +Name[pt_BR]=Aplicativos +Name[ro]=Aplicații +Name[ru]=Приложения +Name[se]=Prográmmat +Name[si]=යෙදුම් +Name[sk]=Aplikácie +Name[sl]=Programi +Name[sr]=програми +Name[sr@ijekavian]=програми +Name[sr@ijekavianlatin]=programi +Name[sr@latin]=programi +Name[sv]=Program +Name[ta]=பயன்பாடுகள் +Name[te]=కార్యక్రమాలు +Name[tg]=Барномаҳо +Name[th]=โปรแกรมต่าง ๆ +Name[tr]=Uygulamalar +Name[ug]=پروگراممىلار +Name[uk]=Програми +Name[uz]=Dasturlar +Name[uz@cyrillic]=Дастурлар +Name[vi]=Ứng dụng +Name[wa]=Programes +Name[x-test]=xxApplicationsxx +Name[zh_CN]=应用程序 +Name[zh_TW]=應用程式 +Comment=Find applications, control panels and services +Comment[ar]=ابحث عن التطبيقات ولوحات التحكم والخدمات +Comment[ast]=Aplicaciones, paneles de control y servicios +Comment[be@latin]=Pošuk aplikacyjaŭ, panelaŭ kiravańnia j słužbaŭ +Comment[bg]=Търсене на програми, панели и услуги +Comment[bs]=Tražite programe, kontrolne panele i servise +Comment[ca]=Cerca aplicacions, plafons de control i serveis +Comment[ca@valencia]=Cerca aplicacions, plafons de control i serveis +Comment[cs]=Najít aplikace, ovládací panely a služby +Comment[da]=Find programmer, kontrolpaneler og tjenester +Comment[de]=Auffinden von Anwendungen, Einrichtungsprogrammen und Diensten +Comment[el]=Αναζήτηση εφαρμογών, πινάκων ελέγχου και υπηρεσιών +Comment[en_GB]=Find applications, control panels and services +Comment[eo]=Trovi aplikaĵojn, stirpanelojn kaj servojn +Comment[es]=Aplicaciones, paneles de control y servicios +Comment[et]=Rakenduste, juhtpaneelide ja teenuste otsimine +Comment[eu]=Bilatu aplikazioak, aginte-panelak eta zerbitzuak +Comment[fi]=Etsi ohjelmat, asetukset ja palvelut +Comment[fr]=Trouver des applications, des tableaux de bords et des services +Comment[fy]=Sykje om applikaasjes, konfiguraasjemodules en tsjinsten +Comment[ga]=Aimsigh feidhmchláir, painéil rialaithe agus seirbhísí +Comment[gl]=Busca programas, paneis de control e servizos +Comment[gu]=કાર્યક્રમો, નિયંત્રણ પેનલો અને સેવાઓ શોધો +Comment[he]=משמש למציאת יישומים, לוחות בקרה ושירותים +Comment[hi]=अनुप्रयोग, नियंत्रण पटल तथा सेवाएँ ढूंढें +Comment[hne]=अनुपरयोग ढूंढव, नियंत्रन केंद्र अउ सेवा +Comment[hr]=Pronađi aplikacije, kontrolne okvire i usluge +Comment[hu]=Alkalmazások, vezérlőpanelek és szolgáltatások keresése +Comment[ia]=Trova applicationes, pannellos de controlo e servicios +Comment[id]=Cari aplikasi, panel kontrol dan layanan +Comment[is]=Finna forrit, stjórneiningar og þjónustur +Comment[it]=Trova applicazioni, pannelli di controllo e servizi +Comment[ja]=アプリケーション、コントロールパネル、サービスを探します +Comment[kk]=Қолданбаларды табу, панельдер мен қызметтерді басқару +Comment[km]=រក​កម្មវិធី បន្ទះ​ត្រួតពិនិត្យ និង​សេវា +Comment[kn]=ಅನ್ವಯಗಳು, ನಿಯಂತ್ರಣಾ ಪುಟೀಪುಗಳು (ಕಂಟ್ರೋಲ್ ಪಾನಲ್ಸ್) ಹಾಗೂ ಸೇವೆಗಳನ್ನು ಹುಡುಕು +Comment[ko]=프로그램, 제어판, 서비스 찾기 +Comment[ku]=Sepanan, panelên kontrolê û servîsan bibîne +Comment[lt]=Rasti programas, valdymo pultus ir tarnybas +Comment[lv]=Meklēt lietotnes, kontroles paneļus un servisus +Comment[mk]=Пронајдете апликации, контролни панели и сервиси +Comment[ml]=പ്രയോഗങ്ങള്‍, നിയന്ത്രണപാനലുകള്‍, സേവനങ്ങള്‍ എന്നിവ കണ്ടുപിടിയ്ക്കുക +Comment[mr]=अनुप्रयोग, नियंत्रण पटल व सेवा शोधा +Comment[nb]=Finn programmer, kontrollpanel og tjenester +Comment[nds]=Programmen, Kuntrullpaneels un Deensten söken +Comment[nl]=Zoek naar programma's, configuratiemodules en diensten +Comment[nn]=Finn program, kontrollpanel og tenester +Comment[or]=ପ୍ରୟୋଗ, ନିୟନ୍ତ୍ରଣ ପଟି ଏବଂ ସର୍ଭିସଗୁଡ଼ିକୁ ଖୋଜନ୍ତୁ +Comment[pa]=ਐਪਲੀਕੇਸ਼ਨ, ਕੰਟਰੋਲ ਪੈਨਲ ਅਤੇ ਸਰਵਿਸਾਂ ਲੱਭੋ +Comment[pl]=Znajdowanie programów, paneli sterowania i usług +Comment[pt]=Procura aplicações, painéis de controlo e serviços +Comment[pt_BR]=Localiza aplicativos, painéis de controle e serviços +Comment[ro]=Găsește aplicații, panouri de control și servicii +Comment[ru]=Поиск приложений и служб +Comment[si]=යෙදුම්, පාළන පුවරු සහ සේවා සොයන්න +Comment[sk]=Hľadanie aplikácií, ovládacích panelov a služieb +Comment[sl]=Najdite programe, nadzorne plošče in storitve +Comment[sr]=Тражите програме, контролне панеле и сервисе +Comment[sr@ijekavian]=Тражите програме, контролне панеле и сервисе +Comment[sr@ijekavianlatin]=Tražite programe, kontrolne panele i servise +Comment[sr@latin]=Tražite programe, kontrolne panele i servise +Comment[sv]=Sök efter program, kontrollpaneler och tjänster +Comment[ta]=Find applications, control panels and services +Comment[te]=అనువర్తనములను, కంట్రోల్ ప్యానల్‍స్ ను మరియు సేవలను కనుగొనుము +Comment[tg]=Ҷустуҷӯи барномаҳо ва хизматҳо +Comment[th]=ค้นหาโปรแกรม, ถาดควบคุม และบริการ +Comment[tr]=Uygulamaları, kontrol panellerini ve servisleri bul +Comment[ug]=پروگرامما، تىزگىن تاختا ۋە مۇلازىمەت ئىزدە +Comment[uk]=Знайти програми, панелі керування та служби +Comment[vi]=Tìm kiếm ứng dụng, bảng thiết lập và dịch vụ +Comment[wa]=Trover des programes, des paneas d' controle et des siervices +Comment[x-test]=xxFind applications, control panels and servicesxx +Comment[zh_CN]=查找应用程序、控制面板和服务 +Comment[zh_TW]=尋找應用程式、控制面板與服務 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=applications-other +X-KDE-Library=krunner_services +X-Plasma-RunnerPhase=first +X-KDE-PluginInfo-Author=Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=services +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-AdvertiseSingleRunnerQueryMode=true diff --git a/plasma/generic/runners/services/servicerunner.cpp b/plasma/generic/runners/services/servicerunner.cpp new file mode 100644 index 00000000..985a09c0 --- /dev/null +++ b/plasma/generic/runners/services/servicerunner.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2006 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "servicerunner.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +ServiceRunner::ServiceRunner(QObject *parent, const QVariantList &args) + : Plasma::AbstractRunner(parent, args) +{ + Q_UNUSED(args) + + setObjectName( QLatin1String("Application" )); + setPriority(AbstractRunner::HighestPriority); + + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds applications whose name or description match :q:"))); +} + +ServiceRunner::~ServiceRunner() +{ +} + +void ServiceRunner::match(Plasma::RunnerContext &context) +{ + const QString term = context.query(); + + QList matches; + QSet seen; + QString query; + + if (term.length() > 1) { + // Search for applications which are executable and case-insensitively match the search term + // See http://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language + // if the following is unclear to you. + query = QString("exist Exec and ('%1' =~ Name)").arg(term); + KService::List services = KServiceTypeTrader::self()->query("Application", query); + + if (!services.isEmpty()) { + //kDebug() << service->name() << "is an exact match!" << service->storageId() << service->exec(); + foreach (const KService::Ptr &service, services) { + if (!service->noDisplay() && service->property("NotShowIn", QVariant::String) != "KDE") { + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::ExactMatch); + setupMatch(service, match); + match.setRelevance(1); + matches << match; + seen.insert(service->storageId()); + seen.insert(service->exec()); + } + } + } + } + + if (!context.isValid()) { + return; + } + + // If the term length is < 3, no real point searching the Keywords and GenericName + if (term.length() < 3) { + query = QString("exist Exec and ( (exist Name and '%1' ~~ Name) or ('%1' ~~ Exec) )").arg(term); + } else { + // Search for applications which are executable and the term case-insensitive matches any of + // * a substring of one of the keywords + // * a substring of the GenericName field + // * a substring of the Name field + // Note that before asking for the content of e.g. Keywords and GenericName we need to ask if + // they exist to prevent a tree evaluation error if they are not defined. + query = QString("exist Exec and ( (exist Keywords and '%1' ~subin Keywords) or (exist GenericName and '%1' ~~ GenericName) or (exist Name and '%1' ~~ Name) or ('%1' ~~ Exec) )").arg(term); + } + + KService::List services = KServiceTypeTrader::self()->query("Application", query); + services += KServiceTypeTrader::self()->query("KCModule", query); + + //kDebug() << "got " << services.count() << " services from " << query; + foreach (const KService::Ptr &service, services) { + if (!context.isValid()) { + return; + } + + if (service->noDisplay()) { + continue; + } + + const QString id = service->storageId(); + const QString name = service->desktopEntryName(); + const QString exec = service->exec(); + + if (seen.contains(id) || seen.contains(exec)) { + //kDebug() << "already seen" << id << exec; + continue; + } + + //kDebug() << "haven't seen" << id << "so processing now"; + seen.insert(id); + seen.insert(exec); + + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::PossibleMatch); + setupMatch(service, match); + qreal relevance(0.6); + + // If the term was < 3 chars and NOT at the beginning of the App's name or Exec, then + // chances are the user doesn't want that app. + if (term.length() < 3) { + if (name.startsWith(term) || exec.startsWith(term)) { + relevance = 0.9; + } else { + continue; + } + } else if (service->name().contains(term, Qt::CaseInsensitive)) { + relevance = 0.8; + + if (service->name().startsWith(term, Qt::CaseInsensitive)) { + relevance += 0.1; + } + } else if (service->genericName().contains(term, Qt::CaseInsensitive)) { + relevance = 0.7; + + if (service->genericName().startsWith(term, Qt::CaseInsensitive)) { + relevance += 0.1; + } + } + + if (service->categories().contains("KDE") || service->serviceTypes().contains("KCModule")) { + //kDebug() << "found a kde thing" << id << match.subtext() << relevance; + if (id.startsWith("kde-")) { + //kDebug() << "old" << service->type(); + if (!service->isApplication()) { + // avoid showing old kcms and what not + continue; + } + + // This is an older version, let's disambiguate it + QString subtext("KDE3"); + + if (!match.subtext().isEmpty()) { + subtext.append(", " + match.subtext()); + } + + match.setSubtext(subtext); + } else { + relevance += .1; + } + } + + //kDebug() << service->name() << "is this relevant:" << relevance; + match.setRelevance(relevance); + matches << match; + } + + //search for applications whose categories contains the query + query = QString("exist Exec and (exist Categories and '%1' ~subin Categories)").arg(term); + services = KServiceTypeTrader::self()->query("Application", query); + + //kDebug() << service->name() << "is an exact match!" << service->storageId() << service->exec(); + foreach (const KService::Ptr &service, services) { + if (!context.isValid()) { + return; + } + + if (!service->noDisplay()) { + QString id = service->storageId(); + QString exec = service->exec(); + if (seen.contains(id) || seen.contains(exec)) { + //kDebug() << "already seen" << id << exec; + continue; + } + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::PossibleMatch); + setupMatch(service, match); + + qreal relevance = 0.6; + if (service->categories().contains("X-KDE-More") || + !service->showInKDE()) { + relevance = 0.5; + } + + if (service->isApplication()) { + relevance += .4; + } + + match.setRelevance(relevance); + matches << match; + } + } + + context.addMatches(term, matches); +} + +void ServiceRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(context); + KService::Ptr service = KService::serviceByStorageId(match.data().toString()); + if (service) { + KRun::run(*service, KUrl::List(), 0); + } +} + +void ServiceRunner::setupMatch(const KService::Ptr &service, Plasma::QueryMatch &match) +{ + const QString name = service->name(); + + match.setText(name); + match.setData(service->storageId()); + + if (!service->genericName().isEmpty() && service->genericName() != name) { + match.setSubtext(service->genericName()); + } else if (!service->comment().isEmpty()) { + match.setSubtext(service->comment()); + } + + if (!service->icon().isEmpty()) { + match.setIcon(KIcon(service->icon())); + } +} + +QMimeData * ServiceRunner::mimeDataForMatch(const Plasma::QueryMatch *match) +{ + KService::Ptr service = KService::serviceByStorageId(match->data().toString()); + if (service) { + QMimeData * result = new QMimeData(); + QList urls; + urls << KUrl(service->entryPath()); + kDebug() << urls; + result->setUrls(urls); + return result; + } + + return 0; +} + +#include "servicerunner.moc" + diff --git a/plasma/generic/runners/services/servicerunner.h b/plasma/generic/runners/services/servicerunner.h new file mode 100644 index 00000000..f7d998d5 --- /dev/null +++ b/plasma/generic/runners/services/servicerunner.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2006 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SERVICERUNNER_H +#define SERVICERUNNER_H + + +#include + +#include + + +/** + * This class looks for matches in the set of .desktop files installed by + * applications. This way the user can type exactly what they see in the + * appications menu and have it start the appropriate app. Essentially anything + * that KService knows about, this runner can launch + */ + +class ServiceRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + ServiceRunner(QObject *parent, const QVariantList &args); + ~ServiceRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + + protected slots: + QMimeData * mimeDataForMatch(const Plasma::QueryMatch *match); + + protected: + void setupMatch(const KService::Ptr &service, Plasma::QueryMatch &action); +}; + +K_EXPORT_PLASMA_RUNNER(services, ServiceRunner) + +#endif + diff --git a/plasma/generic/runners/sessions/CMakeLists.txt b/plasma/generic/runners/sessions/CMakeLists.txt new file mode 100644 index 00000000..816b71db --- /dev/null +++ b/plasma/generic/runners/sessions/CMakeLists.txt @@ -0,0 +1,14 @@ +set(krunner_sessions_SRCS + sessionrunner.cpp +) + +set(screensaver_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/screenlocker/dbus/org.freedesktop.ScreenSaver.xml) +QT4_ADD_DBUS_INTERFACE(krunner_sessions_SRCS ${screensaver_xml} screensaver_interface) + +kde4_add_plugin(krunner_sessions ${krunner_sessions_SRCS}) +target_link_libraries(krunner_sessions ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS} kworkspace) + +install(TARGETS krunner_sessions DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install(FILES plasma-runner-sessions.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/sessions/Messages.sh b/plasma/generic/runners/sessions/Messages.sh new file mode 100755 index 00000000..7fe6ea81 --- /dev/null +++ b/plasma/generic/runners/sessions/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_sessions.pot diff --git a/plasma/generic/runners/sessions/plasma-runner-sessions.desktop b/plasma/generic/runners/sessions/plasma-runner-sessions.desktop new file mode 100644 index 00000000..911be961 --- /dev/null +++ b/plasma/generic/runners/sessions/plasma-runner-sessions.desktop @@ -0,0 +1,164 @@ +[Desktop Entry] +Name=Desktop Sessions +Name[ar]=جلسات سطح المكتب +Name[ast]=Sesiones d'escritoriu +Name[be@latin]=Sesii rabočaha stała +Name[bg]=Сесии +Name[bn]=ডেস্কটপ সেশন +Name[bn_IN]=ডেস্কটপের সেশান +Name[bs]=sesije radne površi +Name[ca]=Sessions d'escriptori +Name[ca@valencia]=Sessions d'escriptori +Name[cs]=Sezení plochy +Name[csb]=Sesëje pùltu +Name[da]=Skrivebordssessioner +Name[de]=Desktop-Sitzungen +Name[el]=Συνεδρίες επιφάνειας εργασίας +Name[en_GB]=Desktop Sessions +Name[eo]=Labortablaj seancoj +Name[es]=Sesiones de escritorio +Name[et]=Töölauaseansid +Name[eu]=Mahaigaineko saioak +Name[fi]=Työpöytäistunnot +Name[fr]=Sessions de bureau +Name[fy]=Buroblêdsesjes +Name[ga]=Seisiúin Deisce +Name[gl]=Sesións do escritorio +Name[gu]=ડેસ્કટોપ સત્રો +Name[he]=הפעלות של שולחן העבודה +Name[hi]=डेस्कटॉप सत्र +Name[hne]=डेस्कटाप सेसन +Name[hr]=Sesije radne površine +Name[hu]=Asztali munkamenetek +Name[ia]=Sessiones de scriptorio +Name[id]=Sesi Desktop +Name[is]=Skjáborðssetur +Name[it]=Sessioni di desktop +Name[ja]=デスクトップセッション +Name[kk]=Үстел сеансы +Name[km]=សម័យ​ផ្ទៃតុ +Name[kn]=ಗಣಕತೆರೆ ಅಧಿವೇಶನಗಳು (ಸೆಶನ್) +Name[ko]=데스크톱 세션 +Name[ku]=Danişînên Sermaseyê +Name[lt]=Darbastalio sesijos +Name[lv]=Darbvirsmas sesijas +Name[mk]=Работни сесии +Name[ml]=പണിയിടത്തിന്റെ പ്രവര്‍ത്തനവേളകള്‍ +Name[mr]=डेस्कटॉप सत्र +Name[nb]=Skrivebordsøkter +Name[nds]=Schriefdischtörns +Name[nl]=Desktopsessies +Name[nn]=Skrivebordsøkter +Name[or]=ଡ଼େସ୍କଟପ ଅଧିବେଶନଗୁଡ଼ିକ +Name[pa]=ਡੈਸਕਟਾਪ ਸ਼ੈਸ਼ਨ +Name[pl]=Sesje pulpitu +Name[pt]=Sessões do Ecrã +Name[pt_BR]=Sessões da área de trabalho +Name[ro]=Sesiuni de birou +Name[ru]=Сеансы +Name[si]=වැඩතල සැසිය +Name[sk]=Sedenia plochy +Name[sl]=Namizne seje +Name[sr]=сесије радне површи +Name[sr@ijekavian]=сесије радне површи +Name[sr@ijekavianlatin]=sesije radne površi +Name[sr@latin]=sesije radne površi +Name[sv]=Skrivbordssessioner +Name[ta]=Desktop Sessions +Name[te]=డెస్‍క్ టాప్ భాగములు +Name[tg]=Амалҳои мизи корӣ +Name[th]=วาระงานของพื้นที่ทำงาน +Name[tr]=Masaüstü Oturumları +Name[ug]=ئۈستەلئۈستى ئەڭگىمە +Name[uk]=Стільничні сеанси +Name[vi]=Phiên làm việc +Name[wa]=Sessions do scribanne +Name[x-test]=xxDesktop Sessionsxx +Name[zh_CN]=桌面会话 +Name[zh_TW]=桌面工作階段 +Comment=Fast user switching +Comment[ar]=تبديل سريع للمستخدم +Comment[ast]=Cambéu rápidu d'usuariu +Comment[be@latin]=Chutkaje pieraklučeńnie karystańnikaŭ +Comment[bg]=Превключване на потребители +Comment[bs]=Brzo prebacivanje korisnika +Comment[ca]=Commutador ràpid d'usuari +Comment[ca@valencia]=Commutador ràpid d'usuari +Comment[cs]=Rychlé přepínání uživatelů +Comment[da]=Hurtig brugerskift +Comment[de]=Schneller Benutzerwechsel +Comment[el]=Γρήγορη αλλαγή χρήστη +Comment[en_GB]=Fast user switching +Comment[eo]=Rapida ŝanĝado de uzantoj +Comment[es]=Cambio rápido de usuario +Comment[et]=Kiire kasutaja vahetamine +Comment[eu]=Erabiltzaile-aldaketa bizkorra +Comment[fi]=Nopea käyttäjänvaihto +Comment[fr]=Commutation rapide d'utilisateurs +Comment[fy]=Flugge brûker wikseljen +Comment[ga]=Athraigh úsáideoirí go tapa +Comment[gl]=Troco rápido de usuario +Comment[gu]=ઝડપી વપરાશકર્તા બદલનાર +Comment[he]=החלפת משתמשים מהירה +Comment[hi]=उपयोक्ता त्वरित बदलें +Comment[hne]=उपयोग करइया के जल्दी अदल-बदल +Comment[hr]=Brza promjena korisnika +Comment[hu]=Felhasználóváltó +Comment[ia]=Commutation rapide de usator +Comment[id]=Penggantian pengguna cepat +Comment[is]=Hröð skipting milli notenda +Comment[it]=Cambio rapido dell'utente +Comment[ja]=ユーザを素早く切り替えます +Comment[kk]=Пайдаланушыны тез ауыстыру +Comment[km]=ការប្ដូរ​អ្នក​ប្រើ​យ៉ាង​លឿន +Comment[kn]=ಶೀಘ್ರ ಬಳಕೆದಾರ ಪರಿವರ್ತನೆ +Comment[ko]=빠른 사용자 전환 +Comment[ku]=Derbasbûna lezgîn a bikarhêner +Comment[lt]=Greitas naudotojų perjungimas +Comment[lv]=Ātra lietotāju pārslēgšana +Comment[mk]=Брзо менување корисници +Comment[ml]=മറ്റൊരു ഉപയോക്താവാകുന്നത് അനുവദിയ്ക്കുന്നതിനുള്ള സംവിധാനം +Comment[mr]=जलद वापरकर्ता बदल +Comment[nb]=Raskt brukerbytte +Comment[nds]=Gau den Bruker wesseln +Comment[nl]=Snel van gebruiker wisselen +Comment[nn]=Kjapt brukarbyte +Comment[or]=ପ୍ରଥମ ଚାଳକ ପରିବର୍ତ୍ତନ ହେଉଅଛି +Comment[pa]=ਤੇਜ਼ ਯੂਜ਼ਰ ਸਵਿੱਚਰ +Comment[pl]=Szybkie przełączanie użytkowników +Comment[pt]=Mudança rápida de utilizador +Comment[pt_BR]=Mudança rápida de usuário +Comment[ro]=Comutare rapidă între utilizatori +Comment[ru]=Быстрое переключение пользователей +Comment[si]=ක්‍ෂණික පරිශීලක මාරුව +Comment[sk]=Rýchle prepínanie užívateľov +Comment[sl]=Hitro preklapljanje uporabnikov +Comment[sr]=Брзо пребацивање корисника +Comment[sr@ijekavian]=Брзо пребацивање корисника +Comment[sr@ijekavianlatin]=Brzo prebacivanje korisnika +Comment[sr@latin]=Brzo prebacivanje korisnika +Comment[sv]=Snabbt användarbyte +Comment[ta]=Fast user switching +Comment[te]=వేగవంతమైన వినియోగదారి మార్పు +Comment[tg]=Мубодилаи фаврии корбар +Comment[th]=สลับผู้ใช้งานด่วน +Comment[tr]=Hızlı kullanıcı değiştirme +Comment[ug]=ئىشلەتكۈچىنى تېز ئالماشتۇرۇش +Comment[uk]=Швидке перемикання користувачів +Comment[vi]=Chuyển đổi người dùng nhanh +Comment[wa]=Candjî rade d' uzeu +Comment[x-test]=xxFast user switchingxx +Comment[zh_CN]=快速用户切换 +Comment[zh_TW]=快速切換使用者 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=system-shutdown +X-KDE-Library=krunner_sessions +X-KDE-PluginInfo-Author=Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=desktopsessions +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-AdvertiseSingleRunnerQueryMode=true + diff --git a/plasma/generic/runners/sessions/sessionrunner.cpp b/plasma/generic/runners/sessions/sessionrunner.cpp new file mode 100644 index 00000000..dde4f390 --- /dev/null +++ b/plasma/generic/runners/sessions/sessionrunner.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2006 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "sessionrunner.h" + + +#include +#include +#include +#include + +#include "kworkspace/kworkspace.h" + +#include "screensaver_interface.h" + +SessionRunner::SessionRunner(QObject *parent, const QVariantList &args) + : Plasma::AbstractRunner(parent, args) +{ + Q_UNUSED(args) + + setObjectName( QLatin1String("Sessions" )); + setPriority(LowPriority); + setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File | + Plasma::RunnerContext::NetworkLocation); + + m_canLogout = KAuthorized::authorizeKAction("logout") && KAuthorized::authorize("logout"); + if (m_canLogout) { + addSyntax(Plasma::RunnerSyntax(i18nc("log out command", "logout"), + i18n("Logs out, exiting the current desktop session"))); + addSyntax(Plasma::RunnerSyntax(i18nc("shutdown computer command", "shutdown"), + i18n("Turns off the computer"))); + } + + if (KAuthorized::authorizeKAction("lock_screen") && m_canLogout) { + addSyntax(Plasma::RunnerSyntax(i18nc("lock screen command", "lock"), + i18n("Locks the current sessions and starts the screen saver"))); + } + + Plasma::RunnerSyntax rebootSyntax(i18nc("restart computer command", "restart"), i18n("Reboots the computer")); + rebootSyntax.addExampleQuery(i18nc("restart computer command", "reboot")); + addSyntax(rebootSyntax); + + m_triggerWord = i18nc("switch user command", "switch"); + addSyntax(Plasma::RunnerSyntax(i18nc("switch user command", "switch :q:"), + i18n("Switches to the active session for the user :q:, " + "or lists all active sessions if :q: is not provided"))); + + Plasma::RunnerSyntax fastUserSwitchSyntax(i18n("switch user"), + i18n("Starts a new session as a different user")); + fastUserSwitchSyntax.addExampleQuery(i18n("new session")); + addSyntax(fastUserSwitchSyntax); + + //"SESSIONS" should not be translated; it's used programmaticaly + setDefaultSyntax(Plasma::RunnerSyntax("SESSIONS", i18n("Lists all sessions"))); + +} + +SessionRunner::~SessionRunner() +{ +} + +void SessionRunner::matchCommands(QList &matches, const QString& term) +{ + if (!m_canLogout) { + return; + } + + if (term.compare(i18nc("log out command","logout"), Qt::CaseInsensitive) == 0 || + term.compare(i18n("log out"), Qt::CaseInsensitive) == 0) { + Plasma::QueryMatch match(this); + match.setText(i18nc("log out command","Logout")); + match.setIcon(KIcon("system-log-out")); + match.setData(LogoutAction); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setRelevance(0.9); + matches << match; + } else if (term.compare(i18nc("restart computer command", "restart"), Qt::CaseInsensitive) == 0 || + term.compare(i18nc("restart computer command", "reboot"), Qt::CaseInsensitive) == 0) { + Plasma::QueryMatch match(this); + match.setText(i18n("Restart the computer")); + match.setIcon(KIcon("system-reboot")); + match.setData(RestartAction); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setRelevance(0.9); + matches << match; + } else if (term.compare(i18nc("shutdown computer command","shutdown"), Qt::CaseInsensitive) == 0) { + Plasma::QueryMatch match(this); + match.setText(i18n("Shutdown the computer")); + match.setIcon(KIcon("system-shutdown")); + match.setData(ShutdownAction); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setRelevance(0.9); + matches << match; + } else if (term.compare(i18nc("lock screen command","lock"), Qt::CaseInsensitive) == 0) { + if (KAuthorized::authorizeKAction("lock_screen")) { + Plasma::QueryMatch match(this); + match.setText(i18n("Lock the screen")); + match.setIcon(KIcon("system-lock-screen")); + match.setData(LockAction); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setRelevance(0.9); + matches << match; + } + } +} + +void SessionRunner::match(Plasma::RunnerContext &context) +{ + const QString term = context.query(); + QString user; + bool matchUser = false; + + QList matches; + + if (term.size() < 3) { + return; + } + + // first compare with SESSIONS. this must *NOT* be translated (i18n) + // as it is used as an internal command trigger (e.g. via d-bus), + // not as a user supplied query. and yes, "Ugh, magic strings" + bool listAll = term.compare("SESSIONS", Qt::CaseInsensitive) == 0 || + term.compare(i18nc("User sessions", "sessions"), Qt::CaseInsensitive) == 0; + + if (!listAll) { + //no luck, try the "switch" user command + if (term.startsWith(m_triggerWord, Qt::CaseInsensitive)) { + user = term.right(term.size() - m_triggerWord.length()).trimmed(); + listAll = user.isEmpty(); + matchUser = !listAll; + } else { + // we know it's not SESSION or "switch ", so let's + // try some other possibilities + matchCommands(matches, term); + } + } + + //kDebug() << "session switching to" << (listAll ? "all sessions" : term); + bool switchUser = listAll || + term.compare(i18n("switch user"), Qt::CaseInsensitive) == 0 || + term.compare(i18n("new session"), Qt::CaseInsensitive) == 0; + + if (switchUser && + KAuthorized::authorizeKAction("start_new_session") && + dm.isSwitchable() && + dm.numReserve() >= 0) { + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setIcon(KIcon("system-switch-user")); + match.setText(i18n("New Session")); + matches << match; + } + + // now add the active sessions + if (listAll || matchUser) { + SessList sessions; + dm.localSessions(sessions); + + foreach (const SessEnt& session, sessions) { + if (!session.vt || session.self) { + continue; + } + + QString name = KDisplayManager::sess2Str(session); + Plasma::QueryMatch::Type type = Plasma::QueryMatch::NoMatch; + qreal relevance = 0.7; + + if (listAll) { + type = Plasma::QueryMatch::ExactMatch; + relevance = 1; + } else if (matchUser) { + if (name.compare(user, Qt::CaseInsensitive) == 0) { + // we need an elif branch here because we don't + // want the last conditional to be checked if !listAll + type = Plasma::QueryMatch::ExactMatch; + relevance = 1; + } else if (name.contains(user, Qt::CaseInsensitive)) { + type = Plasma::QueryMatch::PossibleMatch; + } + } + + if (type != Plasma::QueryMatch::NoMatch) { + Plasma::QueryMatch match(this); + match.setType(type); + match.setRelevance(relevance); + match.setIcon(KIcon("user-identity")); + match.setText(name); + match.setData(QString::number(session.vt)); + matches << match; + } + } + } + + context.addMatches(term, matches); +} + +void SessionRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(context); + if (match.data().type() == QVariant::Int) { + KWorkSpace::ShutdownType type = KWorkSpace::ShutdownTypeDefault; + + switch (match.data().toInt()) { + case LogoutAction: + type = KWorkSpace::ShutdownTypeNone; + break; + case RestartAction: + type = KWorkSpace::ShutdownTypeReboot; + break; + case ShutdownAction: + type = KWorkSpace::ShutdownTypeHalt; + break; + case LockAction: + lock(); + return; + break; + } + + if (type != KWorkSpace::ShutdownTypeDefault) { + KWorkSpace::ShutdownConfirm confirm = KWorkSpace::ShutdownConfirmDefault; + KWorkSpace::requestShutDown(confirm, type); + return; + } + } + + if (!match.data().toString().isEmpty()) { + dm.lockSwitchVT(match.data().toString().toInt()); + return; + } + + //TODO: this message is too verbose and too technical. + int result = KMessageBox::warningContinueCancel( + 0, + i18n("

You have chosen to open another desktop session.
" + "The current session will be hidden " + "and a new login screen will be displayed.
" + "An F-key is assigned to each session; " + "F%1 is usually assigned to the first session, " + "F%2 to the second session and so on. " + "You can switch between sessions by pressing " + "Ctrl, Alt and the appropriate F-key at the same time. " + "Additionally, the KDE Panel and Desktop menus have " + "actions for switching between sessions.

", + 7, 8), + i18n("Warning - New Session"), + KGuiItem(i18n("&Start New Session"), "fork"), + KStandardGuiItem::cancel(), + ":confirmNewSession", + KMessageBox::PlainCaption | KMessageBox::Notify); + + if (result == KMessageBox::Cancel) { + return; + } + + lock(); + dm.startReserve(); +} + +void SessionRunner::lock() +{ + QString interface("org.freedesktop.ScreenSaver"); + org::freedesktop::ScreenSaver screensaver(interface, "/ScreenSaver", + QDBusConnection::sessionBus()); + if (screensaver.isValid()) { + screensaver.Lock(); + } +} + +#include "sessionrunner.moc" diff --git a/plasma/generic/runners/sessions/sessionrunner.h b/plasma/generic/runners/sessions/sessionrunner.h new file mode 100644 index 00000000..04196aa3 --- /dev/null +++ b/plasma/generic/runners/sessions/sessionrunner.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2006 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SESSIONRUNNER_H +#define SESSIONRUNNER_H + +#include +#include + + +/** + * This class provides matches for running sessions as well as + * an action to start a new session, etc. + */ +class SessionRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + SessionRunner(QObject *parent, const QVariantList &args); + ~SessionRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + + enum { LogoutAction = 1, ShutdownAction, RestartAction, LockAction }; + + private: + void lock(); + void matchCommands(QList &matches, const QString& term); + + QString m_triggerWord; + KDisplayManager dm; + bool m_canLogout; +}; + +K_EXPORT_PLASMA_RUNNER(sessions, SessionRunner) + +#endif + diff --git a/plasma/generic/runners/shell/CMakeLists.txt b/plasma/generic/runners/shell/CMakeLists.txt new file mode 100644 index 00000000..9c23d297 --- /dev/null +++ b/plasma/generic/runners/shell/CMakeLists.txt @@ -0,0 +1,12 @@ +set(krunner_shell_SRCS + shellrunner.cpp + shell_config.cpp +) + +kde4_add_ui_files(krunner_shell_SRCS shellOptions.ui) +kde4_add_plugin(krunner_shell ${krunner_shell_SRCS}) +target_link_libraries(krunner_shell ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4_KDESU_LIBS}) + +install(TARGETS krunner_shell DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-runner-shell.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/shell/Messages.sh b/plasma/generic/runners/shell/Messages.sh new file mode 100755 index 00000000..5c826f4b --- /dev/null +++ b/plasma/generic/runners/shell/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma_runner_shell.pot +rm -f rc.cpp diff --git a/plasma/generic/runners/shell/plasma-runner-shell.desktop b/plasma/generic/runners/shell/plasma-runner-shell.desktop new file mode 100644 index 00000000..344677a2 --- /dev/null +++ b/plasma/generic/runners/shell/plasma-runner-shell.desktop @@ -0,0 +1,168 @@ +[Desktop Entry] +Name=Command Line +Name[ar]=سطر الأوامر +Name[ast]=Execución d'órdenes +Name[be@latin]=Zahadny radok +Name[bg]=Команден ред +Name[bn]=কমান্ড লাইন +Name[bn_IN]=কমান্ড-লাইন +Name[bs]=komandna linija +Name[ca]=Línia d'ordres +Name[ca@valencia]=Línia d'ordes +Name[cs]=Příkazový řádek +Name[csb]=Réga pòlétu +Name[da]=Kommandolinje +Name[de]=Befehlszeile +Name[el]=Γραμμή εντολών +Name[en_GB]=Command Line +Name[eo]=Komandlinio +Name[es]=Ejecución de órdenes +Name[et]=Käsurida +Name[eu]=Komando-lerroa +Name[fi]=Komentorivi +Name[fr]=Ligne de commandes +Name[fy]=Kommandorigel +Name[ga]=Líne na nOrduithe +Name[gl]=Execución de ordes +Name[gu]=આદેશ જગ્યા +Name[he]=שורת הפקודה +Name[hi]=कमांड लाइन +Name[hne]=कमांड लाइन +Name[hr]=Naredbena linija +Name[hu]=Parancssor +Name[ia]=Linea de commando +Name[id]=Baris Perintah +Name[is]=Skipanalína +Name[it]=Riga di comando +Name[ja]=コマンドライン +Name[kk]=Команда жолы +Name[km]=បន្ទាត់​ពាក្យ​បញ្ជា +Name[kn]=ಆದೇಶ ತೆರೆ +Name[ko]=명령줄 +Name[ku]=Rêzika Fermanê +Name[lt]=Komandinė eilutė +Name[lv]=Komandrinda +Name[mai]=कमांड लाइन +Name[mk]=Командна линија +Name[ml]=ആജ്ഞാസ്ഥാനം +Name[mr]=आदेश ओळ +Name[nb]=Kommandolinje +Name[nds]=Konsool +Name[nl]=Commandoregel +Name[nn]=Kommandolinje +Name[oc]=Linha de comanda +Name[or]=ନିର୍ଦ୍ଦେଶନାମା +Name[pa]=ਕਮਾਂਡ ਲਾਈਨ +Name[pl]=Wiersz poleceń +Name[pt]=Linha de Comandos +Name[pt_BR]=Linha de comando +Name[ro]=Linie de comandă +Name[ru]=Запуск программ +Name[si]=විධාන රේඛාව +Name[sk]=Príkazový riadok +Name[sl]=Ukazna vrstica +Name[sr]=командна линија +Name[sr@ijekavian]=командна линија +Name[sr@ijekavianlatin]=komandna linija +Name[sr@latin]=komandna linija +Name[sv]=Kommandorad +Name[ta]=Command Line +Name[te]=ఆదేశ వరుస +Name[tg]=Иҷрои фармон +Name[th]=บรรทัดคำสั่ง +Name[tr]=Komut Satırı +Name[ug]=بۇيرۇق قۇرى +Name[uk]=Командний рядок +Name[vi]=Dòng lệnh +Name[wa]=Roye di cmande +Name[x-test]=xxCommand Linexx +Name[zh_CN]=命令行 +Name[zh_TW]=命令列 +Comment=Executes shell commands +Comment[ar]=ينفذ أوامر الصدفة +Comment[ast]=Executa órdenes de la consola +Comment[be@latin]=Vykanańnie zahadaŭ abałonki. +Comment[bg]=Изпълнение на команди на обвивката +Comment[bn]=শেল কমাণ্ড চালায় +Comment[bn_IN]=শেল কমান্ড সঞ্চালনের জন্য প্রয়োগ হবে +Comment[bs]=Izvršavanje naredbi školjke +Comment[ca]=Executa ordres de l'intèrpret d'ordres +Comment[ca@valencia]=Executa ordes de l'intèrpret d'ordes +Comment[cs]=Spouští shellové příkazy +Comment[da]=Kører skal-kommandoer +Comment[de]=Führt Shell-Befehle aus +Comment[el]=Εκτελεί εντολές του κελύφους +Comment[en_GB]=Executes shell commands +Comment[eo]=Plenumas ŝel-komandojn +Comment[es]=Ejecuta órdenes de la consola +Comment[et]=Shellikäskude käivitamine +Comment[eu]=Shell komandoak exekutatzen ditu +Comment[fi]=Suorittaa komentorivikomentoja +Comment[fr]=Exécute des commandes shell +Comment[fy]=Flueskommando's útfiere +Comment[ga]=Rith orduithe blaoisce +Comment[gl]=Executa ordes da shell +Comment[gu]=શૅલ આદેશ ચલાવો +Comment[he]=משמש להרצת פקודות Shell +Comment[hi]=शेल कमांड्स चलाता है +Comment[hne]=सेल कमांड चलाथे +Comment[hr]=Izvodi naredbe ljuske +Comment[hu]=Parancsokat hajt végre terminálban +Comment[ia]=Il exeque commandos de shell +Comment[id]=Eksekusi perintah shell +Comment[is]=Framkvæmir skeljarskipanir +Comment[it]=Esegue comandi della shell +Comment[ja]=シェルコマンドを実行します +Comment[kk]=Қоршау-орта командаларын орындау +Comment[km]=ប្រតិបត្តិ​ពាក្យ​បញ្ជា​សែល +Comment[kn]=ಆದೇಶಗ್ರಾಹಿ (ಶೆಲ್) ಆದೇಶಗಳನ್ನು ಚಾಲಯಿಸುತ್ತದೆ +Comment[ko]=셸 명령 실행 +Comment[ku]=Fermanên Shelê yên xebatî +Comment[lt]=Vykdyti apvalkalo komandas +Comment[lv]=Darbina čaulas komandas +Comment[mk]=Извршува наредби за школка +Comment[ml]=ഷെല്‍ ആജ്ഞകള്‍ നടപ്പിലാക്കുക +Comment[mr]=शेल आदेश चालवितो +Comment[nb]=Kjører skallkommando +Comment[nds]=Föhrt Konsoolbefehlen ut +Comment[nl]=Voert shellcommando's uit +Comment[nn]=Køyr skalkommandoar +Comment[or]=ସେଲ ନିର୍ଦ୍ଦେଶଗୁଡ଼ିକୁ ନିଷ୍ପାଦନ କରନ୍ତୁ +Comment[pa]=ਸ਼ੈੱਲ ਕਮਾਂਡਾਂ ਚਲਾਓ +Comment[pl]=Wykonuje polecenia powłoki +Comment[pt]=Executa comandos da consola +Comment[pt_BR]=Executa comandos do shell +Comment[ro]=Execută comenzi de consolă +Comment[ru]=Запуск исполняемых программ +Comment[si]=ශෙල් විධාන ක්‍රියාකරවන්න +Comment[sk]=Vykonanie príkazov shellu +Comment[sl]=Izvede lupinske ukaze +Comment[sr]=Извршавање наредби шкољке +Comment[sr@ijekavian]=Извршавање наредби шкољке +Comment[sr@ijekavianlatin]=Izvršavanje naredbi školjke +Comment[sr@latin]=Izvršavanje naredbi školjke +Comment[sv]=Kör skalkommandon +Comment[ta]=Executes shell commands +Comment[te]=షెల్ ఆదేశాలను నిర్వర్తిస్తుంది +Comment[tg]=Выполняет команды оболочки +Comment[th]=ประมวลผลคำสั่งของเชลล์ +Comment[tr]=Kabuk komutlarını çalıştırır +Comment[ug]=shell بۇيرۇقنى ئىجرا قىلىدۇ +Comment[uk]=Виконує команди оболонки +Comment[vi]=Thực hiện các lệnh vỏ +Comment[wa]=Enonde des comandes shell +Comment[x-test]=xxExecutes shell commandsxx +Comment[zh_CN]=执行 shell 命令 +Comment[zh_TW]=執行 shell 指令 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=system-run +X-KDE-Library=krunner_shell +X-Plasma-RunnerPhase=first +X-KDE-PluginInfo-Author=Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=shell +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-Plasma-AdvertiseSingleRunnerQueryMode=true +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/runners/shell/shellOptions.ui b/plasma/generic/runners/shell/shellOptions.ui new file mode 100644 index 00000000..83d890b7 --- /dev/null +++ b/plasma/generic/runners/shell/shellOptions.ui @@ -0,0 +1,264 @@ + + + shellOptions + + + + 0 + 0 + 325 + 112 + + + + + 0 + 0 + + + + + 0 + + + 3 + + + + + 3 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 3 + + + + + false + + + + 0 + 0 + + + + Enter the user you want to run the application as here. + + + User&name: + + + leUsername + + + + + + + false + + + + 5 + 0 + + + + Enter the password here for the user you specified above. + + + QLineEdit::Password + + + + + + + false + + + + 0 + 0 + + + + Enter the password here for the user you specified above. + + + Pass&word: + + + lePassword + + + + + + + Check this option if the application you want to run is a text mode application. The application will then be run in a terminal emulator window. + + + Run in &terminal window + + + + + + + false + + + + 5 + 0 + + + + Enter the user you want to run the application as here. + + + + + + + Check this option if you want to run the application with a different user id. Every process has a user id associated with it. This id code determines file access and other permissions. The password of the user is required to do this. + + + Run as a different &user + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+
+ + cbRunInTerminal + cbRunAsOther + leUsername + lePassword + + + + + cbRunAsOther + toggled(bool) + lbUsername + setEnabled(bool) + + + 153 + 59 + + + 96 + 62 + + + + + cbRunAsOther + toggled(bool) + leUsername + setEnabled(bool) + + + 127 + 59 + + + 188 + 62 + + + + + cbRunAsOther + toggled(bool) + lbPassword + setEnabled(bool) + + + 81 + 45 + + + 146 + 101 + + + + + cbRunAsOther + toggled(bool) + lePassword + setEnabled(bool) + + + 114 + 41 + + + 323 + 101 + + + + +
diff --git a/plasma/generic/runners/shell/shell_config.cpp b/plasma/generic/runners/shell/shell_config.cpp new file mode 100644 index 00000000..03efebbd --- /dev/null +++ b/plasma/generic/runners/shell/shell_config.cpp @@ -0,0 +1,61 @@ + +/*************************************************************************** + * Copyright 2008 by Montel Laurent * + * * + * 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 "shell_config.h" + + +#include +#include +#include +#include + +#include + +ShellConfig::ShellConfig(const KConfigGroup &config, QWidget* parent) + : QWidget(parent), + m_config(config) +{ + QHBoxLayout *hboxLayout = new QHBoxLayout(parent); + hboxLayout->addWidget(this); + m_ui.setupUi(this); + +#ifdef Q_OS_UNIX + connect(m_ui.cbRunAsOther, SIGNAL(clicked(bool)), this, SLOT(slotUpdateUser(bool))); +#else + m_ui.cbRunAsOther->hide(); + m_ui.lbUsername->hide(); + m_ui.leUsername->hide(); + m_ui.lbPassword->hide(); + m_ui.lePassword->hide(); +#endif +} + +ShellConfig::~ShellConfig() +{ +} + +void ShellConfig::slotUpdateUser(bool b) +{ + if (b) { + m_ui.leUsername->setFocus(); + } +} + +#include "shell_config.moc" diff --git a/plasma/generic/runners/shell/shell_config.h b/plasma/generic/runners/shell/shell_config.h new file mode 100644 index 00000000..97ae7829 --- /dev/null +++ b/plasma/generic/runners/shell/shell_config.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright 2008 by Montel Laurent * + * * + * 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 SHELLCONFIG_H +#define SHELLCONFIG_H + +#include + +#include + +#include "ui_shellOptions.h" + +class ShellConfig : public QWidget +{ + Q_OBJECT + public: + explicit ShellConfig(const KConfigGroup &config, QWidget* parent = 0); + ~ShellConfig(); + + Ui::shellOptions m_ui; + + protected slots: + void slotUpdateUser(bool); + + private: + KConfigGroup m_config; +}; + +#endif diff --git a/plasma/generic/runners/shell/shellrunner.cpp b/plasma/generic/runners/shell/shellrunner.cpp new file mode 100644 index 00000000..dd24e8fd --- /dev/null +++ b/plasma/generic/runners/shell/shellrunner.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2006 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "shellrunner.h" + +#include +#include + +#include +#include +#ifdef Q_OS_UNIX +#include +#endif +#include +#include +#include +#include +#include +#include + +#include + +#include "shell_config.h" + +ShellRunner::ShellRunner(QObject *parent, const QVariantList &args) + : Plasma::AbstractRunner(parent, args), + m_inTerminal(false), + m_asOtherUser(false) +{ + setObjectName( QLatin1String("Command" )); + setPriority(AbstractRunner::HighestPriority); + setHasRunOptions(true); + m_enabled = KAuthorized::authorizeKAction("run_command") && KAuthorized::authorizeKAction("shell_access"); + setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File | + Plasma::RunnerContext::NetworkLocation | Plasma::RunnerContext::UnknownType | + Plasma::RunnerContext::Help); + + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds commands that match :q:, using common shell syntax"))); +} + +ShellRunner::~ShellRunner() +{ +} + +void ShellRunner::match(Plasma::RunnerContext &context) +{ + if (!m_enabled) { + return; + } + + if (context.type() == Plasma::RunnerContext::Executable || + context.type() == Plasma::RunnerContext::ShellCommand) { + const QString term = context.query(); + Plasma::QueryMatch match(this); + match.setId(term); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setIcon(KIcon("system-run")); + match.setText(i18n("Run %1", term)); + match.setRelevance(0.7); + context.addMatch(term, match); + } +} + +void ShellRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(match); + + // filter match's id to remove runner's name + // as this is the command we want to run + + if (m_enabled) { +#ifdef Q_OS_UNIX + //kDebug() << m_asOtherUser << m_username << m_password; + if (m_asOtherUser && !m_username.isEmpty()) { + //TODO: provide some user feedback on failure + QString exec; + QString args; + if (m_inTerminal) { + // we have to reimplement this from KToolInvocation because we need to use KDESu + KConfigGroup confGroup( KGlobal::config(), "General" ); + exec = confGroup.readPathEntry("TerminalApplication", "konsole"); + if (!exec.isEmpty()) { + if (exec == "konsole") { + args += " --noclose"; + } else if (exec == "xterm") { + args += " -hold"; + } + + args += " -e " + context.query(); + } + } else { + const QStringList commandLine = KShell::splitArgs(context.query(), KShell::TildeExpand); + if (!commandLine.isEmpty()) { + exec = commandLine.at(0); + } + + args = context.query().right(context.query().size() - commandLine.at(0).length()); + } + + if (!exec.isEmpty()) { + exec = KStandardDirs::findExe(exec); + exec.append(args); + if (!exec.isEmpty()) { + KDESu::SuProcess client(m_username.toLocal8Bit(), exec.toLocal8Bit()); + const QByteArray password = m_password.toLocal8Bit(); + //TODO handle errors like wrong password via KNotifications in 4.7 + client.exec(password.constData()); + } + } + } else +#endif + if (m_inTerminal) { + KToolInvocation::invokeTerminal(context.query()); + } else { + KRun::runCommand(context.query(), NULL); + } + } + + // reset for the next run! + m_inTerminal = false; + m_asOtherUser = false; + m_username.clear(); + m_password.clear(); +} + +void ShellRunner::createRunOptions(QWidget *parent) +{ + //TODO: for multiple runners? + //TODO: sync palette on theme changes + ShellConfig *configWidget = new ShellConfig(config(), parent); + + QPalette pal = configWidget->palette(); + Plasma::Theme *theme = Plasma::Theme::defaultTheme(); + pal.setColor(QPalette::Normal, QPalette::Window, theme->color(Plasma::Theme::BackgroundColor)); + pal.setColor(QPalette::Normal, QPalette::WindowText, theme->color(Plasma::Theme::TextColor)); + configWidget->setPalette(pal); + + connect(configWidget->m_ui.cbRunAsOther, SIGNAL(clicked(bool)), this, SLOT(setRunAsOtherUser(bool))); + connect(configWidget->m_ui.cbRunInTerminal, SIGNAL(clicked(bool)), this, SLOT(setRunInTerminal(bool))); + connect(configWidget->m_ui.leUsername, SIGNAL(textChanged(QString)), this, SLOT(setUsername(QString))); + connect(configWidget->m_ui.lePassword, SIGNAL(textChanged(QString)), this, SLOT(setPassword(QString))); +} + +void ShellRunner::setRunAsOtherUser(bool asOtherUser) +{ + m_asOtherUser = asOtherUser; +} + +void ShellRunner::setRunInTerminal(bool runInTerminal) +{ + m_inTerminal = runInTerminal; +} + +void ShellRunner::setUsername(const QString &username) +{ + m_username = username; +} + +void ShellRunner::setPassword(const QString &password) +{ + m_password = password; +} + +#include "shellrunner.moc" diff --git a/plasma/generic/runners/shell/shellrunner.h b/plasma/generic/runners/shell/shellrunner.h new file mode 100644 index 00000000..208f8dc5 --- /dev/null +++ b/plasma/generic/runners/shell/shellrunner.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SHELLRUNNER_H +#define SHELLRUNNER_H + +#include + +class QWidget; + + +/** + * This class runs programs using the literal name of the binary, much as one + * would use at a shell prompt. + */ +class ShellRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + ShellRunner(QObject *parent, const QVariantList &args); + ~ShellRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + void createRunOptions(QWidget *parent); + + private Q_SLOTS: + void setRunAsOtherUser(bool asOtherUser); + void setRunInTerminal(bool runInTerminal); + void setUsername(const QString &username); + void setPassword(const QString &password); + + private: + QString m_username; + QString m_password; + bool m_enabled; + bool m_inTerminal; + bool m_asOtherUser; +}; + +K_EXPORT_PLASMA_RUNNER(shell, ShellRunner) + +#endif diff --git a/plasma/generic/runners/solid/CMakeLists.txt b/plasma/generic/runners/solid/CMakeLists.txt new file mode 100644 index 00000000..4b17c3d9 --- /dev/null +++ b/plasma/generic/runners/solid/CMakeLists.txt @@ -0,0 +1,11 @@ +set(krunner_solid_SRCS + solidrunner.cpp + devicewrapper.cpp +) + +kde4_add_plugin(krunner_solid ${krunner_solid_SRCS}) +target_link_libraries(krunner_solid ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4_SOLID_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS krunner_solid DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install(FILES plasma-runner-solid.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/runners/solid/Messages.sh b/plasma/generic/runners/solid/Messages.sh new file mode 100644 index 00000000..101576f5 --- /dev/null +++ b/plasma/generic/runners/solid/Messages.sh @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_solid.pot + diff --git a/plasma/generic/runners/solid/devicewrapper.cpp b/plasma/generic/runners/solid/devicewrapper.cpp new file mode 100644 index 00000000..176065cc --- /dev/null +++ b/plasma/generic/runners/solid/devicewrapper.cpp @@ -0,0 +1,210 @@ +/************************************************************************** + * Copyright 2009 by Jacopo De Simoi * + * 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 . * + ***************************************************************************/ + +//own +#include "devicewrapper.h" + +//Qt +#include +#include +#include +#include + +//Solid +#include +#include +#include +#include +#include + +//KDE +#include +#include +#include +#include + +//Plasma +#include + +DeviceWrapper::DeviceWrapper(const QString& udi) + : m_device(udi), + m_isStorageAccess(false), + m_isAccessible(false), + m_isEncryptedContainer(false) +{ + m_udi = m_device.udi(); +} + +DeviceWrapper::~DeviceWrapper() +{ +} + +void DeviceWrapper::dataUpdated(const QString &source, Plasma::DataEngine::Data data) +{ + Q_UNUSED(source) + + if (data.isEmpty()) { + return; + } + if (data["text"].isValid()) { + m_actionIds.clear(); + foreach (const QString &desktop, data["predicateFiles"].toStringList()) { + QString filePath = KStandardDirs::locate("data", "solid/actions/" + desktop); + QList services = KDesktopFileActions::userDefinedServices(filePath, true); + + foreach (KServiceAction serviceAction, services) { + QString actionId = id()+'_'+desktop+'_'+serviceAction.name(); + m_actionIds << actionId; + emit registerAction(actionId, serviceAction.icon(), serviceAction.text(), desktop); + } + } + m_isEncryptedContainer = data["isEncryptedContainer"].toBool(); + } else { + if (data["Device Types"].toStringList().contains("Storage Access")) { + m_isStorageAccess = true; + if (data["Accessible"].toBool() == true) { + m_isAccessible = true; + } else { + m_isAccessible = false; + } + } else { + m_isStorageAccess = false; + } + if (data["Device Types"].toStringList().contains("OpticalDisc")) { + m_isOpticalDisc = true; + } else { + m_isOpticalDisc = false; + } + } + + m_emblems = m_device.emblems(); + m_description = m_device.description(); + m_iconName = m_device.icon(); + + emit refreshMatch(m_udi); +} + +QString DeviceWrapper::id() const { + return m_udi; +} + +Solid::Device DeviceWrapper::device() const { + return m_device; +} + +KIcon DeviceWrapper::icon() const { + return KIcon(m_iconName, NULL, m_emblems); +} + +bool DeviceWrapper::isStorageAccess() const { + return m_isStorageAccess; +} + +bool DeviceWrapper::isAccessible() const { + return m_isAccessible; +} + +bool DeviceWrapper::isEncryptedContainer() const { + return m_isEncryptedContainer; +} + +bool DeviceWrapper::isOpticalDisc() const { + return m_isOpticalDisc; +} + +QString DeviceWrapper::description() const { + return m_description; +} + +void DeviceWrapper::setForceEject(bool force) +{ + m_forceEject = force; +} + +QString DeviceWrapper::defaultAction() const { + + QString actionString; + + if (m_isOpticalDisc && m_forceEject) { + actionString = i18n("Eject medium"); + } else if (m_isStorageAccess) { + if (!m_isEncryptedContainer) { + if (!m_isAccessible) { + actionString = i18n("Mount the device"); + } else { + actionString = i18n("Unmount the device"); + } + } else { + if (!m_isAccessible) { + actionString = i18nc("Unlock the encrypted container; will ask for a password; partitions inside will appear as they had been plugged in","Unlock the container"); + } else { + actionString = i18nc("Close the encrypted container; partitions inside will disappear as they had been unplugged", "Lock the container"); + } + } + } else { + actionString = i18n("Eject medium"); + } + return actionString; +} + +void DeviceWrapper::runAction(QAction * action) +{ + if (action) { + QString desktopAction = action->data().toString(); + if (!desktopAction.isEmpty()) { + QStringList desktopFiles; + desktopFiles.append(desktopAction); + QDBusInterface soliduiserver("org.kde.kded", "/modules/soliduiserver", "org.kde.SolidUiServer"); + soliduiserver.asyncCall("showActionsDialog", id(), desktopFiles); + } + } else { + if (isOpticalDisc() && m_forceEject) { + Solid::OpticalDrive *drive = m_device.parent().as(); + if (drive) { + drive->eject(); + } + return; + } + + if (m_device.is()) { + Solid::StorageAccess *access = m_device.as(); + if (access) { + if (access->isAccessible()) { + access->teardown(); + } else { + access->setup(); + } + return; + } + } + + if (isOpticalDisc()) { + Solid::OpticalDrive *drive = m_device.parent().as(); + if (drive) { + drive->eject(); + } + } + } +} + +QStringList DeviceWrapper::actionIds() const +{ + return m_actionIds; +} + +#include "devicewrapper.moc" diff --git a/plasma/generic/runners/solid/devicewrapper.h b/plasma/generic/runners/solid/devicewrapper.h new file mode 100644 index 00000000..c42eded5 --- /dev/null +++ b/plasma/generic/runners/solid/devicewrapper.h @@ -0,0 +1,89 @@ +/************************************************************************** + * Copyright 2009 by Jacopo De Simoi * + * 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 DEVICEWRAPPER_H +#define DEVICEWRAPPER_H + +#include + +#include + +#include + +#include + + +#include + +class DeviceWrapper : public QObject +{ + Q_OBJECT + + public: + DeviceWrapper(const QString& udi); + ~DeviceWrapper(); + + QString id() const; + Solid::Device device() const; + KIcon icon() const; + bool isStorageAccess() const; + bool isAccessible() const; + bool isOpticalDisc() const; + bool isEncryptedContainer() const; + QString description() const; + QString defaultAction() const; + void runAction(QAction *) ; + QStringList actionIds() const; + void setForceEject(bool force); + + signals: + void registerAction(QString &id, QString icon, QString text, QString desktop); + void refreshMatch(QString &id); + + protected slots: + + /** + * slot called when a source of the hotplug engine is updated + * @param source the name of the source + * @param data the data of the source + * + * @internal + **/ + void dataUpdated(const QString &source, Plasma::DataEngine::Data data); + + private: + + Solid::Device m_device; + QString m_iconName; + bool m_isStorageAccess; + bool m_isAccessible; + bool m_isEncryptedContainer; + bool m_isOpticalDisc; + bool m_forceEject; + QString m_description; + QStringList m_actionIds; + // Solid doesn't like multithreading that much + // We cache the informations we need locally so that + // 1) nothing possibly goes wrong when processing a query + // 2) performance++ + + QString m_udi; + QStringList m_emblems; +}; + +#endif //DEVICEWRAPPER_H diff --git a/plasma/generic/runners/solid/plasma-runner-solid.desktop b/plasma/generic/runners/solid/plasma-runner-solid.desktop new file mode 100644 index 00000000..372817b5 --- /dev/null +++ b/plasma/generic/runners/solid/plasma-runner-solid.desktop @@ -0,0 +1,150 @@ +[Desktop Entry] +# ctxt: plasma runner +Name=Devices +Name[ar]=الأجهزة +Name[ast]=Preseos +Name[bg]=Устройства +Name[bn]=ডিভাইস +Name[bs]=uređaji +Name[ca]=Dispositius +Name[ca@valencia]=Dispositius +Name[cs]=Zařízení +Name[csb]=Ùrządzenia +Name[da]=Enheder +Name[de]=Geräte +Name[el]=Συσκευές +Name[en_GB]=Devices +Name[eo]=Aparatoj +Name[es]=Dispositivos +Name[et]=Seadmed +Name[eu]=Gailuak +Name[fa]=دستگاهها +Name[fi]=Laitteet +Name[fr]=Périphériques +Name[fy]=Apparaten +Name[ga]=Gléasanna +Name[gl]=Dispositivos +Name[gu]=ઉપકરણો +Name[he]=התקנים +Name[hi]=औज़ार +Name[hr]=Uređaji +Name[hu]=Eszközök +Name[ia]=Dispositivos +Name[id]=Divais +Name[is]=Tæki +Name[it]=Dispositivi +Name[ja]=デバイス +Name[kk]=Құрылғылар +Name[km]=ឧបករណ៍ +Name[kn]=ಸಾಧನಗಳು +Name[ko]=장치 +Name[lt]=Įrenginiai +Name[lv]=Ierīces +Name[mk]=Уреди +Name[ml]=ഉപകരണങ്ങള്‍ +Name[mr]=साधने +Name[nb]=Enhet +Name[nds]=Reedschappen +Name[nl]=Apparaten +Name[nn]=Einingar +Name[pa]=ਜੰਤਰ +Name[pl]=Urządzenia +Name[pt]=Dispositivos +Name[pt_BR]=Dispositivos +Name[ro]=Dispozitive +Name[ru]=Устройства +Name[si]=මෙවලම් +Name[sk]=Zariadenia +Name[sl]=Naprave +Name[sr]=уређаји +Name[sr@ijekavian]=уређаји +Name[sr@ijekavianlatin]=uređaji +Name[sr@latin]=uređaji +Name[sv]=Enheter +Name[tg]=Дастгоҳҳо +Name[th]=อุปกรณ์ต่าง ๆ +Name[tr]=Aygıtlar +Name[ug]=ئۈسكۈنىلەر +Name[uk]=Пристрої +Name[vi]=Thiết bị +Name[wa]=Éndjins +Name[x-test]=xxDevicesxx +Name[zh_CN]=设备 +Name[zh_TW]=裝置 +Comment=Manage removable devices +Comment[ar]=أدر الأجهزة القابلة للإزالة +Comment[ast]=Xestionar preseos estrayibles +Comment[bn]=অপসারণযোগ্য ডিভাইস ব্যবস্থাপনা +Comment[bs]=Upravljanje uklonjivim uređajima +Comment[ca]=Gestiona dispositius extraïbles +Comment[ca@valencia]=Gestiona dispositius extraïbles +Comment[cs]=Spravovat odpojitelná zařízení +Comment[csb]=Sprôwiôj przenosnyma ùrządzeniama +Comment[da]=Håndtér flytbare enheder +Comment[de]=Wechselmedien verwalten +Comment[el]=Διαχείριση αφαιρούμενων συσκευών +Comment[en_GB]=Manage removable devices +Comment[es]=Gestionar dispositivos extraíbles +Comment[et]=Eemaldatavate seadmete haldamine +Comment[eu]=Kudeatu gailu eramangarriak +Comment[fi]=Hallitse irrotettavia laitteita +Comment[fr]=Gère les périphériques amovibles +Comment[fy]=Utnimbere apparaten beheare +Comment[ga]=Bainistigh gléasanna inbhainte +Comment[gl]=Xestiona os dispositivos extraíbeis +Comment[he]=משמש לניהול התקנים נשלפים +Comment[hr]=Upravlja uklonjivim uređajima +Comment[hu]=Cserélhető eszközök kezelése +Comment[ia]=Gere dispositivos removibile +Comment[id]=Kelola divais dapat dilepas +Comment[is]=Sýsla með fjarlægjanleg tæki +Comment[it]=Gestisci i dispositivi rimovibili +Comment[ja]=リムーバブルデバイスを管理します +Comment[kk]=Ауыстырмалы құрылғыларды басқару +Comment[km]=គ្រប់គ្រង​ឧបករណ៍​ដែល​ចល័ត​បាន +Comment[kn]=ತೆಗೆದು ಹಾಕಬಹುದಾದ ಸಾಧನಗಳನ್ನು ವ್ಯವಸ್ಥಾಪಿಸಿ +Comment[ko]=이동식 장치를 관리합니다 +Comment[lt]=Tvarkyti keičiamuosius įrenginius +Comment[lv]=Pārvaldīt noņemamās iekārtas +Comment[mk]=Ракувајте со подвижните уреди +Comment[ml]=നീക്കം ചെയ്യാവുന്ന ഉപകരണങ്ങള്‍ നോക്കി നടത്തല്‍ +Comment[mr]=काढता येणाऱ्या साधनांचे व्यवस्थापन करा +Comment[nb]=Flyttbar +Comment[nds]=Tuuschbor Reedschappen plegen +Comment[nl]=Verwijderbare apparaten beheren +Comment[nn]=Handter flyttbare einingar +Comment[pa]=ਹਟਾਉਣਯੋਗ ਜੰਤਰ ਪਰਬੰਧ +Comment[pl]=Zarządzanie urządzeniami wymiennymi +Comment[pt]=Gerir os dispositivos removíveis +Comment[pt_BR]=Gerencia dispositivos removíveis +Comment[ro]=Gestionează dispozitive amovibile +Comment[ru]=Управление подключаемыми устройствами +Comment[si]=ඉවත් කල හැකි මෙවලම් කළමනාකරනය කරන්න +Comment[sk]=Správa vymeniteľných zariadení +Comment[sl]=Upravljanje odstranljivih naprav +Comment[sr]=Управљање уклоњивим уређајима +Comment[sr@ijekavian]=Управљање уклоњивим уређајима +Comment[sr@ijekavianlatin]=Upravljanje uklonjivim uređajima +Comment[sr@latin]=Upravljanje uklonjivim uređajima +Comment[sv]=Hantera flyttbara enheter +Comment[tg]=Идоракунии дастгоҳҳои ҷудошаванда +Comment[th]=จัดการอุปกรณ์ที่สามารถถอด/เสียบได้ +Comment[tr]=Çıkarılabilir aygıtları yönet +Comment[ug]=كۆچمە ئۈسكۈنىلەرنى باشقۇرۇش +Comment[uk]=Керування портативними пристроями +Comment[vi]=Quản lý thiết bị gắn ngoài +Comment[wa]=Manaedjî oiståves éndjins +Comment[x-test]=xxManage removable devicesxx +Comment[zh_CN]=管理移动设备 +Comment[zh_TW]=管理可移除裝置 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=device-notifier +X-KDE-Library=krunner_solid +X-KDE-PluginInfo-Author=Jacopo De Simoi +X-KDE-PluginInfo-Email=wilderkde@gmail.com +X-KDE-PluginInfo-Name=solid +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-AdvertiseSingleRunnerQueryMode=true diff --git a/plasma/generic/runners/solid/solidrunner.cpp b/plasma/generic/runners/solid/solidrunner.cpp new file mode 100644 index 00000000..c6266523 --- /dev/null +++ b/plasma/generic/runners/solid/solidrunner.cpp @@ -0,0 +1,286 @@ +/*************************************************************************** + * Copyright 2009 by Jacopo De Simoi * + * 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 . * + ***************************************************************************/ + +//own +#include "solidrunner.h" +#include "devicewrapper.h" + +//Qt +#include + +//KDE +#include + +//Plasma +#include +#include + +//Solid +#include + +using namespace Plasma; + +SolidRunner::SolidRunner(QObject* parent, const QVariantList& args) + : AbstractRunner(parent, args), + m_deviceList() +{ + Q_UNUSED(args) + setObjectName( QLatin1String("Solid" )); + + m_engineManager = Plasma::DataEngineManager::self(); + + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds devices whose name match :q:"))); + + setDefaultSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "device"), + i18n("Lists all devices and allows them to be mounted, unmounted or ejected."))); + addSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "mount"), + i18n("Lists all devices which can be mounted, and allows them to be mounted."))); + addSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "unlock"), + i18n("Lists all encrypted devices which can be unlocked, and allows them to be unlocked."))); + addSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "unmount"), + i18n("Lists all devices which can be unmounted, and allows them to be unmounted."))); + addSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "lock"), + i18n("Lists all encrypted devices which can be locked, and allows them to be locked."))); + + addSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "eject"), + i18n("Lists all devices which can be ejected, and allows them to be ejected."))); + +} + +SolidRunner::~SolidRunner() +{ +} + +void SolidRunner::init() +{ + + m_hotplugEngine = dataEngine("hotplug"); + m_solidDeviceEngine = dataEngine("soliddevice"); + + //connect to engine when a device is plugged + connect(m_hotplugEngine, SIGNAL(sourceAdded(QString)), + this, SLOT(onSourceAdded(QString))); + connect(m_hotplugEngine, SIGNAL(sourceRemoved(QString)), + this, SLOT(onSourceRemoved(QString))); + fillPreviousDevices(); +} + +void SolidRunner::cleanActionsForDevice(DeviceWrapper * dev) +{ + const QStringList actionIds = dev->actionIds(); + if (!actionIds.isEmpty()) { + foreach (const QString& id, actionIds) { + removeAction(id); + } + } +} + +QList SolidRunner::actionsForMatch(const Plasma::QueryMatch &match) +{ + QList actions; + + DeviceWrapper* dev = m_deviceList.value(match.data().toString()); + if (dev) { + QStringList actionIds = dev->actionIds(); + if (!actionIds.isEmpty()) { + foreach (const QString& id, actionIds) { + actions << action(id); + } + } + } + return actions; +} + +void SolidRunner::match(Plasma::RunnerContext& context) +{ + m_currentContext = context; + createOrUpdateMatches(m_deviceList.keys()); +} + +void SolidRunner::createOrUpdateMatches(const QStringList &udiList) +{ + const QString term = m_currentContext.query(); + + if (!m_currentContext.isValid()) { + return; + } + + if (!m_currentContext.singleRunnerQueryMode() && (term.length() < 3)) { + return; + } + QList matches; + + // keyword match: when term starts with "device" we list all devices + QStringList keywords = term.split(" "); + QString deviceDescription; + bool onlyMounted = false; + bool onlyMountable = false; + bool onlyEncrypted = false; + bool onlyOptical = false; + bool forceEject = false; + bool showDevices = false; + if (keywords[0].startsWith(i18nc("Note this is a KRunner keyword", "device") , Qt::CaseInsensitive)) { + showDevices = true; + keywords.removeFirst(); + } + + if (!keywords.isEmpty()) { + if (keywords[0].startsWith(i18nc("Note this is a KRunner keyword", "mount") , Qt::CaseInsensitive)) { + showDevices = true; + onlyMountable = true; + keywords.removeFirst(); + } else if (keywords[0].startsWith(i18nc("Note this is a KRunner keyword", "unmount") , Qt::CaseInsensitive)) { + showDevices = true; + onlyMounted = true; + keywords.removeFirst(); + } else if (keywords[0].startsWith(i18nc("Note this is a KRunner keyword", "eject") , Qt::CaseInsensitive)) { + showDevices = true; + onlyOptical = true; + forceEject = true; + keywords.removeFirst(); + } else if (keywords[0].startsWith(i18nc("Note this is a KRunner keyword", "unlock") , Qt::CaseInsensitive)) { + showDevices = true; + onlyMountable = true; + onlyEncrypted = true; + keywords.removeFirst(); + } else if (keywords[0].startsWith(i18nc("Note this is a KRunner keyword", "lock") , Qt::CaseInsensitive)) { + showDevices = true; + onlyMounted = true; + onlyEncrypted = true; + keywords.removeFirst(); + } + } + + if (!keywords.isEmpty()) { + deviceDescription = keywords[0]; + } + + foreach (const QString& udi, udiList) { + DeviceWrapper * dev = m_deviceList.value(udi); + if ((deviceDescription.isEmpty() && showDevices) || dev->description().contains(deviceDescription, Qt::CaseInsensitive)) { + // This is getting quite messy indeed + if (((!onlyEncrypted) || (onlyEncrypted && dev->isEncryptedContainer())) && + ((!onlyOptical) || (onlyOptical && dev->isOpticalDisc())) && + ((onlyMounted && dev->isAccessible()) || + (onlyMountable && dev->isStorageAccess() && !dev->isAccessible()) || + (!onlyMounted && !onlyMountable))) { + dev->setForceEject(forceEject); + Plasma::QueryMatch match = deviceMatch(dev); + if (dev->description().compare(deviceDescription, Qt::CaseInsensitive)) { + match.setType(Plasma::QueryMatch::ExactMatch); + } else if (deviceDescription.isEmpty()) { + match.setType(Plasma::QueryMatch::PossibleMatch); + } else { + match.setType(Plasma::QueryMatch::CompletionMatch); + } + matches << match; + } + } + } + + if (!matches.isEmpty()) { + m_currentContext.addMatches(term, matches); + } +} + +Plasma::QueryMatch SolidRunner::deviceMatch(DeviceWrapper * device) +{ + Plasma::QueryMatch match(this); + match.setId(device->id()); + match.setData(device->id()); + match.setIcon(device->icon()); + match.setText(device->description()); + + match.setSubtext(device->defaultAction()); + + //Put them in order such that the last added device is on top. + match.setRelevance(0.5+0.1*qreal(m_udiOrderedList.indexOf(device->id()))/qreal(m_udiOrderedList.count())); + + return match; +} + +void SolidRunner::run(const Plasma::RunnerContext& context, const Plasma::QueryMatch& match) +{ + Q_UNUSED(context) + + DeviceWrapper *device = m_deviceList.value(match.data().toString()); + if (device) { + device->runAction(match.selectedAction()); + } +} + +void SolidRunner::registerAction(QString &id, QString icon, QString text, QString desktop) +{ + QAction* action = addAction(id, KIcon(icon), text); + action->setData(desktop); +} + +void SolidRunner::refreshMatch(QString &id) +{ + if (!m_currentContext.isValid()) { + return; + } + + QueryMatch match(this); + match.setId(id); + m_currentContext.removeMatch(match.id()); + QStringList deviceList; + deviceList << id; + createOrUpdateMatches(deviceList); +} + +void SolidRunner::onSourceAdded(const QString &name) +{ + DeviceWrapper * device = new DeviceWrapper(name); + connect(device, SIGNAL(registerAction(QString&,QString,QString,QString)), + this, SLOT(registerAction(QString&,QString,QString,QString))); + connect(device, SIGNAL(refreshMatch(QString&)), this, SLOT(refreshMatch(QString&))); + + m_deviceList.insert(name, device); + m_udiOrderedList << name; + m_hotplugEngine->connectSource(name, device); + m_solidDeviceEngine->connectSource(name, device); +} + +void SolidRunner::onSourceRemoved(const QString &name) +{ + DeviceWrapper * device = m_deviceList.value(name); + if (device) { + m_hotplugEngine->disconnectSource(name, device); + m_solidDeviceEngine->disconnectSource(name, device); + disconnect(device, 0, this, 0); + cleanActionsForDevice(device); + m_deviceList.remove(name); + m_udiOrderedList.removeAll(name); + if (m_currentContext.isValid()) { + QueryMatch match(this); + match.setId(device->id()); + m_currentContext.removeMatch(match.id()); + } + delete device; + } +} + +void SolidRunner::fillPreviousDevices() +{ + foreach (const QString &source, m_hotplugEngine->sources()) { + onSourceAdded(source); + } +} + +#include "solidrunner.moc" diff --git a/plasma/generic/runners/solid/solidrunner.h b/plasma/generic/runners/solid/solidrunner.h new file mode 100644 index 00000000..beac2a85 --- /dev/null +++ b/plasma/generic/runners/solid/solidrunner.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright 2009 by Jacopo De Simoi * + * * + * 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 SOLIDRUNNER_H +#define SOLIDRUNNER_H + +#include + +namespace Plasma { + class DataEngine; + class DataEngineManager; + class RunnerContext; +} + +class DeviceWrapper; + +class SolidRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + SolidRunner(QObject* parent, const QVariantList &args); + ~SolidRunner(); + + virtual void match(Plasma::RunnerContext& context); + virtual void run(const Plasma::RunnerContext& context, const Plasma::QueryMatch& match); + + + protected: + QList actionsForMatch(const Plasma::QueryMatch &match); + + protected slots: + + void init(); + void onSourceAdded(const QString &name); + void onSourceRemoved(const QString &name); + + private slots: + void registerAction(QString &id, QString icon, QString text, QString desktop); + void refreshMatch(QString &id); + + private: + + void fillPreviousDevices(); + void cleanActionsForDevice(DeviceWrapper *); + void createOrUpdateMatches(const QStringList &udiList); + + Plasma::QueryMatch deviceMatch(DeviceWrapper * device); + + Plasma::DataEngine *m_hotplugEngine; + Plasma::DataEngine *m_solidDeviceEngine; + + QHash m_deviceList; + QStringList m_udiOrderedList; + Plasma::DataEngineManager* m_engineManager; + Plasma::RunnerContext m_currentContext; +}; + +K_EXPORT_PLASMA_RUNNER(solid, SolidRunner) + +#endif // SOLIDRUNNER_H diff --git a/plasma/generic/runners/webshortcuts/CMakeLists.txt b/plasma/generic/runners/webshortcuts/CMakeLists.txt new file mode 100644 index 00000000..a6da726d --- /dev/null +++ b/plasma/generic/runners/webshortcuts/CMakeLists.txt @@ -0,0 +1,11 @@ +set(krunner_webshortcuts_SRCS + webshortcutrunner.cpp +) + +kde4_add_plugin(krunner_webshortcuts ${krunner_webshortcuts_SRCS}) +target_link_libraries(krunner_webshortcuts ${KDE4_KIO_LIBS} ${KDE4_PLASMA_LIBS}) + +install(TARGETS krunner_webshortcuts DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install(FILES plasma-runner-webshortcuts.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/runners/webshortcuts/Messages.sh b/plasma/generic/runners/webshortcuts/Messages.sh new file mode 100755 index 00000000..52acdd12 --- /dev/null +++ b/plasma/generic/runners/webshortcuts/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_webshortcuts.pot diff --git a/plasma/generic/runners/webshortcuts/plasma-runner-webshortcuts.desktop b/plasma/generic/runners/webshortcuts/plasma-runner-webshortcuts.desktop new file mode 100644 index 00000000..89db96cb --- /dev/null +++ b/plasma/generic/runners/webshortcuts/plasma-runner-webshortcuts.desktop @@ -0,0 +1,129 @@ +[Desktop Entry] +# ctxt: plasma runner +Name=Web Shortcuts +Name[ar]=اختصارات الوِب +Name[ast]=Accesos rápidos pa web +Name[bg]=Уеб отметки +Name[bn]=ওয়েব শর্টকাট +Name[bs]=veb prečice +Name[ca]=Dreceres web +Name[ca@valencia]=Dreceres web +Name[cs]=Webové zkratky +Name[csb]=Sécowé skrodzënë +Name[da]=Webgenveje +Name[de]=Web-Kürzel +Name[el]=Συντομεύσεις ιστού +Name[en_GB]=Web Shortcuts +Name[eo]=Web Shortcuts +Name[es]=Accesos rápidos para web +Name[et]=Veebi kiirkorraldused +Name[eu]=Web-eko lasterbideak +Name[fa]=میان‌برهای وب +Name[fi]=WWW-pikavalinnat +Name[fr]=Raccourcis Web +Name[fy]=Webskeakels +Name[ga]=Aicearraí Gréasáin +Name[gl]=Atallos web +Name[gu]=વેબ ટૂંકાણો +Name[he]=קיצורי דרך אינטרנטיים +Name[hi]=वेब शॉर्टकट +Name[hr]=Internetski prečaci +Name[hu]=Keresési azonosítók +Name[ia]=Vias breve de Web +Name[id]=Jalan Pintas Web +Name[is]=Vefskammstafanir +Name[it]=Scorciatoie del Web +Name[ja]=ウェブショートカット +Name[kk]=Веб қысқартулары +Name[km]=ផ្លូវកាត់​បណ្ដាញ​ +Name[kn]=ಜಾಲ ಶೀಘ್ರಮಾರ್ಗಗಳು (ಶಾರ್ಟ್ ಕಟ್) +Name[ko]=웹 바로 가기 +Name[lt]=Žiniatinklio trumpės +Name[lv]=Ātrās meklēšanas īsceļi +Name[mk]=Интернет-кратенки +Name[ml]=വെബിലെ കുറക്കുവഴികള്‍ +Name[mr]=वेब शॉर्टकट +Name[nb]=Nettsnarveier +Name[nds]=Söökafkörten +Name[nl]=Websnelkoppelingen +Name[nn]=Vevsnarvegar +Name[pa]=ਵੈਬ ਸ਼ਾਰਟਕੱਟ +Name[pl]=Skróty sieciowe +Name[pt]=Atalhos Web +Name[pt_BR]=Atalhos da Web +Name[ro]=Acceleratori web +Name[ru]=Сокращения +Name[si]=ජාල කෙටිමං +Name[sk]=Webové skratky +Name[sl]=Spletne bližnjice +Name[sr]=веб пречице +Name[sr@ijekavian]=веб пречице +Name[sr@ijekavianlatin]=veb prečice +Name[sr@latin]=veb prečice +Name[sv]=Webbgenvägar +Name[tg]=Тугмаҳои тез +Name[th]=ทางลัดถึงเว็บ +Name[tr]=Web Kısayolları +Name[ug]=تور تېزلەتمىسى +Name[uk]=Вебскорочення +Name[wa]=Rascourtis waibe +Name[x-test]=xxWeb Shortcutsxx +Name[zh_CN]=网页快捷方式 +Name[zh_TW]=網頁捷徑 +Comment=Allows user to use Konqueror's web shortcuts +Comment[bs]=Dozvoli koristenje Koquerorovih web prečica +Comment[ca]=Permet que l'usuari utilitzi les dreceres web del Konqueror +Comment[ca@valencia]=Permet que l'usuari utilitze les dreceres web del Konqueror +Comment[cs]=Umožňuje používat webové zkratky Konqueroru +Comment[da]=Lader brugeren anvende Konquerors webgenveje +Comment[de]=Ermöglicht die Verwendung von Web-Kürzeln in Konqueror +Comment[el]=Επιτρέπει τη χρήση συντομεύσεων ιστού του Konqueror +Comment[en_GB]=Allows user to use Konqueror's web shortcuts +Comment[es]=Permite al usuario usar accesos rápidos web de Konqueror +Comment[et]=Võimaldab kasutajal kasutada Konquerori veebikiirkorraldusi +Comment[eu]=Konqueror-en web-eko lasterbideak erabiltzeko aukera ematen dio erabiltzaileari +Comment[fi]=Mahdollistaa Konquerorin WWW-pikavalintojen käytön +Comment[fr]=Permet d'utiliser les raccourcis Web de Konqueror +Comment[ga]=Ceadaigh don úsáideoir aicearraí Gréasáin de chuid Konqueror a úsáid +Comment[gl]=Permítelle ao usuario empregar os atallos web de Konqueror +Comment[he]=מאפשר למשתמש להשתמש בקיצורי דרך אינטרנטיים של Konqueror +Comment[hu]=Lehetővé teszi a felhasználónak a Konqueror kereső azonosítóinak használatát +Comment[ia]=Il permitte al usator de usar vias breve de Web de Konqueror +Comment[it]=Permette all'utente di usare le scorciatoie del Web di Konqueror +Comment[kk]=Konqueror-дың Веб қысқармаларын пайдалануға мүмкіндік беру +Comment[km]=អនុញ្ញាត​ឲ្យ​អ្នកប្រើ​ ប្រើ​ផ្លូវកាត់​បណ្ដាញ​របស់ Konqueror +Comment[ko]=Konqueror 웹 바로 가기 사용 허용 +Comment[lt]=Leidžia naudotojui naudoti Konqueror žiniatinklio nuorodas +Comment[mr]=कॉन्कररचे वेब शार्टकट वापरण्यास वापरकर्त्यास परवानगी देतो +Comment[nb]=Lar brukeren benytte nettsnarveier i Konqueror +Comment[nds]=Lett den Bruker Konqueror sien Söökafkörten bruken +Comment[nl]=Maakt het mogelijk om webkoppelingen van Konqueror te gebruiken +Comment[pa]=ਯੂਜ਼ਰਾਂ ਨੂੰ ਕੋਨਕਿਉਰੋਰ ਦੇ ਵੈੱਬ ਸ਼ਾਰਟਕੱਟ ਵਰਤਣੇ ਮਨਜ਼ੂਰ +Comment[pl]=Pozwala użytkownikowi na użycie skrótów sieciowych Konquerora +Comment[pt]=Permite ao utilizador usar os atalhos Web do Konqueror +Comment[pt_BR]=Permite ao usuário usar os atalhos da Web do Konqueror +Comment[ro]=Permite utilizatorului să folosească scurtăturile web ale Konqueror +Comment[ru]=Использование веб-сокращений Konqueror +Comment[sk]=Umožňuje používateľovi použiť webové skratky Konquerora +Comment[sl]=Omogoča uporabo spletnih bližnjic iz Konquerorja +Comment[sr]=Употребите К‑освајачеве веб пречице +Comment[sr@ijekavian]=Употријебите К‑освајачеве веб пречице +Comment[sr@ijekavianlatin]=Upotrijebite K‑osvajačeve veb prečice +Comment[sr@latin]=Upotrebite K‑osvajačeve veb prečice +Comment[sv]=Låter användaren utnyttja webbgenvägar i Konqueror +Comment[tr]=Kullanıcının Konqueror Web kısayollarını kullanabilmesini sağlar +Comment[uk]=Надає змогу використовувати вебскорочення Konqueror +Comment[x-test]=xxAllows user to use Konqueror's web shortcutsxx +Comment[zh_CN]=允许用户使用 Konqueror 的网页快捷键 +Comment[zh_TW]=允許使用者使用 Konqueror 的網頁捷徑 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=internet-web-browser +X-KDE-Library=krunner_webshortcuts +X-KDE-PluginInfo-Author=Teemu Rytilahti +X-KDE-PluginInfo-Email=tpr@iki.fi +X-KDE-PluginInfo-Name=webshortcuts +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-Plasma-AdvertiseSingleRunnerQueryMode=true +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/generic/runners/webshortcuts/webshortcutrunner.cpp b/plasma/generic/runners/webshortcuts/webshortcutrunner.cpp new file mode 100644 index 00000000..2777c705 --- /dev/null +++ b/plasma/generic/runners/webshortcuts/webshortcutrunner.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2007 Teemu Rytilahti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "webshortcutrunner.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +WebshortcutRunner::WebshortcutRunner(QObject *parent, const QVariantList& args) + : Plasma::AbstractRunner(parent, args), + m_match(this), m_filterBeforeRun(false) +{ + Q_UNUSED(args); + setObjectName( QLatin1String("Web Shortcut" )); + setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File | Plasma::RunnerContext::Executable); + + m_icon = KIcon("internet-web-browser"); + + m_match.setType(Plasma::QueryMatch::ExactMatch); + m_match.setRelevance(0.9); + + // Listen for KUriFilter plugin config changes and update state... + QDBusConnection sessionDbus = QDBusConnection::sessionBus(); + sessionDbus.connect(QString(), "/", "org.kde.KUriFilterPlugin", + "configure", this, SLOT(readFiltersConfig())); + + connect(this, SIGNAL(teardown()), this, SLOT(resetState())); + readFiltersConfig(); +} + +WebshortcutRunner::~WebshortcutRunner() +{ +} + +void WebshortcutRunner::readFiltersConfig() +{ + // Make sure that the searchEngines cache, etc. is refreshed when the config file is changed. + loadSyntaxes(); +} + +void WebshortcutRunner::loadSyntaxes() +{ + KUriFilterData filterData (QLatin1String(":q")); + filterData.setSearchFilteringOptions(KUriFilterData::RetrieveAvailableSearchProvidersOnly); + if (KUriFilter::self()->filterSearchUri(filterData, KUriFilter::NormalTextFilter)) { + m_delimiter = filterData.searchTermSeparator(); + } + + //kDebug() << "keyword delimiter:" << m_delimiter; + //kDebug() << "search providers:" << filterData.preferredSearchProviders(); + + QList syns; + Q_FOREACH (const QString &provider, filterData.preferredSearchProviders()) { + //kDebug() << "checking out" << provider; + Plasma::RunnerSyntax s(filterData.queryForPreferredSearchProvider(provider), /*":q:",*/ + i18n("Opens \"%1\" in a web browser with the query :q:.", provider)); + syns << s; + } + + setSyntaxes(syns); +} + +void WebshortcutRunner::resetState() +{ + kDebug(); + m_lastFailedKey.clear(); + m_lastProvider.clear(); + m_lastKey.clear(); +} + +void WebshortcutRunner::match(Plasma::RunnerContext &context) +{ + const QString term = context.query(); + + if (term.length() < 3 || !term.contains(m_delimiter)) + return; + + // kDebug() << "checking term" << term; + + const int delimIndex = term.indexOf(m_delimiter); + if (delimIndex == term.length() - 1) + return; + + const QString key = term.left(delimIndex); + + if (key == m_lastFailedKey) { + return; // we already know it's going to suck ;) + } + + if (!context.isValid()) { + kDebug() << "invalid context"; + return; + } + + // Do a fake user feedback text update if the keyword has not changed. + // There is no point filtering the request on every key stroke. + // filtering + if (m_lastKey == key) { + m_filterBeforeRun = true; + m_match.setText(i18n("Search %1 for %2", m_lastProvider, term.mid(delimIndex + 1))); + context.addMatch(term, m_match); + return; + } + + KUriFilterData filterData(term); + if (!KUriFilter::self()->filterSearchUri(filterData, KUriFilter::WebShortcutFilter)) { + m_lastFailedKey = key; + return; + } + + m_lastFailedKey.clear(); + m_lastKey = key; + m_lastProvider = filterData.searchProvider(); + + m_match.setData(filterData.uri().url()); + m_match.setId("WebShortcut:" + key); + + m_match.setIcon(KIcon(filterData.iconName())); + m_match.setText(i18n("Search %1 for %2", m_lastProvider, filterData.searchTerm())); + context.addMatch(term, m_match); +} + +void WebshortcutRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + QString location; + + //kDebug() << "filter before run?" << m_filterBeforeRun; + if (m_filterBeforeRun) { + m_filterBeforeRun = false; + //kDebug() << "look up webshortcut:" << context.query(); + KUriFilterData filterData (context.query()); + if (KUriFilter::self()->filterSearchUri(filterData, KUriFilter::WebShortcutFilter)) + location = filterData.uri().url(); + } else { + location = match.data().toString(); + } + + //kDebug() << location; + if (!location.isEmpty()) { + KToolInvocation::invokeBrowser(location); + } +} + +#include "webshortcutrunner.moc" diff --git a/plasma/generic/runners/webshortcuts/webshortcutrunner.h b/plasma/generic/runners/webshortcuts/webshortcutrunner.h new file mode 100644 index 00000000..73339c47 --- /dev/null +++ b/plasma/generic/runners/webshortcuts/webshortcutrunner.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007 Teemu Rytilahti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WEBSHORTCUTRUNNER_H +#define WEBSHORTCUTRUNNER_H + +#include + +#include + +class WebshortcutRunner : public Plasma::AbstractRunner { + Q_OBJECT + + public: + WebshortcutRunner( QObject *parent, const QVariantList& args ); + ~WebshortcutRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match); + + private: + void loadSyntaxes(); + + private Q_SLOTS: + void readFiltersConfig(); + void resetState(); + + private: + KIcon m_icon; + Plasma::QueryMatch m_match; + bool m_filterBeforeRun; + + QChar m_delimiter; + QString m_lastFailedKey; + QString m_lastKey; + QString m_lastProvider; +}; + +K_EXPORT_PLASMA_RUNNER(webshortcuts, WebshortcutRunner) + +#endif diff --git a/plasma/generic/runners/windowedwidgets/CMakeLists.txt b/plasma/generic/runners/windowedwidgets/CMakeLists.txt new file mode 100644 index 00000000..f17376c7 --- /dev/null +++ b/plasma/generic/runners/windowedwidgets/CMakeLists.txt @@ -0,0 +1,13 @@ +project(windowedwidgetsrunner) + +include_directories( ${QT_INCLUDES} ${KDE4_INCLUDES} ) + +set(krunner_windowedwidgets_SRCS + windowedwidgetsrunner.cpp +) + +kde4_add_plugin(krunner_windowedwidgets ${krunner_windowedwidgets_SRCS}) +target_link_libraries(krunner_windowedwidgets ${KDE4_PLASMA_LIBS}) + +install(TARGETS krunner_windowedwidgets DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-runner-windowedwidgets.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/runners/windowedwidgets/Messages.sh b/plasma/generic/runners/windowedwidgets/Messages.sh new file mode 100644 index 00000000..2ecdc58b --- /dev/null +++ b/plasma/generic/runners/windowedwidgets/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_windowedwidgets.pot diff --git a/plasma/generic/runners/windowedwidgets/plasma-runner-windowedwidgets.desktop b/plasma/generic/runners/windowedwidgets/plasma-runner-windowedwidgets.desktop new file mode 100644 index 00000000..167adcb3 --- /dev/null +++ b/plasma/generic/runners/windowedwidgets/plasma-runner-windowedwidgets.desktop @@ -0,0 +1,136 @@ +[Desktop Entry] +Name=Windowed widgets +Name[ar]=ودجات مُنوفذة +Name[ast]=Componentes en ventana +Name[bg]=Джаджи като прозорци +Name[bs]=Grafičke kontrole s prozorom +Name[ca]=Estris en finestres +Name[ca@valencia]=Estris en finestres +Name[cs]=Widgety v okně +Name[da]=Widgets som vinduer +Name[de]=Eigenständige Miniprogramme +Name[el]=Συστατικά σε παράθυρο +Name[en_GB]=Windowed widgets +Name[es]=Componentes en ventana +Name[et]=Akendesse paigutatavad vidinad +Name[eu]=Trepeta leihodunak +Name[fi]=Ikkunoidut sovelmat +Name[fr]=Composants graphiques fenêtrés +Name[ga]=Giuirléidí i bhfuinneoga +Name[gl]=Widgets en xanelas +Name[he]=ווידג׳טים בחלון +Name[hi]=विंडोज़ विडजेट +Name[hr]=Widgeti u prozorima +Name[hu]=Önálló widgetek +Name[ia]=Widgets (elemento graphic) in le fenestra +Name[id]=Widget jendela +Name[is]=Græjur í gluggum +Name[it]=Oggetti fenestrabili +Name[ja]=ウィンドウ化されたウィジェット +Name[kk]=Терезелерлі виджеттер +Name[km]=ធាតុក្រាហ្វិក​​វីនដូ +Name[kn]=ವಿಂಡೋವ್ಡ್ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟಗಳು (ವಿಡ್ಗೆಟ್) +Name[ko]=창에 들어있는 위젯 +Name[lt]=Langų valdikliai +Name[lv]=Logoti sīkrīki +Name[mr]=चौकटीतील विजेट्स +Name[nb]=Skjermelementer i vinduer +Name[nds]=Lüttprogrammen as Enkelfinstern +Name[nl]=Widgets weergegeven in vensters +Name[pa]=ਵਿੰਡੋ ਵਿਦਜੈੱਟ +Name[pl]=Elementy interfejsu w oknach +Name[pt]=Elementos em janelas +Name[pt_BR]=Widgets em janelas +Name[ro]=Controale în fereastră +Name[ru]=Мобильные виджеты +Name[si]=කවුළුකල විජට්ටු +Name[sk]=Widgety v oknách +Name[sl]=Gradniki v oknih +Name[sr]=виџети с прозором +Name[sr@ijekavian]=виџети с прозором +Name[sr@ijekavianlatin]=vidžeti s prozorom +Name[sr@latin]=vidžeti s prozorom +Name[sv]=Fönsterbaserade grafiska komponenter +Name[th]=วิดเจ็ตที่เป็นหน้าต่าง +Name[tr]=Pencerelendirilmiş gereçler +Name[ug]=كۆزنەكلىك ۋىجېتلار +Name[uk]=Віджети-вікна +Name[wa]=Ahesses metous dins des fniesses +Name[x-test]=xxWindowed widgetsxx +Name[zh_CN]=窗口化部件 +Name[zh_TW]=視窗元件 + + +Comment=Find Plasma widgets that can be run as standalone windows +Comment[ar]=ابحث عن ودجات بلازما التي يمكن تشغيلها كنوافذ مستقلة +Comment[ast]=Gueta componentes Plasma que puen executase como ventanes independientes +Comment[bg]=Търсене на джаджи, които могат да се използват като самостоятелни прозорци +Comment[bs]=Nađite plazma grafičke kontrole koje mogu da rade kao samostalni prozori +Comment[ca]=Cerca estris del Plasma que es poden executar en finestres autònomes +Comment[ca@valencia]=Cerca estris del Plasma que es poden executar en finestres autònomes +Comment[cs]=Najít Plasma widgety, které mohou být spuštěny ve vlastních oknech +Comment[da]=Find Plasma-widgets der kan køres som selvstændige vinduer +Comment[de]=Findet Plasma-Miniprogramme, die als eigenständige Anwendungen gestartet werden können +Comment[el]=Βρείτε γραφικά συστατικά Plasma που να μπορούν να εκτελεστούν ως ανεξάρτητα παράθυρα +Comment[en_GB]=Find Plasma widgets that can be run as standalone windows +Comment[es]=Busca componentes Plasma que se pueden ejecutar como ventanas independientes +Comment[et]=Plasma vidinate otsimine, mida saab panna tööle autonoomsetes akendes +Comment[eu]=Bilatu leiho autonomo gisa exekuta daitezkeen Plasmaren trepetak +Comment[fi]=Etsi Plasma-sovelmia, joita voidaan ajaa omina ikkunoinaan +Comment[fr]=Trouve des composants graphiques de Plasma pouvant êtres démarrés comme des fenêtres individuelles +Comment[ga]=Aimsigh giuirléidí Plasma is féidir rith i bhfuinneog shaorsheasaimh +Comment[gl]=Busca os widgets de Plasma que se poden executar en xanelas independentes +Comment[he]=משמש למציאת ווידג׳טים של Plasma אשר ניתן להריץ אותם בחלון עצמאי +Comment[hr]=Pronađi Plasma widgete koji se mogu pokrenuti kao zasebni prozori +Comment[hu]=Megkeresi az önálló alkalmazásként futtatható Plasma-elemeket +Comment[ia]=Trova widgets (elementos graphic) de plasma que on pote executar como fenestras sole +Comment[id]=Cari widget Plasma yang dapat dijalankan sebagai jendela mandiri +Comment[is]=Finnur Plasmagræjur sem hægt er að keyra sem sjálfstæð forrit +Comment[it]=Trova i plasmoidi che possono essere eseguiti come finestre a sé +Comment[ja]=スタンドアローンのウィンドウとして起動できる Plasma ウィジェットを検索します +Comment[kk]=Бөлек терезелі Plasma виджеттерін табу +Comment[km]=រក​ធាតុក្រាហ្វិក​ប្លាស្មា​ ដែល​អាច​ត្រូវ​បាន​​រត់​ជា​វីនដូ​តែ​ឯង +Comment[ko]=창으로 실행될 수 있는 위젯을 찾습니다 +Comment[lt]=Rasti plasmos elementus, kurie gali veikti kaip atskiri langai +Comment[lv]=Meklē Plasma sīkrīkus, ko var darbināt kā patstāvīgus logus +Comment[mr]=चौकटीत चालण्याजोगी प्लाज्मा विजेट्स शोधा +Comment[nb]=Finn Plasmaelementer som kan kjøres som frittstående programmer +Comment[nds]=Plasma-Lüttprogrammen söken, de ok as alleenstahn Finstern löppt. +Comment[nl]=Zoek Plasma widgets die als zelfstandige vensters kunnen draaien +Comment[pa]=ਪਲਾਜ਼ਾਮ ਵਿਦਜੈੱਟ ਲੱਭੋ, ਜੋ ਕਿ ਇੱਕਲੇ ਵਿੰਡੋਜ਼ ਵਜੋਂ ਚੱਲ ਸਕਦੇ ਹਨ +Comment[pl]=Znajdź elementy interfejsu, które mogą działać jako oddzielne okna +Comment[pt]=Procurar elementos do Plasma que possam ser executados como janelas autónomas +Comment[pt_BR]=Localiza widgets do Plasma que possam ser executados como janelas independentes +Comment[ro]=Găsește controale Plasma ce pot rula în ferestre independente +Comment[ru]=Поиск виджетов, способных работать как самостоятельные приложения +Comment[si]=තනි කවුළු ලෙස ධාවනය කල හැකි ප්ලැස්මා විජට්ටු සොයන්න +Comment[sk]=Nájde Plasma widgety, ktoré môžu bežať ako samostatné okná +Comment[sl]=Najdite gradnike za Plasmo, ki jih je mogoče zagnati v samostojnem oknu +Comment[sr]=Нађите плазма виџете који могу да раде као самостални прозори +Comment[sr@ijekavian]=Нађите плазма виџете који могу да раде као самостални прозори +Comment[sr@ijekavianlatin]=Nađite plasma vidžete koji mogu da rade kao samostalni prozori +Comment[sr@latin]=Nađite plasma vidžete koji mogu da rade kao samostalni prozori +Comment[sv]=Hitta grafiska Plasma-komponenter som kan köras som fristående fönster +Comment[th]=ค้นหาวิดเจ็ตพลาสมาที่สามารถทำงานได้บนหน้าต่างอิสระ +Comment[tr]=Tek başına pencere olarak da çalışabilen Plasma araçlarını bul +Comment[ug]=مۇستەقىل كۆزنەك شەكلىدە ئىجرا قىلغىلى بولىدىغان پلازما widget نى ئىزدەيدۇ +Comment[uk]=Пошук віджетів Плазми, які можна запускати у окремих вікнах +Comment[vi]=Tìm các widget có thể được chạy trong cửa sổ riêng +Comment[wa]=Trover des ahesses Plasma k' on sait enonder dins des fniesses mierseules +Comment[x-test]=xxFind Plasma widgets that can be run as standalone windowsxx +Comment[zh_CN]=查找可以独立窗口形式运行的 Plasma 部件 +Comment[zh_TW]=尋找可以以獨立視窗執行的 Plasma 元件 + + +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=plasma +X-KDE-Library=krunner_windowedwidgets +X-Plasma-RunnerPhase=first +X-KDE-PluginInfo-Author=Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=org.kde.windowedwidgets +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-AdvertiseSingleRunnerQueryMode=true diff --git a/plasma/generic/runners/windowedwidgets/windowedwidgetsrunner.cpp b/plasma/generic/runners/windowedwidgets/windowedwidgetsrunner.cpp new file mode 100644 index 00000000..17e9710c --- /dev/null +++ b/plasma/generic/runners/windowedwidgets/windowedwidgetsrunner.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2006 Aaron Seigo + * Copyright (C) 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "windowedwidgetsrunner.h" + +#include + +#include + +#include +#include +#include + +#include + +WindowedWidgetsRunner::WindowedWidgetsRunner(QObject *parent, const QVariantList &args) + : Plasma::AbstractRunner(parent, args) +{ + Q_UNUSED(args) + + setObjectName( QLatin1String("WindowedWidgets" )); + setPriority(AbstractRunner::HighestPriority); + + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds Plasma widgets whose name or description match :q:"))); + setDefaultSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "mobile applications"), i18n("list all Plasma widgets that can run as standalone applications"))); +} + +WindowedWidgetsRunner::~WindowedWidgetsRunner() +{ +} + +void WindowedWidgetsRunner::match(Plasma::RunnerContext &context) +{ + const QString term = context.query(); + + if (!context.singleRunnerQueryMode() && term.length() < 3) { + return; + } + + + QList matches; + + foreach (const KPluginInfo &info, Plasma::Applet::listAppletInfo()) { + KService::Ptr service = info.service(); + + if ((service->name().contains(term, Qt::CaseInsensitive) || + service->genericName().contains(term, Qt::CaseInsensitive) || + service->comment().contains(term, Qt::CaseInsensitive)) || + service->categories().contains(term, Qt::CaseInsensitive) || + term.startsWith(i18nc("Note this is a KRunner keyword", "mobile applications"))) { + + Plasma::QueryMatch match(this); + setupMatch(service, match); + if (service->name().compare(term, Qt::CaseInsensitive) == 0) { + match.setType(Plasma::QueryMatch::ExactMatch); + match.setRelevance(1); + } else { + match.setType(Plasma::QueryMatch::PossibleMatch); + match.setRelevance(0.7); + } + matches << match; + + kDebug() << service; + } + } + + if (!context.isValid()) { + return; + } + + context.addMatches(term, matches); +} + +void WindowedWidgetsRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) +{ + Q_UNUSED(context); + KService::Ptr service = KService::serviceByStorageId(match.data().toString()); + if (service) { + QProcess::startDetached("plasma-windowed", QStringList() << service->property("X-KDE-PluginInfo-Name", QVariant::String).toString()); + } +} + +void WindowedWidgetsRunner::setupMatch(const KService::Ptr &service, Plasma::QueryMatch &match) +{ + const QString name = service->name(); + + match.setText(name); + match.setData(service->storageId()); + + if (!service->genericName().isEmpty() && service->genericName() != name) { + match.setSubtext(service->genericName()); + } else if (!service->comment().isEmpty()) { + match.setSubtext(service->comment()); + } + + if (!service->icon().isEmpty()) { + match.setIcon(KIcon(service->icon())); + } +} + +QMimeData * WindowedWidgetsRunner::mimeDataForMatch(const Plasma::QueryMatch *match) +{ + KService::Ptr service = KService::serviceByStorageId(match->data().toString()); + if (service) { + + QMimeData *data = new QMimeData(); + data->setData("text/x-plasmoidservicename", + service->property("X-KDE-PluginInfo-Name", QVariant::String).toString().toUtf8()); + return data; + + } + + return 0; +} + + +#include "windowedwidgetsrunner.moc" + diff --git a/plasma/generic/runners/windowedwidgets/windowedwidgetsrunner.h b/plasma/generic/runners/windowedwidgets/windowedwidgetsrunner.h new file mode 100644 index 00000000..7509e166 --- /dev/null +++ b/plasma/generic/runners/windowedwidgets/windowedwidgetsrunner.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2006 Aaron Seigo + * Copyright (C) 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WINDOWEDWIDGETSRUNNER_H +#define WINDOWEDWIDGETSRUNNER_H + + +#include + +#include + + +/** + * This class looks for matches in the set of .desktop files installed by + * applications. This way the user can type exactly what they see in the + * appications menu and have it start the appropriate app. Essentially anything + * that KService knows about, this runner can launch + */ + +class WindowedWidgetsRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + +public: + WindowedWidgetsRunner(QObject *parent, const QVariantList &args); + ~WindowedWidgetsRunner(); + + void match(Plasma::RunnerContext &context); + void run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action); + +protected slots: + QMimeData * mimeDataForMatch(const Plasma::QueryMatch *match); + + +protected: + void setupMatch(const KService::Ptr &service, Plasma::QueryMatch &action); +}; + +K_EXPORT_PLASMA_RUNNER(windowedwidgets, WindowedWidgetsRunner) + +#endif + diff --git a/plasma/generic/runners/windows/CMakeLists.txt b/plasma/generic/runners/windows/CMakeLists.txt new file mode 100644 index 00000000..8bf9258e --- /dev/null +++ b/plasma/generic/runners/windows/CMakeLists.txt @@ -0,0 +1,10 @@ +set(krunner_windows_SRCS + windowsrunner.cpp +) + +kde4_add_plugin(krunner_windows ${krunner_windows_SRCS}) +target_link_libraries(krunner_windows ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS}) + +install(TARGETS krunner_windows DESTINATION ${PLUGIN_INSTALL_DIR} ) + +install(FILES plasma-runner-windows.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/runners/windows/Messages.sh b/plasma/generic/runners/windows/Messages.sh new file mode 100755 index 00000000..412322ba --- /dev/null +++ b/plasma/generic/runners/windows/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_runner_windows.pot diff --git a/plasma/generic/runners/windows/plasma-runner-windows.desktop b/plasma/generic/runners/windows/plasma-runner-windows.desktop new file mode 100644 index 00000000..9764d102 --- /dev/null +++ b/plasma/generic/runners/windows/plasma-runner-windows.desktop @@ -0,0 +1,149 @@ +[Desktop Entry] +# ctxt: plasma runner +Name=Windows +Name[ar]=النوافذ +Name[ast]=Ventanes +Name[bg]=Прозорци +Name[bn]=উইণ্ডো +Name[bs]=prozori +Name[ca]=Finestres +Name[ca@valencia]=Finestres +Name[cs]=Okna +Name[csb]=Òkna +Name[da]=Vinduer +Name[de]=Fenster +Name[el]=Παράθυρα +Name[en_GB]=Windows +Name[eo]=Fenestroj +Name[es]=Ventanas +Name[et]=Aknad +Name[eu]=Leihoak +Name[fa]=پنجره‌ها +Name[fi]=Ikkunat +Name[fr]=Fenêtres +Name[fy]=Finsters +Name[ga]=Fuinneoga +Name[gl]=Xanelas +Name[gu]=વિન્ડોઝ +Name[he]=חלונות +Name[hi]=विंडोज़ +Name[hr]=Prozori +Name[hu]=Ablakok +Name[ia]=Fenestras +Name[id]=Jendela +Name[is]=Gluggar +Name[it]=Finestre +Name[ja]=ウィンドウ +Name[kk]=Терезелер +Name[km]=បង្អួច +Name[kn]=ಕಿಟಕಿಗಳು +Name[ko]=창 +Name[lt]=Langai +Name[lv]=Logi +Name[mk]=Прозорци +Name[ml]=ജാലകങ്ങള്‍ +Name[mr]=चौकटी +Name[nb]=Vinduer +Name[nds]=Finstern +Name[nl]=Vensters +Name[nn]=Vindauge +Name[pa]=ਵਿੰਡੋਜ਼ +Name[pl]=Okna +Name[pt]=Janelas +Name[pt_BR]=Janelas +Name[ro]=Ferestre +Name[ru]=Окна +Name[si]=කවුළු +Name[sk]=Okná +Name[sl]=Okna +Name[sr]=прозори +Name[sr@ijekavian]=прозори +Name[sr@ijekavianlatin]=prozori +Name[sr@latin]=prozori +Name[sv]=Fönster +Name[tg]=Windows +Name[th]=หน้าต่างต่าง ๆ +Name[tr]=Pencereler +Name[ug]=كۆزنەكلەر +Name[uk]=Вікна +Name[wa]=Finiesses +Name[x-test]=xxWindowsxx +Name[zh_CN]=窗口 +Name[zh_TW]=視窗 +Comment=List windows and desktops and switch them +Comment[ar]=اسرد النوافذ وسطوح المكتب وبدّلها +Comment[ast]=Llista ventanes y escritorios y camuda ente ellos +Comment[bg]=Показване и превключване на прозорци и работни плотове +Comment[bs]=Nabrajanje i prebacivanje između prozora i površî +Comment[ca]=Llista finestres i escriptoris i canvia entre ells +Comment[ca@valencia]=Llista finestres i escriptoris i canvia entre ells +Comment[cs]=Seznam oken a ploch k přepínání +Comment[da]=Oplist vinduer og skriveborde og skift mellem dem +Comment[de]=Listet Fenster und Arbeitsflächen auf und wechselt zwischen ihnen. +Comment[el]=Εμφάνιση λίστας παραθύρων και επιφανειών εργασίας για εναλλαγή +Comment[en_GB]=List windows and desktops and switch them +Comment[eo]=Listi fenestrojn kaj labortablojn kaj ŝanĝi ilin +Comment[es]=Lista ventanas y escritorios y cambia entre ellos +Comment[et]=Akende ja töölauade näitamine võimalusega neile lülituda +Comment[eu]=Zerrendatu leihoak eta mahaigainak, eta batetik bestera aldatu +Comment[fi]=Luettele ikkunat ja työpöydät ja vaihda niitä +Comment[fr]=Liste les fenêtres / bureaux et passe de l'un à l'autre +Comment[fy]=Sommet finsters en buroblêden en wikselt har +Comment[ga]=Taispeáin fuinneoga agus deasca agus athraigh eatarthu +Comment[gl]=Lista as xanelas e escritorio e salta entre eles +Comment[he]=משמש להצגת חלונות ושולחנות עבודה ולהחלפה ביניהם +Comment[hr]=Popis prozora i radnih površina za laku promjenu među njima +Comment[hu]=Kilistázza az ablakokat és asztalokat, és vált rájuk +Comment[ia]=Lista fenestras e scriptorios e commuta los +Comment[id]=Urutkan jendela dan desktop lalu kemudian tukar mereka +Comment[is]=Telur upp glugga og skjáborð og skiptir á milli þeirra +Comment[it]=Elenca e scegli finestre e desktop +Comment[ja]=ウィンドウとデスクトップの一覧表示と切り替えを行います +Comment[kk]=Бар терезе мен үстелдерді ұсынып оларға ауысу +Comment[km]=រាយ​​បង្អួច និង​ផ្ទៃតុ​ ហើយ​ប្ដូរ​ពួកវា +Comment[kn]=ವಿಂಡೊ ಹಾಗು ಗಣಕತೆರೆಗಳನ್ನು ಪಟ್ಟಿಮಾಡು ಹಾಗು ಅವುಗಳನ್ನು ಬದಲಾಯಿಸು +Comment[ko]=창 및 데스크톱 목록을 보여 주고 전환합니다 +Comment[lt]=Išvardija langus ir darbastalius su galimybe į juos pereiti +Comment[lv]=Parāda logus un darbvirsmas un pārslēdz tos +Comment[mk]=Приказ на прозорци и раб. површини и преминување меѓу нив +Comment[ml]=ജാലകങ്ങളും പണിയിടങ്ങളും പട്ടികയായി കണ്ടു് പരസ്പരം മാറുക +Comment[mr]=वेगळ्या चौकट व डेस्कटॉप वर जाण्यासाठी यादी दर्शवा व बदला +Comment[nb]=List vinduer og skrivebord og bytt mellom dem +Comment[nds]=Finstern un Schriefdischen oplisten un wesseln +Comment[nl]=Toon vensters en bureaubladen en schakel ze om +Comment[nn]=Vis vindauge og skrivebord, og byt mellom dei +Comment[pa]=ਵਿੰਡੋਜ਼ ਅਤੇ ਡੈਸਕਟਾਪ ਦੀ ਲਿਸਟ ਅਤੇ ਉਹਨਾਂ ਵਿੱਚ ਬਦਲੋ +Comment[pl]=Lista okien i pulpitów oraz przełączenia ich +Comment[pt]=Listar as janelas e ecrãs e mudar entre eles +Comment[pt_BR]=Lista as janelas e áreas de trabalho e alterna entre elas +Comment[ro]=Enumeră ferestre și birouri și le comută +Comment[ru]=Список окон и рабочих столов с возможностью переключения между ними +Comment[si]=කවුළු හා වැඩතල ලැයිස්තුගත කර ඒවා මාරුකරන්න +Comment[sk]=Zoznam okien a plôch a ich prepínanie +Comment[sl]=Seznam oken in namizij ter preklapljanje med njimi +Comment[sr]=Набрајање и пребацивање између прозора и површи̂ +Comment[sr@ijekavian]=Набрајање и пребацивање између прозора и површи̂ +Comment[sr@ijekavianlatin]=Nabrajanje i prebacivanje između prozora i površî +Comment[sr@latin]=Nabrajanje i prebacivanje između prozora i površî +Comment[sv]=Lista fönster och skrivbord, och byt mellan dem +Comment[tg]=Намоиши рӯйхати тирезаҳо, мизҳои корӣ ва панелҳо +Comment[th]=รายการหน้าต่างและพื้นที่ทำงานต่าง ๆ ที่สามารถสลับไปใช้งานได้ +Comment[tr]=Pencereleri ve masaüstlerini listele ve seç +Comment[ug]=ھەممە كۆزنەكلەر ۋە ئۈستەلئۈستى تىزىمىنى كۆرسىتىپ، ئۇلارنى ئالماشتۇرىدۇ +Comment[uk]=Показує список вікон і стільниць і перемикає їх +Comment[vi]=Liệt kê các cửa sổ, màn hình làm việc và chuyển đổi chúng +Comment[wa]=Fé l' djivêye des fniesses eyet des scribannes eyet passer d' n' onk a l' ôte +Comment[x-test]=xxList windows and desktops and switch themxx +Comment[zh_CN]=列出所有窗口和桌面,并可供切换 +Comment[zh_TW]=列出視窗與桌面並切換 +X-KDE-ServiceTypes=Plasma/Runner +Type=Service +Icon=preferences-system-windows +X-KDE-Library=krunner_windows +X-KDE-PluginInfo-Author=Martin Gräßlin +X-KDE-PluginInfo-Email=kde@martin-graesslin.com +X-KDE-PluginInfo-Name=windows +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-AdvertiseSingleRunnerQueryMode=true diff --git a/plasma/generic/runners/windows/windowsrunner.cpp b/plasma/generic/runners/windows/windowsrunner.cpp new file mode 100644 index 00000000..f9712fae --- /dev/null +++ b/plasma/generic/runners/windows/windowsrunner.cpp @@ -0,0 +1,467 @@ +/*************************************************************************** + * Copyright 2009 by Martin Gräßlin * + * * + * 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 "windowsrunner.h" + +#include + +#include +#include +#include + +#ifdef Q_WS_X11 +#include +#include +#endif + +WindowsRunner::WindowsRunner(QObject* parent, const QVariantList& args) + : AbstractRunner(parent, args), + m_inSession(false), + m_ready(false) +{ + Q_UNUSED(args) + setObjectName( QLatin1String("Windows" )); + + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds windows whose name, window class or window role match :q:. " + "It is possible to interact with the windows by using one of the following keywords: " + "activate, close, min(imize), max(imize), fullscreen, shade, keep above and keep below."))); + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Finds windows which are on desktop named :q: " + "It is possible to interact with the windows by using one of the following keywords: " + "activate, close, min(imize), max(imize), fullscreen, shade, keep above and keep below."))); + addSyntax(Plasma::RunnerSyntax(":q:", i18n("Switch to desktop named :q:"))); + setDefaultSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "window"), + i18n("Lists all windows and allows to activate them. " + "With name=, class=, role= and desktop= the list can be reduced to " + "windows matching these restrictions. " + "It is possible to interact with the windows by using one of the following keywords: " + "activate, close, min(imize), max(imize), fullscreen, shade, keep above and keep below."))); + addSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "desktop"), + i18n("Lists all other desktops and allows to switch to them."))); + + connect(this, SIGNAL(prepare()), this, SLOT(prepareForMatchSession())); + connect(this, SIGNAL(teardown()), this, SLOT(matchSessionComplete())); +} + +WindowsRunner::~WindowsRunner() +{ +} + +void WindowsRunner::gatherInfo() +{ + if (!m_inSession) { + return; + } + + foreach (const WId w, KWindowSystem::windows()) { + KWindowInfo info = KWindowSystem::windowInfo(w, NET::WMWindowType | NET::WMDesktop | + NET::WMState | NET::XAWMState | + NET::WMName, + NET::WM2WindowClass | NET::WM2WindowRole | NET::WM2AllowedActions); + if (info.valid()) { + // ignore NET::Tool and other special window types + NET::WindowType wType = info.windowType(NET::NormalMask | NET::DesktopMask | NET::DockMask | + NET::ToolbarMask | NET::MenuMask | NET::DialogMask | + NET::OverrideMask | NET::TopMenuMask | + NET::UtilityMask | NET::SplashMask); + + if (wType != NET::Normal && wType != NET::Override && wType != NET::Unknown && + wType != NET::Dialog && wType != NET::Utility) { + continue; + } + m_windows.insert(w, info); + m_icons.insert(w, QIcon(KWindowSystem::icon(w))); + } + } + + for (int i=1; i<=KWindowSystem::numberOfDesktops(); i++) { + m_desktopNames << KWindowSystem::desktopName(i); + } + + m_ready = true; +} + +void WindowsRunner::prepareForMatchSession() +{ + m_inSession = true; + m_ready = false; + QTimer::singleShot(0, this, SLOT(gatherInfo())); +} + +void WindowsRunner::matchSessionComplete() +{ + m_inSession = false; + m_ready = false; + m_desktopNames.clear(); + m_icons.clear(); + m_windows.clear(); +} + +void WindowsRunner::match(Plasma::RunnerContext& context) +{ + if (!m_ready) { + return; + } + + QString term = context.query(); + + if (!context.singleRunnerQueryMode() && (term.length() < 3)) { + return; + } + QList matches; + + // check if the search term ends with an action keyword + WindowAction action = ActivateAction; + if (term.endsWith(i18nc("Note this is a KRunner keyword", "activate") , Qt::CaseInsensitive)) { + action = ActivateAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "activate")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "close") , Qt::CaseInsensitive)) { + action = CloseAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "close")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "min") , Qt::CaseInsensitive)) { + action = MinimizeAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "min")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "minimize") , Qt::CaseInsensitive)) { + action = MinimizeAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "minimize")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "max") , Qt::CaseInsensitive)) { + action = MaximizeAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "max")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "maximize") , Qt::CaseInsensitive)) { + action = MaximizeAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "maximize")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "fullscreen") , Qt::CaseInsensitive)) { + action = FullscreenAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "fullscreen")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "shade") , Qt::CaseInsensitive)) { + action = ShadeAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "shade")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "keep above") , Qt::CaseInsensitive)) { + action = KeepAboveAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "keep above")) - 1); + } else if (term.endsWith(i18nc("Note this is a KRunner keyword", "keep below") , Qt::CaseInsensitive)) { + action = KeepBelowAction; + term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "keep below")) - 1); + } + + // keyword match: when term starts with "window" we list all windows + // the list can be restricted to windows matching a given name, class, role or desktop + if (term.startsWith(i18nc("Note this is a KRunner keyword", "window") , Qt::CaseInsensitive)) { + const QStringList keywords = term.split(" "); + QString windowName; + QString windowClass; + QString windowRole; + int desktop = -1; + foreach (const QString& keyword, keywords) { + if (keyword.endsWith('=')) { + continue; + } + if (keyword.startsWith(i18nc("Note this is a KRunner keyword", "name") + "=" , Qt::CaseInsensitive)) { + windowName = keyword.split("=")[1]; + } else if (keyword.startsWith(i18nc("Note this is a KRunner keyword", "class") + "=" , Qt::CaseInsensitive)) { + windowClass = keyword.split("=")[1]; + } else if (keyword.startsWith(i18nc("Note this is a KRunner keyword", "role") + "=" , Qt::CaseInsensitive)) { + windowRole = keyword.split("=")[1]; + } else if (keyword.startsWith(i18nc("Note this is a KRunner keyword", "desktop") + "=" , Qt::CaseInsensitive)) { + bool ok; + desktop = keyword.split("=")[1].toInt(&ok); + if (!ok || desktop > KWindowSystem::numberOfDesktops()) { + desktop = -1; // sanity check + } + } else { + // not a keyword - use as name if name is unused, but another option is set + if (windowName.isEmpty() && !keyword.contains('=') && + (!windowRole.isEmpty() || !windowClass.isEmpty() || desktop != -1)) { + windowName = keyword; + } + } + } + QHashIterator it(m_windows); + while(it.hasNext()) { + it.next(); + WId w = it.key(); + KWindowInfo info = it.value(); + QString windowClassCompare = QString::fromUtf8(info.windowClassName()) + " " + + QString::fromUtf8(info.windowClassClass()); + // exclude not matching windows + if (!KWindowSystem::hasWId(w)) { + continue; + } + if (!windowName.isEmpty() && !info.name().contains(windowName, Qt::CaseInsensitive)) { + continue; + } + if (!windowClass.isEmpty() && !windowClassCompare.contains(windowClass, Qt::CaseInsensitive)) { + continue; + } + if (!windowRole.isEmpty() && !QString::fromUtf8(info.windowRole()).contains(windowRole, Qt::CaseInsensitive)) { + continue; + } + if (desktop != -1 && !info.isOnDesktop(desktop)) { + continue; + } + // check for windows when no keywords were used + // check the name, class and role for containing the query without the keyword + if (windowName.isEmpty() && windowClass.isEmpty() && windowRole.isEmpty() && desktop == -1) { + const QString& test = term.mid(keywords[0].length() + 1); + if (!info.name().contains(test, Qt::CaseInsensitive) && + !windowClassCompare.contains(test, Qt::CaseInsensitive) && + !QString::fromUtf8(info.windowRole()).contains(test, Qt::CaseInsensitive)) { + continue; + } + } + // blacklisted everything else: we have a match + if (actionSupported(info, action)){ + matches << windowMatch(info, action); + } + } + + if (!matches.isEmpty()) { + // the window keyword found matches - do not process other syntax possibilities + context.addMatches(context.query(), matches); + return; + } + } + + bool desktopAdded = false; + // check for desktop keyword + if (term.startsWith(i18nc("Note this is a KRunner keyword", "desktop") , Qt::CaseInsensitive)) { + const QStringList parts = term.split(" "); + if (parts.size() == 1) { + // only keyword - list all desktops + for (int i=1; i<=KWindowSystem::numberOfDesktops(); i++) { + if (i == KWindowSystem::currentDesktop()) { + continue; + } + matches << desktopMatch(i); + desktopAdded = true; + } + } else { + // keyword + desktop - restrict matches + bool isInt; + int desktop = term.mid(parts[0].length() + 1).toInt(&isInt); + if (isInt && desktop != KWindowSystem::currentDesktop()) { + matches << desktopMatch(desktop); + desktopAdded = true; + } + } + } + + // check for matches without keywords + QHashIterator it(m_windows); + while (it.hasNext()) { + it.next(); + WId w = it.key(); + if (!KWindowSystem::hasWId(w)) { + continue; + } + // check if window name, class or role contains the query + KWindowInfo info = it.value(); + QString className = QString::fromUtf8(info.windowClassName()); + if (info.name().startsWith(term, Qt::CaseInsensitive) || + className.startsWith(term, Qt::CaseInsensitive)) { + matches << windowMatch(info, action, 0.8, Plasma::QueryMatch::ExactMatch); + } else if ((info.name().contains(term, Qt::CaseInsensitive) || + className.contains(term, Qt::CaseInsensitive)) && + actionSupported(info, action)) { + matches << windowMatch(info, action, 0.7, Plasma::QueryMatch::PossibleMatch); + } + } + + // check for matching desktops by name + foreach (const QString& desktopName, m_desktopNames) { + int desktop = m_desktopNames.indexOf(desktopName) +1; + if (desktopName.contains(term, Qt::CaseInsensitive)) { + // desktop name matches - offer switch to + // only add desktops if it hasn't been added by the keyword which is quite likely + if (!desktopAdded && desktop != KWindowSystem::currentDesktop()) { + matches << desktopMatch(desktop, 0.8); + } + + // search for windows on desktop and list them with less relevance + QHashIterator it(m_windows); + while (it.hasNext()) { + it.next(); + KWindowInfo info = it.value(); + if (info.isOnDesktop(desktop) && actionSupported(info, action)) { + matches << windowMatch(info, action, 0.5, Plasma::QueryMatch::PossibleMatch); + } + } + } + } + + if (!matches.isEmpty()) { + context.addMatches(context.query(), matches); + } +} + +void WindowsRunner::run(const Plasma::RunnerContext& context, const Plasma::QueryMatch& match) +{ + Q_UNUSED(context) + // check if it's a desktop + if (match.id().startsWith("windows_desktop")) { + KWindowSystem::setCurrentDesktop(match.data().toInt()); + return; + } + + const QStringList parts = match.data().toString().split("_"); + WindowAction action = WindowAction(parts[0].toInt()); + WId w = WId(parts[1].toULong()); + KWindowInfo info = m_windows[w]; + switch (action) { + case ActivateAction: + KWindowSystem::forceActiveWindow(w); + break; + case CloseAction: + { + NETRootInfo ri(QX11Info::display(), NET::CloseWindow); + ri.closeWindowRequest(w); + break; + } + case MinimizeAction: + if (info.isMinimized()) { + KWindowSystem::unminimizeWindow(w); + } else { + KWindowSystem::minimizeWindow(w); + } + break; + case MaximizeAction: + if (info.hasState(NET::Max)) { + KWindowSystem::clearState(w, NET::Max); + } else { + KWindowSystem::setState(w, NET::Max); + } + break; + case FullscreenAction: + if (info.hasState(NET::FullScreen)) { + KWindowSystem::clearState(w, NET::FullScreen); + } else { + KWindowSystem::setState(w, NET::FullScreen); + } + break; + case ShadeAction: + if (info.hasState(NET::Shaded)) { + KWindowSystem::clearState(w, NET::Shaded); + } else { + KWindowSystem::setState(w, NET::Shaded); + } + break; + case KeepAboveAction: + if (info.hasState(NET::KeepAbove)) { + KWindowSystem::clearState(w, NET::KeepAbove); + } else { + KWindowSystem::setState(w, NET::KeepAbove); + } + break; + case KeepBelowAction: + if (info.hasState(NET::KeepBelow)) { + KWindowSystem::clearState(w, NET::KeepBelow); + } else { + KWindowSystem::setState(w, NET::KeepBelow); + } + break; + } +} + +Plasma::QueryMatch WindowsRunner::desktopMatch(int desktop, qreal relevance) +{ + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::ExactMatch); + match.setData(desktop); + match.setId("desktop-" + QString::number(desktop)); + match.setIcon(KIcon("user-desktop")); + QString desktopName; + if (desktop <= m_desktopNames.size()) { + desktopName = m_desktopNames[desktop - 1]; + } else { + desktopName = KWindowSystem::desktopName(desktop); + } + match.setText(desktopName); + match.setSubtext(i18n("Switch to desktop %1", desktop)); + match.setRelevance(relevance); + return match; +} + +Plasma::QueryMatch WindowsRunner::windowMatch(const KWindowInfo& info, WindowAction action, qreal relevance, Plasma::QueryMatch::Type type) +{ + Plasma::QueryMatch match(this); + match.setType(type); + match.setData(QString(QString::number((int)action) + "_" + QString::number(info.win()))); + match.setIcon(m_icons[info.win()]); + match.setText(info.name()); + QString desktopName; + int desktop = info.desktop(); + if (desktop == NET::OnAllDesktops) { + desktop = KWindowSystem::currentDesktop(); + } + if (desktop <= m_desktopNames.size()) { + desktopName = m_desktopNames[desktop - 1]; + } else { + desktopName = KWindowSystem::desktopName(desktop); + } + switch (action) { + case CloseAction: + match.setSubtext(i18n("Close running window on %1", desktopName)); + break; + case MinimizeAction: + match.setSubtext(i18n("(Un)minimize running window on %1", desktopName)); + break; + case MaximizeAction: + match.setSubtext(i18n("Maximize/restore running window on %1", desktopName)); + break; + case FullscreenAction: + match.setSubtext(i18n("Toggle fullscreen for running window on %1", desktopName)); + break; + case ShadeAction: + match.setSubtext(i18n("(Un)shade running window on %1", desktopName)); + break; + case KeepAboveAction: + match.setSubtext(i18n("Toggle keep above for running window on %1", desktopName)); + break; + case KeepBelowAction: + match.setSubtext(i18n("Toggle keep below running window on %1", desktopName)); + break; + case ActivateAction: + default: + match.setSubtext(i18n("Activate running window on %1", desktopName)); + break; + } + match.setRelevance(relevance); + return match; +} + +bool WindowsRunner::actionSupported(const KWindowInfo& info, WindowAction action) +{ + switch (action) { + case CloseAction: + return info.actionSupported(NET::ActionClose); + case MinimizeAction: + return info.actionSupported(NET::ActionMinimize); + case MaximizeAction: + return info.actionSupported(NET::ActionMax); + case ShadeAction: + return info.actionSupported(NET::ActionShade); + case FullscreenAction: + return info.actionSupported(NET::ActionFullScreen); + case KeepAboveAction: + case KeepBelowAction: + case ActivateAction: + default: + return true; + } +} + +#include "windowsrunner.moc" diff --git a/plasma/generic/runners/windows/windowsrunner.h b/plasma/generic/runners/windows/windowsrunner.h new file mode 100644 index 00000000..a51041a4 --- /dev/null +++ b/plasma/generic/runners/windows/windowsrunner.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright 2009 by Martin Gräßlin * + * * + * 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 WINDOWSRUNNER_H +#define WINDOWSRUNNER_H + +#include + +class KWindowInfo; + +class WindowsRunner : public Plasma::AbstractRunner +{ + Q_OBJECT + + public: + WindowsRunner(QObject* parent, const QVariantList &args); + ~WindowsRunner(); + + virtual void match(Plasma::RunnerContext& context); + virtual void run(const Plasma::RunnerContext& context, const Plasma::QueryMatch& match); + + private Q_SLOTS: + void prepareForMatchSession(); + void matchSessionComplete(); + void gatherInfo(); + + private: + enum WindowAction { + ActivateAction, + CloseAction, + MinimizeAction, + MaximizeAction, + FullscreenAction, + ShadeAction, + KeepAboveAction, + KeepBelowAction + }; + Plasma::QueryMatch desktopMatch(int desktop, qreal relevance = 1.0); + Plasma::QueryMatch windowMatch(const KWindowInfo& info, WindowAction action, qreal relevance = 1.0, + Plasma::QueryMatch::Type type = Plasma::QueryMatch::ExactMatch); + bool actionSupported(const KWindowInfo& info, WindowAction action); + + QHash m_windows; + QHash m_icons; + QStringList m_desktopNames; + + bool m_inSession : 1; + bool m_ready : 1; +}; + +K_EXPORT_PLASMA_RUNNER(windows, WindowsRunner) + +#endif // WINDOWSRUNNER_H diff --git a/plasma/generic/scriptengines/CMakeLists.txt b/plasma/generic/scriptengines/CMakeLists.txt new file mode 100644 index 00000000..0c50409e --- /dev/null +++ b/plasma/generic/scriptengines/CMakeLists.txt @@ -0,0 +1,9 @@ +macro_optional_add_subdirectory(ruby) + +if(QT_QTWEBKIT_FOUND) + macro_optional_add_subdirectory(webkit) +endif(QT_QTWEBKIT_FOUND) + +if (PYTHONLIBRARY_FOUND AND NOT WIN32) + macro_optional_add_subdirectory(python) +endif (PYTHONLIBRARY_FOUND AND NOT WIN32) diff --git a/plasma/generic/scriptengines/python/CMakeLists.txt b/plasma/generic/scriptengines/python/CMakeLists.txt new file mode 100644 index 00000000..d4e5b133 --- /dev/null +++ b/plasma/generic/scriptengines/python/CMakeLists.txt @@ -0,0 +1,41 @@ +project(plasma-python) + +include(PythonMacros) + +# install the library, .desktop, and plasma.py +python_install(pyappletscript.py ${DATA_INSTALL_DIR}/plasma_scriptengine_python) +python_install(plasma_importer.py ${DATA_INSTALL_DIR}/plasma_scriptengine_python) +python_install(pydataengine.py ${DATA_INSTALL_DIR}/plasma_scriptengine_python) +python_install(pyrunner.py ${DATA_INSTALL_DIR}/plasma_scriptengine_python) +python_install(pywallpaper.py ${DATA_INSTALL_DIR}/plasma_scriptengine_python) + +# remove the following three lines once we branch 4.5, they are only necessary as long +# as people update kdebase but not yet kdelibs (PYTHON_SITE_PACKAGES_INSTALL_DIR has just +# recently been added to FindPYthonLib.cmake and should be used as install destination). Alex +if(NOT PYTHON_SITE_PACKAGES_INSTALL_DIR) + set(PYTHON_SITE_PACKAGES_INSTALL_DIR ${PYTHON_SITE_PACKAGES_DIR} ) +endif(NOT PYTHON_SITE_PACKAGES_INSTALL_DIR) + +python_install(plasmascript.py ${PYTHON_SITE_PACKAGES_INSTALL_DIR}/PyKDE4) + +install(FILES plasma-scriptengine-applet-python.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES plasma-scriptengine-dataengine-python.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES plasma-scriptengine-runner-python.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES plasma-scriptengine-wallpaper-python.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) + +########################################################################### +# Test plasmoids +option(INSTALL_PYTHON_TEST_PLASMA "Install test python applet" OFF) + +if(INSTALL_PYTHON_TEST_PLASMA ) + + install(DIRECTORY test/plasma-applet-pyclock DESTINATION ${DATA_INSTALL_DIR}/plasma/plasmoids) + + #TODO where install it ? + #install(DIRECTORY test/plasma-dataengine-pytime DESTINATION ${DATA_INSTALL_DIR}/plasma/engines) + +endif(INSTALL_PYTHON_TEST_PLASMA) diff --git a/plasma/generic/scriptengines/python/plasma-scriptengine-applet-python.desktop b/plasma/generic/scriptengines/python/plasma-scriptengine-applet-python.desktop new file mode 100644 index 00000000..f07ec350 --- /dev/null +++ b/plasma/generic/scriptengines/python/plasma-scriptengine-applet-python.desktop @@ -0,0 +1,149 @@ +[Desktop Entry] +Name=Python Widget +Name[ar]=ودجة بايثون +Name[ast]=Widget de Python +Name[be@latin]=Widžet „Python” +Name[bg]=Джаджа на Python +Name[bn]=পাইথন উইজেট +Name[bn_IN]=Python উইজেট +Name[bs]=Python grafičkih kontrola +Name[ca]=Estri en Python +Name[ca@valencia]=Estri en Python +Name[cs]=Python widget +Name[csb]=Interfejs Phythona +Name[da]=Python-widget +Name[de]=Python-Miniprogramm +Name[el]=Συστατικό Python +Name[en_GB]=Python Widget +Name[eo]=Pitona fenestraĵo +Name[es]=Widget de Python +Name[et]=Pythoni vidin +Name[eu]=Python trepeta +Name[fi]=Python-sovelma +Name[fr]=Composant graphique Python +Name[fy]=Python Widget +Name[ga]=Giuirléid Python +Name[gl]=Widget de Python +Name[gu]=પાયથોન વિજેટ +Name[he]=ווידג׳ט של Python +Name[hi]=पायथन विज़ेट +Name[hne]=पायथन विजेट +Name[hr]=Python widget +Name[hu]=Python-elem +Name[ia]=Elemento graphic (Widget) de Python +Name[id]=Widget Python +Name[is]=Python græja +Name[ja]=Python ウィジェット +Name[kk]=Python бөлшегі +Name[km]=ធាតុ​ក្រាហ្វិក Python +Name[kn]=ಪೈಥಾನ್ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Name[ko]=파이썬 위젯 +Name[ku]=Alava Python +Name[lt]=Python valdiklis +Name[lv]=Python sīkrīks +Name[ml]=പൈത്തണ്‍ ഉരുപ്പടി +Name[mr]=Python Widget +Name[nb]=Pythonelement +Name[nds]=Python-Lüttprogramm +Name[nl]=Python-widget +Name[nn]=Python-element +Name[or]=ପାଇଥନ ୱିଜେଟ +Name[pa]=ਪਾਈਥਨ ਵਿਦਜੈੱਟ +Name[pl]=Element interfejsu w Pythonie +Name[pt]=Elemento em Python +Name[pt_BR]=Widget em Python +Name[ro]=Control Python +Name[ru]=Виджет на языке Python +Name[si]=QEdje +Name[sk]=Python widget +Name[sl]=Gradnik v Pythonu +Name[sr]=питонски виџет +Name[sr@ijekavian]=питонски виџет +Name[sr@ijekavianlatin]=Python vidžet +Name[sr@latin]=Python vidžet +Name[sv]=Grafisk Python-komponent +Name[ta]=Python Widget +Name[tg]=Илова ба Python +Name[th]=วิดเจ็ตภาษาไพธอน +Name[tr]=Python Programcığı +Name[ug]=Python Widget +Name[uk]=Віджет Python +Name[wa]=Ahesse Python +Name[x-test]=xxPython Widgetxx +Name[zh_CN]=Python 部件 +Name[zh_TW]=Python 元件 +Comment=Plasma widget support written in Python +Comment[ar]=دعم ودجات البلازما المكتوبة بالبايثون +Comment[ast]=Elementu gráficu nativu de Plasma escritu en Python +Comment[be@latin]=Widžet systemy „Plasma”, napisany ŭ movie „Python” +Comment[bg]=Оригинална джаджа за Plasma, написана на Python +Comment[bs]=Podrška plazma grafičkim kontrolama pisanih u Pythonu +Comment[ca]=Estri nadiu del Plasma escrit en Python +Comment[ca@valencia]=Estri nadiu del Plasma escrit en Python +Comment[cs]=Podpora pro plasmoidy napsaná v Pythonu +Comment[da]=Understøttelse af plasma-widgets skrevet i Python +Comment[de]=Plasma-Miniprogramm-Unterstützung, geschrieben in Python +Comment[el]=Υποστήριξη συστατικού Plasma γραμμένο σε Python +Comment[en_GB]=Plasma widget support written in Python +Comment[es]=Elemento gráfico nativo de Plasma escrito en Python +Comment[et]=Pythonis kirjutatud Plasma vidina toetus +Comment[eu]=Python-en idatzitako Plasmaren trepeta-euskarria +Comment[fi]=Tuki Pythonilla kirjoitetuille Plasma-sovelmille +Comment[fr]=Prise en charge des composants graphiques de Plasma écrits en Python +Comment[fy]=Plasma widget stipe skreaun yn Python +Comment[ga]=Tacaíocht giuirléidí Plasma scríofa i Python +Comment[gl]=Widget nativo de Plasma escrito en Python +Comment[gu]=પાયથોનમાં લખાયેલ પ્લાઝમા વિજેટ આધાર +Comment[he]=תמיכה בווידג׳טים של Plasma עבור Python +Comment[hi]=पायथन में लिखा गया प्लाज्मा विजेट समर्थन +Comment[hne]=पायथन मं लिखे प्लाज्मा विजेट सपोर्ट +Comment[hr]=Podrška za Plasma widgete napisana u Pythonu +Comment[hu]=Plazmoid-támogatás Python nyelven +Comment[ia]=Supporto de elemento graphic (Widget) de Plasma scribite in Python +Comment[id]=Dukungan widget Plasma didukung oleh Python +Comment[is]=Stuðningur við plasmadót skrifaður í Python +Comment[ja]=Python で書かれた Plasma のウィジェット +Comment[kk]=Python-да жазылған Plasma интерфейс бөлшегі +Comment[km]=ការ​គាំទ្រ​ធាតុក្រាហ្វិក​ប្លាស្មា​ត្រូវបាន​សរសេរ​នៅ​ក្នុង​ភាសា Python +Comment[kn]=ಪೈಥಾನಿನಲ್ಲಿ ಬರೆಯಲಾದ ಪ್ಲಾಸ್ಮಾ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ(ವಿಡ್ಗೆಟ್) ಬೆಂಬಲ +Comment[ko]=파이썬으로 작성된 Plasma 위젯 +Comment[lt]=Plasma valdiklių palaikymas, parašytas su Python +Comment[lv]=Plasma sīkrīks, kas rakstīts Python +Comment[ml]=പൈത്തണില്‍ തയ്യാറാക്കിയിരിക്കുന്ന പ്ലാസ്മയില്‍ ഉരുപ്പടികള്‍ക്കുള്ള പിന്തുണ +Comment[mr]=Python अंतर्गत लिहीले गेलेले स्थानिक Plasma विजेट +Comment[nb]=Plasma skjermelement skrevet i Python +Comment[nds]=Plasma-Lüttprogrammünnerstütten, schreven in Python +Comment[nl]=Plasma-widget-ondersteuning geschreven in Python +Comment[nn]=Plasmoidestøtte skriven i Python +Comment[or]=ପାଇଥନରେ ଲିଖିତ ପ୍ଲାଜମା ୱିଜେଟ ସମର୍ଥନ +Comment[pa]=ਪਾਈਥਨ ਵਿੱਚ ਲਿਖੇ ਪਲਾਜ਼ਮਾ ਵਿਦਜੈੱਟ ਸਹਿਯੋਗ +Comment[pl]=Obsługa elementu interfejsu Plazmy w Pythonie +Comment[pt]=Elemento nativo do Plasma feito em Python +Comment[pt_BR]=Widget nativo do Plasma escrito em Python +Comment[ro]=Suport controale Plasma scris în Python +Comment[ru]=Виджет Plasma, написанный на языке Python +Comment[si]=Plasma widget support written in Python +Comment[sk]=Podpora widgetov plasmy napísaných v Pythone +Comment[sl]=Podpora za gradnike napisane v Pythonu +Comment[sr]=Подршка плазма виџета писаних у питону +Comment[sr@ijekavian]=Подршка плазма виџета писаних у питону +Comment[sr@ijekavianlatin]=Podrška plasma vidžeta pisanih u Pythonu +Comment[sr@latin]=Podrška plasma vidžeta pisanih u Pythonu +Comment[sv]=Stöd för grafisk Plasma-komponent skriven i Python +Comment[ta]=Plasma widget support written in Python +Comment[tg]=Модуль Plasma, написанный на языке JavaScript +Comment[th]=วิดเจ็ตพลาสมาที่ถูกเขียนด้วยภาษาไพธอน +Comment[tr]=Python ile yazılmış Plasma gereci desteği +Comment[ug]=Python بىلەن يېزىلغان Plasma widget نى قوللايدۇ +Comment[uk]=Віджет Плазми, написаний на Python +Comment[wa]=Sopoirt des ahesses sicrîtes e Python po Plasma +Comment[x-test]=xxPlasma widget support written in Pythonxx +Comment[zh_CN]=Plasma 部件支持用 Python 来编写 +Comment[zh_TW]=用 Python 寫的 Plasma 元件支援 +X-KDE-ServiceTypes=Plasma/ScriptEngine +Type=Service +Icon=text-x-script +X-Plasma-API=python +X-Plasma-ComponentTypes=Applet +X-KDE-Library=kpythonpluginfactory +X-KDE-PluginKeyword=plasma_scriptengine_python/pyappletscript.py diff --git a/plasma/generic/scriptengines/python/plasma-scriptengine-dataengine-python.desktop b/plasma/generic/scriptengines/python/plasma-scriptengine-dataengine-python.desktop new file mode 100644 index 00000000..bf1917b4 --- /dev/null +++ b/plasma/generic/scriptengines/python/plasma-scriptengine-dataengine-python.desktop @@ -0,0 +1,151 @@ +[Desktop Entry] +Name=Python data engine +Name[ar]=محرك بيانات بايثون +Name[ast]=Motor de datos de Python +Name[be@latin]=Systema źviestak u movie „Python” +Name[bg]=Ядро за данни с Python +Name[bn_IN]=Python ডাটা ইঞ্জিন +Name[bs]=Python pogon podataka +Name[ca]=Motor de dades en Python +Name[ca@valencia]=Motor de dades en Python +Name[cs]=Rozhraní v Pythonu +Name[csb]=Czérownik Phythona +Name[da]=Datamotor til Python +Name[de]=Python-Datentreiber +Name[el]=Μηχανή δεδομένων Python +Name[en_GB]=Python data engine +Name[eo]=Pitona datuma motoro +Name[es]=Motor de datos de Python +Name[et]=Pythoni andmete mootor +Name[eu]=Python-en datu-motorra +Name[fi]=Python-tietomoottori +Name[fr]=Moteur de données Python +Name[fy]=Python gegevens motor +Name[ga]=Inneall sonraí Python +Name[gl]=Motor de datos de Python +Name[gu]=પાયથોન માહિતી એન્જિન +Name[he]=מנוע תוכן של Python +Name[hi]=पायथन डाटा इंजिन +Name[hne]=पायथन डाटा इंजिन +Name[hr]=Pythonov podatkovni mehanizam +Name[hu]=Adatkezelő modul Python nyelven +Name[ia]=Motor de datos de Python +Name[id]=Mesin data Python +Name[is]=Python gagnavél +Name[ja]=Python データエンジン +Name[kk]=Python деректер тетігі +Name[km]=ម៉ាស៊ីន​ទិន្នន័យ Python +Name[kn]=ಪೈಥಾನ್ ದತ್ತಾಂಶ ಎಂಜಿನ್ +Name[ko]=파이썬 데이터 엔진 +Name[lt]=Python duomenų variklis +Name[lv]=Python datu dzinējs +Name[ml]=പൈത്തണ്‍ ഡേറ്റാ എഞ്ചിന്‍ +Name[mr]=Python माहिती इन्जीन +Name[nb]=Python datamotor +Name[nds]=Python-Datenkarn +Name[nl]=Python (gegevensengine) +Name[nn]=Python-datamotor +Name[or]=ପାଇଥନ ତଥ୍ୟ ମେସିନ +Name[pa]=ਪਾਈਥਨ ਡਾਟਾ ਇੰਜਣ +Name[pl]=Silnik danych w Pythonie +Name[pt]=Motor de dados em Python +Name[pt_BR]=Mecanismo de dados Python +Name[ro]=Motor de date Python +Name[ru]=Источник данных на языке Python +Name[si]=Python data engine +Name[sk]=Python dátový nástroj +Name[sl]=Podatkovni vir v Pythonu +Name[sr]=питонски датомотор +Name[sr@ijekavian]=питонски датомотор +Name[sr@ijekavianlatin]=Python datomotor +Name[sr@latin]=Python datomotor +Name[sv]=Python datagränssnitt +Name[ta]=Python data engine +Name[tg]=Системаи санаи Python +Name[th]=กลไกข้อมูลภาษาไพธอน +Name[tr]=Python veri motoru +Name[ug]=Python سانلىق-مەلۇمات ماتورى +Name[uk]=Рушій даних Python +Name[wa]=Moteur di dnêyes Python +Name[x-test]=xxPython data enginexx +Name[zh_CN]=Python 数据引擎 +Name[zh_TW]=Python 資料引擎 +Comment=Plasma data engine support for Python +Comment[ar]=دعم محرك بيانات بلازما للبايثون +Comment[ast]=Sofitu del motor de datos de plasma pa Python +Comment[be@latin]=Absłuhoŭvańnie systemy źviestak „Plasma” u movie „Python” +Comment[bg]=Поддръжка за създаване на ядра за данни на Plasma с Python +Comment[bs]=Podrška plazma pogona podataka za Python +Comment[ca]=Implementació de motor de dades del Plasma per al Python +Comment[ca@valencia]=Implementació de motor de dades del Plasma per al Python +Comment[cs]=Podpora datového rozhraní Plasmy v Pythonu +Comment[da]=Plasma datamotor-understøttelse af Python +Comment[de]=Unterstützung für Plasma-Datentreiber in Python +Comment[el]=Υποστήριξη μηχανής δεδομένων Plasma για την Python +Comment[en_GB]=Plasma data engine support for Python +Comment[eo]=Plasma datummotora apogo por Pitono +Comment[es]=Soporte del motor de datos de plasma para Python +Comment[et]=Plasma andmemootori toetus Pythonile +Comment[eu]=Python-erako Plasmaren datu-motorraren euskarria +Comment[fi]=Plasma-tietomoottorituki Python-kielelle +Comment[fr]=Prise en charge du moteur de données Python pour Plasma +Comment[fy]=Plasma-gegevensmotor-stipe foar Python +Comment[ga]=Tacaíocht innill sonraí Plasma le haghaidh Python +Comment[gl]=Motor de datos de Plasma para dar soporte a Python +Comment[gu]=પાયથોન માટે પ્લાઝમા માહિતી એન્જિન આધાર +Comment[he]=תמיכה במנועי תוכן של Plasma עבור Python +Comment[hi]=पायथन के लिए प्लाज्मा डाटा इंजिन समर्थन +Comment[hne]=पायथन बर प्लाज्मा डाटा इंजिन सपोर्ट +Comment[hr]=Plasmin podatkovni mehanizam koji podržava Python +Comment[hu]=Plazma adatkezelő modul Pythonhoz +Comment[ia]=Supporto de motor de datos de Plasma pro Python +Comment[id]=Mesin data Plasma didukung oleh Python +Comment[is]=Plasma gagnavélarstuðningur fyrir Python +Comment[ja]=Python のための Plasma データエンジンのサポート +Comment[kk]=Python деректер тетігінің Plasma қолдауы +Comment[km]=កា​រគាំទ្រ​ម៉ាស៊ីន​ទិន្នន័យ​ប្លាស្មា​សម្រាប់ Python +Comment[kn]=ಪೈಥಾನ್‌ಗಾಗಿ ಪ್ಲಾಸ್ಮಾ ದತ್ತ ಸಾಧನದ ಬೆಂಬಲ +Comment[ko]=파이썬을 위한 Plasma 데이터 엔진 지원 +Comment[lt]=Plasma duomenų variklio palaikymas Python kalbai +Comment[lv]=Plasma datu dzinēju atbalsts Python +Comment[ml]=പൈത്തിണിനുള്ള പ്ലാസ്മ ഡാറ്റാഎഞ്ചിന്‍ പിന്തുണ +Comment[mr]=Python करिता Plasma माहिती इन्जीन समर्थन +Comment[nb]=Plasma datamotor-støtte for Python +Comment[nds]=Plasma-Datenkarnünnerstütten för Python +Comment[nl]=Plasma-gegevensengine-ondersteuning voor Python +Comment[nn]=Plasma-datamotorstøtte for Python +Comment[or]=ପାଇଥନ ପାଇଁ ପ୍ଲାଜମା ତଥ୍ୟ ମେସିନ ସମର୍ଥନ +Comment[pa]=ਪਾਈਥਨ ਲਈ ਪਲਾਜ਼ਮਾ ਡਾਟਾ ਇੰਜਣ ਸਹਿਯੋਗ +Comment[pl]=Obsługa silnika danych Plazmy w Pythonie +Comment[pt]=Suporte para os motores de dados do Plasma em Python +Comment[pt_BR]=Suporte aos mecanismos de dados em Python +Comment[ro]=Suport motor de date Plasma pentru Python +Comment[ru]=Поддержка источников данных для Python +Comment[si]=Plasma data engine support for Python +Comment[sk]=Podpora dátového nástroja plasmy pre Python +Comment[sl]=Podpora za podatkovne vire napisane v Pythonu +Comment[sr]=Подршка плазма датомотора за питон +Comment[sr@ijekavian]=Подршка плазма датомотора за питон +Comment[sr@ijekavianlatin]=Podrška plasma datomotora za Python +Comment[sr@latin]=Podrška plasma datomotora za Python +Comment[sv]=Plasma datagränssnittstöd för Python +Comment[ta]=Plasma data engine support for Python +Comment[te]=ఫైథాన్ మద్దతుకొరకు ప్లాస్మా డాటా యింజన్ +Comment[tg]=Пуштибонии Python дар асоси маълумоти Plasma +Comment[th]=กลไกข้อมูลของพลาสมาที่เป็นภาษาไพธอน +Comment[tr]=Python için Plasma veri motoru desteği +Comment[ug]=Python نىڭ Plasma سانلىق-مەلۇمات ماتورىنى قوللىشى +Comment[uk]=Підтримка у рушіях даних для Python +Comment[wa]=Sopoirt po Python do moteur di dnêyes di Plasma +Comment[x-test]=xxPlasma data engine support for Pythonxx +Comment[zh_CN]=Python 的 Plasma 数据引擎支持 +Comment[zh_TW]=支援 Python 的 Plasma 資料引擎 + +X-KDE-ServiceTypes=Plasma/ScriptEngine +Type=Service +Icon=text-x-script +X-KDE-Library=kpythonpluginfactory +X-KDE-PluginKeyword=plasma_scriptengine_python/pydataengine.py +X-EngineName=pythondataengine +X-Plasma-API=python +X-Plasma-ComponentTypes=DataEngine diff --git a/plasma/generic/scriptengines/python/plasma-scriptengine-runner-python.desktop b/plasma/generic/scriptengines/python/plasma-scriptengine-runner-python.desktop new file mode 100644 index 00000000..c21118c4 --- /dev/null +++ b/plasma/generic/scriptengines/python/plasma-scriptengine-runner-python.desktop @@ -0,0 +1,133 @@ +[Desktop Entry] +Name=Python Runner +Name[ar]=مشغل بايثون +Name[ast]=Llanzador Python +Name[bg]=Стартер с Python +Name[bs]=Python izvođač +Name[ca]=Executor en Python +Name[ca@valencia]=Executor en Python +Name[cs]=Python spouštěč +Name[da]=Python Runner +Name[de]=Python-Starter +Name[el]=Εκτελεστής Python +Name[en_GB]=Python Runner +Name[eo]=Pitona motoro +Name[es]=Lanzador Python +Name[et]=Pythoni käivitaja +Name[eu]=Python abiarazlea +Name[fi]=Python-suoritusohjelma +Name[fr]=Lanceur Python +Name[ga]=Feidhmitheoir Python +Name[gl]=Executor en Python +Name[gu]=Python રનર +Name[he]=Python Runner +Name[hi]=पायथन रनर +Name[hr]=Python Runner +Name[hu]=Python-indító +Name[ia]=Executor de Python +Name[id]=Pelari Python +Name[is]=Python keyrari +Name[ja]=Python ラナー +Name[kk]=Python-ды жегу +Name[km]=កម្មវិធី​រត់ Python +Name[kn]=ಪೈಥಾನ್ ರನ್ನರ್ +Name[ko]=파이썬 실행기 +Name[lt]=Python leistukas +Name[lv]=Python darbinātājs +Name[mr]=पायथोन रनर +Name[nb]=Python-kjører +Name[nds]=Python-Dreger +Name[nl]=Python-starter +Name[nn]=Python-køyrar +Name[pa]=ਪਾਈਥਨ ਰਨਰ +Name[pl]=Uruchamianie w Pythonie +Name[pt]=Módulo de Execução em Python +Name[pt_BR]=Execução em Python +Name[ro]=Executor Python +Name[ru]=Модули запуска команд на языке Python +Name[si]=Python ධාවකය +Name[sk]=Python spúšťač +Name[sl]=Zaganjalnik v Pythonu +Name[sr]=питонски извођач +Name[sr@ijekavian]=питонски извођач +Name[sr@ijekavianlatin]=Python izvođač +Name[sr@latin]=Python izvođač +Name[sv]=Python körningsprogram +Name[tg]=Системаи санаи Python +Name[th]=ตัวเรียกใช้โปรแกรมภาษาไพธอน +Name[tr]=Python Çalıştırıcı +Name[ug]=Python ئىجراچىسى +Name[uk]=Запуск для Python +Name[wa]=Enondeu Python +Name[x-test]=xxPython Runnerxx +Name[zh_CN]=Python 运行器 +Name[zh_TW]=Python 執行器 +Comment=Plasma Runner support for Python +Comment[ar]=دعم مشغل بلازما لبايثون +Comment[ast]=Implementación de llanzador Plasma pa Python +Comment[bg]=Поддръжка за създаване на стартери на Plasma с Python +Comment[bs]=Podrška plazma izvođača za Python +Comment[ca]=Implementació de l'executor del Plasma per al Python +Comment[ca@valencia]=Implementació de l'executor del Plasma per al Python +Comment[cs]=Podpora Plasma spouštěče pro Python +Comment[da]=Understøttelse af Plasma Runner til Python +Comment[de]=Plasma-Starter-Unterstützung für Python +Comment[el]=Υποστήριξη εκτελεστή Plasma για την Python +Comment[en_GB]=Plasma Runner support for Python +Comment[es]=Implementación de lanzador Plasma para Python +Comment[et]=Plasma käivitaja toetus Pythonile +Comment[eu]=Python-erako Plasmaren abiarazlearen euskarria +Comment[fi]=Plasma-suoritusohjelmatuki Python-kielelle +Comment[fr]=Prise en charge du lanceur Plasma pour Python +Comment[gl]=Executor de Plasma que permite usar Python +Comment[he]=תמיכה ב־Runner של Plasma עבור Python +Comment[hi]=पायथन के लिए प्लाज्मा रनर समर्थन +Comment[hr]=Plasma Runner podrška za Python +Comment[hu]=Plazma-indító támogatás Pythonhoz +Comment[ia]=Supporto de executor de Plasma pro Python +Comment[id]=Dukungan Pelari Plasma terhadap Python +Comment[is]=Plasma gagnavélarstuðningur fyrir Python +Comment[ja]=Python のための Plasma ラナーサポート +Comment[kk]=Plasma-дағы Python-ды жегуін қолдауы +Comment[km]=ការ​គាំទ្រ​កម្មវិធី​រត់​ប្លាស្មា​សម្រាប់ Python +Comment[kn]=ಪೈಥಾನ್‌ಗಾಗಿ ಪ್ಲಾಸ್ಮಾ ರನ್ನರ್ ಬೆಂಬಲ +Comment[ko]=Plasma 파이썬 실행기 +Comment[lt]=Plasma paleidiklio palaikymas Python kalbai +Comment[lv]=Plasma darbinātāja atbalsts Python +Comment[mr]=पायथोन करिता प्लाज्मा रनर समर्थन +Comment[nb]=Plasma kjørerstøtte for Python +Comment[nds]=Plasma-Dregerünnerstütten för Python +Comment[nl]=Plasma-starter-ondersteuning voor Python +Comment[nn]=Plasma-køyrarstøtte for Python +Comment[pa]=ਪਾਈਥਨ ਲਈ ਪਲਾਜ਼ਮਾ ਰਨਰ ਸਹਿਯੋਗ +Comment[pl]=Obsługa programów uruchamiających dla Pythona +Comment[pt]=Suporte de módulos de execução do Plasma em Python +Comment[pt_BR]=Suporte aos mecanismos de execução do Plasma para Python +Comment[ro]=Suport executori Plasma pentru Python +Comment[ru]=Поддержка модулей запуска KRunner на языке Python +Comment[si]=Python සඳහා ප්ලාස්මා ධාවක සහාය +Comment[sk]=Podpora spúšťača plasmy pre Python +Comment[sl]=Podpora za zaganjalnike napisane v Pythonu +Comment[sr]=Подршка плазма извођача за питон +Comment[sr@ijekavian]=Подршка плазма извођача за питон +Comment[sr@ijekavianlatin]=Podrška plasma izvođača za Python +Comment[sr@latin]=Podrška plasma izvođača za Python +Comment[sv]=Plasma körningsstöd för Python +Comment[tg]=Пуштибонии Python дар асоси маълумоти Plasma +Comment[th]=ตัวเรียกใช้งานของพลาสมาที่รองรับสำหรับโปรแกรมภาษาไพธอน +Comment[tr]=Python için Plasma Çalıştırıcı desteği +Comment[ug]=Python نى قوللايدىغان Plasma ئىجراچىسى +Comment[uk]=Підтримка Python у інструментах запуску +Comment[wa]=Sopoirt po Python di l' enondeu di Plasma +Comment[x-test]=xxPlasma Runner support for Pythonxx +Comment[zh_CN]=支持 Python 的 Plasma 运行器 +Comment[zh_TW]=支援 Python 的執行器 + +X-KDE-ServiceTypes=Plasma/ScriptEngine +Type=Service +Icon=text-x-script +X-KDE-Library=kpythonpluginfactory +X-KDE-PluginKeyword=plasma_scriptengine_python/pyrunner.py +X-EngineName=pythonrunner +X-Plasma-API=python +X-Plasma-ComponentTypes=Runner diff --git a/plasma/generic/scriptengines/python/plasma-scriptengine-wallpaper-python.desktop b/plasma/generic/scriptengines/python/plasma-scriptengine-wallpaper-python.desktop new file mode 100644 index 00000000..17491cdf --- /dev/null +++ b/plasma/generic/scriptengines/python/plasma-scriptengine-wallpaper-python.desktop @@ -0,0 +1,137 @@ +[Desktop Entry] +Name=Python wallpaper +Name[ar]=خلفية شاشة مكتوبة باستخدام بايثون +Name[ast]=Fondu d'escritoriu en Python +Name[bg]=Тапети с Python +Name[bn]=পাইথন ওয়ালপেপার +Name[bs]=Python pozadinska slika +Name[ca]=Fons d'escriptori en Python +Name[ca@valencia]=Fons d'escriptori en Python +Name[cs]=Python pozadí plochy +Name[da]=Python-baggrundsbillede +Name[de]=Python-Hintergrundbild +Name[el]=Ταπετσαρία Python +Name[en_GB]=Python wallpaper +Name[eo]=Pitona ekranfono +Name[es]=Fondo de escritorio en Python +Name[et]=Pythoni taustapilt +Name[eu]=Python-en horma-papera +Name[fi]=Python-taustakuva +Name[fr]=Papier peint Python +Name[fy]=Python eftergrûnôfbylding +Name[ga]=Cúlbhrat Python +Name[gl]=Fondo de escritorio en Python +Name[gu]=પાયથોન વોલપેપર +Name[he]=רקע לשולחן עבודה של Python +Name[hr]=Python podloga +Name[hu]=Python háttérkép +Name[ia]=Tapete de papiro de Python +Name[id]=Wallpaper Python +Name[is]=Python veggfóður +Name[ja]=Python 壁紙 +Name[kk]=Python тұсқағазы +Name[km]=ផ្ទាំង​រូបភាព​របស់ Python +Name[kn]=ಪೈಥಾನ್ ಹಿನ್ನೆಲೆ ತೆರೆಚಿತ್ರ (ವಾಲ್ ಪೇಪರ್) +Name[ko]=파이썬 배경 그림 +Name[lt]=Python darbastalio fonas +Name[lv]=Python ekrāntapete +Name[ml]=പൈത്തണ്‍ ചുവര്‍ചിത്രം +Name[mr]=पायथोन वॉलपेपर +Name[nb]=Python bakgrunnsbilde +Name[nds]=Python-Achtergrundbild +Name[nl]=Python-achtergrondafbeelding +Name[nn]=Python-bakgrunnsbilete +Name[pa]=ਪਾਈਥਨ ਵਾਲਪੇਪਰ +Name[pl]=Tapeta w Pythonie +Name[pt]=Papel de parede em Python +Name[pt_BR]=Papel de parede em Python +Name[ro]=Fundal Python +Name[ru]=Обои рабочего стола на языке Python +Name[si]=Python වෝල්පේපර +Name[sk]=Python tapeta +Name[sl]=Ozadje v Pythonu +Name[sr]=питонски тапет +Name[sr@ijekavian]=питонски тапет +Name[sr@ijekavianlatin]=Python tapet +Name[sr@latin]=Python tapet +Name[sv]=Python skrivbordsunderlägg +Name[tg]=Барномаи Plasma +Name[th]=ภาพพื้นหลังของโปรแกรมไพธอน +Name[tr]=Python duvar kağıdı +Name[ug]=Python تام قەغىزى +Name[uk]=Шпалери для Python +Name[wa]=Tapisreye Python +Name[x-test]=xxPython wallpaperxx +Name[zh_CN]=Python 壁纸 +Name[zh_TW]=Python 桌布 +Comment=Plasma wallpaper support for Python +Comment[ar]=دعم خلفية شاشة بلازما لبايثون +Comment[ast]=Fondos de pantalla de Plasma pa Python +Comment[bg]=Поддръжка за работа с тапети на Plasma с Python +Comment[bs]=Podrška plazma pozadinskih slika za Python +Comment[ca]=Implementació de fons d'escriptori del Plasma per al Python +Comment[ca@valencia]=Implementació de fons d'escriptori del Plasma per al Python +Comment[cs]=Podpora Plasma pozadí plochy pro Python +Comment[da]=Understøttelse af Plasma wallpaper til Python +Comment[de]=Unterstützung in Plasma für Python-Hintergrundbilder +Comment[el]=Υποστήριξη ταπετσαρίας Plasma για την Python +Comment[en_GB]=Plasma wallpaper support for Python +Comment[es]=Fondos de pantalla de Plasma para Python +Comment[et]=Plasma taustapildi toetus Pythonile +Comment[eu]=Python-erako Plasma horma-paperaren euskarria +Comment[fi]=Plasma-taustakuvatuki Python-kielelle +Comment[fr]=Prise en charge du papier peint de Plasma pour Python +Comment[fy]=Plasma eftergrûnôfbylding stipe foar Python +Comment[gl]=Compatibilidade de Python co fondo de escritorio de Plasma +Comment[he]=תמיכה ברקעי שולחן עבודה של Plasma עבור Python +Comment[hi]=पायथन के लिए प्लाज्मा वालपेपर समर्थन +Comment[hr]=Plasmina podloga koja podržava Python +Comment[hu]=Plasma-háttérkép támogatás Pythonhoz +Comment[ia]=Supporto de tapete de papiro pro Python +Comment[id]=Wallpeper Plasma yang mendukung Python +Comment[is]=Plasma veggfóðurstuðningur fyrir Python +Comment[ja]=Python のための Plasma の壁紙 +Comment[kk]=Plasma-дағы Python тұсқағазының қолдауы +Comment[km]=ការ​គាំទ្រ​​ផ្ទាំង​​រូបភាព​ប្លាស្មា​សម្រាប់ Python +Comment[kn]=ಪೈಥಾನ್‌ಗಾಗಿ ಪ್ಲಾಸ್ಮಾ ಗಣಕತೆರೆ ಹಿನ್ನೆಲೆ ಚಿತ್ರ ಬೆಂಬಲ +Comment[ko]=파이썬을 위한 Plasma 배경 그림 지원 +Comment[lt]=Plasma apmušalo palaikymas Python kalbai +Comment[lv]=Plasma ekrāntapetes atbalsts Python +Comment[ml]=പൈത്തിണിനുള്ള പ്ലാസ്മ ചുമര്‍ച്ചിത്ര പിന്തുണ +Comment[mr]=पायथोन करिता प्लाज्मा वॉलपेपर समर्थन +Comment[nb]=Plasma bakgrunnsbilde-støtte for Python +Comment[nds]=Plasma-Achtergrundünnerstütten för Python +Comment[nl]=Plasma-achtergrondafbeelding-ondersteuning voor Python +Comment[nn]=Plasma-bakgrunnsbiletstøtte for Python +Comment[pa]=ਪਾਈਥਨ ਲਈ ਪਲਾਜ਼ਮਾ ਵਾਲਪੇਪਰ ਸਹਿਯੋਗ +Comment[pl]=Obsługa tapet Plazmy w Pythonie +Comment[pt]=Suporte para os papéis de parede do Plasma em Python +Comment[pt_BR]=Suporte aos mecanismos a papéis de parede do Plasma em Python +Comment[ro]=Suport fundaluri Plasma pentru Python +Comment[ru]=Поддержка обоев рабочего стола на языке Python +Comment[si]=Python සඳහා ප්ලාස්මා වෝල්පේපර් සහය +Comment[sk]=Podpora tapiet plasmy pre Python +Comment[sl]=Podpora za ozadja napisana v Pythonu +Comment[sr]=Подршка плазма тапета за питон +Comment[sr@ijekavian]=Подршка плазма тапета за питон +Comment[sr@ijekavianlatin]=Podrška plasma tapeta za Python +Comment[sr@latin]=Podrška plasma tapeta za Python +Comment[sv]=Plasma skrivbordsunderläggsstöd för Python +Comment[tg]=Пуштибонии Python дар асоси маълумоти Plasma +Comment[th]=ภาพพื้นหลังของพลาสมาที่รองรับสำหรับโปรแกรมภาษาไพธอน +Comment[tr]=Python için Plasma duvar kağıdı desteği +Comment[ug]=Python نى قوللايدىغان Plasma تام قەغەز +Comment[uk]=Підтримка Python у шпалерах Плазми +Comment[wa]=Sopoirt po Python del tapisreye di Plasma +Comment[x-test]=xxPlasma wallpaper support for Pythonxx +Comment[zh_CN]=支持 Python 的 Plasma 壁纸 +Comment[zh_TW]=支援 Python 的 Plasma 桌布 + +X-KDE-ServiceTypes=Plasma/ScriptEngine +Type=Service +Icon=text-x-script +X-KDE-Library=kpythonpluginfactory +X-KDE-PluginKeyword=plasma_scriptengine_python/pywallpaper.py +X-EngineName=pythonwallpaper +X-Plasma-API=python +X-Plasma-ComponentTypes=Wallpaper diff --git a/plasma/generic/scriptengines/python/plasma_importer.py b/plasma/generic/scriptengines/python/plasma_importer.py new file mode 100644 index 00000000..dae245ae --- /dev/null +++ b/plasma/generic/scriptengines/python/plasma_importer.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2008 Simon Edwards +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +import sys +import os +import imp + +PY3 = sys.version_info[0] == 3 + + +class PlasmaImporter(object): + def __init__(self): + self.toplevel = {} + self.toplevelcount = {} + self.marker = '' + str(id(self)) + sys.path.append(self.marker) + sys.path_hooks.append(self.hook) + + def hook(self,path): + if path==self.marker: + return self + else: + raise ImportError() + + def register_top_level(self,name,path): + if name not in self.toplevel: + self.toplevelcount[name] = 1 + self.toplevel[name] = path + else: + self.toplevelcount[name] += 1 + + def unregister_top_level(self,name): + value = self.toplevelcount[name]-1 + self.toplevelcount[name] = value + if value==0: + del self.toplevelcount[name] + del self.toplevel[name] + for key in list(sys.modules.keys()): + if key==name or key.startswith(name+"."): + del sys.modules[key] + + def find_module(self,fullname, path=None): + location = self.find_pymod(fullname) + if location is not None: + return self + else: + return None + + # Find the given module in the plasma directory. + # Result a tuple on success otherwise None. The tuple contains the location + # of the module/package in disk and a boolean indicating if it is a package + # or module + def find_pymod(self,modulename): + parts = modulename.split('.') + toppackage = parts[0] + rest = parts[1:] + + if toppackage in self.toplevel: + path = self.toplevel[toppackage] + if len(rest)==0: + # Simple top level Plasma package + return (path,True) + else: + restpath = apply(os.path.join,rest) + fullpath = os.path.join(path,'contents','code',restpath) + if os.path.isdir(fullpath): + return (fullpath,True) + elif os.path.exists(fullpath+'.py'): + return (fullpath+'.py',False) + else: + return None + + def _get_code(self,location): + return open(location).read() + + def load_module(self, fullname): + location,ispkg = self.find_pymod(fullname) + if ispkg: # Package dir. + initlocation = os.path.join(location,'__init__.py') + code = None + if os.path.isfile(initlocation): + code = open(initlocation) + else: + code = open(location) + + mod = sys.modules.setdefault(fullname, imp.new_module(fullname)) + mod.__file__ = location #"<%s>" % self.__class__.__name__ + mod.__loader__ = self + if ispkg: + mod.__path__ = [self.marker] + if code is not None: + try: + if PY3: + exec(code in mod.__dict__) + else: + exec code in mod.__dict__ + finally: + code.close() + return mod + +#plasma_importer = PlasmaImporter() +#plasma_importer.register_top_level('plasma_pyclock','/home/sbe/devel/python_plasma_2/test/plasma-pyclock') +#from plasma_pyclock import main diff --git a/plasma/generic/scriptengines/python/plasmascript.py b/plasma/generic/scriptengines/python/plasmascript.py new file mode 100644 index 00000000..ba149cf5 --- /dev/null +++ b/plasma/generic/scriptengines/python/plasmascript.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2008 Simon Edwards +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# Plasma applet API for Python + +from PyQt4.QtCore import QObject +from PyQt4.QtGui import QGraphicsWidget +from PyKDE4.plasma import Plasma # Plasma C++ namespace + +#import sip +#import gc + +class Applet(QObject): + ''' Subclass Applet in your module and return an instance of it in a global function named + applet(). Implement the following functions to breathe life into your applet: + * paint - Draw the applet given a QPainter and some options + It provides the same API as Plasma.Applet; it just has slightly less irritating event names. ''' + def __init__(self, parent=None): + # this should be set when the applet is created + QObject.__init__(self, parent) + #sip.settracemask(0x3f) + self.applet = None + self.applet_script = None + self._forward_to_applet = True + + def __getattr__(self, key): + # provide transparent access to the real applet instance + if self._forward_to_applet: + try: + return getattr(self.applet_script, key) + except: + return getattr(self.applet, key) + else: + raise AttributeError(key) + + def _enableForwardToApplet(self): + self._forward_to_applet = True + def _disableForwardToApplet(self): + self._forward_to_applet = False + + # Events + def setApplet(self,applet): + self.applet = applet + + def setAppletScript(self,appletScript): + self.applet_script = appletScript + + def init(self): + pass + + def configChanged(self): + pass + + def paintInterface(self, painter, options, rect): + pass + + def constraintsEvent(self, flags): + pass + + def showConfigurationInterface(self): + self.dlg = self.standardConfigurationDialog() + self.createConfigurationInterface(self.dlg) + self.addStandardConfigurationPages(self.dlg) + self.dlg.show() + + def createConfigurationInterface(self, dlg): + pass + + def contextualActions(self): + return [] + + def shape(self): + return QGraphicsWidget.shape(self.applet) + + def initExtenderItem(self, item): + print ("Missing implementation of initExtenderItem in the applet " + \ + item.config().readEntry('SourceAppletPluginName', '').toString() + \ + "!\nAny applet that uses extenders should implement initExtenderItem to " + \ + "instantiate a widget.") + + def saveState(self, config): + pass + +########################################################################### +class DataEngine(QObject): + def __init__(self, parent=None): + QObject.__init__(self, parent) + self.dataengine = None + self.dataengine_script = None + + def setDataEngine(self,dataEngine): + self.dataEngine = dataEngine + + def setDataEngineScript(self,dataEngineScript): + self.data_engine_script = dataEngineScript + + def __getattr__(self, key): + # provide transparent access to the real dataengine script instance + try: + return getattr(self.data_engine_script, key) + except: + return getattr(self.dataEngine, key) + + def init(self): + pass + + def sources(self): + return [] + + def sourceRequestEvent(self,name): + return False + + def updateSourceEvent(self,source): + return False + + def serviceForSource(self,source): + return Plasma.DataEngineScript.serviceForSource(self.data_engine_script,source) + +########################################################################### +class Wallpaper(QObject): + def __init__(self, parent=None): + QObject.__init__(self, parent) + self.wallpaper = None + self.wallpaper_script = None + + def setWallpaper(self,wallpaper): + self.wallpaper = wallpaper + + def setWallpaperScript(self,wallpaperScript): + self.wallpaper_script = wallpaperScript + + def __getattr__(self, key): + # provide transparent access to the real wallpaper script instance + try: + return getattr(self.wallpaper_script, key) + except: + return getattr(self.wallpaper, key) + + def init(self, config): + pass + + def paint(self,painter, exposedRect): + pass + + def save(self,config): + pass + + def createConfigurationInterface(self,parent): + return None + + def mouseMoveEvent(self,event): + pass + + def mousePressEvent(self,event): + pass + + def mouseReleaseEvent(self,event): + pass + + def wheelEvent(self,event): + pass + + def renderCompleted(self, image): + pass + + def urlDropped(self, url): + pass + +########################################################################### +class Runner(QObject): + def __init__(self, parent=None): + QObject.__init__(self, parent) + self.runner = None + self.runner_script = None + + def setRunner(self,runner): + self.runner = runner + + def setRunnerScript(self,runnerScript): + self.runner_script = runnerScript + + def __getattr__(self, key): + # provide transparent access to the real runner script instance + try: + return getattr(self.runner_script, key) + except: + return getattr(self.runner, key) + + def init(self): + pass + + def match(self, search): + pass + + def run(self, search, action): + pass + + def prepare(self): + pass + + def teardown(self): + pass + + def createRunOptions(self, widget): + pass + + def reloadConfiguration(self): + pass diff --git a/plasma/generic/scriptengines/python/pyappletscript.py b/plasma/generic/scriptengines/python/pyappletscript.py new file mode 100644 index 00000000..907d10ad --- /dev/null +++ b/plasma/generic/scriptengines/python/pyappletscript.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2008 Simon Edwards +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from PyKDE4.plasma import Plasma +import plasma_importer +import os.path + +class PythonAppletScript(Plasma.AppletScript): + importer = None + + def __init__(self, parent): + Plasma.AppletScript.__init__(self,parent) + #print("PythonAppletScript()") + if PythonAppletScript.importer is None: + PythonAppletScript.importer = plasma_importer.PlasmaImporter() + self.initialized = False + + def init(self): + #print("Script Name: " + str(self.applet().name())) + #print("Script Category: " + str(self.applet().category())) + + # applet() cannot be relied on to give the right details in the destructor, + # so the plugin name is stored aside. (n.b module.__name__ cannot be relied + # on either; it might have been changed in the module itself) + self.moduleName = str(self.applet().pluginName()) + #print("pluginname: " + str(self.applet().pluginName())) + self.pluginName = 'applet_' + self.moduleName.replace('-','_') + + PythonAppletScript.importer.register_top_level(self.pluginName, str(self.applet().package().path())) + + #print("mainScript: " + str(self.mainScript())) + #print("package path: " + str(self.applet().package().path())) + + # import the code at the file name reported by mainScript() + relpath = os.path.relpath(str(self.mainScript()),str(self.applet().package().path())) + if relpath.startswith("contents/code/"): + relpath = relpath[14:] + if relpath.endswith(".py"): + relpath = relpath[:-3] + relpath = relpath.replace("/",".") + self.module = __import__(self.pluginName+'.'+relpath) + + # Plasma main scripts not necessarily are named "main" + # So we use __dict__ to get the right main script name + basename = os.path.basename(str(self.mainScript())) + basename = os.path.splitext(basename)[0] + self.pyapplet = self.module.__dict__[basename].CreateApplet(None) + self.pyapplet.setApplet(self.applet()) + self.pyapplet.setAppletScript(self) + self.connect(self.applet(), SIGNAL('extenderItemRestored(Plasma::ExtenderItem*)'), + self, SLOT('initExtenderItem(Plasma::ExtenderItem*)')) + self.connect(self, SIGNAL('saveState(KConfigGroup&)'), + self, SLOT('saveStateSlot(KConfigGroup&)')) + self._setUpEventHandlers() + self.initialized = True + + self.pyapplet.init() + return True + + def __dtor__(self): + #print("~PythonAppletScript()") + if not self.initialized: + return + + PythonAppletScript.importer.unregister_top_level(self.pluginName) + self.pyapplet = None + + @pyqtSignature("initExtenderItem(Plasma::ExtenderItem*)") + def initExtenderItem(self, item): + if not self.initialized: + return + self.pyapplet.initExtenderItem(item) + + @pyqtSignature("saveStateSlot(KConfigGroup&)") + def saveStateSlot(self, config): + if not self.initialized: + return + self.pyapplet.saveState(config) + + def constraintsEvent(self, constraints): + if not self.initialized: + return + self.pyapplet.constraintsEvent(constraints) + + def showConfigurationInterface(self): + if not self.initialized: + return + #print("Script: showConfigurationInterface") + self.pyapplet.showConfigurationInterface() + + def configChanged(self): + if not self.initialized: + return + self.pyapplet.configChanged() + + def paintInterface(self, painter, option, contentsRect): + if not self.initialized: + return + self.pyapplet.paintInterface(painter, option, contentsRect) + + def contextualActions(self): + if not self.initialized: + return + + #print("pythonapplet contextualActions()") + return self.pyapplet.contextualActions() + + def shape(self): + if not self.initialized: + return QPainterPath() + return self.pyapplet.shape() + + def eventFilter(self, obj, event): + handler = self.event_handlers.get(event.type(),None) + if handler is not None: + apply(getattr(self.pyapplet,handler), (event,) ) + return True + else: + return False + + def _setUpEventHandlers(self): + self.event_handlers = {} + + self.pyapplet._disableForwardToApplet() + for event_type,handler in { + QEvent.GraphicsSceneMousePress: "mousePressEvent", + QEvent.GraphicsSceneContextMenu: "contextMenuEvent", + QEvent.GraphicsSceneDragEnter: "dragEnterEvent", + QEvent.GraphicsSceneDragLeave: "dragLeaveEvent", + QEvent.GraphicsSceneDragMove: "dragMoveEvent", + QEvent.GraphicsSceneDrop: "dropEvent", + QEvent.FocusIn: "focusInEvent", + QEvent.FocusOut: "focusOutEvent", + QEvent.GraphicsSceneHoverEnter: "hoverEnterEvent", + QEvent.GraphicsSceneHoverLeave: "hoverLeaveEvent", + QEvent.GraphicsSceneHoverMove: "hoverMoveEvent", + QEvent.InputMethod: "inputMethodEvent", + QEvent.KeyPress: "keyPressEvent", + QEvent.KeyRelease: "keyReleaseEvent", + QEvent.GraphicsSceneMouseDoubleClick: "mouseDoubleClickEvent", + QEvent.GraphicsSceneMouseMove: "mouseMoveEvent", + QEvent.GraphicsSceneMousePress: "mousePressEvent", + QEvent.GraphicsSceneMouseRelease: "mouseReleaseEvent", + QEvent.GraphicsSceneWheel: "wheelEvent" + }.iteritems(): + if hasattr(self.pyapplet,handler): + self.event_handlers[event_type] = handler + self.pyapplet._enableForwardToApplet() + + if self.event_handlers: + self.applet().installEventFilter(self) + +def CreatePlugin(widget_parent, parent, component_data): + return PythonAppletScript(parent) diff --git a/plasma/generic/scriptengines/python/pydataengine.py b/plasma/generic/scriptengines/python/pydataengine.py new file mode 100644 index 00000000..edb93c9c --- /dev/null +++ b/plasma/generic/scriptengines/python/pydataengine.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2008 Simon Edwards +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from PyKDE4.plasma import Plasma +import plasma_importer +import os.path + +class PythonDataEngineScript(Plasma.DataEngineScript): + importer = None + + def __init__(self, parent): + Plasma.DataEngineScript.__init__(self,parent) + if PythonDataEngineScript.importer is None: + PythonDataEngineScript.importer = plasma_importer.PlasmaImporter() + self.initialized = False + + def init(self): + self.moduleName = str(self.dataEngine().pluginName()) + self.pluginName = 'dataengine_' + self.moduleName.replace('-','_') + + PythonDataEngineScript.importer.register_top_level(self.pluginName, str(self.dataEngine().package().path())) + + # import the code at the file name reported by mainScript() + relpath = os.path.relpath(str(self.mainScript()),str(self.dataEngine().package().path())) + if relpath.startswith("contents/code/"): + relpath = relpath[14:] + if relpath.endswith(".py"): + relpath = relpath[:-3] + relpath = relpath.replace("/",".") + self.module = __import__(self.pluginName+'.'+relpath) + # The script may not necessarily be called "main" + # So we use __dict__ to look up the right name + basename = os.path.basename(str(self.mainScript())) + basename = os.path.splitext(basename)[0] + + self.pydataengine = self.module.__dict__[basename].CreateDataEngine(None) + self.pydataengine.setDataEngine(self.dataEngine()) + self.pydataengine.setDataEngineScript(self) + self.pydataengine.init() + + self.initialized = True + return True + + def __dtor__(self): + PythonDataEngineScript.importer.unregister_top_level(self.pluginName) + self.pydataengine = None + + def sources(self): + return self.pydataengine.sources() + + def serviceForSource(self,source): + return self.pydataengine.serviceForSource(source) + + def sourceRequestEvent(self,name): + return self.pydataengine.sourceRequestEvent(name) + + def updateSourceEvent(self,source): + return self.pydataengine.updateSourceEvent(source) + +def CreatePlugin(widget_parent, parent, component_data): + return PythonDataEngineScript(parent) diff --git a/plasma/generic/scriptengines/python/pyrunner.py b/plasma/generic/scriptengines/python/pyrunner.py new file mode 100644 index 00000000..e520e307 --- /dev/null +++ b/plasma/generic/scriptengines/python/pyrunner.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2008 Simon Edwards +# Copyright 2009 Petri Damstén +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from PyKDE4.plasma import Plasma +import plasma_importer +import os.path + +class PythonRunnerScript(Plasma.RunnerScript): + importer = None + + def __init__(self, parent): + Plasma.RunnerScript.__init__(self,parent) + if PythonRunnerScript.importer is None: + PythonRunnerScript.importer = plasma_importer.PlasmaImporter() + self.initialized = False + + def init(self): + self.moduleName = str(self.runner().package().metadata().pluginName()) + self.pluginName = 'runner_' + self.moduleName.replace('-','_') + + PythonRunnerScript.importer.register_top_level(self.pluginName, str(self.runner().package().path())) + + # import the code at the file name reported by mainScript() + relpath = os.path.relpath(str(self.mainScript()),str(self.runner().package().path())) + if relpath.startswith("contents/code/"): + relpath = relpath[14:] + if relpath.endswith(".py"): + relpath = relpath[:-3] + relpath = relpath.replace("/",".") + self.module = __import__(self.pluginName+'.'+relpath) + basename = os.path.basename(str(self.mainScript())) + basename = os.path.splitext(basename)[0] + self.pyrunner = self.module.__dict__[basename].CreateRunner(None) + self.pyrunner.setRunner(self.runner()) + self.pyrunner.setRunnerScript(self) + self.connect(self, SIGNAL('prepare()'), self, SLOT('prepare()')) + self.connect(self, SIGNAL('teardown()'), self, SLOT('teardown()')) + self.connect(self, SIGNAL('createRunOptions(QWidget*)'), + self, SLOT('createRunOptions(QWidget*)')) + self.connect(self, SIGNAL('reloadConfiguration()'), + self, SLOT('reloadConfiguration()')) + self.pyrunner.init() + + self.initialized = True + return True + + def __dtor__(self): + PythonRunnerScript.importer.unregister_top_level(self.pluginName) + self.pyrunner = None + + def match(self, search): + self.pyrunner.match(search) + + def run(self, search, action): + self.pyrunner.run(search, action) + + @pyqtSignature("prepare()") + def prepare(self): + self.pyrunner.prepare() + + @pyqtSignature("teardown()") + def teardown(self): + self.pyrunner.teardown() + + @pyqtSignature("createRunOptions(QWidget*)") + def createRunOptions(self, widget): + self.pyrunner.createRunOptions(widget) + + @pyqtSignature("reloadConfiguration()") + def reloadConfiguration(self): + self.pyrunner.reloadConfiguration() + +def CreatePlugin(widget_parent, parent, component_data): + return PythonRunnerScript(parent) diff --git a/plasma/generic/scriptengines/python/pywallpaper.py b/plasma/generic/scriptengines/python/pywallpaper.py new file mode 100644 index 00000000..e0e7e8cd --- /dev/null +++ b/plasma/generic/scriptengines/python/pywallpaper.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2008 Simon Edwards +# Copyright 2009 Petri Damstén +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from PyKDE4.plasma import Plasma +import plasma_importer +import os.path + +class PythonWallpaperScript(Plasma.WallpaperScript): + importer = None + + def __init__(self, parent): + Plasma.WallpaperScript.__init__(self,parent) + if PythonWallpaperScript.importer is None: + PythonWallpaperScript.importer = plasma_importer.PlasmaImporter() + self.initialized = False + + def init(self): + self.moduleName = str(self.wallpaper().pluginName()) + self.pluginName = 'wallpaper_' + self.moduleName.replace('-','_') + + PythonWallpaperScript.importer.register_top_level(self.pluginName, str(self.wallpaper().package().path())) + + # import the code at the file name reported by mainScript() + relpath = os.path.relpath(str(self.mainScript()),str(self.wallpaper().package().path())) + if relpath.startswith("contents/code/"): + relpath = relpath[14:] + if relpath.endswith(".py"): + relpath = relpath[:-3] + relpath = relpath.replace("/",".") + self.module = __import__(self.pluginName+'.'+relpath) + self.pywallpaper = self.module.main.CreateWallpaper(None) + self.pywallpaper.setWallpaper(self.wallpaper()) + self.pywallpaper.setWallpaperScript(self) + self.initialized = True + return True + + def __dtor__(self): + PythonWallpaperScript.importer.unregister_top_level(self.pluginName) + self.pywallpaper = None + + def paint(self, painter, exposedRect): + self.pywallpaper.paint(painter, exposedRect) + + def initWallpaper(self, config): + self.pywallpaper.init(config) + + def save(self, config): + self.pywallpaper.save(config) + + def createConfigurationInterface(self, parent): + self.connect(self, SIGNAL('settingsChanged(bool)'), parent, SLOT('settingsChanged(bool)')) + return self.pywallpaper.createConfigurationInterface(parent) + + def settingsChanged(self, changed): + self.emit(SIGNAL('settingsChanged(bool)'), changed) + + def mouseMoveEvent(self, event): + self.pywallpaper.mouseMoveEvent(event) + + def mousePressEvent(self, event): + self.pywallpaper.mousePressEvent(event) + + def mouseReleaseEvent(self, event): + self.pywallpaper.mouseReleaseEvent(event) + + def wheelEvent(self, event): + self.pywallpaper.wheelEvent(event) + + @pyqtSignature("renderCompleted(const QImage&)") + def renderCompleted(self, image): + self.pywallpaper.renderCompleted(image) + + @pyqtSignature("urlDropped(const KUrl&)") + def urlDropped(self, url): + self.pywallpaper.urlDropped(url) + +def CreatePlugin(widget_parent, parent, component_data): + return PythonWallpaperScript(parent) diff --git a/plasma/generic/scriptengines/ruby/CMakeLists.txt b/plasma/generic/scriptengines/ruby/CMakeLists.txt new file mode 100644 index 00000000..b6d744c0 --- /dev/null +++ b/plasma/generic/scriptengines/ruby/CMakeLists.txt @@ -0,0 +1,6 @@ +install(FILES applet.rb DESTINATION ${DATA_INSTALL_DIR}/plasma_scriptengine_ruby) +install(FILES data_engine.rb DESTINATION ${DATA_INSTALL_DIR}/plasma_scriptengine_ruby) + +install(FILES plasma-scriptengine-ruby-applet.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES plasma-scriptengine-ruby-dataengine.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/generic/scriptengines/ruby/ChangeLog b/plasma/generic/scriptengines/ruby/ChangeLog new file mode 100644 index 00000000..24df1d18 --- /dev/null +++ b/plasma/generic/scriptengines/ruby/ChangeLog @@ -0,0 +1,140 @@ +2010-02-14 Richard Dale + +* Special case the constructors of the new Plasma widgets so that they can be +passed a PlasmaScripting::Applet as parent +* Fixed the dialog handling so that it uses the standardConfigurationDialog() +and addStandardConfigurationPages() methods + +2009-08-07 Richard Dale +* Fixed typo in the type signature of the initExtenderItem() slot. Thanks to +David Palacio for reporting the bug + +2009-07-19 Richard Dale +* Use the new name 'extenderItemRestored()' for the signal to connect to +initExtenderItem() + +2009-07-18 Richard Dale +* Add a Ruby version of the C++ extender tutorial example on Techbase + +2009-07-17 Richard Dale +* If an applet has implemented an initExtenderItem() method, then connect the +new initScriptingExtenderItem() signal to it. + +2009-06-16 Richard Dale +* The resize() method doesn't work with scripting plasmoids, so if it is used +output a warning message, and suggest adding a X-Plasma-DefautSize entry in +the metadata.desktop file. + +2009-05-26 Richard Dale +* Add a callback for the configChanged() method in scripting applets + +2009-04-27 Richard Dale +* Added some special casing for the new KDE 4.3 widgets, so they work with +PLasmaScripting::Applet arguments + +2009-04-22 Richard Dale +* Added PlasmaScripting::Containment and PlasmaScripting::PopupApplet classes, + now that scripting containments and popups can be created + +2009-02-10 Richard Dale +* For the methods that need to be special cased to work with + PlasmaScripting::Applet type arguments, add lower case/underscore versions + of the methods + +2009-02-05 Richard Dale +* Added various special casing to the Plasma::ToolTipManager class so you can + pass a PlasmaScripting::Applet to the methods. Thanks to Mathieu Jobin for + reporting the bug. + +2008-12-22 Richard Dale +* Changed the tiger applet example to find its tiger.svg resource from within + the plasmoid package. Thanks to Rany Keddo for helping to get it working. + +2008-12-01 Richard Dale +* Added updateAllSources() and removeSource() slots to the + PlasmScripting::DataEngine +* Add DBus notification to the time data engine example for when the config + changes + +2008-11-18 Richard Dale +* Fix problem with the ruby 'type()' method clashing with the one in + Qt::GraphicsItem subclasses reported by David Palacio +* Added a 'dbpedia-queries' data engine for making SPARQL queries to DBpedia + about music albums +* The sources() and init() methods needn't be implemented by a scripting + data engine + +2008-11-17 Richard Dale +* Fixed missing constructor bug in Qt::GraphicsProxyWidget reported by David + Palacio. Thanks to David for reporting the bug. +* Improved the names of the Ruby applet and dataengine examples +* Allow a PlasmaScripting::Applet to be a parent of all the Qt::GraphicsItem + sub classes in their constructors + +2008-11-05 Richard Dale +* Fixed some bugs in the DataEngineScript class. The expected path was + 'plasma/engines' whereas the plasmapkg tool installs them in + 'plasma/dataengines'. The mainScript() and package() methods hadn't been + implemented and were added. +* Added a 'ruby_time' example scripting data engine + +2008-10-30 Richard Dale +* Separated the script engine plugins from the plasma ruby extension and moved + the script engine code to kdebase with the other script engines + +2008-10-23 Richard Dale +* Converted the webapplet to use the script engine api, and renamed it + plasma_applet_ruby_webapplet + +2008-08-15 Richard Dale +* Re-added the ruby version of the plasmoidviewer app + +2008-08-12 Arno Rehn +* Fix restoring of applet sizes. + +2008-08-07 Richard Dale +* The marshaller for Plasma::DataEngine::Data was creating Qt::Variants with + the wrong smoke pointer in the smokeruby_object struct, and this was causing + a crash in the GC marking function. +* In PlasmaScripting::Applet, if a constant such as NoBackground is referenced + and found to be missing, then look for it in Plasma::Applet. +* Fix bugs in the PlasmaScripting::Applet#showConfigurationInterface method +* Special case Plasma::Applet#id so it doesn't get a Ruby warning. +* In PlasmaScriptengineRuby::Applet the module name wasn't being derived + correctly from the Package path +* Add two versions of the clock applet + * plasma_applet_ruby_clock uses the ScriptEngine api and is packaged as a + plasmoid. It can be installed by typing the following command in the + examples/applets directory: + + $ plasmapkg --install plasma_applet_ruby_clock --type plasmoid + + * analog-clock uses the C++ plugin api. Normally Ruby applets should be + written using the script engine api, and this example is only included + to show how the two apis differ. The clocks are functionally identical. + +2008-08-06 Richard Dale +* Add some fixes for the new Plasma::Frame and Plasma::Slider widgets + +2008-07-03 Richard Dale +* Add slots and signals for scripting applets and data engines corresponding + to the ones in Plasma::Applet and Plasma::DataEngine +* Change the install destination to plasma_scriptengine_ruby and the modules + of the plugin classes to match + +2008-06-30 Richard Dale +* For script engine based applets, add the directory where the mainScript was + found to the ruby load path. + +2008-06-29 Richard Dale +* If a method call is invoked on a PlasmaScripting::Applet, then relay it to + the underlying Plasma::Applet in the script engine. +* Add an event filter to the RubyAppletScript::Applet class so that scripting + applets can implement event method handling overrides. +* Change various methods in the QGraphicsView and Plasma api so that they can + accept instances of PlasmaScripting::Applet, and the instance is substituted + for the underlying Plasma::Applet in the ScriptEngine. + +2008-06-28 Richard Dale +* Make the Ruby ScriptEngine based plugins work +* Add a Ruby version of the Javascript Tiger applet diff --git a/plasma/generic/scriptengines/ruby/applet.rb b/plasma/generic/scriptengines/ruby/applet.rb new file mode 100644 index 00000000..7b2a7bec --- /dev/null +++ b/plasma/generic/scriptengines/ruby/applet.rb @@ -0,0 +1,1215 @@ +=begin + * Copyright 2008-2010 by Richard Dale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +=end + +require 'plasma_applet' + +module PlasmaScripting + class Applet < Qt::Object + slots "setImmutability(Plasma::ImmutabilityType)", + :destroy, + :showConfigurationInterface, + :raise, + :lower, + :flushPendingConstraintsEvents, + :init, + 'initExtenderItem(Plasma::ExtenderItem*)' + + signals :releaseVisualFocus, + :geometryChanged, + :configNeedsSaving, + :activate + + attr_accessor :applet_script + + def initialize(parent, args = nil) + super(parent) + @applet_script = parent + connect(@applet_script.applet, SIGNAL(:releaseVisualFocus), self, SIGNAL(:releaseVisualFocus)) + connect(@applet_script.applet, SIGNAL(:geometryChanged), self, SIGNAL(:geometryChanged)) + connect(@applet_script.applet, SIGNAL(:configNeedsSaving), self, SIGNAL(:configNeedsSaving)) + connect(@applet_script.applet, SIGNAL(:activate), self, SIGNAL(:activate)) + connect(@applet_script.applet, SIGNAL('extenderItemRestored(Plasma::ExtenderItem*)'), self, SLOT('initExtenderItem(Plasma::ExtenderItem*)')) + end + + # If a method is called on a PlasmaScripting::Applet instance is found to be missing + # then try calling the method on the underlying Plasma::Applet in the ScriptEngine. + def method_missing(method, *args) + begin + super(method, *args) + rescue + applet_script.applet.method_missing(method, *args) + end + end + + def self.const_missing(name) + begin + super(name) + rescue + Plasma::Applet.const_missing(name) + end + end + + def configChanged + end + + def paintInterface(painter, option, contentsRect) + end + + def initExtenderItem(item) + puts "Missing implementation of initExtenderItem in the applet " \ + "#{item.config.readEntry('SourceAppletPluginName', '')}" \ + "!\n Any applet that uses extenders should implement initExtenderItem to " \ + "instantiate a widget." + end + + def size + @applet_script.size + end + + def shape + @applet_script.shape + end + + def resize(*args) + if args.length == 1 && args[0].kindof?(Qt::Size) + puts "Warning: invalid resize() call. Add this to your metadata.desktop file:" + puts "X-Plasma-DefautSize=%d,%d" % [args[0].width, args[0].height] + elsif args.length == 2 + puts "Warning: invalid resize() call. Add this to your metadata.desktop file:" + puts "X-Plasma-DefautSize=%d,%d" % [args[0].to_i, args[1].to_i] + else + super(*args) + end + end + + def constraintsEvent(constraints) + end + + def contextualActions + return [] + end + + def createConfigurationInterface(dialog) + end + + def showConfigurationInterface + end + + def dataEngine(engine) + @applet_script.dataEngine(engine) + end + + def package + @applet_script.package + end + + def setImmutability(immutabilityType) + @applet_script.applet.setImmutability(immutabilityType) + end + + def immutability=(immutabilityType) + setImmutability(immutabilityType) + end + + def destroy + @applet_script.applet.destroy + end + + def raise + @applet_script.applet.raise + end + + def lower + @applet_script.applet.lower + end + + def flushPendingConstraintsEvents + @applet_script.applet.flushPendingConstraintsEvents + end + end + + class Containment < Applet + def initialize(parent, args = nil) + super(parent, args) + end + end + + class PopupApplet < Applet + def initialize(parent, args = nil) + super(parent, args) + end + end +end + +module PlasmaScriptengineRuby + class Applet < Plasma::AppletScript + def initialize(parent, args) + super(parent) + end + + def camelize(str) + str.gsub(/(^|[._-])(.)/) { $2.upcase } + end + + def init + oldSize = applet.size + + puts "RubyAppletScript::Applet#init mainScript: #{mainScript}" + program = Qt::FileInfo.new(mainScript) + $: << program.path + load Qt::File.encodeName(program.filePath).to_s + moduleName = camelize(Qt::Dir.new(package.path).dirName) + className = camelize(program.baseName) + puts "RubyAppletScript::Applet#init instantiating: #{moduleName}::#{className}" + klass = Object.const_get(moduleName.to_sym).const_get(className.to_sym) + @applet_script = klass.new(self) + @applet_script.init + if oldSize.height > 10 && oldSize.width > 10 + applet.resize(oldSize) + end + + set_up_event_handlers + return true + end + + def configChanged + @applet_script.configChanged + end + + def paintInterface(painter, option, contentsRect) + @applet_script.paintInterface(painter, option, contentsRect) + end + + def constraintsEvent(constraints) + @applet_script.constraintsEvent(constraints) + end + + def contextualActions + @applet_script.contextualActions + end + + def showConfigurationInterface + dialog = standardConfigurationDialog() + @applet_script.createConfigurationInterface(dialog) + addStandardConfigurationPages(dialog) + dialog.show + end + + protected + + def eventFilter(obj, event) + handler = @event_handlers[event.type.to_i] + if handler + @applet_script.send(handler, event) + return true + else + return false + end + end + + private + + def set_up_event_handlers + @event_handlers = {} + + if @applet_script.respond_to?(:mousePressEvent) + @event_handlers[Qt::Event::GraphicsSceneMousePress.to_i] = :mousePressEvent + end + + if @applet_script.respond_to?(:contextMenuEvent) + @event_handlers[Qt::Event::GraphicsSceneContextMenu.to_i] = :contextMenuEvent + end + + if @applet_script.respond_to?(:dragEnterEvent) + @event_handlers[Qt::Event::GraphicsSceneDragEnter.to_i] = :dragEnterEvent + end + + if @applet_script.respond_to?(:dragLeaveEvent) + @event_handlers[Qt::Event::GraphicsSceneDragLeave.to_i] = :dragLeaveEvent + end + + if @applet_script.respond_to?(:dragMoveEvent) + @event_handlers[Qt::Event::GraphicsSceneDragMove.to_i] = :dragMoveEvent + end + + if @applet_script.respond_to?(:dropEvent) + @event_handlers[Qt::Event::GraphicsSceneDrop.to_i] = :dropEvent + end + + if @applet_script.respond_to?(:focusInEvent) + @event_handlers[Qt::Event::FocusIn.to_i] = :focusInEvent + end + + if @applet_script.respond_to?(:focusOutEvent) + @event_handlers[Qt::Event::FocusOut.to_i] = :focusOutEvent + end + + if @applet_script.respond_to?(:hoverEnterEvent) + @event_handlers[Qt::Event::GraphicsSceneHoverEnter.to_i] = :hoverEnterEvent + end + + if @applet_script.respond_to?(:hoverLeaveEvent) + @event_handlers[Qt::Event::GraphicsSceneHoverLeave.to_i] = :hoverLeaveEvent + end + + if @applet_script.respond_to?(:hoverMoveEvent) + @event_handlers[Qt::Event::GraphicsSceneHoverMove.to_i] = :hoverMoveEvent + end + + if @applet_script.respond_to?(:inputMethodEvent) + @event_handlers[Qt::Event::InputMethod.to_i] = :inputMethodEvent + end + + if @applet_script.respond_to?(:keyPressEvent) + @event_handlers[Qt::Event::KeyPress.to_i] = :keyPressEvent + end + + if @applet_script.respond_to?(:keyReleaseEvent) + @event_handlers[Qt::Event::KeyRelease.to_i] = :keyReleaseEvent + end + + if @applet_script.respond_to?(:mouseDoubleClickEvent) + @event_handlers[Qt::Event::GraphicsSceneMouseDoubleClick.to_i] = :mouseDoubleClickEvent + end + + if @applet_script.respond_to?(:mouseMoveEvent) + @event_handlers[Qt::Event::GraphicsSceneMouseMove.to_i] = :mouseMoveEvent + end + + if @applet_script.respond_to?(:mousePressEvent) + @event_handlers[Qt::Event::GraphicsSceneMousePress.to_i] = :mousePressEvent + end + + if @applet_script.respond_to?(:mouseReleaseEvent) + @event_handlers[Qt::Event::GraphicsSceneMouseRelease.to_i] = :mouseReleaseEvent + end + + if @applet_script.respond_to?(:wheelEvent) + @event_handlers[Qt::Event::GraphicsSceneWheel.to_i] = :wheelEvent + end + + if !@event_handlers.empty? + applet.installEventFilter(self) + end + end + + end +end + +module Plasma + # + # Because a PlasmaScript::Applet is not actually a Plasma::Applet we + # need to 'cheat' in the api, to pretend that it is. So the constructors + # in the Plasma widget classes will substitute any PlasmaScript::Applet + # argument passed for the real Plasma::Applet in the ScriptEngine + # + + class BusyWidget < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class CheckBox < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class ComboBox < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class Extender < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class FlashingLabel < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class Frame < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class GroupBox < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class IconWidget < Qt::Base + def initialize(*args) + sargs = [] + for i in 0...args.length do + if args[i].kind_of?(PlasmaScripting::Applet) + sargs << args[i].applet_script.applet + else + sargs << args[i] + end + end + super(*sargs) + end + end + + class ItemBackground < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class Label < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class LineEdit < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class Meter < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class PushButton < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class RadioButton < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class ScrollBar < Qt::Base + def initialize(orientation, parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(orientation, parent.applet_script.applet) + else + super + end + end + end + + class ScrollWidget < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class Separator < Qt::Base + def initialize(parent = nil, wFlags = 0) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + end + + class SignalPlotter < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class Slider < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class SpinBox < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + + def range=(arg) + if arg.kind_of? Range + return super(arg.begin, arg.exclude_end? ? arg.end - 1 : arg.end) + else + return super(arg) + end + end + end + + class SvgWidget < Qt::Base + def initialize(*args) + if args.length > 0 && args[0].kind_of?(PlasmaScripting::Applet) + args[0] = args[0].applet_script.applet + super(*args) + elsif args.length > 2 && args[2].kind_of?(PlasmaScripting::Applet) + args[2] = args[2].applet_script.applet + super(*args) + else + super + end + end + end + + class TabBar < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class TextBrowser < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class TextEdit < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class ToolButton < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class ToolTipManager < Qt::Base + def setContent(widget, data) + if widget.kind_of?(PlasmaScripting::Applet) + super(widget.applet_script.applet, data) + else + super + end + end + + def set_content(widget, data) + setContent(widget, data) + end + + def clearContent(widget) + if widget.kind_of?(PlasmaScripting::Applet) + super(widget.applet_script.applet) + else + super + end + end + + def clear_content(widget) + clearContent(widget) + end + + def show(widget) + if widget.kind_of?(PlasmaScripting::Applet) + super(widget.applet_script.applet) + else + super + end + end + + def visible?(widget) + return isVisible(widget) + end + + def isVisible(widget) + if widget.kind_of?(PlasmaScripting::Applet) + super(widget.applet_script.applet) + else + super + end + end + + def registerWidget(widget) + if widget.kind_of?(PlasmaScripting::Applet) + super(widget.applet_script.applet) + else + super + end + end + + def register_widget(widget) + registerWidget(widget) + end + + def unregisterWidget(widget) + if widget.kind_of?(PlasmaScripting::Applet) + super(widget.applet_script.applet) + else + super + end + end + + def unregister_widget(widget) + unregisterWidget(widget) + end + end + + class TreeView < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class VideoWidget < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + + class WebView < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + end + +end + +module Qt + class GraphicsProxyWidget < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class QAbstractGraphicsShapeItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsEllipseItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsItemGroup < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsLineItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsPathItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsPixmapItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsPolygonItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsRectItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsSimpleTextItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsSvgItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsTextItem < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsWidget < Qt::Base + def initialize(parent = nil, wFlags = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet, wFlags) + else + super + end + end + + def parent_item=(item) + setParentItem(item) + end + + def parentItem=(item) + setParentItem(item) + end + + def setParentItem(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def type(*args) + method_missing(:type, *args) + end + end + + class GraphicsGridLayout < Qt::Base + def initialize(parent = nil) + if parent.kind_of?(PlasmaScripting::Applet) + super(parent.applet_script.applet) + else + super + end + end + + def add_item(*args) + addItem(*args) + end + + def addItem(*args) + sargs = [] + for i in 0...args.length do + if args[i].kind_of?(PlasmaScripting::Applet) + sargs << args[i].applet_script.applet + else + sargs << args[i] + end + end + super(*sargs) + end + + def alignment(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def set_alignment(item, alignment) + setAlignment(item, alignment) + end + + def setAlignment(item, alignment) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet, alignment) + else + super + end + end + end + + class GraphicsLinearLayout < Qt::Base + def initialize(*args) + sargs = [] + for i in 0...args.length do + if args[i].kind_of?(PlasmaScripting::Applet) + sargs << args[i].applet_script.applet + else + sargs << args[i] + end + end + super(*sargs) + end + + def add_item(*args) + addItem(*args) + end + + def addItem(*args) + sargs = [] + for i in 0...args.length do + if args[i].kind_of?(PlasmaScripting::Applet) + sargs << args[i].applet_script.applet + else + sargs << args[i] + end + end + super(*sargs) + end + + def alignment(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + + def insert_item(index, item) + insertItem(index, item) + end + + def insertItem(index, item) + if item.kind_of?(PlasmaScripting::Applet) + super(index, item.applet_script.applet) + else + super + end + end + + def set_alignment(item, alignment) + setAlignment(item, alignment) + end + + def setAlignment(item, alignment) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet, alignment) + else + super + end + end + + def set_stretch_factor(item, stretch) + setStretchFactor(item, stretch) + end + + def setStretchFactor(item, stretch) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet, stretch) + else + super + end + end + + def stretch_factor(item) + stretchFactor(item) + end + + def stretchFactor(item) + if item.kind_of?(PlasmaScripting::Applet) + super(item.applet_script.applet) + else + super + end + end + end +end + +# kate: space-indent on; indent-width 2; replace-tabs on; mixed-indent off; diff --git a/plasma/generic/scriptengines/ruby/data_engine.rb b/plasma/generic/scriptengines/ruby/data_engine.rb new file mode 100644 index 00000000..459c9cc9 --- /dev/null +++ b/plasma/generic/scriptengines/ruby/data_engine.rb @@ -0,0 +1,147 @@ +=begin + * Copyright 2008 by Richard Dale + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +=end + +require 'plasma_applet' + +module PlasmaScripting + class DataEngine < Qt::Object + slots :updateAllSources, "removeSource(QString)" + signals "sourceAdded(QString)", "sourceRemoved(QString)" + + attr_accessor :data_engine_script + + def initialize(parent, args = nil) + super(parent) + @data_engine_script = parent + connect(@data_engine_script.dataEngine, SIGNAL("sourceAdded(QString)"), self, SIGNAL("sourceAdded(QString)")) + connect(@data_engine_script.dataEngine, SIGNAL("sourceRemoved(QString)"), self, SIGNAL("sourceRemoved(QString)")) + end + + def init + end + + def sourceRequestEvent(name) + end + + def updateSourceEvent(source) + end + + def setData(*args) + if args.length == 2 && !args[1].kind_of?(Qt::Variant) + args[1] = Qt::Variant.fromValue(args[1]) + elsif args.length == 3 && !args[2].kind_of?(Qt::Variant) + args[2] = Qt::Variant.fromValue(args[2]) + end + @data_engine_script.setData(*args) + end + + def removeAllData(source) + @data_engine_script.removeAllData(source) + end + + def removeData(source, key) + @data_engine_script.removeData(source, key) + end + + def setMaxSourceCount(limit) + @data_engine_script.setMaxSourceCount(limit) + end + + def maxSourceCount=(limit) + setMaxSourceCount(limit) + end + + def setMinimumPollingInterval(minimumMs) + @data_engine_script.setMinimumPollingInterval(minimumMs) + end + + def minimumPollingInterval=(minimumMs) + setMinimumPollingInterval(minimumMs) + end + + def minimumPollingInterval + @data_engine_script.minimumPollingInterval + end + + def setPollingInterval(frequency) + @data_engine_script.setPollingInterval(frequency) + end + + def pollingInterval=(frequency) + setPollingInterval(frequency) + end + + def removeAllSources + @data_engine_script.removeAllSources + end + + def sources + return [] + end + + def removeSource(source) + @data_engine_script.dataEngine.removeSource(source) + end + + def updateAllSources + @data_engine_script.dataEngine.updateAllSources + end + end +end + +module PlasmaScriptengineRuby + class DataEngine < Plasma::DataEngineScript + def initialize(parent, args) + super(parent) + end + + def camelize(str) + str.gsub(/(^|[._-])(.)/) { $2.upcase } + end + + def init + puts "RubyAppletScript::DataEngine#init mainScript: #{mainScript}" + program = Qt::FileInfo.new(mainScript) + $: << program.path + load Qt::File.encodeName(program.filePath).to_s + moduleName = camelize(Qt::Dir.new(package.path).dirName) + className = camelize(program.baseName) + puts "RubyAppletScript::DataEngine#init instantiating: #{moduleName}::#{className}" + klass = Object.const_get(moduleName.to_sym).const_get(className.to_sym) + @data_engine_script = klass.new(self) + @data_engine_script.init + return true + end + + def sources + @data_engine_script.sources + end + + def sourceRequestEvent(name) + @data_engine_script.sourceRequestEvent(name) + end + + def updateSourceEvent(source) + @data_engine_script.updateSourceEvent(source) + end + end +end + +# kate: space-indent on; indent-width 2; replace-tabs on; mixed-indent off; + diff --git a/plasma/generic/scriptengines/ruby/plasma-scriptengine-ruby-applet.desktop b/plasma/generic/scriptengines/ruby/plasma-scriptengine-ruby-applet.desktop new file mode 100644 index 00000000..e3cd95a0 --- /dev/null +++ b/plasma/generic/scriptengines/ruby/plasma-scriptengine-ruby-applet.desktop @@ -0,0 +1,149 @@ +[Desktop Entry] +Name=Ruby Widget +Name[ar]=ودجة روبي +Name[ast]=Elementu gráficu en Ruby +Name[be@latin]=Widžet u movie „Ruby” +Name[bg]=Джаджа на Ruby +Name[bn]=রুবি উইজেট +Name[bn_IN]=Ruby উইজেট +Name[bs]=Ruby grafička kontrola +Name[ca]=Estri Ruby +Name[ca@valencia]=Estri Ruby +Name[cs]=Ruby widget +Name[csb]=Interfejs Ruby +Name[da]=Ruby-widget +Name[de]=Ruby-Miniprogramm +Name[el]=Συστατικό Ruby +Name[en_GB]=Ruby Widget +Name[eo]=Ruby-fenestraĵo +Name[es]=Elemento gráfico en Ruby +Name[et]=Ruby vidin +Name[eu]=Ruby trepeta +Name[fi]=Ruby-sovelma +Name[fr]=Composant graphique Ruby +Name[fy]=Ruby widget +Name[ga]=Giuirléid Ruby +Name[gl]=Widget escrito en Ruby +Name[gu]=રૂબી વિજેટ +Name[he]=ווידג׳ט של Ruby +Name[hi]=रूबी विज़ेट +Name[hne]=रूबी विजेट +Name[hr]=Ruby widget +Name[hu]=Ruby-elem +Name[ia]=Elemento graphic (Widget) de Ruby +Name[id]=Widget Ruby +Name[is]=Ruby græja +Name[ja]=Ruby ウィジェット +Name[kk]=Ruby бөлшегі +Name[km]=ធាតុក្រាហ្វិក​ +Name[kn]=ರೂಬಿ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Name[ko]=루비 위젯 +Name[ku]=Alava Ruby +Name[lt]=Ruby valdiklis +Name[lv]=Ruby sīkrīks +Name[ml]=റൂബി ഉരുപ്പടി +Name[mr]=Ruby विजेट +Name[nb]=Ruby-element +Name[nds]=Ruby-Lüttprogramm +Name[nl]=Ruby-widget +Name[nn]=Ruby-element +Name[or]=ରୁବି ୱିଜେଟ +Name[pa]=ਰੂਬੀ ਵਿਦਜੈੱਟ +Name[pl]=Element interfejsu w języku Ruby +Name[pt]=Elemento em Ruby +Name[pt_BR]=Widget Ruby +Name[ro]=Control Ruby +Name[ru]=Виджет на языке Ruby +Name[si]=Ruby මෙවලම් +Name[sk]=Ruby widget +Name[sl]=Gradnik v Ruby +Name[sr]=рубијевски виџет +Name[sr@ijekavian]=рубијевски виџет +Name[sr@ijekavianlatin]=ruby vidžet +Name[sr@latin]=ruby vidžet +Name[sv]=Grafisk Ruby-komponent +Name[ta]=Ruby Widget +Name[tg]=Илова ба Ruby +Name[th]=วิดเจ็ตภาษารูบี้ +Name[tr]=Ruby Gereci +Name[ug]=Ruby ۋىجېتى +Name[uk]=Віджет Ruby +Name[wa]=Ahesse Ruby +Name[x-test]=xxRuby Widgetxx +Name[zh_CN]=Ruby 部件 +Name[zh_TW]=Ruby 元件 +Comment=Native Plasma widget written in Ruby +Comment[ar]=وجة بلازما أصلية مكتوبة بروبي +Comment[ast]=Elementu gráficu nativu de Plasma escrito en Ruby +Comment[be@latin]=Rodny widžet systemy „Plasma”, napisany ŭ movie „Ruby” +Comment[bg]=Оригинална джаджа за Plasma, написана на Ruby +Comment[bs]=Samosvojni plazma grafička kontrola napisana u Ruby-ju +Comment[ca]=Estri nadiu del Plasma escrit en Ruby +Comment[ca@valencia]=Estri nadiu del Plasma escrit en Ruby +Comment[cs]=Nativní plasmoid napsaný v Ruby +Comment[da]=Ægte Plasma-widget skrevet i Ruby +Comment[de]=Echtes Plasma-Programm, geschrieben in Ruby +Comment[el]=Εγγενές συστατικό Plasma γραμμένο σε Ruby +Comment[en_GB]=Native Plasma widget written in Ruby +Comment[es]=Elemento gráfico nativo de Plasma escrito en Ruby +Comment[et]=Rubys kirjutatud Plasma vidin +Comment[eu]=Jatorrizko Plasma trepeta, Ruby lengoaian idatzia +Comment[fi]=Natiivi, Ruby-pohjainen Plasma-sovelma +Comment[fr]=Composant graphique natif de Plasma écrit en Ruby +Comment[fy]=Plasma widget skreaun yn Ruby +Comment[ga]=Giuirléid dhúchasach Plasma scríofa i Ruby +Comment[gl]=Widget nativo de Plasma escrito en Ruby +Comment[gu]=રૂબીમાં લખાયેલ મૂળભૂત પ્લાઝમા વિજેટ +Comment[he]=ווידג׳ט Plasma הנכתב ב־Ruby +Comment[hi]=रूबी में लिखा गया नेटिव प्लाज्मा विजेट +Comment[hne]=रुबी मं लिखे नेटिव प्लाज्मा विजेट +Comment[hr]=Izvorna Plasma widget napisana u Rubyu +Comment[hu]=Plasma-elem Ruby nyelven +Comment[ia]=Elemento graphic (widget) native de Plasma scribite in Ruby +Comment[id]=Widget Plasma asli yang ditulis dalam Ruby +Comment[is]=Upprunabundin Plasma græja skrifuð í Ruby +Comment[ja]=Ruby で書かれた Plasma のネイティブウィジェット +Comment[kk]=Ruby-дег жазылған Plasma интерфейс бөлшегі +Comment[km]=ធាតុក្រាហ្វិក​ប្លាស្មា​ដើម​បាន​សរសេរ​នៅ​ក្នុង Ruby +Comment[kn]=ರೂಬಿಯಲ್ಲಿ ಬರೆಯಲಾದ ಸ್ಥಳೀಯ ಪ್ಲಾಸ್ಮಾ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Comment[ko]=루비로 작성된 Plasma 위젯 +Comment[lt]=Nuosavas Plasma valdiklis parašytas Ruby kalba +Comment[lv]=Plasma sīkrīks, rakstīts Ruby +Comment[ml]=റൂബിയില്‍ തയ്യാറാക്കിയിരിക്കുന്ന നേറ്റീവ് പ്ലാസ്മാ ഉരുപ്പടി +Comment[mr]=Ruby अंतर्गत लिहीले गेलेले मूळ Plasma विजेट +Comment[nb]=Plasmaelement for dette systemet, skrevet i Ruby +Comment[nds]=En orginaal Plasma-Lüttprogramm, schreven in Ruby +Comment[nl]=Plasma-widget geschreven in Ruby +Comment[nn]=Lokalt Plasma-element skrive i Ruby +Comment[or]=Ruby ରେ ଲେଖା ହୋଇଥିବା ସ୍ଥାନୀୟ ପ୍ଲାଜମା ୱିଜେଟ +Comment[pa]=ਰੂਬੀ ਵਿੱਚ ਲਿਖੇ ਨੇਟਿਵ ਪਲਾਜ਼ਮਾ ਵਿਦਜੈੱਟ +Comment[pl]=Element interfejsu Plazmy napisany w języku Ruby +Comment[pt]=Elemento nativo do Plasma feito em Ruby +Comment[pt_BR]=Widget nativo do Plasma, escrito em Ruby +Comment[ro]=Miniaplicație Plasma scrisă în Ruby +Comment[ru]=Виджет Plasma, написанный на языке Ruby +Comment[si]=Native Plasma widget written in Ruby +Comment[sk]=Natívny plasma widget napísaný v Ruby +Comment[sl]=Lastni gradnik za Plasmo, ki je napisan v Rubyu +Comment[sr]=Самосвојни плазма виџет написан у рубију +Comment[sr@ijekavian]=Самосвојни плазма виџет написан у рубију +Comment[sr@ijekavianlatin]=Samosvojni plasma vidžet napisan u Rubyju +Comment[sr@latin]=Samosvojni plasma vidžet napisan u Rubyju +Comment[sv]=Inbyggd grafisk Plasma-komponent skriven i Ruby +Comment[ta]=Native Plasma widget written in Ruby +Comment[tg]=Модуль Plasma, написанный на языке JavaScript +Comment[th]=วิดเจ็ตพลาสมาแท้ที่ถูกเขียนด้วยภาษารูบี้ +Comment[tr]=Ruby ile yazılmış gerçek Plasma gereci +Comment[ug]=Ruby بىلەن يېزىلغان ئەسلى Plasma widget +Comment[uk]=Віджет Плазми, написаний на Ruby +Comment[wa]=Ahesse askepieye po Plasma eyet scrîte e Ruby +Comment[x-test]=xxNative Plasma widget written in Rubyxx +Comment[zh_CN]=使用 Ruby 编写的原生 Plasma 部件 +Comment[zh_TW]=用 Ruby 寫的原始 Plasma 元件 +X-KDE-ServiceTypes=Plasma/ScriptEngine +Type=Service +Icon=text-x-script +X-KDE-Library=krubypluginfactory +X-KDE-PluginKeyword=plasma_scriptengine_ruby/applet.rb +X-Plasma-API=ruby-script +X-Plasma-ComponentTypes=Applet diff --git a/plasma/generic/scriptengines/ruby/plasma-scriptengine-ruby-dataengine.desktop b/plasma/generic/scriptengines/ruby/plasma-scriptengine-ruby-dataengine.desktop new file mode 100644 index 00000000..881ab4d8 --- /dev/null +++ b/plasma/generic/scriptengines/ruby/plasma-scriptengine-ruby-dataengine.desktop @@ -0,0 +1,150 @@ +[Desktop Entry] +Name=Ruby Widget +Name[ar]=ودجة روبي +Name[ast]=Elementu gráficu en Ruby +Name[be@latin]=Widžet u movie „Ruby” +Name[bg]=Джаджа на Ruby +Name[bn]=রুবি উইজেট +Name[bn_IN]=Ruby উইজেট +Name[bs]=Ruby grafička kontrola +Name[ca]=Estri Ruby +Name[ca@valencia]=Estri Ruby +Name[cs]=Ruby widget +Name[csb]=Interfejs Ruby +Name[da]=Ruby-widget +Name[de]=Ruby-Miniprogramm +Name[el]=Συστατικό Ruby +Name[en_GB]=Ruby Widget +Name[eo]=Ruby-fenestraĵo +Name[es]=Elemento gráfico en Ruby +Name[et]=Ruby vidin +Name[eu]=Ruby trepeta +Name[fi]=Ruby-sovelma +Name[fr]=Composant graphique Ruby +Name[fy]=Ruby widget +Name[ga]=Giuirléid Ruby +Name[gl]=Widget escrito en Ruby +Name[gu]=રૂબી વિજેટ +Name[he]=ווידג׳ט של Ruby +Name[hi]=रूबी विज़ेट +Name[hne]=रूबी विजेट +Name[hr]=Ruby widget +Name[hu]=Ruby-elem +Name[ia]=Elemento graphic (Widget) de Ruby +Name[id]=Widget Ruby +Name[is]=Ruby græja +Name[ja]=Ruby ウィジェット +Name[kk]=Ruby бөлшегі +Name[km]=ធាតុក្រាហ្វិក​ +Name[kn]=ರೂಬಿ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Name[ko]=루비 위젯 +Name[ku]=Alava Ruby +Name[lt]=Ruby valdiklis +Name[lv]=Ruby sīkrīks +Name[ml]=റൂബി ഉരുപ്പടി +Name[mr]=Ruby विजेट +Name[nb]=Ruby-element +Name[nds]=Ruby-Lüttprogramm +Name[nl]=Ruby-widget +Name[nn]=Ruby-element +Name[or]=ରୁବି ୱିଜେଟ +Name[pa]=ਰੂਬੀ ਵਿਦਜੈੱਟ +Name[pl]=Element interfejsu w języku Ruby +Name[pt]=Elemento em Ruby +Name[pt_BR]=Widget Ruby +Name[ro]=Control Ruby +Name[ru]=Виджет на языке Ruby +Name[si]=Ruby මෙවලම් +Name[sk]=Ruby widget +Name[sl]=Gradnik v Ruby +Name[sr]=рубијевски виџет +Name[sr@ijekavian]=рубијевски виџет +Name[sr@ijekavianlatin]=ruby vidžet +Name[sr@latin]=ruby vidžet +Name[sv]=Grafisk Ruby-komponent +Name[ta]=Ruby Widget +Name[tg]=Илова ба Ruby +Name[th]=วิดเจ็ตภาษารูบี้ +Name[tr]=Ruby Gereci +Name[ug]=Ruby ۋىجېتى +Name[uk]=Віджет Ruby +Name[wa]=Ahesse Ruby +Name[x-test]=xxRuby Widgetxx +Name[zh_CN]=Ruby 部件 +Name[zh_TW]=Ruby 元件 +Comment=Native Plasma widget written in Ruby +Comment[ar]=وجة بلازما أصلية مكتوبة بروبي +Comment[ast]=Elementu gráficu nativu de Plasma escrito en Ruby +Comment[be@latin]=Rodny widžet systemy „Plasma”, napisany ŭ movie „Ruby” +Comment[bg]=Оригинална джаджа за Plasma, написана на Ruby +Comment[bs]=Samosvojni plazma grafička kontrola napisana u Ruby-ju +Comment[ca]=Estri nadiu del Plasma escrit en Ruby +Comment[ca@valencia]=Estri nadiu del Plasma escrit en Ruby +Comment[cs]=Nativní plasmoid napsaný v Ruby +Comment[da]=Ægte Plasma-widget skrevet i Ruby +Comment[de]=Echtes Plasma-Programm, geschrieben in Ruby +Comment[el]=Εγγενές συστατικό Plasma γραμμένο σε Ruby +Comment[en_GB]=Native Plasma widget written in Ruby +Comment[es]=Elemento gráfico nativo de Plasma escrito en Ruby +Comment[et]=Rubys kirjutatud Plasma vidin +Comment[eu]=Jatorrizko Plasma trepeta, Ruby lengoaian idatzia +Comment[fi]=Natiivi, Ruby-pohjainen Plasma-sovelma +Comment[fr]=Composant graphique natif de Plasma écrit en Ruby +Comment[fy]=Plasma widget skreaun yn Ruby +Comment[ga]=Giuirléid dhúchasach Plasma scríofa i Ruby +Comment[gl]=Widget nativo de Plasma escrito en Ruby +Comment[gu]=રૂબીમાં લખાયેલ મૂળભૂત પ્લાઝમા વિજેટ +Comment[he]=ווידג׳ט Plasma הנכתב ב־Ruby +Comment[hi]=रूबी में लिखा गया नेटिव प्लाज्मा विजेट +Comment[hne]=रुबी मं लिखे नेटिव प्लाज्मा विजेट +Comment[hr]=Izvorna Plasma widget napisana u Rubyu +Comment[hu]=Plasma-elem Ruby nyelven +Comment[ia]=Elemento graphic (widget) native de Plasma scribite in Ruby +Comment[id]=Widget Plasma asli yang ditulis dalam Ruby +Comment[is]=Upprunabundin Plasma græja skrifuð í Ruby +Comment[ja]=Ruby で書かれた Plasma のネイティブウィジェット +Comment[kk]=Ruby-дег жазылған Plasma интерфейс бөлшегі +Comment[km]=ធាតុក្រាហ្វិក​ប្លាស្មា​ដើម​បាន​សរសេរ​នៅ​ក្នុង Ruby +Comment[kn]=ರೂಬಿಯಲ್ಲಿ ಬರೆಯಲಾದ ಸ್ಥಳೀಯ ಪ್ಲಾಸ್ಮಾ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Comment[ko]=루비로 작성된 Plasma 위젯 +Comment[lt]=Nuosavas Plasma valdiklis parašytas Ruby kalba +Comment[lv]=Plasma sīkrīks, rakstīts Ruby +Comment[ml]=റൂബിയില്‍ തയ്യാറാക്കിയിരിക്കുന്ന നേറ്റീവ് പ്ലാസ്മാ ഉരുപ്പടി +Comment[mr]=Ruby अंतर्गत लिहीले गेलेले मूळ Plasma विजेट +Comment[nb]=Plasmaelement for dette systemet, skrevet i Ruby +Comment[nds]=En orginaal Plasma-Lüttprogramm, schreven in Ruby +Comment[nl]=Plasma-widget geschreven in Ruby +Comment[nn]=Lokalt Plasma-element skrive i Ruby +Comment[or]=Ruby ରେ ଲେଖା ହୋଇଥିବା ସ୍ଥାନୀୟ ପ୍ଲାଜମା ୱିଜେଟ +Comment[pa]=ਰੂਬੀ ਵਿੱਚ ਲਿਖੇ ਨੇਟਿਵ ਪਲਾਜ਼ਮਾ ਵਿਦਜੈੱਟ +Comment[pl]=Element interfejsu Plazmy napisany w języku Ruby +Comment[pt]=Elemento nativo do Plasma feito em Ruby +Comment[pt_BR]=Widget nativo do Plasma, escrito em Ruby +Comment[ro]=Miniaplicație Plasma scrisă în Ruby +Comment[ru]=Виджет Plasma, написанный на языке Ruby +Comment[si]=Native Plasma widget written in Ruby +Comment[sk]=Natívny plasma widget napísaný v Ruby +Comment[sl]=Lastni gradnik za Plasmo, ki je napisan v Rubyu +Comment[sr]=Самосвојни плазма виџет написан у рубију +Comment[sr@ijekavian]=Самосвојни плазма виџет написан у рубију +Comment[sr@ijekavianlatin]=Samosvojni plasma vidžet napisan u Rubyju +Comment[sr@latin]=Samosvojni plasma vidžet napisan u Rubyju +Comment[sv]=Inbyggd grafisk Plasma-komponent skriven i Ruby +Comment[ta]=Native Plasma widget written in Ruby +Comment[tg]=Модуль Plasma, написанный на языке JavaScript +Comment[th]=วิดเจ็ตพลาสมาแท้ที่ถูกเขียนด้วยภาษารูบี้ +Comment[tr]=Ruby ile yazılmış gerçek Plasma gereci +Comment[ug]=Ruby بىلەن يېزىلغان ئەسلى Plasma widget +Comment[uk]=Віджет Плазми, написаний на Ruby +Comment[wa]=Ahesse askepieye po Plasma eyet scrîte e Ruby +Comment[x-test]=xxNative Plasma widget written in Rubyxx +Comment[zh_CN]=使用 Ruby 编写的原生 Plasma 部件 +Comment[zh_TW]=用 Ruby 寫的原始 Plasma 元件 +X-KDE-ServiceTypes=Plasma/ScriptEngine +Type=Service +Icon=text-x-script +X-KDE-Library=krubypluginfactory +X-KDE-PluginKeyword=plasma_scriptengine_ruby/data_engine.rb +X-EngineName=ruby-dataengine-script +X-Plasma-API=ruby-script +X-Plasma-ComponentTypes=DataEngine diff --git a/plasma/generic/scriptengines/webkit/CMakeLists.txt b/plasma/generic/scriptengines/webkit/CMakeLists.txt new file mode 100644 index 00000000..12a4a79a --- /dev/null +++ b/plasma/generic/scriptengines/webkit/CMakeLists.txt @@ -0,0 +1,33 @@ +add_subdirectory(dashboard) + +project(plasma-webapplet) + +set(webapplet_SRCS + webpage.cpp webapplet.cpp plasmawebapplet.cpp plasmajs.cpp webapplet_plugin.cpp) +kde4_add_plugin(plasma_appletscriptengine_webapplet ${webapplet_SRCS}) +target_link_libraries(plasma_appletscriptengine_webapplet ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${QT_QTWEBKIT_LIBRARY} ) +install(TARGETS plasma_appletscriptengine_webapplet DESTINATION ${PLUGIN_INSTALL_DIR}) + +set(webappletpackage_SRCS + webapplet_package.cpp) +kde4_add_plugin(plasma_packagestructure_web ${webappletpackage_SRCS}) +target_link_libraries(plasma_packagestructure_web ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${QT_QTWEBKIT_LIBRARY} ) +install(TARGETS plasma_packagestructure_web DESTINATION ${PLUGIN_INSTALL_DIR}) + +set(dashboardapplet_SRCS + webpage.cpp webapplet.cpp dashboardapplet.cpp bundle.cpp dashboardjs.cpp) +kde4_add_plugin(plasma_appletscriptengine_dashboard ${dashboardapplet_SRCS}) +target_link_libraries(plasma_appletscriptengine_dashboard ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${QT_QTWEBKIT_LIBRARY} ) +install(TARGETS plasma_appletscriptengine_dashboard DESTINATION ${PLUGIN_INSTALL_DIR}) + +set(bundlepackage_SRCS + bundle.cpp dashboard_plugin.cpp) +kde4_add_plugin(plasma_packagestructure_dashboard ${bundlepackage_SRCS}) +target_link_libraries(plasma_packagestructure_dashboard ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${QT_QTWEBKIT_LIBRARY} ) +install(TARGETS plasma_packagestructure_dashboard DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-scriptengine-applet-web.desktop + plasma-scriptengine-applet-dashboard.desktop + plasma-packagestructure-dashboard.desktop + plasma-packagestructure-web.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/scriptengines/webkit/Messages.sh b/plasma/generic/scriptengines/webkit/Messages.sh new file mode 100755 index 00000000..f6730e1f --- /dev/null +++ b/plasma/generic/scriptengines/webkit/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_appletscriptengine_dashboard.pot diff --git a/plasma/generic/scriptengines/webkit/README b/plasma/generic/scriptengines/webkit/README new file mode 100644 index 00000000..ff8717bc --- /dev/null +++ b/plasma/generic/scriptengines/webkit/README @@ -0,0 +1,2 @@ +Document about dashboard stuff +http://developer.apple.com/documentation/AppleApplications/Conceptual/Dashboard_ProgTopics/Dashboard_ProgTopics.pdf diff --git a/plasma/generic/scriptengines/webkit/bundle.cpp b/plasma/generic/scriptengines/webkit/bundle.cpp new file mode 100644 index 00000000..8d9c73fe --- /dev/null +++ b/plasma/generic/scriptengines/webkit/bundle.cpp @@ -0,0 +1,430 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ + +#include "bundle.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +void recursive_print(const KArchiveDirectory *dir, const QString &path) +{ + const QStringList l = dir->entries(); + QStringList::const_iterator it = l.constBegin(); + for (; it != l.end(); ++it) + { + const KArchiveEntry* entry = dir->entry((*it)); + printf("mode=%07o %s %s size: %lld pos: %lld %s%s isdir=%d%s", + entry->permissions(), + entry->user().toLatin1().constData(), + entry->group().toLatin1().constData(), + entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->size(), + entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->position(), + path.toLatin1().constData(), + (*it).toLatin1().constData(), entry->isDirectory(), + entry->symLinkTarget().isEmpty() ? "" : + QString(" symlink: %1").arg( + entry->symLinkTarget()).toLatin1().constData()); + + //if (!entry->isDirectory()) printf("%d", + // ((KArchiveFile*)entry)->size()); + printf("\n"); + if (entry->isDirectory()) + recursive_print((KArchiveDirectory *)entry, path+(*it)+'/'); + } +} + + +static const KArchiveDirectory *recursiveFind(const KArchiveDirectory *dir) +{ + const QStringList l = dir->entries(); + QStringList::const_iterator it; + for (it = l.constBegin(); it != l.constEnd(); ++it) { + const KArchiveEntry* entry = dir->entry((*it)); + if (entry->isDirectory()) { + QString name = *it; + if (name.startsWith(QLatin1String("__MACOSX"))) { + //skip this + continue; + } else if (name.endsWith(QLatin1String(".wdgt"))) { + //got our bad boy + return static_cast(entry); + } else { + const KArchiveDirectory *fd = + recursiveFind(static_cast(entry)); + if (fd) + return fd; + } + } + } + return 0; +} + +Bundle::Bundle(const QString &path) + : PackageStructure(0, "MacDashboard"), + m_isValid(false), + m_width(0), m_height(0) +{ + setContentsPrefix(QString()); + QFile f(path); + f.open(QIODevice::ReadOnly); + m_data = f.readAll(); + f.close(); + initTempDir(); + open(); +} + +Bundle::Bundle(const QByteArray &data) + : PackageStructure(0, "MacDashboard"), + m_isValid(false), + m_width(0), + m_height(0) +{ + setContentsPrefix(QString()); + m_data = data; + initTempDir(); + open(); +} + +Bundle::Bundle(QObject *parent, QVariantList args) + : PackageStructure(parent, "MacDashboard"), + m_isValid(false), + m_tempDir(0), + m_width(0), + m_height(0) +{ + Q_UNUSED(args) + setContentsPrefix(QString()); +} + +Bundle::~Bundle() +{ + close(); +} + +void Bundle::setData(const QByteArray &data) +{ + m_data = data; + close(); + open(); +} + +QByteArray Bundle::data() const +{ + return m_data; +} + +bool Bundle::open() +{ + if (!m_tempDir) { + initTempDir(); + } + + if (m_data.isEmpty()) { + return false; + } + + QBuffer buffer(&m_data); + KZip zip(&buffer); + if (!zip.open(QIODevice::ReadOnly)) { + qWarning("Couldn't open the bundle!"); + return false; + } + + const KArchiveDirectory *dir = zip.directory(); + + const KArchiveDirectory *foundDir = recursiveFind(dir); + if (!foundDir) { + qWarning("not a bundle"); + m_isValid = false; + zip.close(); + return 0; + } + + m_isValid = extractArchive(foundDir, QLatin1String("")); + qDebug()<<"Dir = "<name() << m_isValid; + + if (m_isValid) { + setPath(m_tempDir->name()); + } + + zip.close(); + + return m_isValid; +} + +bool Bundle::close() +{ + bool ret = m_tempDir; + delete m_tempDir; + m_tempDir = 0; + return ret; +} + +bool Bundle::extractArchive(const KArchiveDirectory *dir, const QString &path) +{ + const QStringList l = dir->entries(); + + QStringList::const_iterator it; + for (it = l.constBegin(); it != l.constEnd(); ++it) { + const KArchiveEntry* entry = dir->entry((*it)); + QString fullPath = QString("%1/%2").arg(path).arg(*it); + if (entry->isDirectory()) { + QString outDir = QString("%1%2").arg(m_tempDir->name()).arg(path); + QDir qdir(outDir); + qdir.mkdir(*it); + extractArchive(static_cast(entry), fullPath); + } else if (entry->isFile()) { + QString outName = QString("%1%2").arg(m_tempDir->name()).arg(fullPath.remove(0, 1)); + //qDebug()<<"-------- "<(entry); + f.write(archiveFile->data()); + f.close(); + } else { + qWarning("Unidentified entry at %s", qPrintable(fullPath)); + } + } + return true; +} + +void Bundle::pathChanged() +{ + //qDebug() << "path changed"; + m_isValid = extractInfo(); +} + +bool Bundle::extractInfo() +{ + QString plistLocation = QString("%1Info.plist").arg(path()); + QString configXml = QString("%1config.xml").arg(path()); + if (QFile::exists(plistLocation)) { + //qDebug() << "doing plist"; + return parsePlist(plistLocation); + } else if (QFile::exists(configXml)) { + return parseConfigXml(configXml); + } + + return false; +} + +bool Bundle::parsePlist(const QString &loc) +{ + QFile f(loc); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("Couldn't open info file: '%s'", qPrintable(loc)); + return false; + } + + QMap infoMap; + QString str = f.readAll(); + QXmlStreamReader reader(str); + while (!reader.atEnd()) { + reader.readNext(); + // do processing + if (reader.isStartElement()) { + //qDebug() << reader.name().toString(); + if (reader.name() == "key") { + QString key, value; + reader.readNext(); + if (reader.isCharacters()) { + QString str = reader.text().toString(); + str = str.trimmed(); + if (!str.isEmpty()) + key = str; + } + if (key.isEmpty()) + continue; + while (!reader.isStartElement()) + reader.readNext(); + if (reader.name() != "string" && + reader.name() != "integer") { + qDebug()<<"Unrecognized val "<setAutoRemove(false); + QString pluginName = "dashboard_" + m_bundleId; + //kDebug() << "valid, so going to move it in to" << pluginName; + KIO::CopyJob* job = KIO::move(m_tempDir->name(), QString(packageRoot + pluginName), KIO::HideProgressInfo); + m_isValid = job->exec(); + + if (m_isValid) { + //kDebug() << "still so good ... registering"; + Plasma::PackageMetadata data; + data.setName(m_name); + data.setDescription(m_description); + data.setPluginName(pluginName); + data.setImplementationApi("dashboard"); + Plasma::Package::registerPackage(data, m_iconLocation); + } + } + + if (!m_isValid) { + // make sure we clean up after ourselves afterwards on failure + m_tempDir->setAutoRemove(true); + } + + return m_isValid; +} + +bool Bundle::parseConfigXml(const QString &loc) +{ + QFile f(loc); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("Couldn't open info file: '%s'", qPrintable(loc)); + return false; + } + + qWarning("FIXME: Widgets 1.0 not implemented"); + + return false; +} + +void Bundle::initTempDir() +{ + m_tempDir = new KTempDir(); + //make it explicit + m_tempDir->setAutoRemove(true); +} + +QString Bundle::bundleId() const +{ + return m_bundleId; +} + +QString Bundle::name() const +{ + return m_name; +} + +QString Bundle::version() const +{ + return m_version; +} + +QString Bundle::description() const +{ + return m_description; +} + +int Bundle::width() const +{ + return m_width; +} + +int Bundle::height() const +{ + return m_height; +} + +QString Bundle::htmlLocation() const +{ + return m_htmlLocation; +} + +QString Bundle::iconLocation() const +{ + return m_iconLocation; +} + +bool Bundle::isValid() const +{ + return m_isValid; +} + + diff --git a/plasma/generic/scriptengines/webkit/bundle.h b/plasma/generic/scriptengines/webkit/bundle.h new file mode 100644 index 00000000..e312dace --- /dev/null +++ b/plasma/generic/scriptengines/webkit/bundle.h @@ -0,0 +1,86 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#ifndef BUNDLE_H +#define BUNDLE_H + +#include +#include + +#include + +class KArchiveDirectory; + +class Bundle : public Plasma::PackageStructure +{ + Q_OBJECT +public: + Bundle(const QString &path); + Bundle(const QByteArray &data); + Bundle(QObject *parent, QVariantList args); + ~Bundle(); + + bool isValid() const; + + void setData(const QByteArray &fn); + QByteArray data() const; + + QString bundleId() const; + QString name() const; + QString version() const; + QString description() const; + int width() const; + int height() const; + QString htmlLocation() const; + QString iconLocation() const; + +protected: + void pathChanged(); + +private: + bool extractArchive(const KArchiveDirectory *dir, const QString &path); + bool extractInfo(); + + bool parsePlist(const QString &loc); + bool parseConfigXml(const QString &loc); + + void initTempDir(); + + bool open(); + bool close(); + bool installPackage(const QString &archivePath, const QString &packageRoot); + +private: + QByteArray m_data; + bool m_isValid; + KTempDir *m_tempDir; + + QString m_bundleId; + QString m_name; + QString m_version; + QString m_description; + int m_width; + int m_height; + QString m_htmlLocation; + QString m_iconLocation; +}; + +#endif diff --git a/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleAnimator.js b/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleAnimator.js new file mode 100644 index 00000000..93b51297 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleAnimator.js @@ -0,0 +1,142 @@ +/* + * Copyright 2008 Stefan Buller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +function AppleAnimator(duration, interval, start, finish, handler) +{ + //properties specified by Apple + this.duration = duration; + this.interval = interval; + this.animations = []; + this.timer = 0; + this.oncomplete; //no documentation exists for this. + + //internal members: + this.intervalPointer = undefined; + + var that = this; + + if (arguments.length === 5) { + var animation = new AppleAnimation(start, finish, handler); + that.addAnimation(animation); //I hope I can use this already + } +}; + +AppleAnimator.prototype.addAnimation = function (animation) { + //I'm unsure what the behaviour of this function should be if + //AppleAnimator.start() has already been called. + animation.initialize(this.duration, this.interval); + this.animations.push(animation); +}; + +AppleAnimator.prototype.start = function () +{ + if (this.intervalPointer == undefined) { + + var that = this; //for the closure (may not be necessary?) + function intervalHandler() { + //setInterval doesn't pass 'this', so we need a closure instead. + that.timer += that.interval; + if (that.timer > that.duration) { + that.stop(); + } else { + for (var i=0; i + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +function AppleScrollArea(content) { + for (var i = 0; i < arguments.length; i++) { + this.addScrollbar(arguments[i]); + } + var that=this; + var handler=function(e) { + switch(e.which) { + case 37: //left + that.horizontalScrollTo(that.content.scrollLeft - + that.singlepressScrollPixels); + break; + case 38: //up + that.verticalScrollTo(that.content.scrollTop - + that.singlepressScrollPixels); + break; + case 39: //right + that.horizontalScrollTo(that.content.scrollLeft + + that.singlepressScrollPixels); + break; + case 40: //down + that.verticalScrollTo(that.content.scrollTop + + that.singlepressScrollPixels); + break; + default: + //the event may contiue to propagate + return true; + } + //arrest propagation + return false; + } + content.addEventListener('keydown',handler,false); + + //Apple mandated properties that must be reacted to. + this.scrollsVertically = false; + this.scrollsHorizontally = false; + this.singlepressScrollPixels = 10; //Somebody change this. Please. + + //Apple mandated properties that are `read only'. + this.viewHeight = content.clientHeight; + this.viewToContentHeightRatio = content.clientHeight / content.scrollHeight; + this.viewWidth = content.clientWidth; + this.viewToContentWidthRatio = content.clientWidth / content.scrollWidth; + //I'm worried that the scrollHeight/Width could change on me. If that turns + //out to be a problem, then getters would be the way to go. + + //extras + this.scrollbars = []; + this.content = content; +} + +AppleScrollArea.prototype.addScrollbar = function(scrollbar) { + this.scrollbars.push(scrollbar); + scrollbar.setScrollArea(this); +} + +AppleScrollArea.prototype.removeScrollbar = function(scrollbar) { + this.scrollbars.filter(function(element){return (element === scrollbar);}); + scrollbar.setScrollArea(null); //Just a guess. This might not be right. +} + +AppleScrollArea.prototype.remove = function() { + //Remove the div, or remove the effects of AppleScrollArea? + //Perhaps this can all be replaced with a simple removeChild() + content.scrollTop = 0; + content.scrollLeft = 0; + for (var i = 0; i < this.scrollbars.length; i++) { + this.scrollbars[i].remove(); + delete this.scrollbars[i]; + } + delete this; +} + +AppleScrollArea.prototype.reveal = function(element) { + //First we find it + var distX = 0; + var distY = 0; + var el = element; + while (el !== this.content) { + distX += (+el.offsetTop); + distY += (+el.offsetLeft); + el = el.parentNode; + if (el == null) { + throw "Target element not in ScrollArea."; + } + } + + this.verticalScrollTo(distY); + this.horizontalScrollTo(distX); +} + +AppleScrollArea.prototype.focus = function() { + this.content.focus(); +} + +AppleScrollArea.prototype.blur = function() { + this.content.blur(); +} + +AppleScrollArea.prototype.verticalScrollTo = function(position) { + this.scrollTop = position; +} + +AppleScrollArea.prototype.horizontalScrollTo = function(position) { + this.scrollLeft = position; +} + + diff --git a/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleScrollbar.js b/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleScrollbar.js new file mode 100644 index 00000000..8d1c8b69 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleScrollbar.js @@ -0,0 +1 @@ + diff --git a/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleSlider.js b/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleSlider.js new file mode 100644 index 00000000..8d1c8b69 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/AppleSlider.js @@ -0,0 +1 @@ + diff --git a/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/CMakeLists.txt b/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/CMakeLists.txt new file mode 100644 index 00000000..b9a2b4c7 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboard/AppleClasses/CMakeLists.txt @@ -0,0 +1,7 @@ +install(FILES AppleButton.js + AppleInfoButton.js + AppleAnimator.js + AppleScrollArea.js + AppleScrollbar.js + AppleSlider.js + DESTINATION ${DATA_INSTALL_DIR}/plasma/dashboard/AppleClasses/) diff --git a/plasma/generic/scriptengines/webkit/dashboard/CMakeLists.txt b/plasma/generic/scriptengines/webkit/dashboard/CMakeLists.txt new file mode 100644 index 00000000..9477cb9d --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboard/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(button) +add_subdirectory(AppleClasses) \ No newline at end of file diff --git a/plasma/generic/scriptengines/webkit/dashboard/button/CMakeLists.txt b/plasma/generic/scriptengines/webkit/dashboard/button/CMakeLists.txt new file mode 100644 index 00000000..afa0eb40 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboard/button/CMakeLists.txt @@ -0,0 +1,2 @@ +install(FILES genericButton.js + DESTINATION ${DATA_INSTALL_DIR}/plasma/dashboard/button) diff --git a/plasma/generic/scriptengines/webkit/dashboard/button/genericButton.js b/plasma/generic/scriptengines/webkit/dashboard/button/genericButton.js new file mode 100644 index 00000000..464eda40 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboard/button/genericButton.js @@ -0,0 +1,8 @@ + + +function createGenericButton(placeElement,buttonText,clickHandler) { + var b = document.createElement("button"); + b.appendChild(document.createTextNode(buttonText)); + b.onclick = clickHandler; + placeElement.appendChild(b); +} \ No newline at end of file diff --git a/plasma/generic/scriptengines/webkit/dashboard_plugin.cpp b/plasma/generic/scriptengines/webkit/dashboard_plugin.cpp new file mode 100644 index 00000000..f7a421f7 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboard_plugin.cpp @@ -0,0 +1,25 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#include "bundle.h" + +K_EXPORT_PLASMA_PACKAGESTRUCTURE(dashboard, Bundle) + diff --git a/plasma/generic/scriptengines/webkit/dashboardapplet.cpp b/plasma/generic/scriptengines/webkit/dashboardapplet.cpp new file mode 100644 index 00000000..0da78188 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboardapplet.cpp @@ -0,0 +1,94 @@ +/* +Copyright (c) 2007 Zack Rusin +Copyright (c) 2008 Beat Wolf + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#include "dashboardapplet.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "dashboardjs.h" + +DashboardApplet::DashboardApplet(QObject *parent, const QVariantList &args) + : WebApplet(parent, args) +{ +} + +DashboardApplet::~DashboardApplet() +{ +} + +bool DashboardApplet::init() +{ + applet()->setAspectRatioMode(Plasma::FixedSize); + return WebApplet::init(); +} + +void DashboardApplet::loadFinished(bool success) +{ + WebApplet::loadFinished(success); + if (success) { + view()->resize(view()->mainFrame()->contentsSize()); + applet()->resize(view()->mainFrame()->contentsSize()); + } +} + +void DashboardApplet::constraintsEvent(Plasma::Constraints constraints) +{ + if (constraints & Plasma::FormFactorConstraint) { + applet()->setBackgroundHints(Plasma::Applet::NoBackground); + } +} + +void DashboardApplet::initJsObjects() +{ + QWebFrame *frame = qobject_cast(sender()); + Q_ASSERT(frame); + frame->addToJavaScriptWindowObject(QLatin1String("applet"), this); + frame->addToJavaScriptWindowObject(QLatin1String("widget"), new DashboardJs(frame, this, applet())); +} + +QByteArray DashboardApplet::dataFor(const QString &str) +{ + QFile f(str); + f.open(QIODevice::ReadOnly); + QByteArray data = f.readAll(); + f.close(); + + //replace the apple javascript imports with the kde ones + QString jsBaseDir = KGlobal::dirs()->findResourceDir("data","plasma/dashboard/button/genericButton.js") + + "plasma/dashboard"; + + data.replace("file:///System/Library/WidgetResources", jsBaseDir.toUtf8()); + data.replace("/System/Library/WidgetResources", jsBaseDir.toUtf8()); + + return data; +} + +#include "dashboardapplet.moc" diff --git a/plasma/generic/scriptengines/webkit/dashboardapplet.h b/plasma/generic/scriptengines/webkit/dashboardapplet.h new file mode 100644 index 00000000..193be084 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboardapplet.h @@ -0,0 +1,54 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#ifndef SAMPLEITEM_H +#define SAMPLEITEM_H + +#include "webapplet.h" +#include "bundle.h" + +#include "dashboardjs.h" + +#include + +#include + +class DashboardApplet : public WebApplet +{ + Q_OBJECT +public: + DashboardApplet(QObject *parent, const QVariantList &args); + ~DashboardApplet(); + + bool init(); + +protected: + virtual QByteArray dataFor(const QString &str); + +protected slots: + virtual void loadFinished(bool success); + virtual void initJsObjects(); + virtual void constraintsEvent(Plasma::Constraints constraints); +}; + +K_EXPORT_PLASMA_APPLETSCRIPTENGINE(dashboard, DashboardApplet) + +#endif diff --git a/plasma/generic/scriptengines/webkit/dashboardjs.cpp b/plasma/generic/scriptengines/webkit/dashboardjs.cpp new file mode 100644 index 00000000..d41252e8 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboardjs.cpp @@ -0,0 +1,179 @@ +/* +Copyright (c) 2008 Beat Wolf + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "dashboardjs.h" +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +DashboardJs::DashboardJs(QWebFrame *frame, QObject *parent, Plasma::Applet *applet) + : QObject(parent) +{ + m_applet = applet; + m_frame = frame; +} + +DashboardJs::~DashboardJs() +{ + if(m_frame){ + kDebug() << "deconstructor calles javascript: " << m_onremove; + m_frame->evaluateJavaScript(m_onremove); + } +} + +void DashboardJs::openApplication(QString name) +{ + //STUB + kDebug() << "not implemented: open application" << name; + + //WARNING: this might be dangerous and exploited (or not) + /* create list of applications: + * com.apple.ical + * com.RealNetworks.RealPlayer + */ +} + +void DashboardJs::openURL(QString name) +{ + //TODO: this could be dangerous(really?). filter valid urls + new KRun(name, 0); +} + +QVariant DashboardJs::preferenceForKey(QString key) +{ + KConfigGroup conf = m_applet->config(); + + if (!conf.hasKey(key)) { + return QVariant(); + } + + return conf.readEntry(key,""); +} + +void DashboardJs::prepareForTransition(QString transition) +{ + //STUB + kDebug() << "not implemented: transition with name" << transition; + //TODO:freeze widget drawing. possible? + //not really needed for things to work, but would be prettier +} + +void DashboardJs::performTransition() +{ + //STUB + //TODO: enable widget drawing again, perform nice animation. + kDebug() << "not implemented: perform transition"; + //not really needed for things to work, but would be prettier +} + +void DashboardJs::setCloseBoxOffset(int x, int y) +{ + //STUB, not needed, plasma has its own close box + kDebug() << "not implemented: close box offset" << x << y; +} + +void DashboardJs::setPreferenceForKey(QString value, QString key) +{ + kDebug() << "save key" << key << value; + KConfigGroup conf = m_applet->config(); + conf.writeEntry(key, value); +} + +void DashboardJs::system(QString command, QString handler) +{ + //WARNING: this might be dangerous and exploited. + //STUB + kDebug() << "not implemented: system command:" << command << handler; +} + +//Property sets and gets +QString DashboardJs::identifier() const +{ + return QString::number(m_applet->id()); +} + +QString DashboardJs::onshow() const +{ + return m_onshow; +} + +void DashboardJs::setOnshow(const QString &value) +{ + m_onshow = value; +} + +QString DashboardJs::onhide() const +{ + return m_onhide; +} + +void DashboardJs::setOnhide(const QString &value) +{ + m_onhide = value; +} + +QString DashboardJs::onremove() const +{ + return m_onremove; +} + +void DashboardJs::setOnremove(const QString &value) +{ + m_onremove = value; +} + + +QString DashboardJs::ondragstart() const +{ + return m_ondragstart; +} + +void DashboardJs::setOndragstart(const QString &value) +{ + m_ondragstart = value; +} + +QString DashboardJs::ondragstop() const +{ + return m_ondragstop; +} + +void DashboardJs::setOndragstop(const QString &value) +{ + m_ondragstop = value; +} +//only for testing purpose +//TODO: remove when not needed anymore +void DashboardJs::hello(int test) +{ + kDebug() << "hello world" << test; +} + diff --git a/plasma/generic/scriptengines/webkit/dashboardjs.h b/plasma/generic/scriptengines/webkit/dashboardjs.h new file mode 100644 index 00000000..2376571d --- /dev/null +++ b/plasma/generic/scriptengines/webkit/dashboardjs.h @@ -0,0 +1,116 @@ +/* +Copyright (c) 2008 Beat Wolf + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ + +#ifndef DASHBOARDJS_H +#define DASHBOARDJS_H + +#include +#include +#include + +#include + +#include + +/** + * Implements the Mac OS X Dashboard widget javascript functions. + * This document was used to create this class: + * http://developer.apple.com/documentation/AppleApplications/Reference/Dashboard_Ref/Dashboard_Ref.pdf + */ +class DashboardJs : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString identifier READ identifier) + + Q_PROPERTY(QString onshow READ onshow WRITE setOnshow) + Q_PROPERTY(QString onhide READ onhide WRITE setOnhide) + Q_PROPERTY(QString onremove READ onremove WRITE setOnremove) + Q_PROPERTY(QString ondragstart READ ondragstart WRITE setOndragstart) + Q_PROPERTY(QString ondragstop READ ondragstop WRITE setOndragstop) + +public: + DashboardJs(QWebFrame *frame, QObject *parent= 0, Plasma::Applet *applet = 0); + ~DashboardJs(); + + QString identifier() const; + + QString onshow() const; + void setOnshow(const QString &onshow); + + QString onhide() const; + void setOnhide(const QString &onhide); + + QString onremove() const; + void setOnremove(const QString &onremove); + + QString ondragstart() const; + void setOndragstart(const QString &ondragstart); + + QString ondragstop() const; + void setOndragstop(const QString &ondragstop); + +public slots: + void hello(int test); + + /** + * opens a certain application + */ + void openApplication(QString name); + + /** + * opens a URL. Does not open file urls by default. + * TODO: find out what protocols dashboard widgets support. filter out the others + */ + void openURL(QString name); //ok + + /** + * Returns the value associated with a certain key + */ + QVariant preferenceForKey(QString key); //ok + + void prepareForTransition(QString transition); + + void performTransition(); + + void setCloseBoxOffset(int x, int y); //not needed + + /** + * Saves a value to a key + */ + void setPreferenceForKey(QString value, QString key); //ok + + void system(QString command, QString handler); //cannot really be implemented +private: + //TODO: execute when needed + QString m_onshow; //has no equivalent in plasma, because always shown + QString m_onhide; //has no equivalent in plasma, because always shown + QString m_onremove; //ok + + QString m_ondragstart; + QString m_ondragstop; + + //my private stuff + Plasma::Applet *m_applet; + QWebFrame *m_frame; +}; + +#endif diff --git a/plasma/generic/scriptengines/webkit/plasma-packagestructure-dashboard.desktop b/plasma/generic/scriptengines/webkit/plasma-packagestructure-dashboard.desktop new file mode 100644 index 00000000..1a2485b6 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/plasma-packagestructure-dashboard.desktop @@ -0,0 +1,159 @@ +[Desktop Entry] +Name=MacOS Dashboard Widgets +Name[ar]=ودجات لوحة MacOS +Name[ast]=Elementos gráficos del tableru de mandos de MacOS +Name[be@latin]=Widžety „Dashboard” dla systemy „MacOS” +Name[bg]=Джаджи за табло на MacOS +Name[bs]=Grafičke kontrole instrument-table MacOS‑a +Name[ca]=Estri del tauler del MacOS +Name[ca@valencia]=Estri del tauler del MacOS +Name[cs]=Widgety palubní desky MacOS +Name[da]=MacOS dashboard-widgets +Name[de]=MacOS-Dashboard-Miniprogramme +Name[el]=Συστατικά του MacOS dashboard +Name[en_GB]=MacOS Dashboard Widgets +Name[eo]=MacOS stirtabla fenestraĵo +Name[es]=Elementos gráficos del tablero de mandos de MacOS +Name[et]=MacOS-i vidinavaate vidinad +Name[eu]=MacOS-ren aginte-mahaiko trepetak +Name[fi]=MacOS-kojelautasovelmat +Name[fr]=Composants graphiques du panneau de contrôle de MacOS +Name[fy]=MacOS Dashboard Widgets +Name[ga]=Giuirléidí Dashboard MacOS +Name[gl]=Widget do Dashboard de MacOS +Name[gu]=MacOS ડેશબોર્ડ વિજેટ +Name[he]=ווידג׳טים של MacOS Dashboard +Name[hi]=मैकओएस डैशबोर्ड विजेट +Name[hne]=मेकओएस डेसबोर्ड विजेट +Name[hr]=MacOS widgeti nadzorne ploče +Name[hu]=MacOS Dashboard-elem +Name[ia]=MacOS Dashboard Widgets +Name[id]=Widget Dasbor MacOS +Name[is]=MacOS dashboard græjur +Name[ja]=MacOS ダッシュボードウィジェット +Name[kk]=MacOS аспаптар панелі +Name[km]=ធាតុក្រាហ្វិក​ផ្ទាំង​គ្រប់គ្រង MacOS +Name[kn]=MacOS ಯಂತ್ರೋಪಕರಣ ಪಟ್ಟಿ (ಡ್ಯಾಶ್‌ಬೋರ್ಡ್) ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟಗಳು (ವಿಡ್ಗೆಟ್) +Name[ko]=MacOS 대시보드 위젯 +Name[ku]=Alavên Panela Kontrolê yên MacOS +Name[lt]=MacOS prietaisų skydelio valdikliai +Name[lv]=MacOS dashboard sīkrīki +Name[ml]=മാക് ഓഎസ് ഡാഷ്ബോര്‍ഡ് ഉരുപ്പടികള്‍ +Name[mr]=MacOS डॅशबोर्ड विजेट +Name[nb]=Kontrollpult-elementer for MacOS +Name[nds]=MacOs-Klockpaneel-Lüttprogrammen +Name[nl]=MacOS Dashboard Widgets +Name[nn]=MacOS-kontrollpultelement +Name[or]=MacOS ଡ୍ୟାସବୋର୍ଡ ୱିଜେଟଗୁଡ଼ିକ +Name[pa]=MacOS ਡੈਸ਼ਬੋਰਡ ਵਿਦਜੈੱਟ +Name[pl]=Element interfejsu na tablicy z MacOS +Name[pt]=Elementos do Painel do MacOS +Name[pt_BR]=Widgets do painel do MacOS +Name[ro]=Controale ale tabloului de bord MacOS +Name[ru]=Виджеты Mac OS +Name[si]=MacOS Dashboard Widgets +Name[sk]=MacOS Dashboard widgety +Name[sl]=Gradniki za Mac OS Dashboard +Name[sr]=виџети инструмент-табле МекОС‑а +Name[sr@ijekavian]=виџети инструмент-табле МекОС‑а +Name[sr@ijekavianlatin]=vidžeti instrument-table MacOS‑a +Name[sr@latin]=vidžeti instrument-table MacOS‑a +Name[sv]=Grafiska komponenter för MacOS instrumentpanel +Name[ta]=MacOS Dashboard Widgets +Name[tg]=Илова ба панели MacOS +Name[th]=วิดเจ็ตของแดชบอร์ด MacOS +Name[tr]=MacOS Kontrol Paneli Gereçleri +Name[ug]=MacOS تىزگىن تاختا ۋىجېتلىرى +Name[uk]=Віджети панелі приладів MacOS +Name[vi]=Widget bảng thông tin MacOS +Name[wa]=Ahesses Dashboard MacOS +Name[x-test]=xxMacOS Dashboard Widgetsxx +Name[zh_CN]=MacOS 部件板部件 +Name[zh_TW]=MacOS 資訊看板元件 +Comment=MacOS dashboard widget +Comment[ar]=ودجة لوحة MacOS +Comment[ast]=Elementu gráficu del tableru de mandos de MacOS +Comment[be@latin]=Widžet „Dashboard” dla systemy „MacOS” +Comment[bg]=Джаджа за табло на MacOS +Comment[bs]=Grafičke kontrola instrument-table kao u MacOS‑u +Comment[ca]=Estri del tauler del MacOS +Comment[ca@valencia]=Estri del tauler del MacOS +Comment[cs]=Widget palubní desky MacOS +Comment[da]=MacOS dashboard-widget +Comment[de]=MacOS-Dashboard-Miniprogramm +Comment[el]=Συστατικό του MacOS dashboard +Comment[en_GB]=MacOS dashboard widget +Comment[eo]=MacOS stirtabla fenestraĵo +Comment[es]=Elemento gráfico del tablero de mandos de MacOS +Comment[et]=MacOS-i vidinavaate vidin +Comment[eu]=MacOS-ren aginte-mahaiko trepeta +Comment[fi]=MacOS-kojelautasovelma +Comment[fr]=Composant graphique du panneau de contrôle de MacOS +Comment[fy]=MacOS dashboard widget +Comment[ga]=Giuirléid Dashboard MacOS +Comment[gl]=Widget do dashboard de MacOS +Comment[gu]=MacOS ડેશબોર્ડ વિજેટ +Comment[he]=ווידג׳ט של MacOS dashboard +Comment[hi]=मैकओएस डैशबोर्ड विजेट +Comment[hne]=मेकओएस डेसबोर्ड विजेट +Comment[hr]=MacOS widget nadzorne ploče +Comment[hu]=MacOS Dashboard-elem +Comment[ia]=Widget de pannello de instrumentos de MacOS +Comment[id]=Widget dasbor MacOS +Comment[is]=MacOS dashboard græja +Comment[ja]=MacOS ダッシュボードウィジェット +Comment[kk]=MacOS аспаптар панелі +Comment[km]=ធាតុ​ក្រាហ្វិក​ផ្ទាំង​គ្រប់គ្រង​របស់ MacOS +Comment[kn]=MacOS ಯಂತ್ರೋಪಕರಣ ಪಟ್ಟಿ (ಡಾಶ್ ಬೋರ್ಡ್) ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Comment[ko]=MacOS 대시보드 위젯 +Comment[ku]=Amûrê MacOS dashboardê +Comment[lt]=MacOS prietaisų skydelio valdiklis +Comment[lv]=MacOS dashboard skrīks +Comment[ml]=മാക് ഓഎസ് ഡാഷ്ബോര്‍ഡ് ഉരുപ്പടി +Comment[mr]=MacOS डॅशबोर्ड विजेट +Comment[nb]=Kontrollpult-element for MacOS +Comment[nds]=MacOs-Klockpaneel +Comment[nl]=MacOS-dashboard-widget +Comment[nn]=MacOS-kontrollpultelement +Comment[or]=MacOS ଡ୍ୟାସବୋର୍ଡ ୱିଜେଟ +Comment[pa]=MacOS ਡੈਸ਼ਬੋਰਡ ਵਿਦਜੈੱਟ +Comment[pl]=Element interfejsu przypominający tablicę z MacOS +Comment[pt]=Elemento do Painel do MacOS +Comment[pt_BR]=Widget do painel do MacOS +Comment[ro]=Control al tabloului de bord MacOS +Comment[ru]=Виджет Mac OS +Comment[si]=MacOS dashboard widget +Comment[sk]=MacOS dashboard widget +Comment[sl]=Gradnik za Mac OS Dashboard +Comment[sr]=Виџет инструмент-табле као у МекОС‑у +Comment[sr@ijekavian]=Виџет инструмент-табле као у МекОС‑у +Comment[sr@ijekavianlatin]=Vidžet instrument-table kao u MacOS‑u +Comment[sr@latin]=Vidžet instrument-table kao u MacOS‑u +Comment[sv]=Grafisk komponent för MacOS instrumentpanel +Comment[ta]=MacOS dashboard widget +Comment[te]=MacOS డాష్‌బోర్‍డ్ విడ్జట్ +Comment[tg]=Илова ба панели MacOS +Comment[th]=วิดเจ็ตของแดชบอร์ด MacOS +Comment[tr]=MacOS kontrol paneli gereci +Comment[ug]=MacOS تىزگىن تاختا ۋىجېتى +Comment[uk]=Віджет панелі приладів MacOS +Comment[vi]=Widget bảng thông tin MacOS +Comment[wa]=Ahesse do tåvlea d' boird dashboard di MacOS +Comment[x-test]=xxMacOS dashboard widgetxx +Comment[zh_CN]=MacOS 部件板 +Comment[zh_TW]=MacOS 資訊看板元件 +Type=Service +ServiceTypes=Plasma/PackageStructure + +X-KDE-Library=plasma_packagestructure_dashboard +X-KDE-PluginInfo-Author=Zack Rusin +X-KDE-PluginInfo-Email=zackr@kde.org +X-KDE-PluginInfo-Name=dashboard +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Applet +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=BSD +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-PackageFileFilter=* +X-Plasma-PackageFileMimetypes=application/zip diff --git a/plasma/generic/scriptengines/webkit/plasma-packagestructure-web.desktop b/plasma/generic/scriptengines/webkit/plasma-packagestructure-web.desktop new file mode 100644 index 00000000..1cb95afe --- /dev/null +++ b/plasma/generic/scriptengines/webkit/plasma-packagestructure-web.desktop @@ -0,0 +1,163 @@ +[Desktop Entry] +Name=Web Widgets +Name[ar]=ودجات الوِب +Name[ast]=Elementos gráficos Web +Name[be@latin]=Sieciŭnyja widžety +Name[bg]=Уеб джаджи +Name[bn]=ওয়েব উইজেট +Name[bn_IN]=ওয়েব উইজেট +Name[bs]=Web grafičke kontrola +Name[ca]=Estris web +Name[ca@valencia]=Estris web +Name[cs]=Webové widgety +Name[csb]=Interfejs sécë Web +Name[da]=Web-widgets +Name[de]=Web-Miniprogramme +Name[el]=Συστατικά ιστού +Name[en_GB]=Web Widgets +Name[eo]=Reta fenestraĵo +Name[es]=Elementos gráficos Web +Name[et]=Veebividinad +Name[eu]=Web-trepetak +Name[fi]=Web-sovelmat +Name[fr]=Composants graphiques Web +Name[fy]=Web Widgets +Name[ga]=Giuirléidí Gréasáin +Name[gl]=Widgets web +Name[gu]=વેબ વિજેટ્સ +Name[he]=ווידג׳טים אינטרנטיים +Name[hi]=वेब विजेट +Name[hne]=वेब विजेट +Name[hr]=Web widgeti +Name[hu]=Webes elem +Name[ia]=Web Widgets +Name[id]=Widget Web +Name[is]=Vefgræjur +Name[ja]=ウェブウィジェット +Name[kk]=Веб интерфейс бөлшегі +Name[km]=ធាតុក្រាហ្វិក​បណ្ដាញ +Name[kn]=ಜಾಲ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟಗಳು (ವಿಡ್ಗೆಟ್) +Name[ko]=웹 위젯 +Name[ku]=Alavên Torê +Name[lt]=Žiniatinklio valdikliai +Name[lv]=Tīmekļa sīkrīki +Name[ml]=വെബ് ഉരുപ്പടികള്‍ +Name[mr]=वेब विजेट +Name[nb]=Nett-elementer +Name[nds]=Nett-Lüttprogrammen +Name[nl]=Web Widgets +Name[nn]=Vevelement +Name[or]=ୱେବ ୱିଜେଟଗୁଡ଼ିକ +Name[pa]=ਵੈੱਬ ਵਿਦਜੈੱਟ +Name[pl]=Strona sieci Web (element interfejsu) +Name[pt]=Elementos Web +Name[pt_BR]=Widgets da Internet +Name[ro]=Controale WEB +Name[ru]=Веб-виджеты +Name[si]=වෙබ් මෙවලම් +Name[sk]=Webové widgety +Name[sl]=Spletni gradniki +Name[sr]=веб виџети +Name[sr@ijekavian]=веб виџети +Name[sr@ijekavianlatin]=veb vidžeti +Name[sr@latin]=veb vidžeti +Name[sv]=Grafiska webbkomponenter +Name[ta]=Web Widgets +Name[tg]=Иловагиҳо ба Интернет +Name[th]=วิดเจ็ตแบบเว็บ +Name[tr]=Web Gereçleri +Name[ug]=تور بەت Widget +Name[uk]=Віджети Тенет +Name[wa]=Ahesses waibe +Name[x-test]=xxWeb Widgetsxx +Name[zh_CN]=网页部件 +Name[zh_TW]=網頁元件 +Comment=HTML widget +Comment[ar]=ودجة HTML +Comment[ast]=Elementu gráficu HTML +Comment[be@latin]=Widžet HTML +Comment[bg]=HTML джаджи +Comment[bn]=HTML উইজেট +Comment[bn_IN]=HTML উইজেট +Comment[bs]=HTML grafička kontrola +Comment[ca]=Estri HTML +Comment[ca@valencia]=Estri HTML +Comment[cs]=HTML widget +Comment[csb]=Interfejs HTML +Comment[da]=HTML-widget +Comment[de]=HTML-Miniprogramme +Comment[el]=Συστατικό HTML +Comment[en_GB]=HTML widget +Comment[eo]=HTML-fenestraĵo +Comment[es]=Elemento gráfico HTML +Comment[et]=HTML-vidin +Comment[eu]=HTML trepeta +Comment[fi]=HTML-sovelma +Comment[fr]=Composant graphique HTML +Comment[fy]=HTML widget +Comment[ga]=Giuirléid HTML +Comment[gl]=Widget HTML +Comment[gu]=HTML વિજેટ +Comment[he]=ווידג׳ט HTML +Comment[hi]=एचटीएमएल विज़ेट +Comment[hne]=एचटीएमएल विजेट +Comment[hr]=HTML widget +Comment[hu]=HTML-elem +Comment[ia]=widget HTML +Comment[id]=Widget HTML +Comment[is]=HTML græja +Comment[ja]=HTML ウィジェット +Comment[kk]=HTML интерфейс бөлшегі +Comment[km]=ធាតុ​ក្រាហ្វិក HTML +Comment[kn]=HTML ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Comment[ko]=HTML 위젯 +Comment[ku]=Alava HTML +Comment[lt]=HTML valdiklis +Comment[lv]=HTML sīkrīks +Comment[ml]=എച്ച്ടിഎംഎല്‍ ഉരുപ്പടി +Comment[mr]=HTML विजेट +Comment[nb]=HTML-element +Comment[nds]=HTML-Lüttprogramm +Comment[nl]=HTML-widget +Comment[nn]=HTML-element +Comment[or]=HTML ୱିଜେଟ +Comment[pa]=HTML ਵਿਦਜੈੱਟ +Comment[pl]=Element interfejsu będący stroną w HTML-u +Comment[pt]=Elemento HTML +Comment[pt_BR]=Widget HTML +Comment[ro]=Control HTML +Comment[ru]=Виджет на HTML +Comment[si]=HTML මෙවලම් +Comment[sk]=HTML widget +Comment[sl]=Gradnik HTML +Comment[sr]=ХТМЛ виџет +Comment[sr@ijekavian]=ХТМЛ виџет +Comment[sr@ijekavianlatin]=HTML vidžet +Comment[sr@latin]=HTML vidžet +Comment[sv]=Grafisk HTML-komponent +Comment[ta]=HTML widget +Comment[tg]=Илова ба HTML +Comment[th]=วิดเจ็ตแบบ HTML +Comment[tr]=HTML parçacığı +Comment[ug]=HTML widget +Comment[uk]=Віджет HTML +Comment[vi]=Widget HTML +Comment[wa]=Ahesse HTML +Comment[x-test]=xxHTML widgetxx +Comment[zh_CN]=HTML 部件 +Comment[zh_TW]=HTML 元件 +Type=Service +ServiceTypes=Plasma/PackageStructure + +X-KDE-Library=plasma_packagestructure_web +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=webkit +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Applet +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=BSD +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-PackageFileFilter=* +X-Plasma-PackageFileMimetypes=application/zip diff --git a/plasma/generic/scriptengines/webkit/plasma-scriptengine-applet-dashboard.desktop b/plasma/generic/scriptengines/webkit/plasma-scriptengine-applet-dashboard.desktop new file mode 100644 index 00000000..a74dabd1 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/plasma-scriptengine-applet-dashboard.desktop @@ -0,0 +1,166 @@ +[Desktop Entry] +Name=Dashboard +Name[ar]=لوحة الودجات +Name[ast]=Tableru de mandos +Name[be@latin]=Dashboard +Name[bg]=Табло +Name[bn]=ড্যাশবোর্ড +Name[bn_IN]=Dashboard +Name[bs]=instrument-tabla +Name[ca]=Tauler +Name[ca@valencia]=Tauler +Name[cs]=Dashboard +Name[csb]=Panel +Name[da]=Instrumentbræt +Name[de]=Dashboard +Name[el]=Πίνακας συστατικών +Name[en_GB]=Dashboard +Name[eo]=Stirtablo +Name[es]=Tablero de mandos +Name[et]=Vidinavaade +Name[eu]=Agente-mahaia +Name[fi]=Kojelauta +Name[fr]=Panneau de contrôle +Name[fy]=Dashboard +Name[ga]=Dashboard +Name[gl]=Cadro de control +Name[gu]=ડેશબોર્ડ +Name[he]=מכתבה +Name[hi]=डैशबोर्ड +Name[hne]=डेशबोर्ड +Name[hr]=Nadzorna ploča +Name[hu]=Dashboard +Name[ia]=Pannello de instrumentos +Name[id]=Dasbor +Name[is]=Dashboard +Name[it]=Dashboard +Name[ja]=ダッシュボード +Name[kk]=Аспаптар панелі +Name[km]=ផ្ទាំង​គ្រប់គ្រង +Name[kn]=ಯಂತ್ರೋಪಕರಣ ಪಟ್ಟಿ (ಡಾಶ್ ಬೋರ್ಡ್) +Name[ko]=대시보드 +Name[ku]=Panela Kontrolê +Name[lt]=Prietaisų skydelis +Name[lv]=Dashboard +Name[ml]=ഡാഷ്ബോര്‍ഡ് +Name[mr]=डॅशबोर्ड +Name[nb]=Kontrollpult +Name[nds]=Klockpaneel +Name[nl]=Dashboard +Name[nn]=Kontrollpult +Name[or]=ଡ୍ୟାସବୋର୍ଡ +Name[pa]=ਡੈਸ਼ਬੋਰਡ +Name[pl]=Tablica +Name[pt]=Dashboard +Name[pt_BR]=Painel +Name[ro]=Tablou de bord +Name[ru]=Приборная доска +Name[si]=පාලක පුරුව +Name[sk]=Nástenka +Name[sl]=Nadzorna plošča +Name[sr]=инструмент-табла +Name[sr@ijekavian]=инструмент-табла +Name[sr@ijekavianlatin]=instrument-tabla +Name[sr@latin]=instrument-tabla +Name[sv]=Instrumentpanel +Name[ta]= எக்ஸ்போர்டு +Name[te]=డాష్‌బోర్‍డ్ +Name[tg]=Панели иловагиҳо +Name[th]=แดชบอร์ด +Name[tr]=Kontrol Paneli +Name[ug]=باشقۇرۇش بېتى +Name[uk]=Панель приладів +Name[vi]=Bảng thông tin +Name[wa]=Tåvlea d' boird +Name[x-test]=xxDashboardxx +Name[zh_CN]=部件板 +Name[zh_TW]=資訊看板 +Comment=MacOS X dashboard widget +Comment[ar]=ودجة لوحة MacOS +Comment[ast]=Elementu gráficu del tableru de mandos de MacOS X +Comment[be@latin]=Widžet „Dashboard” systemy „MacOS X”. +Comment[bg]=Джаджа за табло на MacOS X +Comment[bs]=Grafička kontrola instrument-table MacOS‑a X +Comment[ca]=Estri del tauler del MacOS X +Comment[ca@valencia]=Estri del tauler del MacOS X +Comment[cs]=Widget palubní desky MacOS +Comment[da]=MacOS X dashboard-widget +Comment[de]=MacOS-X-Dashboard-Miniprogramm +Comment[el]=Συστατικό MacOS X dashboard +Comment[en_GB]=MacOS X dashboard widget +Comment[eo]=MacOS X stirtabla fenestraĵo +Comment[es]=Elemento gráfico del tablero de mandos de MacOS X +Comment[et]=MacOS X vidinavaate vidin +Comment[eu]=MacOS X-ren aginte-mahaiko trepeta +Comment[fi]=MacOS X -kojelautasovelma +Comment[fr]=Composant graphique du panneau de contrôle de MacOS X +Comment[fy]=MacOS X dashboard widget +Comment[ga]=Giuirléid Dashboard MacOS X +Comment[gl]=Widget do dashboard de MacOS X +Comment[gu]=MacOS X ડેશબોર્ડ વિજેટ +Comment[he]=ווידג׳טים של MacOS X dashboard +Comment[hi]=मैकओएस X डैशबोर्ड विजेट +Comment[hne]=मेकओएस X डेसबोर्ड विजेट +Comment[hr]=MacOS X nadzorna ploča za widgete +Comment[hu]=MacOS X Dashboard-elem +Comment[ia]=Widget de pannello de instrumentos de MacOS X +Comment[id]=Widget dasbor MacOS X +Comment[is]=MacOS X dashboard græja +Comment[ja]=MacOS X ダッシュボードウィジェット +Comment[kk]=MacOS X аспаптар панелі +Comment[km]=ធាតុ​ក្រាហ្វិក​ផ្ទាំងគ្រប់គ្រង​របស់ MacOS +Comment[kn]=MacOS X ಯಂತ್ರೋಪಕರಣ ಪಟ್ಟಿ (ಡಾಶ್ ಬೋರ್ಡ್) ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Comment[ko]=Mac OS X 대시보드 위젯 +Comment[ku]=Amûrê MacOS X dashboardê +Comment[lt]=MacOS X prietaisų skydelio valdiklis +Comment[lv]=MacOS X dashboard sīkrīks +Comment[ml]=മാക് ഓഎസ് എക്സ് ഡാഷ്ബോര്‍ഡ് ഉരുപ്പടി +Comment[mr]=MacOS X डॅशबोर्ड विजेट +Comment[nb]=MacOS X kontrollpult-element +Comment[nds]=MacOs-X-Klockpaneel +Comment[nl]=MacOS X-dashboard-widget +Comment[nn]=MacOS X-kontrollpultelement +Comment[or]=MacOS X ଡ୍ୟାସବୋର୍ଡ ୱିଜେଟ +Comment[pa]=MacOS X ਡੈਸ਼ਬੋਰਡ ਵਿਦਜੈੱਟ +Comment[pl]=Element interfejsu przypominający tablicę z MacOS X +Comment[pt]=Elemento gráfico do painel do MacOS X +Comment[pt_BR]=Widget do painel do MacOS X +Comment[ro]=Control al tabloului de bord MacOS X +Comment[ru]=Виджет Mac OS X +Comment[si]=MacOS X dashboard widget +Comment[sk]=MacOS X dashboard widget +Comment[sl]=Gradnik za Mac OS X Dashboard +Comment[sr]=Виџет инструмент-табле МекОС‑а X +Comment[sr@ijekavian]=Виџет инструмент-табле МекОС‑а X +Comment[sr@ijekavianlatin]=Vidžet instrument-table MacOS‑a X +Comment[sr@latin]=Vidžet instrument-table MacOS‑a X +Comment[sv]=Grafisk komponent för MacOS X instrumentpanel +Comment[ta]=MacOS X dashboard widget +Comment[te]=MacOS X డాష్‌బోర్‍డ్ విడ్జట్ +Comment[tg]=Илова ба панели MacOS X +Comment[th]=วิดเจ็ตของแดชบอร์ด MacOS X +Comment[tr]=MacOS X kontrol paneli programcığı +Comment[ug]=MacOS X تىزگىن تاختا ۋىجېتى +Comment[uk]=Віджет панелі приладів MacOS X +Comment[vi]=Widget bảng thông tin MacOS X +Comment[wa]=Ahesse do tåvlea d' boird dashboard di MacOS X +Comment[x-test]=xxMacOS X dashboard widgetxx +Comment[zh_CN]=MacOS X 部件板 +Comment[zh_TW]=MacOS X 資訊看板元件 +Type=Service +ServiceTypes=Plasma/ScriptEngine +Icon=internet-web-browser + +X-KDE-Library=plasma_appletscriptengine_dashboard +X-KDE-PluginInfo-Author=Zack Rusin +X-KDE-PluginInfo-Email=zackr@kde.org +X-KDE-PluginInfo-Name=dashboard +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Applet +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=BSD +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-ComponentTypes=Applet +X-Plasma-API=dashboard +X-Plasma-PackageFormat=dashboard diff --git a/plasma/generic/scriptengines/webkit/plasma-scriptengine-applet-web.desktop b/plasma/generic/scriptengines/webkit/plasma-scriptengine-applet-web.desktop new file mode 100644 index 00000000..dac3dd10 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/plasma-scriptengine-applet-web.desktop @@ -0,0 +1,163 @@ +[Desktop Entry] +Name=Web Widget +Name[ar]=ودجة وِب +Name[ast]=Elementu gráficu Web +Name[be@latin]=Sieciŭny widžet +Name[bg]=Уеб джаджа +Name[bn]=ওয়েব উইজেট +Name[bn_IN]=ওয়েব উইজেট +Name[bs]=Web grafička kontrola +Name[ca]=Estri web +Name[ca@valencia]=Estri web +Name[cs]=Webový widget +Name[csb]=Sztél zblëżający bedënk do sécë Web +Name[da]=Webwidget +Name[de]=Web-Miniprogramm +Name[el]=Συστατικό ιστού +Name[en_GB]=Web Widget +Name[eo]=Reta fenestraĵo +Name[es]=Elemento gráfico Web +Name[et]=Veebividin +Name[eu]=Web-trepeta +Name[fi]=Web-sovelma +Name[fr]=Composant graphique Web +Name[fy]=Web Widget +Name[ga]=Giuirléid Ghréasáin +Name[gl]=Widget web +Name[gu]=વેબ વિજેટ +Name[he]=ווידג׳ט אינטרנט +Name[hi]=वेब विज़ेट +Name[hne]=वेब विजेट +Name[hr]=Web widget +Name[hu]=Webes elem +Name[ia]=Web Widget +Name[id]=Widget Web +Name[is]=Vefgræja +Name[ja]=ウェブウィジェット +Name[kk]=Веб интерфейс бөлшегі +Name[km]=ធាតុក្រាហ្វិក​បណ្ដាញ +Name[kn]=ಜಾಲ ನಿಯಂತ್ರಣಾ ಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Name[ko]=웹 위젯 +Name[ku]=Alava Torê +Name[lt]=Žiniatinklio valdiklis +Name[lv]=Tīmekļa sīkrīks +Name[ml]=വെബ് ഉരുപ്പടി +Name[mr]=वेब विजेट +Name[nb]=Nett-element +Name[nds]=Nett-Lüttprogramm +Name[nl]=Web-widget +Name[nn]=Vevelement +Name[or]=ୱେବ ୱିଜେଟ +Name[pa]=ਵੈੱਬ ਵਿਦਜੈੱਟ +Name[pl]=Strona sieci Web (element interfejsu) +Name[pt]=Elemento Web +Name[pt_BR]=Widget da Internet +Name[ro]=Control WEB +Name[ru]=Веб-виджет +Name[si]=වෙබ් මෙවලම් +Name[sk]=Webový widget +Name[sl]=Spletni gradnik +Name[sr]=веб виџет +Name[sr@ijekavian]=веб виџет +Name[sr@ijekavianlatin]=veb vidžet +Name[sr@latin]=veb vidžet +Name[sv]=Webbkomponent +Name[ta]=Web Widget +Name[te]=వెబ్ విడ్జట్ +Name[tg]=Илова ба Интернет +Name[th]=วิดเจ็ตแบบเว็บ +Name[tr]=Web Programcığı +Name[ug]=تور بەت Widget +Name[uk]=Віджет тенет +Name[wa]=Ahesse waibe +Name[x-test]=xxWeb Widgetxx +Name[zh_CN]=网页部件 +Name[zh_TW]=網頁元件 +Comment=Webpage widget using HTML and JavaScript +Comment[ar]=صفحة وِب باستخدام HTML وجافا سكربت +Comment[ast]=Elementu gráficu de páxina web qu'usa HTML y JavaScript +Comment[be@latin]=Widžet z staronkaj u farmacie „HTML” i z skryptami „JavaScript”. +Comment[bg]=Джаджа за уеб страници (HTML и JavaScript) +Comment[bs]=Grafička kontrola web stranice sa HTML‑om i JavaScriptom +Comment[ca]=Estri per a pàgines web que usa HTML i JavaScript +Comment[ca@valencia]=Estri per a pàgines web que usa HTML i JavaScript +Comment[cs]=Widget webové stránky s HTML a JS +Comment[da]=Hjemmeside-widget som bruger HTML og JavaScript +Comment[de]=Webseiten-Miniprogramm (verwendet HTML und JavaScript) +Comment[el]=Συστατικό ιστοσελίδας με χρήση HTML και JavaScript +Comment[en_GB]=Webpage widget using HTML and JavaScript +Comment[eo]=Reta fenestraĵo kiu uzas HTML-on kaj Ĝavoskripton +Comment[es]=Elemento gráfico de página web que usa HTML y JavaScript +Comment[et]=HTML-i ja JavaScripti kasutav veebilehekülje vidin +Comment[eu]=HTML eta JavaScript erabiltzen dituen web-orriko trepeta +Comment[fi]=HTML:ää ja JavaScriptiä käyttävä verkkosivusovelma +Comment[fr]=Composant graphique de page Web utilisant HTML et JavaScript +Comment[fy]=Webside widget brûkend HTML en JavaSkript +Comment[ga]=Giuirléid Ghréasáin a úsáideann HTML agus JavaScript +Comment[gl]=Widget de páxina web que emprega HTML e JavaScript +Comment[gu]=HTML અને જાવાસ્ક્રિપ્ટ ઉપયોગ કરીને વેબપાનું વિજેટ +Comment[he]=ווידג׳ט עמוד אינטרנט העושה שימוש ב־HTML וב־JavaScript +Comment[hi]=एचटीएमएल एवं जावा-स्क्रिप्ट के प्रयोग से जालपृष्ठ विजेट +Comment[hne]=एचटीएमएल अउ जावास्क्रिप्ट के उपयोग से वेबपेज विजेट +Comment[hr]=Widgeti web stranice koja koristi HTML i JavaScript +Comment[hu]=Webes elem HTML/Javascript használatával +Comment[ia]=Elemento graphic (Widget) de pagina web usante HTML e JavaScript +Comment[id]=Widget halaman web menggunakan HTML dan JavaScript +Comment[is]=Vefsíðugræja sem notar HTML og JavaScript +Comment[ja]=HTML と JavaScript を使ったウェブページウィジェット +Comment[kk]=HTML мен JavaScript негіздеген Веб-парақ бөлшегі +Comment[km]=ធាតុក្រាហ្វិក​ទំព័រ​បណ្ដាញ​ដោយប្រើ HTML និង JavaScript +Comment[kn]=HTML ಮತ್ತು ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಬಳಸುವ ಜಾಲಪುಟ ನಿಯಂತ್ರಣಾಸಂಪರ್ಕತಟ (ವಿಡ್ಗೆಟ್) +Comment[ko]=HTML과 자바스크립트를 사용하는 웹 페이지 위젯 +Comment[ku]=Amûrê Rûpela Webê HTML û JavaScript bi kar tîne +Comment[lt]=Žiniatinklio puslapio valdiklis naudojantis HTML ir JavaScript +Comment[lv]=Tīmekļa lapas sīkrīks, kas izmanto HTML un JavaScript +Comment[ml]=എച്ച്ടിഎംഎലും ജാവാസ്ക്രിപ്റ്റും ഉപയോഗിക്കുന്ന വെബ്താള്‍ ഉരുപ്പടി +Comment[mr]=HTML व जावास्क्रिप्टचा वापर करणारे वेबपान विजेट +Comment[nb]=Nettside-element som bruker HTML og JavaScript +Comment[nds]=Nettsieden-Finster, bruukt HTML un JavaScript +Comment[nl]=Webpagina-widget, gebruikmakend van HTML en JavaScript +Comment[nn]=Nettsideelement som brukar HTML og JavaScript +Comment[or]=HTML ଏବଂ JavaScript ବ୍ୟବହାର କରି ୱେବ ପୃଷ୍ଠା ୱିଜେଟ +Comment[pa]=HTML ਅਤੇ ਜਾਵਾ-ਸਕ੍ਰਿਪਟ ਨਾਲ ਵੈੱਬ-ਪੇਜ਼ ਵਿਦਜੈੱਟ +Comment[pl]=Element interfejsu wykorzystujący HTML oraz JavaScript +Comment[pt]=Elemento de página Web que usa HTML e JavaScript +Comment[pt_BR]=Widget de página da Internet usando HTML e JavaScript +Comment[ro]=Control web scris în HTML și JavaScript +Comment[ru]=Показ веб-страницы +Comment[si]=Webpage widget using HTML and JavaScript +Comment[sk]=Widget webovej stránky, ktorý používa HTML a JavaScript +Comment[sl]=Spletni gradnik, ki uporablja HTML in JavaScript +Comment[sr]=Виџет веб странице са ХТМЛ‑ом и јаваскриптом +Comment[sr@ijekavian]=Виџет веб странице са ХТМЛ‑ом и јаваскриптом +Comment[sr@ijekavianlatin]=Vidžet veb stranice sa HTML‑om i JavaScriptom +Comment[sr@latin]=Vidžet veb stranice sa HTML‑om i JavaScriptom +Comment[sv]=Grafisk webbkomponent som använder HTML och Javascript +Comment[ta]=Webpage widget using HTML and JavaScript +Comment[te]=HTML మరియు జావాస్క్రిప్‍ట్ ఉపయోగించు వెబ్‌పేజ్ విడ్జట్ +Comment[tg]=Модуль, использующий HTML и JavaScript +Comment[th]=วิดเจ็ตหน้าเว็บที่ถูกเขียนด้วย HTML และจาวาสคริปต์ +Comment[tr]=HTML ve JavaScript kullanan Web sayfası programcığı +Comment[ug]=HTML ۋە JavaScript ئىشلەتكەن تور بەت widget +Comment[uk]=Віджет сторінки тенет, що використовує HTML і JavaScript +Comment[wa]=Ahesse di pådje waibe eployant l' HTML eyet JavaScript +Comment[x-test]=xxWebpage widget using HTML and JavaScriptxx +Comment[zh_CN]=使用 HTML 和JavaScript 的网页部件 +Comment[zh_TW]=使用 HTML 與 JavaScript 的網頁元件 +Type=Service +ServiceTypes=Plasma/ScriptEngine +Icon=internet-web-browser + +X-KDE-Library=plasma_appletscriptengine_webapplet +X-KDE-PluginInfo-Author=Zack Rusin +X-KDE-PluginInfo-Email=zack@kde.org +X-KDE-PluginInfo-Name=webkit +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Applet +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=BSD +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-API=webkit +X-Plasma-ComponentTypes=Applet +X-Plasma-PackageFormat=webkit diff --git a/plasma/generic/scriptengines/webkit/plasmajs.cpp b/plasma/generic/scriptengines/webkit/plasmajs.cpp new file mode 100644 index 00000000..3bfe4132 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/plasmajs.cpp @@ -0,0 +1,141 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#include "plasmajs.h" +#include "plasmawebapplet.h" + +#include + +using namespace Plasma; + +ConfigGroupWrapper::ConfigGroupWrapper(const KConfigGroup &config) +: m_config(config) +{ +} + +void ConfigGroupWrapper::setConfig(const KConfigGroup &config) +{ + //kDebug() << config.config()->name() << config.name(); + m_config = config; +} + +QVariant ConfigGroupWrapper::readEntry(const QString &key, const QVariant &aDefault) const +{ + // Should KConfig do this? + // There is readEntry(key, QVariant) but it does not seem to work + // (if writeEntry was not QVariant??) + // kDebug() << aDefault.typeName(); + if (aDefault.type() == QVariant::Int) { + return m_config.readEntry(key, aDefault.toInt()); + } else if (aDefault.type() == QVariant::Double) { + return m_config.readEntry(key, aDefault.toDouble()); + } else if (aDefault.type() == QVariant::Bool) { + return m_config.readEntry(key, aDefault.toBool()); + } else { + return m_config.readEntry(key, aDefault.toString()); + } +} + +void ConfigGroupWrapper::writeEntry(const QString &key, const QVariant& value) +{ + m_config.writeEntry(key, value); +} + +DataEngineDataWrapper::DataEngineDataWrapper(const DataEngine::Data &data) + : m_data(data) +{ +} + +int DataEngineDataWrapper::length() const +{ + return m_data.count(); +} + +void DataEngineDataWrapper::setData(const Plasma::DataEngine::Data &data) +{ + m_data = data; +} + +QVariant DataEngineDataWrapper::value(const QString &key) const +{ + return m_data[key]; +} + +bool DataEngineDataWrapper::contains(const QString &key) const +{ + return m_data.keys().contains(key); +} + +QStringList DataEngineDataWrapper::keys() const +{ + return m_data.keys(); +} + +QString DataEngineDataWrapper::key(int i) const +{ + return m_data.keys().at(i); +} + +DataEngineWrapper::DataEngineWrapper(Plasma::DataEngine *engine, QObject *applet) + : QObject(engine), m_engine(engine), m_applet(applet) +{ +} + +QStringList DataEngineWrapper::sources() const +{ + return m_engine->sources(); +} + +QString DataEngineWrapper::engineName() const +{ + return m_engine->name(); +} + +bool DataEngineWrapper::isValid() const +{ + return m_engine->isValid(); +} + +QString DataEngineWrapper::icon() const +{ + return m_engine->icon(); +} + +QObject * DataEngineWrapper::query(const QString &str) const +{ + DataEngine::Data data = m_engine->query(str); + return new DataEngineDataWrapper(data); +} + +DataEngineWrapper::~DataEngineWrapper() +{ +} + +void DataEngineWrapper::connectSource(const QString& source, + uint pollingInterval, uint intervalAlignment) +{ + if (m_applet) { + m_engine->connectSource(source, m_applet, pollingInterval, + (Plasma::IntervalAlignment)intervalAlignment); + } +} + +#include "plasmajs.moc" diff --git a/plasma/generic/scriptengines/webkit/plasmajs.h b/plasma/generic/scriptengines/webkit/plasmajs.h new file mode 100644 index 00000000..af5b4319 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/plasmajs.h @@ -0,0 +1,93 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#ifndef PLASMAJS_H +#define PLASMAJS_H + +#include +#include +#include + +class PlasmaWebApplet; + +class DataEngineDataWrapper : public QObject +{ + Q_OBJECT + Q_PROPERTY(int length READ length) +public: + DataEngineDataWrapper(const Plasma::DataEngine::Data &data = Plasma::DataEngine::Data()); + + int length() const; + void setData(const Plasma::DataEngine::Data &data); + +public Q_SLOTS: + bool contains(const QString &key) const; + QVariant value(const QString &key) const; + QStringList keys() const; + QString key(int i) const; + +private: + Plasma::DataEngine::Data m_data; +}; + +class DataEngineWrapper : public QObject +{ + Q_OBJECT + Q_PROPERTY(QStringList sources READ sources) + Q_PROPERTY(bool valid READ isValid) + Q_PROPERTY(QString icon READ icon) + Q_PROPERTY(QString engineName READ engineName) +public: + DataEngineWrapper(Plasma::DataEngine *engine, QObject *applet = 0); + ~DataEngineWrapper(); + + QStringList sources() const; + QString engineName() const; + bool isValid() const; + QString icon() const; + +public Q_SLOTS: + QObject *query(const QString &str) const; + void connectSource(const QString& source, + uint pollingInterval = 0, uint intervalAlignment = 0); + +private: + Plasma::DataEngine *m_engine; + QObject *m_applet; +}; + +class ConfigGroupWrapper : public QObject +{ + Q_OBJECT +public: + ConfigGroupWrapper(const KConfigGroup &config = KConfigGroup()); + + void setConfig(const KConfigGroup &config); + +public Q_SLOTS: + QVariant readEntry(const QString &key, const QVariant &aDefault) const; + void writeEntry(const QString &key, const QVariant& value); + +private: + KConfigGroup m_config; +}; + +#endif diff --git a/plasma/generic/scriptengines/webkit/plasmawebapplet.cpp b/plasma/generic/scriptengines/webkit/plasmawebapplet.cpp new file mode 100644 index 00000000..c5bf20cb --- /dev/null +++ b/plasma/generic/scriptengines/webkit/plasmawebapplet.cpp @@ -0,0 +1,483 @@ +/* +Copyright (c) 2007 Zack Rusin +Copyright (c) 2008 Petri Damstén + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "plasmawebapplet.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#define JS_CONSTANTS_CONSTRAINT \ +"var NoConstraint = %1;\n"\ +"var FormFactorConstraint = %2;\n"\ +"var LocationConstraint = %3;\n"\ +"var ScreenConstraint = %4;\n"\ +"var SizeConstraint = %5;\n"\ +"var ImmutableConstraint = %6;\n"\ +"var StartupCompletedConstraint = %7;\n"\ +"var ContextConstraint = %8;\n"\ +"var AllConstraints = %9;\n" + +#define JS_CONSTANTS_BACKGROUND \ +"var NoBackground = %1;\n"\ +"var StandardBackground = %2;\n"\ +"var TranslucentBackground = %3;\n"\ +"var DefaultBackground = %5;\n" + +#define JS_CONSTANTS_SCROLLBAR \ +"var QtHorizontal = %1;\n"\ +"var QtVertical = %2;\n"\ +"var ScrollBarAsNeeded = %3;\n"\ +"var ScrollBarAlwaysOff = %4;\n"\ +"var ScrollBarAlwaysOn = %5;\n"\ + +#define JS_CONSTANTS_ASPECTRATIO \ +"var InvalidAspectRatioMode = %1;\n"\ +"var IgnoreAspectRatio = %2;\n"\ +"var KeepAspectRatio = %3;\n"\ +"var Square = %4;\n"\ +"var ConstrainedSquare = %5;\n"\ +"var FixedSize = %6;\n" + +#define JS_CONSTANTS_FORMFACTOR \ +"var Planar = %1;\n"\ +"var MediaCenter = %2;\n"\ +"var Horizontal = %3;\n"\ +"var Vertical = %4;\n"\ + +#define JS_CONSTANTS_LOCATION \ +"var Floating = %1;\n"\ +"var Desktop = %2;\n"\ +"var FullScreen = %3;\n"\ +"var TopEdge = %4;\n"\ +"var BottomEdge = %5;\n"\ +"var LeftEdge = %6;\n"\ +"var RightEdge = %7;\n" + +#define JS_CONSTANTS_OTHER \ +"var size_width = 0;\n"\ +"var size_height = 1;\n"\ +"var point_x = 0;\n"\ +"var point_y = 1;\n"\ +"var rect_x = 0;\n"\ +"var rect_y = 1;\n"\ +"var rect_width = 2;\n"\ +"var rect_height = 3;\n"\ +"var margin_left = 0;\n"\ +"var margin_top = 1;\n"\ +"var margin_right = 2;\n"\ +"var margin_bottom = 3;\n"\ + +#define CSS "body { font-family: %3; font-size: %4pt; color:%1; background-color:%2 }\n" + +QString PlasmaWebApplet::s_jsConstants; + +PlasmaWebApplet::PlasmaWebApplet(QObject *parent, const QVariantList &args) +: WebApplet(parent, args) +{ + if (s_jsConstants.isEmpty()) { + s_jsConstants = JS_CONSTANTS_OTHER; + s_jsConstants += QString(JS_CONSTANTS_CONSTRAINT) + .arg(Plasma::NoConstraint) + .arg(Plasma::FormFactorConstraint) + .arg(Plasma::LocationConstraint) + .arg(Plasma::ScreenConstraint) + .arg(Plasma::SizeConstraint) + .arg(Plasma::ImmutableConstraint) + .arg(Plasma::StartupCompletedConstraint) + .arg(Plasma::ContextConstraint) + .arg(Plasma::AllConstraints); + s_jsConstants += QString(JS_CONSTANTS_BACKGROUND) + .arg(Plasma::Applet::NoBackground) + .arg(Plasma::Applet::StandardBackground) + .arg(Plasma::Applet::TranslucentBackground) + .arg(Plasma::Applet::DefaultBackground); + s_jsConstants += QString(JS_CONSTANTS_SCROLLBAR) + .arg(Qt::Horizontal) + .arg(Qt::Vertical) + .arg(Qt::ScrollBarAsNeeded) + .arg(Qt::ScrollBarAlwaysOff) + .arg(Qt::ScrollBarAlwaysOn); + s_jsConstants += QString(JS_CONSTANTS_ASPECTRATIO) + .arg(Plasma::InvalidAspectRatioMode) + .arg(Plasma::IgnoreAspectRatio) + .arg(Plasma::KeepAspectRatio) + .arg(Plasma::Square) + .arg(Plasma::ConstrainedSquare) + .arg(Plasma::FixedSize); + s_jsConstants += QString(JS_CONSTANTS_FORMFACTOR) + .arg(Plasma::Planar) + .arg(Plasma::MediaCenter) + .arg(Plasma::Horizontal) + .arg(Plasma::Vertical); + s_jsConstants += QString(JS_CONSTANTS_LOCATION) + .arg(Plasma::Floating) + .arg(Plasma::Desktop) + .arg(Plasma::FullScreen) + .arg(Plasma::TopEdge) + .arg(Plasma::BottomEdge) + .arg(Plasma::LeftEdge) + .arg(Plasma::RightEdge); + } +} + +PlasmaWebApplet::~PlasmaWebApplet() +{ +} + +bool PlasmaWebApplet::init() +{ + if (WebApplet::init()) { + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), + this, SLOT(themeChanged())); + makeStylesheet(); + page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); + QAction *inspectAction = page()->action(QWebPage::InspectElement); + inspectAction->setText(i18n("Inspect this widget")); + return true; + } + + return false; +} + +void PlasmaWebApplet::makeStylesheet() +{ + if (!page()) { + return; + } + + // this temporary file contains the style sheet to be used when loading/reloading the + // web content. we keep it around for the lifetime of the widget since it needs to be there + // when reloaded + + //TODO perhaps share this file between all instances? perhaps even keep it persistent on disk + // to limit disk write/deletes. that would be simple enough, the only trick would be to + // ensure it updates (and only updates once) on Plasma theme changes so that it doesn't get + // written to in a flury by every PlasmaWebApplet when the theme updates + // probably a reference counted singleton would be the way to go here. + if (!m_styleSheetFile.open()) { + return; + } + + KColorScheme plasmaColorTheme = KColorScheme(QPalette::Active, KColorScheme::View, + Plasma::Theme::defaultTheme()->colorScheme()); + QColor textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); + QColor backgroundColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor); + QFont font = Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont); + + QString css = QString(CSS).arg(textColor.name()) + .arg(backgroundColor.name()) + .arg(font.family()) + .arg(font.pointSize()); + m_styleSheetFile.write(css.toUtf8()); + page()->settings()->setUserStyleSheetUrl(QUrl(m_styleSheetFile.fileName())); + m_styleSheetFile.close(); +} + +void PlasmaWebApplet::themeChanged() +{ + makeStylesheet(); + callJsFunction("themeChanged"); +} + +void PlasmaWebApplet::loadFinished(bool success) +{ + WebApplet::loadFinished(success); + if (success) { + page()->mainFrame()->evaluateJavaScript(s_jsConstants); + callJsFunction("init"); + } +} + +void PlasmaWebApplet::constraintsEvent(Plasma::Constraints constraints) +{ + if (page() && constraints & Plasma::SizeConstraint) { + qreal left; + qreal top; + qreal right; + qreal bottom; + applet()->getContentsMargins(&left, &top, &right, &bottom); + view()->setPos(QPointF(left, top)); + view()->resize(WebApplet::size() - QSizeF(left + right, top + bottom)); + //kDebug() << WebApplet::size() << left << right << top << bottom << page()->size(); + } + callJsFunction("constraintsEvent", QVariantList() << (int)constraints); +} + +QVariant PlasmaWebApplet::arg(int index) const +{ + return m_args[index]; +} + +QObject* PlasmaWebApplet::objArg(int index) const +{ + return m_args[index].value(); +} + +QString PlasmaWebApplet::name() const +{ + return applet()->name(); +} + +uint PlasmaWebApplet::id() const +{ + return applet()->id(); +} + +int PlasmaWebApplet::formFactor() const +{ + return (int)applet()->formFactor(); +} + +int PlasmaWebApplet::location() const +{ + return (int)applet()->location(); +} + +QString PlasmaWebApplet::pluginName() const +{ + return applet()->pluginName(); +} + +QString PlasmaWebApplet::icon() const +{ + return applet()->icon(); +} + +QString PlasmaWebApplet::category() const +{ + return applet()->category(); +} + +bool PlasmaWebApplet::shouldConserveResources() const +{ + return applet()->shouldConserveResources(); +} + +QStringList PlasmaWebApplet::listAllDataEngines() +{ + return Plasma::DataEngineManager::listAllEngines(); +} + +QObject* PlasmaWebApplet::dataEngine(const QString& name) +{ + QString id = QString("%1").arg(applet()->id()); + Plasma::DataEngine *de = applet()->dataEngine(name); + DataEngineWrapper *wrapper = de->findChild(id); + if (!wrapper) { + wrapper = new DataEngineWrapper(de, this); + wrapper->setObjectName(id); + } + return wrapper; +} + +QObject* PlasmaWebApplet::config() +{ + m_config.setConfig(applet()->config()); + return &m_config; +} + +QObject* PlasmaWebApplet::globalConfig() +{ + m_globalConfig.setConfig(applet()->globalConfig()); + return &m_globalConfig; +} + +void PlasmaWebApplet::resize(qreal w, qreal h) +{ + applet()->resize(w, h); +} + +void PlasmaWebApplet::setBackgroundHints(int hints) +{ + applet()->setBackgroundHints((Plasma::Applet::BackgroundHints)hints); +} + +void PlasmaWebApplet::setScrollBarPolicy(int orientation, int policy) +{ + page()->mainFrame()->setScrollBarPolicy((Qt::Orientation)orientation, + (Qt::ScrollBarPolicy)policy); +} + +void PlasmaWebApplet::setAspectRatioMode(int mode) +{ + applet()->setAspectRatioMode((Plasma::AspectRatioMode)mode); +} + +QVariant PlasmaWebApplet::callJsFunction(const QString& func, const QVariantList& args) +{ + if (loaded()) { + m_args = args; + QString cmd = "if (window." + func + ") { " + func + '('; + for(int i = 0; i < args.count(); ++i) { + if (i > 0) { + cmd += ','; + } + if (args[i].canConvert()) { + cmd += QString("window.plasmoid.objArg(%1)").arg(i); + } else { + cmd += QString("window.plasmoid.arg(%1)").arg(i); + } + } + cmd += ") }"; + //kDebug() << cmd; + return page()->mainFrame()->evaluateJavaScript(cmd); + } + return QVariant(); +} + +void PlasmaWebApplet::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data) +{ + m_dataEngineData.setData(data); + callJsFunction("dataUpdated", + QVariantList() << source << QVariant::fromValue((QObject*)&m_dataEngineData)); +} + +void PlasmaWebApplet::configChanged() +{ + callJsFunction("configChanged"); +} + +void PlasmaWebApplet::initJsObjects() +{ + QWebFrame *frame = qobject_cast(sender()); + Q_ASSERT(frame); + frame->addToJavaScriptWindowObject(QLatin1String("plasmoid"), this); +} + +QVariantList PlasmaWebApplet::geometry() +{ + return QVariantList() << applet()->geometry().left() << applet()->geometry().top() + << applet()->geometry().width() << applet()->geometry().height(); +} + +QVariantList PlasmaWebApplet::screenRect() +{ + return QVariantList() << applet()->screenRect().left() << applet()->screenRect().top() + << applet()->screenRect().width() << applet()->screenRect().height(); +} + +int PlasmaWebApplet::backgroundHints() +{ + return applet()->backgroundHints(); +} + +int PlasmaWebApplet::aspectRatioMode() +{ + return applet()->aspectRatioMode(); +} + +void PlasmaWebApplet::setConfigurationRequired(bool needsConfiguring, const QString &reason) +{ + WebApplet::setConfigurationRequired(needsConfiguring, reason); +} + +void PlasmaWebApplet::setMaximumSize(qreal w, qreal h) +{ + applet()->setMaximumSize(w, h); +} + +void PlasmaWebApplet::setMinimumSize(qreal w, qreal h) +{ + applet()->setMinimumSize(w, h); +} + +void PlasmaWebApplet::setPreferredSize(qreal w, qreal h) +{ + applet()->setPreferredSize(w, h); +} + +QVariantList PlasmaWebApplet::maximumSize() +{ + return QVariantList() << applet()->maximumSize().width() << applet()->maximumSize().height(); +} + +QVariantList PlasmaWebApplet::minimumSize() +{ + return QVariantList() << applet()->minimumSize().width() << applet()->minimumSize().height(); +} + +QVariantList PlasmaWebApplet::preferredSize() +{ + return QVariantList() << applet()->preferredSize().width() + << applet()->preferredSize().height(); +} + +QVariantList PlasmaWebApplet::getContentsMargins() +{ + qreal left; + qreal top; + qreal right; + qreal bottom; + applet()->getContentsMargins(&left, &top, &right, &bottom); + return QVariantList() << left << top << right << bottom; +} + +void PlasmaWebApplet::setGeometry(qreal x, qreal y, qreal w, qreal h) +{ + applet()->setGeometry(x, y, w, h); +} + +void PlasmaWebApplet::setPos(qreal x, qreal y) +{ + applet()->setPos(x, y); +} + +QVariantList PlasmaWebApplet::pos() +{ + return QVariantList() << applet()->pos().x() << applet()->pos().y(); +} + +QVariantList PlasmaWebApplet::size() +{ + return QVariantList() << applet()->size().width() << applet()->size().height(); +} + +void PlasmaWebApplet::setFailedToLaunch(bool failed, const QString &reason) +{ + WebApplet::setFailedToLaunch(failed, reason); +} + +void PlasmaWebApplet::update() +{ + applet()->update(); +} + +bool PlasmaWebApplet::isBusy() const +{ + return applet()->isBusy(); +} + +void PlasmaWebApplet::setBusy(bool busy) +{ + applet()->setBusy(busy); +} + +#include "plasmawebapplet.moc" diff --git a/plasma/generic/scriptengines/webkit/plasmawebapplet.h b/plasma/generic/scriptengines/webkit/plasmawebapplet.h new file mode 100644 index 00000000..90b7a326 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/plasmawebapplet.h @@ -0,0 +1,112 @@ +/* +Copyright (c) 2007 Zack Rusin +Copyright (c) 2008 Petri Damstén + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef PLASMAWEBAPPLET_H +#define PLASMAWEBAPPLET_H + +#include "webapplet.h" +#include "plasmajs.h" + +#include + +class PlasmaWebApplet : public WebApplet +{ + Q_OBJECT + Q_PROPERTY(QString name READ name) + Q_PROPERTY(uint id READ id) + Q_PROPERTY(QString pluginName READ pluginName) + Q_PROPERTY(QString icon READ icon) + Q_PROPERTY(QString category READ category) + Q_PROPERTY(int formFactor READ formFactor) + Q_PROPERTY(int location READ location) + +public: + PlasmaWebApplet(QObject *parent, const QVariantList &args); + virtual ~PlasmaWebApplet(); + + virtual bool init(); + + QString name() const; + uint id() const; + QString pluginName() const; + QString icon() const; + QString category() const; + bool shouldConserveResources() const; + int formFactor() const; + int location() const; + +public slots: + QStringList listAllDataEngines(); + QObject* dataEngine(const QString& name); + QObject* config(); + QObject* globalConfig(); + void setScrollBarPolicy(int orientation, int policy); + QVariantList screenRect(); + void setConfigurationRequired(bool needsConfiguring, const QString &reason = QString()); + QVariantList getContentsMargins(); + void resize(qreal w, qreal h); + QVariantList size(); + void setBackgroundHints(int hints); + int backgroundHints(); + void setAspectRatioMode(int mode); + int aspectRatioMode(); + void setMaximumSize(qreal w, qreal h); + QVariantList maximumSize(); + void setMinimumSize(qreal w, qreal h); + QVariantList minimumSize(); + void setPreferredSize(qreal w, qreal h); + QVariantList preferredSize(); + void setGeometry(qreal x, qreal y, qreal w, qreal h); + QVariantList geometry(); + void setPos(qreal x, qreal y); + QVariantList pos(); + void setFailedToLaunch(bool failed, const QString &reason = QString()); + void update(); + bool isBusy() const; + void setBusy(bool busy); + + QVariant arg(int index) const; + QObject* objArg(int index) const; + void dataUpdated(const QString& source, const Plasma::DataEngine::Data &data); + void configChanged(); + void themeChanged(); + void makeStylesheet(); + +protected: + QVariant callJsFunction(const QString &func, const QVariantList &args = QVariantList()); + void constraintsEvent(Plasma::Constraints constraints); + +protected slots: + virtual void loadFinished(bool success); + virtual void initJsObjects(); + +private: + QVariantList m_args; + DataEngineDataWrapper m_dataEngineData; + ConfigGroupWrapper m_config; + ConfigGroupWrapper m_globalConfig; + KTemporaryFile m_styleSheetFile; + static QString s_jsConstants; +}; + +#endif diff --git a/plasma/generic/scriptengines/webkit/tests/AppletAnimatorTest.html b/plasma/generic/scriptengines/webkit/tests/AppletAnimatorTest.html new file mode 100644 index 00000000..d450c8da --- /dev/null +++ b/plasma/generic/scriptengines/webkit/tests/AppletAnimatorTest.html @@ -0,0 +1,39 @@ + + + + + + +
+ + diff --git a/plasma/generic/scriptengines/webkit/tests/HelloWorld.zip b/plasma/generic/scriptengines/webkit/tests/HelloWorld.zip new file mode 100644 index 00000000..bdada5d3 Binary files /dev/null and b/plasma/generic/scriptengines/webkit/tests/HelloWorld.zip differ diff --git a/plasma/generic/scriptengines/webkit/webapplet.cpp b/plasma/generic/scriptengines/webkit/webapplet.cpp new file mode 100644 index 00000000..0a35e4ae --- /dev/null +++ b/plasma/generic/scriptengines/webkit/webapplet.cpp @@ -0,0 +1,154 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#include "webapplet.h" + +#include "webpage.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace Plasma; + +class WebApplet::Private +{ +public: + Private() + : view(0) + { + } + + void init(WebApplet *q) + { + loaded = false; + + Plasma::Applet *applet = q->applet(); + applet->setAcceptsHoverEvents(true); + + view = new Plasma::WebView(applet); + QObject::connect(view, SIGNAL(loadFinished(bool)), + q, SLOT(loadFinished(bool))); + QObject::connect(view->page(), SIGNAL(frameCreated(QWebFrame*)), + q, SLOT(connectFrame(QWebFrame*))); + q->connectFrame(view->mainFrame()); + + view->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); + view->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); + + QPalette palette = view->palette(); + palette.setColor(QPalette::Base, Qt::transparent); + view->page()->setPalette(palette); + } + + Plasma::WebView *view; + bool loaded; +}; + +WebApplet::WebApplet(QObject *parent, const QVariantList &args) + : AppletScript(parent), + d(new Private) +{ + Q_UNUSED(args) +} + +WebApplet::~WebApplet() +{ + delete d; +} + +bool WebApplet::init() +{ + d->init(this); + + QString webpage; + webpage = package()->filePath("mainscript"); + + if (webpage.isEmpty()) { + kDebug() << "fail! no page"; + delete d->view; + d->view = 0; + return false; + } + + KUrl url(package()->filePath("html")); + kDebug() << webpage << package()->path() << url; + d->view->mainFrame()->setHtml(dataFor(webpage), url); + return true; +} + +void WebApplet::paintInterface(QPainter *painter, + const QStyleOptionGraphicsItem *option, + const QRect &contentsRect) +{ + Q_UNUSED(painter) + Q_UNUSED(option) + Q_UNUSED(contentsRect) +} + +Plasma::WebView* WebApplet::view() const +{ + return d->view; +} + +void WebApplet::loadFinished(bool success) +{ + d->loaded = success; +} + +void WebApplet::connectFrame(QWebFrame *frame) +{ + connect(frame, SIGNAL(javaScriptWindowObjectCleared()), + this, SLOT(initJsObjects())); +} + +void WebApplet::initJsObjects() +{ +} + +QByteArray WebApplet::dataFor(const QString &str) +{ + QFile f(str); + f.open(QIODevice::ReadOnly); + QByteArray data = f.readAll(); + f.close(); + return data; +} + +QWebPage *WebApplet::page() +{ + return d->view ? d->view->page() : 0; +} + +bool WebApplet::loaded() +{ + return d->loaded; +} + +#include "webapplet.moc" diff --git a/plasma/generic/scriptengines/webkit/webapplet.h b/plasma/generic/scriptengines/webkit/webapplet.h new file mode 100644 index 00000000..d08620fc --- /dev/null +++ b/plasma/generic/scriptengines/webkit/webapplet.h @@ -0,0 +1,66 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#ifndef WEBAPPLET_H +#define WEBAPPLET_H + +#include + +#include +#include + +class QWebFrame; +class QWebPage; + +namespace Plasma +{ + class WebView; +} // namespace Plasma + +class WebApplet : public Plasma::AppletScript +{ + Q_OBJECT +public: + WebApplet(QObject *parent, const QVariantList &args); + ~WebApplet(); + + bool init(); + +protected: + Plasma::WebView *view() const; + void paintInterface(QPainter *painter, + const QStyleOptionGraphicsItem *option, + const QRect &contentsRect); + virtual QByteArray dataFor(const QString &str); + QWebPage *page(); + bool loaded(); + +protected slots: + void connectFrame(QWebFrame *); + virtual void loadFinished(bool); + virtual void initJsObjects(); + +private: + class Private; + Private *const d; +}; + +#endif diff --git a/plasma/generic/scriptengines/webkit/webapplet_package.cpp b/plasma/generic/scriptengines/webkit/webapplet_package.cpp new file mode 100644 index 00000000..11b4b5f0 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/webapplet_package.cpp @@ -0,0 +1,50 @@ +/* +Copyright (c) 2008 Petri Damstén + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "webapplet_package.h" + +#include + +WebAppletPackage::WebAppletPackage(QObject *parent, QVariantList args) +: Plasma::PackageStructure(parent, "Web") +{ + Q_UNUSED(args) + // copy the main applet structure + Plasma::PackageStructure::operator=(*Plasma::Applet::packageStructure()); + addFileDefinition("mainscript", "code/main.html", i18n("Main Script File")); + setRequired("mainscript", true); + + // For Webapplet::init() + addDirectoryDefinition("html", "code/", i18n("Root HTML directory")); +} + +void WebAppletPackage::pathChanged() +{ + KDesktopFile config(path() + "/metadata.desktop"); + KConfigGroup cg = config.desktopGroup(); + QString mainScript = cg.readEntry("X-Plasma-MainScript", QString()); + if (!mainScript.isEmpty()) { + addFileDefinition("mainscript", mainScript, i18n("Main Script File")); + setRequired("mainscript", true); + } +} + diff --git a/plasma/generic/scriptengines/webkit/webapplet_package.h b/plasma/generic/scriptengines/webkit/webapplet_package.h new file mode 100644 index 00000000..671e1c5d --- /dev/null +++ b/plasma/generic/scriptengines/webkit/webapplet_package.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 2008 Petri Damstén + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef WEBAPPLET_PACKAGE_H +#define WEBAPPLET_PACKAGE_H + +#include + +#include + +class WebAppletPackage : public Plasma::PackageStructure +{ +public: + WebAppletPackage(QObject *parent, QVariantList args); + +protected: + void pathChanged(); +}; + +K_EXPORT_PLASMA_PACKAGESTRUCTURE(webkit, WebAppletPackage) + +#endif diff --git a/plasma/generic/scriptengines/webkit/webapplet_plugin.cpp b/plasma/generic/scriptengines/webkit/webapplet_plugin.cpp new file mode 100644 index 00000000..8e720e58 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/webapplet_plugin.cpp @@ -0,0 +1,25 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#include "plasmawebapplet.h" + +K_EXPORT_PLASMA_APPLETSCRIPTENGINE(webkit, PlasmaWebApplet) + diff --git a/plasma/generic/scriptengines/webkit/webpage.cpp b/plasma/generic/scriptengines/webkit/webpage.cpp new file mode 100644 index 00000000..ea547118 --- /dev/null +++ b/plasma/generic/scriptengines/webkit/webpage.cpp @@ -0,0 +1,75 @@ +/* +Copyright (c) 2007 Zack Rusin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#include "webpage.h" + +#include +#include + +namespace Plasma +{ + +WebPage::WebPage(QObject *parent) + : QWebPage(parent) +{ + settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, false); + settings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, true); + settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain, true); +} + +QWebPage * WebPage::createWindow(QWebPage::WebWindowType) +{ + Q_ASSERT(0); + return 0; +} + +void WebPage::javaScriptAlert(QWebFrame *frame, const QString& message) +{ + Q_UNUSED(frame) + qDebug()<< "JS ALERT: "<< message; +} + +void WebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, + const QString& sourceID) +{ + Q_UNUSED(sourceID) + qDebug()<< "JS CONSOLE MESSAGE: line "<< lineNumber<<": " << message; +} + +bool WebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg) +{ + Q_UNUSED(frame) + qDebug()<< "JS CONFIRM: "<< msg; + return true; +} + +bool WebPage::javaScriptPrompt(QWebFrame *frame, const QString& msg, + const QString& defaultValue, QString* result) +{ + Q_UNUSED(frame) + qDebug()<<"JS PROMPT: "<< msg <<", default text: "< + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +#ifndef WEBPAGE_H +#define WEBPAGE_H + +#include +#include + +namespace Plasma +{ + +class WebPage : public QWebPage +{ + Q_OBJECT +public: + WebPage(QObject *parent=0); + + QWebPage *createWindow(QWebPage::WebWindowType); + + void javaScriptAlert(QWebFrame *frame, const QString& message); + void javaScriptConsoleMessage(const QString& message, int lineNumber, + const QString& sourceID); + bool javaScriptConfirm(QWebFrame *frame, const QString& msg); + bool javaScriptPrompt(QWebFrame *frame, const QString& msg, + const QString& defaultValue, QString* result); +}; + +} // namespace Plasma + +#endif diff --git a/plasma/generic/shells/CMakeLists.txt b/plasma/generic/shells/CMakeLists.txt new file mode 100644 index 00000000..cbec9580 --- /dev/null +++ b/plasma/generic/shells/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(plasma-windowed) diff --git a/plasma/generic/shells/plasma-windowed/CMakeLists.txt b/plasma/generic/shells/plasma-windowed/CMakeLists.txt new file mode 100644 index 00000000..86b7770b --- /dev/null +++ b/plasma/generic/shells/plasma-windowed/CMakeLists.txt @@ -0,0 +1,19 @@ +include_directories(${KDEBASE_WORKSPACE_SOURCE_DIR}/libs ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kworkspace) + + +set(plasma-windowed_SRCS + singleview.cpp + main.cpp + plasmaapp.cpp + ${appletbrowserdialog_SRCS} +) + + +kde4_add_kdeinit_executable(plasma-windowed ${plasma-windowed_SRCS}) + +target_link_libraries(kdeinit_plasma-windowed ${KDE4_PLASMA_LIBS} kworkspace ${KDE4_KIO_LIBS} ${X11_LIBRARIES} ${KDE4_KFILE_LIBS} ) + + +install(TARGETS kdeinit_plasma-windowed DESTINATION ${LIB_INSTALL_DIR}) +install(TARGETS plasma-windowed ${INSTALL_TARGETS_DEFAULT_ARGS}) + diff --git a/plasma/generic/shells/plasma-windowed/Messages.sh b/plasma/generic/shells/plasma-windowed/Messages.sh new file mode 100755 index 00000000..61de9a35 --- /dev/null +++ b/plasma/generic/shells/plasma-windowed/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma-windowed.pot diff --git a/plasma/generic/shells/plasma-windowed/main.cpp b/plasma/generic/shells/plasma-windowed/main.cpp new file mode 100644 index 00000000..7cdf2e3c --- /dev/null +++ b/plasma/generic/shells/plasma-windowed/main.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2006-2008 Aaron Seigo + * Copyright 2009 Marco Martin + * + * 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, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include "plasmaapp.h" + +static const char description[] = I18N_NOOP( "Shell used to load Plasma widgets as stand-alone applications." ); +static const char version[] = "0.1"; + +extern "C" +KDE_EXPORT int kdemain(int argc, char **argv) +{ + KAboutData aboutData("plasma-windowed", 0, ki18n("Plasma Widgets shell"), + version, ki18n(description), KAboutData::License_GPL, + ki18n("Copyright 2006-2009, The KDE Team")); + aboutData.addAuthor(ki18n("Marco Martin"), + ki18n("Author and maintainer"), + "notmart@gmail.com"); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("b", ki18n("Show window decorations around the widget")); + options.add("noborder", ki18n("Do not show window decorations around the widget")); + options.add("f"); + options.add("fullscreen", ki18n("Display the widget fullscreen")); + options.add("+applet", ki18n("Name of applet to view; may refer to the plugin name or be a path " + "(absolute or relative) to a package. If not provided, then an " + "attempt is made to load a package from the current directory.")); + options.add("+[args]", ki18n("Optional arguments for the applet to add")); + KCmdLineArgs::addCmdLineOptions(options); + + PlasmaApp *app = PlasmaApp::self(); + QApplication::setWindowIcon(KIcon("plasma")); + int rc = app->exec(); + delete app; + return rc; +} + diff --git a/plasma/generic/shells/plasma-windowed/plasmaapp.cpp b/plasma/generic/shells/plasma-windowed/plasmaapp.cpp new file mode 100644 index 00000000..dbdff472 --- /dev/null +++ b/plasma/generic/shells/plasma-windowed/plasmaapp.cpp @@ -0,0 +1,255 @@ +/* + * Copyright 2006-2008 Aaron Seigo + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "plasmaapp.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "singleview.h" + + +PlasmaApp* PlasmaApp::self() +{ + if (!kapp) { + return new PlasmaApp(); + } + + return qobject_cast(kapp); +} + +PlasmaApp::PlasmaApp() + : KUniqueApplication(), + m_corona(0), + m_maxId(0) +{ + KGlobal::locale()->insertCatalog("plasma-standaloneplasmoids"); + KCrash::setFlags(KCrash::AutoRestart); + + KConfigGroup cg(KGlobal::config(), "General"); + Plasma::Theme::defaultTheme()->setFont(cg.readEntry("desktopFont", font())); + + corona(); + + KConfigGroup applets = storedConfig(0); + foreach (const QString &group, applets.groupList()) { + KConfigGroup appletGroup(&applets, group); + + int id = appletGroup.name().toInt(); + QString pluginName = appletGroup.readEntry("plugin", QString()); + if (id != 0 && !pluginName.isEmpty()) { + m_storedApplets.insert(pluginName, id); + m_maxId = qMax(id, m_maxId); + } + } + + //newInstance(); + connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanup())); + setQuitOnLastWindowClosed(true); +} + +PlasmaApp::~PlasmaApp() +{ +} + +KConfigGroup PlasmaApp::storedConfig(int appletId) +{ + KConfigGroup cg(m_corona->config(), "StoredApplets"); + + if (appletId > 0) { + cg = KConfigGroup(&cg, QString::number(appletId)); + } + + return cg; +} + +int PlasmaApp::newInstance() +{ + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + if (args->count() == 0) { + KCmdLineArgs::usage(); + return 0; + } + + QString pluginName; + if (args->count() > 0) { + pluginName = args->arg(0); + } + + //is the applet already running? + if (m_viewForPlugin.contains(pluginName)) { + m_viewForPlugin.value(pluginName)->activateWindow(); + m_viewForPlugin.value(pluginName)->raise(); + return 0; + } + + QVariantList appletArgs; + for (int i = 1; i < args->count(); ++i) { + appletArgs << args->arg(i); + } + + int appletId; + Plasma::Containment *containment = m_corona->addContainment("null"); + containment->setFormFactor(Plasma::Application); + containment->setLocation(Plasma::Floating); + appletId = ++m_maxId; + + if (m_storedApplets.contains(pluginName)) { + int storedAppletId = m_storedApplets.values(pluginName).first(); + KConfigGroup config = storedConfig(storedAppletId); + + KConfigGroup actualConfig(containment->config()); + actualConfig = KConfigGroup(&actualConfig, "Applets"); + actualConfig = KConfigGroup(&actualConfig, QString::number(appletId)); + + config.copyTo(&actualConfig); + config.deleteGroup(); + m_storedApplets.remove(pluginName, storedAppletId); + } + + SingleView *view = new SingleView(m_corona, containment, pluginName, appletId, appletArgs); + + if (!view->applet()) { + delete view; + return 0; + } + + connect(view, SIGNAL(storeApplet(Plasma::Applet*)), this, SLOT(storeApplet(Plasma::Applet*))); + connect(view, SIGNAL(destroyed(QObject*)), this, SLOT(viewDestroyed(QObject*))); + + if (args->isSet("border")) { + view->setBackgroundBrush(KColorUtils::mix(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor), Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor), 0.15)); + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(themeChanged())); + view->applet()->setBackgroundHints(Plasma::Applet::NoBackground); + } else { + view->setWindowFlags(Qt::FramelessWindowHint); + view->setAttribute(Qt::WA_TranslucentBackground); + view->setAutoFillBackground(false); + view->viewport()->setAutoFillBackground(false); + view->setAttribute(Qt::WA_NoSystemBackground); + view->viewport()->setAttribute(Qt::WA_NoSystemBackground); + Plasma::WindowEffects::overrideShadow(view->winId(), true); + } + + if (args->isSet("fullscreen")) { + view->setWindowState(Qt::WindowFullScreen); + } + + args->clear(); + + m_viewForPlugin[pluginName] = view; + m_pluginForView[view] = pluginName; + KWindowSystem::setOnDesktop(view->winId(), KWindowSystem::currentDesktop()); + view->show(); + view->raise(); + + return 0; +} + + +void PlasmaApp::cleanup() +{ + if (m_corona) { + m_corona->saveLayout(); + } + + qDeleteAll(m_viewForPlugin); + + delete m_corona; + m_corona = 0; + + //TODO: This manual sync() should not be necessary? + syncConfig(); +} + +void PlasmaApp::syncConfig() +{ + KGlobal::config()->sync(); +} + +void PlasmaApp::themeChanged() +{ + foreach (SingleView *view, m_viewForPlugin) { + if (view->autoFillBackground()) { + view->setBackgroundBrush(KColorUtils::mix(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor), Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor), 0.15)); + } + } +} + +Plasma::Corona* PlasmaApp::corona() +{ + if (!m_corona) { + m_corona = new Plasma::Corona(this); + connect(m_corona, SIGNAL(configSynced()), this, SLOT(syncConfig())); + + m_corona->setItemIndexMethod(QGraphicsScene::NoIndex); + //m_corona->initializeLayout(); + } + + return m_corona; +} + +bool PlasmaApp::hasComposite() +{ + return KWindowSystem::compositingActive(); +} + + +void PlasmaApp::storeApplet(Plasma::Applet *applet) +{ + m_storedApplets.insert(applet->name(), applet->id()); + KConfigGroup storage = storedConfig(0); + KConfigGroup cg(applet->containment()->config()); + cg = KConfigGroup(&cg, "Applets"); + cg = KConfigGroup(&cg, QString::number(applet->id())); + delete applet; +// kDebug() << "storing" << applet->name() << applet->id() << "to" << storage.name() << ", applet config is" << cg.name(); + cg.reparent(&storage); +} + +void PlasmaApp::viewDestroyed(QObject *view) +{ + SingleView *sView = static_cast(view); + + m_viewForPlugin.remove(m_pluginForView.value(sView)); + m_pluginForView.remove(sView); + if (m_viewForPlugin.isEmpty()) { + quit(); + } +} + +#include "plasmaapp.moc" diff --git a/plasma/generic/shells/plasma-windowed/plasmaapp.h b/plasma/generic/shells/plasma-windowed/plasmaapp.h new file mode 100644 index 00000000..057d303e --- /dev/null +++ b/plasma/generic/shells/plasma-windowed/plasmaapp.h @@ -0,0 +1,83 @@ +/* + * Copyright 2006-2008 Aaron Seigo + * Copyright 2009 Marco Martin + * + * 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, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLASMA_APP_H +#define PLASMA_APP_H + +#include +#include + +#include +#include + +#include + +#ifdef Q_WS_X11 +#include +#include +#endif + +namespace Plasma +{ + class Corona; + class View; + class Applet; +} // namespace Plasma + +class SingleView; + +class PlasmaApp : public KUniqueApplication +{ + Q_OBJECT +public: + ~PlasmaApp(); + + int newInstance(); + + static PlasmaApp* self(); + static bool hasComposite(); + + Plasma::Corona* corona(); + + +private: + PlasmaApp(); + +private Q_SLOTS: + void cleanup(); + void syncConfig(); + void themeChanged(); + void storeApplet(Plasma::Applet *view); + void viewDestroyed(QObject *view); + +private: + KConfigGroup storedConfig(int appletId); + + Plasma::Corona *m_corona; + QMultiHash m_storedApplets; + + int m_maxId; + + QHash m_viewForPlugin; + QHash m_pluginForView; +}; + +#endif // multiple inclusion guard + diff --git a/plasma/generic/shells/plasma-windowed/singleview.cpp b/plasma/generic/shells/plasma-windowed/singleview.cpp new file mode 100644 index 00000000..d56e6f44 --- /dev/null +++ b/plasma/generic/shells/plasma-windowed/singleview.cpp @@ -0,0 +1,165 @@ +/* + * Copyright 2007-2008 Aaron Seigo + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "singleview.h" + +#include +#include +#include + +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +SingleView::SingleView(Plasma::Corona *corona, Plasma::Containment *containment, const QString &pluginName, int appletId, const QVariantList &appletArgs, QWidget *parent) + : QGraphicsView(parent), + m_applet(0), + m_containment(containment), + m_corona(corona) +{ + setScene(m_corona); + QFileInfo info(pluginName); + if (!info.isAbsolute()) { + info = QFileInfo(QDir::currentPath() + '/' + pluginName); + } + + if (info.exists()) { + m_applet = Plasma::Applet::loadPlasmoid(info.absoluteFilePath(), appletId, appletArgs); + } + + if (!m_applet) { + m_applet = Plasma::Applet::load(pluginName, appletId, appletArgs); + } + + if (!m_applet) { + kDebug() << "failed to load" << pluginName; + return; + } + + m_containment->addApplet(m_applet, QPointF(-1, -1), false); + m_containment->resize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + + m_applet->setPos(0, 0); + m_applet->setFlag(QGraphicsItem::ItemIsMovable, false); + setSceneRect(m_applet->sceneBoundingRect()); + setWindowTitle(m_applet->name()); + setWindowIcon(SmallIcon(m_applet->icon())); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setFrameStyle(QFrame::NoFrame); + + QAction *action = m_applet->action("remove"); + delete action; + + QAction *quitAction = KStandardAction::quit(this, SLOT(close()), this); + m_applet->addAction(QString("remove"), quitAction); + addAction(quitAction); + // enforce the applet being our size + connect(m_applet, SIGNAL(geometryChanged()), this, SLOT(updateGeometry())); +} + +SingleView::~SingleView() +{ + m_containment->destroy(false); +} + + +void SingleView::setContainment(Plasma::Containment *c) +{ + if (m_containment) { + disconnect(m_containment, 0, this, 0); + } + + m_containment = c; + updateGeometry(); +} + + +void SingleView::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event) + updateGeometry(); + emit geometryChanged(); +} + +void SingleView::closeEvent(QCloseEvent *event) +{ + if (m_applet) { + KConfigGroup dummy; + m_containment->save(dummy); + emit storeApplet(m_applet); + m_applet = 0; + } + + QGraphicsView::closeEvent(event); + deleteLater(); +} + +Plasma::Applet *SingleView::applet() +{ + return m_applet; +} + +Plasma::Location SingleView::location() const +{ + return m_containment->location(); +} + +Plasma::FormFactor SingleView::formFactor() const +{ + return m_containment->formFactor(); +} + +void SingleView::updateGeometry() +{ + if (!m_containment) { + return; + } + + //kDebug() << "New applet geometry is" << m_applet->geometry(); + + if (m_applet) { + if (m_applet->size().toSize() != size()) { + m_applet->resize(size()); + } + + setSceneRect(m_applet->sceneBoundingRect()); + } + + if ((windowFlags() & Qt::FramelessWindowHint) && + applet()->backgroundHints() != Plasma::Applet::NoBackground) { + + // TODO: Use the background's mask for blur + QRegion mask; + mask += QRect(QPoint(), size()); + + Plasma::WindowEffects::enableBlurBehind(winId(), true, mask); + } +} + +#include "singleview.moc" + diff --git a/plasma/generic/shells/plasma-windowed/singleview.h b/plasma/generic/shells/plasma-windowed/singleview.h new file mode 100644 index 00000000..47d4d019 --- /dev/null +++ b/plasma/generic/shells/plasma-windowed/singleview.h @@ -0,0 +1,70 @@ +/* + * Copyright 2007-2008 Aaron Seigo + * Copyright 2009 Marco Martin + * + * 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, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SINGLEVIEW_H +#define SINGLEVIEW_H + +#include + +#include + +namespace Plasma +{ + class Containment; + class Applet; + class Corona; +} // namespace Plasma + +class SingleView; + +class SingleView : public QGraphicsView +{ + Q_OBJECT + +public: + SingleView(Plasma::Corona *corona, Plasma::Containment *containment, const QString &pluginName, int appletId, const QVariantList &appletArgs, QWidget *parent=0); + ~SingleView(); + + + Plasma::Applet *applet(); + Plasma::Location location() const; + Plasma::FormFactor formFactor() const; + +public Q_SLOTS: + void setContainment(Plasma::Containment *containment); + void updateGeometry(); + +Q_SIGNALS: + void locationChanged(const SingleView *view); + void geometryChanged(); + void containmentActivated(); + void storeApplet(Plasma::Applet *applet); + +protected: + void resizeEvent(QResizeEvent *event); + void closeEvent(QCloseEvent *event); + +private: + Plasma::Applet *m_applet; + Plasma::Containment *m_containment; + Plasma::Corona *m_corona; +}; + +#endif // multiple inclusion guard diff --git a/plasma/generic/wallpapers/CMakeLists.txt b/plasma/generic/wallpapers/CMakeLists.txt new file mode 100644 index 00000000..7a1777bb --- /dev/null +++ b/plasma/generic/wallpapers/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(color) +add_subdirectory(image) diff --git a/plasma/generic/wallpapers/color/CMakeLists.txt b/plasma/generic/wallpapers/color/CMakeLists.txt new file mode 100644 index 00000000..5ad829d8 --- /dev/null +++ b/plasma/generic/wallpapers/color/CMakeLists.txt @@ -0,0 +1,15 @@ +project(plasma-wallpaper-color) + +set(color_SRCS + color.cpp + backgrounddelegate.cpp + backgroundlistmodel.cpp + itemsview.cpp +) +kde4_add_ui_files(color_SRCS config.ui) + +kde4_add_plugin(plasma_wallpaper_color ${color_SRCS}) +target_link_libraries(plasma_wallpaper_color ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_wallpaper_color DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-wallpaper-color.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/generic/wallpapers/color/Messages.sh b/plasma/generic/wallpapers/color/Messages.sh new file mode 100755 index 00000000..ce80d610 --- /dev/null +++ b/plasma/generic/wallpapers/color/Messages.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma_wallpaper_color.pot +rm -f rc.cpp + diff --git a/plasma/generic/wallpapers/color/backgrounddelegate.cpp b/plasma/generic/wallpapers/color/backgrounddelegate.cpp new file mode 100644 index 00000000..3a9e2e0a --- /dev/null +++ b/plasma/generic/wallpapers/color/backgrounddelegate.cpp @@ -0,0 +1,131 @@ +/* + Copyright (c) 2007 Paolo Capriotti + Copyright (c) 2010 Dario Andres Rodriguez + Copyright 2012 Reza Fatahilah Shah + + 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. +*/ + +#include "backgrounddelegate.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static const int BLUR_PAD = 6; + +BackgroundDelegate::BackgroundDelegate(QObject *parent) + : QAbstractItemDelegate(parent) +{ + m_maxHeight = SCREENSHOT_SIZE/1.6 + BLUR_INCREMENT; + m_maxWidth = SCREENSHOT_SIZE + BLUR_INCREMENT; +} + +void BackgroundDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + const QString title = index.model()->data(index, Qt::DisplayRole).toString(); + const QPixmap pix = index.model()->data(index, ScreenshotRole).value(); + + // Highlight selected item + QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &option, painter); + + // Draw wallpaper thumbnail + if (pix.isNull()) { + painter->fillRect(option.rect, option.palette.brush(QPalette::Base)); + } else { + // blur calculation + QImage blur(pix.size() + QSize(BLUR_INCREMENT + BLUR_PAD, BLUR_INCREMENT + BLUR_PAD), QImage::Format_ARGB32); + QRect blurRect = QRect(QPoint((blur.width() - pix.width()) / 2, (blur.height() - pix.height()) / 2), pix.size()); + blur.fill(Qt::transparent); + QPainter p(&blur); + + QColor color = option.palette.color(QPalette::Base); + bool darkBaseColor = qGray(color.rgb()) < 192; + p.fillRect(blurRect, darkBaseColor ? Qt::white : Qt::black); + p.end(); + + // apply blur with a radius of 2 as thumbnail shadow + Plasma::PaintUtils::shadowBlur(blur, 2, darkBaseColor ? Qt::white : Qt::black); + + // calculate point + const int bx = (option.rect.width() - blur.width()) / 2; + const int by = MARGIN + qMax(0, m_maxHeight - blur.height()); + QRect shadowRect = QRect(option.rect.topLeft(), blur.size()).translated(bx, by); + // draw the blur + painter->drawImage(shadowRect.topLeft(), blur); + // draw the actual thumbnail + painter->drawPixmap(QRect(shadowRect.topLeft() + QPoint((shadowRect.width() - pix.width()) / 2, (shadowRect.height() - pix.height()) / 2), + pix.size()), pix); + } + + //Use a QTextDocument to layout the text + QTextDocument document; + QString html = QString("%1").arg(title); + + //Set the text color according to the item state + QPalette::ColorGroup cg = QPalette::Active; + if (!(option.state & QStyle::State_Enabled)) { + cg = QPalette::Disabled; + } else if (!(option.state & QStyle::State_Active)) { + cg = QPalette::Inactive; + } + + QColor color; + if (option.state & QStyle::State_Selected) { + color = QApplication::palette().brush(cg, QPalette::HighlightedText).color(); + } else { + color = QApplication::palette().brush(cg, QPalette::Text).color(); + } + + html = QString("
%2
").arg(color.name()).arg(html); + + document.setHtml(html); + + //Calculate positioning + int x = option.rect.left() + MARGIN; + + //Enable word-wrap + document.setTextWidth(m_maxWidth); + + //Center text on the row + int y = option.rect.top() + m_maxHeight + MARGIN * 2; //qMax(0 ,(int)((option.rect.height() - document.size().height()) / 2)); + + //Draw text + painter->save(); + painter->translate(x, y); + document.drawContents(painter, QRect(QPoint(0, 0), option.rect.size() - QSize(0, m_maxHeight + MARGIN * 2))); + painter->restore(); +} + +QSize BackgroundDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + Q_UNUSED(option) + const QString title = index.model()->data(index, Qt::DisplayRole).toString(); + const int fontSize = KGlobalSettings::smallestReadableFont().pointSize(); + + //Generate a sample complete entry (with the real title) to calculate sizes + QTextDocument document; + QString html = QString("%1
").arg(title); + html += QString("1600x1200").arg(fontSize); + + document.setHtml(html); + document.setTextWidth(m_maxWidth); + + QSize s(m_maxWidth + MARGIN * 2, + m_maxHeight + MARGIN * 3 + (int)(document.size().height())); + return s; +} + diff --git a/plasma/generic/wallpapers/color/backgrounddelegate.h b/plasma/generic/wallpapers/color/backgrounddelegate.h new file mode 100644 index 00000000..3c9cd2e7 --- /dev/null +++ b/plasma/generic/wallpapers/color/backgrounddelegate.h @@ -0,0 +1,41 @@ +/* + Copyright (c) 2007 Paolo Capriotti + Copyright 2012 Reza Fatahilah Shah + + 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. +*/ + +#ifndef BACKGROUNDDELEGATE_H +#define BACKGROUNDDELEGATE_H + +#include + +class BackgroundDelegate : public QAbstractItemDelegate +{ +public: + enum { + ScreenshotRole = Qt::UserRole + }; + + BackgroundDelegate(QObject *parent = 0); + + virtual void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + static const int SCREENSHOT_SIZE = 128; + static const int BLUR_INCREMENT = 9; + static const int MARGIN = 6; + + void resetMaxHeight() { m_maxHeight = 0; } + int m_maxHeight; +private: + int m_maxWidth; +}; + +#endif // BACKGROUNDDELEGATEL_H diff --git a/plasma/generic/wallpapers/color/backgroundlistmodel.cpp b/plasma/generic/wallpapers/color/backgroundlistmodel.cpp new file mode 100644 index 00000000..4819a161 --- /dev/null +++ b/plasma/generic/wallpapers/color/backgroundlistmodel.cpp @@ -0,0 +1,131 @@ +#ifndef BACKGROUNDLISTMODEL_CPP +#define BACKGROUNDLISTMODEL_CPP +/* + Copyright (c) 2007 Paolo Capriotti + Copyright 2012 Reza Fatahilah Shah + + 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. +*/ + +#include "backgroundlistmodel.h" + +#include + +#include "backgrounddelegate.h" +#include "color.h" + +BackgroundListModel::BackgroundListModel(Color *listener, QObject *parent) + : QAbstractListModel(parent), + m_structureParent(listener) +{ + m_previewUnavailablePix.fill(Qt::transparent); +} + +BackgroundListModel::~BackgroundListModel() +{ +} + +void BackgroundListModel::reload() +{ + for (int i = 0; i < m_backgroundModes.size(); i++) { + m_previews.insert(m_backgroundModes[i], createPixmap(m_backgroundModes[i])); + } +} + +void BackgroundListModel::addColor(int mode, const QString &title) +{ + m_titles.insert(mode, title); + m_backgroundModes.append(mode); + m_previews.insert(mode, createPixmap(mode)); +} + +QModelIndex BackgroundListModel::indexOf(const int &path) const +{ + for (int i = 0; i < m_backgroundModes.size(); i++) { + if (path == m_backgroundModes[i]) { + return index(i, 0); + } + } + return QModelIndex(); +} + +int BackgroundListModel::rowCount(const QModelIndex &) const +{ + return m_backgroundModes.size(); +} + +QVariant BackgroundListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() >= m_backgroundModes.size()) { + return QVariant(); + } + + int mode = backgroundMode(index.row()); + + switch (role) { + case Qt::DisplayRole: { + if (m_titles.contains(mode)) { + return m_titles.value(mode); + } + + return QVariant(); + } + break; + + case BackgroundDelegate::ScreenshotRole: { + if (m_previews.contains(mode)) { + return m_previews.value(mode); + } + + const_cast(this)->m_previews.insert(mode, m_previewUnavailablePix); + return m_previewUnavailablePix; + } + break; + + default: + return QVariant(); + break; + } + return QVariant(); +} + +int BackgroundListModel::backgroundMode(int index) const +{ + return m_backgroundModes.at(index); +} + +void BackgroundListModel::setWallpaperSize(const QSize& size) +{ + float newHeight = ((float)size.height() / (float)size.width()) * BackgroundDelegate::SCREENSHOT_SIZE; + + m_size = QSize(BackgroundDelegate::SCREENSHOT_SIZE, newHeight); + + m_size.scale(BackgroundDelegate::SCREENSHOT_SIZE, BackgroundDelegate::SCREENSHOT_SIZE/1.6, Qt::KeepAspectRatio); +} + +QPixmap BackgroundListModel::createPixmap(int mode) const +{ + if (m_structureParent.isNull()) { + return QPixmap(); + } + + QPixmap scaledPixmap(m_size); + QPainter p(&scaledPixmap); + + m_structureParent.data()->generatePainting(mode, &p, scaledPixmap.rect(), scaledPixmap.rect()); + + p.end(); + + return scaledPixmap; +} +#include "backgroundlistmodel.moc" + + +#endif // BACKGROUNDLISTMODEL_CPP diff --git a/plasma/generic/wallpapers/color/backgroundlistmodel.h b/plasma/generic/wallpapers/color/backgroundlistmodel.h new file mode 100644 index 00000000..491216e7 --- /dev/null +++ b/plasma/generic/wallpapers/color/backgroundlistmodel.h @@ -0,0 +1,53 @@ +/* + Copyright (c) 2007 Paolo Capriotti + Copyright 2012 Reza Fatahilah Shah + + 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. +*/ + +#ifndef BACKGROUNDLISTMODEL_H +#define BACKGROUNDLISTMODEL_H + +#include +#include + +#include + +class Color; + +class BackgroundListModel : public QAbstractListModel +{ + Q_OBJECT + +public: + BackgroundListModel(Color *listener, QObject *parent); + virtual ~BackgroundListModel(); + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + int backgroundMode(int index) const; + + void reload(); + QModelIndex indexOf(const int &path) const; + + void setWallpaperSize(const QSize& size); + void setResizeMethod(Plasma::Wallpaper::ResizeMethod resizeMethod); + + void addColor(int mode, const QString &title); + +private: + QPixmap createPixmap(int mode) const; + +private: + QWeakPointer m_structureParent; + QList m_backgroundModes; + QHash m_previews; + QHash m_titles; + QPixmap m_previewUnavailablePix; + QSize m_size; +}; + +#endif // BACKGROUNDLISTMODEL_H diff --git a/plasma/generic/wallpapers/color/color.cpp b/plasma/generic/wallpapers/color/color.cpp new file mode 100644 index 00000000..411fbd41 --- /dev/null +++ b/plasma/generic/wallpapers/color/color.cpp @@ -0,0 +1,236 @@ +/* + * Copyright 2008 by Petri Damsten + * Copyright 2012 by Reza Fatahilah Shah + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "color.h" + +#include +#include +#include + +#include "backgroundlistmodel.h" +#include "backgrounddelegate.h" + +K_EXPORT_PLASMA_WALLPAPER(color, Color) + +enum BackgroundMode { + SOLID, + HORIZONTAL, + VERTICAL, + RECTANGULAR, + RADIAL, + TOP_LEFT_DIAGONAL, + TOP_RIGHT_DIAGONAL +}; + +Color::Color(QObject *parent, const QVariantList &args) + : Plasma::Wallpaper(parent, args), + m_model(0) +{ +} + +void Color::init(const KConfigGroup &config) +{ + m_color1 = config.readEntry("color1", QColor(Qt::white)); + m_color2 = config.readEntry("color2", QColor(Qt::black)); + m_backgroundMode = config.readEntry("backgroundMode", (int)SOLID); + emit update(boundingRect()); +} + +void Color::paint(QPainter *painter, const QRectF& exposedRect) +{ + generatePainting(m_backgroundMode, painter, exposedRect, boundingRect()); +} + +QWidget* Color::createConfigurationInterface(QWidget* parent) +{ + QWidget *widget = new QWidget(parent); + + m_ui.setupUi(widget); + + m_ui.m_color1->setColor(m_color1); + m_ui.m_color2->setColor(m_color2); + + m_model = new BackgroundListModel(this, widget); + m_model->setWallpaperSize(targetSizeHint().toSize()); + m_model->addColor(0,i18n("Solid")); + m_model->addColor(1,i18n("Horizontal")); + m_model->addColor(2,i18n("Vertical")); + m_model->addColor(3,i18n("Rectangular")); + m_model->addColor(4,i18n("Radial")); + m_model->addColor(5,i18n("Top Left Diagonal")); + m_model->addColor(6,i18n("Top Right Diagonal")); + + m_ui.m_view->setItemDelegate(new BackgroundDelegate(m_ui.m_view)); + m_ui.m_view->setMinimumWidth((BackgroundDelegate::SCREENSHOT_SIZE + BackgroundDelegate::MARGIN * 2 + + BackgroundDelegate::BLUR_INCREMENT) * 3 + + m_ui.m_view->spacing() * 4 + + QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent) + + QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2 + 7); + m_ui.m_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + m_ui.m_view->setModel(m_model); + connect(m_ui.m_view->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(backgroundModeChanged(QModelIndex))); + + QModelIndex index = m_model->indexOf(m_backgroundMode); + if (index.isValid()) { + m_ui.m_view->setCurrentIndex(index); + } + + connect(m_ui.m_color1, SIGNAL(changed(QColor)), SLOT(widgetChanged())); + connect(m_ui.m_color2, SIGNAL(changed(QColor)), SLOT(widgetChanged())); + + connect(this, SIGNAL(settingsChanged(bool)), parent, SLOT(settingsChanged(bool))); + + return widget; +} + +void Color::save(KConfigGroup &config) +{ + config.writeEntry("color1", m_color1); + config.writeEntry("color2", m_color2); + config.writeEntry("backgroundMode", m_backgroundMode); +} + +void Color::backgroundModeChanged(const QModelIndex &index) +{ + if (index.row() == -1 || !m_model) { + return; + } + + m_backgroundMode = m_model->backgroundMode(index.row()); + + emit settingsChanged(true); + emit update(boundingRect()); +} + +void Color::widgetChanged() +{ + const QColor newColor1 = m_ui.m_color1->color(); + const QColor newColor2 = m_ui.m_color2->color(); + const bool updateThumbs = (m_color1 != newColor1) || (m_color2 != newColor2); + + m_color1 = newColor1; + m_color2 = newColor2; + + if (updateThumbs) { + m_model->reload(); + } + + emit settingsChanged(true); + emit update(boundingRect()); +} + +void Color::generatePainting(int mode, QPainter* painter, const QRectF& exposedRect, const QRectF& boundingRect) const +{ + switch (mode) { + case SOLID: { + painter->fillRect(exposedRect, m_color1); + break; + } + + case HORIZONTAL: { + QLinearGradient gradient = QLinearGradient(boundingRect.topLeft(), + boundingRect.topRight()); + gradient.setColorAt(0, m_color1); + gradient.setColorAt(1, m_color2); + painter->fillRect(exposedRect, gradient); + break; + } + + case VERTICAL: { + QLinearGradient gradient = QLinearGradient(boundingRect.topLeft(), + boundingRect.bottomLeft()); + gradient.setColorAt(0, m_color1); + gradient.setColorAt(1, m_color2); + painter->fillRect(exposedRect, gradient); + break; + } + + case RECTANGULAR: { + // First draw a horizontal gradient covering the whole view/screen + QLinearGradient horizontalGradient = QLinearGradient(boundingRect.topLeft(), + boundingRect.topRight()); + horizontalGradient.setColorAt(0, m_color2); + horizontalGradient.setColorAt(0.5, m_color1); + horizontalGradient.setColorAt(1, m_color2); + + painter->fillRect(exposedRect, horizontalGradient); + + // Then draw two triangles with vertical gradient + QLinearGradient verticalGradient = QLinearGradient(boundingRect.topLeft(), + boundingRect.bottomLeft()); + verticalGradient.setColorAt(0, m_color2); + verticalGradient.setColorAt(0.5, m_color1); + verticalGradient.setColorAt(1, m_color2); + painter->setBrush(verticalGradient); + painter->setPen(Qt::NoPen); + + QPolygon triangle = QPolygon(3); + + // Draw a triangle which starts from the top edge to the center + triangle.append(boundingRect.topLeft().toPoint()); + triangle.append(boundingRect.topRight().toPoint()); + triangle.append(boundingRect.center().toPoint()); + painter->drawPolygon(triangle); + + triangle.clear(); + + // Draw a triangle which starts from the bottom edge to the center + triangle.append(boundingRect.bottomLeft().toPoint()); + triangle.append(boundingRect.bottomRight().toPoint()); + triangle.append(boundingRect.center().toPoint()); + painter->drawPolygon(triangle); + + break; + } + + case RADIAL: { + // The diameter of the gradient will be the max screen dimension + int maxDimension = qMax(boundingRect.height(), boundingRect.width()); + + QRadialGradient gradient = QRadialGradient(boundingRect.center(), + maxDimension / 2, + boundingRect.center()); + gradient.setColorAt(0, m_color1); + gradient.setColorAt(1, m_color2); + painter->fillRect(exposedRect, gradient); + break; + } + + case TOP_LEFT_DIAGONAL: { + QLinearGradient gradient = QLinearGradient(boundingRect.topLeft(), + boundingRect.bottomRight()); + gradient.setColorAt(0, m_color1); + gradient.setColorAt(1, m_color2); + painter->fillRect(exposedRect, gradient); + break; + } + + case TOP_RIGHT_DIAGONAL: { + QLinearGradient gradient = QLinearGradient(boundingRect.topRight(), + boundingRect.bottomLeft()); + gradient.setColorAt(0, m_color1); + gradient.setColorAt(1, m_color2); + painter->fillRect(exposedRect, gradient); + break; + } + + } +} +#include "color.moc" diff --git a/plasma/generic/wallpapers/color/color.h b/plasma/generic/wallpapers/color/color.h new file mode 100644 index 00000000..1519cd9b --- /dev/null +++ b/plasma/generic/wallpapers/color/color.h @@ -0,0 +1,62 @@ +/* + * Copyright 2008 by Petri Damsten + * Copyright 2012 by Reza Fatahilah Shah + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COLOR_HEADER +#define COLOR_HEADER + +#include +#include +#include "ui_config.h" + +class BackgroundListModel; + +class Color : public Plasma::Wallpaper +{ + Q_OBJECT + public: + Color(QObject* parent, const QVariantList& args); + + virtual void save(KConfigGroup &config); + virtual void paint(QPainter* painter, const QRectF& exposedRect); + virtual QWidget* createConfigurationInterface(QWidget* parent); + void generatePainting(int mode, QPainter* painter, const QRectF& exposedRect, const QRectF &boundingRect) const; + + Q_SIGNALS: + void settingsChanged(bool modified); + + protected: + virtual void init(const KConfigGroup &config); + + protected slots: + void backgroundModeChanged(const QModelIndex &index); + + private slots: + void widgetChanged(); + + private: + Ui::Config m_ui; + BackgroundListModel *m_model; + QColor m_color1; + QColor m_color2; + + int m_backgroundMode; +}; + +#endif diff --git a/plasma/generic/wallpapers/color/config.ui b/plasma/generic/wallpapers/color/config.ui new file mode 100644 index 00000000..da66736d --- /dev/null +++ b/plasma/generic/wallpapers/color/config.ui @@ -0,0 +1,176 @@ + + + Config + + + + 0 + 0 + 437 + 313 + + + + Color + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 300 + 220 + + + + QListView::Static + + + QListView::Adjust + + + QListView::Batched + + + 2 + + + QListView::IconMode + + + false + + + + + + + + 0 + 0 + + + + &Second Color: + + + + 70 + 90 + 130 + + + + + 70 + 90 + 130 + + + + + + + + Qt::Horizontal + + + + 187 + 20 + + + + + + + + + 0 + 0 + + + + + 70 + 90 + 130 + + + + + 70 + 90 + 130 + + + + + + + + + 125 + 0 + + + + &Second color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_color1 + + + + + + + + 125 + 0 + + + + &First color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_color1 + + + + + + + + KColorButton + QPushButton +
kcolorbutton.h
+
+ + ItemsView + QListView +
itemsview.h
+
+
+ + +
diff --git a/plasma/generic/wallpapers/color/itemsview.cpp b/plasma/generic/wallpapers/color/itemsview.cpp new file mode 100644 index 00000000..281b19ab --- /dev/null +++ b/plasma/generic/wallpapers/color/itemsview.cpp @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010 Frederik Gladhorn + + 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, see . +*/ + +#include "itemsview.h" + +#include + +ItemsView::ItemsView(QWidget* parent) + : QListView(parent) +{ +} + +void ItemsView::wheelEvent(QWheelEvent* event) +{ + // this is a workaround because scrolling by mouse wheel is broken in Qt list views for big items + verticalScrollBar()->setSingleStep(10); + QListView::wheelEvent(event); +} diff --git a/plasma/generic/wallpapers/color/itemsview.h b/plasma/generic/wallpapers/color/itemsview.h new file mode 100644 index 00000000..b9bdef3b --- /dev/null +++ b/plasma/generic/wallpapers/color/itemsview.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010 Frederik Gladhorn + + 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, see . +*/ + +#ifndef ITEMSVIEW_H +#define ITEMSVIEW_H + +#include + +class ItemsView: public QListView +{ +public: + ItemsView(QWidget* parent = 0); + +protected: + void wheelEvent(QWheelEvent* event); +}; + +#endif diff --git a/plasma/generic/wallpapers/color/plasma-wallpaper-color.desktop b/plasma/generic/wallpapers/color/plasma-wallpaper-color.desktop new file mode 100644 index 00000000..435c923d --- /dev/null +++ b/plasma/generic/wallpapers/color/plasma-wallpaper-color.desktop @@ -0,0 +1,135 @@ +[Desktop Entry] +Name=Color +Name[ar]=لون +Name[as]=ৰং +Name[ast]=Color +Name[be@latin]=Koler +Name[bg]=Цвят +Name[bn]=রং +Name[bn_IN]=রং +Name[bs]=boja +Name[ca]=Color +Name[ca@valencia]=Color +Name[cs]=Barva +Name[csb]=Farwa +Name[da]=Farve +Name[de]=Farbe +Name[el]=Χρώμα +Name[en_GB]=Colour +Name[eo]=Koloro +Name[es]=Color +Name[et]=Värv +Name[eu]=Kolorea +Name[fi]=Väri +Name[fr]=Couleur +Name[fy]=Kleur +Name[ga]=Dath +Name[gl]=Cor +Name[gu]=રંગ +Name[he]=צבע +Name[hi]=रंग +Name[hne]=रंग +Name[hr]=Boja +Name[hu]=Szín +Name[ia]=Color +Name[id]=Warna +Name[is]=Litur +Name[ja]=色 +Name[ka]=ფერი +Name[kk]=Түсі +Name[km]=ពណ៌ +Name[kn]=ಬಣ್ಣ +Name[ko]=색 +Name[ku]=Reng +Name[lt]=Spalvos +Name[lv]=Krāsa +Name[mai]=रंग +Name[mk]=Боја +Name[ml]=നിറം +Name[mr]=रंग +Name[nb]=Farge +Name[nds]=Klöör +Name[nl]=Kleur +Name[nn]=Farge +Name[or]=ରଙ୍ଗ +Name[pa]=ਰੰਗ +Name[pl]=Kolor +Name[pt]=Cor +Name[pt_BR]=Cor +Name[ro]=Culoare +Name[ru]=Цвет +Name[si]=වර්‍ණය +Name[sk]=Farba +Name[sl]=Barva +Name[sr]=боја +Name[sr@ijekavian]=боја +Name[sr@ijekavianlatin]=boja +Name[sr@latin]=boja +Name[sv]=Färg +Name[ta]=Color +Name[te]=రంగు +Name[tg]=Ранг +Name[th]=สี +Name[tr]=Renk +Name[ug]=رەڭ +Name[uk]=Колір +Name[vi]=Màu sắc +Name[wa]=Coleur +Name[x-test]=xxColorxx +Name[zh_CN]=颜色 +Name[zh_TW]=顏色 +Comment=A plain color or gradient +Comment[bs]=Prosta boja ili gradijent +Comment[ca]=Un color normal o degradat +Comment[ca@valencia]=Un color normal o degradat +Comment[cs]=Barva nebo barevný přechod +Comment[da]=En enkelt farve eller gradient +Comment[de]=Einfache Farbe oder Verlauf +Comment[el]=Ένα απλό χρώμα ή μια διαβάθμιση +Comment[en_GB]=A plain colour or gradient +Comment[es]=Un color liso o gradiente +Comment[et]=Puhas värv või üleminek +Comment[eu]=Kolore bakarra edo gradientea +Comment[fi]=Tasainen väri tai liukuväri +Comment[fr]=Une couleur pleine ou un dégradé +Comment[gl]=Unha cor ou gradación. +Comment[hu]=Egy homogén szín vagy színátmenet +Comment[ia]=Unn color plan o gradiente +Comment[it]=Un colore semplice o sfumatura +Comment[kk]=Жәй түс пе, градиент пе +Comment[ko]=단색이나 그라디언트 +Comment[nb]=En enkel farge eller gradient +Comment[nds]=En eenfach Klöörövergang +Comment[nl]=Een vlakke kleur of verloop +Comment[pa]=ਇਕਸਾਰ ਰੰਗ ਜਾਂ ਗਰੇਡੀਐਂਟ +Comment[pl]=Jednolity kolor lub gradient +Comment[pt]=Uma cor simples ou gradiente +Comment[pt_BR]=Cor simples ou gradiente +Comment[ro]=Culoare simplă sau gradient +Comment[ru]=Простой цвет или градиент +Comment[sk]=Jednoduchá farba alebo prechod +Comment[sl]=Preprosta barva ali preliv +Comment[sr]=Обична боја или прелив +Comment[sr@ijekavian]=Обична боја или прелив +Comment[sr@ijekavianlatin]=Obična boja ili preliv +Comment[sr@latin]=Obična boja ili preliv +Comment[sv]=En enkel färg eller toning +Comment[tr]=Düz veya gradyan bir renk +Comment[uk]=Простий колір або градієнт +Comment[x-test]=xxA plain color or gradientxx +Comment[zh_CN]=纯色或渐变色 +Comment[zh_TW]=簡單的顏色或漸層 +Type=Service +Icon=preferences-desktop-color +ServiceTypes=Plasma/Wallpaper + +X-KDE-Library=plasma_wallpaper_color +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=color +X-KDE-PluginInfo-Version=0.2 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + diff --git a/plasma/generic/wallpapers/image/CMakeLists.txt b/plasma/generic/wallpapers/image/CMakeLists.txt new file mode 100644 index 00000000..47183413 --- /dev/null +++ b/plasma/generic/wallpapers/image/CMakeLists.txt @@ -0,0 +1,22 @@ +project(plasma-wallpaper-image) + +set(image_SRCS + image.cpp + backgrounddelegate.cpp + backgroundlistmodel.cpp + removebuttonmanager.cpp + removebutton.cpp + itemsview.cpp +) +kde4_add_ui_files(image_SRCS imageconfig.ui slideshowconfig.ui) + +set(ksmserver_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/org.kde.KSMServerInterface.xml) +qt4_add_dbus_interface(image_SRCS ${ksmserver_xml} ksmserver_interface) + +kde4_add_plugin(plasma_wallpaper_image ${image_SRCS}) +target_link_libraries(plasma_wallpaper_image ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KFILE_LIBS} ${KDE4_KNEWSTUFF3_LIBS} ${KDE4_THREADWEAVER_LIBRARY}) + +install(TARGETS plasma_wallpaper_image DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-wallpaper-image.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + +install(FILES wallpaper.knsrc DESTINATION ${CONFIG_INSTALL_DIR}) diff --git a/plasma/generic/wallpapers/image/Messages.sh b/plasma/generic/wallpapers/image/Messages.sh new file mode 100755 index 00000000..01788de2 --- /dev/null +++ b/plasma/generic/wallpapers/image/Messages.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma_wallpaper_image.pot +rm -f rc.cpp + diff --git a/plasma/generic/wallpapers/image/backgrounddelegate.cpp b/plasma/generic/wallpapers/image/backgrounddelegate.cpp new file mode 100644 index 00000000..dab0bc9e --- /dev/null +++ b/plasma/generic/wallpapers/image/backgrounddelegate.cpp @@ -0,0 +1,162 @@ +/* + Copyright (c) 2007 Paolo Capriotti + Copyright (c) 2010 Dario Andres Rodriguez + + 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. +*/ + +#include "backgrounddelegate.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static const int BLUR_PAD = 6; + +BackgroundDelegate::BackgroundDelegate(QObject *parent) + : QAbstractItemDelegate(parent) +{ + m_maxHeight = SCREENSHOT_SIZE/1.6 + BLUR_INCREMENT; + m_maxWidth = SCREENSHOT_SIZE + BLUR_INCREMENT; +} + +void BackgroundDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + const QString title = index.model()->data(index, Qt::DisplayRole).toString(); + const QString author = index.model()->data(index, AuthorRole).toString(); + const QString resolution = index.model()->data(index, ResolutionRole).toString(); + const QPixmap pix = index.model()->data(index, ScreenshotRole).value(); + + // Highlight selected item + QStyleOptionViewItemV4 opt(option); + opt.showDecorationSelected = true; + QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); + + // Draw wallpaper thumbnail + if (pix.isNull()) { + painter->fillRect(option.rect, option.palette.brush(QPalette::Base)); + } else { + // blur calculation + QImage blur(pix.size() + QSize(BLUR_INCREMENT + BLUR_PAD, BLUR_INCREMENT + BLUR_PAD), QImage::Format_ARGB32); + QRect blurRect = QRect(QPoint((blur.width() - pix.width()) / 2, (blur.height() - pix.height()) / 2), pix.size()); + blur.fill(Qt::transparent); + QPainter p(&blur); + + QColor color = option.palette.color(QPalette::Base); + bool darkBaseColor = qGray(color.rgb()) < 192; + p.fillRect(blurRect, darkBaseColor ? Qt::white : Qt::black); + p.end(); + + // apply blur with a radius of 2 as thumbnail shadow + Plasma::PaintUtils::shadowBlur(blur, 2, darkBaseColor ? Qt::white : Qt::black); + + // calculate point + const int bx = (option.rect.width() - blur.width()) / 2; + const int by = MARGIN + qMax(0, m_maxHeight - blur.height()); + QRect shadowRect = QRect(option.rect.topLeft(), blur.size()).translated(bx, by); + // draw the blur + painter->drawImage(shadowRect.topLeft(), blur); + // draw the actual thumbnail + painter->drawPixmap(QRect(shadowRect.topLeft() + QPoint((shadowRect.width() - pix.width()) / 2, (shadowRect.height() - pix.height()) / 2), + pix.size()), pix); + } + + //Use a QTextDocument to layout the text + + // Borrowed from Dolphin for consistency and beauty. + // For the color of the additional info the inactive text color + // is not used as this might lead to unreadable text for some color schemes. Instead + // the text color is slightly mixed with the background color. + const QColor textColor = option.palette.text().color(); + const QColor baseColor = option.palette.base().color(); + const int p1 = 70; + const int p2 = 100 - p1; + const QColor detailsColor = QColor((textColor.red() * p1 + baseColor.red() * p2) / 100, + (textColor.green() * p1 + baseColor.green() * p2) / 100, + (textColor.blue() * p1 + baseColor.blue() * p2) / 100); + QTextDocument document; + QString html = title; + + if (!resolution.isEmpty()) { + html += QString("
%2") + .arg(detailsColor.name()) + .arg(resolution); + } + + if (!author.isEmpty()) { + html += QString("
%2") + .arg(detailsColor.name()) + .arg(author); + } + + //Set the text color according to the item state + QPalette::ColorGroup cg = QPalette::Active; + if (!(option.state & QStyle::State_Enabled)) { + cg = QPalette::Disabled; + } else if (!(option.state & QStyle::State_Active)) { + cg = QPalette::Inactive; + } + + QColor color; + if (option.state & QStyle::State_Selected) { + color = QApplication::palette().brush(cg, QPalette::HighlightedText).color(); + } else { + color = QApplication::palette().brush(cg, QPalette::Text).color(); + } + + html = QString("
%2
").arg(color.name()).arg(html); + + document.setHtml(html); + + //Calculate positioning + int x = option.rect.left() + MARGIN; + + //Enable word-wrap + document.setTextWidth(m_maxWidth); + + //Center text on the row + int y = option.rect.top() + m_maxHeight + MARGIN * 2; //qMax(0 ,(int)((option.rect.height() - document.size().height()) / 2)); + + //Draw text + painter->save(); + painter->translate(x, y); + document.drawContents(painter, QRect(QPoint(0, 0), option.rect.size() - QSize(0, m_maxHeight + MARGIN * 2))); + painter->restore(); +} + +QSize BackgroundDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + Q_UNUSED(option) + const QString title = index.model()->data(index, Qt::DisplayRole).toString(); + const QString author = index.model()->data(index, AuthorRole).toString(); + + //Generate a sample complete entry (with the real title) to calculate sizes + QTextDocument document; + QString html = title + "
"; + if (!author.isEmpty()) { + html += author + "
"; + } + html += QString("1600x1200"); + + document.setHtml(html); + document.setTextWidth(m_maxWidth); + + QSize s(m_maxWidth + MARGIN * 2, + m_maxHeight + MARGIN * 3 + (int)(document.size().height())); + return s; +} + diff --git a/plasma/generic/wallpapers/image/backgrounddelegate.h b/plasma/generic/wallpapers/image/backgrounddelegate.h new file mode 100644 index 00000000..9e38b501 --- /dev/null +++ b/plasma/generic/wallpapers/image/backgrounddelegate.h @@ -0,0 +1,42 @@ +/* + Copyright (c) 2007 Paolo Capriotti + + 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. +*/ + +#ifndef BACKGROUNDDELEGATE_H +#define BACKGROUNDDELEGATE_H + +#include + +class BackgroundDelegate : public QAbstractItemDelegate +{ +public: + enum { + AuthorRole = Qt::UserRole, + ScreenshotRole, + ResolutionRole + }; + + BackgroundDelegate(QObject *parent = 0); + + virtual void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + static const int SCREENSHOT_SIZE = 128; + static const int BLUR_INCREMENT = 9; + static const int MARGIN = 6; + + void resetMaxHeight() { m_maxHeight = 0; } + int m_maxHeight; +private: + int m_maxWidth; +}; + +#endif // BACKGROUNDDELEGATEL_H diff --git a/plasma/generic/wallpapers/image/backgroundlistmodel.cpp b/plasma/generic/wallpapers/image/backgroundlistmodel.cpp new file mode 100644 index 00000000..d79cdbb5 --- /dev/null +++ b/plasma/generic/wallpapers/image/backgroundlistmodel.cpp @@ -0,0 +1,428 @@ +#ifndef BACKGROUNDLISTMODEL_CPP +#define BACKGROUNDLISTMODEL_CPP +/* + Copyright (c) 2007 Paolo Capriotti + + 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. +*/ + +#include "backgroundlistmodel.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "backgrounddelegate.h" +#include "image.h" + +QSet BackgroundFinder::m_suffixes; + +ImageSizeFinder::ImageSizeFinder(const QString &path, QObject *parent) + : QObject(parent), + m_path(path) +{ +} + +void ImageSizeFinder::run() +{ + QImage image(m_path); + emit sizeFound(m_path, image.size()); +} + + +BackgroundListModel::BackgroundListModel(Image *listener, QObject *parent) + : QAbstractListModel(parent), + m_structureParent(listener), + m_size(0,0), + m_resizeMethod(Plasma::Wallpaper::ScaledResize) +{ + connect(&m_dirwatch, SIGNAL(deleted(QString)), this, SLOT(removeBackground(QString))); + m_previewUnavailablePix.fill(Qt::transparent); + //m_previewUnavailablePix = KIcon("unknown").pixmap(m_previewUnavailablePix.size()); +} + +BackgroundListModel::~BackgroundListModel() +{ + qDeleteAll(m_packages); +} + +void BackgroundListModel::removeBackground(const QString &path) +{ + QModelIndex index; + while ((index = indexOf(path)).isValid()) { + beginRemoveRows(QModelIndex(), index.row(), index.row()); + Plasma::Package *package = m_packages.at(index.row()); + m_packages.removeAt(index.row()); + m_sizeCache.remove(package); + m_previews.remove(package); + delete package; + endRemoveRows(); + } +} + +void BackgroundListModel::reload() +{ + reload(QStringList()); +} + +void BackgroundListModel::reload(const QStringList &selected) +{ + if (!m_packages.isEmpty()) { + beginRemoveRows(QModelIndex(), 0, m_packages.count() - 1); + qDeleteAll(m_packages); + m_packages.clear(); + m_sizeCache.clear(); + m_previews.clear(); + endRemoveRows(); + } + + if (!m_structureParent) { + return; + } + + if (!selected.isEmpty()) { + processPaths(selected); + } + + const QStringList dirs = KGlobal::dirs()->findDirs("wallpaper", ""); + kDebug() << "going looking in" << dirs; + BackgroundFinder *finder = new BackgroundFinder(m_structureParent.data(), dirs); + connect(finder, SIGNAL(backgroundsFound(QStringList,QString)), this, SLOT(backgroundsFound(QStringList,QString))); + m_findToken = finder->token(); + finder->start(); +} + +void BackgroundListModel::backgroundsFound(const QStringList &paths, const QString &token) +{ + if (token == m_findToken) { + processPaths(paths); + } +} + +void BackgroundListModel::processPaths(const QStringList &paths) +{ + if (!m_structureParent) { + return; + } + + QList newPackages; + foreach (const QString &file, paths) { + if (!contains(file) && QFile::exists(file)) { + Plasma::PackageStructure::Ptr structure = Plasma::Wallpaper::packageStructure(m_structureParent.data()); + Plasma::Package *package = new Plasma::Package(file, structure); + if (package->isValid()) { + newPackages << package; + } else { + delete package; + } + } + } + + // add new files to dirwatch + foreach (Plasma::Package *b, newPackages) { + if (!m_dirwatch.contains(b->path())) { + m_dirwatch.addFile(b->path()); + } + } + + if (!newPackages.isEmpty()) { + const int start = rowCount(); + beginInsertRows(QModelIndex(), start, start + newPackages.size()); + m_packages.append(newPackages); + endInsertRows(); + } + //kDebug() << t.elapsed(); +} + +void BackgroundListModel::addBackground(const QString& path) +{ + if (!m_structureParent || !contains(path)) { + if (!m_dirwatch.contains(path)) { + m_dirwatch.addFile(path); + } + beginInsertRows(QModelIndex(), 0, 0); + Plasma::PackageStructure::Ptr structure = Plasma::Wallpaper::packageStructure(m_structureParent.data()); + Plasma::Package *pkg = new Plasma::Package(path, structure); + m_packages.prepend(pkg); + endInsertRows(); + } +} + +QModelIndex BackgroundListModel::indexOf(const QString &path) const +{ + for (int i = 0; i < m_packages.size(); i++) { + // packages will end with a '/', but the path passed in may not + QString package = m_packages[i]->path(); + if (package.at(package.length() - 1) == '/') { + package.truncate(package.length() - 1); + } + + if (path.startsWith(package)) { + // FIXME: ugly hack to make a difference between local files in the same dir + // package->path does not contain the actual file name + if ((!m_packages[i]->structure()->contentsPrefixPaths().isEmpty()) || + (path == m_packages[i]->filePath("preferred"))) { + return index(i, 0); + } + } + } + return QModelIndex(); +} + +bool BackgroundListModel::contains(const QString &path) const +{ + return indexOf(path).isValid(); +} + +int BackgroundListModel::rowCount(const QModelIndex &) const +{ + return m_packages.size(); +} + +QSize BackgroundListModel::bestSize(Plasma::Package *package) const +{ + if (m_sizeCache.contains(package)) { + return m_sizeCache.value(package); + } + + const QString image = package->filePath("preferred"); + if (image.isEmpty()) { + return QSize(); + } + + ImageSizeFinder *finder = new ImageSizeFinder(image); + connect(finder, SIGNAL(sizeFound(QString,QSize)), this, + SLOT(sizeFound(QString,QSize))); + QThreadPool::globalInstance()->start(finder); + + QSize size(-1, -1); + const_cast(this)->m_sizeCache.insert(package, size); + return size; +} + +void BackgroundListModel::sizeFound(const QString &path, const QSize &s) +{ + if (!m_structureParent) { + return; + } + + QModelIndex index = indexOf(path); + if (index.isValid()) { + Plasma::Package *package = m_packages.at(index.row()); + m_sizeCache.insert(package, s); + m_structureParent.data()->updateScreenshot(index); + } +} + +QVariant BackgroundListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() >= m_packages.size()) { + return QVariant(); + } + + Plasma::Package *b = package(index.row()); + if (!b) { + return QVariant(); + } + + switch (role) { + case Qt::DisplayRole: { + QString title = b->metadata().name(); + + if (title.isEmpty()) { + return QFileInfo(b->filePath("preferred")).completeBaseName(); + } + + return title; + } + break; + + case BackgroundDelegate::ScreenshotRole: { + if (m_previews.contains(b)) { + return m_previews.value(b); + } + + KUrl file(b->filePath("preferred")); + if (!m_previewJobs.contains(file) && file.isValid()) { + KFileItemList list; + list.append(KFileItem(file, QString(), 0)); + KIO::PreviewJob* job = KIO::filePreview(list, + QSize(BackgroundDelegate::SCREENSHOT_SIZE, + BackgroundDelegate::SCREENSHOT_SIZE/1.6)); + job->setIgnoreMaximumSize(true); + connect(job, SIGNAL(gotPreview(KFileItem,QPixmap)), + this, SLOT(showPreview(KFileItem,QPixmap))); + connect(job, SIGNAL(failed(KFileItem)), + this, SLOT(previewFailed(KFileItem))); + const_cast(this)->m_previewJobs.insert(file, QPersistentModelIndex(index)); + } + + const_cast(this)->m_previews.insert(b, m_previewUnavailablePix); + return m_previewUnavailablePix; + } + break; + + case BackgroundDelegate::AuthorRole: + return b->metadata().author(); + break; + + case BackgroundDelegate::ResolutionRole:{ + QSize size = bestSize(b); + + if (size.isValid()) { + return QString("%1x%2").arg(size.width()).arg(size.height()); + } + + return QString(); + } + break; + + default: + return QVariant(); + break; + } +} + +void BackgroundListModel::showPreview(const KFileItem &item, const QPixmap &preview) +{ + if (!m_structureParent) { + return; + } + + QPersistentModelIndex index = m_previewJobs.value(item.url()); + m_previewJobs.remove(item.url()); + + if (!index.isValid()) { + return; + } + + Plasma::Package *b = package(index.row()); + if (!b) { + return; + } + + m_previews.insert(b, preview); + //kDebug() << "preview size:" << preview.size(); + m_structureParent.data()->updateScreenshot(index); +} + +void BackgroundListModel::previewFailed(const KFileItem &item) +{ + m_previewJobs.remove(item.url()); +} + +Plasma::Package* BackgroundListModel::package(int index) const +{ + return m_packages.at(index); +} + +void BackgroundListModel::setWallpaperSize(const QSize& size) +{ + m_size = size; +} + +void BackgroundListModel::setResizeMethod(Plasma::Wallpaper::ResizeMethod resizeMethod) +{ + m_resizeMethod = resizeMethod; +} + +BackgroundFinder::BackgroundFinder(Plasma::Wallpaper *structureParent, const QStringList &paths) + : QThread(structureParent), + m_structure(Plasma::Wallpaper::packageStructure(structureParent)), + m_paths(paths), + m_token(QUuid().toString()) +{ +} + +BackgroundFinder::~BackgroundFinder() +{ + wait(); +} + +QString BackgroundFinder::token() const +{ + return m_token; +} + +const QSet &BackgroundFinder::suffixes() +{ + if(m_suffixes.isEmpty()) { + m_suffixes << "png" << "jpeg" << "jpg" << "svg" << "svgz"; + } + + return m_suffixes; +} + +void BackgroundFinder::run() +{ + //QTime t; + //t.start(); + const QSet &fileSuffixes = suffixes(); + + QStringList papersFound; + //kDebug() << "starting with" << m_paths; + + QDir dir; + dir.setFilter(QDir::AllDirs | QDir::Files | QDir::Hidden | QDir::Readable); + Plasma::Package pkg(QString(), m_structure); + + int i; + for (i = 0; i < m_paths.count(); ++i) { + const QString path = m_paths.at(i); + //kDebug() << "doing" << path; + dir.setPath(path); + const QFileInfoList files = dir.entryInfoList(); + foreach (const QFileInfo &wp, files) { + if (wp.isDir()) { + //kDebug() << "directory" << wp.fileName() << validPackages.contains(wp.fileName()); + const QString name = wp.fileName(); + if (name == "." || name == "..") { + // do nothing + continue; + } + + const QString filePath = wp.filePath(); + if (QFile::exists(filePath + "/metadata.desktop")) { + pkg.setPath(filePath); + if (pkg.isValid()) { + papersFound << pkg.path(); + continue; + //kDebug() << "gots a" << wp.filePath(); + } + } + + // add this to the directories we should be looking at + m_paths.append(filePath); + } else if (fileSuffixes.contains(wp.suffix().toLower())) { + //kDebug() << " adding image file" << wp.filePath(); + papersFound << wp.filePath(); + } + } + } + + //kDebug() << "background found!" << papersFound.size() << "in" << i << "dirs, taking" << t.elapsed() << "ms"; + emit backgroundsFound(papersFound, m_token); + deleteLater(); +} + +#include "backgroundlistmodel.moc" + + +#endif // BACKGROUNDLISTMODEL_CPP diff --git a/plasma/generic/wallpapers/image/backgroundlistmodel.h b/plasma/generic/wallpapers/image/backgroundlistmodel.h new file mode 100644 index 00000000..8ec913b3 --- /dev/null +++ b/plasma/generic/wallpapers/image/backgroundlistmodel.h @@ -0,0 +1,118 @@ +/* + Copyright (c) 2007 Paolo Capriotti + + 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. +*/ + +#ifndef BACKGROUNDLISTMODEL_H +#define BACKGROUNDLISTMODEL_H + +#include +#include +#include +#include + +#include +#include + +#include + +class QEventLoop; +class KProgressDialog; + +namespace Plasma +{ + class Package; +} // namespace Plasma + +class Image; + +class ImageSizeFinder : public QObject, public QRunnable +{ + Q_OBJECT + public: + ImageSizeFinder(const QString &path, QObject *parent = 0); + void run(); + + Q_SIGNALS: + void sizeFound(const QString &path, const QSize &size); + + private: + QString m_path; +}; + +class BackgroundListModel : public QAbstractListModel +{ + Q_OBJECT + +public: + BackgroundListModel(Image *listener, QObject *parent); + virtual ~BackgroundListModel(); + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + Plasma::Package *package(int index) const; + + void reload(); + void reload(const QStringList &selected); + void addBackground(const QString &path); + QModelIndex indexOf(const QString &path) const; + virtual bool contains(const QString &bg) const; + + void setWallpaperSize(const QSize& size); + void setResizeMethod(Plasma::Wallpaper::ResizeMethod resizeMethod); + +protected Q_SLOTS: + void removeBackground(const QString &path); + void showPreview(const KFileItem &item, const QPixmap &preview); + void previewFailed(const KFileItem &item); + void sizeFound(const QString &path, const QSize &s); + void backgroundsFound(const QStringList &paths, const QString &token); + void processPaths(const QStringList &paths); + +private: + QSize bestSize(Plasma::Package *package) const; + + QWeakPointer m_structureParent; + QList m_packages; + QHash m_sizeCache; + QHash m_previews; + QHash m_previewJobs; + KDirWatch m_dirwatch; + + QSize m_size; + Plasma::Wallpaper::ResizeMethod m_resizeMethod; + QString m_findToken; + QPixmap m_previewUnavailablePix; +}; + +class BackgroundFinder : public QThread +{ + Q_OBJECT + +public: + BackgroundFinder(Plasma::Wallpaper *structureParent, const QStringList &p); + ~BackgroundFinder(); + + QString token() const; + + static const QSet &suffixes(); + +signals: + void backgroundsFound(const QStringList &paths, const QString &token); + +protected: + void run(); + +private: + Plasma::PackageStructure::Ptr m_structure; + QStringList m_paths; + QString m_token; + + static QSet m_suffixes; +}; + +#endif // BACKGROUNDLISTMODEL_H diff --git a/plasma/generic/wallpapers/image/image.cpp b/plasma/generic/wallpapers/image/image.cpp new file mode 100644 index 00000000..02b4e6b8 --- /dev/null +++ b/plasma/generic/wallpapers/image/image.cpp @@ -0,0 +1,935 @@ +/* + Copyright (c) 2007 by Paolo Capriotti + Copyright (c) 2007 by Aaron Seigo + Copyright (c) 2008 by Alexis Ménard + Copyright (c) 2008 by Petri Damsten + + 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. +*/ + +#include "image.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "backgroundlistmodel.h" +#include "backgrounddelegate.h" +#include "removebuttonmanager.h" +#include "ksmserver_interface.h" + +K_EXPORT_PLASMA_WALLPAPER(image, Image) + +Image::Image(QObject *parent, const QVariantList &args) + : Plasma::Wallpaper(parent, args), + m_delay(10), + m_dirWatch(0), + m_scanDirty(false), + m_configWidget(0), + m_wallpaperPackage(0), + m_currentSlide(-1), + m_fadeValue(0), + m_animation(0), + m_model(0), + m_dialog(0), + m_nextWallpaperAction(0), + m_openImageAction(0) +{ + connect(this, SIGNAL(renderCompleted(QImage)), this, SLOT(wallpaperRenderComplete(QImage))); + connect(this, SIGNAL(renderHintsChanged()), this, SLOT(checkSize())); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(nextSlide())); + connect(&m_delayedRenderTimer, SIGNAL(timeout()), this, SLOT(actuallyRenderWallpaper())); + m_delayedRenderTimer.setSingleShot(true); +} + +Image::~Image() +{ + delete m_animation; +} + +void Image::init(const KConfigGroup &config) +{ + m_timer.stop(); + + if (renderingMode().name().isEmpty()) { + m_mode = "SingleImage"; + } else { + m_mode = renderingMode().name(); + } + + calculateGeometry(); + + m_delay = config.readEntry("slideTimer", 10); + setResizeMethodHint((ResizeMethod)config.readEntry("wallpaperposition", (int)ScaledResize)); + m_wallpaper = config.readEntry("wallpaper", QString()); + if (m_wallpaper.isEmpty()) { + useSingleImageDefaults(); + } + + m_color = config.readEntry("wallpapercolor", QColor(Qt::black)); + m_usersWallpapers = config.readEntry("userswallpapers", QStringList()); + QStringList dirs = config.readEntry("slidepaths", QStringList()); + + if (dirs.isEmpty()) { + dirs << KStandardDirs::installPath("wallpaper"); + } + + setUsingRenderingCache(m_mode == "SingleImage"); + + if (m_mode == "SingleImage") { + setSingleImage(); + setContextualActions(QList()); + } else { + m_nextWallpaperAction = new QAction(KIcon("user-desktop"), i18n("Next Wallpaper Image"), this); + connect(m_nextWallpaperAction, SIGNAL(triggered(bool)), this, SLOT(nextSlide())); + m_openImageAction = new QAction(KIcon("document-open"), i18n("Open Wallpaper Image"), this); + connect(m_openImageAction, SIGNAL(triggered(bool)), this, SLOT(openSlide())); + QTimer::singleShot(200, this, SLOT(startSlideshow())); + updateDirWatch(dirs); + QList actions; + actions.push_back(m_nextWallpaperAction); + actions.push_back(m_openImageAction); + setContextualActions(actions); + updateWallpaperActions(); + } +} + +void Image::useSingleImageDefaults() +{ + m_wallpaper = Plasma::Theme::defaultTheme()->wallpaperPath(); + int index = m_wallpaper.indexOf("/contents/images/"); + if (index > -1) { // We have file from package -> get path to package + m_wallpaper = m_wallpaper.left(index); + } +} + +void Image::save(KConfigGroup &config) +{ + config.writeEntry("slideTimer", m_delay); + config.writeEntry("wallpaperposition", (int)resizeMethodHint()); + config.writeEntry("slidepaths", m_dirs); + config.writeEntry("wallpaper", m_wallpaper); + config.writeEntry("wallpapercolor", m_color); + config.writeEntry("userswallpapers", m_usersWallpapers); +} + +void Image::configWidgetDestroyed() +{ + m_configWidget = 0; + m_model = 0; +} + +QWidget* Image::createConfigurationInterface(QWidget* parent) +{ + m_configWidget = new QWidget(parent); + connect(m_configWidget, SIGNAL(destroyed(QObject*)), this, SLOT(configWidgetDestroyed())); + + if (m_mode == "SingleImage") { + m_uiImage.setupUi(m_configWidget); + + m_model = new BackgroundListModel(this, m_configWidget); + m_model->setResizeMethod(resizeMethodHint()); + m_model->setWallpaperSize(m_size); + m_model->reload(m_usersWallpapers); + QTimer::singleShot(0, this, SLOT(setConfigurationInterfaceModel())); + m_uiImage.m_view->setItemDelegate(new BackgroundDelegate(m_uiImage.m_view)); + //FIXME: setting the minimum width is rather ugly, but this gets us 3 columns of papers + //which looks quite good as a default. the magic number 7 at the end of the calculation is + //evidently making up for some other PM involved in the QListView that isn't being caught. + //if a cleaner way can be found to achieve all this, that would be great + m_uiImage.m_view->setMinimumWidth((BackgroundDelegate::SCREENSHOT_SIZE + BackgroundDelegate::MARGIN * 2 + + BackgroundDelegate::BLUR_INCREMENT) * 3 + + m_uiImage.m_view->spacing() * 4 + + QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent) + + QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2 + 7); + m_uiImage.m_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + + RemoveButtonManager *rmManager = new RemoveButtonManager(m_uiImage.m_view, &m_usersWallpapers); + connect(rmManager, SIGNAL(removeClicked(QString)), this, SLOT(removeWallpaper(QString))); + + m_uiImage.m_pictureUrlButton->setIcon(KIcon("document-open")); + connect(m_uiImage.m_pictureUrlButton, SIGNAL(clicked()), this, SLOT(showFileDialog())); + + m_uiImage.m_resizeMethod->addItem(i18n("Scaled & Cropped"), ScaledAndCroppedResize); + m_uiImage.m_resizeMethod->addItem(i18n("Scaled"), ScaledResize); + m_uiImage.m_resizeMethod->addItem(i18n("Scaled, keep proportions"), MaxpectResize); + m_uiImage.m_resizeMethod->addItem(i18n("Centered"), CenteredResize); + m_uiImage.m_resizeMethod->addItem(i18n("Tiled"), TiledResize); + m_uiImage.m_resizeMethod->addItem(i18n("Center Tiled"), CenterTiledResize); + for (int i = 0; i < m_uiImage.m_resizeMethod->count(); ++i) { + if (resizeMethodHint() == m_uiImage.m_resizeMethod->itemData(i).value()) { + m_uiImage.m_resizeMethod->setCurrentIndex(i); + break; + } + } + connect(m_uiImage.m_resizeMethod, SIGNAL(currentIndexChanged(int)), + this, SLOT(positioningChanged(int))); + + m_uiImage.m_color->setColor(m_color); + //Color button is useless with some resize methods + m_uiImage.m_color->setEnabled(resizeMethodHint() == MaxpectResize || resizeMethodHint() == CenteredResize); + connect(m_uiImage.m_color, SIGNAL(changed(QColor)), this, SLOT(colorChanged(QColor))); + + m_uiImage.m_newStuff->setIcon(KIcon("get-hot-new-stuff")); + connect(m_uiImage.m_newStuff, SIGNAL(clicked()), this, SLOT(getNewWallpaper())); + + connect(m_uiImage.m_color, SIGNAL(changed(QColor)), this, SLOT(modified())); + connect(m_uiImage.m_resizeMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(modified())); + connect(m_uiImage.m_view, SIGNAL(clicked(QModelIndex)), this, SLOT(modified())); + + } else { + m_uiSlideshow.setupUi(m_configWidget); + m_uiSlideshow.m_newStuff->setIcon(KIcon("get-hot-new-stuff")); + m_uiSlideshow.m_dirlist->clear(); + m_uiSlideshow.m_systemCheckBox->setChecked(false); + m_uiSlideshow.m_downloadedCheckBox->setChecked(false); + + QString systemPath = KStandardDirs::installPath("wallpaper"); + QString localPath = KGlobal::dirs()->saveLocation("wallpaper"); + + foreach (const QString &dir, m_dirs) { + if (dir == KStandardDirs::installPath("wallpaper")) { + m_uiSlideshow.m_systemCheckBox->setChecked(true); + } else if (dir == localPath) { + m_uiSlideshow.m_downloadedCheckBox->setChecked(true); + } else { + m_uiSlideshow.m_dirlist->addItem(dir); + } + } + m_uiSlideshow.m_dirlist->setCurrentRow(0); + updateDirs(); + m_uiSlideshow.m_addDir->setIcon(KIcon("list-add")); + connect(m_uiSlideshow.m_addDir, SIGNAL(clicked()), this, SLOT(addDir())); + m_uiSlideshow.m_removeDir->setIcon(KIcon("list-remove")); + connect(m_uiSlideshow.m_removeDir, SIGNAL(clicked()), this, SLOT(removeDir())); + + QTime time(0, 0, 0); + time = time.addSecs(m_delay); + m_uiSlideshow.m_slideshowDelay->setTime(time); + m_uiSlideshow.m_slideshowDelay->setMinimumTime(QTime(0, 0, 10)); + connect(m_uiSlideshow.m_slideshowDelay, SIGNAL(timeChanged(QTime)), + this, SLOT(timeChanged(QTime))); + + m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled & Cropped"), ScaledAndCroppedResize); + m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled"), ScaledResize); + m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled, keep proportions"), MaxpectResize); + m_uiSlideshow.m_resizeMethod->addItem(i18n("Centered"), CenteredResize); + m_uiSlideshow.m_resizeMethod->addItem(i18n("Tiled"), TiledResize); + m_uiSlideshow.m_resizeMethod->addItem(i18n("Center Tiled"), CenterTiledResize); + for (int i = 0; i < m_uiSlideshow.m_resizeMethod->count(); ++i) { + if (resizeMethodHint() == m_uiSlideshow.m_resizeMethod->itemData(i).value()) { + m_uiSlideshow.m_resizeMethod->setCurrentIndex(i); + break; + } + } + connect(m_uiSlideshow.m_resizeMethod, SIGNAL(currentIndexChanged(int)), + this, SLOT(positioningChanged(int))); + + m_uiSlideshow.m_color->setColor(m_color); + //Color button is useless with some resize methods + m_uiSlideshow.m_color->setEnabled(resizeMethodHint() == MaxpectResize || resizeMethodHint() == CenteredResize); + connect(m_uiSlideshow.m_color, SIGNAL(changed(QColor)), this, SLOT(colorChanged(QColor))); + connect(m_uiSlideshow.m_newStuff, SIGNAL(clicked()), this, SLOT(getNewWallpaper())); + + connect(m_uiSlideshow.m_systemCheckBox, SIGNAL(toggled(bool)), + this, SLOT(systemCheckBoxToggled(bool))); + connect(m_uiSlideshow.m_downloadedCheckBox, SIGNAL(toggled(bool)), + this, SLOT(downloadedCheckBoxToggled(bool))); + connect(m_uiSlideshow.m_color, SIGNAL(changed(QColor)), this, SLOT(modified())); + connect(m_uiSlideshow.m_resizeMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(modified())); + connect(m_uiSlideshow.m_addDir, SIGNAL(clicked()), this, SLOT(modified())); + connect(m_uiSlideshow.m_removeDir, SIGNAL(clicked()), this, SLOT(modified())); + connect(m_uiSlideshow.m_slideshowDelay, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(modified())); + connect(m_uiSlideshow.m_dirlist, SIGNAL(currentRowChanged(int)), SLOT(updateDirs())); + } + + connect(this, SIGNAL(settingsChanged(bool)), parent, SLOT(settingsChanged(bool))); + return m_configWidget; +} + +void Image::systemCheckBoxToggled(bool checked) +{ + if (checked) { + m_dirs << KStandardDirs::installPath("wallpaper"); + } else { + m_dirs.removeAll(KStandardDirs::installPath("wallpaper")); + } + modified(); +} + +void Image::downloadedCheckBoxToggled(bool checked) +{ + if (checked) { + m_dirs << KGlobal::dirs()->saveLocation("wallpaper"); + } else { + m_dirs.removeAll(KGlobal::dirs()->saveLocation("wallpaper")); + } + modified(); +} + +void Image::setConfigurationInterfaceModel() +{ + m_uiImage.m_view->setModel(m_model); + connect(m_uiImage.m_view->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(pictureChanged(QModelIndex))); + + QModelIndex index = m_model->indexOf(m_wallpaper); + if (index.isValid()) { + m_uiImage.m_view->setCurrentIndex(index); + } +} + +void Image::modified() +{ + emit settingsChanged(true); +} + +void Image::calculateGeometry() +{ + m_size = boundingRect().size().toSize(); + + if (m_model) { + m_model->setWallpaperSize(m_size); + } +} + +void Image::paint(QPainter *painter, const QRectF& exposedRect) +{ + // Check if geometry changed + //kDebug() << m_size << boundingRect().size().toSize(); + if (m_pixmap.isNull()) { + painter->fillRect(exposedRect, QBrush(m_color)); + //kDebug() << "pixmap null"; + return; + } + + if (painter->worldMatrix() == QMatrix()) { + // draw the background untransformed when possible;(saves lots of per-pixel-math) + painter->resetTransform(); + } + + // blit the background (saves all the per-pixel-products that blending does) + painter->setCompositionMode(QPainter::CompositionMode_Source); + + // for pixmaps we draw only the exposed part (untransformed since the + // bitmapBackground already has the size of the viewport) + painter->drawPixmap(exposedRect, m_pixmap, exposedRect.translated(-boundingRect().topLeft())); + + if (!m_oldFadedPixmap.isNull()) { + // Put old faded image on top. + painter->setCompositionMode(QPainter::CompositionMode_SourceAtop); + painter->drawPixmap(exposedRect, m_oldFadedPixmap, + exposedRect.translated(-boundingRect().topLeft())); + } +} + +void Image::timeChanged(const QTime& time) +{ + m_delay = QTime(0, 0, 0).secsTo(time); + if (!m_slideshowBackgrounds.isEmpty()) { + m_timer.start(m_delay * 1000); + } +} + +void Image::addDir() +{ + KUrl empty; + KDirSelectDialog *dialog = new KDirSelectDialog(empty, true, m_configWidget); + connect(dialog, SIGNAL(accepted()), this, SLOT(addDirFromSelectionDialog())); + dialog->show(); +} + +void Image::addDirFromSelectionDialog() +{ + KDirSelectDialog *dialog = qobject_cast(sender()); + if (dialog) { + QString urlDir = dialog->url().path(); + if (!urlDir.isEmpty() && m_uiSlideshow.m_dirlist->findItems(urlDir, Qt::MatchExactly).isEmpty()) { + m_uiSlideshow.m_dirlist->addItem(urlDir); + updateDirs(); + startSlideshow(); + } + } +} + +void Image::removeDir() +{ + int row = m_uiSlideshow.m_dirlist->currentRow(); + if (row != -1) { + m_uiSlideshow.m_dirlist->takeItem(row); + updateDirs(); + startSlideshow(); + } +} + +void Image::updateDirs() +{ + m_dirs.clear(); + + if (m_uiSlideshow.m_systemCheckBox->isChecked()) { + m_dirs << KStandardDirs::installPath("wallpaper"); + } + if (m_uiSlideshow.m_downloadedCheckBox->isChecked()) { + m_dirs << KGlobal::dirs()->saveLocation("wallpaper"); + } + + const int dirCount = m_uiSlideshow.m_dirlist->count(); + for (int i = 0; i < dirCount; ++i) { + m_dirs.append(m_uiSlideshow.m_dirlist->item(i)->text()); + } + + m_uiSlideshow.m_removeDir->setEnabled(m_uiSlideshow.m_dirlist->currentRow() != -1); +} + +void Image::updateDirWatch(const QStringList &newDirs) +{ + if (isPreviewing()) { + return; + } + + if (!m_dirWatch) { + m_dirWatch = new KDirWatch(this); + connect(m_dirWatch, SIGNAL(created(QString)), SLOT(pathCreated(QString))); + connect(m_dirWatch, SIGNAL(dirty(QString)), SLOT(pathDirty(QString))); + connect(m_dirWatch, SIGNAL(deleted(QString)), SLOT(pathDeleted(QString))); + } + + foreach (const QString &oldDir, m_dirs) { + if (!newDirs.contains(oldDir)) { + m_dirWatch->removeDir(oldDir); + } + } + + foreach (const QString &newDir, newDirs) { + if (!m_dirWatch->contains(newDir)) { + m_dirWatch->addDir(newDir, KDirWatch::WatchSubDirs | KDirWatch::WatchFiles); + } + } + + m_dirWatch->startScan(); + m_dirs = newDirs; +} + +void Image::setSingleImage() +{ + if (isPreviewing()) { + return; + } + + if (m_wallpaper.isEmpty()) { + useSingleImageDefaults(); + } + + QString img; + + if (QDir::isAbsolutePath(m_wallpaper)) { + Plasma::Package b(m_wallpaper, packageStructure(this)); + img = b.filePath("preferred"); + //kDebug() << img << m_wallpaper; + + if (img.isEmpty() && QFile::exists(m_wallpaper)) { + img = m_wallpaper; + } + } else { + //if it's not an absolute path, check if it's just a wallpaper name + const QString path = KStandardDirs::locate("wallpaper", m_wallpaper + "/metadata.desktop"); + + if (!path.isEmpty()) { + QDir dir(path); + dir.cdUp(); + + Plasma::Package b(dir.path(), packageStructure(this)); + img = b.filePath("preferred"); + } + } + + if (img.isEmpty()) { + // ok, so the package we have failed to work out; let's try the default + // if we have already + const QString wallpaper = m_wallpaper; + useSingleImageDefaults(); + if (wallpaper != m_wallpaper) { + setSingleImage(); + } + } + + if (!m_size.isEmpty()) { + renderWallpaper(img); + } +} + +void Image::addUrls(const KUrl::List &urls) +{ + bool first = true; + foreach (const KUrl &url, urls) { + // set the first drop as the current paper, just add the rest to the roll + addUrl(url, first); + first = false; + } +} + +void Image::addUrl(const KUrl &url, bool setAsCurrent) +{ + ///kDebug() << "droppage!" << url << url.isLocalFile(); + if (url.isLocalFile()) { + const QString path = url.toLocalFile(); + if (setAsCurrent) { + setWallpaper(path); + } else { + if (m_mode != "SingleImage") { + // it's a slide show, add it to the slide show + m_slideshowBackgrounds.append(path); + m_unseenSlideshowBackgrounds.append(path); + } + + // always add it to the user papers, though + if (!m_usersWallpapers.contains(path)) { + m_usersWallpapers.append(path); + } + } + } else { + QString wallpaperPath = KGlobal::dirs()->locateLocal("wallpaper", url.fileName()); + + if (!wallpaperPath.isEmpty()) { + KIO::FileCopyJob *job = KIO::file_copy(url, KUrl(wallpaperPath)); + if (setAsCurrent) { + connect(job, SIGNAL(result(KJob*)), this, SLOT(setWallpaperRetrieved(KJob*))); + } else { + connect(job, SIGNAL(result(KJob*)), this, SLOT(addWallpaperRetrieved(KJob*))); + } + } + } +} + +void Image::setWallpaperRetrieved(KJob *job) +{ + KIO::FileCopyJob *copyJob = qobject_cast(job); + if (copyJob && !copyJob->error()) { + setWallpaper(copyJob->destUrl().toLocalFile()); + } +} + +void Image::addWallpaperRetrieved(KJob *job) +{ + KIO::FileCopyJob *copyJob = qobject_cast(job); + if (copyJob && !copyJob->error()) { + addUrl(copyJob->destUrl(), false); + } +} + +void Image::setWallpaper(const QString &path) +{ + if (m_mode == "SingleImage") { + m_wallpaper = path; + setSingleImage(); + } else { + m_slideshowBackgrounds.append(path); + m_unseenSlideshowBackgrounds.clear(); + m_currentSlide = -1; + nextSlide(); + updateWallpaperActions(); + } + + if (!m_usersWallpapers.contains(path)) { + m_usersWallpapers.append(path); + } +} + +void Image::startSlideshow() +{ + if (isPreviewing()) { + return; + } + + if (m_findToken.isEmpty()) { + // populate background list + m_timer.stop(); + m_slideshowBackgrounds.clear(); + m_unseenSlideshowBackgrounds.clear(); + BackgroundFinder *finder = new BackgroundFinder(this, m_dirs); + m_findToken = finder->token(); + connect(finder, SIGNAL(backgroundsFound(QStringList,QString)), this, SLOT(backgroundsFound(QStringList,QString))); + finder->start(); + //TODO: what would be cool: paint on the wallpaper itself a busy widget and perhaps some text + //about loading wallpaper slideshow while the thread runs + } else { + m_scanDirty = true; + } +} + +void Image::backgroundsFound(const QStringList &paths, const QString &token) +{ + if (token != m_findToken) { + return; + } + + m_findToken.clear(); + + if(m_scanDirty) { + m_scanDirty = false; + startSlideshow(); + return; + } + + m_slideshowBackgrounds = paths; + m_unseenSlideshowBackgrounds.clear(); + updateWallpaperActions(); + // start slideshow + if (m_slideshowBackgrounds.isEmpty()) { + // no image has been found, which is quite weird... try again later (this is useful for events which + // are not detected by KDirWatch, like a NFS directory being mounted) + QTimer::singleShot(1000, this, SLOT(startSlideshow())); + m_pixmap = QPixmap(); + emit update(boundingRect()); + } else { + m_currentSlide = -1; + nextSlide(); + m_timer.start(m_delay * 1000); + } +} + +void Image::updateWallpaperActions() +{ + if (m_nextWallpaperAction) { + m_nextWallpaperAction->setEnabled(!m_slideshowBackgrounds.isEmpty()); + } + + if (m_openImageAction) { + m_openImageAction->setEnabled(!m_slideshowBackgrounds.isEmpty()); + } +} + +void Image::getNewWallpaper() +{ + if (!m_newStuffDialog) { + m_newStuffDialog = new KNS3::DownloadDialog( "wallpaper.knsrc", m_configWidget ); + connect(m_newStuffDialog.data(), SIGNAL(accepted()), SLOT(newStuffFinished())); + } + m_newStuffDialog.data()->show(); +} + +void Image::newStuffFinished() +{ + if (m_model && (!m_newStuffDialog || m_newStuffDialog.data()->changedEntries().size() > 0)) { + m_model->reload(); + } +} + +void Image::colorChanged(const QColor& color) +{ + m_color = color; + setSingleImage(); +} + +void Image::pictureChanged(const QModelIndex &index) +{ + if (index.row() == -1 || !m_model) { + return; + } + + Plasma::Package *b = m_model->package(index.row()); + if (!b) { + return; + } + + if (b->structure()->contentsPrefixPaths().isEmpty()) { + // it's not a full package, but a single paper + m_wallpaper = b->filePath("preferred"); + } else { + m_wallpaper = b->path(); + } +} + +void Image::positioningChanged(int index) +{ + if (m_mode == "SingleImage") { + setResizeMethodHint((ResizeMethod)m_uiImage.m_resizeMethod->itemData(index).value()); + setSingleImage(); + } else { + setResizeMethodHint((ResizeMethod)m_uiSlideshow.m_resizeMethod->itemData(index).value()); + startSlideshow(); + } + + //Color button is useless with some resize methods + const bool colorizable = resizeMethodHint() == MaxpectResize || resizeMethodHint() == CenteredResize; + if (m_mode == "SingleImage") { + m_uiImage.m_color->setEnabled(colorizable); + } else { + m_uiSlideshow.m_color->setEnabled(colorizable); + } + + if (m_model) { + m_model->setResizeMethod(resizeMethodHint()); + } +} + +void Image::showFileDialog() +{ + if (!m_dialog) { + KUrl baseUrl; + if(m_wallpaper.indexOf(QDir::homePath()) > -1){ + baseUrl = KUrl(m_wallpaper); + } + + m_dialog = new KFileDialog(baseUrl, "*.png *.jpeg *.jpg *.xcf *.svg *.svgz *.bmp", m_configWidget); + m_dialog->setOperationMode(KFileDialog::Opening); + m_dialog->setInlinePreviewShown(true); + m_dialog->setCaption(i18n("Select Wallpaper Image File")); + m_dialog->setModal(false); + + connect(m_dialog, SIGNAL(okClicked()), this, SLOT(wallpaperBrowseCompleted())); + connect(m_dialog, SIGNAL(destroyed(QObject*)), this, SLOT(fileDialogFinished())); + } + + m_dialog->show(); + m_dialog->raise(); + m_dialog->activateWindow(); +} + +void Image::fileDialogFinished() +{ + m_dialog = 0; +} + +void Image::wallpaperBrowseCompleted() +{ + Q_ASSERT(m_model); + + const QFileInfo info(m_dialog->selectedFile()); + + //the full file path, so it isn't broken when dealing with symlinks + const QString wallpaper = info.canonicalFilePath(); + + if (wallpaper.isEmpty()) { + return; + } + + if (m_model->contains(wallpaper)) { + m_uiImage.m_view->setCurrentIndex(m_model->indexOf(wallpaper)); + return; + } + + // add background to the model + m_model->addBackground(wallpaper); + + // select it + QModelIndex index = m_model->indexOf(wallpaper); + if (index.isValid()) { + m_uiImage.m_view->setCurrentIndex(index); + pictureChanged(index); + modified(); + } + + // save it + m_usersWallpapers << wallpaper; +} + +void Image::nextSlide() +{ + if (m_slideshowBackgrounds.isEmpty()) { + return; + } + + QString previousPath; + if (m_currentSlide > -1 && m_currentSlide < m_unseenSlideshowBackgrounds.size()) { + previousPath = m_unseenSlideshowBackgrounds.takeAt(m_currentSlide); + } + + if (m_unseenSlideshowBackgrounds.isEmpty()) { + m_unseenSlideshowBackgrounds = m_slideshowBackgrounds; + + // We're filling the queue again, make sure we can't pick up again + // the last one picked from the previous set + if (!previousPath.isEmpty()) { + m_unseenSlideshowBackgrounds.removeAll(previousPath); + + // prevent empty list + if (m_unseenSlideshowBackgrounds.isEmpty()) { + m_unseenSlideshowBackgrounds = m_slideshowBackgrounds; + } + } + } + + m_currentSlide = KRandom::random() % m_unseenSlideshowBackgrounds.size(); + const QString currentPath = m_unseenSlideshowBackgrounds.at(m_currentSlide); + + if (!m_wallpaperPackage) { + m_wallpaperPackage = new Plasma::Package(currentPath, packageStructure(this)); + } else { + m_wallpaperPackage->setPath(currentPath); + } + + m_timer.stop(); + renderWallpaper(m_wallpaperPackage->filePath("preferred")); + m_timer.start(m_delay * 1000); +} + +void Image::openSlide() +{ + if (!m_wallpaperPackage) { + return; + } + + // open in image viewer + KUrl filepath(m_wallpaperPackage->filePath("preferred")); + //kDebug() << "opening file " << filepath.path(); + new KRun(filepath, NULL); +} + +void Image::renderWallpaper(const QString& image) +{ + if (!image.isEmpty()) { + m_img = image; + } + + if (m_img.isEmpty()) { + return; + } + + m_delayedRenderTimer.start(100); +} + +void Image::actuallyRenderWallpaper() +{ + render(m_img, m_size, resizeMethodHint(), m_color); +} + +void Image::pathCreated(const QString &path) +{ + if (!m_slideshowBackgrounds.contains(path)) { + QFileInfo fileInfo(path); + if (fileInfo.isFile() && BackgroundFinder::suffixes().contains(fileInfo.suffix().toLower())) { + m_slideshowBackgrounds.append(path); + m_unseenSlideshowBackgrounds.append(path); + if (m_slideshowBackgrounds.count() == 1) { + nextSlide(); + } + } + } +} + +void Image::pathDirty(const QString &path) +{ + if (path == m_img) { + renderWallpaper(path); + } +} + +void Image::pathDeleted(const QString &path) +{ + if (m_slideshowBackgrounds.removeAll(path)) { + m_unseenSlideshowBackgrounds.removeAll(path); + if (path == m_img) { + nextSlide(); + } + } +} + +void Image::wallpaperRenderComplete(const QImage &img) +{ + m_oldPixmap = m_pixmap; + m_oldFadedPixmap = m_oldPixmap; + m_pixmap = QPixmap::fromImage(img); + + if (!m_oldPixmap.isNull()) { + if (!m_animation) { + m_animation = new QPropertyAnimation(this, "fadeValue"); + m_animation->setProperty("easingCurve", QEasingCurve::OutQuad); + m_animation->setProperty("duration", 300); + m_animation->setProperty("startValue", 0.2); + m_animation->setProperty("endValue", 1.0); + } + + m_animation->start(); + setFadeValue(0.1); + } else { + emit update(boundingRect()); + } +} + +void Image::updateScreenshot(QPersistentModelIndex index) +{ + m_uiImage.m_view->update(index); +} + +qreal Image::fadeValue() const +{ + return m_fadeValue; +} + +void Image::setFadeValue(qreal value) +{ + m_fadeValue = value; + + //If we are done, delete the pixmaps and don't draw. + if (qFuzzyCompare(m_fadeValue, qreal(1.0))) { + m_oldFadedPixmap = QPixmap(); + m_oldPixmap = QPixmap(); + emit update(boundingRect()); + return; + } + + //Create the faded image. + m_oldFadedPixmap.fill(Qt::transparent); + + QPainter p; + p.begin(&m_oldFadedPixmap); + p.drawPixmap(0, 0, m_oldPixmap); + + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + p.fillRect(m_oldFadedPixmap.rect(), QColor(0, 0, 0, 254 * (1-m_fadeValue)));//255*((150 - m_fadeValue)/150))); + + p.end(); + + emit update(boundingRect()); +} + +//FIXME: we have to save the configuration also when the dialog cancel button is clicked. +void Image::removeWallpaper(QString name) +{ + int wallpaperIndex = m_usersWallpapers.indexOf(name); + if (wallpaperIndex >= 0){ + m_usersWallpapers.removeAt(wallpaperIndex); + m_model->reload(m_usersWallpapers); + //TODO: save the configuration in the right way + emit settingsChanged(true); + } +} + +bool Image::checkSize() +{ + if (m_size != boundingRect().size().toSize()) { + calculateGeometry(); + if (!m_size.isEmpty()) { // We have a size set + if (m_mode == "SingleImage") { + // make sure we pick the best size wallpaper for the new size + setSingleImage(); + } else { + renderWallpaper(); + } + //kDebug() << "re-rendering"; + } + + return false; + } + + return true; +} + +#include "image.moc" diff --git a/plasma/generic/wallpapers/image/image.h b/plasma/generic/wallpapers/image/image.h new file mode 100644 index 00000000..49271e8f --- /dev/null +++ b/plasma/generic/wallpapers/image/image.h @@ -0,0 +1,142 @@ +/* + Copyright (c) 2007 Paolo Capriotti + Copyright (c) 2008 by Petri Damsten + + 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. +*/ + +#ifndef IMAGE_HEADER +#define IMAGE_HEADER + +#include +#include +#include + +#include +#include + +#include "ui_imageconfig.h" +#include "ui_slideshowconfig.h" + +class QPropertyAnimation; + +class KDirWatch; +class KFileDialog; +class KJob; + +namespace KNS3 { + class DownloadDialog; +} + +class BackgroundListModel; + +class Image : public Plasma::Wallpaper +{ + Q_OBJECT + Q_PROPERTY(qreal fadeValue READ fadeValue WRITE setFadeValue) + + public: + Image(QObject* parent, const QVariantList& args); + ~Image(); + + virtual void save(KConfigGroup &config); + virtual void paint(QPainter* painter, const QRectF& exposedRect); + virtual QWidget* createConfigurationInterface(QWidget* parent); + void updateScreenshot(QPersistentModelIndex index); + qreal fadeValue() const; + + signals: + void settingsChanged(bool); + + protected slots: + void removeWallpaper(QString name); + void timeChanged(const QTime& time); + void positioningChanged(int index); + void addDir(); + void removeDir(); + void getNewWallpaper(); + void colorChanged(const QColor& color); + void pictureChanged(const QModelIndex &); + void wallpaperBrowseCompleted(); + void nextSlide(); + /** + * Open the current slide in the default image application + */ + void openSlide(); + void wallpaperRenderComplete(const QImage &img); + void showFileDialog(); + void setFadeValue(qreal value); + void configWidgetDestroyed(); + void startSlideshow(); + void modified(); + void fileDialogFinished(); + void addUrl(const KUrl &url, bool setAsCurrent); + void addUrls(const KUrl::List &urls); + void setWallpaper(const QString &path); + void setWallpaperRetrieved(KJob *job); + void addWallpaperRetrieved(KJob *job); + void newStuffFinished(); + void setConfigurationInterfaceModel(); + void updateDirs(); + void updateDirWatch(const QStringList &newDirs); + void addDirFromSelectionDialog(); + void systemCheckBoxToggled(bool); + void downloadedCheckBoxToggled(bool); + void pathCreated(const QString &path); + void pathDirty(const QString &path); + void pathDeleted(const QString &path); + void backgroundsFound(const QStringList &paths, const QString &token); + bool checkSize(); + void actuallyRenderWallpaper(); + + protected: + void init(const KConfigGroup &config); + void renderWallpaper(const QString& image = QString()); + void suspendStartup(bool suspend); // for ksmserver + void calculateGeometry(); + void setSingleImage(); + void updateWallpaperActions(); + void useSingleImageDefaults(); + + private: + static bool s_startupResumed; + static bool s_startupSuspended; + + int m_delay; + QStringList m_dirs; + QString m_wallpaper; + QColor m_color; + QStringList m_usersWallpapers; + KDirWatch *m_dirWatch; + bool m_scanDirty; + + QWidget* m_configWidget; + Ui::ImageConfig m_uiImage; + Ui::SlideshowConfig m_uiSlideshow; + QString m_mode; + Plasma::Package *m_wallpaperPackage; + QStringList m_slideshowBackgrounds; + QStringList m_unseenSlideshowBackgrounds; + QTimer m_timer; + QTimer m_delayedRenderTimer; + QPixmap m_pixmap; + QPixmap m_oldPixmap; + QPixmap m_oldFadedPixmap; + int m_currentSlide; + qreal m_fadeValue; + QPropertyAnimation *m_animation; + BackgroundListModel *m_model; + KFileDialog *m_dialog; + QSize m_size; + QString m_img; + QWeakPointer m_newStuffDialog; + QString m_findToken; + + QAction* m_nextWallpaperAction; + QAction* m_openImageAction; +}; + +#endif diff --git a/plasma/generic/wallpapers/image/imageconfig.ui b/plasma/generic/wallpapers/image/imageconfig.ui new file mode 100644 index 00000000..7c0dc2f6 --- /dev/null +++ b/plasma/generic/wallpapers/image/imageconfig.ui @@ -0,0 +1,194 @@ + + + ImageConfig + + + + 0 + 0 + 568 + 379 + + + + + + + + 300 + 220 + + + + QListView::Static + + + QListView::Adjust + + + QListView::Batched + + + 2 + + + QListView::IconMode + + + false + + + + + + + P&ositioning: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_resizeMethod + + + + + + + &Color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_color + + + + + + + + + + 0 + 0 + + + + Change wallpaper frame color + + + Change the color of the frame that it may be visible when the wallpaper is centered or scaled with the same proportions. + + + + 70 + 90 + 130 + + + + + 70 + 90 + 130 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 187 + 17 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Open... + + + + + + + + + Get New Wallpapers... + + + + + + + + ItemsView + QListView +
itemsview.h
+
+ + KPushButton + QPushButton +
kpushbutton.h
+
+ + KColorButton + QPushButton +
kcolorbutton.h
+
+
+ + +
diff --git a/plasma/generic/wallpapers/image/itemsview.cpp b/plasma/generic/wallpapers/image/itemsview.cpp new file mode 100644 index 00000000..281b19ab --- /dev/null +++ b/plasma/generic/wallpapers/image/itemsview.cpp @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010 Frederik Gladhorn + + 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, see . +*/ + +#include "itemsview.h" + +#include + +ItemsView::ItemsView(QWidget* parent) + : QListView(parent) +{ +} + +void ItemsView::wheelEvent(QWheelEvent* event) +{ + // this is a workaround because scrolling by mouse wheel is broken in Qt list views for big items + verticalScrollBar()->setSingleStep(10); + QListView::wheelEvent(event); +} diff --git a/plasma/generic/wallpapers/image/itemsview.h b/plasma/generic/wallpapers/image/itemsview.h new file mode 100644 index 00000000..1a497357 --- /dev/null +++ b/plasma/generic/wallpapers/image/itemsview.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010 Frederik Gladhorn + + 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, see . +*/ + +#ifndef ITEMSVIEW_H +#define ITEMSVIEW_H + +#include + +class ItemsView: public QListView +{ +public: + ItemsView(QWidget* parent = 0); + +protected: + void wheelEvent(QWheelEvent* event); +}; + +#endif diff --git a/plasma/generic/wallpapers/image/plasma-wallpaper-image.desktop b/plasma/generic/wallpapers/image/plasma-wallpaper-image.desktop new file mode 100644 index 00000000..c4a633f0 --- /dev/null +++ b/plasma/generic/wallpapers/image/plasma-wallpaper-image.desktop @@ -0,0 +1,341 @@ +[Desktop Entry] +Type=Service +Name=Image +Name[ar]=صورة +Name[ast]=Imaxe +Name[be@latin]=Vyjava +Name[bg]=Изображение +Name[bn]=ছবি +Name[bn_IN]=ছবি +Name[bs]=slika +Name[ca]=Imatge +Name[ca@valencia]=Imatge +Name[cs]=Obrázek +Name[csb]=Òbrôzk +Name[da]=Billede +Name[de]=Bild +Name[el]=Εικόνα +Name[en_GB]=Image +Name[eo]=Bildo +Name[es]=Imagen +Name[et]=Pilt +Name[eu]=Irudia +Name[fa]=تصویر +Name[fi]=Kuva +Name[fr]=Image +Name[fy]=Ofbylding +Name[ga]=Íomhá +Name[gl]=Imaxe +Name[gu]=ચિત્ર +Name[he]=תמונה +Name[hi]=छवि +Name[hne]=फोटो +Name[hr]=Slika +Name[hu]=Kép +Name[ia]=Image +Name[id]=Gambar +Name[is]=Mynd +Name[it]=Immagine +Name[ja]=画像 +Name[ka]=გამოსახულება +Name[kk]=Кескіні +Name[km]=រូបភាព +Name[kn]=ಬಿಂಬ (ಇಮೇಜ್) +Name[ko]=그림 +Name[ku]=Wêne +Name[lt]=Paveikslėlis +Name[lv]=Attēls +Name[mai]=चित्र +Name[mk]=Слика +Name[ml]=ചിത്രം +Name[mr]=प्रतिमा +Name[nb]=Bilde +Name[nds]=Bild +Name[nl]=Afbeelding +Name[nn]=Bilete +Name[or]=ପ୍ରତିଛବି +Name[pa]=ਚਿੱਤਰ +Name[pl]=Obraz +Name[pt]=Imagem +Name[pt_BR]=Imagem +Name[ro]=Imagine +Name[ru]=Изображение +Name[si]=පිංතූරය +Name[sk]=Obrázok +Name[sl]=Slika +Name[sr]=слика +Name[sr@ijekavian]=слика +Name[sr@ijekavianlatin]=slika +Name[sr@latin]=slika +Name[sv]=Bild +Name[ta]=Image +Name[tg]=Тасвир +Name[th]=ภาพ +Name[tr]=Resim +Name[ug]=سۈرەت +Name[uk]=Зображення +Name[vi]=Ảnh +Name[wa]=Imådje +Name[x-test]=xxImagexx +Name[zh_CN]=图像 +Name[zh_TW]=影像 +Icon=image-jpeg +ServiceTypes=Plasma/Wallpaper +Actions=SingleImage;Slideshow; + +X-KDE-Library=plasma_wallpaper_image +X-KDE-PluginInfo-Author=Petri Damstén +X-KDE-PluginInfo-Email=damu@iki.fi +X-KDE-PluginInfo-Name=image +X-KDE-PluginInfo-Version=pre0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +MimeType=image/jpeg;image/png;image/svg+xml;image/svg+xml-compressed;image/bmp; +X-Plasma-DropMimeTypes=image/jpeg,image/png,image/svg+xml,image/svg+xml-compressed,image/bmp + +[Desktop Action SingleImage] +Name=Image +Name[ar]=صورة +Name[ast]=Imaxe +Name[be@latin]=Vyjava +Name[bg]=Изображение +Name[bn]=ছবি +Name[bn_IN]=ছবি +Name[bs]=slika +Name[ca]=Imatge +Name[ca@valencia]=Imatge +Name[cs]=Obrázek +Name[csb]=Òbrôzk +Name[da]=Billede +Name[de]=Bild +Name[el]=Εικόνα +Name[en_GB]=Image +Name[eo]=Bildo +Name[es]=Imagen +Name[et]=Pilt +Name[eu]=Irudia +Name[fa]=تصویر +Name[fi]=Kuva +Name[fr]=Image +Name[fy]=Ofbylding +Name[ga]=Íomhá +Name[gl]=Imaxe +Name[gu]=ચિત્ર +Name[he]=תמונה +Name[hi]=छवि +Name[hne]=फोटो +Name[hr]=Slika +Name[hu]=Kép +Name[ia]=Image +Name[id]=Gambar +Name[is]=Mynd +Name[it]=Immagine +Name[ja]=画像 +Name[ka]=გამოსახულება +Name[kk]=Кескіні +Name[km]=រូបភាព +Name[kn]=ಬಿಂಬ (ಇಮೇಜ್) +Name[ko]=그림 +Name[ku]=Wêne +Name[lt]=Paveikslėlis +Name[lv]=Attēls +Name[mai]=चित्र +Name[mk]=Слика +Name[ml]=ചിത്രം +Name[mr]=प्रतिमा +Name[nb]=Bilde +Name[nds]=Bild +Name[nl]=Afbeelding +Name[nn]=Bilete +Name[or]=ପ୍ରତିଛବି +Name[pa]=ਚਿੱਤਰ +Name[pl]=Obraz +Name[pt]=Imagem +Name[pt_BR]=Imagem +Name[ro]=Imagine +Name[ru]=Изображение +Name[si]=පිංතූරය +Name[sk]=Obrázok +Name[sl]=Slika +Name[sr]=слика +Name[sr@ijekavian]=слика +Name[sr@ijekavianlatin]=slika +Name[sr@latin]=slika +Name[sv]=Bild +Name[ta]=Image +Name[tg]=Тасвир +Name[th]=ภาพ +Name[tr]=Resim +Name[ug]=سۈرەت +Name[uk]=Зображення +Name[vi]=Ảnh +Name[wa]=Imådje +Name[x-test]=xxImagexx +Name[zh_CN]=图像 +Name[zh_TW]=影像 +Icon=image-jpeg +Comment=A single image +Comment[bs]=Prosta slika +Comment[ca]=Una única imatge +Comment[ca@valencia]=Una única imatge +Comment[cs]=Jeden obrázek +Comment[da]=Et enkelt billede +Comment[de]=Ein einzelnes Bild +Comment[el]=Μια εικόνα μόνο +Comment[en_GB]=A single image +Comment[es]=Una única imagen +Comment[et]=Üks pilt +Comment[eu]=Irudi bakuna +Comment[fi]=Yksi kuva +Comment[fr]=Une image simple +Comment[gl]=Unha imaxe. +Comment[hu]=Egy egyszerű kép +Comment[ia]=Un imagine singule +Comment[kk]=Жалғыз кескін +Comment[ko]=단일 그림 +Comment[nb]=Ett enkelt bilde +Comment[nds]=En eenfach Bild +Comment[nl]=Een enkele afbeelding +Comment[pa]=ਇੱਕਲਾ ਚਿੱਤਰ +Comment[pl]=Pojedynczy obraz +Comment[pt]=Uma imagem simples +Comment[pt_BR]=Imagem simples +Comment[ru]=Одно изображение +Comment[sk]=Jednoduchý obrázok +Comment[sl]=Ena slika +Comment[sr]=Једна слика +Comment[sr@ijekavian]=Једна слика +Comment[sr@ijekavianlatin]=Jedna slika +Comment[sr@latin]=Jedna slika +Comment[sv]=En enda bild +Comment[tr]=Tek bir resim +Comment[uk]=Окреме зображення +Comment[x-test]=xxA single imagexx +Comment[zh_CN]=单个图像 +Comment[zh_TW]=單一影像 +# Dummy +Exec=plasma + +[Desktop Action Slideshow] +Name=Slideshow +Name[ar]=عرض شرائح +Name[ast]=Presentación +Name[be@latin]=Słajdy +Name[bg]=Прожекция +Name[bn]=স্লাইড-শো +Name[bn_IN]=স্লাইড-শো +Name[bs]=slajd‑šou +Name[ca]=Passi de diapositives +Name[ca@valencia]=Passe de diapositives +Name[cs]=Promítání +Name[csb]=Pòkôz slajdów +Name[da]=Diasshow +Name[de]=Diaschau +Name[el]=Προβολή σλάιντ +Name[en_GB]=Slideshow +Name[eo]=Bildoserio +Name[es]=Presentación +Name[et]=Slaidiseanss +Name[eu]=Diaporama +Name[fi]=Diaesitys +Name[fr]=Diaporama +Name[fy]=Diafoarstelling +Name[ga]=Taispeántas Sleamhnán +Name[gl]=Presentación +Name[gu]=સ્લાઇડશો +Name[he]=מצגת +Name[hi]=स्लाइड-शो +Name[hne]=स्लाइडसो +Name[hr]=Prezentacija +Name[hu]=Diabemutató +Name[ia]=Slideshow (Sequentia de diapositivas) +Name[id]=Salindia +Name[is]=Skyggnusýning +Name[it]=Presentazione +Name[ja]=スライドショー +Name[kk]=Слайд көрсетілімі +Name[km]=បញ្ចាំង​ស្លាយ +Name[kn]=ಚಿತ್ರಫಲಕ ಪ್ರದರ್ಶನ (ಸ್ಲೈಡ್ ಶೋ) +Name[ko]=슬라이드 쇼 +Name[ku]=NîşandanaSlaydê +Name[lt]=Skaidrių peržiūra +Name[lv]=Slīdrāde +Name[mai]=स्लाइडशो +Name[mk]=Слајдшоу +Name[ml]=മാറുന്ന ചിത്രങ്ങള്‍ +Name[mr]=स्लाइडशो +Name[nb]=Lysbildevisning +Name[nds]=Diaschau +Name[nl]=Diavoorstelling +Name[nn]=Lysbiletvising +Name[or]=ସ୍ଲାଇଡ଼ ଦୃଶ୍ୟ +Name[pa]=ਸਲਾਈਡ-ਸ਼ੋ +Name[pl]=Pokaz slajdów +Name[pt]=Apresentação +Name[pt_BR]=Apresentação de slides +Name[ro]=Diapozitiv +Name[ru]=Слайд-шоу +Name[si]=ස්ලයිඩ් දසුන +Name[sk]=Prezentácia +Name[sl]=Predstavitev +Name[sr]=слајд‑шоу +Name[sr@ijekavian]=слајд‑шоу +Name[sr@ijekavianlatin]=slajd‑šou +Name[sr@latin]=slajd‑šou +Name[sv]=Bildspel +Name[ta]=Slideshow +Name[tg]=Намоиши слайдҳо +Name[th]=นำเสนอภาพนิ่ง +Name[tr]=Slayt Gösterisi +Name[ug]=تام تەسۋىرى +Name[uk]=Показ слайдів +Name[wa]=Diaporama +Name[x-test]=xxSlideshowxx +Name[zh_CN]=幻灯显示 +Name[zh_TW]=投影播放 +Comment=Cycles through a set of images +Comment[bs]=Ciklus kroz skup slika +Comment[ca]=Passa a través d'un conjunt d'imatges +Comment[ca@valencia]=Passa a través d'un conjunt d'imatges +Comment[cs]=Prochází sadu obrázků +Comment[da]=Gennemgår et sæt af billeder +Comment[de]=Durchläuft einen Satz Bilder +Comment[el]=Επανάληψη μιας σειράς εικόνων +Comment[en_GB]=Cycles through a set of images +Comment[es]=Repetir un conjunto de imágenes +Comment[et]=Pildivaliku läbikerimine +Comment[eu]=Irudi multzo batekin zikloa osatzen du +Comment[fi]=Käy läpi kuvasarjaa +Comment[fr]=Un cycle d'une série d'images +Comment[gl]=Mostra unha serie de imaxes unha detrás da outra. +Comment[hu]=Ciklikusan változtatja a képek halmazát +Comment[ia]=Il cycla trans un unsimul de imagines +Comment[kk]=Кескін жиынын қайталай беру +Comment[ko]=여러 그림 사이를 순환하기 +Comment[nb]=Roterer gjennom et sett bilder +Comment[nds]=Geiht en Sett vun Biller dör +Comment[nl]=Circuleert door een set afbeeldingen +Comment[pa]=ਚਿੱਤਰਾਂ ਦੇ ਸਮੂਹ ਵਿੱਚੋਂ +Comment[pl]=Krąży po zestawie obrazów +Comment[pt]=Percorre um conjunto de imagens +Comment[pt_BR]=Percorre um conjunto de imagens +Comment[ru]=Циклическая смена изображений +Comment[sk]=Cyklus cez sadu obrázkov +Comment[sl]=Kroži po naboru slik +Comment[sr]=Кружење кроз скуп слика +Comment[sr@ijekavian]=Кружење кроз скуп слика +Comment[sr@ijekavianlatin]=Kruženje kroz skup slika +Comment[sr@latin]=Kruženje kroz skup slika +Comment[sv]=Går igenom en uppsättning bilder +Comment[tr]=Birden fazla resim arasında gezinir +Comment[uk]=Циклічне відтворення набору зображень +Comment[x-test]=xxCycles through a set of imagesxx +Comment[zh_CN]=在一系列图像间循环 +Comment[zh_TW]=許多影像循環播放 +Icon=folder-image +# Dummy +Exec=plasma + diff --git a/plasma/generic/wallpapers/image/removebutton.cpp b/plasma/generic/wallpapers/image/removebutton.cpp new file mode 100644 index 00000000..dbe7e7e2 --- /dev/null +++ b/plasma/generic/wallpapers/image/removebutton.cpp @@ -0,0 +1,230 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * Copyright (C) 2010 by Davide Bettio * + * * + * 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 "removebutton.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +RemoveButton::RemoveButton(QWidget* parent) : + QAbstractButton(parent), + m_isHovered(false), + m_leftMouseButtonPressed(false), + m_fadingValue(0), + m_icon(), + m_fadingTimeLine(0) +{ + setFocusPolicy(Qt::NoFocus); + parent->installEventFilter(this); + resize(sizeHint()); + connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), + this, SLOT(refreshIcon())); + + m_icon = KIconLoader::global()->loadIcon("edit-delete", + KIconLoader::NoGroup, + qMin(width(), height())); + setToolTip(i18n("Remove from list")); +} + +RemoveButton::~RemoveButton() +{ +} + +QSize RemoveButton::sizeHint() const +{ + return QSize(32, 32); +} + +void RemoveButton::reset() +{ + m_itemName = ""; + hide(); +} + +void RemoveButton::setVisible(bool visible) +{ + QAbstractButton::setVisible(visible); + + stopFading(); + if (visible) { + startFading(); + } + +} + +bool RemoveButton::eventFilter(QObject* obj, QEvent* event) +{ + if (obj == parent()) { + switch (event->type()) { + case QEvent::Leave: + hide(); + break; + + case QEvent::MouseMove: + if (m_leftMouseButtonPressed) { + // Don't forward mouse move events to the viewport, + // otherwise a rubberband selection will be shown when + // clicking on the selection removeButton and moving the mouse + // above the viewport. + return true; + } + break; + + default: + break; + } + } + + return QAbstractButton::eventFilter(obj, event); +} + +void RemoveButton::enterEvent(QEvent* event) +{ + QAbstractButton::enterEvent(event); + + // if the mouse cursor is above the selection removeButton, display + // it immediately without fading timer + m_isHovered = true; + if (m_fadingTimeLine != 0) { + m_fadingTimeLine->stop(); + } + m_fadingValue = 255; + + update(); +} + +void RemoveButton::leaveEvent(QEvent* event) +{ + QAbstractButton::leaveEvent(event); + m_isHovered = false; + update(); +} + +void RemoveButton::mousePressEvent(QMouseEvent* event) +{ + QAbstractButton::mousePressEvent(event); + m_leftMouseButtonPressed = (event->buttons() & Qt::LeftButton); +} + +void RemoveButton::mouseReleaseEvent(QMouseEvent* event) +{ + QAbstractButton::mouseReleaseEvent(event); + m_leftMouseButtonPressed = (event->buttons() & Qt::LeftButton); +} + +void RemoveButton::resizeEvent(QResizeEvent* event) +{ + QAbstractButton::resizeEvent(event); + + m_icon = KIconLoader::global()->loadIcon("edit-delete", + KIconLoader::NoGroup, + qMin(width(), height())); + update(); +} + +void RemoveButton::paintEvent(QPaintEvent* event) +{ + QPainter painter(this); + painter.setClipRect(event->rect()); + + // draw the icon overlay + if (m_isHovered) { + KIconEffect iconEffect; + QPixmap activeIcon = iconEffect.apply(m_icon, KIconLoader::Desktop, KIconLoader::ActiveState); + painter.drawPixmap(0, 0, activeIcon); + } else { + if (m_fadingValue < 255) { + // apply an alpha mask respecting the fading value to the icon + QPixmap icon = m_icon; + QPixmap alphaMask(icon.width(), icon.height()); + const QColor color(m_fadingValue, m_fadingValue, m_fadingValue); + alphaMask.fill(color); + icon.setAlphaChannel(alphaMask); + painter.drawPixmap(0, 0, icon); + } else { + // no fading is required + painter.drawPixmap(0, 0, m_icon); + } + } +} + +void RemoveButton::setFadingValue(int value) +{ + m_fadingValue = value; + if (m_fadingValue >= 255) { + Q_ASSERT(m_fadingTimeLine != 0); + m_fadingTimeLine->stop(); + } + update(); +} + +void RemoveButton::refreshIcon() +{ + m_icon = KIconLoader::global()->loadIcon("edit-delete", + KIconLoader::NoGroup, + qMin(width(), height())); + update(); +} + +void RemoveButton::startFading() +{ + Q_ASSERT(m_fadingTimeLine == 0); + + const bool animate = KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects; + const int duration = animate ? 600 : 1; + + m_fadingTimeLine = new QTimeLine(duration, this); + connect(m_fadingTimeLine, SIGNAL(frameChanged(int)), + this, SLOT(setFadingValue(int))); + m_fadingTimeLine->setFrameRange(0, 255); + m_fadingTimeLine->start(); + m_fadingValue = 0; +} + +void RemoveButton::stopFading() +{ + if (m_fadingTimeLine != 0) { + m_fadingTimeLine->stop(); + delete m_fadingTimeLine; + m_fadingTimeLine = 0; + } + m_fadingValue = 0; +} + +void RemoveButton::setItemName(const QString& name) +{ + m_itemName = name; +} + +QString RemoveButton::itemName() const +{ + return m_itemName; +} + +#include "removebutton.moc" diff --git a/plasma/generic/wallpapers/image/removebutton.h b/plasma/generic/wallpapers/image/removebutton.h new file mode 100644 index 00000000..536ebc9d --- /dev/null +++ b/plasma/generic/wallpapers/image/removebutton.h @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * Copyright (C) 2010 by Davide Bettio * + * * + * 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 SELECTIONTOGGLE_H +#define SELECTIONTOGGLE_H + +#include + +#include +#include + +class QTimeLine; + +/** + * @brief Toggle button for changing the selection of an hovered item. + * + * The removeButton button is visually invisible until it is displayed at least + * for one second. + * + * @see RemoveButtonManager + */ +class RemoveButton : public QAbstractButton +{ + Q_OBJECT + +public: + explicit RemoveButton(QWidget* parent); + virtual ~RemoveButton(); + virtual QSize sizeHint() const; + + /** + * Resets the selection removeButton so that it is hidden and stays + * visually invisible for at least one second after it is shown again. + */ + void reset(); + void setItemName(const QString& name); + QString itemName() const; + +public slots: + virtual void setVisible(bool visible); + +protected: + virtual bool eventFilter(QObject* obj, QEvent* event); + virtual void enterEvent(QEvent* event); + virtual void leaveEvent(QEvent* event); + virtual void mousePressEvent(QMouseEvent* event); + virtual void mouseReleaseEvent(QMouseEvent* event); + virtual void resizeEvent(QResizeEvent* event); + virtual void paintEvent(QPaintEvent* event); + +private slots: + /** + * Sets the alpha value for the fading animation and is + * connected with m_fadingTimeLine. + */ + void setFadingValue(int value); + + void refreshIcon(); + +private: + void startFading(); + void stopFading(); + +private: + bool m_isHovered; + bool m_leftMouseButtonPressed; + int m_fadingValue; + QPixmap m_icon; + QTimeLine* m_fadingTimeLine; + QString m_itemName; +}; + +#endif diff --git a/plasma/generic/wallpapers/image/removebuttonmanager.cpp b/plasma/generic/wallpapers/image/removebuttonmanager.cpp new file mode 100644 index 00000000..def212a9 --- /dev/null +++ b/plasma/generic/wallpapers/image/removebuttonmanager.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * Copyright (C) 2010 by Davide Bettio * + * * + * 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 "removebuttonmanager.h" + +#include "removebutton.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "backgroundlistmodel.h" +#include + +RemoveButtonManager::RemoveButtonManager(QAbstractItemView* parent, QStringList *list) : + QObject(parent), + m_view(parent), + m_removeButton(0), + m_connected(false) +{ + m_removableWallpapers = list; + + parent->setMouseTracking(true); + + connect(parent, SIGNAL(entered(QModelIndex)), + this, SLOT(slotEntered(QModelIndex))); + connect(parent, SIGNAL(viewportEntered()), + this, SLOT(slotViewportEntered())); + m_removeButton = new RemoveButton(m_view->viewport()); + m_removeButton->hide(); + connect(m_removeButton, SIGNAL(clicked(bool)), + this, SLOT(removeButtonClicked())); +} + +RemoveButtonManager::~RemoveButtonManager() +{ +} + +void RemoveButtonManager::slotEntered(const QModelIndex& index) +{ + m_removeButton->hide(); + + BackgroundListModel *model = static_cast(m_view->model()); + m_removeButton->setItemName(model->package(index.row())->filePath("preferred")); + + if (m_removableWallpapers->indexOf(m_removeButton->itemName()) < 0){ + return; + } + + if (!m_connected) { + connect(m_view->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(slotRowsRemoved(QModelIndex,int,int))); + connect(m_view->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); + m_connected = true; + } + + // increase the size of the removeButton for large items + const int height = m_view->iconSize().height(); + if (height >= KIconLoader::SizeEnormous) { + m_removeButton->resize(KIconLoader::SizeMedium, KIconLoader::SizeMedium); + } else if (height >= KIconLoader::SizeLarge) { + m_removeButton->resize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium); + } else { + m_removeButton->resize(KIconLoader::SizeSmall, KIconLoader::SizeSmall); + } + + const QRect rect = m_view->visualRect(index); + int x = rect.left(); + int y = rect.top(); + + m_removeButton->move(QPoint(x, y)); + m_removeButton->show(); +} + +void RemoveButtonManager::slotViewportEntered() +{ + m_removeButton->hide(); +} + +void RemoveButtonManager::slotRowsRemoved(const QModelIndex& parent, int start, int end) +{ + Q_UNUSED(parent); + Q_UNUSED(start); + Q_UNUSED(end); + m_removeButton->hide(); +} + +void RemoveButtonManager::removeButtonClicked() +{ + RemoveButton *removeButton = static_cast(sender()); + emit removeClicked(removeButton->itemName()); +} + +#include "removebuttonmanager.moc" diff --git a/plasma/generic/wallpapers/image/removebuttonmanager.h b/plasma/generic/wallpapers/image/removebuttonmanager.h new file mode 100644 index 00000000..691352fe --- /dev/null +++ b/plasma/generic/wallpapers/image/removebuttonmanager.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2008 by Peter Penz * + * Copyright (C) 2010 by Davide Bettio * + * * + * 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 SELECTIONMANAGER_H +#define SELECTIONMANAGER_H + +#include + +#include + +class QAbstractItemView; +class QModelIndex; +class QItemSelection; +class RemoveButton; + +/** + * @brief Allows to select and deselect items for item views. + * + * Whenever an item is hovered by the mouse, a removeButton button is shown + * which allows to select/deselect the current item. + */ +class RemoveButtonManager : public QObject +{ + Q_OBJECT + +public: + RemoveButtonManager(QAbstractItemView* parent, QStringList *list); + virtual ~RemoveButtonManager(); + +signals: + /** Is emitted if the selection has been changed by the removeButton button. */ + void selectionChanged(); + void removeClicked(QString item); + +private slots: + void slotEntered(const QModelIndex& index); + void slotViewportEntered(); + void slotRowsRemoved(const QModelIndex& parent, int start, int end); + void removeButtonClicked(); + +private: + const QModelIndex indexForUrl(const KUrl& url) const; + +private: + QAbstractItemView* m_view; + RemoveButton* m_removeButton; + bool m_connected; + QStringList *m_removableWallpapers; +}; + +#endif diff --git a/plasma/generic/wallpapers/image/slideshowconfig.ui b/plasma/generic/wallpapers/image/slideshowconfig.ui new file mode 100644 index 00000000..8990f3d1 --- /dev/null +++ b/plasma/generic/wallpapers/image/slideshowconfig.ui @@ -0,0 +1,330 @@ + + + SlideshowConfig + + + + 0 + 0 + 634 + 470 + + + + + + + &Positioning: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_resizeMethod + + + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + &Color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_color + + + + + + + + + Change wallpaper frame color + + + Change the color of the frame that it may be visible when the wallpaper is centered or scaled with the same proportions. + + + + 70 + 90 + 130 + + + + + 70 + 90 + 130 + + + + + + + + Qt::Horizontal + + + + 325 + 20 + + + + + + + + + + + 0 + 0 + + + + C&hange images every: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_slideshowDelay + + + + + + + + 0 + 0 + 0 + 2000 + 1 + 1 + + + + + + + QDateTimeEdit::HourSection + + + hh 'Hours' mm 'Mins' ss 'Secs' + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 12 + + + + + + + + <b>Images</b> + + + + + + + &System wallpapers: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_systemCheckBox + + + + + + + Use system-installed wallpapers in slideshow + + + + + + false + + + + + + + &My downloaded wallpapers: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_downloadedCheckBox + + + + + + + Use wallpapers I have downloaded with "Get New Wallpapers..." in slideshow + + + + + + false + + + + + + + Custom folders: + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + m_downloadedCheckBox + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + &Add Folder... + + + + + + + + 0 + 0 + + + + &Remove Folder + + + + + + + Download new wallpapers + + + Get New Wallpapers... + + + + + + + + + + KColorButton + QPushButton +
kcolorbutton.h
+
+ + KPushButton + QPushButton +
kpushbutton.h
+
+ + KListWidget + QListWidget +
klistwidget.h
+
+
+ + m_resizeMethod + m_color + m_slideshowDelay + m_systemCheckBox + m_downloadedCheckBox + m_dirlist + m_addDir + m_removeDir + m_newStuff + + + +
diff --git a/plasma/generic/wallpapers/image/wallpaper.knsrc b/plasma/generic/wallpapers/image/wallpaper.knsrc new file mode 100644 index 00000000..6d55e3d6 --- /dev/null +++ b/plasma/generic/wallpapers/image/wallpaper.knsrc @@ -0,0 +1,6 @@ +[KNewStuff3] +ProvidersUrl=http://download.kde.org/ocs/providers.xml +Categories=KDE Wallpaper 800x600,KDE Wallpaper 1024x768,KDE Wallpaper 1280x1024,KDE Wallpaper 1440x900,KDE Wallpaper 1600x1200,KDE Wallpaper 1680x1050,KDE Wallpaper 1920x1200,KDE Wallpaper 2560x1600,KDE Wallpaper (other),KDE Wallpaper (SVG) +StandardResource=wallpaper +Uncompress=archive + diff --git a/plasma/netbook/CMakeLists.txt b/plasma/netbook/CMakeLists.txt new file mode 100644 index 00000000..1eff685c --- /dev/null +++ b/plasma/netbook/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(applets) +add_subdirectory(containments) +add_subdirectory(dataengines) +add_subdirectory(desktoptheme) +if(NOT WIN32) +add_subdirectory(shell) +endif(NOT WIN32) diff --git a/plasma/netbook/applets/CMakeLists.txt b/plasma/netbook/applets/CMakeLists.txt new file mode 100644 index 00000000..04db5fff --- /dev/null +++ b/plasma/netbook/applets/CMakeLists.txt @@ -0,0 +1,5 @@ +if(X11_XTest_FOUND) + add_subdirectory(currentappcontrol) +endif(X11_XTest_FOUND) + +add_subdirectory(searchbox) diff --git a/plasma/netbook/applets/currentappcontrol/CMakeLists.txt b/plasma/netbook/applets/currentappcontrol/CMakeLists.txt new file mode 100644 index 00000000..46178ce3 --- /dev/null +++ b/plasma/netbook/applets/currentappcontrol/CMakeLists.txt @@ -0,0 +1,16 @@ +project(plasma-currentappcontrol) + + +set(currentappcontrol_SRCS currentappcontrol.cpp) + +kde4_add_ui_files(currentappcontrol_SRCS general.ui ) + +kde4_add_plugin(plasma_applet_currentappcontrol ${currentappcontrol_SRCS}) +target_link_libraries(plasma_applet_currentappcontrol + ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS} ${X11_XTest_LIB} ${X11_X11_LIB} ${X11_LIBS}) + +install(TARGETS plasma_applet_currentappcontrol + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-applet-currentappcontrol.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/netbook/applets/currentappcontrol/Messages.sh b/plasma/netbook/applets/currentappcontrol/Messages.sh new file mode 100644 index 00000000..45d44681 --- /dev/null +++ b/plasma/netbook/applets/currentappcontrol/Messages.sh @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma_applet_currentappcontrol.pot diff --git a/plasma/netbook/applets/currentappcontrol/currentappcontrol.cpp b/plasma/netbook/applets/currentappcontrol/currentappcontrol.cpp new file mode 100644 index 00000000..de8dc9ce --- /dev/null +++ b/plasma/netbook/applets/currentappcontrol/currentappcontrol.cpp @@ -0,0 +1,451 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * * + * 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 "currentappcontrol.h" + +//Qt +#include +#include +#include +#include +#include + +//KDE +#include +#include +#include +#include +#include + +//Plasma +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//X +#ifdef Q_WS_X11 +#include +#include +#endif + +CurrentAppControl::CurrentAppControl(QObject *parent, const QVariantList &args) + : Plasma::Applet(parent, args), + m_syncDelay(false), + m_activeWindow(0), + m_lastActiveWindow(0), + m_pendingActiveWindow(0), + m_listDialog(0), + m_listWidget(0), + m_showMaximize(false), + m_alwaysUseDialog(false) +{ + m_currentTask = new Plasma::IconWidget(this); + m_currentTask->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_currentTask->setTextBackgroundColor(QColor()); + m_currentTask->setTextBackgroundColor(QColor(Qt::transparent)); + m_closeTask = new Plasma::IconWidget(this); + m_closeTask->setSvg("widgets/configuration-icons", "close"); + m_closeTask->setMaximumWidth(KIconLoader::SizeSmallMedium); + + m_maximizeTask = new Plasma::IconWidget(this); + m_maximizeTask->setSvg("widgets/configuration-icons", "maximize"); + m_maximizeTask->setMaximumWidth(KIconLoader::SizeSmallMedium); + m_maximizeTask->setZValue(999); + + connect(m_closeTask, SIGNAL(clicked()), this, SLOT(closeWindow())); + connect(m_closeTask, SIGNAL(pressed(bool)), this, SLOT(setSyncDelay(bool))); + connect(m_maximizeTask, SIGNAL(clicked()), this, SLOT(toggleMaximizedWindow())); + connect(m_maximizeTask, SIGNAL(pressed(bool)), this, SLOT(setSyncDelay(bool))); + connect(m_currentTask, SIGNAL(clicked()), this, SLOT(listWindows())); +} + + +CurrentAppControl::~CurrentAppControl() +{ +} + +void CurrentAppControl::init() +{ + connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), + this, SLOT(activeWindowChanged(WId))); + connect(KWindowSystem::self(), SIGNAL(windowChanged(WId)), + this, SLOT(windowChanged(WId))); + connect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)), + this, SLOT(windowRemoved(WId))); + QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(Qt::Horizontal, this); + lay->setContentsMargins(0, 0, 0, 0); + lay->setSpacing(0); + lay->addItem(m_currentTask); + lay->addItem(m_closeTask); + activeWindowChanged(KWindowSystem::activeWindow()); + configChanged(); +} + +void CurrentAppControl::configChanged() +{ + QGraphicsLinearLayout *lay = static_cast(layout()); + m_showMaximize = config().readEntry("ShowMaximize", true); + m_alwaysUseDialog = config().readEntry("AlwaysUseDialog", false); + if (m_showMaximize) { + m_maximizeTask->show(); + lay->insertItem(lay->count()-1, m_maximizeTask); + m_closeTask->setMaximumWidth(KIconLoader::SizeSmallMedium); + } else { + lay->removeItem(m_maximizeTask); + m_closeTask->setMaximumWidth(KIconLoader::SizeSmallMedium*2); + m_maximizeTask->hide(); + } +} + +void CurrentAppControl::constraintsEvent(Plasma::Constraints constraints) +{ + + if ((constraints & Plasma::FormFactorConstraint) || + (constraints & Plasma::SizeConstraint) ) { + QFontMetrics fm(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont)); + if (formFactor() == Plasma::Vertical) { + m_currentTask->setOrientation(Qt::Vertical); + //FIXME: all this minimum/maximum sizes shouldn't be necessary + m_currentTask->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + m_currentTask->setMinimumSize(0, 0); + } else { + m_currentTask->setOrientation(Qt::Horizontal); + const int width = qMin((qreal)(KIconLoader::SizeSmallMedium*2 + fm.width('M')*30), containment()->size().width()/4); + m_currentTask->setMaximumSize(width, QWIDGETSIZE_MAX); + m_currentTask->setMinimumSize(width, 0); + } + } +} + +void CurrentAppControl::windowChanged(WId id) +{ + bool applicationActive = false; + + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + if (widget->winId() == id) { + applicationActive = true; + break; + } + } + if (!applicationActive && id == m_activeWindow) { + m_pendingActiveWindow = m_activeWindow; + syncActiveWindow(); + } +} + +void CurrentAppControl::activeWindowChanged(WId id) +{ + m_pendingActiveWindow = id; + //delay the switch to permit to pass the close action to the proper window if our view accepts focus + if (!m_syncDelay) { + syncActiveWindow(); + } +} + +void CurrentAppControl::windowRemoved(WId id) +{ + Q_UNUSED(id) + + QTimer::singleShot(300, this, SLOT(syncActiveWindow())); +} + +void CurrentAppControl::syncActiveWindow() +{ + m_syncDelay = false; + bool applicationActive = false; + + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + if (widget->winId() == m_pendingActiveWindow || + widget->winId() == KWindowSystem::activeWindow()) { + applicationActive = true; + break; + } + } + + Plasma::ToolTipContent toolTipData = Plasma::ToolTipContent(); + toolTipData.setAutohide(true); + toolTipData.setSubText(i18n("Click here to have an overview of all the running applications")); + + if (applicationActive && m_pendingActiveWindow > 0) { + m_activeWindow = 0; + m_currentTask->setIcon("preferences-system-windows"); + const int activeWindows = qMax(0, windowsCount()-1); + if (activeWindows) { + m_currentTask->setText(i18np("%1 running app", "%1 running apps", activeWindows)); + } else { + m_currentTask->setText(i18n("No running apps")); + } + m_closeTask->hide(); + m_maximizeTask->hide(); + + toolTipData.setMainText(m_currentTask->text()); + toolTipData.setImage(KIcon("preferences-system-windows")); + + } else if (m_pendingActiveWindow <= 0) { + toolTipData.setMainText(m_currentTask->text()); + toolTipData.setImage(KWindowSystem::icon(m_activeWindow, KIconLoader::SizeHuge, KIconLoader::SizeHuge)); + } else { + m_activeWindow = m_pendingActiveWindow; + m_lastActiveWindow = m_pendingActiveWindow; + KWindowInfo info = KWindowSystem::windowInfo(m_activeWindow, NET::WMName|NET::WMState); + m_currentTask->setIcon(KWindowSystem::icon(m_activeWindow, KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium)); + m_currentTask->setText(info.name()); + //FIXME: this is utterly bad: the layout seems to -not- resize it? + m_currentTask->resize(size().width() - m_closeTask->size().width(), m_currentTask->size().height()); + m_closeTask->show(); + if (m_showMaximize) { + m_maximizeTask->show(); + } + + toolTipData.setMainText(info.name()); + toolTipData.setImage(KWindowSystem::icon(m_activeWindow, KIconLoader::SizeHuge, KIconLoader::SizeHuge)); + + if (info.state() & (NET::MaxVert|NET::MaxHoriz)) { + m_maximizeTask->setSvg("widgets/configuration-icons", "unmaximize"); + } else { + m_maximizeTask->setSvg("widgets/configuration-icons", "maximize"); + } + } + + Plasma::ToolTipManager::self()->registerWidget(this); + Plasma::ToolTipManager::self()->setContent(m_currentTask, toolTipData); + m_pendingActiveWindow = 0; +} + +void CurrentAppControl::setSyncDelay(bool delay) +{ + m_syncDelay = delay; +} + +void CurrentAppControl::closeWindow() +{ + m_syncDelay = false; + + if (m_activeWindow) { +#ifdef Q_WS_X11 + NETRootInfo ri( QX11Info::display(), NET::CloseWindow ); + ri.closeWindowRequest(m_activeWindow); +#endif + } + + syncActiveWindow(); +} + +void CurrentAppControl::toggleMaximizedWindow() +{ + //TODO: change the icon +#ifdef Q_WS_X11 + KWindowInfo info = KWindowSystem::windowInfo(m_activeWindow, NET::WMState | NET::XAWMState | NET::WMDesktop); + bool on_current = info.isOnCurrentDesktop(); + + if (!on_current) { + KWindowSystem::setCurrentDesktop(info.desktop()); + } + + if (info.isMinimized()) { + KWindowSystem::unminimizeWindow(m_activeWindow); + } + + NETWinInfo ni(QX11Info::display(), m_activeWindow, QX11Info::appRootWindow(), NET::WMState); + + if (!(ni.state() & NET::Max)) { + ni.setState(NET::Max, NET::Max); + m_maximizeTask->setSvg("widgets/configuration-icons", "unmaximize"); + } else { + ni.setState(0, NET::Max); + m_maximizeTask->setSvg("widgets/configuration-icons", "maximize"); + } + + if (!on_current) { + KWindowSystem::forceActiveWindow(m_activeWindow); + } +#endif +} + +void CurrentAppControl::listWindows() +{ + QGraphicsView *v = view(); + if (v) { + KWindowSystem::forceActiveWindow(v->winId()); + } + + if (!m_alwaysUseDialog && Plasma::WindowEffects::isEffectAvailable(Plasma::WindowEffects::PresentWindows)) { + Plasma::WindowEffects::presentWindows(view()->winId() , KWindowSystem::currentDesktop()); + } else if (!m_listDialog || !m_listDialog->isVisible()) { + if (!m_listDialog) { + m_listDialog = new Plasma::Dialog(); + m_listWidget = new QGraphicsWidget(this); + m_listWidget->installEventFilter(this); + m_listWidget->setAcceptHoverEvents(true); + m_listDialog->setGraphicsWidget(m_listWidget); + Plasma::Corona *corona = 0; + if (containment() && containment()->corona()) { + corona = containment()->corona(); + corona->addOffscreenWidget(m_listWidget); + } + + m_listDialog->setWindowFlags(Qt::FramelessWindowHint|Qt::Dialog); + KWindowSystem::setType(m_listDialog->winId(), NET::PopupMenu); + KWindowSystem::setState(m_listDialog->winId(), NET::SkipTaskbar); + m_listDialog->installEventFilter(this); + + connect(m_listDialog, SIGNAL(destroyed()), this, SLOT(closePopup())); + + m_layout = new QGraphicsLinearLayout(m_listWidget); + m_layout->setOrientation(Qt::Vertical); + m_itemBackground = new Plasma::ItemBackground(m_listWidget); + } else { + QHash::const_iterator i = m_windowIcons.constBegin(); + while (i != m_windowIcons.constEnd()) { + i.key()->hide(); + m_oldIcons << i.key(); + ++i; + } + m_windowIcons.clear(); + } + + m_itemBackground->hide(); + + Plasma::WindowEffects::slideWindow(m_listDialog, location()); + + foreach(WId window, KWindowSystem::stackingOrder()) { + KWindowInfo info = KWindowSystem::windowInfo(window, NET::WMName|NET::WMState|NET::WMWindowType); + NET::WindowType type = info.windowType(NET::AllTypesMask); + if (!(info.state() & NET::SkipTaskbar) && + ((type == NET::Normal) || (type == NET::Unknown))) { + Plasma::IconWidget *icon; + if (m_oldIcons.isEmpty()) { + icon = new Plasma::IconWidget(m_listWidget); + icon->setTextBackgroundColor(QColor()); + icon->setTextBackgroundColor(QColor(Qt::transparent)); + icon->setDrawBackground(false); + icon->setPreferredIconSize(QSizeF(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium)); + + qreal left, top, right, bottom; + m_itemBackground->getContentsMargins(&left, &top, &right, &bottom); + icon->setContentsMargins(left, top, right, bottom); + icon->installEventFilter(this); + } else { + icon = m_oldIcons.first(); + m_oldIcons.pop_front(); + } + + icon->setOrientation(Qt::Horizontal); + if (containment()) { + const qreal maxWidth = containment()->corona()->screenGeometry(containment()->screen()).width() * 0.8; + QFontMetrics fm(icon->font()); + icon->setText(fm.elidedText(info.name(), Qt::ElideRight, maxWidth)); + } else { + icon->setText(info.name()); + } + icon->setIcon(KWindowSystem::icon(window, KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium)); + icon->setMinimumSize(icon->effectiveSizeHint(Qt::PreferredSize)); + connect(icon, SIGNAL(clicked()), this, SLOT(windowItemClicked())); + m_windowIcons[icon] = window; + m_layout->addItem(icon); + icon->show(); + } + } + + if (containment() && containment()->corona()) { + m_listDialog->move(containment()->corona()->popupPosition(this, m_listDialog->size())); + } + + m_listDialog->show(); + } else { + closePopup(); + KWindowSystem::forceActiveWindow(m_lastActiveWindow); + } +} + +void CurrentAppControl::createConfigurationInterface(KConfigDialog *parent) +{ + QWidget *widget = new QWidget(); + m_generalUi.setupUi(widget); + parent->addPage(widget, i18nc("General configuration page", "General"), icon()); + + connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); + connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); + + m_generalUi.alwaysUseDialog->setChecked(m_alwaysUseDialog); + connect(m_generalUi.alwaysUseDialog, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); +} + +void CurrentAppControl::configAccepted() +{ + m_alwaysUseDialog = m_generalUi.alwaysUseDialog->checkState() == Qt::Checked; + config().writeEntry("AlwaysUseDialog", m_alwaysUseDialog); +} + +int CurrentAppControl::windowsCount() const +{ + int count = 0; + foreach(WId window, KWindowSystem::stackingOrder()) { + KWindowInfo info = KWindowSystem::windowInfo(window, NET::WMWindowType | NET::WMPid | NET::WMState); + if (!(info.state() & NET::SkipTaskbar) && + info.windowType(NET::NormalMask | NET::DialogMask | + NET::OverrideMask | NET::UtilityMask) != NET::Utility && + info.windowType(NET::NormalMask | NET::DialogMask | + NET::OverrideMask | NET::UtilityMask | NET::DockMask) != NET::Dock) { + ++count; + } + } + return count; +} + +void CurrentAppControl::windowItemClicked() +{ + if (sender() && m_windowIcons.contains(static_cast(sender()))) { + KWindowSystem::forceActiveWindow(m_windowIcons.value(static_cast(sender()))); + } +} + +void CurrentAppControl::closePopup() +{ + m_listDialog->deleteLater(); + m_listWidget->deleteLater(); + m_listDialog = 0; + m_listWidget = 0; +} + +bool CurrentAppControl::eventFilter(QObject *watched, QEvent *event) +{ + Plasma::IconWidget *icon = qobject_cast(watched); + + if (watched == m_listDialog && event->type() == QEvent::WindowDeactivate) { + closePopup(); + } else if (icon && event->type() == QEvent::GraphicsSceneHoverEnter) { + m_itemBackground->show(); + m_itemBackground->setTargetItem(icon); + } else if (watched == m_listWidget && event->type() == QEvent::GraphicsSceneHoverLeave) { + m_itemBackground->hide(); + } + + return false; +} + +#include "currentappcontrol.moc" diff --git a/plasma/netbook/applets/currentappcontrol/currentappcontrol.h b/plasma/netbook/applets/currentappcontrol/currentappcontrol.h new file mode 100644 index 00000000..29c04cb9 --- /dev/null +++ b/plasma/netbook/applets/currentappcontrol/currentappcontrol.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * * + * 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 CURRENTAPPCONTROL_HEADER +#define CURRENTAPPCONTROL_HEADER + +#include + +#include "ui_general.h" + +class QGraphicsLinearLayout; + +namespace Plasma +{ + class IconWidget; + class ItemBackground; + class Dialog; +} + +class CurrentAppControl : public Plasma::Applet +{ + Q_OBJECT +public: + + CurrentAppControl(QObject *parent, const QVariantList &args); + ~CurrentAppControl(); + + void init(); + void configChanged(); + void constraintsEvent(Plasma::Constraints constraints); + + void createConfigurationInterface(KConfigDialog *parent); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + int windowsCount() const; + +protected Q_SLOTS: + void activeWindowChanged(WId id); + void windowChanged(WId id); + void windowRemoved(WId id); + void setSyncDelay(bool delay); + void syncActiveWindow(); + void closeWindow(); + void toggleMaximizedWindow(); + void listWindows(); + void windowItemClicked(); + void closePopup(); + void configAccepted(); + +private: + Plasma::IconWidget *m_currentTask; + Plasma::IconWidget *m_closeTask; + Plasma::IconWidget *m_maximizeTask; + bool m_syncDelay; + WId m_activeWindow; + WId m_lastActiveWindow; + WId m_pendingActiveWindow; + + Plasma::Dialog *m_listDialog; + QGraphicsWidget *m_listWidget; + QGraphicsLinearLayout *m_layout; + Plasma::ItemBackground *m_itemBackground; + bool m_showMaximize; + bool m_alwaysUseDialog; + QList m_oldIcons; + QHash m_windowIcons; + + Ui::GeneralConfig m_generalUi; +}; + +K_EXPORT_PLASMA_APPLET(currentappcontrol, CurrentAppControl) +#endif diff --git a/plasma/netbook/applets/currentappcontrol/general.ui b/plasma/netbook/applets/currentappcontrol/general.ui new file mode 100644 index 00000000..0b799957 --- /dev/null +++ b/plasma/netbook/applets/currentappcontrol/general.ui @@ -0,0 +1,32 @@ + + + GeneralConfig + + + + 0 + 0 + 329 + 79 + + + + + + + Always list the applications in a menu + + + + + + + + + + + + + + + diff --git a/plasma/netbook/applets/currentappcontrol/plasma-applet-currentappcontrol.desktop b/plasma/netbook/applets/currentappcontrol/plasma-applet-currentappcontrol.desktop new file mode 100644 index 00000000..37aa9e95 --- /dev/null +++ b/plasma/netbook/applets/currentappcontrol/plasma-applet-currentappcontrol.desktop @@ -0,0 +1,146 @@ +[Desktop Entry] +Name=Current Application Control +Name[ar]=التحكم بالتطبيق الحالي +Name[ast]=Control de l'aplicación actual +Name[bn]=সক্রিয় অ্যাপলিকেশন নিয়ন্ত্রণ +Name[bs]=upravljanje tekućim programom +Name[ca]=Control d'aplicació actual +Name[ca@valencia]=Control d'aplicació actual +Name[cs]=Ovládání aktuální aplikace +Name[da]=Styring af aktuelt program +Name[de]=Steuerung für aktuelles Fenster +Name[el]=Έλεγχος τρέχουσας εφαρμογής +Name[en_GB]=Current Application Control +Name[es]=Control de la aplicación actual +Name[et]=Aktiivne rakenduse juhtimine +Name[eu]=Uneko aplikazioaren kontrola +Name[fi]=Nykyinen sovellusohjain +Name[fr]=Contrôle de l'application courante +Name[fy]=Aktive programma kontrôle +Name[gl]=Control do programa actual +Name[gu]=હાલનાં કાર્યક્રમનું નિયંત્રણ +Name[he]=שליטה ביישום הנוכחי +Name[hi]=मोजूदा अनुप्रयोग नियंत्रण +Name[hr]=Kontrola trenutne aplikacije +Name[hu]=Alkalmazásvezérlő +Name[ia]=Controlo de application currente ... +Name[id]=Kontrol Aplikasi Saat Ini +Name[is]=Stýringar fyrir forrit í keyrslu +Name[ja]=現在のアプリケーションコントロール +Name[kk]=Орындалып жатқан қолданбаны басқару +Name[km]=ការ​ត្រួតពិនិត្យ​កម្មវិធី​បច្ចុប្បន្ន +Name[kn]=ಪ್ರಸ್ತುತ ಅನ್ವಯಗಳ ನಿಯಂತ್ರಣ +Name[ko]=현재 프로그램의 컨트롤 +Name[lt]=Dabartinės programos valdymas +Name[lv]=Aktīvās programmas kontrole +Name[mk]=Контрола за активната апликација +Name[ml]=നിലവിലെ പ്രയോഗനിയന്ത്രണം +Name[mr]=चालू अनुप्रयोग नियंत्रण +Name[nb]=Styring for gjeldende program +Name[nds]=Programmstüern +Name[nl]=De huidige besturing van programma's +Name[nn]=Kontroll for gjeldande program +Name[pa]=ਮੌਜੂਦਾ ਐਪਲੀਕੇਸ਼ਨ ਕੰਟਰੋਲ +Name[pl]=Sterowanie bieżącym programem +Name[pt]=Controlo da Aplicação Actual +Name[pt_BR]=Controle do aplicativo atual +Name[ro]=Control aplicații curente +Name[ru]=Текущее приложение +Name[si]=වත්මන් යෙදුම් පාලකය +Name[sk]=Ovládanie aktuálnej aplikácie +Name[sl]=Nadzor trenutnega programa +Name[sr]=управљање текућим програмом +Name[sr@ijekavian]=управљање текућим програмом +Name[sr@ijekavianlatin]=upravljanje tekućim programom +Name[sr@latin]=upravljanje tekućim programom +Name[sv]=Styrning av nuvarande program +Name[tg]=Барномаҳои иловагӣ +Name[th]=ควบคุมโปรแกรมปัจจุบัน +Name[tr]=Geçerli Uygulama Denetimi +Name[ug]=نۆۋەتتىكى پروگرامما تىزگىنى +Name[uk]=Керування поточною програмою +Name[vi]=Điều khiển ứng dụng hiện tại +Name[wa]=Controle do programe do moumint +Name[x-test]=xxCurrent Application Controlxx +Name[zh_CN]=当前程序控制 +Name[zh_TW]=目前應用程式控制 +Comment=Controls for the active window +Comment[ar]=تتحكم بالنافذة المُفعلة +Comment[ast]=Controles de la ventana activa +Comment[bn]=সক্রিয় উইণ্ডোর জন্য নিয়ন্ত্রণসমূহ +Comment[bs]=Upravljanje aktivnim prozorom +Comment[ca]=Controls per a la finestra activa +Comment[ca@valencia]=Controls per a la finestra activa +Comment[cs]=Ovládání aktivního okna +Comment[da]=Styring af det aktive vindue +Comment[de]=Das aktuelle Fenster steuern +Comment[el]=Χειριστήρια για το ενεργό παράθυρο +Comment[en_GB]=Controls for the active window +Comment[es]=Controles de la ventana activa +Comment[et]=Aktiivse akna juhtimine +Comment[eu]=Leiho aktiborako kontrolak +Comment[fi]=Ohjaimet ikkunan aktivoimiseksi +Comment[fr]=Contrôles pour la fenêtre active +Comment[fy]=Bestjoering foar it aktive finster +Comment[ga]=Rialtáin le haghaidh na fuinneoige reatha +Comment[gl]=Controla a xanela actual +Comment[he]=בקרים לחלון הפעיל +Comment[hi]=सक्रिय विंडो के लिए नियंत्रण +Comment[hr]=Kontrole aktivnog prozora +Comment[hu]=Vezérlők az aktív ablakhoz +Comment[ia]=Controlos pro le fenestra de activitate +Comment[id]=Kontrol untuk jendela aktif +Comment[is]=Stillingar virka gluggans +Comment[ja]=アクティブウィンドウのコントロール +Comment[kk]=Белсенді терезені басқару +Comment[km]=ការត្រួតពិនិត្យ​សម្រាប់​បង្អួច​សកម្ម +Comment[kn]=ಸಕ್ರಿಯ ಕಿಟಕಿಯನ್ನು ನಿಯಂತ್ರಿಸುತ್ತದೆ +Comment[ko]=현재 프로그램에 있는 컨트롤 +Comment[lt]=Aktyvaus lango valdymo priemonės +Comment[lv]=Kontroles aktīvajam logam +Comment[mk]=Контроли за активниот прозорец +Comment[ml]=സജീവ ജാലകത്തിനുള്ള നിയന്ത്രണങ്ങള്‍ +Comment[mr]=चालू चौकटीकरिता नियंत्रणे +Comment[nb]=Styring for det aktive vinduet +Comment[nds]=Kuntrull för't aktive Finster +Comment[nl]=Besturing van het actieve venster +Comment[nn]=Kontroll for det aktive vindauget +Comment[pa]=ਐਕਟਿਵ ਵਿੰਡੋ ਲਈ ਕੰਟਰੋਲ +Comment[pl]=Sterowanie aktywnym oknem +Comment[pt]=Controlos para a janela activa +Comment[pt_BR]=Controles para a janela ativa +Comment[ro]=Controale pentru fereastra activă +Comment[ru]=Элементы управления для активного окна +Comment[si]=සක්‍රිය කවුළුව සඳහා පාලක +Comment[sk]=Ovládanie pre aktívne okno +Comment[sl]=Nadzorniki za dejavno okno +Comment[sr]=Управљање активним прозором +Comment[sr@ijekavian]=Управљање активним прозором +Comment[sr@ijekavianlatin]=Upravljanje aktivnim prozorom +Comment[sr@latin]=Upravljanje aktivnim prozorom +Comment[sv]=Styrning av det aktiva fönstret +Comment[tg]=Барномаи идоракунии Jack +Comment[th]=ควบคุมหน้าต่างที่กำลังทำงานอยู่ +Comment[tr]=Etkin pencere için denetimler +Comment[ug]=ئاكتىپ كۆزنەكنى تىزگىنلەيدۇ +Comment[uk]=Інструменти керування активним вікном +Comment[vi]=Các nút điều khiển cho cửa sổ đang hoạt động +Comment[wa]=Controle po l' finiesse ovrante +Comment[x-test]=xxControls for the active windowxx +Comment[zh_CN]=控制活动窗口 +Comment[zh_TW]=作用中視窗控制 +Icon=preferences-system-windows +Type=Service + +X-KDE-ServiceTypes=Plasma/Applet +X-KDE-Library=plasma_applet_currentappcontrol +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=currentappcontrol +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + diff --git a/plasma/netbook/applets/searchbox/CMakeLists.txt b/plasma/netbook/applets/searchbox/CMakeLists.txt new file mode 100644 index 00000000..bc07d652 --- /dev/null +++ b/plasma/netbook/applets/searchbox/CMakeLists.txt @@ -0,0 +1,15 @@ +project(plasma-searchbox) + + +set(searchbox_SRCS searchbox.cpp) + + +kde4_add_plugin(plasma_applet_searchbox ${searchbox_SRCS}) +target_link_libraries(plasma_applet_searchbox + ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS}) + +install(TARGETS plasma_applet_searchbox + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-applet-searchbox.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/netbook/applets/searchbox/Messages.sh b/plasma/netbook/applets/searchbox/Messages.sh new file mode 100644 index 00000000..d22cbe18 --- /dev/null +++ b/plasma/netbook/applets/searchbox/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_applet_searchbox.pot diff --git a/plasma/netbook/applets/searchbox/plasma-applet-searchbox.desktop b/plasma/netbook/applets/searchbox/plasma-applet-searchbox.desktop new file mode 100644 index 00000000..a8390060 --- /dev/null +++ b/plasma/netbook/applets/searchbox/plasma-applet-searchbox.desktop @@ -0,0 +1,142 @@ +[Desktop Entry] +Name=Search Box +Name[ar]=صندوق البحث +Name[ast]=Caxa de gueta +Name[bg]=Поле за търсене +Name[bn]=অনুসন্ধান বাক্স +Name[bs]=polje pretrage +Name[ca]=Quadre de cerca +Name[ca@valencia]=Quadre de cerca +Name[cs]=Vyhledávací pole +Name[csb]=Kastka szëkbë +Name[da]=Søgfelt +Name[de]=Suchfeld +Name[el]=Πλαίσιο Αναζήτησης +Name[en_GB]=Search Box +Name[eo]=Skatol-serĉo +Name[es]=Caja de búsqueda +Name[et]=Otsingukast +Name[eu]=Bilaketa-koadroa +Name[fi]=Hakuikkuna +Name[fr]=Boîte de recherche +Name[fy]=Sykfak +Name[ga]=Bosca Cuardaigh +Name[gl]=Caixa de busca +Name[gu]=શોધ ખાનું +Name[he]=תיבת חיפוש +Name[hi]=खोज़ डिब्बा +Name[hr]=Polje za pretragu +Name[hu]=Keresődoboz +Name[ia]=Quadrato de cerca +Name[id]=Kotak Pencarian +Name[is]=Leitarreitur +Name[ja]=検索ボックス +Name[kk]=Іздеу панелі +Name[km]=ប្រអប់​ស្វែងរក +Name[kn]=ಹುಡುಕು ಪೆಟ್ಟಿಗೆ +Name[ko]=검색 상자 +Name[lt]=Paieškos laukas +Name[lv]=Meklēšanas lodziņš +Name[ml]=തെരച്ചിലിനുള്ള പെട്ടി +Name[mr]=शोध पट्टी +Name[nb]=Søkeboks +Name[nds]=Söökreeg +Name[nl]=Zoekvak +Name[nn]=Søkjefelt +Name[pa]=ਖੋਜ ਬਕਸਾ +Name[pl]=Pole wyszukiwania +Name[pt]=Campo de Pesquisa +Name[pt_BR]=Campo de pesquisa +Name[ro]=Casetă de căutare +Name[ru]=Строка поиска +Name[si]=සෙවුම් කොටුව +Name[sk]=Vyhľadávacie pole +Name[sl]=Iskalno polje +Name[sr]=поље претраге +Name[sr@ijekavian]=поље претраге +Name[sr@ijekavianlatin]=polje pretrage +Name[sr@latin]=polje pretrage +Name[sv]=Sökruta +Name[tg]=Ҷои ҷустуҷӯӣ +Name[th]=กล่องค้นหา +Name[tr]=Arama Kutusu +Name[ug]=ئىزدەش رامكىسى +Name[uk]=Панель пошуку +Name[wa]=Boesse di cweraedje +Name[x-test]=xxSearch Boxxx +Name[zh_CN]=搜索框 +Name[zh_TW]=搜尋盒 +Comment=Search Box for a given RunnerManager +Comment[ar]=صندوق بحث لـ RunnerManager معين +Comment[ast]=Caxa de gueta pa un determináu xestor de llanzamientu +Comment[bs]=Okvir pretrage za dati menadžer izvođača +Comment[ca]=Quadre de cerca per a un gestor d'execució indicat +Comment[ca@valencia]=Quadre de cerca per a un gestor d'execució indicat +Comment[cs]=Vyhledávací pole pro daný RunnerManager +Comment[da]=Søgfelt til en given RunnerManager +Comment[de]=Suchfeld für einen Starter-Manager +Comment[el]=Πλαίσιο αναζήτησης για ένα δοσμένο διαχειριστή εκτελέσεων +Comment[en_GB]=Search Box for a given RunnerManager +Comment[eo]=Serĉu dialogujon por la proponita RunnerManager +Comment[es]=Caja de búsqueda para un determinado gestor de lanzamiento +Comment[et]=Käivitamishalduri otsingukast +Comment[eu]=Abiarazle-kudeatzaile jakin baterako bilaketa-koadroa +Comment[fi]=Etsintäikkuna tietylle RunnerManagerille +Comment[fr]=Boîte de recherche pour un gestionnaire de lancement donné +Comment[fy]=Sykfak foar de oantsjutte RunnerManager +Comment[gl]=Caixa de busca para un RunnerManager dado +Comment[he]=תיבת חיפוש עבור RunnerManager נתון +Comment[hr]=Polje za pretragu za dani Upravitelj Pokretanja +Comment[hu]=Keresődoboz egy adott RunnerManagerhez +Comment[ia]=Quadrato de cerca pro un date RunnerManager (Gerente de Execution) +Comment[id]=Kotak pencarian untuk manajer pelari yang diberikan +Comment[is]=Leitarreitur fyrir tiltekinn KeyrsluStjóra (RunnerManager) +Comment[ja]=RunnerManager の検索ボックス +Comment[kk]=Таңдаған ЖегуМенеджері үшін Іздеу панелі +Comment[km]=ប្រអប់​ស្វែងរក​សម្រាប់​កម្មវិធី​គ្រប់គ្រង​របស់​កម្មវិធី​ដែលបាន​ផ្ដល់ +Comment[kn]=ಒದಗಿಸಲಾದ RunnerManager ಗಾಗಿನ ಹುಡುಕು ಚೌಕ +Comment[ko]=주어진 실행기 관리자를 위한 검색 상자 +Comment[lt]=Paieškos laukas nurodytam paleidiklio tvarkikliui +Comment[lv]=Meklēšanas lodziņš dotam RunnerManager +Comment[ml]=റണ്ണര്‍മാനേജറിനു് വേണ്ടിയുള്ള തെരച്ചില്‍ പെട്ടി +Comment[mr]=दिलेल्या RunnerManager साठी शोध पट्टी +Comment[nb]=Søkeboks for en gitt RunnerManager +Comment[nds]=Söökreeg för en angeven Dreegpleger +Comment[nl]=Zoekvak voor een gegeven startbeheerder +Comment[nn]=Søkjefelt for ein gjeven RunnerManager +Comment[pa]=ਦਿੱਤੇ ਰਨਰਮੈਨੇਜਰ ਲਈ ਖੋਜ ਬਾਕਸ +Comment[pl]=Pole wyszukiwania w podanym programie uruchamiającym +Comment[pt]=Campo de Pesquisa para um dado Gestor de Execuções +Comment[pt_BR]=Campo de pesquisa para um gerenciador de execuções indicado +Comment[ro]=Casetă de căutare pentru un anumit RunnerManager +Comment[ru]=Строка поиска для заданного диспетчера запуска +Comment[si]=දෙනලද ක්‍රියාකරවුම් පාලකය සඳහා සෙවුම් කොටුව +Comment[sk]=Vyhľadávacie pole pre zadaný spúšťač +Comment[sl]=Iskalno polje za določen upravljalnik zaganjalnikov +Comment[sr]=Оквир претраге за дати менаџер извођача +Comment[sr@ijekavian]=Оквир претраге за дати менаџер извођача +Comment[sr@ijekavianlatin]=Okvir pretrage za dati menadžer izvođača +Comment[sr@latin]=Okvir pretrage za dati menadžer izvođača +Comment[sv]=Sökruta för en given hanterare av programkörning +Comment[th]=กล่องค้นหาสำหรับตัวจัดการเรียกใช้งานที่ให้มา +Comment[tr]=Verilen bir Çalıştırıcı Yöneticisi için Arama Kutusu +Comment[ug]=باشقۇرغۇچنى ئىجرا قىلىدىغان ئىزدەش قۇتىسى +Comment[uk]=Панель пошуку для вказаного Керування запуском +Comment[wa]=Boesse di cweraedje pos on Manaedjeu d' enondaedje di dné +Comment[x-test]=xxSearch Box for a given RunnerManagerxx +Comment[zh_CN]=运行管理器的搜索框 +Comment[zh_TW]=RunnerManager 的搜尋盒 +Icon=edit-find +Type=Service + +X-KDE-ServiceTypes=Plasma/Applet +X-KDE-Library=plasma_applet_searchbox +X-KDE-PluginInfo-Author=Artur Souza +X-KDE-PluginInfo-Email=asouza@kde.org +X-KDE-PluginInfo-Name=searchbox +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/applets/searchbox/searchbox.cpp b/plasma/netbook/applets/searchbox/searchbox.cpp new file mode 100644 index 00000000..e1b582ce --- /dev/null +++ b/plasma/netbook/applets/searchbox/searchbox.cpp @@ -0,0 +1,153 @@ +/* + * Copyright 2009 by Artur Duque de Souza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "searchbox.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +SearchBox::SearchBox(QObject *parent, const QVariantList &args) + : Plasma::PopupApplet(parent, args), m_widget(0), m_search(0), + m_closeIcon(0) +{ + setPopupIcon("edit-find"); + setPassivePopup(true); + setAspectRatioMode(Plasma::IgnoreAspectRatio); +} + +void SearchBox::init() +{ + // tooltip stuff + Plasma::ToolTipContent toolTipData = Plasma::ToolTipContent(); + toolTipData.setAutohide(true); + toolTipData.setMainText(name()); + toolTipData.setImage(KIcon("edit-find")); + + Plasma::ToolTipManager::self()->registerWidget(this); + Plasma::ToolTipManager::self()->setContent(this, toolTipData); +} + +SearchBox::~SearchBox() +{ +} + +QGraphicsWidget *SearchBox::graphicsWidget() +{ + if (m_widget) { + return m_widget; + } + + m_search = new Plasma::LineEdit(); + m_search->nativeWidget()->setClearButtonShown(true); + m_search->nativeWidget()->setClickMessage(i18n("Enter your query here")); + connect(m_search, SIGNAL(returnPressed()), this, SLOT(query())); + connect(m_search->nativeWidget(), SIGNAL(textChanged(QString)), this, SLOT(delayedQuery())); + + m_searchTimer = new QTimer(this); + m_searchTimer->setSingleShot(true); + connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(query())); + + + m_closeIcon = new Plasma::IconWidget(); + m_closeIcon->setIcon("dialog-close"); + m_closeIcon->setPreferredSize(KIconLoader::SizeSmallMedium, + KIconLoader::SizeSmallMedium); + connect(m_closeIcon, SIGNAL(clicked()), this, SLOT(hidePopup())); + + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(); + layout->addItem(m_search); + layout->addItem(m_closeIcon); + layout->setStretchFactor(m_search, 4); + + m_widget = new QGraphicsWidget(this); + m_widget->setLayout(layout); + m_widget->setPreferredWidth(300); + m_widget->installEventFilter(this); + + return m_widget; +} + +void SearchBox::popupEvent(bool shown) +{ + if (!m_search) { + return; + } + + if (shown) { + focusEditor(); + } else { + m_search->setText(QString()); + } +} + +void SearchBox::focusInEvent(QFocusEvent *event) +{ + Q_UNUSED(event); + + focusEditor(); +} + +bool SearchBox::eventFilter(QObject* watched, QEvent *event) +{ + Q_UNUSED(watched); + + //FIXME: is there a way to do it in PopupApplet? + if (event->type() == QEvent::FocusIn) { + focusEditor(); + } + return false; +} + +void SearchBox::focusEditor() +{ + m_search->clearFocus(); + m_search->setFocus(); + m_search->nativeWidget()->clearFocus(); + m_search->nativeWidget()->setFocus(); +} + +void SearchBox::delayedQuery() +{ + m_searchTimer->start(500); +} + +void SearchBox::query() +{ + Plasma::Service *service = dataEngine("searchlaunch")->serviceForSource("query"); + KConfigGroup ops = service->operationDescription("query"); + ops.writeEntry("query", m_search->text()); + KJob *job = service->startOperationCall(ops); + connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater())); +} + +#include "searchbox.moc" diff --git a/plasma/netbook/applets/searchbox/searchbox.h b/plasma/netbook/applets/searchbox/searchbox.h new file mode 100644 index 00000000..e8662332 --- /dev/null +++ b/plasma/netbook/applets/searchbox/searchbox.h @@ -0,0 +1,63 @@ +/* + * Copyright 2009 by Artur Duque de Souza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SEARCHBOX_APPLET_H +#define SEARCHBOX_APPLET_H + +#include + + +namespace Plasma +{ + class IconWidget; + class LineEdit; +} + +class QTimer; + +class SearchBox: public Plasma::PopupApplet +{ + Q_OBJECT + +public: + SearchBox(QObject *parent, const QVariantList &args); + ~SearchBox(); + void init(); + + QGraphicsWidget *graphicsWidget(); + +public slots: + void delayedQuery(); + void query(); + +protected: + void popupEvent(bool shown); + void focusInEvent(QFocusEvent *event); + bool eventFilter(QObject* watched, QEvent *event); + void focusEditor(); + +private: + QGraphicsWidget *m_widget; + Plasma::LineEdit *m_search; + Plasma::IconWidget *m_closeIcon; + QTimer *m_searchTimer; +}; + +K_EXPORT_PLASMA_APPLET(searchbox, SearchBox) + +#endif diff --git a/plasma/netbook/containments/CMakeLists.txt b/plasma/netbook/containments/CMakeLists.txt new file mode 100644 index 00000000..c96a688c --- /dev/null +++ b/plasma/netbook/containments/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(netpanel) +if(NOT WIN32) +add_subdirectory(sal) +endif(NOT WIN32) diff --git a/plasma/netbook/containments/common/appletmovespacer.cpp b/plasma/netbook/containments/common/appletmovespacer.cpp new file mode 100644 index 00000000..7a4a259a --- /dev/null +++ b/plasma/netbook/containments/common/appletmovespacer.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "appletmovespacer.h" + +#include + +#include + +AppletMoveSpacer::AppletMoveSpacer(QGraphicsWidget *parent) + : QGraphicsWidget(parent) +{ + m_background = new Plasma::FrameSvg(this); + m_background->setImagePath("widgets/frame"); + m_background->setElementPrefix("sunken"); +} + +AppletMoveSpacer::~AppletMoveSpacer() +{ +} + +void AppletMoveSpacer::dropEvent(QGraphicsSceneDragDropEvent *event) +{ + event->setPos(mapToParent(event->pos())); + emit dropRequested(event); +} + +void AppletMoveSpacer::resizeEvent(QGraphicsSceneResizeEvent *event) +{ + m_background->resizeFrame(event->newSize()); +} + +void AppletMoveSpacer::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option) + Q_UNUSED(widget) + + m_background->paintFrame(painter); +} + +#include "appletmovespacer.moc" diff --git a/plasma/netbook/containments/common/appletmovespacer.h b/plasma/netbook/containments/common/appletmovespacer.h new file mode 100644 index 00000000..ff2d1be7 --- /dev/null +++ b/plasma/netbook/containments/common/appletmovespacer.h @@ -0,0 +1,50 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef APPLETMOVESPACER_H +#define APPLETMOVESPACER_H + +#include + +namespace Plasma { + class FrameSvg; +} + +class AppletMoveSpacer : public QGraphicsWidget +{ + Q_OBJECT + +public: + AppletMoveSpacer(QGraphicsWidget *parent); + ~AppletMoveSpacer(); + +protected: + void resizeEvent(QGraphicsSceneResizeEvent *event); + void dropEvent(QGraphicsSceneDragDropEvent *event); + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +Q_SIGNALS: + void dropRequested(QGraphicsSceneDragDropEvent *event); + +private: + Plasma::FrameSvg *m_background; +}; + +#endif diff --git a/plasma/netbook/containments/common/linearappletoverlay.cpp b/plasma/netbook/containments/common/linearappletoverlay.cpp new file mode 100644 index 00000000..ac352c42 --- /dev/null +++ b/plasma/netbook/containments/common/linearappletoverlay.cpp @@ -0,0 +1,298 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linearappletoverlay.h" + +#include "../common/appletmovespacer.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include + +LinearAppletOverlay::LinearAppletOverlay(Plasma::Containment *parent, QGraphicsLinearLayout *layout) + : QGraphicsWidget(parent), + m_applet(0), + m_containment(parent), + m_layout(layout), + m_spacer(0), + m_spacerIndex(0), + m_clickDrag(false) +{ + setAcceptHoverEvents(true); + setAcceptDrops(true); + setZValue(900); +} + +LinearAppletOverlay::~LinearAppletOverlay() +{ +} + +void LinearAppletOverlay::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(widget) + + QColor c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); + c.setAlphaF(0.15); + + painter->fillRect(option->exposedRect, c); + + if (m_applet) { + QRectF geom = m_applet->geometry(); + geom.moveTopLeft(geom.topLeft()); + c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor); + c.setAlphaF(0.30); + QPainterPath p = Plasma::PaintUtils::roundedRectangle(geom, 4); + painter->save(); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->fillPath(p, c); + painter->restore(); + } +} + +void LinearAppletOverlay::appletDestroyed() +{ + m_applet = 0; +} + +void LinearAppletOverlay::spacerRequestedDrop(QGraphicsSceneDragDropEvent *event) +{ + dropEvent(event); +} + +void LinearAppletOverlay::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() != Qt::LeftButton) { + //Hack to make scene::itemAt() work + int z = zValue(); + setZValue(-100); + //FIXME:here we don't have a screen pos in the event + m_containment->showContextMenu(event->pos(), event->pos().toPoint()); + setZValue(z); + return; + } + + if (m_clickDrag) { + m_clickDrag = false; + m_origin = QPoint(); + return; + } + + if (m_applet) { + m_origin = event->pos(); + showSpacer(event->pos()); + if (m_layout) { + m_layout->removeItem(m_applet); + m_applet->raise(); + } + if (m_spacer) { + m_spacer->setMinimumHeight(m_applet->size().height()); + } + } +} + +void LinearAppletOverlay::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + if (m_clickDrag) { + //Cheat and pretend a mousemoveevent is arrived + QGraphicsSceneMouseEvent me; + me.setPos(event->pos()); + me.setLastPos(event->lastPos()); + mouseMoveEvent(&me); + return; + } + + if (m_applet) { + disconnect(m_applet, SIGNAL(destroyed()), this, SLOT(appletDestroyed())); + } + m_applet = 0; + + Plasma::Applet *oldApplet = 0; + + //FIXME: is there a way more efficient than this linear one? scene()itemAt() won't work because it would always be == this + foreach (Plasma::Applet *applet, m_containment->applets()) { + if (applet->geometry().contains(event->pos())) { + m_applet = applet; + connect(applet, SIGNAL(destroyed()), this, SLOT(appletDestroyed())); + break; + } + } + if (m_applet != oldApplet) { + update(); + } +} + +void LinearAppletOverlay::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (m_spacer) { + QPointF delta = event->pos()-event->lastPos(); + if (m_applet) { + if (m_containment->formFactor() == Plasma::Vertical) { + m_applet->moveBy(0, delta.y()); + } else { + m_applet->moveBy(delta.x(), 0); + } + } + showSpacer(event->pos()); + } + + update(); +} + +void LinearAppletOverlay::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event) + + QPoint delta = event->pos().toPoint() - m_origin.toPoint(); + if (m_origin != QPointF() && delta.manhattanLength() < KGlobalSettings::dndEventDelay()) { + m_clickDrag = true; + m_origin = QPointF(); + return; + } + + if (m_spacer && m_layout) { + m_layout->removeItem(m_spacer); + if (m_applet) { + m_layout->insertItem(m_spacerIndex, m_applet); + } + } + + delete m_spacer; + m_spacer = 0; + m_spacerIndex = 0; +} + +void LinearAppletOverlay::dragEnterEvent(QGraphicsSceneDragDropEvent *event) +{ + showSpacer(event->pos()); + event->accept(); +} + +void LinearAppletOverlay::dragMoveEvent(QGraphicsSceneDragDropEvent *event) +{ + showSpacer(event->pos()); +} + +void LinearAppletOverlay::dropEvent(QGraphicsSceneDragDropEvent *event) +{ + event->setPos(mapToParent(event->pos())); + emit dropRequested(event); + + if (m_layout) { + m_layout->removeItem(m_spacer); + } + + if (m_spacer) { + m_spacer->deleteLater(); + } + + m_spacer = 0; + m_spacerIndex = 0; +} + +void LinearAppletOverlay::showSpacer(const QPointF &pos) +{ + if (!scene()) { + return; + } + + if (pos == QPoint()) { + if (m_spacer) { + m_layout->removeItem(m_spacer); + m_spacer->hide(); + } + return; + } + + //lucky case: the spacer is already in the right position + if (m_spacer && m_spacer->geometry().contains(pos)) { + return; + } + + int insertIndex = -1; + + for (int i = 0; i < m_layout->count(); ++i) { + if (!dynamic_cast(m_layout->itemAt(i)) && + !dynamic_cast(m_layout->itemAt(i))) { + continue; + } + QRectF siblingGeometry = m_layout->itemAt(i)->geometry(); + + if (m_containment->formFactor() != Plasma::Vertical) { + qreal middle = siblingGeometry.center().x(); + if (pos.x() < middle) { + insertIndex = i; + break; + } else if (pos.x() <= siblingGeometry.right()) { + insertIndex = i + 1; + break; + } + } else { // Vertical + qreal middle = siblingGeometry.center().y(); + + if (pos.y() < middle) { + insertIndex = i; + break; + } else if (pos.y() <= siblingGeometry.bottom()) { + insertIndex = i + 1; + break; + } + } + } + + if (m_spacerIndex < insertIndex) { + --insertIndex; + } + + //if is -1 let's see if there are spacers, zero, one or two + if (insertIndex < 0) { + bool firstSpacer = (!dynamic_cast(m_layout->itemAt(0)) && + !dynamic_cast(m_layout->itemAt(0))); + bool lastSpacer = (!dynamic_cast(m_layout->itemAt(m_layout->count() - 1)) && + !dynamic_cast(m_layout->itemAt(m_layout->count() - 1))); + + if (firstSpacer && lastSpacer && m_layout->count() > 1) { + insertIndex = m_layout->count() - 2; + } else if (lastSpacer) { + insertIndex = 0; + } + } + + m_spacerIndex = insertIndex; + if (insertIndex != -1) { + if (!m_spacer) { + m_spacer = new AppletMoveSpacer(this); + connect (m_spacer, SIGNAL(dropRequested(QGraphicsSceneDragDropEvent*)), + this, SLOT(spacerRequestedDrop(QGraphicsSceneDragDropEvent*))); + } + + m_layout->removeItem(m_spacer); + m_spacer->show(); + m_layout->insertItem(insertIndex, m_spacer); + } +} + +#include + diff --git a/plasma/netbook/containments/common/linearappletoverlay.h b/plasma/netbook/containments/common/linearappletoverlay.h new file mode 100644 index 00000000..d33addc7 --- /dev/null +++ b/plasma/netbook/containments/common/linearappletoverlay.h @@ -0,0 +1,77 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef LINEARAPPLETOVERLAY_H +#define LINEARAPPLETOVERLAY_H + + +#include + +namespace Plasma +{ + class Applet; + class Containment; +} + +class Panel; +class AppletMoveSpacer; +class QGraphicsLinearLayout; +class QTimer; + +class LinearAppletOverlay : public QGraphicsWidget +{ + Q_OBJECT + + friend class AppletMoveSpacer; + +public: + explicit LinearAppletOverlay(Plasma::Containment *parent = 0, QGraphicsLinearLayout *layout = 0); + ~LinearAppletOverlay(); + + void showSpacer(const QPointF &pos); + +protected Q_SLOTS: + void appletDestroyed(); + void spacerRequestedDrop(QGraphicsSceneDragDropEvent *event); + +protected: + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=0); + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void dragEnterEvent(QGraphicsSceneDragDropEvent *event); + void dragMoveEvent(QGraphicsSceneDragDropEvent *event); + void dropEvent(QGraphicsSceneDragDropEvent *event); + +Q_SIGNALS: + void dropRequested(QGraphicsSceneDragDropEvent *event); + +private: + Plasma::Applet *m_applet; + Plasma::Containment *m_containment; + QGraphicsLinearLayout *m_layout; + Panel *m_panel; + AppletMoveSpacer *m_spacer; + int m_spacerIndex; + bool m_clickDrag; + QPointF m_origin; +}; + +#endif diff --git a/plasma/netbook/containments/netpanel/CMakeLists.txt b/plasma/netbook/containments/netpanel/CMakeLists.txt new file mode 100644 index 00000000..f6f768a4 --- /dev/null +++ b/plasma/netbook/containments/netpanel/CMakeLists.txt @@ -0,0 +1,13 @@ + +set(panel_SRCS + panel.cpp + dummytoolbox.cpp + ../common/linearappletoverlay.cpp + ../common/appletmovespacer.cpp + ) + +kde4_add_plugin(plasma_containment_netpanel ${panel_SRCS}) +target_link_libraries(plasma_containment_netpanel ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS}) + +install(TARGETS plasma_containment_netpanel DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containment-netpanel.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/netbook/containments/netpanel/Messages.sh b/plasma/netbook/containments/netpanel/Messages.sh new file mode 100644 index 00000000..4aa94ac2 --- /dev/null +++ b/plasma/netbook/containments/netpanel/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_applet_netpanel.pot diff --git a/plasma/netbook/containments/netpanel/dummytoolbox.cpp b/plasma/netbook/containments/netpanel/dummytoolbox.cpp new file mode 100644 index 00000000..7363af2d --- /dev/null +++ b/plasma/netbook/containments/netpanel/dummytoolbox.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "dummytoolbox.h" + + + +DummyToolBox::DummyToolBox(Plasma::Containment *parent) + : Plasma::AbstractToolBox(parent), + m_showing(false) +{ +} + +DummyToolBox::~DummyToolBox() +{ +} + +bool DummyToolBox::isShowing() const +{ + return m_showing; +} + +void DummyToolBox::setShowing(const bool show) +{ + if (show != m_showing) { + emit toggled(); + emit visibilityChanged(show); + } + + m_showing = show; +} + + +void DummyToolBox::addTool(QAction *) +{ + //not supported +} + +void DummyToolBox::removeTool(QAction *) +{ + //not supported +} + +#include "dummytoolbox.moc" diff --git a/plasma/netbook/containments/netpanel/dummytoolbox.h b/plasma/netbook/containments/netpanel/dummytoolbox.h new file mode 100644 index 00000000..492da18c --- /dev/null +++ b/plasma/netbook/containments/netpanel/dummytoolbox.h @@ -0,0 +1,45 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DUMMYTOOLBOX_H +#define DUMMYTOOLBOX_H + + +#include + + +class DummyToolBox : public Plasma::AbstractToolBox +{ + Q_OBJECT + Q_PROPERTY(bool showing READ isShowing WRITE setShowing ) +public: + DummyToolBox(Plasma::Containment *parent = 0); + ~DummyToolBox(); + + bool isShowing() const; + void setShowing(const bool show); + + void addTool(QAction *action); + void removeTool(QAction *action); + +private: + bool m_showing; +}; + +#endif diff --git a/plasma/netbook/containments/netpanel/panel.cpp b/plasma/netbook/containments/netpanel/panel.cpp new file mode 100644 index 00000000..488946ba --- /dev/null +++ b/plasma/netbook/containments/netpanel/panel.cpp @@ -0,0 +1,535 @@ +/* +* Copyright 2007 by Alex Merry +* Copyright 2008 by Alexis Ménard +* Copyright 2008 by Aaron Seigo +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License version 2, +* or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "panel.h" +#include "dummytoolbox.h" +#include "../common/linearappletoverlay.h" + +#include + +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + +#include +#include +#include +#include + +using namespace Plasma; + +Panel::Panel(QObject *parent, const QVariantList &args) + : Containment(parent, args), + m_layout(0), + m_appletOverlay(0) +{ + m_background = new Plasma::FrameSvg(this); + m_background->setImagePath("widgets/panel-background"); + m_background->setEnabledBorders(Plasma::FrameSvg::AllBorders); + connect(m_background, SIGNAL(repaintNeeded()), this, SLOT(backgroundChanged())); + setZValue(150); + setContainmentType(Containment::PanelContainment); + + QSize size = QSize(args.count() ? args[0].toInt() : 1024, 22); + kDebug() << "**********" << size; + resize(size); + setMinimumSize(size); + setMaximumSize(size); + setDrawWallpaper(false); + + DummyToolBox *toolBox = new DummyToolBox(this); + setToolBox(toolBox); + + connect(this, SIGNAL(appletRemoved(Plasma::Applet*)), + this, SLOT(appletRemoved(Plasma::Applet*))); + connect(this, SIGNAL(toolBoxVisibilityChanged(bool)), + this, SLOT(updateConfigurationMode(bool))); +} + +Panel::~Panel() +{ +} + +void Panel::init() +{ + Containment::init(); + + Plasma::Corona *c = corona(); + connect(c, SIGNAL(containmentAdded(Plasma::Containment*)), + this, SLOT(containmentAdded(Plasma::Containment*))); + + KAction *lockAction = new KAction(this); + addAction("lock panel", lockAction); + lockAction->setText(i18n("Lock Panel")); + lockAction->setIcon(KIcon("object-locked")); + QObject::connect(lockAction, SIGNAL(triggered(bool)), this, SLOT(toggleImmutability())); + lockAction->setShortcut(KShortcut("alt+d, l")); + lockAction->setShortcutContext(Qt::ApplicationShortcut); + + QAction *configureAction = new QAction(KIcon("configure"), i18n("Settings"), this); + addAction("configure panel", configureAction); + connect(configureAction, SIGNAL(triggered(bool)), this, SLOT(showToolBox())); +} + +void Panel::toggleImmutability() +{ + if (immutability() == Plasma::UserImmutable) { + setImmutability(Plasma::Mutable); + } else if (immutability() == Plasma::Mutable) { + setImmutability(Plasma::UserImmutable); + } +} + +void Panel::containmentAdded(Plasma::Containment *containment) +{ + connect(containment, SIGNAL(toolBoxVisibilityChanged(bool)), + this, SLOT(updateConfigurationMode(bool))); +} + +void Panel::showToolBox() +{ + setToolBoxOpen(true); +} + +void Panel::backgroundChanged() +{ + constraintsEvent(Plasma::LocationConstraint); +} + +void Panel::layoutApplet(Plasma::Applet* applet, const QPointF &pos) +{ + // this gets called whenever an applet is added, and we add it to our m_layoutout + + if (!m_layout) { + return; + } + + Plasma::FormFactor f = formFactor(); + int insertIndex = -1; + + //if pos is (-1,-1) insert at the end of the panel + if (pos != QPoint(-1, -1)) { + for (int i = 0; i < m_layout->count(); ++i) { + QRectF siblingGeometry = m_layout->itemAt(i)->geometry(); + if (f == Plasma::Horizontal) { + qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0; + if (pos.x() < middle) { + insertIndex = i; + break; + } else if (pos.x() <= siblingGeometry.right()) { + insertIndex = i + 1; + break; + } + } else { // Plasma::Vertical + qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0; + if (pos.y() < middle) { + insertIndex = i; + break; + } else if (pos.y() <= siblingGeometry.bottom()) { + insertIndex = i + 1; + break; + } + } + } + } + + if (insertIndex == -1) { + m_layout->addItem(applet); + } else { + m_layout->insertItem(insertIndex, applet); + } + + connect(applet, SIGNAL(sizeHintChanged(Qt::SizeHint)), this, SLOT(updateSize())); +} + +void Panel::appletRemoved(Plasma::Applet* applet) +{ + //shrink the panel if possible + if (formFactor() == Plasma::Horizontal) { + resize(size().width() - applet->size().width(), size().height()); + } else { + resize(size().width(), size().height() - applet->size().height()); + } + layout()->setMaximumSize(size()); +} + +void Panel::updateSize() +{ + Plasma::Applet *applet = qobject_cast(sender()); + + if (applet) { + if (formFactor() == Plasma::Horizontal) { + const int delta = applet->preferredWidth() - applet->size().width(); + //setting the preferred width when delta = 0 and preferredWidth() < minimumWidth() + // leads to the same thing as setPreferredWidth(minimumWidth()) + if (delta != 0) { + setPreferredWidth(preferredWidth() + delta); + } + } else if (formFactor() == Plasma::Vertical) { + const int delta = applet->preferredHeight() - applet->size().height(); + if (delta != 0) { + setPreferredHeight(preferredHeight() + delta); + } + } + + resize(preferredSize()); + } +} + +void Panel::updateBorders() +{ + FrameSvg::EnabledBorders enabledBorders = FrameSvg::AllBorders; + + kDebug() << "!!!!!!!!!!!!!!!! location be:" << location(); + switch (location()) { + case BottomEdge: + enabledBorders = FrameSvg::TopBorder; + break; + case TopEdge: + enabledBorders = FrameSvg::BottomBorder; + break; + case LeftEdge: + enabledBorders = FrameSvg::RightBorder; + break; + case RightEdge: + enabledBorders = FrameSvg::LeftBorder; + break; + default: + break; + } + + qreal topHeight = 0; + qreal bottomHeight = 0; + qreal leftWidth = 0; + qreal rightWidth = 0; + + //activate borders and fetch sizes again + m_background->setEnabledBorders(enabledBorders); + m_background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight); + + //FIXME: this will be probably just killed not kept in this zombie state :) +#if 0 + //calculation of extra margins has to be done after getMargins + if (formFactor() == Vertical) { + //hardcoded extra margin for the toolbox right now + if (immutability() == Mutable) { + bottomHeight += 20; + } + //Default to horizontal for now + } else { + //hardcoded extra margin for the toolbox for now + if (immutability() == Mutable) { + if (QApplication::layoutDirection() == Qt::RightToLeft) { + leftWidth += 20; + } else { + rightWidth += 20; + } + } + } +#endif + + switch (location()) { + case LeftEdge: + rightWidth = qMin(rightWidth, qMax(qreal(1), size().width() - KIconLoader::SizeMedium)); + break; + case RightEdge: + leftWidth = qMin(leftWidth, qMax(qreal(1), size().width() - KIconLoader::SizeMedium)); + break; + case TopEdge: + bottomHeight = qMin(bottomHeight, qMax(qreal(1), size().height() - KIconLoader::SizeMedium)); + break; + case BottomEdge: + topHeight = qMin(topHeight, qMax(qreal(1), size().height() - KIconLoader::SizeMedium)); + break; + default: + break; + } + + //invalidate the layout and set again + if (layout()) { + layout()->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight); + layout()->invalidate(); + } + + update(); +} + +void Panel::constraintsEvent(Plasma::Constraints constraints) +{ + kDebug() << "constraints updated with" << constraints << "!!!!!!"; + + if (constraints & Plasma::FormFactorConstraint) { + Plasma::FormFactor form = formFactor(); + Qt::Orientation layoutDirection = form == Plasma::Vertical ? Qt::Vertical : Qt::Horizontal; + + // create our layout! + if (layout()) { + QGraphicsLayout *lay = layout(); + QGraphicsLinearLayout * linearLay = dynamic_cast(lay); + if (linearLay) { + linearLay->setOrientation(layoutDirection); + } + } else { + m_layout = new QGraphicsLinearLayout(this); + m_layout->setOrientation(layoutDirection); + m_layout->setContentsMargins(0, 0, 0, 0); + m_layout->setSpacing(4); + m_layout->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding)); + setLayout(m_layout); + updateBorders(); + + foreach (Applet *applet, applets()) { + m_layout->addItem(applet); + } + } + } + + //we need to know if the width or height is 100% + if (constraints & Plasma::LocationConstraint || constraints & Plasma::SizeConstraint) { + QSize size = geometry().size().toSize(); + QRectF screenRect = screen() >= 0 ? QApplication::desktop()->screenGeometry(screen()) : geometry(); + + if (formFactor() == Horizontal || + formFactor() == Vertical) { + m_background->setElementPrefix(location()); + } else { + m_background->setElementPrefix(QString()); + } + + m_background->resizeFrame(size); + updateBorders(); + } + + if (constraints & Plasma::SizeConstraint && m_appletOverlay) { + m_appletOverlay->resize(size()); + } + + //FIXME: this seems the only way to correctly resize the layout the first time when the + // saved panel size is less than the default is to setting a maximum size. + // this shouldn't happen. maybe even a qgraphicslayout bug? + if (layout() && (constraints & Plasma::SizeConstraint)) { + layout()->setMaximumSize(size()); + } + + if (constraints & Plasma::LocationConstraint) { + setFormFactorFromLocation(location()); + } + + if (constraints & Plasma::ImmutableConstraint) { + updateBorders(); + + QAction *a = action("lock panel"); + if (a) { + switch (immutability()) { + case Plasma::SystemImmutable: + a->setEnabled(false); + a->setVisible(false); + break; + case Plasma::UserImmutable: + a->setText(i18n("Unlock Panel")); + a->setIcon(KIcon("object-unlocked")); + a->setEnabled(true); + a->setVisible(true); + break; + case Plasma::Mutable: + a->setText(i18n("Lock Panel")); + a->setIcon(KIcon("object-locked")); + a->setEnabled(true); + a->setVisible(true); + break; + } + } + a = action("configure panel"); + if (a) { + switch (immutability()) { + case Plasma::Mutable: + a->setEnabled(true); + a->setVisible(true); + break; + default: + a->setEnabled(false); + a->setVisible(false); + } + } + } + + if (constraints & Plasma::StartupCompletedConstraint) { + connect(this, SIGNAL(appletAdded(Plasma::Applet*,QPointF)), + this, SLOT(layoutApplet(Plasma::Applet*,QPointF))); + delete action("remove"); + } +} + +QList Panel::contextualActions() +{ + QList actions; + + QAction *a = action("lock panel"); + if (a) { + actions << a; + } + a = action("configure panel"); + if (a) { + actions << a; + } + + return actions; +} + +void Panel::updateConfigurationMode(bool config) +{ + if (config && !m_appletOverlay && immutability() == Plasma::Mutable) { + m_appletOverlay = new LinearAppletOverlay(this, m_layout); + m_appletOverlay->resize(size()); + connect (m_appletOverlay, SIGNAL(dropRequested(QGraphicsSceneDragDropEvent*)), + this, SLOT(overlayRequestedDrop(QGraphicsSceneDragDropEvent*))); + } else if (!config) { + delete m_appletOverlay; + m_appletOverlay = 0; + } +} + +void Panel::overlayRequestedDrop(QGraphicsSceneDragDropEvent *event) +{ + dropEvent(event); +} + +//TODO: fold it into saveContents even if it's not strictly contents related? +void Panel::saveState(KConfigGroup &config) const +{ + config.writeEntry("minimumSize", minimumSize()); + config.writeEntry("maximumSize", maximumSize()); +} + +void Panel::paintInterface(QPainter *painter, + const QStyleOptionGraphicsItem *option, + const QRect& contentsRect) +{ + Q_UNUSED(contentsRect) + + //FIXME: this background drawing is bad and ugly =) + // draw the background untransformed (saves lots of per-pixel-math) + painter->save(); + painter->resetTransform(); + + const Containment::StyleOption *containmentOpt = qstyleoption_cast(option); + + QRect viewGeom; + if (containmentOpt) { + viewGeom = containmentOpt->view->geometry(); + } + + painter->fillRect(option->exposedRect, Qt::transparent); + m_background->paintFrame(painter, option->exposedRect, option->exposedRect); + + + // restore transformation and composition mode + painter->restore(); +} + +void Panel::setFormFactorFromLocation(Plasma::Location loc) { + switch (loc) { + case BottomEdge: + case TopEdge: + //kDebug() << "setting horizontal form factor"; + setFormFactor(Plasma::Horizontal); + break; + case RightEdge: + case LeftEdge: + //kDebug() << "setting vertical form factor"; + setFormFactor(Plasma::Vertical); + break; + case Floating: + //TODO: implement a form factor for floating panels + kDebug() << "Floating is unimplemented."; + break; + default: + kDebug() << "invalid location!!"; + } +} + +void Panel::restore(KConfigGroup &group) +{ + Containment::restore(group); + + KConfigGroup appletsConfig(&group, "Applets"); + + QMap oderedApplets; + QList unoderedApplets; + + foreach (Applet *applet, applets()) { + KConfigGroup appletConfig(&appletsConfig, QString::number(applet->id())); + KConfigGroup layoutConfig(&appletConfig, "LayoutInformation"); + + int order = layoutConfig.readEntry("Order", -1); + + if (order > -1) { + oderedApplets[order] = applet; + //if LayoutInformation is not available use the usual way, as a bonus makes it retrocompatible with oler configs + } else { + unoderedApplets.append(applet); + } + + connect(applet, SIGNAL(sizeHintChanged(Qt::SizeHint)), this, SLOT(updateSize())); + } + + foreach (Applet *applet, oderedApplets) { + m_layout->addItem(applet); + } + + foreach (Applet *applet, unoderedApplets) { + layoutApplet(applet, applet->pos()); + } + + updateSize(); +} + +void Panel::saveContents(KConfigGroup &group) const +{ + Containment::saveContents(group); + + if (!m_layout) { + return; + } + + KConfigGroup appletsConfig(&group, "Applets"); + for (int order = 0; order < m_layout->count(); ++order) { + const Applet *applet = dynamic_cast(m_layout->itemAt(order)); + if (applet) { + KConfigGroup appletConfig(&appletsConfig, QString::number(applet->id())); + KConfigGroup layoutConfig(&appletConfig, "LayoutInformation"); + + layoutConfig.writeEntry("Order", order); + } + } +} + +K_EXPORT_PLASMA_APPLET(netpanel, Panel) + +#include "panel.moc" + diff --git a/plasma/netbook/containments/netpanel/panel.h b/plasma/netbook/containments/netpanel/panel.h new file mode 100644 index 00000000..6871ba07 --- /dev/null +++ b/plasma/netbook/containments/netpanel/panel.h @@ -0,0 +1,89 @@ +/* +* Copyright 2007 by Alex Merry +* Copyright 2008 by Alexis Ménard +* +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License version 2, +* or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef PLASMA_PANEL_H +#define PLASMA_PANEL_H + +#include + +class QAction; +class QGraphicsLinearLayout; +class LinearAppletOverlay; + +namespace Plasma +{ + class FrameSvg; +} + +class Panel : public Plasma::Containment +{ + Q_OBJECT + Q_PROPERTY(QString shadowPath READ shadowPath) + +public: + Panel(QObject *parent, const QVariantList &args); + ~Panel(); + void init(); + + void constraintsEvent(Plasma::Constraints constraints); + + void paintInterface(QPainter *painter, + const QStyleOptionGraphicsItem *option, + const QRect &contentsRect); + void paintBackground(QPainter *painter, const QRect &contentsRect); + QList contextualActions(); + + QString shadowPath() {return "widgets/panel-background";} + +protected: + void saveState(KConfigGroup &config) const; + + void saveContents(KConfigGroup &group) const; + void restore(KConfigGroup &group); + +private Q_SLOTS: + void toggleImmutability(); + void backgroundChanged(); + void layoutApplet(Plasma::Applet* applet, const QPointF &pos); + void appletRemoved(Plasma::Applet* applet); + void updateSize(); + void updateConfigurationMode(bool config); + void overlayRequestedDrop(QGraphicsSceneDragDropEvent *event); + void containmentAdded(Plasma::Containment *containment); + void showToolBox(); + +private: + /** + * update the formfactor based on the location + */ + void setFormFactorFromLocation(Plasma::Location loc); + + /** + * recalculate which borders to show + */ + void updateBorders(); + + Plasma::FrameSvg *m_background; + QGraphicsLinearLayout *m_layout; + LinearAppletOverlay *m_appletOverlay; +}; + + +#endif // PLASMA_PANEL_H diff --git a/plasma/netbook/containments/netpanel/plasma-containment-netpanel.desktop b/plasma/netbook/containments/netpanel/plasma-containment-netpanel.desktop new file mode 100644 index 00000000..bbe343ef --- /dev/null +++ b/plasma/netbook/containments/netpanel/plasma-containment-netpanel.desktop @@ -0,0 +1,155 @@ +[Desktop Entry] +Name=Panel for Netbooks +Name[ar]=لوحة للحاسب المحمول الشبكي +Name[ast]=Panel pa netbooks +Name[bg]=Панел за нетбук +Name[bn]=নেটবুক-এর জন্য প্যানেল +Name[bs]=panel za netbuke +Name[ca]=Plafó per a ordinadors ultraportàtils +Name[ca@valencia]=Plafó per a ordinadors ultraportàtils +Name[cs]=Panel pro Netbooky +Name[csb]=Panel dlô Netbooków +Name[da]=Panel til netbooks +Name[de]=Kontrollleiste für Netbooks +Name[el]=Πίνακας για Netbooks +Name[en_GB]=Panel for Netbooks +Name[eo]=Panelo por malgrandaj komputiloj +Name[es]=Panel para netbooks +Name[et]=Väikesülearvuti paneel +Name[eu]=Netbooketarako panela +Name[fi]=Paneeli miniläppäreille +Name[fr]=Tableau de bord pour les ultra portables +Name[fy]=Paniel foar Netbooks +Name[gl]=Panel para ultraportátiles +Name[he]=לוח עבור נטבוקים +Name[hi]=नेटबुक के लिए पटल +Name[hr]=Ploča za Netbooke +Name[hu]=Netbook panel +Name[ia]=Pannello pro Netbooks +Name[id]=Panel untuk Komputer Mini +Name[is]=Spjald fyrir smáfartölvur +Name[ja]=ネットブックのパネル +Name[kk]=Нетбуктерге арналған панель +Name[km]=បន្ទះ​សម្រាប់ Netbooks +Name[kn]=ನೆಟ್‌ಬುಕ್‌ಗಳಿಗಾಗಿನ ಫಲಕ +Name[ko]=넷북을 위한 패널 +Name[lt]=Pultas Netbukams +Name[lv]=Panelis mazdatoriem +Name[ml]=നെറ്റ്ബുക്കുകള്‍ക്കു വേണ്ടിയുള്ള പാളി +Name[mr]=नेटबूक करिता पटल +Name[nb]=Panel for nettbok +Name[nds]=Paneel för Nettböker +Name[nl]=Paneel voor netbooks +Name[nn]=Panel for mini-PC-ar +Name[pa]=ਨੈੱਟਬੁੱਕ ਲਈ ਪੈਨਲ +Name[pl]=Panel dla netbooków +Name[pt]=Painel para Netbooks +Name[pt_BR]=Painel para Netbooks +Name[ro]=Panou pentru netbook-uri +Name[ru]=Панель для нетбуков +Name[si]=නෙට්බුක් සඳහා පැනලය +Name[sk]=Panel pre Netbooky +Name[sl]=Pult za male prenosnike +Name[sr]=панел за нетбуке +Name[sr@ijekavian]=панел за нетбуке +Name[sr@ijekavianlatin]=panel za netbuke +Name[sr@latin]=panel za netbuke +Name[sv]=Panel för bärbara nätdatorer +Name[tg]=Панел баро Нетбук +Name[th]=แถบพาเนลสำหรับเน็ตบุ้ค +Name[tr]=Netbooklar için Panel +Name[ug]=تور كومپيۇتېرنىڭ تاختىسى +Name[uk]=Панель для субноутбука +Name[wa]=Scriftôr po les poirtåvès éndjoletes +Name[x-test]=xxPanel for Netbooksxx +Name[zh_CN]=笔记本面板 +Name[zh_TW]=Netbooks 的面板 +Comment=A containment for a panel +Comment[af]='n Plekhouer vir 'n paneel +Comment[ar]=حاوية للوحة +Comment[ast]=Un contenedor pa un panel +Comment[be@latin]=Jomišča dla paneli +Comment[bg]=Контейнер за панел +Comment[bs]=Sadržalac za panel +Comment[ca]=Un contenidor per un plafó +Comment[ca@valencia]=Un contenidor per un plafó +Comment[cs]=Kontejner pro panel +Comment[da]=En beholder til et panel +Comment[de]=Ein Behältnis für eine Kontrollleiste +Comment[el]=Ένας υποδοχέας για έναν πίνακα +Comment[en_GB]=A containment for a panel +Comment[eo]=Panelujo +Comment[es]=Un contenedor para un panel +Comment[et]=Paneeli konteiner +Comment[eu]=Panel baterako edukiontzi bat +Comment[fi]=Sovelmasäiliö paneelille +Comment[fr]=Un conteneur pour un tableau de bord +Comment[fy]=In ynslúter foar in paniel +Comment[ga]=Coimeádán le haghaidh painéil +Comment[gl]=Un contido para un panel +Comment[gu]=પેનલ માટે ધરાવનાર +Comment[he]=תיבה ללוח +Comment[hi]=फलक के लिए कंटेनमेंट +Comment[hne]=पेनल बर कंटेनमेंट +Comment[hr]=Okruženje za panel +Comment[hu]=Tartóobjektum a panelhez +Comment[ia]=Un contento pro un pannello +Comment[id]=Pembatasan untuk panel +Comment[is]=Afmörkun fyrir spjald +Comment[ja]=プラズモイド (Plasma パネル) の入れ物 +Comment[kk]=Панельдің ішіндегісі +Comment[km]=ការ​ផ្ទុក​សម្រាប់​បន្ទះ +Comment[kn]=ಪುಟೀಪಿಗೆ (ಪಾನಲ್) ಒಂದು ಧಾರಕ +Comment[ko]=모든 것을 포함하는 패널 +Comment[lt]=Pulto laikiklis +Comment[lv]=Ietvērums panelim +Comment[ml]=പാളി വെയ്ക്കാനുള്ള കണ്ടൈന്‍മെന്റ് +Comment[mr]=पटल करिता एक कंटेनर +Comment[nb]=En beholder for et panel +Comment[nds]=En Gelaats för en Paneel +Comment[ne]=प्यानलका लागि एउटा रोकथाम +Comment[nl]=Een insluiting voor een paneel +Comment[nn]=Ein behaldar for panel +Comment[or]=ଫଳକ ପାଇଁ ଗୋଟିଏ ପ୍ୟାନେଲ +Comment[pa]=ਇੱਕ ਪੈਨਲ ਲਈ ਕੰਨਟੇਨਮੈਂਟ +Comment[pl]=Kontener dla panelu +Comment[pt]=Um contentor para um painel +Comment[pt_BR]=Um contêiner para um painel +Comment[ro]=Container pentru un panou +Comment[ru]=Контейнер панели +Comment[se]=Lihtti mii sisttisdoallá panela +Comment[si]=පැනලය සඳහා ධාරකය +Comment[sk]=Kontajner pre panel +Comment[sl]=Vsebnik za pult +Comment[sr]=Садржалац за панел +Comment[sr@ijekavian]=Садржалац за панел +Comment[sr@ijekavianlatin]=Sadržalac za panel +Comment[sr@latin]=Sadržalac za panel +Comment[sv]=En omgivning för en panel +Comment[ta]=A containment for a panel +Comment[te]=ప్యానల్ కొరకు ఒక కంటైన్‌మెంట్ +Comment[tg]=Контейнер для панели +Comment[th]=ส่วนบรรจุสำหรับพาเนล +Comment[tr]=Panel için bir tutucu +Comment[ug]=تاختا قاچىسى +Comment[uk]=Вмістилище для панелі +Comment[wa]=On contneu pos on scriftôr +Comment[x-test]=xxA containment for a panelxx +Comment[zh_CN]=面板容器 +Comment[zh_TW]=面板容器 +Icon= +Type=Service +X-KDE-ServiceTypes=Plasma/Applet,Plasma/Containment +X-Plasma-ContainmentCategories=netbook,panel +NoDisplay=true + +X-KDE-Library=plasma_containment_netpanel +X-KDE-PluginInfo-Author=The Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=netpanel +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Containments +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/containments/sal/CMakeLists.txt b/plasma/netbook/containments/sal/CMakeLists.txt new file mode 100644 index 00000000..7d6c4215 --- /dev/null +++ b/plasma/netbook/containments/sal/CMakeLists.txt @@ -0,0 +1,26 @@ + +set(sal_SRCS + sal.cpp + itemcontainer.cpp + itemview.cpp + ../common/linearappletoverlay.cpp + ../common/appletmovespacer.cpp + stripwidget.cpp + resultwidget.cpp + runnersconfig.cpp + iconactioncollection.cpp + models/krunnermodel.cpp + models/standarditemfactory.cpp + models/favouritesmodel.cpp + models/kservicemodel.cpp + ) + +kde4_add_plugin(plasma_containment_sal ${sal_SRCS}) +target_link_libraries(plasma_containment_sal ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KCMUTILS_LIBS} ) + +install(TARGETS plasma_containment_sal DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containment-sal.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES plasma-sal-menu.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) + +file(GLOB services services/*.desktop) +install(FILES ${services} DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/netbook/containments/sal/Messages.sh b/plasma/netbook/containments/sal/Messages.sh new file mode 100644 index 00000000..2692643c --- /dev/null +++ b/plasma/netbook/containments/sal/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_applet_sal.pot diff --git a/plasma/netbook/containments/sal/iconactioncollection.cpp b/plasma/netbook/containments/sal/iconactioncollection.cpp new file mode 100644 index 00000000..c1ed8f66 --- /dev/null +++ b/plasma/netbook/containments/sal/iconactioncollection.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "iconactioncollection.h" + + +IconActionCollection::IconActionCollection(Plasma::Applet *applet, QObject *parent) + : QObject(parent), + m_immutability(Plasma::Mutable) +{ + if (applet) { + connect (applet, SIGNAL(immutabilityChanged(Plasma::ImmutabilityType)), this, SLOT(immutabilityChanged(Plasma::ImmutabilityType))); + m_immutability = Plasma::Mutable; + } +} + +IconActionCollection::~IconActionCollection() +{ +} + +void IconActionCollection::addAction(QAction *action) +{ + if (action) { + m_actions.insert(action); + connect (action, SIGNAL(destroyed(QObject*)), this, SLOT(actionDestroyed(QObject*))); + action->setVisible(m_immutability == Plasma::Mutable); + action->setEnabled(m_immutability == Plasma::Mutable); + } +} + +void IconActionCollection::removeAction(QAction *action) +{ + m_actions.remove(action); +} + + + +QList IconActionCollection::actions() const +{ + return m_actions.toList(); +} + + + +void IconActionCollection::actionDestroyed(QObject *object) +{ + m_actions.remove(static_cast(object)); +} + +void IconActionCollection::immutabilityChanged(Plasma::ImmutabilityType immutability) +{ + m_immutability = immutability; + + foreach (QAction *action, m_actions) { + action->setVisible(immutability == Plasma::Mutable); + action->setEnabled(immutability == Plasma::Mutable); + } +} + + +#include "iconactioncollection.moc" diff --git a/plasma/netbook/containments/sal/iconactioncollection.h b/plasma/netbook/containments/sal/iconactioncollection.h new file mode 100644 index 00000000..dff4a78a --- /dev/null +++ b/plasma/netbook/containments/sal/iconactioncollection.h @@ -0,0 +1,50 @@ +/* + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLASMA_ICONACTIONCOLLECTION_H +#define PLASMA_ICONACTIONCOLLECTION_H + +#include + +#include +#include + +class IconActionCollection : public QObject +{ + Q_OBJECT + +public: + IconActionCollection(Plasma::Applet *applet, QObject *parent = 0); + ~IconActionCollection(); + + void addAction(QAction *action); + void removeAction(QAction *action); + + QList actions() const; + +protected Q_SLOTS: + void actionDestroyed(QObject *object); + void immutabilityChanged(Plasma::ImmutabilityType immutability); + +private: + QSet m_actions; + Plasma::ImmutabilityType m_immutability; +}; + +#endif diff --git a/plasma/netbook/containments/sal/itemcontainer.cpp b/plasma/netbook/containments/sal/itemcontainer.cpp new file mode 100644 index 00000000..459ed609 --- /dev/null +++ b/plasma/netbook/containments/sal/itemcontainer.cpp @@ -0,0 +1,721 @@ +/* + * Copyright 2009 by Marco Martin + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "itemcontainer.h" +#include "itemview.h" +#include "resultwidget.h" +#include "models/commonmodel.h" +#include "iconactioncollection.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +ItemContainer::ItemContainer(ItemView *parent) + : QGraphicsWidget(parent), + m_orientation(Qt::Vertical), + m_currentIconIndexX(-1), + m_currentIconIndexY(-1), + m_iconSize(-1), + m_spacerIndex(-1), + m_firstRelayout(true), + m_dragAndDropMode(ItemContainer::NoDragAndDrop), + m_dragging(false), + m_model(0), + m_itemView(parent) +{ + m_positionAnimation = new QPropertyAnimation(this, "pos", this); + m_positionAnimation->setEasingCurve(QEasingCurve::InOutQuad); + m_positionAnimation->setDuration(250); + + setIconSize(KIconLoader::SizeHuge); + + QGraphicsItem *pi = parent->parentItem(); + Plasma::Applet *applet = 0; + //FIXME: this way to find the Applet is quite horrible + while (pi) { + applet = dynamic_cast(pi); + if (applet) { + break; + } else { + pi = pi->parentItem(); + } + } + m_iconActionCollection = new IconActionCollection(applet, this); + + setFocusPolicy(Qt::StrongFocus); + setAcceptHoverEvents(true); + m_hoverIndicator = new Plasma::ItemBackground(this); + m_hoverIndicator->setZValue(-100); + m_hoverIndicator->hide(); + + m_relayoutTimer = new QTimer(this); + m_relayoutTimer->setSingleShot(true); + connect(m_relayoutTimer, SIGNAL(timeout()), this, SLOT(relayout())); + + m_setCurrentTimer = new QTimer(this); + m_setCurrentTimer->setSingleShot(true); + connect(m_setCurrentTimer, SIGNAL(timeout()), this, SLOT(syncCurrentItem())); + + m_hideUsedItemsTimer = new QTimer(this); + m_hideUsedItemsTimer->setSingleShot(true); + connect(m_hideUsedItemsTimer, SIGNAL(timeout()), this, SLOT(hideUsedItems())); +} + +ItemContainer::~ItemContainer() +{} + +void ItemContainer::setCurrentItem(ResultWidget *currentIcon) +{ + if (m_relayoutTimer->isActive()) { + m_setCurrentTimer->start(400); + m_currentIcon = currentIcon; + return; + } + + QWeakPointer currentWeakIcon = currentIcon; + //m_currentIcon.clear(); + + if (m_currentIcon.data() != currentIcon) { + const int nColumns = qMax(1, (int)ceil(size().width() / m_cellSize.width())); + + for (int i = 0; i < m_model->rowCount(); ++i) { + QModelIndex index = m_model->index(i, 0, m_rootIndex); + ResultWidget *item = m_items.value(index); + + if (item == currentIcon) { + m_currentIconIndexX = i % nColumns; + m_currentIconIndexY = i / nColumns; + break; + } + } + } + + m_hoverIndicator->setTargetItem(currentIcon); +} + +void ItemContainer::syncCurrentItem() +{ + setCurrentItem(m_currentIcon.data()); +} + +ResultWidget *ItemContainer::currentItem() const +{ + return m_currentIcon.data(); +} + +//FIXME: remove +QList ItemContainer::items() const +{ + return m_items.values(); +} + +ResultWidget *ItemContainer::createItem(QModelIndex index) +{ + ResultWidget *item; + if (!m_usedItems.isEmpty()) { + int key = m_usedItems.keys().first(); + item = m_usedItems.values(key).first(); + m_usedItems.remove(key, item); + } else { + item = new ResultWidget(this); + item->setCacheMode(QGraphicsItem::ItemCoordinateCache); + item->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + item->hide(); + item->setPos(boundingRect().center().x(), size().height()); + } + + item->installEventFilter(m_itemView); + + if (index.isValid()) { + item->setPreferredIconSize(QSizeF(m_iconSize, m_iconSize)); + item->setMaximumIconSize(QSizeF(m_iconSize, m_iconSize)); + item->setMinimumIconSize(QSizeF(m_iconSize, m_iconSize)); + item->setIcon(index.data(Qt::DecorationRole).value()); + item->setText(index.data(Qt::DisplayRole).value()); + + Plasma::ToolTipContent toolTipData = Plasma::ToolTipContent(); + toolTipData.setAutohide(true); + toolTipData.setMainText(index.data(Qt::DisplayRole).value()); + toolTipData.setSubText(index.data(CommonModel::Description).value()); + toolTipData.setImage(index.data(Qt::DecorationRole).value()); + + Plasma::ToolTipManager::self()->registerWidget(this); + Plasma::ToolTipManager::self()->setContent(item, toolTipData); + + CommonModel::ActionType actionType = (CommonModel::ActionType)index.data(CommonModel::ActionTypeRole).value(); + if (actionType != CommonModel::NoAction) { + QAction *action = new QAction(item); + if (actionType == CommonModel::AddAction) { + action->setIcon(KIcon("favorites")); + } else { + action->setIcon(KIcon("list-remove")); + } + item->addIconAction(action); + m_iconActionCollection->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered())); + } + + qreal left, top, right, bottom; + m_hoverIndicator->getContentsMargins(&left, &top, &right, &bottom); + item->setContentsMargins(left, top, right, bottom); + + item->setMinimumSize(m_cellSize); + item->setMaximumSize(m_cellSize); + item->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(item, SIGNAL(clicked()), this, SLOT(itemClicked())); + connect(item, SIGNAL(dragStartRequested(ResultWidget*)), this, SLOT(itemRequestedDrag(ResultWidget*))); + } + + return item; +} + +void ItemContainer::disposeItem(ResultWidget *icon) +{ + if (m_usedItems.count() < 40) { + icon->removeIconAction(0); + disconnect(icon, 0, 0, 0); + + int row = m_itemToIndex.value(icon).row(); + row = icon->pos().x() + icon->pos().y()/10 * size().width(); + + m_usedItems.insert(row, icon); + icon->removeEventFilter(m_itemView); + + //if they will be immediately recycled they won't be hidden at all + m_hideUsedItemsTimer->start(500); + } else { + icon->deleteLater(); + } +} + +void ItemContainer::setOrientation(Qt::Orientation orientation) +{ + m_orientation = orientation; + if (orientation == Qt::Horizontal) { + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + } else { + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + } + askRelayout(); +} + +Qt::Orientation ItemContainer::orientation() const +{ + return m_orientation; +} + +void ItemContainer::setIconSize(int size) +{ + if (size == m_iconSize) { + return; + } + + m_iconSize = size; + + QFontMetrics fm(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DesktopFont)); + int cellSize = m_iconSize + fm.height()*2 + 40; + m_cellSize = QSize(cellSize, cellSize); + + foreach (ResultWidget *icon, m_items) { + icon->setPreferredIconSize(QSizeF(size, size)); + icon->setMaximumIconSize(QSizeF(size, size)); + icon->setMinimumIconSize(QSizeF(size, size)); + } +} + +int ItemContainer::iconSize() const +{ + return m_iconSize; +} + +void ItemContainer::setDragAndDropMode(DragAndDropMode mode) +{ + m_dragAndDropMode = mode; +} + +ItemContainer::DragAndDropMode ItemContainer::dragAndDropMode() const +{ + return m_dragAndDropMode; +} + +void ItemContainer::askRelayout() +{ + if (!m_relayoutTimer->isActive()) { + m_relayoutTimer->start(200); + } +} + +void ItemContainer::relayout() +{ + if (!m_model) { + return; + } + + + //FIXME: reserve a random fixed size for the scrollbars, regardless they're present or not + QSizeF availableSize(m_itemView->size() - QSizeF(30, 30)); + + + int nColumns = qMax(1, (int)availableSize.width() / m_cellSize.width()); + int nRows = qMax(1, (int)availableSize.height() / m_cellSize.height()); + + nColumns = qMin(m_model->rowCount(), nColumns); + nRows = qMin(m_model->rowCount(), nRows); + + setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + + if (m_orientation == Qt::Vertical) { + nRows = qMax(1, (int)ceil((qreal)m_model->rowCount() / nColumns)); + for (int i = 0; i <= m_model->rowCount() - 1; i++) { + + int actualIndex = i; + if (m_spacerIndex > -1) { + if (i >= m_spacerIndex) { + actualIndex = i+1; + } + if (i >= m_draggingIndex.row()) { + --actualIndex; + } + } + + const int row = actualIndex / nColumns; + const int column = actualIndex % nColumns; + + QModelIndex index = m_model->index(i, 0, m_rootIndex); + if (index == m_draggingIndex) { + continue; + } + + ResultWidget *icon = m_items.value(index); + if (icon) { + icon->animatePos(QPoint(column*m_cellSize.width(), row*m_cellSize.height())); + icon->show(); + } + } + } else { + nColumns = qMax(1, (int)ceil((qreal)m_model->rowCount() / nRows)); + for (int i = 0; i <= m_model->rowCount() - 1; i++) { + + int actualIndex = i; + if (m_spacerIndex > -1) { + if (i >= m_spacerIndex) { + actualIndex = i+1; + } + if (i >= m_draggingIndex.row()) { + --actualIndex; + } + } + + const int row = actualIndex % nRows; + const int column = actualIndex / nRows; + + QModelIndex index = m_model->index(i, 0, m_rootIndex); + if (index == m_draggingIndex) { + continue; + } + ResultWidget *icon = m_items.value(index); + if (icon) { + icon->animatePos(QPoint(column*m_cellSize.width(), row*m_cellSize.height())); + icon->show(); + } + } + } + + + m_itemView->setSnapSize(QSizeF(m_cellSize.width(), m_cellSize.height()) + QSizeF(0,0)); //TODO: items spacing? + + QSizeF newSize = sizeHint(Qt::MinimumSize, QSizeF()); + newSize = QSizeF(nColumns*m_cellSize.width(), nRows*m_cellSize.height()); + + setMaximumSize(newSize); + setPreferredSize(newSize); + resize(newSize); + m_relayoutTimer->stop(); + m_firstRelayout = false; +} + +void ItemContainer::itemRequestedDrag(ResultWidget *icon) +{ + if (m_dragging || dragAndDropMode() == NoDragAndDrop) { + return; + } + + if (dragAndDropMode() == MoveDragAndDrop) { + m_dragging = true; + icon->setZValue(900); + icon->installEventFilter(this); + m_draggingIndex = m_itemToIndex.value(icon); + //ugly but necessary to don't make it clipped + icon->setParentItem(0); + } + + QModelIndex index = m_itemToIndex.value(icon); + if (index.isValid()) { + emit dragStartRequested(index); + } +} + +void ItemContainer::keyPressEvent(QKeyEvent *event) +{ + const int nColumns = qMax(1, (int)ceil(size().width() / m_cellSize.width())); + const int nRows = qMax(1, (int)ceil(size().height() / m_cellSize.height())); + + switch (event->key()) { + case Qt::Key_Left: { + m_currentIcon.clear(); + while (!m_currentIcon.data()) { + m_currentIconIndexX = (nColumns + m_currentIconIndexX - 1) % nColumns; + m_currentIcon = m_items.value(m_model->index(nColumns*(m_currentIconIndexY)+m_currentIconIndexX, 0, m_rootIndex)); + } + m_hoverIndicator->setTargetItem(m_currentIcon.data()); + emit itemSelected(m_currentIcon.data()); + break; + } + case Qt::Key_Right: { + m_currentIcon.clear(); + while (!m_currentIcon.data()) { + m_currentIconIndexX = (m_currentIconIndexX + 1) % nColumns; + m_currentIcon = m_items.value(m_model->index(nColumns*(m_currentIconIndexY)+m_currentIconIndexX, 0, m_rootIndex)); + } + m_hoverIndicator->setTargetItem(m_currentIcon.data()); + emit itemSelected(m_currentIcon.data()); + break; + } + case Qt::Key_Up: { + m_currentIcon.clear(); + while (!m_currentIcon) { + m_currentIconIndexY = (nRows + m_currentIconIndexY - 1) % nRows; + m_currentIcon = m_items.value(m_model->index(nColumns*(m_currentIconIndexY)+m_currentIconIndexX, 0, m_rootIndex)); + } + m_hoverIndicator->setTargetItem(m_currentIcon.data()); + emit itemSelected(m_currentIcon.data()); + break; + } + case Qt::Key_Down: { + m_currentIcon.clear(); + while (!m_currentIcon.data()) { + m_currentIconIndexY = (m_currentIconIndexY + 1) % nRows; + m_currentIcon = m_items.value(m_model->index(nColumns*(m_currentIconIndexY)+m_currentIconIndexX, 0, m_rootIndex)); + } + m_hoverIndicator->setTargetItem(m_currentIcon.data()); + emit itemSelected(m_currentIcon.data()); + break; + } + case Qt::Key_Enter: + case Qt::Key_Return: + if (m_currentIcon) { + QModelIndex index = m_itemToIndex.value(m_currentIcon.data()); + if (index.isValid()) { + emit itemActivated(m_model->index(index.row(), 0, m_rootIndex)); + } + } + break; + case Qt::Key_Backspace: + case Qt::Key_Home: + emit resetRequested(); + break; + default: + break; + } +} + +QVariant ItemContainer::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemPositionChange) { + QPointF newPos = value.toPointF(); + if (m_dragging) { + return pos(); + } + } + + return QGraphicsWidget::itemChange(change, value); +} + +void ItemContainer::showSpacer(const QPointF &pos) +{ + if (pos == QPointF()) { + m_spacerIndex = -1; + } else { + m_spacerIndex = rowForPosition(pos); + //FIXME: this is not pretty, but rowForPosition should never return a number bigger than the model rows + if ((m_orientation == Qt::Horizontal && pos.x() > size().width()-m_cellSize.width()/2) || + (m_orientation == Qt::Vertical && pos.y() > size().height()-m_cellSize.height()/2)) { + m_spacerIndex++; + } + } + askRelayout(); +} + +bool ItemContainer::eventFilter(QObject *watched, QEvent *event) +{ + ResultWidget *icon = qobject_cast(watched); + + if (event->type() == QEvent::GraphicsSceneMouseMove) { + QGraphicsSceneMouseEvent *me = static_cast(event); + + icon->setPos(icon->mapToParent(me->pos()) - icon->boundingRect().center()); + m_dragging = false; + + m_itemView->setScrollPositionFromDragPosition(icon->mapToParent(me->pos())); + m_dragging = true; + + showSpacer(mapFromScene(me->scenePos())); + + askRelayout(); + } else if (event->type() == QEvent::GraphicsSceneMouseRelease) { + QGraphicsSceneMouseEvent *me = static_cast(event); + m_dragging = false; + icon->setZValue(10); + icon->removeEventFilter(this); + icon->setPos(icon->mapToItem(this, QPoint(0,0))); + icon->setParentItem(this); + + QModelIndex index = m_itemToIndex.value(icon); + if (index.isValid()) { + emit itemAskedReorder(index, mapFromScene(me->scenePos())); + } + + m_spacerIndex = -1; + m_draggingIndex = QModelIndex(); + askRelayout(); + } + + return false; +} + + +int ItemContainer::rowForPosition(const QPointF &point) +{ + const int nColumns = qMax(1, (int)ceil(size().width() / m_cellSize.width())); + const int nRows = qMax(1, (int)ceil(size().height() / m_cellSize.height())); + + int row = qMin(nRows-1, (int)round(point.y()/m_cellSize.height())); + int column = qMin(nColumns-1, (int)round(point.x()/m_cellSize.width())); + + kDebug() << "The item will be put at" << row; + + int modelRow = qMin(m_model->rowCount(), row*nColumns + qBound(0, column, nColumns)); + + kDebug() << "Corresponding to the model row" << modelRow; + + return modelRow; +} + +void ItemContainer::focusInEvent(QFocusEvent *event) +{ + Q_UNUSED(event) + + if (m_model->rowCount() > 0 && m_currentIconIndexX == -1) { + m_currentIconIndexX = 0; + m_currentIconIndexY = 0; + QModelIndex index = m_model->index(0, 0, m_rootIndex); + ResultWidget *item = m_items.value(index); + emit itemSelected(item); + setCurrentItem(item); + } else { + setCurrentItem(m_currentIcon.data()); + } +} + +void ItemContainer::focusOutEvent(QFocusEvent *event) +{ + Q_UNUSED(event) + + m_hoverIndicator->hide(); +} + +void ItemContainer::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + Q_UNUSED(event) + + if (!hasFocus()) { + m_hoverIndicator->hide(); + } +} + +void ItemContainer::resizeEvent(QGraphicsSceneResizeEvent *event) +{ + QGraphicsWidget *pw = parentWidget(); + if (pw) { + QRectF parentRect = pw->boundingRect(); + QPointF newPos(pos()); + if (size().width() < parentRect.size().width()) { + newPos.setX(parentRect.center().x() - size().width()/2); + } else { + newPos.setX(qMin(pos().x(), (qreal)0.0)); + } + if (size().height() < parentRect.size().height()) { + newPos.setY(parentRect.center().y() - size().height()/2); + } else { + newPos.setY(qMin(pos().y(), (qreal)0.0)); + } + if (m_positionAnimation->state() == QAbstractAnimation::Running) { + m_positionAnimation->stop(); + } + if (m_firstRelayout) { + setPos(newPos.toPoint()); + } else { + m_positionAnimation->setEndValue(newPos.toPoint()); + m_positionAnimation->start(); + } + } + + if ((m_orientation == Qt::Vertical && !qFuzzyCompare(event->newSize().width(), event->oldSize().width())) || + (m_orientation == Qt::Horizontal && !qFuzzyCompare(event->newSize().height(), event->oldSize().height()))) { + m_relayoutTimer->start(300); + } +} + +void ItemContainer::setModel(QAbstractItemModel *model) +{ + if (m_model) { + disconnect(m_model, 0, this, 0); + reset(); + } + + m_model = model; + connect (m_model, SIGNAL(modelAboutToBeReset()), this, SLOT(reset())); + connect (m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(generateItems(QModelIndex,int,int))); + connect (m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(removeItems(QModelIndex,int,int))); + + generateItems(m_rootIndex, 0, m_model->rowCount()); +} + +QAbstractItemModel *ItemContainer::model() const +{ + return m_model; +} + +void ItemContainer::reset() +{ + m_hoverIndicator->setTargetItem(0); + + + foreach (ResultWidget *icon, m_items) { + disposeItem(icon); + } + m_items.clear(); + m_itemToIndex.clear(); + askRelayout(); +} + +void ItemContainer::generateItems(const QModelIndex &parent, int start, int end) +{ + if (parent != m_rootIndex) { + return; + } + + for (int i = start; i <= end; i++) { + QModelIndex index = m_model->index(i, 0, m_rootIndex); + + if (index.isValid()) { + ResultWidget *icon = createItem(index); + + m_items.insert(QPersistentModelIndex(index), icon); + m_itemToIndex.insert(icon, QPersistentModelIndex(index)); + } + } + m_relayoutTimer->start(500); +} + +void ItemContainer::actionTriggered() +{ + ResultWidget *icon = static_cast(sender()->parent()); + QModelIndex index = m_itemToIndex.value(icon); + + CommonModel::ActionType actionType = (CommonModel::ActionType)index.data(CommonModel::ActionTypeRole).value(); + + if (actionType == CommonModel::RemoveAction) { + m_model->removeRow(index.row()); + } else if (actionType == CommonModel::AddAction) { + emit addActionTriggered(index); + } +} + +void ItemContainer::removeItems(const QModelIndex &parent, int start, int end) +{ + if (m_rootIndex != parent) { + return; + } + + for (int i = start; i <= end; i++) { + QModelIndex index = m_model->index(i, 0, m_rootIndex); + ResultWidget *icon = m_items.value(index); + disposeItem(icon); + m_items.remove(index); + m_itemToIndex.remove(icon); + } + m_relayoutTimer->start(500); +} + +void ItemContainer::itemClicked() +{ + ResultWidget *icon = qobject_cast(sender()); + + if (icon) { + QModelIndex i = m_itemToIndex.value(icon); + if (i.isValid()) { + QModelIndex index = m_model->index(i.row(), 0, m_rootIndex); + emit itemActivated(index); + } + } +} + +void ItemContainer::setRootIndex(QModelIndex index) +{ + m_rootIndex = index; + reset(); +} + +QModelIndex ItemContainer::rootIndex() const +{ + return m_rootIndex; +} + +void ItemContainer::hideUsedItems() +{ + QMapIterator i(m_usedItems); + while (i.hasNext()) { + i.next(); + foreach (ResultWidget *icon, m_usedItems.values(i.key())) { + icon->animateHide(); + } + } +} + +#include diff --git a/plasma/netbook/containments/sal/itemcontainer.h b/plasma/netbook/containments/sal/itemcontainer.h new file mode 100644 index 00000000..d44d24d5 --- /dev/null +++ b/plasma/netbook/containments/sal/itemcontainer.h @@ -0,0 +1,140 @@ +/* + * Copyright 2009 by Marco Martin + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ITEMCONTAINER_H +#define ITEMCONTAINER_H + +#include +#include + +#include + +#include +#include + +class QGraphicsGridLayout; +class QPropertyAnimation; +class QAbstractItemModel; + +namespace Plasma +{ + class ItemBackground; +} + +class ItemView; +class IconActionCollection; +class ResultWidget; + +class ItemContainer : public QGraphicsWidget +{ + Q_OBJECT + +public: + enum DragAndDropMode{ + NoDragAndDrop = 0, + CopyDragAndDrop = 1, + MoveDragAndDrop = 2 + }; + + ItemContainer(ItemView *parent); + ~ItemContainer(); + + void setCurrentItem(ResultWidget *currentItem); + ResultWidget *currentItem() const; + + void setOrientation(Qt::Orientation orientation); + Qt::Orientation orientation() const; + + void setIconSize(int size); + int iconSize() const; + + void showSpacer(const QPointF &pos); + + void setDragAndDropMode(DragAndDropMode mode); + DragAndDropMode dragAndDropMode() const; + + QListitems() const; + + void askRelayout(); + + void setModel(QAbstractItemModel *model); + QAbstractItemModel *model() const; + void setRootIndex(QModelIndex index); + QModelIndex rootIndex() const; + int rowForPosition(const QPointF &point); + +protected: + void focusInEvent(QFocusEvent *event); + void focusOutEvent(QFocusEvent *event); + void keyPressEvent(QKeyEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + void resizeEvent(QGraphicsSceneResizeEvent *event); + bool eventFilter(QObject *watched, QEvent *event); + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + ResultWidget *createItem(QModelIndex index); + void disposeItem(ResultWidget *icon); + +private Q_SLOTS: + void relayout(); + void syncCurrentItem(); + void itemRequestedDrag(ResultWidget *); + void reset(); + void generateItems(const QModelIndex &parent, int start, int end); + void removeItems(const QModelIndex &parent, int start, int end); + void itemClicked(); + void actionTriggered(); + void hideUsedItems(); + +Q_SIGNALS: + void itemSelected(ResultWidget *); + void itemActivated(const QModelIndex &); + void resetRequested(); + void itemAskedReorder(const QModelIndex &index, const QPointF &point); + void dragStartRequested(const QModelIndex &index); + void addActionTriggered(const QModelIndex &index); + +private: + QWeakPointer m_currentIcon; + ResultWidget *m_ghostIcon; + Plasma::ItemBackground *m_hoverIndicator; + QTimer *m_relayoutTimer; + QTimer *m_setCurrentTimer; + QTimer *m_hideUsedItemsTimer; + QHash m_items; + QHash m_itemToIndex; + //we store the old row to sort them, necessary to do a good animation + QMultiMap m_usedItems; + Qt::Orientation m_orientation; + QPropertyAnimation *m_positionAnimation; + int m_currentIconIndexX; + int m_currentIconIndexY; + int m_iconSize; + int m_spacerIndex; + QSize m_cellSize; + bool m_firstRelayout; + DragAndDropMode m_dragAndDropMode; + bool m_dragging; + QAbstractItemModel *m_model; + QModelIndex m_rootIndex; + QModelIndex m_draggingIndex; + ItemView *m_itemView; + IconActionCollection *m_iconActionCollection; +}; + +#endif diff --git a/plasma/netbook/containments/sal/itemview.cpp b/plasma/netbook/containments/sal/itemview.cpp new file mode 100644 index 00000000..ecd23906 --- /dev/null +++ b/plasma/netbook/containments/sal/itemview.cpp @@ -0,0 +1,213 @@ +/* + * Copyright 2009 by Marco Martin + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "itemview.h" +#include "itemcontainer.h" +#include "resultwidget.h" + +#include +#include +#include + + +ItemView::ItemView(QGraphicsWidget *parent) + : Plasma::ScrollWidget(parent) +{ + setFocusPolicy(Qt::StrongFocus); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_itemContainer = new ItemContainer(this); + setAlignment(Qt::AlignCenter); + setWidget(m_itemContainer); + m_noActivateTimer = new QTimer(this); + m_noActivateTimer->setSingleShot(true); + m_itemContainer->installEventFilter(this); + + connect(m_itemContainer, SIGNAL(itemSelected(ResultWidget*)), this, SIGNAL(itemSelected(ResultWidget*))); + connect(m_itemContainer, SIGNAL(itemActivated(QModelIndex)), this, SIGNAL(itemActivated(QModelIndex))); + connect(m_itemContainer, SIGNAL(resetRequested()), this, SIGNAL(resetRequested())); + connect(m_itemContainer, SIGNAL(itemSelected(ResultWidget*)), this, SLOT(selectItem(ResultWidget*))); + connect(m_itemContainer, SIGNAL(itemAskedReorder(QModelIndex,QPointF)), this, SIGNAL(itemAskedReorder(QModelIndex,QPointF))); + connect(m_itemContainer, SIGNAL(dragStartRequested(QModelIndex)), this, SIGNAL(dragStartRequested(QModelIndex))); + + connect(m_itemContainer, SIGNAL(addActionTriggered(QModelIndex)), this, SIGNAL(addActionTriggered(QModelIndex))); +} + +ItemView::~ItemView() +{} + +void ItemView::selectItem(ResultWidget *icon) +{ + if (!m_noActivateTimer->isActive()) { + ensureItemVisible(icon); + } +} + +void ItemView::setCurrentItem(ResultWidget *currentIcon) +{ + m_itemContainer->setCurrentItem(currentIcon); +} + +ResultWidget *ItemView::currentItem() const +{ + return m_itemContainer->currentItem(); +} + +void ItemView::focusInEvent(QFocusEvent *event) +{ + m_itemContainer->setFocus(); + Plasma::ScrollWidget::focusInEvent(event); +} + + +void ItemView::setOrientation(Qt::Orientation orientation) +{ + m_itemContainer->setOrientation(orientation); +} + +Qt::Orientation ItemView::orientation() const +{ + return m_itemContainer->orientation(); +} + +void ItemView::setIconSize(int size) +{ + m_itemContainer->setIconSize(size); +} + +QList ItemView::items() const +{ + return m_itemContainer->items(); +} + +int ItemView::iconSize() const +{ + return m_itemContainer->iconSize(); +} + +void ItemView::setDragAndDropMode(ItemContainer::DragAndDropMode mode) +{ + m_itemContainer->setDragAndDropMode(mode); +} + +ItemContainer::DragAndDropMode ItemView::dragAndDropMode() const +{ + return m_itemContainer->dragAndDropMode(); +} + +void ItemView::setScrollPositionFromDragPosition(const QPointF &point) +{ + const qreal xRatio = point.x() / size().width(); + const qreal yRatio = point.y() / size().height(); + + QPointF newPos(scrollPosition()); + + if (size().width() < contentsSize().width()) { + qreal newXPos = xRatio * (size().width() - contentsSize().width()); + newPos.setX(qBound(qreal(0.0), -newXPos, contentsSize().width() - viewportGeometry().width())); + } + if (size().height() < contentsSize().height()) { + newPos.setY(-(yRatio * (size().height() - contentsSize().height()))); + } + + setScrollPosition(newPos); +} + +void ItemView::resizeEvent(QGraphicsSceneResizeEvent *event) +{ + QRectF rect = boundingRect(); + QPointF newPos(m_itemContainer->pos()); + if (m_itemContainer->size().width() < rect.size().width()) { + newPos.setX(rect.center().x() - m_itemContainer->size().width()/2); + } else { + newPos.setX(qMin(m_itemContainer->pos().x(), (qreal)0.0)); + } + if (m_itemContainer->size().height() < rect.size().height()) { + newPos.setY(rect.center().y() - m_itemContainer->size().height()/2); + } else { + newPos.setY(qMin(m_itemContainer->pos().y(), (qreal)0.0)); + } + m_itemContainer->setPos(newPos.toPoint()); + m_itemContainer->askRelayout(); + + Plasma::ScrollWidget::resizeEvent(event); +} + +bool ItemView::eventFilter(QObject *watched, QEvent *event) +{ + ResultWidget *icon = qobject_cast(watched); + if (icon && event->type() == QEvent::GraphicsSceneHoverEnter) { + if (icon) { + m_itemContainer->setCurrentItem(icon); + } + } else if (watched == m_itemContainer && event->type() == QEvent::GraphicsSceneResize) { + + ScrollBarFlags scrollBars = NoScrollBar; + if (m_itemContainer->pos().x() < 0 || m_itemContainer->geometry().right() > size().width()) { + scrollBars |= HorizontalScrollBar; + } + if (m_itemContainer->pos().y() < 0 || m_itemContainer->geometry().bottom() > size().height()) { + scrollBars |= VerticalScrollBar; + } + emit scrollBarsNeededChanged(scrollBars); + } else if (watched == m_itemContainer && event->type() == QEvent::GraphicsSceneMove) { + m_noActivateTimer->start(300); + ScrollBarFlags scrollBars = NoScrollBar; + if (m_itemContainer->pos().x() < 0 || m_itemContainer->geometry().right() > size().width()) { + scrollBars |= HorizontalScrollBar; + } + if (m_itemContainer->pos().y() < 0 || m_itemContainer->geometry().bottom() > size().height()) { + scrollBars |= VerticalScrollBar; + } + emit scrollBarsNeededChanged(scrollBars); + } + + return Plasma::ScrollWidget::eventFilter(watched, event); +} + +void ItemView::showSpacer(const QPointF &pos) +{ + m_itemContainer->showSpacer(pos); +} + +void ItemView::setModel(QAbstractItemModel *model) +{ + m_itemContainer->setModel(model); +} + +QAbstractItemModel *ItemView::model() const +{ + return m_itemContainer->model(); +} + +void ItemView::setRootIndex(QModelIndex index) +{ + m_itemContainer->setRootIndex(index); +} + +QModelIndex ItemView::rootIndex() const +{ + return m_itemContainer->rootIndex(); +} + +int ItemView::rowForPosition(const QPointF &point) +{ + return m_itemContainer->rowForPosition(point); +} + +#include diff --git a/plasma/netbook/containments/sal/itemview.h b/plasma/netbook/containments/sal/itemview.h new file mode 100644 index 00000000..f93ed39e --- /dev/null +++ b/plasma/netbook/containments/sal/itemview.h @@ -0,0 +1,102 @@ +/* + * Copyright 2009 by Marco Martin + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ITEMVIEW_H +#define ITEMVIEW_H + +#include +#include + +#include + +#include "itemcontainer.h" + + +namespace Plasma +{ + class IconWidget; +} + +class QTimer; + +class ItemView : public Plasma::ScrollWidget +{ + Q_OBJECT + +public: + enum ScrollBarNeeded { + NoScrollBar = 0, + HorizontalScrollBar = 1, + VerticalScrollBar = 2, + AllScrollBars = HorizontalScrollBar|VerticalScrollBar + }; + Q_DECLARE_FLAGS(ScrollBarFlags, ScrollBarNeeded) + + ItemView(QGraphicsWidget *parent); + ~ItemView(); + + void setCurrentItem(ResultWidget *currentItem); + ResultWidget *currentItem() const; + + void setOrientation(Qt::Orientation orientation); + Qt::Orientation orientation() const; + + void showSpacer(const QPointF &pos); + + void setIconSize(int size); + int iconSize() const; + + QListitems() const; + + void setDragAndDropMode(ItemContainer::DragAndDropMode mode); + ItemContainer::DragAndDropMode dragAndDropMode() const; + + qreal positionToWeight(const QPointF &point); + void setModel(QAbstractItemModel *model); + QAbstractItemModel *model() const; + void setRootIndex(QModelIndex index); + QModelIndex rootIndex() const; + int rowForPosition(const QPointF &point); + +public Q_SLOTS: + void setScrollPositionFromDragPosition(const QPointF &point); + +protected: + void resizeEvent(QGraphicsSceneResizeEvent *event); + bool eventFilter(QObject *watched, QEvent *event); + void focusInEvent(QFocusEvent *event); + +protected Q_SLOTS: + void selectItem(ResultWidget *icon); + +Q_SIGNALS: + void itemSelected(ResultWidget *); + void itemActivated(const QModelIndex &index); + void resetRequested(); + void scrollBarsNeededChanged(ItemView::ScrollBarFlags); + void itemAskedReorder(const QModelIndex &index, const QPointF &point); + void dragStartRequested(const QModelIndex &index); + void addActionTriggered(const QModelIndex &index); + +private: + ItemContainer *m_itemContainer; + QTimer *m_noActivateTimer; +}; + +#endif diff --git a/plasma/netbook/containments/sal/models/commonmodel.h b/plasma/netbook/containments/sal/models/commonmodel.h new file mode 100644 index 00000000..588458bc --- /dev/null +++ b/plasma/netbook/containments/sal/models/commonmodel.h @@ -0,0 +1,41 @@ +/* + Copyright 2010 Marco Martin + + 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 COMMONMODEL_H +#define COMMONMODEL_H + +#include + +namespace CommonModel +{ + enum ActionType { + NoAction = 0, + AddAction = 1, + RemoveAction = 2 + }; + + enum Roles { + Description = Qt::UserRole+1, + Url = Qt::UserRole+2, + Weight = Qt::UserRole+3, + ActionTypeRole = Qt::UserRole+4 + }; +} + +#endif diff --git a/plasma/netbook/containments/sal/models/favouritesmodel.cpp b/plasma/netbook/containments/sal/models/favouritesmodel.cpp new file mode 100644 index 00000000..fd23c2a0 --- /dev/null +++ b/plasma/netbook/containments/sal/models/favouritesmodel.cpp @@ -0,0 +1,209 @@ +/* + Copyright 2009 Ivan Cukic + Copyright 2010 Marco Martin + + 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. +*/ + +// Own +#include "favouritesmodel.h" +#include "krunnermodel.h" +#include "kservicemodel.h" +#include "commonmodel.h" + +// Qt + +// KDE +#include +#include +#include +#include + +//Plasma +#include +#include + + +FavouritesModel::FavouritesModel(QObject *parent) + : QStandardItemModel(parent) +{ + QHash newRoleNames = roleNames(); + newRoleNames[CommonModel::Description] = "description"; + newRoleNames[CommonModel::Url] = "url"; + newRoleNames[CommonModel::Weight] = "weight"; + newRoleNames[CommonModel::ActionTypeRole] = "action"; + + setRoleNames(newRoleNames); +} + +FavouritesModel::~FavouritesModel() +{ +} + +Plasma::RunnerManager *FavouritesModel::runnerManager() +{ + return KRunnerModel::runnerManager(); +} + +void FavouritesModel::restore(KConfigGroup &cg) +{ + kDebug() << "----------------> Restoring Stuff..."; + + KConfigGroup stripGroup(&cg, "stripwidget"); + + clear(); + // get all the favourites + QStringList groupNames(stripGroup.groupList()); + qSort(groupNames); + QMap favouritesConfigs; + foreach (const QString &favouriteGroup, stripGroup.groupList()) { + if (favouriteGroup.startsWith("favourite-")) { + KConfigGroup favouriteConfig(&stripGroup, favouriteGroup); + favouritesConfigs.insert(favouriteGroup.split("-").last().toUInt(), favouriteConfig); + } + } + + QVector urls; + int numIcons; + + if (favouritesConfigs.isEmpty()) { + numIcons = 4; + urls << "konqueror" << "kmail" << "systemsettings" << "dolphin"; + } else { + urls.resize(favouritesConfigs.size()); + QMap::const_iterator it = favouritesConfigs.constBegin(); + int i = 0; + while (it != favouritesConfigs.constEnd()) { + KConfigGroup favouriteConfig = it.value(); + + urls[i] = favouriteConfig.readEntry("url"); + ++i; + ++it; + } + numIcons = stripGroup.groupList().size(); + } + + for (int i = 0; i < numIcons; ++i ) { + if (!urls[i].isNull()) { + add(urls[i]); + } + } +} + + +void FavouritesModel::add(const QUrl &url, const QModelIndex &before) +{ + + KService::Ptr service = KService::serviceByDesktopPath(url.path()); + + if (!service) { + service = KService::serviceByDesktopName(url.path()); + } + + if (!service) { + if (!url.isValid()) { + return; + } + + QString query = url.path(); + QString runnerId = url.host(); + QString matchId = url.fragment(); + if (matchId.startsWith(QLatin1Char('/'))) { + matchId = matchId.remove(0, 1); + } + + //FIXME: another inefficient async query + runnerManager()->blockSignals(true); + runnerManager()->execQuery(query, runnerId); + runnerManager()->blockSignals(false); + + Plasma::QueryMatch match(runnerManager()->searchContext()->match(matchId)); + + if (match.isValid()) { + if (before.isValid()) { + insertRow( + before.row(), + StandardItemFactory::createItem( + match.icon(), + match.text(), + match.subtext(), + url.path(), + 1, //don't need weigt here + CommonModel::RemoveAction + ) + ); + } else { + appendRow( + StandardItemFactory::createItem( + match.icon(), + match.text(), + match.subtext(), + url.path(), + 1, //don't need weigt here + CommonModel::RemoveAction + ) + ); + } + } + } else { + if (before.isValid()) { + insertRow( + before.row(), + StandardItemFactory::createItem( + KIcon(service->icon()), + service->name(), + service->genericName(), + service->entryPath(), + 1, //don't need weigt here + CommonModel::RemoveAction + ) + ); + } else { + appendRow( + StandardItemFactory::createItem( + KIcon(service->icon()), + service->name(), + service->genericName(), + service->entryPath(), + 1, //don't need weigt here + CommonModel::RemoveAction + ) + ); + } + } +} + +void FavouritesModel::save(KConfigGroup &cg) +{ + kDebug() << "----------------> Saving Stuff..."; + + // erase the old stuff before saving the new one + KConfigGroup oldGroup(&cg, "stripwidget"); + oldGroup.deleteGroup(); + + KConfigGroup stripGroup(&cg, "stripwidget"); + + for (int i = 0; i <= rowCount(); i++) { + QModelIndex currentIndex = index(i, 0); + KConfigGroup config(&stripGroup, QString("favourite-%1").arg(i)); + QString url = currentIndex.data(CommonModel::Url).value(); + if (!url.isNull()) { + config.writeEntry("url", url); + } + } +} + +#include "favouritesmodel.moc" diff --git a/plasma/netbook/containments/sal/models/favouritesmodel.h b/plasma/netbook/containments/sal/models/favouritesmodel.h new file mode 100644 index 00000000..eab47592 --- /dev/null +++ b/plasma/netbook/containments/sal/models/favouritesmodel.h @@ -0,0 +1,54 @@ +/* + Copyright 2009 Ivan Cukic + Copyright 2010 Marco Martin + + 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 FAVOURITESMODEL_H +#define FAVOURITESMODEL_H + +#include + +#include + +#include + +#include "standarditemfactory.h" + +namespace Plasma { + class RunnerManager; +} + + +class FavouritesModel : public QStandardItemModel +{ + Q_OBJECT + +public: + FavouritesModel(QObject *parent); + virtual ~FavouritesModel(); + + void save(KConfigGroup &cg); + void add(const QUrl &url, const QModelIndex &before = QModelIndex()); + void restore(KConfigGroup &cg); + + static Plasma::RunnerManager *runnerManager(); + +}; + +#endif // FAVOURITESMODEL_H + diff --git a/plasma/netbook/containments/sal/models/krunnermodel.cpp b/plasma/netbook/containments/sal/models/krunnermodel.cpp new file mode 100644 index 00000000..f191e927 --- /dev/null +++ b/plasma/netbook/containments/sal/models/krunnermodel.cpp @@ -0,0 +1,228 @@ +/* + Copyright 2009 Ivan Cukic + Copyright 2010 Marco Martin + + 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. +*/ + +// Own +#include "krunnermodel.h" +#include "models/commonmodel.h" + +// Qt +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include + +#define DELAY_TIME 50 + + +Plasma::RunnerManager * s_runnerManager = NULL; +Plasma::RunnerManager * runnerManager() { + if (s_runnerManager == NULL) { + s_runnerManager = new Plasma::RunnerManager(); + } + return s_runnerManager; +} + +KService::Ptr serviceForUrl(const KUrl & url) +{ + QString runner = url.host(); + QString id = url.fragment(); + + if (id.startsWith(QLatin1Char('/'))) { + id = id.remove(0, 1); + } + + if (runner != QLatin1String("services")) { + return KService::Ptr(NULL); + } + + // URL path example: services_kde4-kate.desktop + // or: services_firefox.desktop + id.remove("services_"); + + return KService::serviceByStorageId(id); +} + + +bool KRunnerItemHandler::openUrl(const KUrl& url) +{ + QString runner = url.host(); + QString id = url.fragment(); + if (id.startsWith(QLatin1Char('/'))) { + id = id.remove(0, 1); + } + + runnerManager()->run(id); + return true; +} + +class KRunnerModel::Private { +public: + Private() + { + } + + ~Private() + { + } + + QBasicTimer searchDelay; + QString searchQuery; + QString currentRunner; +}; + +KRunnerModel::KRunnerModel(QObject *parent) + : QStandardItemModel(parent) + , d(new Private()) +{ + connect(runnerManager(), + SIGNAL(matchesChanged(QList)), + this, + SLOT(matchesChanged(QList))); + + QHash newRoleNames = roleNames(); + newRoleNames[CommonModel::Description] = "description"; + newRoleNames[CommonModel::Url] = "url"; + newRoleNames[CommonModel::Weight] = "weight"; + newRoleNames[CommonModel::ActionTypeRole] = "action"; + + setRoleNames(newRoleNames); + + setSortRole(CommonModel::Weight); +} + +KRunnerModel::~KRunnerModel() +{ + delete d; +} + +void KRunnerModel::setQuery(const QString& query, const QString& runner) +{ + runnerManager()->reset(); + clear(); + + d->searchQuery = query.trimmed(); + d->currentRunner = runner; + + if (d->searchQuery.isEmpty()) { + return; + } + + d->searchDelay.start(DELAY_TIME, this); +} + +void KRunnerModel::timerEvent(QTimerEvent * event) +{ + QStandardItemModel::timerEvent(event); + + if (event->timerId() == d->searchDelay.timerId()) { + d->searchDelay.stop(); + runnerManager()->launchQuery(d->searchQuery, d->currentRunner); + }; +} + + +void KRunnerModel::matchesChanged(const QList< Plasma::QueryMatch > & m) +{ + QList< Plasma::QueryMatch > matches = m; + + qSort(matches.begin(), matches.end()); + + clear(); + + while (matches.size()) { + Plasma::QueryMatch match = matches.takeLast(); + + appendRow( + StandardItemFactory::createItem( + match.icon(), + match.text(), + match.subtext(), + QString("krunner://") + match.runner()->id() + "/" + ::runnerManager()->query() + "#" + match.id(), + match.relevance(), + CommonModel::AddAction + ) + ); + } + + sort(0, Qt::DescendingOrder); +} + +Qt::ItemFlags KRunnerModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = QStandardItemModel::flags(index); + + if (index.isValid()) { + KUrl url = data(index, CommonModel::Url).toString(); + QString host = url.host(); + if (host != "services") { + flags &= ~ ( Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled ); + } + } else { + flags = 0; + } + + return flags; +} + +QMimeData * KRunnerModel::mimeData(const QModelIndexList &indexes) const +{ + KUrl::List urls; + + foreach (const QModelIndex & index, indexes) { + KUrl url = data(index, CommonModel::Url).toString(); + + KService::Ptr service = serviceForUrl(url); + + if (service) { + urls << KUrl(service->entryPath()); + } + } + + QMimeData *mimeData = new QMimeData(); + + if (!urls.isEmpty()) { + urls.populateMimeData(mimeData); + } else { + QList urls; + foreach (const QModelIndex & index, indexes) { + urls << QUrl(data(index, CommonModel::Url).toString()); + } + + mimeData = new QMimeData; + mimeData->setUrls(urls); + } + + return mimeData; + +} + +Plasma::RunnerManager *KRunnerModel::runnerManager() +{ + return ::runnerManager(); +} + +#include "krunnermodel.moc" diff --git a/plasma/netbook/containments/sal/models/krunnermodel.h b/plasma/netbook/containments/sal/models/krunnermodel.h new file mode 100644 index 00000000..416551cb --- /dev/null +++ b/plasma/netbook/containments/sal/models/krunnermodel.h @@ -0,0 +1,72 @@ +/* + Copyright 2009 Ivan Cukic + Copyright 2010 Marco Martin + + 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 KRUNNERMODEL_H +#define KRUNNERMODEL_H + +#include + +#include + +#include + +#include "standarditemfactory.h" + +namespace Plasma +{ + class RunnerManager; +} + +namespace KRunnerItemHandler { + bool openUrl(const KUrl& url); +} + +class KRunnerModel : public QStandardItemModel +{ + Q_OBJECT + +public: + KRunnerModel(QObject *parent); + virtual ~KRunnerModel(); + + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual QMimeData *mimeData(const QModelIndexList &indexes) const; + + static Plasma::RunnerManager *runnerManager(); + +private: + void timerEvent(QTimerEvent * event); + +public Q_SLOTS: + void setQuery(const QString& query, const QString& runner = QString()); + +private Q_SLOTS: + void matchesChanged(const QList< Plasma::QueryMatch > & matches); + +Q_SIGNALS: + void resultsAvailable(); + +private: + class Private; + Private * const d; +}; + +#endif // KRUNNERMODEL_H + diff --git a/plasma/netbook/containments/sal/models/kservicemodel.cpp b/plasma/netbook/containments/sal/models/kservicemodel.cpp new file mode 100644 index 00000000..e19632d8 --- /dev/null +++ b/plasma/netbook/containments/sal/models/kservicemodel.cpp @@ -0,0 +1,299 @@ +/* + Copyright 2009 Ivan Cukic + Copyright 2010 Marco Martin + + 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. +*/ + +// Own +#include "kservicemodel.h" +#include "commonmodel.h" + +// Qt +#include + +// KDE +#include +#include +#include +#include +#include +#include + +//Plasma +#include +#include + + +bool KServiceItemHandler::openUrl(const KUrl& url) +{ + QString urlString = url.path(); + KService::Ptr service = KService::serviceByDesktopPath(urlString); + + if (!service) { + service = KService::serviceByDesktopName(urlString); + } + + if (!service) { + return false; + } + + return KRun::run(*service, KUrl::List(), 0); +} + + +KServiceModel::KServiceModel(const KConfigGroup &group, QObject *parent) + : QStandardItemModel(parent), + m_config(group), + m_path("/"), + m_allRootEntriesModel(0) +{ + QHash newRoleNames = roleNames(); + newRoleNames[CommonModel::Description] = "description"; + newRoleNames[CommonModel::Url] = "url"; + newRoleNames[CommonModel::Weight] = "weight"; + newRoleNames[CommonModel::ActionTypeRole] = "action"; + + setRoleNames(newRoleNames); + + loadRootEntries(this); +} + +KServiceModel::~KServiceModel() +{ +} + +QMimeData * KServiceModel::mimeData(const QModelIndexList &indexes) const +{ + KUrl::List urls; + + foreach (const QModelIndex & index, indexes) { + QString urlString = data(index, CommonModel::Url).toString(); + + KService::Ptr service = KService::serviceByDesktopPath(urlString); + + if (!service) { + service = KService::serviceByDesktopName(urlString); + } + + if (service) { + urls << KUrl(service->entryPath()); + } + } + + QMimeData *mimeData = new QMimeData(); + + if (!urls.isEmpty()) { + urls.populateMimeData(mimeData); + } + + return mimeData; + +} + +void KServiceModel::setPath(const QString &path) +{ + clear(); + + if (path == "/") { + loadRootEntries(this); + } else { + loadServiceGroup(KServiceGroup::group(path)); + setSortRole(Qt::DisplayRole); + sort(0, Qt::AscendingOrder); + } + m_path = path; +} + +QString KServiceModel::path() const +{ + return m_path; +} + +void KServiceModel::saveConfig() +{ + if (!m_allRootEntriesModel) { + return; + } + + QStringList enabledEntries; + + for (int i = 0; i <= m_allRootEntriesModel->rowCount() - 1; i++) { + QModelIndex index = m_allRootEntriesModel->index(i, 0, QModelIndex()); + QStandardItem *item = m_allRootEntriesModel->itemFromIndex(index); + if (item && item->checkState() == Qt::Checked) { + enabledEntries << index.data(CommonModel::Url).value(); + } + } + + m_config.writeEntry("EnabledEntries", enabledEntries); + + //sync should be kinda safe here this function is very rarely called + m_config.sync(); + + setPath("/"); +} + +QStandardItemModel *KServiceModel::allRootEntriesModel() +{ + if (!m_allRootEntriesModel) { + m_allRootEntriesModel = new QStandardItemModel(this); + loadRootEntries(m_allRootEntriesModel); + } + + return m_allRootEntriesModel; +} + +void KServiceModel::loadRootEntries(QStandardItemModel *model) +{ + QStringList defaultEnabledEntries; + defaultEnabledEntries << "plasma-sal-contacts.desktop" << "plasma-sal-bookmarks.desktop" + << "plasma-sal-multimedia.desktop" << "plasma-sal-internet.desktop" + << "plasma-sal-graphics.desktop" << "plasma-sal-education.desktop" + << "plasma-sal-games.desktop" << "plasma-sal-office.desktop"; + QSet enabledEntries = m_config.readEntry("EnabledEntries", defaultEnabledEntries).toSet(); + + QHash groupSet; + KServiceGroup::Ptr group = KServiceGroup::root(); + KServiceGroup::List list = group->entries(); + + for( KServiceGroup::List::ConstIterator it = list.constBegin(); + it != list.constEnd(); it++) { + const KSycocaEntry::Ptr p = (*it); + + if (p->isType(KST_KServiceGroup)) { + KServiceGroup::Ptr subGroup = KServiceGroup::Ptr::staticCast(p); + + if (!subGroup->noDisplay() && subGroup->childCount() > 0) { + groupSet.insert(subGroup->relPath(), subGroup); + } + } + + } + + KService::List services = KServiceTypeTrader::self()->query("Plasma/Sal/Menu"); + if (!services.isEmpty()) { + foreach (const KService::Ptr &service, services) { + const QUrl url = QUrl(service->property("X-Plasma-Sal-Url", QVariant::String).toString()); + const int relevance = service->property("X-Plasma-Sal-Relevance", QVariant::Int).toInt(); + const QString groupName = url.path().remove(0, 1); + + if ((model != m_allRootEntriesModel) && enabledEntries.contains(service->storageId()) && + (url.scheme() != "kservicegroup" || groupSet.contains(groupName))) { + model->appendRow( + StandardItemFactory::createItem( + KIcon(service->icon()), + service->name(), + service->comment(), + url.toString(), + relevance, + CommonModel::NoAction + ) + ); + } else if (model == m_allRootEntriesModel && (url.scheme() != "kservicegroup" || groupSet.contains(groupName))) { + QStandardItem * item = StandardItemFactory::createItem( + KIcon(service->icon()), + service->name(), + service->comment(), + service->storageId(), + relevance, + CommonModel::NoAction + ); + item->setCheckable(true); + item->setCheckState(enabledEntries.contains(service->storageId())?Qt::Checked:Qt::Unchecked); + model->appendRow(item); + } + + if (groupSet.contains(groupName)) { + groupSet.remove(groupName); + } + } + } + + foreach (const KServiceGroup::Ptr group, groupSet) { + if ((model != m_allRootEntriesModel) && enabledEntries.contains(group->relPath())) { + model->appendRow( + StandardItemFactory::createItem( + KIcon(group->icon()), + group->caption(), + group->comment(), + QString("kserviceGroup://root/") + group->relPath(), + 0.1, + CommonModel::NoAction + ) + ); + } else if (model == m_allRootEntriesModel) { + QStandardItem *item = StandardItemFactory::createItem( + KIcon(group->icon()), + group->caption(), + group->comment(), + group->storageId(), + 0.1, + CommonModel::NoAction + ); + item->setCheckable(true); + item->setCheckState(enabledEntries.contains(group->storageId())?Qt::Checked:Qt::Unchecked); + model->appendRow(item); + } + } + + model->setSortRole(CommonModel::Weight); + model->sort(0, Qt::DescendingOrder); +} + +void KServiceModel::loadServiceGroup(KServiceGroup::Ptr group) +{ + if (group && group->isValid()) { + KServiceGroup::List list = group->entries(); + + for( KServiceGroup::List::ConstIterator it = list.constBegin(); + it != list.constEnd(); it++) { + const KSycocaEntry::Ptr p = (*it); + + if (p->isType(KST_KService)) { + const KService::Ptr service = KService::Ptr::staticCast(p); + + if (!service->noDisplay()) { + QString genericName = service->genericName(); + if (genericName.isNull()) { + genericName = service->comment(); + } + appendRow( + StandardItemFactory::createItem( + KIcon(service->icon()), + service->name(), + genericName, + service->entryPath(), + 0.5, + CommonModel::AddAction + ) + ); + } + + } else if (p->isType(KST_KServiceGroup)) { + const KServiceGroup::Ptr subGroup = KServiceGroup::Ptr::staticCast(p); + + if (!subGroup->noDisplay() && subGroup->childCount() > 0) { + loadServiceGroup(subGroup); + } + } + + } + + } +} + +#include "kservicemodel.moc" diff --git a/plasma/netbook/containments/sal/models/kservicemodel.h b/plasma/netbook/containments/sal/models/kservicemodel.h new file mode 100644 index 00000000..64379bef --- /dev/null +++ b/plasma/netbook/containments/sal/models/kservicemodel.h @@ -0,0 +1,67 @@ +/* + Copyright 2010 Marco Martin + + 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 KSERVICEMODEL_H +#define KSERVICEMODEL_H + +#include + +#include +#include +#include + +#include "standarditemfactory.h" + +namespace Plasma { +} + +namespace KServiceItemHandler { + bool openUrl(const KUrl& url); +} + +class KServiceModel : public QStandardItemModel +{ + Q_OBJECT + +public: + KServiceModel(const KConfigGroup &group, QObject *parent); + virtual ~KServiceModel(); + + virtual QMimeData *mimeData(const QModelIndexList &indexes) const; + + void setPath(const QString &path); + QString path() const; + + QStandardItemModel *allRootEntriesModel(); + +public Q_SLOTS: + void saveConfig(); + +protected: + void loadRootEntries(QStandardItemModel *model); + void loadServiceGroup(KServiceGroup::Ptr group); + +private: + KConfigGroup m_config; + QString m_path; + QStandardItemModel *m_allRootEntriesModel; +}; + +#endif // KSERVICEMODEL_H + diff --git a/plasma/netbook/containments/sal/models/standarditemfactory.cpp b/plasma/netbook/containments/sal/models/standarditemfactory.cpp new file mode 100644 index 00000000..e8d85568 --- /dev/null +++ b/plasma/netbook/containments/sal/models/standarditemfactory.cpp @@ -0,0 +1,37 @@ +/* + Copyright 2009 Ivan Cukic + Copyright 2010 Marco Martin + + 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 "standarditemfactory.h" +#include "commonmodel.h" + +QStandardItem *StandardItemFactory::createItem(const QIcon & icon, const QString & title, + const QString & description, const QString & url, qreal weight, int actionType) +{ + QStandardItem *appItem = new QStandardItem; + + appItem->setText(title); + appItem->setIcon(icon); + appItem->setData(description, CommonModel::Description); + appItem->setData(url, CommonModel::Url); + appItem->setData(weight, CommonModel::Weight); + appItem->setData(actionType, CommonModel::ActionTypeRole); + + return appItem; +} diff --git a/plasma/netbook/containments/sal/models/standarditemfactory.h b/plasma/netbook/containments/sal/models/standarditemfactory.h new file mode 100644 index 00000000..93c426f0 --- /dev/null +++ b/plasma/netbook/containments/sal/models/standarditemfactory.h @@ -0,0 +1,41 @@ +/* + Copyright 2009 Ivan Cukic + Copyright 2010 Marco Martin + + 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 STANDARDITEMFACTORY_H +#define STANDARDITEMFACTORY_H + + +#include +#include +/** + * Factory for creating QStandardItems with appropriate text, icons, URL + * and other information for a given URL or Service. + */ +class StandardItemFactory +{ +public: + static QStandardItem *createItem(const QIcon & icon, const QString & title, + const QString & description, const QString & url, qreal weight, int actionType); + +private: + static void setSpecialUrlProperties(const KUrl& url, QStandardItem *item); +}; + +#endif diff --git a/plasma/netbook/containments/sal/plasma-containment-sal.desktop b/plasma/netbook/containments/sal/plasma-containment-sal.desktop new file mode 100644 index 00000000..6c3a742f --- /dev/null +++ b/plasma/netbook/containments/sal/plasma-containment-sal.desktop @@ -0,0 +1,128 @@ +[Desktop Entry] +Name=Search and Launch +Name[ar]=ابحث و شغل +Name[ast]=Guetar y executar +Name[bg]=Търсене и стартиране +Name[bs]=Traženje i pokretanje +Name[ca]=Cerca i llançament +Name[ca@valencia]=Cerca i llançament +Name[cs]=Vyhledat a spustit +Name[da]=Søg og start +Name[de]=Suchen und ausführen +Name[el]=Αναζήτηση και εκτέλεση +Name[en_GB]=Search and Launch +Name[es]=Buscar y ejecutar +Name[et]=Otsimine ja käivitamine +Name[eu]=Bilatu eta abiarazi +Name[fi]=Etsi ja käynnistä +Name[fr]=Rechercher et lancer +Name[ga]=Cuardaigh agus Tosaigh +Name[gl]=Buscar e executar +Name[he]=חיפוש והפעלה +Name[hi]=खोज कर लाँच करें +Name[hr]=Pretraži i pokreni +Name[hu]=Keresés és indítás +Name[ia]=Cerca e lancea +Name[is]=Leit að forritum og ræsing +Name[ja]=検索と起動 +Name[kk]=Іздеу және жегу +Name[km]=ស្វែងរក​ ហើយ​​ចាប់ផ្ដើម +Name[kn]=ಹುಡುಕು ಹಾಗು ಪ್ರಕ್ಷೇಪನ +Name[ko]=찾아서 실행하기 +Name[lt]=Rasti ir paleisti +Name[lv]=Meklēt un palaist +Name[mr]=शोधा व प्रक्षेपण करा +Name[nb]=Søk og start +Name[nds]=Söken un opropen +Name[nl]=Zoeken en starten +Name[nn]=Søk og køyr +Name[pa]=ਖੋਜ ਅਤੇ ਚਲਾਓ +Name[pl]=Znajdź i uruchom +Name[pt]=Pesquisa e Lançamento +Name[pt_BR]=Pesquisa e execução +Name[ro]=Căutare și lansare +Name[ru]=Поиск и запуск +Name[sk]=Hľadať a spustiť +Name[sl]=Iskanje in zaganjanje +Name[sr]=Тражење и покретање +Name[sr@ijekavian]=Тражење и покретање +Name[sr@ijekavianlatin]=Traženje i pokretanje +Name[sr@latin]=Traženje i pokretanje +Name[sv]=Sök och starta +Name[th]=ค้นหาและเรียกใช้งาน +Name[tr]=Ara ve Çalıştır +Name[ug]=ئىزدەش ۋە ئىجرا قىلىش +Name[uk]=Пошук і запуск +Name[wa]=Trover ey enonder +Name[x-test]=xxSearch and Launchxx +Name[zh_CN]=搜索与启动 +Name[zh_TW]=搜尋並啟動 +Comment=Full screen application launcher with search interface +Comment[ast]=Llanzador d'aplicaciones a pantalla completa con una interface de gueta +Comment[bs]=Pokretač programa preko cijelog ekrana sa sučeljem za pretragu +Comment[ca]=Llançador d'aplicacions de pantalla completa amb interfície de cerca +Comment[ca@valencia]=Llançador d'aplicacions de pantalla completa amb interfície de cerca +Comment[cs]=Celoobrazovkový spouštěč aplikací s rozhraním pro vyhledávání +Comment[da]=Startmenu i fuldskærm med søgefunktion +Comment[de]=Anwendungsstarter im Vollbildmodus mit Suchfeld +Comment[el]=Ένας πλήρης οθόνης εκτελεστής εφαρμογών, με λειτουργία αναζήτησης +Comment[en_GB]=Full screen application launcher with search interface +Comment[es]=Lanzador de aplicaciones a pantalla completa con una interfaz de búsqueda +Comment[et]=Täisekraanis rakenduste käivitaja otsinguliidesega +Comment[eu]=Bilaketa-interfazea duen pantaila osoko aplikazio-abiarazlea +Comment[fi]=Koko näytön sovelluskäynnistin haulla +Comment[fr]=Lanceur d'applications en plein écran avec interface de recherche +Comment[gl]=Iniciador de programas a pantalla completa con interface de buscas +Comment[he]=משגר יישומים במסך מלא עם ממשק חיפוש +Comment[hr]=Pokretač aplikacija sa sučeljem za pretraživanje preko cijelog ekrana +Comment[hu]=Teljes képernyős alkalmazásindító- és keresőfelület +Comment[ia]=Lanceator de application a schermo plen con interfacie de cerca +Comment[is]=Forritaræsir í heilsjásham með leitarviðmóti +Comment[kk]=Іздеу интерфейсі бар, толық экранды бағдарлама жеккіші +Comment[km]=កម្មវិធី​ចាប់ផ្ដើម​​​នៃ​កម្មវិធី​ពេញអេក្រង់​ដែលមាន​ចំណុច​ប្រទាក់​ស្វែងរក +Comment[ko]=검색 인터페이스가 있는 전체 화면 프로그램 실행기 +Comment[lt]=Pilno ekrano programų paleidiklis su paieškos sąsaja +Comment[lv]=Pilnekrāna programmu palaidējs ar meklēšanas saskarni +Comment[mr]=शोध संवादासहीत पूर्ण स्क्रीन अनुप्रयोग प्रक्षेपक +Comment[nb]=Fullskjerms programstarter med grensesnitt for søk +Comment[nds]=Heelschirm-Programmoproper mit Söök-Koppelsteed +Comment[nl]=Programmastarter op volledig scherm met zoekinterface +Comment[pa]=ਖੋਜ ਇੰਟਰਫੇਸ ਨਾਲ ਪੂਰੀ ਸਕਰੀਨ ਉੱਤੇ ਐਪਲੀਕੇਸਨ ਲਾਂਚਰਖੋਜ ਇੰਟਰਫੇਸ ਨਾਲ ਪੂਰੀ ਸਕਰੀਨ ਉੱਤੇ ਐਪਲੀਕੇਸਨ ਕਖੋਜ ਇੰਟਰਫੇਸ ਨਾਲ ਪੂਰੀ ਸਕਰੀਨ ਉੱਤੇ ਐਪਲੀਕੇਸ਼ਣ ਖੋਜ ਇੰਟਰਫੇਸ ਨਾਲ ਪੂਰੀ ਖੋਜ ਇੰਟਰ +Comment[pl]=Pełnoekranowy aktywator programów z interfejsem wyszukiwania +Comment[pt]=Um lançador de aplicações de ecrã completo, com interface de pesquisa +Comment[pt_BR]=Executa aplicativos em tela cheia com interface de pesquisa +Comment[ro]=Lansator de aplicații pe tot ecranul, cu interfață de căutare +Comment[ru]=Полноэкранное меню запуска приложений с возможностью поиска +Comment[sk]=Celoobrazovkový spúšťač aplikácií s rozhraním pre vyhľadávanie +Comment[sl]=Celozaslonski zaganjalnik programov z vmesnikom za iskanje +Comment[sr]=Покретач програма преко целог екрана са сучељем за претрагу +Comment[sr@ijekavian]=Покретач програма преко цијелог екрана са сучељем за претрагу +Comment[sr@ijekavianlatin]=Pokretač programa preko cijelog ekrana sa sučeljem za pretragu +Comment[sr@latin]=Pokretač programa preko celog ekrana sa sučeljem za pretragu +Comment[sv]=Startprogram med fullskärm och sökgränssnitt +Comment[th]=ตัวเรียกใช้งานแอพลิเคชันเต็มจอด้วยอินเทอร์เฟซการค้นหา +Comment[tr]=Arama arayüzüyle birlikte tam ekran uygulama başlatıcı +Comment[ug]=ئىزدەش ئارا يۈزى بار تولۇق ئېكران پروگرامما ئىجراچىسى +Comment[uk]=Повноекранний інструмент запуску програм з інтерфейсом пошуку +Comment[vi]=Trình chạy ứng dụng toàn màn hình với giao diện tìm kiếm +Comment[wa]=Enondeu di programe so tote li waitroûle avou èn eterface di cweraedje +Comment[x-test]=xxFull screen application launcher with search interfacexx +Comment[zh_CN]=带搜索界面的全屏应用程序启动器 +Comment[zh_TW]=全畫面應用程式啟動器,有搜尋介面 + +Icon=edit-find +Type=Service +X-KDE-ServiceTypes=Plasma/Applet,Plasma/Containment +X-Plasma-ContainmentCategories=netbook,desktop +NoDisplay=false + +X-KDE-Library=plasma_containment_sal +X-KDE-PluginInfo-Author=The Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=sal +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Containments +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/containments/sal/plasma-sal-menu.desktop b/plasma/netbook/containments/sal/plasma-sal-menu.desktop new file mode 100644 index 00000000..d193201e --- /dev/null +++ b/plasma/netbook/containments/sal/plasma-sal-menu.desktop @@ -0,0 +1,139 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Plasma/Sal/Menu + +Name=Plasma Search and Launch menu +Name[ar]=قائمة بلازما للبحث والإطلاق +Name[ast]=Menú Plasma de gueta y llanzamientu +Name[bg]=Меню за търсене и стартиране в Plasma +Name[bs]=meni pretrage i pokretanja +Name[ca]=Menú de cerca i llançament del Plasma +Name[ca@valencia]=Menú de cerca i llançament del Plasma +Name[cs]=Vyhledávací a spouštěcí nabídka plasmy +Name[csb]=Menu szëkbë ë zrëszaniô plazmë +Name[da]=Plasma menu til søgning og opstart +Name[de]=Menü „Suchen und Starten“ für Plasma +Name[el]=Μενού Plasma αναζήτησης και εκτέλεσης +Name[en_GB]=Plasma Search and Launch menu +Name[es]=Menú Plasma de búsqueda y lanzamiento +Name[et]=Plasma otsimise ja käivitamise menüü +Name[eu]=Bilaketa eta abiorako Plasmaren menua +Name[fi]=Plasma-etsintä- ja -käynnistysvalikko +Name[fr]=Menu Plasma de recherche et de lancement +Name[fy]=Plasma syk en útfier menu +Name[ga]=Roghchlár Cuardaigh/Tosaithe Plasma +Name[gl]=Menú de busca e inicio de Plasma +Name[he]=תפריט חיפוש והפעלה של Plasma +Name[hi]=प्लासमा खोज व लाँच मीनु +Name[hr]=Plasmin izbornik "Traži i pokreni" +Name[hu]=Plasma keresés és indítás menü +Name[ia]=Menu de Plasma per cercar e lancear +Name[id]=Menu Pencarian dan Peluncuran Plasma +Name[is]=Plasma leitar- og ræsingavalmynd +Name[ja]=Plasma 検索と起動メニュー +Name[kk]=Plasma іздеу және жегу мәзірі +Name[km]=ស្វែងរក​ប្លាស្មា ហើយ​ចាប់ផ្ដើម​ម៉ឺនុយ +Name[kn]=ಪ್ಲಾಸ್ಮಾ ಹುಡುಕು ಹಾಗು ಪ್ರಕ್ಷೇಪನ ಪರಿವಿಡಿ +Name[ko]=Plasma 찾아서 실행 메뉴 +Name[lt]=Plasma paieškos ir paleidimo meniu +Name[lv]=Plasma meklēšanas un palaišanas izvēlne +Name[mk]=Мени за Пребарување и стартување преку Плазма +Name[ml]=പ്ലാസ്മയിലെ തെരയാനും തുടങ്ങാനുമുള്ള മെനു +Name[mr]=प्लाज्मा शोधा व प्रक्षेपण करा मेन्यू +Name[nb]=Plasma søk og start-meny +Name[nds]=Plasma-Söök- un Oproopmenü +Name[nl]=Menu voor Plasma zoeken en starten +Name[nn]=Søk- og køyr i Plasma +Name[pa]=ਪਲਾਜ਼ਮਾ ਖੋਜ ਅਤੇ ਲਾਂਚ ਮੇਨੂ +Name[pl]=Menu Plazmy "znajdź i uruchom" +Name[pt]=Menu de Pesquisa e Lançamento do Plasma +Name[pt_BR]=Menu de pesquisa e execução do Plasma +Name[ro]=Meniu de căutare și lansare Plasma +Name[ru]=Меню «Поиск и запуск» +Name[si]=ප්ලාස්මා සොයා ක්‍රියාකරවන එන්ජිම +Name[sk]=Menu "Hľadať a spustiť" pre plasmu +Name[sl]=Meni za iskanje in zaganjanje +Name[sr]=мени претраге и покретања +Name[sr@ijekavian]=мени претраге и покретања +Name[sr@ijekavianlatin]=meni pretrage i pokretanja +Name[sr@latin]=meni pretrage i pokretanja +Name[sv]=Plasma sök- och startmeny +Name[tg]=Барномаи ҷустуҷӯ +Name[th]=พลาสมารูปแบบค้นหาและเมนูเรียกใช้งาน +Name[tr]=Plasma Ara ve Çalıştır Menüsü +Name[ug]=پلازما ئىزدە ۋە ئىجرا تىزىملىكى +Name[uk]=Меню пошуку і запуску Плазми +Name[wa]=Dressêye Plasma po trover eyet enonder +Name[x-test]=xxPlasma Search and Launch menuxx +Name[zh_CN]=Plasma 搜索与启动菜单 +Name[zh_TW]=Plasma 搜尋與啟動選單 +Comment=Menu entry for The Plasma search and launch activity +Comment[ar]=مدخلة قائمة لنشاط بلازما للبحث والإطلاق +Comment[ast]=Entrada de menú pa la xera de gueta y llanzamientu de Plasma +Comment[bg]=Запис в менюто за търсене и стартиране в Plasma +Comment[bs]=Stavka menija za aktivnost plazma pretrage i pokretanja +Comment[ca]=Entrada de menú per a l'activitat de cerca i llançament del Plasma +Comment[ca@valencia]=Entrada de menú per a l'activitat de cerca i llançament del Plasma +Comment[cs]=Položka nabídky pro pro Vyhledávací a spouštěcí aktivitu plasmy +Comment[da]=Menupunkt til Plasma søg og opstart-aktivitet +Comment[de]=Menüeintrag für die Aktivität „Suchen und Starten“ von Plasma +Comment[el]=Καταχώρηση μενού για τις ενέργειες αναζήτησης και εκτέλεσης Plasma +Comment[en_GB]=Menu entry for The Plasma search and launch activity +Comment[es]=Entrada de menú para la actividad de búsqueda y lanzamiento de Plasma +Comment[et]=Plasma otsimis- ja käivitamistegevuse menüükirje +Comment[eu]=Plasmaren bilaketa- eta abiarazte-jarduerako menu-sarrera +Comment[fi]=Valikkorivi Plasma-etsintä- ja -käynnistysaktiviteettiin +Comment[fr]=Entrée de menu pour l'activité de Plasma pour la recherche et le lancement +Comment[fy]=Menu ynfier foar de Plasma syk en útfier aktiviteit +Comment[gl]=Unha entrada no menú para a actividade de busca e inicio de Plasma +Comment[he]=רשומה בתפריט לפעילות החיפוש וההפעלה של Plasma +Comment[hr]=Stavka izbornika za Plasminu "traži i pokreni" aktivnost +Comment[hu]=Menübejegyzés a Plasma keresés és indítás aktivitáshoz +Comment[ia]=Entrata de menu pro activitate de Plasma per cercar e lancear +Comment[id]=Lema menu untuk aktivitas pencarian dan peluncuran Plasma +Comment[is]=Valmyndarfærsla fyrir aðgerð í Plasma leit- og ræsingu +Comment[ja]=Plasma 検索と起動メニュー用のメニューエントリ +Comment[kk]=Plasma-да іздеу және жегуді орындайтын мәзір бабы +Comment[km]=ធាតុ​ម៉ឺនុយ​សម្រាប់​កា​រស្វែងរក​ប្លាស្មា និង​​ចាប់ផ្ដើម​សកម្មភាព +Comment[ko]=Plasma 찾아서 실행 활동을 위한 메뉴 항목 +Comment[lt]=Plazmos meniu įrašas, skirtas paieškai ir programų paleidimui +Comment[lv]=Izvēlnes ieraksts Plasma meklēšanas un palaišanas nodarbei +Comment[mk]=Ставка од мени за активноста „Пребарување и стартување преку Плазма“ +Comment[ml]=പ്ലാസ്മാ തെരച്ചില്‍ വിക്ഷേപണ പ്രവര്‍ത്തനങ്ങള്‍ക്കുള്ള മെനുവിലെ വരി +Comment[mr]=शोधा व प्रक्षेपण करा या प्लाज्मा कार्यपध्दतीची मेन्यू नोंद +Comment[nb]=Menyinnslag for Plasmas søk-og-start-aktivitet +Comment[nds]=Menüindrag för de Plasma-Aktiviteet »Söken un Opropen« +Comment[nl]=Menu-item voor de Plasma zoeken en starten activiteit +Comment[nn]=Menyoppføring av søk- og køyr i Plasma +Comment[pa]=ਪਲਾਜ਼ਮਾ ਖੋਜ ਤੇ ਲਾਂਚ ਸਰਗਰਮੀ ਲਈ ਮੇਨੂ ਐਂਟਰੀ +Comment[pl]=Wpis menu dla działania Plazmy "znajdź i uruchom" +Comment[pt]=Item do menu para a actividade de pesquisa e lançamento do Plasma +Comment[pt_BR]=Entrada do menu para a atividade de pesquisa e execução do Plasma +Comment[ro]=Înregistrare de meniu pentru activitatea de căutare și lansare Plasma +Comment[ru]=Пункт меню для поиска и запуска комнат Plasma +Comment[si]=ප්ලාස්මා සොයා ක්‍රියාකරවන ක්‍රියාවලියට මෙනු ඇතුළත් කිරීමක් +Comment[sk]=Položka menu pre aktivitu plasmy Hľadať a spustiť +Comment[sl]=Menijski vnos za dejavnost iskanja in zaganjanja +Comment[sr]=Ставка менија за активност плазма претраге и покретања +Comment[sr@ijekavian]=Ставка менија за активност плазма претраге и покретања +Comment[sr@ijekavianlatin]=Stavka menija za aktivnost plasma pretrage i pokretanja +Comment[sr@latin]=Stavka menija za aktivnost plasma pretrage i pokretanja +Comment[sv]=Menyalternativ för sök- och startåtgärder i Plasma +Comment[tg]=Менюи воридот барои ҷустуҷӯ ва оғози фаъолияти Plasma +Comment[th]=รายการเมนูของกิจกรรมพลาสมารูปแบบค้นหาและเมนูเรียกใช้งาน +Comment[tr]=Plasma ara ve çalıştır etkinliği için menü girdisi +Comment[ug]=پلازمىنىڭ تىزىملىك تۈرىنى ئىزدەپ ئىجرا قىلىدۇ +Comment[uk]=Пункт меню для простору дій пошуку і запису Плазми +Comment[wa]=Intrêye del dressêye pol cweraedje di Plasma eyet l' activité d' enondeu +Comment[x-test]=xxMenu entry for The Plasma search and launch activityxx +Comment[zh_CN]=搜索与启动 Plasma 的菜单项 +Comment[zh_TW]=Plasma 搜尋與啟動的選單項目 + +[PropertyDef::X-Plasma-Sal-Url] +Type=QString + +[PropertyDef::X-Plasma-Sal-Relevance] +Type=int + + + diff --git a/plasma/netbook/containments/sal/resultwidget.cpp b/plasma/netbook/containments/sal/resultwidget.cpp new file mode 100644 index 00000000..4fd23d06 --- /dev/null +++ b/plasma/netbook/containments/sal/resultwidget.cpp @@ -0,0 +1,94 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "resultwidget.h" + +#include +#include + +ResultWidget::ResultWidget(QGraphicsItem *parent) + : Plasma::IconWidget(parent), + m_shouldBeVisible(true) +{ + m_animation = new QPropertyAnimation(this, "pos", this); + m_animation->setEasingCurve(QEasingCurve::InOutQuad); + m_animation->setDuration(250); + connect(m_animation, SIGNAL(finished()), this, SLOT(animationFinished())); +} + +ResultWidget::~ResultWidget() +{ +} + +void ResultWidget::animateHide() +{ + m_shouldBeVisible = false; + QGraphicsItem *parent = parentItem(); + if (parent) { + animatePos(QPoint(parent->boundingRect().center().x(), parent->boundingRect().bottom())); + } +} + +void ResultWidget::animatePos(const QPointF &point) +{ + m_animation->stop(); + m_animation->setStartValue(pos()); + m_animation->setEndValue(point); + m_animation->start(); +} + +void ResultWidget::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + Plasma::IconWidget::mousePressEvent(event); +} + +void ResultWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + const int distance = QPointF(boundingRect().center() - event->pos()).manhattanLength(); + + //arbitrary drag distance: this has to be way more than the usual: + //double of the average of width and height + if (distance > ((size().width() + size().height())/2)*2) { + emit dragStartRequested(this); + } + + Plasma::IconWidget::mouseMoveEvent(event); +} + +void ResultWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + Plasma::IconWidget::mouseReleaseEvent(event); +} + +void ResultWidget::animationFinished() +{ + setVisible(m_shouldBeVisible); +} + +QVariant ResultWidget::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (change == QGraphicsItem::ItemVisibleChange) { + m_shouldBeVisible = value.toBool(); + } + + return QGraphicsWidget::itemChange(change, value); +} + + +#include "resultwidget.moc" diff --git a/plasma/netbook/containments/sal/resultwidget.h b/plasma/netbook/containments/sal/resultwidget.h new file mode 100644 index 00000000..9fc5ae3b --- /dev/null +++ b/plasma/netbook/containments/sal/resultwidget.h @@ -0,0 +1,56 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLASMA_RESULTWIDGET_H +#define PLASMA_RESULTWIDGET_H + + +#include + +class QPropertyAnimation; + +class ResultWidget : public Plasma::IconWidget +{ + Q_OBJECT +public: + ResultWidget(QGraphicsItem *parent); + ~ResultWidget(); + + void animateHide(); + void animatePos(const QPointF &point); + + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + +protected Q_SLOTS: + void animationFinished(); + +Q_SIGNALS: + void dragStartRequested(ResultWidget *); + +private: + QPropertyAnimation *m_animation; + bool m_shouldBeVisible; +}; + +#endif diff --git a/plasma/netbook/containments/sal/runnersconfig.cpp b/plasma/netbook/containments/sal/runnersconfig.cpp new file mode 100644 index 00000000..40765002 --- /dev/null +++ b/plasma/netbook/containments/sal/runnersconfig.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2008 Ryan P. Bitanga + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "runnersconfig.h" + +#include + +#include +#include +#include +#include + +#include + + +RunnersConfig::RunnersConfig(Plasma::RunnerManager *manager, QWidget *parent) + : KPluginSelector(parent), + m_manager(manager) +{ + connect(this, SIGNAL(configCommitted(QByteArray)), this, SLOT(updateRunner(QByteArray))); + + KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner"); + QList runnerInfo = KPluginInfo::fromServices(offers); + addPlugins(runnerInfo, KPluginSelector::ReadConfigFile, i18n("Available Features"), QString(), KGlobal::config()); +} + +void RunnersConfig::updateRunner(const QByteArray &name) +{ + Plasma::AbstractRunner *runner = m_manager->runner(name); + //Update runner if runner is loaded + if (runner) { + runner->reloadConfiguration(); + } +} + +RunnersConfig::~RunnersConfig() +{ +} + +void RunnersConfig::accept() +{ + save(); + m_manager->reloadConfiguration(); + close(); +} + +#include "runnersconfig.moc" + diff --git a/plasma/netbook/containments/sal/runnersconfig.h b/plasma/netbook/containments/sal/runnersconfig.h new file mode 100644 index 00000000..608bcb65 --- /dev/null +++ b/plasma/netbook/containments/sal/runnersconfig.h @@ -0,0 +1,55 @@ +/* + * Copyright 2008 Ryan P. Bitanga + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KRUNNERCONFIG_H +#define KRUNNERCONFIG_H + +#include + + + +class KPluginSelector; + +namespace Plasma { + class RunnerManager; +} + +class RunnersConfig : public KPluginSelector +{ +Q_OBJECT + public: + RunnersConfig(Plasma::RunnerManager *manager, QWidget *parent = 0); + ~RunnersConfig(); + + public slots: + void accept(); + + private slots: + void updateRunner(const QByteArray& runnerName); + + private: + void init(); + + KPluginSelector *m_sel; + Plasma::RunnerManager *m_manager; +}; + +#endif + diff --git a/plasma/netbook/containments/sal/sal.cpp b/plasma/netbook/containments/sal/sal.cpp new file mode 100644 index 00000000..c4759746 --- /dev/null +++ b/plasma/netbook/containments/sal/sal.cpp @@ -0,0 +1,753 @@ +/* + * Copyright 2009 by Aaron Seigo + * Copyright 2009 by Artur Duque de Souza + * Copyright 2009 by Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "sal.h" +#include "stripwidget.h" +#include "itemview.h" +#include "runnersconfig.h" +#include "../common/linearappletoverlay.h" +#include "../common/appletmovespacer.h" +#include "iconactioncollection.h" +#include "models/commonmodel.h" +#include "models/kservicemodel.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +SearchLaunch::SearchLaunch(QObject *parent, const QVariantList &args) + : Containment(parent, args), + m_runnerModel(0), + m_serviceModel(0), + m_backButton(0), + m_queryCounter(0), + m_maxColumnWidth(0), + m_searchField(0), + m_resultsView(0), + m_orientation(Qt::Vertical), + m_firstItem(0), + m_appletsLayout(0), + m_appletOverlay(0), + m_iconActionCollection(0), + m_stripUninitialized(true) +{ + setContainmentType(Containment::CustomContainment); + m_iconActionCollection = new IconActionCollection(this, this); + setHasConfigurationInterface(true); + setFocusPolicy(Qt::StrongFocus); + setFlag(QGraphicsItem::ItemIsFocusable, true); + m_background = new Plasma::FrameSvg(this); + m_background->setImagePath("widgets/frame"); + m_background->setElementPrefix("raised"); + m_background->setEnabledBorders(Plasma::FrameSvg::BottomBorder); +} + +SearchLaunch::~SearchLaunch() +{ + KConfigGroup cg = config(); + m_stripWidget->save(cg); + config().writeEntry("orientation", (int)m_orientation); +} + +void SearchLaunch::init() +{ + Containment::init(); + connect(this, SIGNAL(appletAdded(Plasma::Applet*,QPointF)), + this, SLOT(layoutApplet(Plasma::Applet*,QPointF))); + connect(this, SIGNAL(appletRemoved(Plasma::Applet*)), + this, SLOT(appletRemoved(Plasma::Applet*))); + + connect(this, SIGNAL(toolBoxVisibilityChanged(bool)), this, SLOT(updateConfigurationMode(bool))); + + + setToolBox(Plasma::AbstractToolBox::load(corona()->preferredToolBoxPlugin(Plasma::Containment::DesktopContainment), QVariantList(), this)); + + QAction *a = action("add widgets"); + if (a) { + addToolBoxAction(a); + } + + + if (toolBox()) { + connect(toolBox(), SIGNAL(toggled()), this, SIGNAL(toolBoxToggled())); + connect(toolBox(), SIGNAL(visibilityChanged(bool)), this, SIGNAL(toolBoxVisibilityChanged(bool))); + toolBox()->show(); + } + + a = action("configure"); + if (a) { + addToolBoxAction(a); + a->setText(i18n("Configure Search and Launch")); + } + + + QAction *lockAction = 0; + if (corona()) { + lockAction = corona()->action("lock widgets"); + } + + if (!lockAction || !lockAction->isEnabled()) { + lockAction = new QAction(this); + addAction("lock page", lockAction); + lockAction->setText(i18n("Lock Page")); + lockAction->setIcon(KIcon("object-locked")); + QObject::connect(lockAction, SIGNAL(triggered(bool)), this, SLOT(toggleImmutability())); + } + + addToolBoxAction(lockAction); + + //FIXME: two different use cases for the desktop and the newspaper, another reason to move the toolbox management out of here + QAction *activityAction = 0; + if (corona()) { + activityAction = corona()->action("manage activities"); + } + if (activityAction) { + addToolBoxAction(activityAction); + } + + a = new QAction(i18n("Next activity"), this); + addAction("next containment", a); + a = new QAction(i18n("Previous activity"), this); + addAction("previous containment", a); + + if (corona()) { + connect(corona(), SIGNAL(availableScreenRegionChanged()), this, SLOT(availableScreenRegionChanged())); + availableScreenRegionChanged(); + } + + Plasma::FormFactor form = formFactor(); + Qt::Orientation layoutOtherDirection = form == Plasma::Vertical ? \ + Qt::Horizontal : Qt::Vertical; + + // create main layout + m_mainLayout = new QGraphicsLinearLayout(); + m_mainLayout->setOrientation(layoutOtherDirection); + m_mainLayout->setContentsMargins(0, 0, 0, 0); + m_mainLayout->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Expanding)); + setLayout(m_mainLayout); + + // create launch grid and make it centered + m_resultsLayout = new QGraphicsLinearLayout; + + + m_resultsView = new ItemView(this); + + m_resultsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_resultsView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_resultsLayout->addItem(m_resultsView); + + connect(m_resultsView, SIGNAL(dragStartRequested(QModelIndex)), this, SLOT(resultsViewRequestedDrag(QModelIndex))); + connect(m_resultsView, SIGNAL(itemActivated(QModelIndex)), this, SLOT(launch(QModelIndex))); + connect(m_resultsView, SIGNAL(addActionTriggered(QModelIndex)), this, SLOT(addFavourite(QModelIndex))); + + + //TODO how to do the strip widget? + m_stripWidget = new StripWidget(this); + m_stripWidget->setImmutability(immutability()); + connect(m_stripWidget, SIGNAL(saveNeeded()), this, SLOT(saveFavourites())); + + //load all config, only at this point we are sure it won't crash + configChanged(); + + m_appletsLayout = new QGraphicsLinearLayout(Qt::Horizontal); + m_appletsLayout->setPreferredHeight(KIconLoader::SizeMedium); + m_appletsLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + QGraphicsWidget *leftSpacer = new QGraphicsWidget(this); + QGraphicsWidget *rightSpacer = new QGraphicsWidget(this); + m_appletsLayout->addItem(leftSpacer); + m_appletsLayout->addItem(rightSpacer); + + m_backButton = new Plasma::IconWidget(this); + m_backButton->setIcon(KIcon("go-previous")); + m_backButton->setText(i18n("Back")); + m_backButton->setOrientation(Qt::Horizontal); + m_backButton->setPreferredSize(m_backButton->sizeFromIconSize(KIconLoader::SizeSmallMedium)); + connect(m_backButton, SIGNAL(clicked()), this, SLOT(reset())); + connect(m_resultsView, SIGNAL(resetRequested()), this, SLOT(reset())); + + QGraphicsAnchorLayout *searchLayout = new QGraphicsAnchorLayout(); + searchLayout->setSpacing(10); + + m_searchField = new Plasma::LineEdit(this); + m_searchField->setPreferredWidth(200); + m_searchField->nativeWidget()->setClearButtonShown(true); + m_searchField->nativeWidget()->setClickMessage(i18n("Search...")); + connect(m_searchField, SIGNAL(returnPressed()), this, SLOT(searchReturnPressed())); + connect(m_searchField->nativeWidget(), SIGNAL(textEdited(QString)), this, SLOT(delayedQuery())); + m_searchTimer = new QTimer(this); + m_searchTimer->setSingleShot(true); + connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(query())); + searchLayout->addAnchor(m_searchField, Qt::AnchorHorizontalCenter, searchLayout, Qt::AnchorHorizontalCenter); + searchLayout->addAnchors(m_searchField, searchLayout, Qt::Vertical); + searchLayout->addAnchors(m_backButton, searchLayout, Qt::Vertical); + searchLayout->addAnchor(m_backButton, Qt::AnchorRight, m_searchField, Qt::AnchorLeft); + + + // add our layouts to main vertical layout + m_mainLayout->addItem(m_stripWidget); + m_mainLayout->addItem(searchLayout); + m_mainLayout->addItem(m_resultsLayout); + + + // correctly set margins + m_mainLayout->activate(); + m_mainLayout->updateGeometry(); + + setTabOrder(m_stripWidget, m_searchField); + setTabOrder(m_searchField, m_resultsView); + setFormFactorFromLocation(location()); + + if (action("remove")) { + addToolBoxAction(action("remove")); + } +} + +void SearchLaunch::launchPackageManager() +{ + if (toolBox()) { + toolBox()->setShowing(false); + } + KRun::run(*m_packageManagerService.data(), KUrl::List(), 0); +} + +void SearchLaunch::configChanged() +{ + setOrientation((Qt::Orientation)config().readEntry("Orientation", (int)Qt::Vertical)); + + m_stripWidget->setIconSize(config().readEntry("FavouritesIconSize", (int)KIconLoader::SizeLarge)); + + m_resultsView->setIconSize(config().readEntry("ResultsIconSize", (int)KIconLoader::SizeHuge)); + + const QString packageManagerName = config().readEntry("PackageManager", "kpackagekit"); + if (!packageManagerName.isEmpty()) { + m_packageManagerService = KService::serviceByDesktopName(packageManagerName); + + if (!action("add applications") && m_packageManagerService && !m_packageManagerService->exec().isEmpty()) { + KAction *addApplicationsAction = new KAction(this); + addAction("add applications", addApplicationsAction); + addApplicationsAction->setText(i18n("Add applications")); + addApplicationsAction->setIcon(KIcon("applications-other")); + addToolBoxAction(addApplicationsAction); + + connect(addApplicationsAction, SIGNAL(triggered()), this, SLOT(launchPackageManager())); + } + } + + if (m_serviceModel) { + m_serviceModel->setPath("/"); + } + restoreStrip(); + m_stripUninitialized = false; +} + +void SearchLaunch::availableScreenRegionChanged() +{ + if (!corona()) { + return; + } + + QRect maxRect; + int maxArea = 0; + //we don't want the bounding rect (that could include panels too), but the maximumone representing the desktop + foreach (const QRect &rect, corona()->availableScreenRegion(screen()).rects()) { + int area = rect.width() * rect.height(); + if (area > maxArea) { + maxRect = rect; + maxArea = area; + } + } + + QGraphicsView *ownView = view(); + + //FIXME: the second check is a workaround to a qt bug: when a qwidget has just been created, maptoglobal and mapfromglobal aren't symmetryc. remove as soon as the bug is fixed + if (ownView && (ownView->mapFromGlobal(QPoint(0,0)) == -ownView->mapToGlobal(QPoint(0,0)))) { + maxRect.moveTopLeft(ownView->mapFromGlobal(maxRect.topLeft())); + } + + maxRect.moveTopLeft(QPoint(qMax(0, maxRect.left()), qMax(0, maxRect.top()))); + + setContentsMargins(maxRect.left(), maxRect.top(), qMax((qreal)0.0, size().width() - maxRect.right()), qMax((qreal)0.0, size().height() - maxRect.bottom())); +} + +void SearchLaunch::toggleImmutability() +{ + if (immutability() == Plasma::UserImmutable) { + setImmutability(Plasma::Mutable); + } else if (immutability() == Plasma::Mutable) { + setImmutability(Plasma::UserImmutable); + } +} + +void SearchLaunch::doSearch(const QString &query, const QString &runner) +{ + if (!query.isEmpty()) { + m_resultsView->setModel(m_runnerModel); + } else { + m_resultsView->setModel(m_serviceModel); + m_serviceModel->setPath("/"); + } + + m_runnerModel->setQuery(query, runner); + m_lastQuery = query; + //enable or disable drag and drop + if (immutability() == Plasma::Mutable && (m_resultsView->model() != m_serviceModel || m_serviceModel->path() != "/")) { + m_resultsView->setDragAndDropMode(ItemContainer::CopyDragAndDrop); + } else { + m_resultsView->setDragAndDropMode(ItemContainer::NoDragAndDrop); + } +} + +void SearchLaunch::reset() +{ + if (m_resultsView->model() != m_serviceModel || m_serviceModel->path() != "/") { + m_searchField->setText(QString()); + doSearch(QString()); + m_serviceModel->setPath("/"); + m_resultsView->setModel(m_serviceModel); + } +} + +void SearchLaunch::launch(QModelIndex index) +{ + KUrl url(index.data(CommonModel::Url).value()); + + if (m_resultsView->model() == m_runnerModel) { + KRunnerItemHandler::openUrl(url); + emit releaseVisualFocus(); + } else { + QString id = url.path(); + if (id.startsWith(QLatin1Char('/'))) { + id = id.remove(0, 1); + } + if (url.protocol() == "kservicegroup") { + m_serviceModel->setPath(id); + } else if (url.protocol() == "krunner") { + m_resultsView->setModel(m_runnerModel); + m_runnerModel->setQuery(id, url.host()); + } else { + KServiceItemHandler::openUrl(url); + reset(); + emit releaseVisualFocus(); + } + } + + //enable or disable drag and drop + if (immutability() == Plasma::Mutable && (m_resultsView->model() != m_serviceModel || m_serviceModel->path() != "/")) { + m_resultsView->setDragAndDropMode(ItemContainer::CopyDragAndDrop); + } else { + m_resultsView->setDragAndDropMode(ItemContainer::NoDragAndDrop); + } +} + +void SearchLaunch::addFavourite(const QModelIndex &index) +{ + QMimeData *mimeData = m_resultsView->model()->mimeData(QModelIndexList()<urls().isEmpty()) { + m_stripWidget->add(mimeData->urls().first()); + } +} + +void SearchLaunch::layoutApplet(Plasma::Applet* applet, const QPointF &pos) +{ + Q_UNUSED(pos); + + if (!m_appletsLayout) { + return; + } + + if (m_appletsLayout->count() == 2) { + m_mainLayout->removeItem(m_appletsLayout); + m_mainLayout->addItem(m_appletsLayout); + } + + Plasma::FormFactor f = formFactor(); + int insertIndex = -1; + + //if pos is (-1,-1) insert at the end of the panel + if (pos != QPoint(-1, -1)) { + for (int i = 1; i < m_appletsLayout->count()-1; ++i) { + if (!dynamic_cast(m_appletsLayout->itemAt(i)) && + !dynamic_cast(m_appletsLayout->itemAt(i))) { + continue; + } + + QRectF siblingGeometry = m_appletsLayout->itemAt(i)->geometry(); + if (f == Plasma::Horizontal) { + qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0; + if (pos.x() < middle) { + insertIndex = i; + break; + } else if (pos.x() <= siblingGeometry.right()) { + insertIndex = i + 1; + break; + } + } else { // Plasma::Vertical + qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0; + if (pos.y() < middle) { + insertIndex = i; + break; + } else if (pos.y() <= siblingGeometry.bottom()) { + insertIndex = i + 1; + break; + } + } + } + } + + if (insertIndex != -1) { + m_appletsLayout->insertItem(insertIndex, applet); + } else { + m_appletsLayout->insertItem(m_appletsLayout->count()-1, applet); + } + + applet->setBackgroundHints(NoBackground); +} + +void SearchLaunch::appletRemoved(Plasma::Applet* applet) +{ + Q_UNUSED(applet) + + if (!m_appletOverlay && m_appletsLayout->count() == 3) { + m_mainLayout->removeItem(m_appletsLayout); + } +} + +void SearchLaunch::constraintsEvent(Plasma::Constraints constraints) +{ + //kDebug() << "constraints updated with" << constraints << "!!!!!!"; + + if (constraints & Plasma::FormFactorConstraint || + constraints & Plasma::StartupCompletedConstraint) { + + // create the models + if (!m_runnerModel) { + m_runnerModel = new KRunnerModel(this); + m_serviceModel = new KServiceModel(config(), this); + m_resultsView->setModel(m_serviceModel); + } + + resize(corona()->screenGeometry(screen()).size()); + } + + if (constraints & Plasma::LocationConstraint) { + setFormFactorFromLocation(location()); + } + + if (constraints & Plasma::SizeConstraint) { + availableScreenRegionChanged(); + if (m_appletsLayout) { + m_appletsLayout->setMaximumHeight(size().height()/4); + } + if (m_appletOverlay) { + m_appletOverlay->resize(size()); + } + } + + if (constraints & Plasma::StartupCompletedConstraint) { + Plasma::DataEngine *engine = dataEngine("searchlaunch"); + engine->connectSource("query", this); + } + + if (constraints & Plasma::ScreenConstraint) { + if (screen() != -1 && m_searchField) { + m_searchField->setFocus(); + } + } + + if (constraints & Plasma::ImmutableConstraint) { + //update lock button + QAction *a = action("lock page"); + if (a) { + switch (immutability()) { + case Plasma::SystemImmutable: + a->setEnabled(false); + a->setVisible(false); + break; + + case Plasma::UserImmutable: + a->setText(i18n("Unlock Page")); + a->setIcon(KIcon("object-unlocked")); + a->setEnabled(true); + a->setVisible(true); + break; + + case Plasma::Mutable: + a->setText(i18n("Lock Page")); + a->setIcon(KIcon("object-locked")); + a->setEnabled(true); + a->setVisible(true); + break; + } + } + + //kill or create the config overlay if needed + if (immutability() == Plasma::Mutable && !m_appletOverlay && toolBox() && toolBox()->isShowing()) { + m_appletOverlay = new LinearAppletOverlay(this, m_appletsLayout); + m_appletOverlay->resize(size()); + } else if (immutability() != Plasma::Mutable && m_appletOverlay && toolBox() && toolBox()->isShowing()) { + m_appletOverlay->deleteLater(); + m_appletOverlay = 0; + } + + //enable or disable drag and drop + if (immutability() == Plasma::Mutable && (m_resultsView->model() != m_serviceModel || m_serviceModel->path() != "/")) { + m_resultsView->setDragAndDropMode(ItemContainer::CopyDragAndDrop); + } else { + m_resultsView->setDragAndDropMode(ItemContainer::NoDragAndDrop); + } + m_stripWidget->setImmutability(immutability()); + } +} + +void SearchLaunch::setOrientation(Qt::Orientation orientation) +{ + if (m_orientation == orientation) { + return; + } + + m_orientation = orientation; + m_resultsView->setOrientation(orientation); +} + +void SearchLaunch::setFormFactorFromLocation(Plasma::Location loc) +{ + switch (loc) { + case Plasma::BottomEdge: + case Plasma::TopEdge: + //kDebug() << "setting horizontal form factor"; + setFormFactor(Plasma::Horizontal); + break; + case Plasma::RightEdge: + case Plasma::LeftEdge: + //kDebug() << "setting vertical form factor"; + setFormFactor(Plasma::Vertical); + break; + default: + setFormFactor(Plasma::Horizontal); + } +} + +void SearchLaunch::restoreStrip() +{ + KConfigGroup cg = config(); + m_stripWidget->restore(cg); + //reset(); +} + +void SearchLaunch::updateConfigurationMode(bool config) +{ + + if (config && !m_appletOverlay && immutability() == Plasma::Mutable) { + if (m_appletsLayout->count() == 2) { + m_mainLayout->addItem(m_appletsLayout); + } + m_appletOverlay = new LinearAppletOverlay(this, m_appletsLayout); + m_appletOverlay->resize(size()); + connect (m_appletOverlay, SIGNAL(dropRequested(QGraphicsSceneDragDropEvent*)), + this, SLOT(overlayRequestedDrop(QGraphicsSceneDragDropEvent*))); + } else if (!config) { + delete m_appletOverlay; + m_appletOverlay = 0; + if (m_appletsLayout->count() == 2) { + m_mainLayout->removeItem(m_appletsLayout); + } + } +} + +void SearchLaunch::overlayRequestedDrop(QGraphicsSceneDragDropEvent *event) +{ + dropEvent(event); +} + + +void SearchLaunch::resultsViewRequestedDrag(QModelIndex index) +{ + if (!m_resultsView->model()) { + return; + } + + + QModelIndexList list; + list.append(index); + QMimeData *mimeData = m_resultsView->model()->mimeData(list); + + QDrag *drag = new QDrag(view()); + drag->setMimeData(mimeData); + drag->setPixmap(index.data(Qt::DecorationRole).value().pixmap(KIconLoader::SizeHuge, KIconLoader::SizeHuge)); + + drag->exec(Qt::CopyAction); +} + +void SearchLaunch::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *, const QRect &) +{ + if (m_stripUninitialized) { + m_stripUninitialized = false; + QTimer::singleShot(100, this, SLOT(restoreStrip())); + } else { + m_background->resizeFrame(QSizeF(size().width(), m_stripWidget->geometry().bottom())); + m_background->paintFrame(painter); + } +} + +void SearchLaunch::delayedQuery() +{ + m_searchTimer->start(500); +} + +void SearchLaunch::query() +{ + QString query = m_searchField->text(); + doSearch(query); + m_lastQuery = query; +} + +void SearchLaunch::searchReturnPressed() +{ + QString query = m_searchField->text(); + //by pressing enter do a query or + if (query == m_lastQuery && !query.isEmpty()) { + launch(m_resultsView->model()->index(0, 0, QModelIndex())); + reset(); + } else { + doSearch(query); + m_lastQuery = query; + } +} + +void SearchLaunch::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data) +{ + Q_UNUSED(sourceName); + + const QString query(data["query"].toString()); + //Take ownership of the screen if we don't have one + //FIXME: hardcoding 0 is bad: maybe pass the screen from the dataengine? + if (!query.isEmpty()) { + if (screen() < 0) { + setScreen(0); + } + emit activate(); + } + + doSearch(query); + if (m_searchField) { + m_searchField->setText(query); + } +} + +void SearchLaunch::focusInEvent(QFocusEvent *event) +{ + if (m_searchField) { + m_searchField->setFocus(); + } + if (screen() < 0) { + setScreen(0); + } + Containment::focusInEvent(event); +} + +void SearchLaunch::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::ContentsRectChange) { + + if (toolBox() && toolBox()->isShowing()) { + updateConfigurationMode(true); + } + } + Plasma::Containment::changeEvent(event); +} + +void SearchLaunch::createConfigurationInterface(KConfigDialog *parent) +{ + RunnersConfig *runnersConfig = new RunnersConfig(m_runnerModel->runnerManager(), parent); + parent->addPage(runnersConfig, i18nc("Title of the page that lets the user choose the loaded krunner plugins", "Search plugins"), "edit-find"); + + connect(parent, SIGNAL(applyClicked()), runnersConfig, SLOT(accept())); + connect(parent, SIGNAL(okClicked()), runnersConfig, SLOT(accept())); + + QListView *enabledEntries = new QListView(parent); + enabledEntries->setModel(m_serviceModel->allRootEntriesModel()); + enabledEntries->setModelColumn(0); + parent->addPage(enabledEntries, i18nc("Title of the page that lets the user choose what entries will be allowed in the main menu", "Main menu"), "view-list-icons"); + + QWidget *page = new QWidget; + QVBoxLayout *layout = new QVBoxLayout(page); + + if (!m_shortcutEditor) { + m_shortcutEditor = new KKeySequenceWidget(page); + connect(parent, SIGNAL(applyClicked()), this, SLOT(configDialogFinished())); + connect(parent, SIGNAL(okClicked()), this, SLOT(configDialogFinished())); + } + + m_shortcutEditor.data()->setKeySequence(globalShortcut().primary()); + layout->addWidget(m_shortcutEditor.data()); + layout->addStretch(); + parent->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard"); + + connect(parent, SIGNAL(applyClicked()), m_serviceModel, SLOT(saveConfig())); + connect(parent, SIGNAL(okClicked()), m_serviceModel, SLOT(saveConfig())); +} + +void SearchLaunch::configDialogFinished() +{ + if (m_shortcutEditor) { + QKeySequence sequence = m_shortcutEditor.data()->keySequence(); + if (sequence != globalShortcut().primary()) { + setGlobalShortcut(KShortcut(sequence)); + emit configNeedsSaving(); + } + } +} + +void SearchLaunch::saveFavourites() +{ + KConfigGroup cg = config(); + m_stripWidget->save(cg); +} + +K_EXPORT_PLASMA_APPLET(sal, SearchLaunch) + +#include "sal.moc" + diff --git a/plasma/netbook/containments/sal/sal.h b/plasma/netbook/containments/sal/sal.h new file mode 100644 index 00000000..367934f7 --- /dev/null +++ b/plasma/netbook/containments/sal/sal.h @@ -0,0 +1,135 @@ +/* + * Copyright 2007 by Alex Merry + * Copyright 2008 by Alexis Ménard + * Copyright 2009 by Marco Martin + * Copyright 2009 by Artur Duque de Souza + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SEARCHLAUNCH_CONTAINMENT_H +#define SEARCHLAUNCH_CONTAINMENT_H + +#include "models/krunnermodel.h" + +#include +#include + +#include + +class QTimer; +class StripWidget; +class ItemView; +class LinearAppletOverlay; +class IconActionCollection; +class KRunnerModel; +class KServiceModel; +class KKeySequenceWidget; + +namespace Plasma +{ + class IconWidget; + class LineEdit; + class Frame; + class FrameSvg; +} + +class SearchLaunch : public Plasma::Containment +{ + Q_OBJECT +public: + SearchLaunch(QObject *parent, const QVariantList &args); + ~SearchLaunch(); + void init(); + + void setOrientation(Qt::Orientation orientation); + + void constraintsEvent(Plasma::Constraints constraints); + + void createConfigurationInterface(KConfigDialog *parent); + +protected: + void focusInEvent(QFocusEvent *event); + void paintInterface(QPainter *, const QStyleOptionGraphicsItem *, const QRect &); + void changeEvent(QEvent *event); + void doSearch(const QString &query, const QString &runner = QString()); + +public Q_SLOTS: + void configChanged(); + void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data); + +private Q_SLOTS: + void toggleImmutability(); + void layoutApplet(Plasma::Applet* applet, const QPointF &pos); + void appletRemoved(Plasma::Applet* applet); + void restoreStrip(); + void updateConfigurationMode(bool config); + void overlayRequestedDrop(QGraphicsSceneDragDropEvent *event); + void resultsViewRequestedDrag(QModelIndex index); + void availableScreenRegionChanged(); + void launchPackageManager(); + void configDialogFinished(); + + void delayedQuery(); + void query(); + void searchReturnPressed(); + void launch(QModelIndex index); + void addFavourite(const QModelIndex &index); + void reset(); + + void saveFavourites(); + +private: + /** + * update the formfactor based on the location + */ + void setFormFactorFromLocation(Plasma::Location loc); + + Plasma::FrameSvg *m_background; + KRunnerModel *m_runnerModel; + KServiceModel *m_serviceModel; + Plasma::IconWidget *m_backButton; + + int m_queryCounter; + int m_maxColumnWidth; + + QTimer *m_searchTimer; + + Plasma::LineEdit *m_searchField; + + ItemView *m_resultsView; + StripWidget *m_stripWidget; + + Qt::Orientation m_orientation; + QString m_lastQuery; + Plasma::IconWidget *m_firstItem; + + KSharedPtr m_packageManagerService; + + QGraphicsLinearLayout *m_mainLayout; + QGraphicsLinearLayout *m_resultsLayout; + QGraphicsLinearLayout *m_appletsLayout; + QPointF m_buttonDownMousePos; + LinearAppletOverlay *m_appletOverlay; + + IconActionCollection *m_iconActionCollection; + QWeakPointer m_shortcutEditor; + + bool m_stripUninitialized; +}; + + +#endif // PLASMA_SEARCHLAUNCH_H diff --git a/plasma/netbook/containments/sal/services/plasma-sal-bookmarks.desktop b/plasma/netbook/containments/sal/services/plasma-sal-bookmarks.desktop new file mode 100644 index 00000000..ebba0f54 --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-bookmarks.desktop @@ -0,0 +1,169 @@ +[Desktop Entry] +Name=Bookmarks +Name[af]=Boekmerke +Name[ar]=العلامات +Name[as]=পত্ৰচিহ্ন +Name[ast]=Marcadores +Name[be]=Закладкі +Name[be@latin]=Zakładki +Name[bg]=Отметки +Name[bn]=বুকমার্ক +Name[bn_IN]=বুকমার্ক +Name[br]=Sinedoù +Name[bs]=Zabilješke +Name[ca]=Adreces d'interès +Name[ca@valencia]=Adreces d'interés +Name[cs]=Záložky +Name[csb]=Załóżczi +Name[cy]=Nodau Tudalen +Name[da]=Bogmærker +Name[de]=Lesezeichen +Name[el]=Σελιδοδείκτες +Name[en_GB]=Bookmarks +Name[eo]=Legosignoj +Name[es]=Marcadores +Name[et]=Järjehoidjad +Name[eu]=Laster-markak +Name[fa]=چوب الفها +Name[fi]=Kirjanmerkit +Name[fr]=Signets +Name[fy]=Blêdwizers +Name[ga]=Leabharmharcanna +Name[gl]=Marcadores +Name[gu]=બુકમાર્ક્સ +Name[he]=סימניות +Name[hi]= पसंदीदा +Name[hne]=निसानी +Name[hr]=Oznake +Name[hsb]=Lubuški +Name[hu]=Könyvjelzők +Name[ia]=Marcatores de libro +Name[id]=Penanda +Name[is]=Bókamerki +Name[ja]=ブックマーク +Name[ka]=სანიშნეები +Name[kk]=Бетбелгі +Name[km]=ចំណាំ +Name[kn]=ಅಂಕನಗಳು (ಬುಕ್ ಮಾರ್ಕ್) +Name[ko]=책갈피 +Name[ku]=Bijare +Name[lt]=Žymelės +Name[lv]=Grāmatzīmes +Name[mai]=पुस्तकचिह्न +Name[mk]=Обележувачи +Name[ml]=ഓര്‍മ്മക്കുറിപ്പുകള്‍ +Name[mr]=ओळखचिन्ह +Name[ms]=Tanda Buku +Name[nb]=Bokmerker +Name[nds]=Leestekens +Name[ne]=पुस्तकचिनो +Name[nl]=Bladwijzers +Name[nn]=Bokmerke +Name[oc]=Marca-paginas +Name[or]=ଚିହ୍ନିତ ସ୍ଥାନ +Name[pa]=ਬੁੱਕਮਾਰਕ +Name[pl]=Zakładki +Name[pt]=Favoritos +Name[pt_BR]=Favoritos +Name[ro]=Semne de carte +Name[ru]=Закладки +Name[se]=Girjemearkkat +Name[si]=පිටු සලකුණු +Name[sk]=Záložky +Name[sl]=Zaznamki +Name[sr]=Обележивачи +Name[sr@ijekavian]=Обиљеживачи +Name[sr@ijekavianlatin]=Obilježivači +Name[sr@latin]=Obeleživači +Name[sv]=Bokmärken +Name[ta]=நினைவுக்குறிகள் +Name[te]=పేజి గుర్తులు +Name[tg]=Хатчӯбмонӣ +Name[th]=ที่คั่นหน้า +Name[tr]=Yer İmleri +Name[ug]=خەتكۈشلەر +Name[uk]=Закладки +Name[uz]=Xatchoʻplar +Name[uz@cyrillic]=Хатчўплар +Name[vi]=Dấu trang +Name[wa]=Rimarkes +Name[xh]=Amanqaku eencwadi +Name[x-test]=xxBookmarksxx +Name[zh_CN]=书签 +Name[zh_TW]=書籤 +Comment=List all your bookmarks +Comment[ar]=اسرد كل علاماتك +Comment[ast]=Llistar tolos tos marcadores +Comment[bg]=Списък с отметките ви +Comment[bs]=Nabraja sve vaše zabilješke +Comment[ca]=Llista totes les adreces d'interès +Comment[ca@valencia]=Llista totes les adreces d'interés +Comment[cs]=Seznam všech vašich záložek +Comment[csb]=Wëskrzëni wszëtczé twòjé załóżczi +Comment[da]=Oplist alle dine bogmærker +Comment[de]=Alle Lesezeichen auflisten +Comment[el]=Λίστα με όλους τους σελιδοδείκτες +Comment[en_GB]=List all your bookmarks +Comment[eo]=Listi ĉiujn viajn legosignojn +Comment[es]=Listar todos sus marcadores +Comment[et]=Kõigi järjehoidjate loend +Comment[eu]=Zerrendatu laster-marka guztiak +Comment[fi]=Luettelo kaikista kirjanmerkeistäsi +Comment[fr]=Liste tous vos signets +Comment[fy]=All jo blêdwizers opsomme +Comment[ga]=Taispeáin do chuid leabharmharcanna +Comment[gl]=Enumera todos os marcadores +Comment[gu]=તમારા બધાં બુકમાર્ક્સની યાદી બતાવો +Comment[he]=משמש להצגת כל הסימניות שלך +Comment[hi]=सभी पसंदीदा दिखाएँ +Comment[hr]=Izlistaj sve moje oznake +Comment[hu]=Kilistázza az összes könyvjelzőt +Comment[ia]=Il lista tote tu marcatores de libro +Comment[id]=Tampilkan semua penanda anda +Comment[is]=Listar öll bókamerkin þín +Comment[ja]=すべてのブックマークを一覧表示します +Comment[kk]=Барлық бетбелгілер тізімі +Comment[km]=រាយ​ចំណាំ​របស់​អ្នក​ទាំងអស់ +Comment[kn]=ಇರಬಹುದಾದ ಎಲ್ಲಾ ಅಂಕನಗಳನ್ನು(ಬುಕ್ ಮಾರ್ಕ್) ಪಟ್ಟಿ ಮಾಡು +Comment[ko]=모든 책갈피를 표시합니다 +Comment[lt]=Rodyti visas jūsų žymeles +Comment[lv]=Parāda visas jūsu grāmatzīmes +Comment[mk]=Прикажете ги сите ваши обележувачи +Comment[ml]=എല്ലാ അടയാളക്കുറിപ്പുകളും കാണിയ്ക്കുക +Comment[mr]=तुमच्या सर्व ओळखचिन्हांची यादी करा +Comment[nb]=List alle dine bokmerker +Comment[nds]=All Dien Leestekens oplisten +Comment[nl]=Alle bladwijzers tonen +Comment[nn]=Vis alle bokmerka +Comment[pa]=ਤੁਹਾਡੇ ਸਭ ਬੁੱਕਮਾਰਕ ਦੀ ਲਿਸਟ +Comment[pl]=Wykaz wszystkich twoich zakładek +Comment[pt]=Apresentar todos os seus favoritos +Comment[pt_BR]=Lista todos os seus favoritos +Comment[ro]=Enumeră toate semnele de carte +Comment[ru]=Список всех ваших закладок +Comment[si]=ඔබේ පොත්සලකුණු සියල්ල ලැයිස්තුගත කරන්න +Comment[sk]=Zoznam všetkých záložiek +Comment[sl]=Izpiše seznam vseh zaznamkov +Comment[sr]=Набраја све ваше обележиваче +Comment[sr@ijekavian]=Набраја све ваше обиљеживаче +Comment[sr@ijekavianlatin]=Nabraja sve vaše obilježivače +Comment[sr@latin]=Nabraja sve vaše obeleživače +Comment[sv]=Lista alla bokmärken +Comment[tg]=Ҷустуҷӯи замимаҳо +Comment[th]=เรียกดูที่คั่นหน้าทั้งหมดของคุณ +Comment[tr]=Tüm yer imlerini listele +Comment[ug]=ھەممە خەتكۈچلەر تىزىمى +Comment[uk]=Список всіх ваших закладок +Comment[vi]=Liệt kê tất cả đánh dấu trang của bạn +Comment[wa]=Fé l' djivêye di totes vos rimarkes +Comment[x-test]=xxList all your bookmarksxx +Comment[zh_CN]=列出所有书签 +Comment[zh_TW]=列出所有的書籤 +Icon=bookmarks + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-bookmarks + +X-Plasma-Sal-Url=krunner://bookmarks/bookmarks +X-Plasma-Sal-Relevance=9 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-contacts.desktop b/plasma/netbook/containments/sal/services/plasma-sal-contacts.desktop new file mode 100644 index 00000000..7f517544 --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-contacts.desktop @@ -0,0 +1,146 @@ +[Desktop Entry] +Name=Contacts +Name[ar]=المراسلون +Name[ast]=Contautos +Name[bg]=Контакти +Name[bs]=kontakti +Name[ca]=Contactes +Name[ca@valencia]=Contactes +Name[cs]=Kontakty +Name[csb]=Łączbë +Name[da]=Kontakter +Name[de]=Kontakte +Name[el]=Επαφές +Name[en_GB]=Contacts +Name[eo]=Kontaktoj +Name[es]=Contactos +Name[et]=Kontaktid +Name[eu]=Kontaktuak +Name[fa]=تماسها +Name[fi]=Yhteystiedot +Name[fr]=Contacts +Name[fy]=Kontakten +Name[ga]=Teagmhálacha +Name[gl]=Contactos +Name[gu]=સંબંધો +Name[he]=אנשי קשר +Name[hi]=संपर्क +Name[hr]=Kontakti +Name[hu]=Névjegyek +Name[ia]=Contactos +Name[id]=Kontak +Name[is]=Tengiliðir +Name[ja]=連絡先 +Name[kk]=Контакттар +Name[km]=ទំនាក់ទំនង +Name[kn]=ಸಂಪರ್ಕ ವಿಳಾಸಗಳು +Name[ko]=연락처 +Name[lt]=Kontaktai +Name[lv]=Kontakti +Name[mk]=Контакти +Name[ml]=വിലാസങ്ങള്‍ +Name[mr]=संपर्क +Name[nb]=Kontakter +Name[nds]=Kontakten +Name[nl]=Contacts +Name[nn]=Kontaktar +Name[pa]=ਸੰਪਰਕ +Name[pl]=Kontakty +Name[pt]=Contactos +Name[pt_BR]=Contatos +Name[ro]=Contacte +Name[ru]=Контакты +Name[si]=සබඳතා +Name[sk]=Kontakty +Name[sl]=Stiki +Name[sr]=контакти +Name[sr@ijekavian]=контакти +Name[sr@ijekavianlatin]=kontakti +Name[sr@latin]=kontakti +Name[sv]=Kontakter +Name[tg]=Тамосҳо +Name[th]=ที่อยู่ติดต่อต่าง ๆ +Name[tr]=Kişiler +Name[ug]=ئالاقەداشلار +Name[uk]=Контакти +Name[vi]=Liên lạc +Name[wa]=Contaks +Name[x-test]=xxContactsxx +Name[zh_CN]=联系人 +Name[zh_TW]=聯絡人 +Comment=List all your contacts +Comment[ar]=اسرد جميع مراسليك +Comment[ast]=Llistar tolos contautos +Comment[bg]=Списък с контактите ви +Comment[bs]=Nabraja sve vaše kontakte +Comment[ca]=Llista tots els contactes +Comment[ca@valencia]=Llista tots els contactes +Comment[cs]=Seznam všech vašich kontaktů +Comment[csb]=Wëskrzëni wszëtczé twòjé łączbë +Comment[da]=Oplist alle dine kontakter +Comment[de]=Alle Kontakte auflisten +Comment[el]=Λίστα με όλες οι επαφές +Comment[en_GB]=List all your contacts +Comment[eo]=Listo de ĉiuj viaj kontaktoj +Comment[es]=Listar todos sus contactos +Comment[et]=Kõigi kontaktide loend +Comment[eu]=Zerrendatu kontaktu guztiak +Comment[fi]=Luettelo kaikista yhteystiedoistasi +Comment[fr]=Liste tous vos contacts +Comment[fy]=Al jo kontakten opsomme +Comment[ga]=Taispeáin do theagmhálacha go léir +Comment[gl]=Enumera todos os contactos +Comment[gu]=તમારા બધાં સંપર્કો બતાવે છે +Comment[he]=משמש להצגת כל אנשי הקשר שלך +Comment[hi]=अपने सभी संपर्क दिखाएँ +Comment[hr]=Izlistaj sve moje kontakte +Comment[hu]=Kilistázza az összes névjegyet +Comment[ia]=Il lista tote tu contactos +Comment[id]=Tampilkan semua kontak anda +Comment[is]=Listar alla tengiliðina þína +Comment[ja]=すべての連絡先を一覧表示します +Comment[kk]=Контакттарыңыздың тізімі +Comment[km]=រាយ​ទំនាក់ទំនង​របស់​អ្នក​ទាំងអស់​ +Comment[kn]=ನಿಮ್ಮ ಎಲ್ಲಾ ಸಂಪರ್ಕಗಳನ್ನು ಪಟ್ಟಿ ಮಾಡು +Comment[ko]=모든 연락처를 표시합니다 +Comment[lt]=Visų kontaktų sąrašas +Comment[lv]=Parāda visus jūsu kontaktus +Comment[mk]=Прикажете ги сите Ваши контакти +Comment[ml]=നിങ്ങളുടെ എല്ലാ വിലാസങ്ങളും കാണിയ്ക്കുക +Comment[mr]=तुमच्या सर्व संपर्कातील व्यक्तिंची यादी करा +Comment[nb]=List alle dine kontakter +Comment[nds]=All Dien Kontakten oplisten +Comment[nl]=Toon al uw contacten +Comment[nn]=Vis alle kontaktane +Comment[pa]=ਆਪਣੇ ਸਭ ਸੰਪਰਕ ਵੇਖੋ +Comment[pl]=Wykaz wszystkich twoich kontaktów +Comment[pt]=Apresentar todos os seus contactos +Comment[pt_BR]=Lista todos os seus contatos +Comment[ro]=Enumeră toate contactele +Comment[ru]=Список всех ваших контактов +Comment[si]=ඔබේ සබඳතා සියල්ල ලැයිස්තුගත කරන්න +Comment[sk]=Zoznam všetkých kontaktov +Comment[sl]=Izpiše seznam vseh stikov +Comment[sr]=Набраја све ваше контакте +Comment[sr@ijekavian]=Набраја све ваше контакте +Comment[sr@ijekavianlatin]=Nabraja sve vaše kontakte +Comment[sr@latin]=Nabraja sve vaše kontakte +Comment[sv]=Lista alla kontakter +Comment[tg]=Рӯйхати алоқаҳо +Comment[th]=เรียกดูรายการที่อยู่ติดต่อต่าง ๆ ของคุณ +Comment[tr]=Tüm kişileri listele +Comment[ug]=ھەممە ئالاقەداشلار تىزىمىڭىز +Comment[uk]=Список всіх ваших записів контактів +Comment[vi]=Liệt kê các liên lạc của bạn +Comment[wa]=Fé l' djivêye di tos vos contaks +Comment[x-test]=xxList all your contactsxx +Comment[zh_CN]=列出所有联系人 +Comment[zh_TW]=列出所有聯絡人 +Icon=view-pim-contacts + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-contacts + +X-Plasma-Sal-Url=krunner://kabccontacts/contacts +X-Plasma-Sal-Relevance=8 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-development.desktop b/plasma/netbook/containments/sal/services/plasma-sal-development.desktop new file mode 100644 index 00000000..6e2cf5c5 --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-development.desktop @@ -0,0 +1,162 @@ +[Desktop Entry] +Name=Development +Name[af]=Ontwikkeling +Name[ar]=تطوير +Name[as]=বিকাশ +Name[ast]=Desendolcu +Name[be]=Распрацоўка +Name[be@latin]=Raspracoŭvańnie +Name[bg]=Разработка +Name[bn]=ডেভেলপমেন্ট +Name[bn_IN]=ডিভেলপমেন্ট +Name[br]=Diorren +Name[bs]=Razvoj +Name[ca]=Desenvolupament +Name[ca@valencia]=Desenvolupament +Name[cs]=Vývoj +Name[csb]=Nôrzãdza programistów +Name[cy]=Datblygu +Name[da]=Udvikling +Name[de]=Entwicklung +Name[el]=Ανάπτυξη +Name[en_GB]=Development +Name[eo]=Programado +Name[es]=Desarrollo +Name[et]=Arendus +Name[eu]=Garapena +Name[fa]=توسعه +Name[fi]=Kehitystyökalut +Name[fr]=Développement +Name[fy]=Untwikkelje +Name[ga]=Forbairt +Name[gl]=Desenvolvemento +Name[gu]=ડેવલોપમેન્ટ +Name[he]=פיתוח +Name[hi]=विकास +Name[hne]=विकास +Name[hr]=Razvoj +Name[hsb]=Wuwiwanje +Name[hu]=Fejlesztőeszközök +Name[ia]=Developpamento +Name[id]=Pengembangan +Name[is]=Forritaþróun +Name[it]=Sviluppo +Name[ka]=განვითარება +Name[kk]=Жетілдіру +Name[km]=ការ​​អភិវឌ្ឍន៍ +Name[kn]=ವಿಕಸನ +Name[ko]=개발 +Name[ku]=Pêşvebirin +Name[lt]=Programavimas +Name[lv]=Izstrāde +Name[mai]=विकास +Name[mk]=Развој +Name[ml]=വികസനം‌ +Name[mr]=विकास +Name[ms]=Pemaju +Name[nb]=Utvikling +Name[nds]=Utwickeln +Name[ne]=विकास +Name[nl]=Ontwikkeling +Name[nn]=Utvikling +Name[oc]=Desvolopament +Name[or]=ବିକାଶ +Name[pa]=ਡਿਵੈਲਪਮੈਂਟ +Name[pl]=Narzędzia programistów +Name[pt]=Desenvolvimento +Name[pt_BR]=Desenvolvimento +Name[ro]=Dezvoltare +Name[ru]=Разработка +Name[se]=Ovdánahttin +Name[si]=සංවර්‍ධණය +Name[sk]=Vývoj +Name[sl]=Razvoj +Name[sr]=Развој +Name[sr@ijekavian]=Развој +Name[sr@ijekavianlatin]=Razvoj +Name[sr@latin]=Razvoj +Name[sv]=Utveckling +Name[ta]=உருவாக்கம் +Name[te]=డెవలప్ మెంట్ +Name[tg]=Пешрафт +Name[th]=พัฒนาโปรแกรม +Name[tr]=Geliştirme +Name[ug]=ئىجادىيەت +Name[uk]=Розробка +Name[uz]=Tuzish +Name[uz@cyrillic]=Тузиш +Name[vi]=Phát triển +Name[wa]=Programaedje +Name[xh]=Ubhekiso phambili +Name[x-test]=xxDevelopmentxx +Name[zh_CN]=开发 +Name[zh_TW]=程式開發 +Comment=Applications targeted to software development +Comment[ar]=تطبيقات لتطوير البرامج +Comment[ast]=Aplicaciones orientaes al desendolcu de software +Comment[bg]=Програми за разработка на софтуер +Comment[bn]=সফটওয়্যার ডেভেলপমেন্ট সংক্রান্ত অ্যাপলিকেশন +Comment[bs]=Programi namijenjeni razvoju softvera +Comment[ca]=Aplicacions enfocades al desenvolupament de programari +Comment[ca@valencia]=Aplicacions enfocades al desenvolupament de programari +Comment[cs]=Aplikace změřené na vývoj softwaru +Comment[da]=Programmer til softwareudvikling +Comment[de]=Anwendungen für die Software-Entwicklung +Comment[el]=Εφαρμογές στοχευμένες στην ανάπτυξη λογισμικού +Comment[en_GB]=Applications targeted to software development +Comment[es]=Aplicaciones orientadas al desarrollo de software +Comment[et]=Tarkvara arendamiseks mõeldud rakendused +Comment[eu]=Softwarea garatzeko aplikazioak +Comment[fi]=Ohjelmistokehitykseen suunnatut sovellukset +Comment[fr]=Applications destinées au développement de logiciels +Comment[ga]=Feidhmchlár dírithe ar fhorbairt bhogearraí +Comment[gl]=Programas para o desenvolvemento de software +Comment[he]=יישומים המיועדים לפיתוח תוכנות +Comment[hr]=Aplikacije namijenjene za razvoj softvera +Comment[hu]=Szoftverfejlesztő alkalmazások +Comment[ia]=Applicationes adressate al disveloppamento de software +Comment[id]=Aplikasi yang ditargetkan untuk pengembangan peranti lunak +Comment[is]=Forrit sem nýtast til hugbúnaðarþróunar +Comment[ja]=ソフトウェア開発に向けたアプリケーション +Comment[kk]=Бағдарлама құрастыруға арналған қолданбалар +Comment[km]=កម្មវិធីមានគោលដៅ​​ទៅនឹង​ការអភិវឌ្ឍន៍​កម្មវិធី +Comment[kn]=ತಂತ್ರಾಂಶ ವಿನ್ಯಾಸಕ್ಕೆ ಗುರಿಯಾಗಿರಿಸಲ್ಪಟ್ಟ ಅನ್ವಯಗಳು +Comment[ko]=소프트웨어 개발을 위한 프로그램 +Comment[lt]=Programos, skirtos programų kūrimui +Comment[lv]=Uz programmatūras izstrādi mērķētas aplikācijas +Comment[mr]=सॉफ्टवेअर विकासाकरिता अनुप्रयोग +Comment[nb]=Programmer beregnet på programvareutvikling +Comment[nds]=Programmen för Programmschrievers +Comment[nl]=Applicaties bedoelt voor software ontwikkelen +Comment[pa]=ਸਾਫਟਵੇਅਰ ਡਿਵੈਲਪਮੈਂਟ ਲਈ ਐਪਲੀਕੇਸ਼ਨ ਟਾਰਗੇਟ +Comment[pl]=Programy przeznaczone dla programistów +Comment[pt]=Aplicações destinadas ao desenvolvimento de 'software' +Comment[pt_BR]=Aplicativos destinados ao desenvolvimento de software +Comment[ro]=Aplicații orientate spre dezvoltarea de programe +Comment[ru]=Приложения, предназначенные для разработки программных продуктов +Comment[si]=මෘදුකාංග සංවර්ධනයට ඉලක්ක වූ යෙදුම් +Comment[sk]=Aplikácie zamerané na vývoj softvéru +Comment[sl]=Programi za razvoj programske opreme +Comment[sr]=Програми намењени развоју софтвера +Comment[sr@ijekavian]=Програми намијењени развоју софтвера +Comment[sr@ijekavianlatin]=Programi namijenjeni razvoju softvera +Comment[sr@latin]=Programi namenjeni razvoju softvera +Comment[sv]=Program med programvaruutveckling som målsättning +Comment[th]=แอพลิเคชันที่ตั้งเป้าเพื่อการพัฒนาซอฟต์แวร์ +Comment[tr]=Yazılım geliştirmeye yönelik uygulamalar +Comment[ug]=يۇمشاق دېتال ئىجادىيىتىگە يۈزلەنگەن پروگرامما +Comment[uk]=Програми, призначені для розробки програмного забезпечення +Comment[vi]=Các ứng dụng hỗ trợ phát triển phần mềm +Comment[wa]=Programes kel såme est d' siervi å diswalpaedje di programes +Comment[x-test]=xxApplications targeted to software developmentxx +Comment[zh_CN]=面向软件开发的应用程序 +Comment[zh_TW]=為了軟體開發而設計的應用程式 + +Icon=applications-development + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-utility + +X-Plasma-Sal-Url=kservicegroup://root/Development/ +X-Plasma-Sal-Relevance=0.8 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-education.desktop b/plasma/netbook/containments/sal/services/plasma-sal-education.desktop new file mode 100644 index 00000000..85b08992 --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-education.desktop @@ -0,0 +1,166 @@ +[Desktop Entry] +Name=Education +Name[af]=Opvoeding +Name[ar]=التعليم +Name[as]=শিক্ষা +Name[ast]=Educación +Name[be]=Адукацыя +Name[be@latin]=Adukacyja +Name[bg]=Обучение +Name[bn]=‌শিক্ষা +Name[bn_IN]=শিক্ষা +Name[bs]=Obrazovanje +Name[ca]=Educació +Name[ca@valencia]=Educació +Name[cs]=Výuka +Name[csb]=Edukacëjô +Name[da]=Uddannelse +Name[de]=Lernprogramme +Name[el]=Εκπαίδευση +Name[en_GB]=Education +Name[eo]=Edukado +Name[es]=Educación +Name[et]=Õppimine +Name[eu]=Hezkuntza +Name[fa]=آموزش +Name[fi]=Opetus +Name[fr]=Éducation +Name[fy]=Edukaasje +Name[ga]=Oideachas +Name[gl]=Educación +Name[gu]=શિક્ષણ +Name[he]=חינוך +Name[hi]=शिक्षा +Name[hne]=सिक्छा +Name[hr]=Obrazovanje +Name[hsb]=Wuknjenje a hrajkanje +Name[hu]=Oktatás +Name[ia]=Education +Name[id]=Pendidikan +Name[is]=Kennsla +Name[it]=Didattica +Name[kk]=Оқу-ағарту +Name[km]=ការ​អប់រំ +Name[kn]=ಶಿಕ್ಷಣ +Name[ko]=교육 +Name[ku]=Perwerdehî +Name[lt]=Švietimas +Name[lv]=Izglītība +Name[mai]=शिक्षा +Name[mk]=Едукација +Name[ml]=വിദ്യാഭ്യാസം +Name[mr]=शिक्षण +Name[nb]=Utdanning +Name[nds]=Lehren +Name[ne]=शिक्षा +Name[nl]=Onderwijs +Name[nn]=Utdanning +Name[oc]=Educacion +Name[or]=ଶିକ୍ଷା +Name[pa]=ਸਿੱਖਿਆ +Name[pl]=Edukacja +Name[pt]=Educação +Name[pt_BR]=Educação +Name[ro]=Educație +Name[ru]=Образование +Name[se]=Oahpahus +Name[si]=අධ්‍යාපනික +Name[sk]=Vzdelávanie +Name[sl]=Izobraževanje +Name[sr]=Образовање +Name[sr@ijekavian]=Образовање +Name[sr@ijekavianlatin]=Obrazovanje +Name[sr@latin]=Obrazovanje +Name[sv]=Utbildning +Name[ta]=கல்வி +Name[te]=విధ్య +Name[tg]=Омӯзиш ва парвариш +Name[th]=การศึกษา +Name[tr]=Eğitim +Name[ug]=مائارىپ +Name[uk]=Освіта +Name[uz]=Taʼlim +Name[uz@cyrillic]=Таълим +Name[vi]=Giáo dục +Name[wa]=Sicolaedje +Name[x-test]=xxEducationxx +Name[zh_CN]=教育 +Name[zh_TW]=教育 +Comment=Educational applications +Comment[ar]=برامج تعليمية +Comment[ast]=Aplicaciones educatives +Comment[bg]=Образователни програми +Comment[bn]=শিক্ষামূলক অ্যাপলিকেশন +Comment[bs]=Obrazovni programi +Comment[ca]=Aplicacions educatives +Comment[ca@valencia]=Aplicacions educatives +Comment[cs]=Výukové aplikace +Comment[csb]=Edukacjowé aplikacëje +Comment[da]=Læringsprogrammer +Comment[de]=Lernprogramme +Comment[el]=Εκπαιδευτικές εφαρμογές +Comment[en_GB]=Educational applications +Comment[eo]=Edukadaj Aplikaĵoj +Comment[es]=Aplicaciones educativas +Comment[et]=Õpirakendused +Comment[eu]=Hezkuntzarako aplikazioak +Comment[fa]=برنامه‌های آموزشی +Comment[fi]=Koulutussovellukset +Comment[fr]=Applications pour l'éducation +Comment[fy]=Leer programma's +Comment[ga]=Feidhmchláir oideachasúla +Comment[gl]=Programas educativos +Comment[gu]=શૈક્ષણિક કાર્યક્રમો +Comment[he]=יישומים חינוכיים +Comment[hi]=शेक्षणिक अनुप्रयोग +Comment[hr]=Edukacijske aplikacije +Comment[hu]=Oktatóprogramok +Comment[ia]=Applicationes de Instruction +Comment[id]=Aplikasi edukasi +Comment[is]=Kennslu- og fræðsluforrit +Comment[ja]=教育アプリケーション +Comment[kk]=Білім-беру қолданбалары +Comment[km]=កម្មវិធីអប់រំ +Comment[kn]=ಕಲಿಕೆಯ ಆನ್ವಯಗಳು +Comment[ko]=교육 프로그램 +Comment[lt]=Mokomosios programos +Comment[lv]=Izglītības programmas +Comment[mk]=Едукативни апликации +Comment[ml]=വിദ്യഭ്യാസ പ്രയോഗങ്ങള്‍ +Comment[mr]=शिक्षणोपयोगी अनुप्रयोग +Comment[nb]=Opplæringsprogrammer +Comment[nds]=Lehrprogrammen +Comment[nl]=Onderwijstoepassingen +Comment[nn]=Lærerike program +Comment[pa]=ਸਿੱਖਿਅਕ ਐਪਲੀਕੇਸ਼ਨ +Comment[pl]=Programy edukacyjne +Comment[pt]=Aplicações educativas +Comment[pt_BR]=Aplicativos educacionais +Comment[ro]=Aplicații educaționale +Comment[ru]=Обучающие приложения +Comment[si]=අධ්‍යාපන යෙදුම් +Comment[sk]=Vzdelávacie aplikácie +Comment[sl]=Izobraževalni programi +Comment[sr]=Образовни програми +Comment[sr@ijekavian]=Образовни програми +Comment[sr@ijekavianlatin]=Obrazovni programi +Comment[sr@latin]=Obrazovni programi +Comment[sv]=Utbildningsprogram +Comment[tg]=Барномаҳои терминал +Comment[th]=โปรแกรมต่าง ๆ ด้านการศึกษา +Comment[tr]=Eğitim uygulamaları +Comment[ug]=ئوقۇتۇش پروگراممىلىرى +Comment[uk]=Навчальні програми +Comment[vi]=Ứng dụng giáo dục +Comment[wa]=Programes di scolaedje +Comment[x-test]=xxEducational applicationsxx +Comment[zh_CN]=教学程序 +Comment[zh_TW]=教育類應用程式 +Icon=applications-education + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-education + +X-Plasma-Sal-Url=kservicegroup://root/Education/ +X-Plasma-Sal-Relevance=1 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-games.desktop b/plasma/netbook/containments/sal/services/plasma-sal-games.desktop new file mode 100644 index 00000000..8f1a9768 --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-games.desktop @@ -0,0 +1,169 @@ +[Desktop Entry] +Name=Games +Name[af]=Speletjies +Name[ar]=ألعاب +Name[as]=খেলা +Name[ast]=Xuegos +Name[be]=Гульні +Name[be@latin]=Hulni +Name[bg]=Игри +Name[bn]=খেলা +Name[bn_IN]=খেলা +Name[br]=C'hoarioù +Name[bs]=Igre +Name[ca]=Jocs +Name[ca@valencia]=Jocs +Name[cs]=Hry +Name[csb]=Grë +Name[cy]=Gemau +Name[da]=Spil +Name[de]=Spiele +Name[el]=Παιχνίδια +Name[en_GB]=Games +Name[eo]=Ludoj +Name[es]=Juegos +Name[et]=Mängud +Name[eu]=Jokoak +Name[fa]=بازیها +Name[fi]=Pelit +Name[fr]=Jeux +Name[fy]=Amusemint +Name[ga]=Cluichí +Name[gl]=Xogos +Name[gu]=રમતો +Name[he]=משחקים +Name[hi]=खेल +Name[hne]=खेल +Name[hr]=Igre +Name[hsb]=Hry +Name[hu]=Játékok +Name[ia]=Jocos +Name[id]=Permainan +Name[is]=Leikir +Name[it]=Giochi +Name[ka]=თამაშები +Name[kk]=Ойындар +Name[km]=ល្បែង +Name[kn]=ಆಟಗಳು +Name[ko]=게임 +Name[ku]=Listîk +Name[lt]=Žaidimai +Name[lv]=Spēles +Name[mai]=खेल +Name[mk]=Игри +Name[ml]=കളികള്‍ +Name[mr]=खेळ +Name[ms]=Permainan +Name[nb]=Spill +Name[nds]=Spelen +Name[ne]=खेल +Name[nl]=Amusement +Name[nn]=Spel +Name[oc]=Jòcs +Name[or]=ଖେଳ +Name[pa]=ਖੇਡਾਂ +Name[pl]=Gry +Name[pt]=Jogos +Name[pt_BR]=Jogos +Name[ro]=Jocuri +Name[ru]=Игры +Name[se]=Spealut +Name[si]=ක්‍රීඩා +Name[sk]=Hry +Name[sl]=Igre +Name[sr]=Игре +Name[sr@ijekavian]=Игре +Name[sr@ijekavianlatin]=Igre +Name[sr@latin]=Igre +Name[sv]=Spel +Name[ta]=விளையாட்டுகள் +Name[te]=ఆటలు +Name[tg]=Бозиҳо +Name[th]=เกมต่าง ๆ +Name[tr]=Oyunlar +Name[ug]=ئويۇنلار +Name[uk]=Ігри +Name[uz]=Oʻyinlar +Name[uz@cyrillic]=Ўйинлар +Name[vi]=Trò chơi +Name[wa]=Djeus +Name[xh]=Imidlalo +Name[x-test]=xxGamesxx +Name[zh_CN]=游戏 +Name[zh_TW]=遊戲 +Comment=A collection of fun games +Comment[ar]=مجموعة من الألعاب المسلية +Comment[ast]=Un garrapiellu de xuegos prestosos +Comment[bg]=Набор от забавни игри +Comment[bn]=মজাদার খেলার একটি সংগ্রহ +Comment[bs]=Zbirka igara za razonodu +Comment[ca]=Una col·lecció de jocs divertits +Comment[ca@valencia]=Una col·lecció de jocs divertits +Comment[cs]=Sbírka zábavných her +Comment[csb]=Zbiérk grów dlô szpôsu +Comment[da]=En samling af sjove spil +Comment[de]=Eine Sammlung Spielspaß +Comment[el]=Μια συλλογή παιχνιδιών για διασκέδαση +Comment[en_GB]=A collection of fun games +Comment[eo]=Amuza ludaro +Comment[es]=Una colección de juegos +Comment[et]=Lahedate mängude kogu +Comment[eu]=Joko dibertigarrien bilduma bat +Comment[fi]=Hauskojen pelien kokoelma +Comment[fr]=Une collection de jeux amusants +Comment[fy]=In samling grappige spultsjes +Comment[ga]=Bailiúchán de chluichí taitneamhacha +Comment[gl]=Unha colección de xogos +Comment[gu]=આનંદમય રમતોનો સંગ્રહ +Comment[he]=אוסף משחקי כיף +Comment[hi]=मस्ती भरे खेल +Comment[hr]=Zbirka zabavnih igara +Comment[hu]=Szórakoztató játékok gyűjteménye +Comment[ia]=Un collection de jocos divertente +Comment[id]=Koleksi permainan seru +Comment[is]=Safn sniðugra leikja +Comment[ja]=楽しいゲームのコレクション +Comment[kk]=Ойындар жинағы +Comment[km]=បណ្ដុំ​ល្បែង​កំសាន្ត​ជា​ច្រើន +Comment[kn]=ಮನೋರಂಜನಾ ಆಟಗಳ ಸಂಗ್ರಹ +Comment[ko]=재미있는 게임 모음 +Comment[lt]=Linksmų žaidimų rinkinys +Comment[lv]=Jautru spēļu krājums +Comment[mk]=Колекција од забавни игри +Comment[ml]=തമാശയുള്ള കളികളുടെ ശേഖരം +Comment[mr]=मनोरंजक खेळांचा संग्रह +Comment[nb]=En samling underholdende spill +Comment[nds]=En Sammeln vun Spaaßspelen +Comment[nl]=Een verzameling van grappige spellen +Comment[nn]=Ei samling morosame spel +Comment[pa]=ਖੇਡ ਤਮਾਸ਼ਿਆਂ ਦਾ ਭੰਡਾਰ +Comment[pl]=Kolekcja zabawnych gier +Comment[pt]=Uma colecção de jogos engraçados +Comment[pt_BR]=Uma coleção de jogos divertidos +Comment[ro]=Colecție de jocuri distractive +Comment[ru]=Коллекция весёлых игр +Comment[si]=විනෝද ක්‍රීඩා එකතුවක් +Comment[sk]=Kolekcia zábavných hier +Comment[sl]=Zbirka zabavnih iger +Comment[sr]=Збирка игара за разоноду +Comment[sr@ijekavian]=Збирка игара за разоноду +Comment[sr@ijekavianlatin]=Zbirka igara za razonodu +Comment[sr@latin]=Zbirka igara za razonodu +Comment[sv]=En samling roliga spel +Comment[tg]=Маҷмӯъи бозиҳои хушӣ +Comment[th]=ชุดเกมสนุก ๆ ต่าง ๆ +Comment[tr]=Neşeli oyunlar koleksiyonu +Comment[ug]=بىر توپلام قىزىقارلىق ئويۇنلار +Comment[uk]=Збірка веселих ігор +Comment[wa]=Ene ramexhnêye di zûnants djeus +Comment[x-test]=xxA collection of fun gamesxx +Comment[zh_CN]=一组趣味游戏 +Comment[zh_TW]=好玩遊戲的集合 +Icon=applications-games + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-games + +X-Plasma-Sal-Url=kservicegroup://root/Games/ +X-Plasma-Sal-Relevance=1 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-graphics.desktop b/plasma/netbook/containments/sal/services/plasma-sal-graphics.desktop new file mode 100644 index 00000000..340cd156 --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-graphics.desktop @@ -0,0 +1,166 @@ +[Desktop Entry] +Name=Graphics +Name[af]=Grafieka +Name[ar]=برامج رسم +Name[as]=চিত্ৰাঙ্কন +Name[ast]=Gráficos +Name[be]=Графіка +Name[be@latin]=Hrafika +Name[bg]=Графика +Name[bn]=গ্রাফিক্স +Name[bn_IN]=গ্রাফিক্স +Name[br]=Grafikoù +Name[bs]=Grafika +Name[ca]=Gràfics +Name[ca@valencia]=Gràfics +Name[cs]=Grafika +Name[csb]=Grafika +Name[cy]=Graffeg +Name[da]=Grafik +Name[de]=Grafik +Name[el]=Γραφικά +Name[en_GB]=Graphics +Name[eo]=Grafiko +Name[es]=Gráficos +Name[et]=Graafika +Name[eu]=Grafikoak +Name[fa]=نگاره‌ها +Name[fi]=Grafiikka +Name[fr]=Graphisme +Name[fy]=Grafysk +Name[ga]=Grafaic +Name[gl]=Gráficos +Name[gu]=ચિત્રો +Name[he]=גרפיקה +Name[hi]=ग्राफिक्स +Name[hne]=ग्राफिक्स +Name[hr]=Grafika +Name[hsb]=Grafika +Name[hu]=Grafikai programok +Name[ia]=Graphiches +Name[id]=Grafik +Name[is]=Myndvinnsla +Name[it]=Grafica +Name[ka]=გრაფიკა +Name[kk]=Графика +Name[km]=ក្រាហ្វិក +Name[kn]=ಸಚಿತ್ರತೆ (ಗ್ರಾಫಿಕ್ಸ್) +Name[ko]=그래픽 +Name[ku]=Grafîk +Name[lt]=Grafika +Name[lv]=Grafika +Name[mai]=आलेखी +Name[mk]=Графика +Name[ml]=ഗ്രാഫിക്സ് +Name[mr]=आलेखीय +Name[ms]=Grafik +Name[nb]=Grafikk +Name[nds]=Grafik +Name[ne]=ग्राफिक्स +Name[nl]=Grafisch +Name[nn]=Bilete +Name[oc]=Grafisme +Name[or]=ଆଲେଖି +Name[pa]=ਗਰਾਫਿਕਸ +Name[pl]=Grafika +Name[pt]=Gráficos +Name[pt_BR]=Gráficos +Name[ro]=Grafică +Name[ru]=Графика +Name[se]=Grafihkka +Name[si]=චිත්‍රක +Name[sk]=Grafika +Name[sl]=Grafika +Name[sr]=Графика +Name[sr@ijekavian]=Графика +Name[sr@ijekavianlatin]=Grafika +Name[sr@latin]=Grafika +Name[sv]=Grafik +Name[ta]=சித்திரங்கள் +Name[te]=గ్రాఫిక్స్ +Name[tg]=Графика +Name[th]=กราฟิก +Name[tr]=Grafik +Name[ug]=گرافىك +Name[uk]=Графіка +Name[uz]=Grafika +Name[uz@cyrillic]=Графика +Name[vi]=Đồ hoạ +Name[wa]=Imådjes +Name[xh]=Imizobo +Name[x-test]=xxGraphicsxx +Name[zh_CN]=图像 +Name[zh_TW]=圖形 +Comment=Graphics applications, such as paint programs and image viewers +Comment[ar]=برامج رسومية مثل برامج التلوين وعارضات الصور +Comment[ast]=Aplicaciones de gráficos, como programes de dibuxu y visores d'imáxenes +Comment[bg]=Графични програми – за рисуване и преглед +Comment[bn]=গ্রাফিক্স অ্যাপলিকেশন, যেমন আঁকার প্রোগ্রাম এবং ছবি প্রদর্শক +Comment[bs]=Grafički programi, poput onih za crtanje i prikazivača slika +Comment[ca]=Aplicacions gràfiques, com programes de pintura i visors d'imatges +Comment[ca@valencia]=Aplicacions gràfiques, com programes de pintura i visors d'imatges +Comment[cs]=Grafické aplikace, jako kreslící programy a prohlížeče obrázků +Comment[csb]=Graficzné aplikacëje jakno do malënków ë przezéraniô òbrôzków +Comment[da]=Grafikprogrammer, såsom tegneprogrammer og billedfremvisere +Comment[de]=Grafikanwendungen wie Malprogramme und Bildbetrachter +Comment[el]=Εφαρμογές γραφικών, όπως προγράμματα ζωγραφικής και προβολής εικόνων +Comment[en_GB]=Graphics applications, such as paint programs and image viewers +Comment[es]=Aplicaciones de gráficos, como programas de dibujo y visores de imágenes +Comment[et]=Graafikarakendused, näiteks joonistamisrakendused ja pildinäitajad +Comment[eu]=Aplikazio grafikoak; adibidez, margotzeko programak eta irudi-ikustaileak +Comment[fi]=Grafiikkasovellukset, kuten piirto-ohjelmat ja kuvankatselimet +Comment[fr]=Applications graphiques tel que les programmes de dessin et les afficheurs d'images +Comment[fy]=Grafyske applikaasjes, lykas tekenprogramma's en ôfbylding werjouwers +Comment[ga]=Feidhmchláir ghrafaice, mar shampla ríomhchláir phéinteála agus amharcáin íomhánna +Comment[gl]=Programas gráficos, por ex. programas de debuxo e visores de imaxes +Comment[he]=יישומים גרפיים, כמו תוכנות ציור ומציגי תמונות +Comment[hr]=Grafičke aplikacije, poput programa za crtanje i pregledavanje slika +Comment[hu]=Grafikus alkalmazások, például rajzprogramok és képmegjelenítők +Comment[ia]=Applicationes graphic, tal como programmas de picturar e visores de imagines +Comment[id]=Aplikasi grafis, seperti program menggambar dan penampil gambar +Comment[is]=Myndmeðhöndlunarforrit eins og myndvinnsluforrit, teikniforrit og myndskoðarar +Comment[ja]=お絵描きアプリケーションやイメージビューアなどのグラフィックアプリケーション +Comment[kk]=Сурет салу және кескінді қарау құралы секілді графикалық қолданбалар +Comment[km]=កម្មវិធី​ក្រាហ្វិក ដូ​ចជា​ កម្មវិធី​គូរ និង​កម្មវិធីមើល​រូបភាព +Comment[ko]=그림 편집기, 뷰어와 같은 그래픽 프로그램 +Comment[lt]=Vaizdų programos, pavyzdžiui piešimo ir nuotraukų peržiūros +Comment[lv]=Grafikas lietotnes, zīmēšanas programmas un attēlu skatītāji +Comment[mk]=Графички апликации, како што се програми за цртање и прегледувачи на слики +Comment[ml]=വരയ്ക്കാനും ചിത്രങ്ങള്‍ കാണുന്നതിനും പോലുമുള്ള ഗ്രാഫിക്സ് പ്രയോഗങ്ങള്‍ +Comment[mr]=आलेखीय अनुप्रयोग. उदा. पेंट कार्यक्रम व प्रतिमा प्रदर्शक +Comment[nb]=Grafiske programmer, slik som maleprogrammer og bildevisere +Comment[nds]=Grafikprogrammen, so as Maalprogrammen un Bildkiekers +Comment[nl]=Grafische programma's, zoals teken- en afbeeldingsweergave-programma's +Comment[nn]=Biletprogram, som teikneprogram og fotovisarar +Comment[pa]=ਗਰਾਫਿਕਸ ਐਪਲੀਕੇਸ਼ਨ, ਜਿਵੇਂ ਕਿ ਪੇਂਟ ਪਰੋਗਰਾਮ ਅਤੇ ਚਿੱਤਰ ਦਰਸ਼ਕ +Comment[pl]=Programy graficzne, takie jak programy do rysowania i przeglądarki obrazów +Comment[pt]=Aplicações gráficas, como os programas de pintura e os visualizadores de imagens +Comment[pt_BR]=Aplicativos gráficos, tais como programas de desenho e visualizadores de imagens +Comment[ro]=Aplicații de grafică, cum ar fi programe de desen și vizualizare de imagini +Comment[ru]=Графические приложения, такие как программы рисования и просмотра изображений +Comment[si]=චිත්‍රණ යෙදුම්, චිත්‍ර ඇඳීම් හා පින්තූර දසුන් වැඩසටහන් වැනි +Comment[sk]=Grafické aplikácie, ako kresliace programy a prehliadače obrázkov +Comment[sl]=Grafični programi, npr. slikarski programi in pregledovalniki slik +Comment[sr]=Графички програми, попут оних за цртање и приказивача слика +Comment[sr@ijekavian]=Графички програми, попут оних за цртање и приказивача слика +Comment[sr@ijekavianlatin]=Grafički programi, poput onih za crtanje i prikazivača slika +Comment[sr@latin]=Grafički programi, poput onih za crtanje i prikazivača slika +Comment[sv]=Grafikprogram, som ritprogram och bildvisning +Comment[tg]=Поиск приложений и служб +Comment[th]=โปรแกรมต่าง ๆ ด้านกราฟิก เช่นโปรแกรมวาดภาพ และโปรแกรมดูรูปภาพ +Comment[tr]=Grafik uygulamaları, boyama ve resim gösterme uygulamaları gibi +Comment[ug]=گرافىك پروگراممىلىرى، رەسىم سىزىش ۋە سۈرەت كۆرگۈچ پروگراممىلىرى +Comment[uk]=Програми для роботи з графікою, зокрема програми для малювання та перегляду зображень +Comment[vi]=Các ứng dụng đồ hoạ như các chương trình vẽ hay trình xem ảnh +Comment[wa]=Programes po les imådjes come des programes di pondeure eyet des håyneus d' imådjes +Comment[x-test]=xxGraphics applications, such as paint programs and image viewersxx +Comment[zh_CN]=图形图像应用程序,如绘画工具和图像查看器 +Comment[zh_TW]=美工應用程式,如繪圖程式與影像檢視器等 +Icon=applications-graphics + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-graphics + +X-Plasma-Sal-Url=kservicegroup://root/Graphics/ +X-Plasma-Sal-Relevance=1 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-internet.desktop b/plasma/netbook/containments/sal/services/plasma-sal-internet.desktop new file mode 100644 index 00000000..0fa8f42c --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-internet.desktop @@ -0,0 +1,165 @@ +[Desktop Entry] +Name=Internet +Name[af]=Internet +Name[ar]=الإنترنت +Name[as]=ইন্টাৰ্নে'ট +Name[ast]=Internet +Name[be]=Інтэрнэт +Name[be@latin]=Internet +Name[bg]=Интернет +Name[bn]=ইন্টারনেট +Name[bn_IN]=ইন্টারনেট +Name[br]=Kenrouedad +Name[bs]=Internet +Name[ca]=Internet +Name[ca@valencia]=Internet +Name[cs]=Internet +Name[csb]=Internet +Name[cy]=Rhyngrwyd +Name[da]=Internet +Name[de]=Internet +Name[el]=Διαδίκτυο +Name[en_GB]=Internet +Name[eo]=Interreto +Name[es]=Internet +Name[et]=Internet +Name[eu]=Internet +Name[fa]=اینترنت +Name[fi]=Internet +Name[fr]=Internet +Name[fy]=Ynternet +Name[ga]=Idirlíon +Name[gl]=Internet +Name[gu]=ઇન્ટરનેટ +Name[he]=אינטרנט +Name[hi]=इन्टरनेट +Name[hne]=इन्टरनेट +Name[hr]=Internet +Name[hsb]=Internet +Name[hu]=Internet +Name[ia]=Internet +Name[id]=Internet +Name[is]=Internetið +Name[it]=Internet +Name[ka]=ინტერნეტი +Name[kk]=Интернет +Name[km]=អ៊ីនធឺណិត +Name[kn]=ಅಂತರ್ಜಾಲ +Name[ko]=인터넷 +Name[ku]=Înternet +Name[lt]=Internetas +Name[lv]=Internets +Name[mai]=इंटरनेट +Name[mk]=Интернет +Name[ml]=ഇന്റര്‍നെറ്റ് +Name[mr]=महाजाळ +Name[ms]=Internet +Name[nb]=Internett +Name[nds]=Internet +Name[ne]=इन्टरनेट +Name[nl]=Internet +Name[nn]=Internett +Name[oc]=Internet +Name[or]=ଇଣ୍ଟରନେଟ +Name[pa]=ਇੰਟਰਨੈੱਟ +Name[pl]=Internet +Name[pt]=Internet +Name[pt_BR]=Internet +Name[ro]=Internet +Name[ru]=Интернет +Name[se]=Interneahtta +Name[si]=අන්තර්ජාලය +Name[sk]=Internet +Name[sl]=Internet +Name[sr]=Интернет +Name[sr@ijekavian]=Интернет +Name[sr@ijekavianlatin]=Internet +Name[sr@latin]=Internet +Name[sv]=Internet +Name[ta]=இணையம் +Name[te]=ఇంటర్నెట్ +Name[tg]=Интернет +Name[th]=อินเทอร์เน็ต +Name[tr]=İnternet +Name[ug]=ئىنتېرنېت +Name[uk]=Інтернет +Name[uz]=Internet +Name[uz@cyrillic]=Интернет +Name[vi]=Internet +Name[wa]=Daegntoele +Name[x-test]=xxInternetxx +Name[zh_CN]=互联网 +Name[zh_TW]=網際網路 +Comment=Internet related applications, such as Web browser, Email and chat +Comment[ar]=برامج متعلقة بالإنترنت كمتصفح الوِب والبريد والدردشة +Comment[ast]=Aplicaciones rellacionaes con Internet, como restoladores web, corréu electrónicu y chat +Comment[bg]=Интернет приложения, като уеб браузър, електронна поща и чат +Comment[bn]=ইন্টারনেট সংক্রান্ত অ্যাপলিকেশন, যেমন ওয়েব-ব্রাউসার, ই-মেইল এবং চ্যাট +Comment[bs]=Programi u vezi s Internetom, poput veb pregledača, e‑pošte i ćaskanja +Comment[ca]=Aplicacions relacionades amb Internet, com navegador Web, correu electrònic i xat +Comment[ca@valencia]=Aplicacions relacionades amb Internet, com navegador Web, correu electrònic i xat +Comment[cs]=Aplikace související s internetem jako je internetový prohlížeč, e-mail a rozhovor +Comment[csb]=Aplikacëje sparłãczoné z internetã, jakno przezérniczi, programë e-mailowé ë czatowé +Comment[da]=Internetrelaterede programmer, såsom webbrowser, e-mail og chat +Comment[de]=Internet-Anwendungen wie Webbrowser, E-Mail-Programm oder Chat +Comment[el]=Εφαρμογές σχετικές με το διαδίκτυο, όπως περιηγητές διαδικτύου, ηλεκτρονικής αλληλογραφίας και συνομιλίας +Comment[en_GB]=Internet related applications, such as Web browser, Email and chat +Comment[es]=Aplicaciones relacionadas con Internet, como navegadores web, correo electrónico y chat +Comment[et]=Internetiga seotud rakendused, näiteks veebibrauser, e-posti klient ja kiirsuhtlusrakendus +Comment[eu]=Internetekin erlazionatutako aplikazioak; adibidez, web-arakatzaileak, posta elektronikoa eta berriketa +Comment[fi]=Internetiin liittyvät sovellukset, kuten verkkoselain, sähköposti ja verkkokeskustelu +Comment[fr]=Applications en relation avec Internet tel que les navigateurs, les clients de courrier électronique et les logiciels de messagerie instantanée +Comment[fy]=Mei ynternet relatearre applikaasje, lykas webblêd, e-post en tsjet +Comment[ga]=Feidhmchlár a bhaineann leis an Idirlíon, mar shampla brabhsálaithe, cliaint ríomhphoist agus cláir chomhrá +Comment[gl]=Programas relacionados con internet, como un navegador web, correo e chat +Comment[he]=יישומי אינטרנט, כגון דפדפן רשת, דואר אלקטרוני ומסרים מידיים +Comment[hr]=Aplikacije vezane za Internet, poput web preglednika, te programa za e-poštu i čavrljanje +Comment[hu]=Internetes alkalmazások, például webböngésző, e-mail kliens és csevegőprogram +Comment[ia]=Applicationes referite a Internet, tal como Navigator Web, E-Posta e confabulation +Comment[id]=Aplikasi terkait Internet, seperti peramban Web, Email dan obrolan +Comment[is]=Internetforrit á borð við vafra, tölvupóst- og spjallforrit +Comment[ja]=ウェブブラウザ、電子メール、チャットなどのインターネット関連のアプリケーション +Comment[kk]=Веб шолғыш, эл.пошта, чат секілді Интернетке қатысты қолданбалар +Comment[km]=កម្មវិធី​ដែលទាក់ទង​នឹង​អ៊ីនធឺណិត ដូចជា​ កម្មវិធី​រុករក​បណ្ដាញ អ៊ីមែល ជជែក +Comment[kn]=ಜಾಲ ವೀಕ್ಷಕ, ವಿಅಂಚೆ ಹಾಗು ಚಾಟ್‌ನಂತಹ ಅಂತರ್ಜಾಲ ಸಂಬಂಧಿತವಾದ ಅನ್ವಯಗಳು +Comment[ko]=웹 브라우저, 이메일, 채팅과 같은 인터넷 프로그램 +Comment[lt]=Su internetu susijusios programos, tokios kaip naršyklės, el. pašto ar pokalbių +Comment[lv]=Ar Internetu saistītas lietotnes, tīmekļa pārlūks, e-pasts un tērzēšana +Comment[mk]=Апликации поврзани со Интернет, како што е веб-прелистување, е-пошта и разговор +Comment[ml]=ഇന്റര്‍നെറ്റിനോടനുബന്ധിച്ചിട്ടുള്ള പ്രയോഗങ്ങളായ വെബ് ബ്രൌസര്‍, ഈമെയില്‍, സല്ലാപം മുതലായവ +Comment[mr]=महाजाळ संबंधित अनुप्रयोग. उदा. वेब ब्राऊजर, इमेल व चेैट +Comment[nb]=Internett-relaterte programmer, slik som nettleser, e-post og prateprogrammer +Comment[nds]=Programmen rund dat Internet, so as Nettkiekers, Nettpost- un Klöönprogrammen +Comment[nl]=Internet gerelateerde programma's, zoals Webbrowser, E-mail en chat +Comment[nn]=Internett-relaterte program, som nettlesarar og e-post- og prateprogram +Comment[pa]=ਇੰਟਰਨੈੱਟ ਨਾਲ ਸਬੰਧਿਤ ਐਪਲੀਕੇਸ਼ਨ, ਜਿਵੇਂ ਕਿ ਵੈੱਬ ਬਰਾਊਜ਼ਰ, ਈਮੇਲ ਅਤੇ ਚੈਟ +Comment[pl]=Programy internetowe, takie jak przeglądarka WWW, poczta i czat +Comment[pt]=Aplicações relacionadas com a Internet, como o navegador Web, o E-mail e as conversações +Comment[pt_BR]=Aplicativos relacionados à Internet, tais como o navegador da Web, e-mail e bate-papo +Comment[ro]=Aplicații legate de Internet, cum ar fi navigator web, poștă și discuții +Comment[ru]=Приложения, связанные с Интернетом, такие как браузер, почтовый клиент и клиент мгновенных сообщений +Comment[si]=අන්තර්ජාලය සම්බන්ධ භාවිත යෙදවුම්, වෙබ් ගවේශකය, තැපැල් හා සංවාද වැනි +Comment[sk]=Internetové aplikácie, ako webový prehliadač, poštový klient a chat +Comment[sl]=Internetni programi, npr. spletni brskalniki, e-pošta in klepet +Comment[sr]=Програми у вези с Интернетом, попут веб прегледача, е‑поште и ћаскања +Comment[sr@ijekavian]=Програми у вези с Интернетом, попут веб прегледача, е‑поште и ћаскања +Comment[sr@ijekavianlatin]=Programi u vezi s Internetom, poput veb pregledača, e‑pošte i ćaskanja +Comment[sr@latin]=Programi u vezi s Internetom, poput veb pregledača, e‑pošte i ćaskanja +Comment[sv]=Internet-relaterade program, som webbläsare, e-post och chatt +Comment[th]=โปรแกรมต่าง ๆ ด้านอินเทอร์เน็ต เช่นเว็บเบราว์เซอร์, การรับส่งจดหมาย และโปรแกรมพูดคุย +Comment[tr]=İnternet ile ilgili uygulamalar, Web tarayıcı, e-posta ve sohbet istemcileri gibi +Comment[ug]=ئىنتېرنېتقا مۇناسىۋەتلىك پروگراممىلار، توركۆرگۈ، ئېلخەت ۋە مۇڭداشقۇلار +Comment[uk]=Програми, пов’язані з інтернетом, зокрема переглядач інтернету, поштовий клієнт та клієнти служб обміну повідомленнями +Comment[vi]=Các ứng dụng mạng như trình duyệt web, thư điện tử và chat +Comment[wa]=Programes pol Daegntoele come li betchteu waibe, l' emilaedje eyet l' berdelaedje sol moumint +Comment[x-test]=xxInternet related applications, such as Web browser, Email and chatxx +Comment[zh_CN]=互联网应用程序,如网络浏览器、邮件客户端和聊天工具 +Comment[zh_TW]=網際網路相關應用程式,如瀏覽器、電子郵件收發程式與聊天室 +Icon=applications-internet + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-internet + +X-Plasma-Sal-Url=kservicegroup://root/Internet/ +X-Plasma-Sal-Relevance=1 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-multimedia.desktop b/plasma/netbook/containments/sal/services/plasma-sal-multimedia.desktop new file mode 100644 index 00000000..e1cc9a1b --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-multimedia.desktop @@ -0,0 +1,166 @@ +[Desktop Entry] +Name=Multimedia +Name[af]=Multimedia +Name[ar]=الوسائط المتعددة +Name[as]=মাল্টিমিডিয়া +Name[ast]=Multimedia +Name[be]=Мультымедыя +Name[be@latin]=Multymedyja +Name[bg]=Мултимедия +Name[bn]=মাল্টিমিডিয়া +Name[bn_IN]=মাল্টি-মিডিয়া +Name[br]=Liesvedia +Name[bs]=Multimedija +Name[ca]=Multimèdia +Name[ca@valencia]=Multimèdia +Name[cs]=Multimédia +Name[csb]=Mùltimedia +Name[cy]=Amlgyfryngau +Name[da]=Multimedie +Name[de]=Multimedia +Name[el]=Πολυμέσα +Name[en_GB]=Multimedia +Name[eo]=Aŭdvido +Name[es]=Multimedia +Name[et]=Multimeedia +Name[eu]=Multimedia +Name[fa]=چند رسانه‌ای +Name[fi]=Multimedia +Name[fr]=Multimédia +Name[fy]=Multimedia +Name[ga]=Ilmheáin +Name[gl]=Multimedia +Name[gu]=મલ્ટિમીડિઆ +Name[he]=מולטימדיה +Name[hi]=मल्टीमीडिया +Name[hne]=मल्टीमीडिया +Name[hr]=Multimedija +Name[hsb]=Multimedija +Name[hu]=Multimédia +Name[ia]=Multimedia +Name[id]=Multimedia +Name[is]=Margmiðlun +Name[it]=Multimedia +Name[ka]=მულტიმედია +Name[kk]=Мультимедиа +Name[km]=ពហុព័ត៌មាន +Name[kn]=ಬಹುಮಾಧ್ಯಮ +Name[ko]=멀티미디어 +Name[ku]=Multîmedya +Name[lt]=Multimedia +Name[lv]=Multivide +Name[mai]=मल्टीमीडिया +Name[mk]=Мултимедија +Name[ml]=മള്‍ട്ടീമീഡിയ +Name[mr]=मल्टीमीडिया +Name[ms]=Multimedia +Name[nb]=Multimedia +Name[nds]=Multimedia +Name[ne]=मल्टिमिडिया +Name[nl]=Multimedia +Name[nn]=Multimedia +Name[oc]=Multimedià +Name[or]=ବହୁମାଧ୍ଯମ +Name[pa]=ਮਲਟੀਮੀਡਿਆ +Name[pl]=Multimedia +Name[pt]=Multimédia +Name[pt_BR]=Multimídia +Name[ro]=Multimedia +Name[ru]=Мультимедиа +Name[se]=Multimedia +Name[si]=බහුමාධ්‍යය +Name[sk]=Multimédiá +Name[sl]=Predstavnost +Name[sr]=Мултимедија +Name[sr@ijekavian]=Мултимедија +Name[sr@ijekavianlatin]=Multimedija +Name[sr@latin]=Multimedija +Name[sv]=Multimedia +Name[ta]=பல்லூடகம் +Name[te]=బహుళ మాద్యమం +Name[tg]=Мултимедиа +Name[th]=มัลติมีเดีย +Name[tr]=Çoklu Ortam +Name[ug]=كۆپ ۋاسىتە +Name[uk]=Мультимедіа +Name[uz]=Multimedia +Name[uz@cyrillic]=Мултимедиа +Name[vi]=Nhạc/Ảnh +Name[wa]=Multimedia +Name[xh]=Iindlela ezininzi zokwenza +Name[x-test]=xxMultimediaxx +Name[zh_CN]=多媒体 +Name[zh_TW]=多媒體 +Comment=Multimedia applications, such as audio and video players +Comment[ar]=برامج الوسائط المتعدّدة كمشغلات الصوت والفيديو +Comment[ast]=Aplicaciones multimedia, como reproductores d'audio y videu +Comment[bg]=Мултимедийни приложения, като аудио и видео плеъри +Comment[bn]=মাল্টিমিডিয়া অ্যাপলিকেশন, যেমন অডিও ও ভিডিও প্লেয়ার +Comment[bs]=Multimedijski programi, poput audio i video plejera +Comment[ca]=Aplicacions multimèdia, com reproductors d'àudio i vídeo +Comment[ca@valencia]=Aplicacions multimèdia, com reproductors d'àudio i vídeo +Comment[cs]=Multimediální aplikace jako jsou audio a video přehrávače +Comment[csb]=Mùltimedialné aplikacëje jakno grôcze aùdio ë wideò +Comment[da]=Multimedieprogrammer, såsom lyd- og videoafspillere +Comment[de]=Multimedia-Anwendungen wie Abspielprogramme für Audio und Video +Comment[el]=Εφαρμογές πολυμέσων, όπως αναπαραγωγείς ήχου και εικόνας +Comment[en_GB]=Multimedia applications, such as audio and video players +Comment[eo]=Plurmediaj aplikaĵoj kiel son- kaj film- legiloj +Comment[es]=Aplicaciones multimedia, como reproductores de audio y vídeo +Comment[et]=Multimeediarakendused, näiteks muusika- ja videomängija +Comment[eu]=Multimedia-aplikazioak; adibidez, audio- eta bideo-jotzaileak +Comment[fi]=Multimediasovellukset, kuten ääni- ja videosoittimet +Comment[fr]=Applications multimédia tel que les lecteurs audio et vidéo +Comment[fy]=Multymedia applikaasjes, lykas audio en fideo spilers +Comment[ga]=Feidhmchláir ilmheán, mar shampla seinnteoirí fuaime agus físe +Comment[gl]=Programas multimedia, do estilo de reprodutores de son e vídeo +Comment[he]=יישומי מולטימדיה, כגון נגני מוזיקה וסרטים +Comment[hr]=Multimedijalne aplikacije, poput audio i video svirača +Comment[hu]=Multimédiás alkalmazások, például hang- és videolejátszók +Comment[ia]=Applicationes multimedial, tal como reproductores audio e video +Comment[id]=Aplikasi multimedia, seperti pemutar audio dan video +Comment[is]=Margmiðlunarforrit eins og vídeó- og hljóðspilarar +Comment[ja]=オーディオやビデオプレーヤーなどのマルチメディアアプリケーション +Comment[kk]=Аудио және видео плейер секілді мультимедиа қолданбалар +Comment[km]=កម្មវិធី​​ពហុ​មេឌៀ ដូច​ជា កម្មវិធី​ចាក់​អូឌីយ៉ូ និង​វីដេអូ +Comment[ko]=오디오 및 비디오 재생기와 같은 멀티미디어 프로그램 +Comment[lt]=Daugialypės terpės programos, tokios kaip audio ir video leistuvai +Comment[lv]=Multivides lietotnes, audio un video atskaņotāji +Comment[mk]=Мултимедијални апликации, како што се аудио и видео плеери +Comment[ml]=മള്‍ട്ടീമീഡിയാ പ്രയോഗങ്ങളായ: ഓഡിയോ, വീഡിയോ പ്ലയറുകള്‍ മുതലായവ +Comment[mr]=मल्टीमीडिया अनुप्रयोग. उदा. ऑडिओ व व्हिडीओ प्लेयर्स +Comment[nb]=Multimediaprogrammer, slik som lyd- og videospillere +Comment[nds]=Multimedia-Programmen, so as Klang- un Video-Afspelers +Comment[nl]=Multimedia programma's, zoals audio- en videospelers +Comment[nn]=Multimedia-program, som musikk- og filmspelarar +Comment[pa]=ਮਲਟੀਮੀਡਿਆ ਐਪਲੀਕੇਸ਼ਨ, ਜਿਵੇਂ ਆਡੀਓ ਅਤੇ ਵਿਡੀਓ ਪਲੇਅਰ +Comment[pl]=Programy multimedialne, takie jak odtwarzacze audio i wideo +Comment[pt]=Aplicações multimédia, como os leitores de áudio e vídeo +Comment[pt_BR]=Aplicativos multimídia, tais como reprodutores de áudio e vídeo +Comment[ro]=Aplicații multimedia, pentru redare de sunet și imagine +Comment[ru]=Мультимедийные приложения, в том числе проигрыватели аудио и видео +Comment[si]=බහුමාධ්‍ය භාවිත යෙදවුම්, ශ්‍රව්‍ය දෘශ්‍ය ධාවක වැනි +Comment[sk]=Multimediálne aplikácie, ako prehrávače videa a zvuku +Comment[sl]=Predstavnostni programi, npr. predvajalniki zvoka in videa +Comment[sr]=Мултимедијски програми, попут аудио и видео плејера +Comment[sr@ijekavian]=Мултимедијски програми, попут аудио и видео плејера +Comment[sr@ijekavianlatin]=Multimedijski programi, poput audio i video plejera +Comment[sr@latin]=Multimedijski programi, poput audio i video plejera +Comment[sv]=Multimediaprogram, som ljud- och videospelare +Comment[tg]=Барномаҳои мултимедиа монанди плеерҳои аудио ва видео +Comment[th]=โปรแกรมต่าง ๆ ด้านสื่อประสม เช่น เครื่องเล่นวีดิทัศน์และเครื่องเล่นเสียง +Comment[tr]=Ses ve video oynatıcılar gibi çoklu ortam uygulamaları +Comment[ug]=كۆپ ۋاسىتە پروگراممىلار، ئۈن ۋە سىن چالغۇلار +Comment[uk]=Мультимедійні програми, зокрема програвачі звукових та відеоданих +Comment[wa]=Programes multimedia come des djouweus odio ou d' videyo +Comment[x-test]=xxMultimedia applications, such as audio and video playersxx +Comment[zh_CN]=多媒体应用程序,如视频/音频播放器 +Comment[zh_TW]=多媒體應用程式,如音效與影像播放器 +Icon=applications-multimedia + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-multimedia + +X-Plasma-Sal-Url=kservicegroup://root/Multimedia/ +X-Plasma-Sal-Relevance=1 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-office.desktop b/plasma/netbook/containments/sal/services/plasma-sal-office.desktop new file mode 100644 index 00000000..d710a3bd --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-office.desktop @@ -0,0 +1,165 @@ +[Desktop Entry] +Name=Office +Name[af]=Kantoor +Name[ar]=المكتب +Name[as]=কাৰ্যালয় +Name[ast]=Oficina +Name[be]=Офіс +Name[be@latin]=Ofis +Name[bg]=Офис +Name[bn]=অফিস +Name[bn_IN]=অফিস +Name[br]=Burev +Name[bs]=Kancelarija +Name[ca]=Oficina +Name[ca@valencia]=Oficina +Name[cs]=Kancelář +Name[csb]=Biuro +Name[cy]=Swyddfa +Name[da]=Kontor +Name[de]=Büroprogramme +Name[el]=Γραφείο +Name[en_GB]=Office +Name[eo]=Laborejo +Name[es]=Oficina +Name[et]=Kontoritöö +Name[eu]=Bulegoa +Name[fa]=اداره +Name[fi]=Toimisto-ohjelmat +Name[fr]=Bureautique +Name[fy]=Kantoartapassingen +Name[ga]=Oifig +Name[gl]=Ofimática +Name[gu]=ઓફિસ +Name[he]=משרד +Name[hi]=कार्यालय +Name[hne]=आफिस +Name[hr]=Ured +Name[hsb]=Běrowowe programy +Name[hu]=Irodai alkalmazások +Name[ia]=Officio +Name[id]=Perkantoran +Name[is]=Skrifstofuforrit +Name[it]=Ufficio +Name[ka]=ოფისი +Name[kk]=Офис +Name[km]=ការិយាល័យ +Name[kn]=ಕಛೇರಿ +Name[ko]=사무용 도구 +Name[ku]=Nivîsgeh +Name[lt]=Biuro programos +Name[lv]=Birojs +Name[mai]=कार्यालय +Name[mk]=Канцеларија +Name[ml]=ഓഫീസ് +Name[mr]=ऑफीस +Name[ms]=Pejabat +Name[nb]=Kontor +Name[nds]=Kontoor +Name[ne]=कार्यालय +Name[nl]=Kantoortoepassingen +Name[nn]=Kontor +Name[oc]=Burèu +Name[or]=ଅଫିସ +Name[pa]=ਦਫ਼ਤਰ +Name[pl]=Biuro +Name[pt]=Escritório +Name[pt_BR]=Escritório +Name[ro]=Aplicații birotică +Name[ru]=Офис +Name[se]=Kántuvra +Name[si]=කාර්‍යයාලීය +Name[sk]=Kancelária +Name[sl]=Pisarna +Name[sr]=Канцеларија +Name[sr@ijekavian]=Канцеларија +Name[sr@ijekavianlatin]=Kancelarija +Name[sr@latin]=Kancelarija +Name[sv]=Kontor +Name[ta]=அலுவலகம் +Name[te]=కార్యాలయము +Name[tg]=Офис +Name[th]=สำนักงาน +Name[tr]=Ofis +Name[ug]=ئىشخانا +Name[uk]=Офіс +Name[uz]=Idora uchun dasturlar +Name[uz@cyrillic]=Идора учун дастурлар +Name[vi]=Văn phòng +Name[wa]=Buro +Name[xh]=Ofisi +Name[x-test]=xxOfficexx +Name[zh_CN]=办公 +Name[zh_TW]=辦公軟體 +Comment=Office related applications, such as wordprocessing and spreadsheets +Comment[ar]=برامج متعلقة بالمكتب كمعالجة النصوص والجداول الممتدة +Comment[ast]=Aplicaciones d'oficina, como procesadores de testu y fueyes de cálculu +Comment[bg]=Офисни приложения, като текстообработка и таблици +Comment[bn]=অফিস সংক্রান্ত অ্যাপলিকেশন, যেমন ওয়ার্ড-প্রসেসর এবং স্প্রেডশীট +Comment[bs]=Kancelarijski programi, poput obrade riječi i računskih tablica +Comment[ca]=Aplicacions relacionades amb una oficina, com processament de textos i fulls de càlcul +Comment[ca@valencia]=Aplicacions relacionades amb una oficina, com processament de textos i fulls de càlcul +Comment[cs]=Kancelářské aplikace jako jsou textové a tabulkové procesory +Comment[csb]=Biurowé aplikacëje, jakno procesorë tekstu ë sprôwdzanié pisënkù +Comment[da]=Kontorrelaterede programmer, såsom tekstbehandling og regneark +Comment[de]=Büroanwendungen wie Textverarbeitung oder Tabellenkalkulation +Comment[el]=Εφαρμογές γραφείου, όπως επεξεργαστές κειμένου και λογιστικά φύλλα +Comment[en_GB]=Office related applications, such as wordprocessing and spreadsheets +Comment[es]=Aplicaciones de oficina, como procesadores de texto y hojas de cálculo +Comment[et]=Kontoritöö rakendused, näiteks teksti- ja tabelitöötluseks +Comment[eu]=Bulegoko aplikazioak; adibidez, testu-prozesatzailea eta kalkulu-orriak +Comment[fi]=Toimistoon liittyvät sovellukset, kuten tekstinkäsittely ja taulukonlaskenta +Comment[fr]=Applications en rapport avec la bureautique tel que les traitements de texte et les tableurs +Comment[fy]=Mei kantoor relatearre applikaasjes, lyk tekstferwurker en rekkenboerden +Comment[ga]=Feidhmchláir oifige, mar shampla próiseálaithe focal agus scarbhileoga +Comment[gl]=Programas ofimáticos, como procesadores de texto e follas de cálculo +Comment[he]=יישומים משרדיים, כגון מעבדי תמלילים וגיליונות אלקטרונים +Comment[hr]=Uredske aplikacije, poput procesora teksta i proračunskih tablica +Comment[hu]=Irodai alkalmazások, például szövegszerkesztők és táblázatkezelők +Comment[ia]=Applicationes referite al officio, tal como processator de parolas e folios de calculo +Comment[id]=Aplikasi terkait perkantoran, seperti pengolah kata dan lembar gaya +Comment[is]=Skrifstofutengd forrit, svo sem ritvinnsla og töflureiknar +Comment[ja]=ワープロやスプレッドシートなどのオフィス関連アプリケーション +Comment[kk]=Мәтін өңдегіші мен электрондық кесте секілді Офисіне қатысты қолданбалар +Comment[km]=ការ​រិយាល័យ​ដែល​ទាក់ទង​នឹង​កម្មវិធី ដូច​ជាកម្មវិធី​វាយ​អត្ថបទ និង​សៀវភៅ​បញ្ជី +Comment[ko]=워드프로세서, 스프레드시트와 같은 사무용 프로그램 +Comment[lt]=Biuro programos, tokios, kaip tekstų rinkimo ir elektroninių lentelių +Comment[lv]=Biroja lietotnes, tekstapstrādes un izklājlapu programmas +Comment[mk]=Канцелариски апликации, како што е обработка на текст и табеларни пресметки +Comment[ml]=ആപ്പീസുമായി ബന്ധപ്പെട്ട പ്രയോഗങ്ങളായ വേര്‍ഡ് പ്രൊസസ്സര്‍, സ്പ്രെഡ് ഷീറ്റ് മുതലായവ +Comment[mr]=ऑफीस संबंधित अनुप्रयोग. उदा. वर्डप्रोसेसिंग व स्प्रेडशीट +Comment[nb]=Kontorprogrammer, slik som tekstbehandling og regneark +Comment[nds]=Programmen rund dat Kontoor, so as Textverarbeiden un Tabellrekenprogrammen +Comment[nl]=Kantoor gerelateerde programma's, zoals woordprocessing en rekenbladen +Comment[nn]=Kontorprogramvare, som teksthandsaming og rekneark +Comment[pa]=ਦਫ਼ਤਰ ਨਾਲ ਸਬੰਧਿਤ ਐਪਲੀਕੇਸ਼ਨ, ਜਿਵੇਂ ਕਿ ਵਰਲਡ-ਪਰੋਸੈਸਿੰਗ ਅਤੇ ਸਪਰੈੱਡਸ਼ੀਟ +Comment[pl]=Programy biurowe, takie jak edytory tekstu i arkusze kalkulacyjne +Comment[pt]=Aplicações relacionadas com o escritório, como os processadores de texto e folhas de cálculo +Comment[pt_BR]=Aplicativos de escritório, tais como processadores de texto e planilhas +Comment[ro]=Aplicații legate de birou, cum ar fi procesare de texte și tabele +Comment[ru]=Офисные приложения, такие как текстовые процессоры и электронные таблицы +Comment[si]=වදන් සැකසුම් හා පැතුරුම්ත් වැනි කාර්‍යාල සම්බන්ධ යෙදුම්. +Comment[sk]=Kancelárske aplikácie, ako textový a tabuľkový procesor +Comment[sl]=Pisarniški programi, npr. urejevalniki besedil in preglednice +Comment[sr]=Канцеларијски програми, попут обраде речи и рачунских таблица +Comment[sr@ijekavian]=Канцеларијски програми, попут обраде ријечи и рачунских таблица +Comment[sr@ijekavianlatin]=Kancelarijski programi, poput obrade riječi i računskih tablica +Comment[sr@latin]=Kancelarijski programi, poput obrade reči i računskih tablica +Comment[sv]=Kontorsrelaterade program, som ordbehandling och kalkylblad +Comment[tg]=Барномаҳо барои корҳои идоравӣ, монанди барномаҳои таҳрири матн ва ҷадвалҳои электронӣ +Comment[th]=โปรแกรมต่าง ๆ ด้านสำนักงาน เช่น โปรแกรมประมวลผลคำ และกระดาษคำนวณ +Comment[tr]=Ofis ile ilgili uygulamalar, kelime işlemciler ve hesap tabloları gibi +Comment[ug]=ئىشخانا يۈرۈشلۈك پروگراممىلار، يېزىق بىر تەرەپ قىلىش ۋە ئېلېكترونلۇق جەدۋەل +Comment[uk]=Програми, пов’язані з офісними завданнями, зокрема текстові процесори та електронні таблиці +Comment[wa]=Programes di burotike, come li scrijhaedje di tecses eyet les tåvleus +Comment[x-test]=xxOffice related applications, such as wordprocessing and spreadsheetsxx +Comment[zh_CN]=办公应用程序,如文字处理工具和电子表格 +Comment[zh_TW]=辦公相關應用程式,如文書處理與試算表等 +Icon=applications-office + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-office + +X-Plasma-Sal-Url=kservicegroup://root/Office/ +X-Plasma-Sal-Relevance=1 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-system.desktop b/plasma/netbook/containments/sal/services/plasma-sal-system.desktop new file mode 100644 index 00000000..3f437858 --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-system.desktop @@ -0,0 +1,165 @@ +[Desktop Entry] +Name=System +Name[af]=Stelsel +Name[ar]=النظام +Name[as]=ব্যৱস্থাপ্ৰণালী +Name[ast]=Sistema +Name[be]=Сістэма +Name[be@latin]=Systema +Name[bg]=Система +Name[bn]=সিস্টেম +Name[bn_IN]=সিস্টেম +Name[br]=Reizhiad +Name[bs]=Sistem +Name[ca]=Sistema +Name[ca@valencia]=Sistema +Name[cs]=Systém +Name[csb]=Systema +Name[cy]=Cysawd +Name[da]=System +Name[de]=System +Name[el]=Σύστημα +Name[en_GB]=System +Name[eo]=Sistemo +Name[es]=Sistema +Name[et]=Süsteem +Name[eu]=Sistema +Name[fa]=سیستم +Name[fi]=Järjestelmä +Name[fr]=Système +Name[fy]=Systeem +Name[ga]=Córas +Name[gl]=Sistema +Name[gu]=સિસ્ટમ +Name[he]=מערכת +Name[hi]=तंत्र +Name[hne]=तंत्र +Name[hr]=Sustav +Name[hsb]=System +Name[hu]=Rendszer +Name[ia]=Systema +Name[id]=Sistem +Name[is]=Kerfi +Name[it]=Sistema +Name[ka]=სისტემა +Name[kk]=Жүйе +Name[km]=ប្រព័ន្ធ +Name[kn]=ವ್ಯವಸ್ಥೆ +Name[ko]=시스템 +Name[ku]=Pergal +Name[lt]=Sistema +Name[lv]=Sistēma +Name[mai]=सिस्टम +Name[mk]=Систем +Name[ml]=സിസ്റ്റം +Name[mr]=प्रणाली +Name[ms]=Sistem +Name[nb]=System +Name[nds]=Systeem +Name[ne]=प्रणाली +Name[nl]=Systeem +Name[nn]=System +Name[oc]=Sistèma +Name[or]=ତନ୍ତ୍ର +Name[pa]=ਸਿਸਟਮ +Name[pl]=System +Name[pt]=Sistema +Name[pt_BR]=Sistema +Name[ro]=Sistem +Name[ru]=Система +Name[se]=Vuogádat +Name[si]=පද්ධතිය +Name[sk]=Systém +Name[sl]=Sistem +Name[sr]=Систем +Name[sr@ijekavian]=Систем +Name[sr@ijekavianlatin]=Sistem +Name[sr@latin]=Sistem +Name[sv]=System +Name[ta]=அமைப்பு +Name[te]=వ్యవస్థ +Name[tg]=Система +Name[th]=ระบบ +Name[tr]=Sistem +Name[ug]=سىستېما +Name[uk]=Система +Name[uz]=Tizim +Name[uz@cyrillic]=Тизим +Name[vi]=Hệ thống +Name[wa]=Sistinme +Name[xh]=Indlela esestyenziswayo +Name[x-test]=xxSystemxx +Name[zh_CN]=系统 +Name[zh_TW]=系統 +Comment=System preferences and setup programs +Comment[ar]=تفضيلات النظام وإعدادت البرامج +Comment[ast]=Preferencies del sistemes y configuración de programes +Comment[bg]=Програми за системни настройки +Comment[bs]=Programi za podešavanje sistema +Comment[ca]=Preferències del sistema i programes de configuració +Comment[ca@valencia]=Preferències del sistema i programes de configuració +Comment[cs]=Systémové předvolby a nastavení programů +Comment[csb]=Nastôwë systemë ë ùstôwë programów +Comment[da]=Systemindstillinger og opsætningsprogrammer +Comment[de]=Systemeinstellungen und Einrichtungsprogramme +Comment[el]=Προτιμήσεις συστήματος και προγράμματα ρυθμίσεων +Comment[en_GB]=System preferences and setup programs +Comment[eo]=Sistem-preferencoj kaj agordaj programoj +Comment[es]=Preferencias del sistema y configuración de programas +Comment[et]=Süsteemi eelistused ja häälestamisprogrammid +Comment[eu]=Sistemaren hobespenak eta konfigurazio-programak +Comment[fi]=Järjestelmäoikeudet ja asetusohjelmat +Comment[fr]=Programmes de préférences et de configuration du système +Comment[fy]=Systeem foarkar en opset programma's +Comment[ga]=Sainroghanna an chórais agus cláir chumraíochta +Comment[gl]=Preferencias do sistema e programas de configuración +Comment[he]=העדפות מערכת והגדרות יישומים +Comment[hr]=Podešavanje sustava i programi za postavljanje +Comment[hu]=Rendszerbeállítások és beállítóprogramok +Comment[ia]=Preferentias de systema e programmas de disposition +Comment[id]=Pengaturan sistem dan pengaturan program +Comment[is]=Kerfisvalkostir og uppsetningaforrit +Comment[ja]=システム設定やセットアッププログラム +Comment[kk]=Жүйе параметрлер мен оларды баптау қолданбалар +Comment[km]=ចំណូល​ចិត្ត​​ប្រព័ន្ធ និង​រៀបចំ​កម្មវិធី +Comment[kn]=ವ್ಯವಸ್ಥೆಯ ಆದ್ಯತೆಗಳು ಹಾಗು ಸಿದ್ಧತಾ ಕ್ರಮವಿಧಿಗಳು +Comment[ko]=시스템 설정 및 관리 프로그램 +Comment[lt]=Sistemos nustatymų ir derinimo programos +Comment[lv]=Sistēmas iestaījumi un konfigurēšanas programmas +Comment[ml]=സിസ്റ്റത്തിലെ മുന്‍ഗണനകളും സജ്ജീകരണ പ്രോഗ്രാമുകളും +Comment[mr]=प्रणाली प्राधान्य व संयोजना कार्यक्रम +Comment[nb]=Systeminnstillinger og oppsettsprogrammer +Comment[nds]=Systeeminstell- un Inrichtprogrammen +Comment[nl]=Systeemvoorkeuren en instellingsprogramma's +Comment[nn]=Systeminnstillingar og oppsettprogram +Comment[pa]=ਸਿਸਟਮ ਪਸੰਦ ਅਤੇ ਸੈਟਅੱਪ ਪਰੋਗਰਾਮ +Comment[pl]=Ustawienia systemowe i programy konfigurujące +Comment[pt]=Preferências do sistema e programas de configuração +Comment[pt_BR]=Preferências do sistema e programas de configuração +Comment[ro]=Preferințe de sistem și programe de configurare +Comment[ru]=Системные параметры и установка программ +Comment[si]=පද්ධති අභිප්‍රේත හා ස්ථාපක වැඩසටහන් +Comment[sk]=Nastavenie systému a programov +Comment[sl]=Sistemske možnosti in nastavitveni programi +Comment[sr]=Програми за подешавање система +Comment[sr@ijekavian]=Програми за подешавање система +Comment[sr@ijekavianlatin]=Programi za podešavanje sistema +Comment[sr@latin]=Programi za podešavanje sistema +Comment[sv]=Systemanpassning och inställningsprogram +Comment[tg]=Хусусиятҳои система ва танзимоти барномаҳо +Comment[th]=การตั้งค่าต่าง ๆ ของระบบ และโปรแกรมตั้งค่าต่าง ๆ +Comment[tr]=Sistem tercihleri ve ayarlama uygulamaları +Comment[ug]=سىستېما مايىللىقى ۋە بەلگىلەش پروگراممىسى +Comment[uk]=Налаштування системи та програми для налаштування +Comment[wa]=Preferinces do sistinme eyet programes d' apontiaedje +Comment[x-test]=xxSystem preferences and setup programsxx +Comment[zh_CN]=系统首选项和系统设置程序 +Comment[zh_TW]=系統喜好與設定程式 +Icon=preferences-system + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-system + +X-Plasma-Sal-Url=kservicegroup://root/System/ +X-Plasma-Sal-Relevance=0.1 diff --git a/plasma/netbook/containments/sal/services/plasma-sal-utility.desktop b/plasma/netbook/containments/sal/services/plasma-sal-utility.desktop new file mode 100644 index 00000000..65125c44 --- /dev/null +++ b/plasma/netbook/containments/sal/services/plasma-sal-utility.desktop @@ -0,0 +1,165 @@ +[Desktop Entry] +Name=Utilities +Name[af]=Nutsprogramme +Name[ar]=خدمات +Name[as]=সৰঞ্জাম +Name[ast]=Utilidaes +Name[be]=Службовыя праграмы +Name[be@latin]=Pryładździe +Name[bg]=Инструменти +Name[bn]=আনুষঙ্গিক +Name[bn_IN]=বিবিধ সামগ্রী +Name[br]=Mavegoù +Name[bs]=Alatke +Name[ca]=Utilitats +Name[ca@valencia]=Utilitats +Name[cs]=Nástroje +Name[csb]=Nôrzãdza +Name[cy]=Defnyddioldebau +Name[da]=Værktøjer +Name[de]=Dienstprogramme +Name[el]=Εργαλεία +Name[en_GB]=Utilities +Name[eo]=Utilaĵoj +Name[es]=Utilidades +Name[et]=Tööriistad +Name[eu]=Utilitateak +Name[fa]=برنامه‌های سودمند +Name[fi]=Apuohjelmat +Name[fr]=Utilitaires +Name[fy]=Helpmiddelen +Name[ga]=Uirlisí +Name[gl]=Utensilios +Name[gu]=ઉપયોગી વસ્તુઓ +Name[he]=כלים +Name[hi]=यूटिलिटीज़ +Name[hne]=यूटिलिटीज +Name[hr]=Alati +Name[hsb]=Pomocniki +Name[hu]=Segédprogramok +Name[ia]=Utilitates +Name[id]=Utilitas +Name[is]=Nytjatól +Name[it]=Accessori +Name[ka]=ხელსაწყოები +Name[kk]=Утилиталары +Name[km]=ឧបករណ៍​ប្រើ​ប្រាស់ +Name[kn]=ಸೌಲಭ್ಯಗಳು +Name[ko]=유틸리티 +Name[ku]=Bernameyên Alîkar +Name[lt]=Pagalbininkai +Name[lv]=Utilītas +Name[mai]=उपयोगिता +Name[mk]=Алатки +Name[ml]=ഉപകരണങ്ങള്‍ +Name[mr]=उपकार्यक्रम +Name[ms]=Utiliti +Name[nb]=Verktøy +Name[nds]=Warktüüch +Name[ne]=युटिलिटी +Name[nl]=Hulpmiddelen +Name[nn]=Verktøy +Name[oc]=Utilitaris +Name[or]=ଉପଯୋଗିତା +Name[pa]=ਸਹੂਲਤ +Name[pl]=Narzędzia +Name[pt]=Utilitários +Name[pt_BR]=Utilitários +Name[ro]=Utilitare +Name[ru]=Служебные +Name[se]=Reaiddut +Name[si]=උපයෝග +Name[sk]=Nástroje +Name[sl]=Potrebščine +Name[sr]=Алатке +Name[sr@ijekavian]=Алатке +Name[sr@ijekavianlatin]=Alatke +Name[sr@latin]=Alatke +Name[sv]=Verktyg +Name[ta]=கருவிகள் +Name[te]=సౌలభ్యాలు +Name[tg]=Барномаҳои системавӣ +Name[th]=อรรถประโยชน์ +Name[tr]=Yardımcı Araçlar +Name[ug]=قوراللار +Name[uk]=Утиліти +Name[uz]=Vositalar +Name[uz@cyrillic]=Воситалар +Name[vi]=Tiện ích +Name[wa]=Usteyes +Name[xh]=Izinto eziluncedo +Name[x-test]=xxUtilitiesxx +Name[zh_CN]=工具 +Name[zh_TW]=實用工具 +Comment=Small utilities and accessories +Comment[ar]=أدوات خدمية وملحقات +Comment[ast]=Pequeñes utilidaes y accesorios +Comment[bg]=Разни инструменти +Comment[bs]=Manje priručne alatke +Comment[ca]=Petites utilitats i accessoris +Comment[ca@valencia]=Petites utilitats i accessoris +Comment[cs]=Malé nástroje a příslušenství +Comment[csb]=Môłé nôrzãdza ë pòmòcné aplikacëje +Comment[da]=Små værktøjer og tilbehør +Comment[de]=Kleine Werkzeuge und Zubehörprogramme +Comment[el]=Μικρές εφαρμογές και εξαρτήματα +Comment[en_GB]=Small utilities and accessories +Comment[es]=Pequeñas utilidades y accesorios +Comment[et]=Väikesed tööriistad ja abivahendid +Comment[eu]=Utilitate txikiak eta gehigarriak +Comment[fi]=Pienet apuohjelmat ja oheislaitteet +Comment[fr]=Petits utilitaires et accessoires +Comment[fy]=Stikmannich lyts ark +Comment[ga]=Uirlisí beaga agus oiriúintí +Comment[gl]=Pequenas utilidades e accesorios +Comment[he]=כלים ועזרים קטנים +Comment[hr]=Mali uslužni programi i pomagala +Comment[hu]=Kis segédprogramok és kellékek +Comment[ia]=Parve utilitates e accessorios +Comment[id]=Utilitas dan aksesoris kecil +Comment[is]=Lítil nytjatól og aukahlutir +Comment[ja]=小さなユーティリティとアクセサリ +Comment[kk]=Шағын утилиталар мен әбзелдері +Comment[km]=ឧបករណ៍​ប្រើប្រាស់​តូច និង​គ្រឿង​របស់​វា +Comment[kn]=ಸಣ್ಣ ಸವಲತ್ತುಗಳು ಮತ್ತು ಸಲಕರಣೆಗಳು +Comment[ko]=작은 유틸리티와 액세서리 +Comment[lt]=Nedideli pagalbininkai +Comment[lv]=Mazas utilītas un aksesuāri +Comment[mk]=Мали алатки и додатоци +Comment[ml]=ചെറിയ ഉപകരണങ്ങള്‍ +Comment[mr]=लहान उपकार्यक्रम व साधने +Comment[nb]=Små verktøy- og tilbehørsprogrammer +Comment[nds]=Lütte Warktüüch un Hülpprogrammen +Comment[nl]=Kleine programma's en accessoires +Comment[nn]=Små verktøy og nytteprogram +Comment[pa]=ਛੋਟੀਆਂ ਸਹੂਲਤਾਂ ਅਤੇ ਸਹਾਇਕ +Comment[pl]=Niewielkie narzędzia i akcesoria +Comment[pt]=Pequenos utilitários e acessórios +Comment[pt_BR]=Pequenos utilitários e acessórios +Comment[ro]=Mici accesorii și utilitare +Comment[ru]=Небольшие программы и инструменты +Comment[si]=කුඩා උපයෝග සහ උපාංග +Comment[sk]=Nástroje a príslušenstvo +Comment[sl]=Majhna orodja in pripomočki +Comment[sr]=Мање приручне алатке +Comment[sr@ijekavian]=Мање приручне алатке +Comment[sr@ijekavianlatin]=Manje priručne alatke +Comment[sr@latin]=Manje priručne alatke +Comment[sv]=Mindre verktyg och tillbehör +Comment[tg]=Барномаҳо ва афзорҳои хурд +Comment[th]=เครื่องมืออรรถประโยชน์และโปรแกรมเพิ่มเติมต่าง ๆ ที่มีขนาดเล็ก +Comment[tr]=Küçük ve faydalı uygulamalar +Comment[ug]=كىچىك قوراللار ۋە قوشۇمچە قوراللار +Comment[uk]=Малі програми та інструменти +Comment[wa]=Pititès usteyes +Comment[x-test]=xxSmall utilities and accessoriesxx +Comment[zh_CN]=小型附件和辅助工具 +Comment[zh_TW]=小型實用工具與輔助程式 +Icon=applications-utilities + +Type=Service +X-KDE-ServiceTypes=Plasma/Sal/Menu +X-KDE-PluginInfo-Name=plasma-sal-utility + +X-Plasma-Sal-Url=kservicegroup://root/Utilities/ +X-Plasma-Sal-Relevance=0.2 diff --git a/plasma/netbook/containments/sal/stripwidget.cpp b/plasma/netbook/containments/sal/stripwidget.cpp new file mode 100644 index 00000000..cded4bcf --- /dev/null +++ b/plasma/netbook/containments/sal/stripwidget.cpp @@ -0,0 +1,292 @@ +/* + * Copyright 2009 by Artur Duque de Souza + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "stripwidget.h" +#include "models/favouritesmodel.h" +#include "models/krunnermodel.h" +#include "models/kservicemodel.h" +#include "models/commonmodel.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "itemview.h" +#include "iconactioncollection.h" + +StripWidget::StripWidget(QGraphicsWidget *parent) + : QGraphicsWidget(parent), + m_itemView(0), + m_deleteTarget(0), + m_iconActionCollection(0), + m_offset(0), + m_startupCompleted(false) +{ + m_favouritesModel = new FavouritesModel(this); + + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + setAcceptDrops(true); + + Plasma::Applet *applet = qobject_cast(parent); + if (applet) { + m_iconActionCollection = new IconActionCollection(applet, this); + } + + m_arrowsLayout = new QGraphicsLinearLayout(this); + m_arrowsLayout->setContentsMargins(0, 0, 0, 0); + setFocusPolicy(Qt::StrongFocus); + + m_leftArrow = new Plasma::ToolButton(this); + m_leftArrow->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + m_leftArrow->setPreferredWidth(KIconLoader::SizeMedium); + m_leftArrow->setImage("widgets/arrows", "left-arrow"); + connect(m_leftArrow, SIGNAL(clicked()), this, SLOT(goLeft())); + connect(m_leftArrow, SIGNAL(pressed()), this, SLOT(scrollTimeout())); + + m_rightArrow = new Plasma::ToolButton(this); + m_rightArrow->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + m_rightArrow->setPreferredWidth(KIconLoader::SizeMedium); + m_rightArrow->setImage("widgets/arrows", "right-arrow"); + connect(m_rightArrow, SIGNAL(clicked()), this, SLOT(goRight())); + connect(m_rightArrow, SIGNAL(pressed()), this, SLOT(scrollTimeout())); + + m_leftArrow->setEnabled(false); + m_rightArrow->setEnabled(false); + m_leftArrow->hide(); + m_rightArrow->hide(); + + m_itemView = new ItemView(this); + m_itemView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_itemView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_itemView->installEventFilter(this); + m_itemView->setOrientation(Qt::Horizontal); + m_itemView->setIconSize(KIconLoader::SizeLarge); + m_itemView->setDragAndDropMode(ItemContainer::MoveDragAndDrop); + m_itemView->setModel(m_favouritesModel); + + connect(m_itemView, SIGNAL(itemActivated(QModelIndex)), this, SLOT(launchFavourite(QModelIndex))); + connect(m_itemView, SIGNAL(scrollBarsNeededChanged(ItemView::ScrollBarFlags)), this, SLOT(arrowsNeededChanged(ItemView::ScrollBarFlags))); + connect(m_itemView, SIGNAL(itemAskedReorder(QModelIndex,QPointF)), this, SLOT(reorderItem(QModelIndex,QPointF))); + connect(m_itemView, SIGNAL(dragStartRequested(QModelIndex)), this, SLOT(showDeleteTarget())); + + m_arrowsLayout->addItem(m_leftArrow); + m_arrowsLayout->addItem(m_itemView); + m_arrowsLayout->addItem(m_rightArrow); + + m_scrollTimer = new QTimer(this); + m_scrollTimer->setSingleShot(false); + connect(m_scrollTimer, SIGNAL(timeout()), this, SLOT(scrollTimeout())); +} + +StripWidget::~StripWidget() +{ +} + +void StripWidget::showDeleteTarget() +{ + if (!m_deleteTarget) { + m_deleteTarget = new Plasma::IconWidget(); + scene()->addItem(m_deleteTarget); + m_deleteTarget->setIcon("user-trash"); + m_deleteTarget->resize(KIconLoader::SizeHuge, KIconLoader::SizeHuge); + m_deleteTarget->setZValue(99); + } + m_deleteTarget->setPos(mapToScene(boundingRect().bottomLeft())); + m_deleteTarget->show(); + Plasma::Animation *zoomAnim = Plasma::Animator::create(Plasma::Animator::ZoomAnimation); + zoomAnim->setTargetWidget(m_deleteTarget); + zoomAnim->setProperty("zoom", 1.0); + zoomAnim->start(QAbstractAnimation::DeleteWhenStopped); +} + +void StripWidget::setImmutability(Plasma::ImmutabilityType immutability) +{ + if (immutability == Plasma::Mutable) { + m_itemView->setDragAndDropMode(ItemContainer::MoveDragAndDrop); + } else { + m_itemView->setDragAndDropMode(ItemContainer::NoDragAndDrop); + } +} + + +void StripWidget::reorderItem(const QModelIndex &index, const QPointF &pos) +{ + if (m_deleteTarget && m_deleteTarget->geometry().contains(m_itemView->widget()->mapToItem(this, pos))) { + m_favouritesModel->removeRow(index.row()); + } else { + QListitems = m_favouritesModel->takeRow(index.row()); + int row = m_itemView->rowForPosition(pos); + + m_favouritesModel->insertRow(row, items); + } + + Plasma::Animation *zoomAnim = Plasma::Animator::create(Plasma::Animator::ZoomAnimation); + zoomAnim->setTargetWidget(m_deleteTarget); + zoomAnim->start(QAbstractAnimation::DeleteWhenStopped); +} + +void StripWidget::save(KConfigGroup &cg) +{ + m_favouritesModel->save(cg); +} + +void StripWidget::restore(KConfigGroup &cg) +{ + m_favouritesModel->restore(cg); +} + +void StripWidget::launchFavourite(const QModelIndex &index) +{ + KUrl url(index.data(CommonModel::Url).value()); + if (!KServiceItemHandler::openUrl(url)) { + KRunnerItemHandler::openUrl(url); + } +} + +void StripWidget::add(const QUrl &url) +{ + m_favouritesModel->add(url); + emit saveNeeded(); +} + +void StripWidget::goRight() +{ + QRectF rect(m_itemView->boundingRect()); + rect.moveLeft(rect.right() - m_itemView->widget()->pos().x()); + rect.setWidth(rect.width()/4); + + m_itemView->ensureRectVisible(rect); +} + +void StripWidget::goLeft() +{ + QRectF rect(m_itemView->boundingRect()); + rect.setWidth(rect.width()/4); + rect.moveRight(- m_itemView->widget()->pos().x()); + + m_itemView->ensureRectVisible(rect); +} + +void StripWidget::scrollTimeout() +{ + if (!m_scrollTimer->isActive()) { + m_scrollTimer->start(250); + } else if (m_leftArrow->isDown()) { + goLeft(); + } else if (m_rightArrow->isDown()) { + goRight(); + } else { + m_scrollTimer->stop(); + } +} + +void StripWidget::setIconSize(int iconSize) +{ + m_itemView->setIconSize(iconSize); +} + +int StripWidget::iconSize() const +{ + return m_itemView->iconSize(); +} + +void StripWidget::arrowsNeededChanged(ItemView::ScrollBarFlags flags) +{ + bool leftNeeded = false; + bool rightNeeded = false; + + if (flags & ItemView::HorizontalScrollBar) { + leftNeeded = m_itemView->scrollPosition().x() > 0; + rightNeeded = m_itemView->contentsSize().width() - m_itemView->scrollPosition().x() > m_itemView->size().width(); + } + + m_leftArrow->setEnabled(leftNeeded); + m_rightArrow->setEnabled(rightNeeded); + m_leftArrow->setVisible(leftNeeded|rightNeeded); + m_rightArrow->setVisible(leftNeeded|rightNeeded); + m_arrowsLayout->invalidate(); +} + + + +void StripWidget::focusInEvent(QFocusEvent *event) +{ + Q_UNUSED(event) + + m_itemView->setFocus(); +} + +void StripWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event) +{ + event->setAccepted(event->mimeData()->hasFormat("application/x-plasma-salquerymatch") || event->mimeData()->hasFormat("text/uri-list")); +} + +void StripWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event) +{ + m_itemView->setScrollPositionFromDragPosition(event->pos()); + m_itemView->showSpacer(m_itemView->widget()->mapFromScene(event->scenePos())); +} + +void StripWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) +{ + Q_UNUSED(event) + + m_itemView->showSpacer(QPointF()); +} + +void StripWidget::dropEvent(QGraphicsSceneDragDropEvent *event) +{ + m_itemView->showSpacer(QPointF()); + if (event->mimeData()->hasFormat("application/x-plasma-salquerymatch")) { + QByteArray itemData = event->mimeData()->data("application/x-plasma-salquerymatch"); + QDataStream dataStream(&itemData, QIODevice::ReadOnly); + + QUrl url; + + dataStream >>url; + + int row = m_itemView->rowForPosition(m_itemView->widget()->mapFromScene(event->scenePos())); + QModelIndex index = m_favouritesModel->index(row, 0, QModelIndex()); + //TODO: proper index + m_favouritesModel->add(url.toString(), index); + emit saveNeeded(); + + } else if (event->mimeData()->urls().size() > 0) { + int row = m_itemView->rowForPosition(m_itemView->widget()->mapFromScene(event->scenePos())); + QModelIndex index = m_favouritesModel->index(row, 0, QModelIndex()); + m_favouritesModel->add(event->mimeData()->urls().first().path(), index); + emit saveNeeded(); + } else { + event->ignore(); + } +} diff --git a/plasma/netbook/containments/sal/stripwidget.h b/plasma/netbook/containments/sal/stripwidget.h new file mode 100644 index 00000000..208e74d4 --- /dev/null +++ b/plasma/netbook/containments/sal/stripwidget.h @@ -0,0 +1,102 @@ +/* + * Copyright 2009 by Artur Duque de Souza + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef STRIPWIDGET_H +#define STRIPWIDGET_H + + +#include +#include + +#include +#include +#include + + +#include + +#include "itemview.h" + +namespace Plasma +{ + class IconWidget; + class ToolButton; +} + +class QTimer; +class IconActionCollection; + +class FavouritesModel; + +class StripWidget : public QGraphicsWidget +{ + Q_OBJECT + +public: + StripWidget(QGraphicsWidget *parent = 0); + ~StripWidget(); + + void save(KConfigGroup &cg); + void restore(KConfigGroup &cg); + + void setIconSize(int iconSize); + int iconSize() const; + + //TODO: geter and setter? + void setImmutability(Plasma::ImmutabilityType immutability); + void add(const QUrl &url); + +protected: + Plasma::IconWidget *createIcon(const QPointF &point); + void focusInEvent(QFocusEvent *event); + void dragEnterEvent(QGraphicsSceneDragDropEvent *event); + void dragMoveEvent(QGraphicsSceneDragDropEvent *event); + void dragLeaveEvent(QGraphicsSceneDragDropEvent *event); + void dropEvent(QGraphicsSceneDragDropEvent *event); + +private Q_SLOTS: + void launchFavourite(const QModelIndex &index); + void arrowsNeededChanged(ItemView::ScrollBarFlags flags); + void goLeft(); + void goRight(); + void scrollTimeout(); + void reorderItem(const QModelIndex &index, const QPointF &point); + void showDeleteTarget(); + +Q_SIGNALS: + void saveNeeded(); + +private: + Plasma::ToolButton *m_leftArrow; + Plasma::ToolButton *m_rightArrow; + QGraphicsLinearLayout *m_arrowsLayout; + + QHash m_services; + ItemView *m_itemView; + Plasma::RunnerContext *m_context; + QTimer *m_scrollTimer; + Plasma::IconWidget *m_deleteTarget; + IconActionCollection *m_iconActionCollection; + int m_shownIcons; + int m_offset; + bool m_startupCompleted; + FavouritesModel *m_favouritesModel; +}; + +#endif diff --git a/plasma/netbook/dataengines/CMakeLists.txt b/plasma/netbook/dataengines/CMakeLists.txt new file mode 100644 index 00000000..e6a67825 --- /dev/null +++ b/plasma/netbook/dataengines/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(searchlaunch) diff --git a/plasma/netbook/dataengines/searchlaunch/CMakeLists.txt b/plasma/netbook/dataengines/searchlaunch/CMakeLists.txt new file mode 100644 index 00000000..a4ecc661 --- /dev/null +++ b/plasma/netbook/dataengines/searchlaunch/CMakeLists.txt @@ -0,0 +1,19 @@ +project(searchlaunchengine) + +set(searchlaunch_engine_SRCS + salengine.cpp + salservice.cpp) + +kde4_add_plugin(plasma_engine_searchlaunch ${searchlaunch_engine_SRCS}) +target_link_libraries(plasma_engine_searchlaunch + ${KDE4_KDECORE_LIBS} + ${KDE4_PLASMA_LIBS}) + +install(TARGETS plasma_engine_searchlaunch + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-engine-searchlaunch.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) + +install(FILES searchlaunch.operations + DESTINATION ${DATA_INSTALL_DIR}/plasma/services) diff --git a/plasma/netbook/dataengines/searchlaunch/plasma-engine-searchlaunch.desktop b/plasma/netbook/dataengines/searchlaunch/plasma-engine-searchlaunch.desktop new file mode 100644 index 00000000..d952ce6e --- /dev/null +++ b/plasma/netbook/dataengines/searchlaunch/plasma-engine-searchlaunch.desktop @@ -0,0 +1,140 @@ +[Desktop Entry] +Name=Search and Launch Engine +Name[ar]=محرك البحث والإطلاق +Name[ast]=Motor de gueta y llanzamientu +Name[bs]=motor pretrage i pokretanja +Name[ca]=Motor de cerca i llançament +Name[ca@valencia]=Motor de cerca i llançament +Name[cs]=Vyhledávací a spouštěcí stroj +Name[csb]=Mòtórë szëkbë ë zrëszaniô +Name[da]=Motor til søg og opstart +Name[de]=Treiber für „Suchen und ausführen“ +Name[el]=Μηχανή αναζήτησης και εκτέλεσης +Name[en_GB]=Search and Launch Engine +Name[eo]=Serĉi kaj lanĉi motoron +Name[es]=Motor de búsqueda y lanzamiento +Name[et]=Otsimise ja käivitamise mootor +Name[eu]=Bilaketetarako eta abioetarako motorra +Name[fi]=Haku- ja käynnistyskone +Name[fr]=Moteur de recherche et de lancement +Name[fy]=Syk en útfier motor +Name[ga]=Inneall Cuardaigh/Tosaithe +Name[gl]=Motor de busca e inicio +Name[gu]=શોધ અને શરુકરનાર એન્જિન +Name[he]=מנוע חיפוש והפעלה +Name[hi]=खोज और लाँच इंजन +Name[hr]=Mehanizam za pretragu i pokretanje +Name[hu]=Keresés és indítás modul +Name[ia]=Motor per cercar e lancear +Name[id]=Mesin Pencari dan Peluncur +Name[is]=Leitar- og ræsingarvél +Name[ja]=検索起動エンジン +Name[kk]=Іздеу және жегу тетіктер +Name[km]=ស្វែងរក ហើយ​ចាប់ផ្ដើម​ម៉ាស៊ីន +Name[kn]=ಹುಡುಕು ಹಾಗು ಪ್ರಕ್ಷೇಪನ ಯಂತ್ರ +Name[ko]=찾아서 실행하기 엔진 +Name[lt]=Paieškos ir paleidimo variklis +Name[lv]=Meklēšanas un plaišanas dzinējs +Name[mk]=Машина за пребарување и стартување +Name[ml]=തെരയാനും തുടങ്ങാനുമുള്ള എഞ്ചിന്‍ +Name[mr]=शोधा व प्रक्षेपण करा इंजिन +Name[nb]=Søk og start-motor +Name[nds]=Söök- un Oproopkarn +Name[nl]=Zoek- en start-engine +Name[nn]=Motor for søk og køyr +Name[pa]=ਖੋਜ ਅਤੇ ਚਲਾਉਣ ਇੰਜਣ +Name[pl]=Silnik wyszukiwania i uruchamiania +Name[pt]=Motor de Busca e Lançamento +Name[pt_BR]=Mecanismo de pesquisa e execução +Name[ro]=Motor de căutare și lansare +Name[ru]=Источник данных для страницы «Поиск и запуск» +Name[si]=සොයා ක්‍රියාකරවන එන්ජිම +Name[sk]=Nástroj pre Hľadať a spustiť +Name[sl]=Pogon za iskanje in zaganjanje +Name[sr]=мотор претраге и покретања +Name[sr@ijekavian]=мотор претраге и покретања +Name[sr@ijekavianlatin]=motor pretrage i pokretanja +Name[sr@latin]=motor pretrage i pokretanja +Name[sv]=Sök- och startprogram +Name[tg]=Барномаи ҷустуҷӯ +Name[th]=กลไลการค้นหาและเรียกใช้งาน +Name[tr]=Ara ve Çalıştır Motoru +Name[ug]=ئىزدە ۋە ئىجرا قىلىش ماتورى +Name[uk]=Рушій пошуку і запуску +Name[wa]=Moteur di cweraedje et d' enondaedje +Name[x-test]=xxSearch and Launch Enginexx +Name[zh_CN]=搜索与启动引擎 +Name[zh_TW]=搜索與啟動引擎 +Comment=Engine to handle queries to SAL containment +Comment[ar]=محرك لمعاملة الاستعلامات إلى حاوية البحث والإطلاق +Comment[ast]=Motor pa remanar consultes a un contenedor SAL +Comment[bs]=Datomotor za obradu upita za sadržalac pretrage i pokretanja +Comment[ca]=Motor per gestionar consultes al contenidor SAL +Comment[ca@valencia]=Motor per gestionar consultes al contenidor SAL +Comment[cs]=Stroj pro řízení dotazů SAL kontejneru +Comment[da]=Motor til at håndtere forespørgsler til SAL-beholderen +Comment[de]=Treiber zur Behandlung von Anfragen an den Container „Suchen und Ausführen“ +Comment[el]=Μηχανή ελέγχου ερωτημάτων για τον υποδοχέα SAL +Comment[en_GB]=Engine to handle queries to SAL containment +Comment[es]=Motor para manejar consultas a un contenedor SAL +Comment[et]=SAL konteineri päringuid käitlev mootor +Comment[eu]=Kontsultak SAL edukiontzira kudeatzeko motorra +Comment[fi]=Kone käsittelemään SAL-sovelmasäiliön kyselyjä +Comment[fr]=Moteur manipulant les requêtes vers le conteneur SAL +Comment[fy]=Motor om defragen nei SAL kontainer ôf te hanneljen +Comment[gl]=Un motor para manipular consultas ao contedor SAL +Comment[he]=מנוע לניהול שאילתות לתיבת החיפוש וההפעלה +Comment[hr]=Mehanizam za rad s upitima SAL okruženju +Comment[hu]=Modul lekérdezések kezelésére a SAL tartóelemtől +Comment[ia]=Motor pro manear interrogationes al contento SAL +Comment[id]=Mesin untuk menangani lema ke pembatasan SAL +Comment[is]=Kerfi sem meðhöndlar fyrirspurnir til SAL geymslugrunns +Comment[ja]=SAL コンテンツのクエリを処理するエンジン +Comment[kk]=SAL контейнеріне қойылған сұраныстарына жауап беретін тетік +Comment[km]=ម៉ាស៊ីន​ត្រូវ​គ្រប់គ្រង​សំណួរ​ការ​ផ្ទុក SAL +Comment[ko]=SAL 포함 플러그인의 쿼리 처리를 위한 엔진 +Comment[lt]=Variklis, skirtas tvarkyti užklausas į SAL konteinerį +Comment[lv]=Dzinējs, kas apstrādā pieprasījumus uz SAL ietvērumu +Comment[ml]=എസ്എഎല്‍ കണ്ടൈന്‍മെന്റിനുള്ള ക്വറികള്‍ കൈകാര്യം ചെയ്യുന്നതിനുള്ള എഞ്ചിന്‍ +Comment[mr]=SAL कंटेनमेंटचे प्रश्न हाताळणारे इंजिन +Comment[nb]=Motor som håndterer forespørsler til SoS-beholder +Comment[nds]=Karn för Anfragen na't SuO-Gelaats +Comment[nl]=Engine voor het afhandelen van zoekopdrachten naar de SAL-houder +Comment[nn]=Motor for å handtera spørjinga til SAL-behaldaren +Comment[pa]=SAL ਕਨਟੇਨਮੈਂਟ ਲਈ ਕਿਊਰੀ ਹੈਂਡਲ ਕਰਨ ਵਾਸਤੇ ਇੰਜਣ +Comment[pl]=Silnik do obsługi zapytań do kontenera SAL +Comment[pt]=Motor para lidar com as pesquisas ao contentor ASL +Comment[pt_BR]=Mecanismo para lidar com pesquisas ao contêiner ASL +Comment[ro]=Motor pentru tratarea cererilor către un container SAL +Comment[ru]=Обработка запросов к контейнеру «Поиск и запуск» +Comment[si]=SAL ධාරක විමසීම් හැසිරවිම සඳහා එන්ජිම +Comment[sk]=Nástroj na spracovanie dotazov pre Hľadať a spustiť +Comment[sl]=Pogon za ravnanje s poizvedbami za vsebnik SAL +Comment[sr]=Датомотор за обраду упита за садржалац претраге и покретања +Comment[sr@ijekavian]=Датомотор за обраду упита за садржалац претраге и покретања +Comment[sr@ijekavianlatin]=Datomotor za obradu upita za sadržalac pretrage i pokretanja +Comment[sr@latin]=Datomotor za obradu upita za sadržalac pretrage i pokretanja +Comment[sv]=Program för att hantera förfrågningar till SAL-omgivning +Comment[th]=กลไกที่จะจัดการการสืบค้นไปยังส่วนบรรจุ SAL +Comment[tr]=SAL içericisine gelen sorgular için bir motor +Comment[ug]=SAL قاچا سۈرۈشتۈرىدىغان ماتورنى بىر تەرەپ قىلىدۇ +Comment[uk]=Рушій для обробки запитів до контейнера SAL +Comment[vi]=Cơ chế xử lý truy vấn tới SAL +Comment[wa]=Moteur pos apougnî les rcweraedje e contenmint SAL +Comment[x-test]=xxEngine to handle queries to SAL containmentxx +Comment[zh_CN]=处理 SAL 容器查询的引擎 +Comment[zh_TW]=處理 SAL 容器查詢的引擎 +Type=Service + +X-KDE-ServiceTypes=Plasma/DataEngine +X-KDE-Library=plasma_engine_searchlaunch +X-Plasma-EngineName=searchlaunch +X-KDE-PluginInfo-Author=Artur Souza +X-KDE-PluginInfo-Email=morpheuz@gmail.com +X-KDE-PluginInfo-Name=searchlaunch +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/dataengines/searchlaunch/salengine.cpp b/plasma/netbook/dataengines/searchlaunch/salengine.cpp new file mode 100644 index 00000000..a8df7c60 --- /dev/null +++ b/plasma/netbook/dataengines/searchlaunch/salengine.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2009 Artur Duque de Souza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "salengine.h" +#include "salservice.h" + + +SearchLaunchEngine::SearchLaunchEngine(QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args) +{ + Q_UNUSED(args); +} + +void SearchLaunchEngine::init() +{ + setData("query", QString()); +} + +Plasma::Service *SearchLaunchEngine::serviceForSource(const QString &source) +{ + if (source != "query") { + return 0; + } + + SearchLaunchService *service = new SearchLaunchService(this); + service->setParent(this); + return service; +} + +K_EXPORT_PLASMA_DATAENGINE(searchlaunch, SearchLaunchEngine) + +#include "salengine.moc" diff --git a/plasma/netbook/dataengines/searchlaunch/salengine.h b/plasma/netbook/dataengines/searchlaunch/salengine.h new file mode 100644 index 00000000..ee4c6695 --- /dev/null +++ b/plasma/netbook/dataengines/searchlaunch/salengine.h @@ -0,0 +1,40 @@ +/* + * Copyright 2009 Artur Duque de Souza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SEARCHLAUNCH_ENGINE_H +#define SEARCHLAUNCH_ENGINE_H + +#include +#include + +class SearchLaunchService; + +class SearchLaunchEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + SearchLaunchEngine(QObject* parent, const QVariantList& args); + Plasma::Service *serviceForSource(const QString &source); + void init(); + + friend class SearchLaunchService; +}; + +#endif // SEARCHLAUNCH_ENGINE_H diff --git a/plasma/netbook/dataengines/searchlaunch/salservice.cpp b/plasma/netbook/dataengines/searchlaunch/salservice.cpp new file mode 100644 index 00000000..ffeb4b35 --- /dev/null +++ b/plasma/netbook/dataengines/searchlaunch/salservice.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2009 Artur Duque de Souza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "salservice.h" + + +SearchLaunchService::SearchLaunchService(SearchLaunchEngine *engine) +{ + m_engine = engine; + setName("searchlaunch"); +} + +ServiceJob *SearchLaunchService::createJob(const QString &operation, + QMap ¶meters) +{ + if (!m_engine) { + return 0; + } + + m_engine->setData(operation, parameters["query"]); + return 0; +} + +#include "salservice.moc" diff --git a/plasma/netbook/dataengines/searchlaunch/salservice.h b/plasma/netbook/dataengines/searchlaunch/salservice.h new file mode 100644 index 00000000..bbce8e78 --- /dev/null +++ b/plasma/netbook/dataengines/searchlaunch/salservice.h @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Artur Duque de Souza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SEARCHLAUNCH_SERVICE_H +#define SEARCHLAUNCH_SERVICE_H + +#include "salengine.h" + +#include +#include + +using namespace Plasma; + + +class SearchLaunchService : public Plasma::Service +{ + Q_OBJECT + +public: + SearchLaunchService(SearchLaunchEngine *engine); + ServiceJob *createJob(const QString &operation, + QMap ¶meters); + +private: + SearchLaunchEngine *m_engine; +}; + +#endif // SEARCHLAUNCH_SERVICE_H diff --git a/plasma/netbook/dataengines/searchlaunch/searchlaunch.operations b/plasma/netbook/dataengines/searchlaunch/searchlaunch.operations new file mode 100644 index 00000000..d71d182f --- /dev/null +++ b/plasma/netbook/dataengines/searchlaunch/searchlaunch.operations @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/plasma/netbook/desktoptheme/CMakeLists.txt b/plasma/netbook/desktoptheme/CMakeLists.txt new file mode 100644 index 00000000..1b5ccec0 --- /dev/null +++ b/plasma/netbook/desktoptheme/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory(air-netbook) diff --git a/plasma/netbook/desktoptheme/air-netbook/CMakeLists.txt b/plasma/netbook/desktoptheme/air-netbook/CMakeLists.txt new file mode 100644 index 00000000..a4216bbe --- /dev/null +++ b/plasma/netbook/desktoptheme/air-netbook/CMakeLists.txt @@ -0,0 +1,6 @@ + +install(FILES colors metadata.desktop DESTINATION ${DATA_INSTALL_DIR}/desktoptheme/air-netbook/) + +FILE(GLOB widgets widgets/*.svgz) +install( FILES ${widgets} DESTINATION ${DATA_INSTALL_DIR}/desktoptheme/air-netbook/widgets/ ) + diff --git a/plasma/netbook/desktoptheme/air-netbook/colors b/plasma/netbook/desktoptheme/air-netbook/colors new file mode 100644 index 00000000..faba1450 --- /dev/null +++ b/plasma/netbook/desktoptheme/air-netbook/colors @@ -0,0 +1,82 @@ +[Colors:Button] +BackgroundAlternate=218,221,215 +BackgroundNormal=218,221,215 +DecorationFocus=239,132,65 +DecorationHover=72,177,60 +ForegroundActive=255,0,0 +ForegroundInactive=152,154,149 +ForegroundLink=0,0,255 +ForegroundNegative=107,0,0 +ForegroundNeutral=0,90,95 +ForegroundNormal=0,0,0 +ForegroundPositive=0,95,0 +ForegroundVisited=88,55,150 + +[Colors:Selection] +BackgroundAlternate=62,138,204 +BackgroundNormal=65,139,212 +DecorationFocus=43,116,199 +DecorationHover=119,183,255 +ForegroundActive=255,128,224 +ForegroundInactive=165,193,228 +ForegroundLink=0,49,110 +ForegroundNegative=156,14,14 +ForegroundNeutral=255,221,0 +ForegroundNormal=255,255,255 +ForegroundPositive=128,255,128 +ForegroundVisited=69,40,134 + + +[Colors:Tooltip] +BackgroundAlternate=255,248,209 +BackgroundNormal=255,255,255 +DecorationFocus=239,132,65 +DecorationHover=72,177,60 +ForegroundActive=255,0,0 +ForegroundInactive=232,185,149 +ForegroundLink=0,0,255 +ForegroundNegative=107,0,0 +ForegroundNeutral=0,90,95 +ForegroundNormal=0,0,0 +ForegroundPositive=0,95,0 +ForegroundVisited=88,55,150 + +[Colors:View] +BackgroundAlternate=248,247,246 +BackgroundNormal=255,255,255 +DecorationFocus=43,116,199 +DecorationHover=119,183,255 +ForegroundActive=255,128,224 +ForegroundInactive=36,35,34 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=20,19,18 +ForegroundPositive=0,110,40 +ForegroundVisited=100,74,155 + +[Colors:Window] +BackgroundAlternate=218,217,216 +BackgroundNormal=255,255,255 +DecorationFocus=43,116,199 +DecorationHover=119,183,255 +ForegroundActive=10,128,224 +ForegroundInactive=36,35,34 +ForegroundLink=0,87,174 +ForegroundNegative=191,3,3 +ForegroundNeutral=176,128,0 +ForegroundNormal=20,19,18 +ForegroundPositive=0,110,40 +ForegroundVisited=100,74,155 + +[General] +shadeSortColumn=true + +[KDE] +contrast=7 + +[WM] +activeBackground=65,142,220 +activeForeground=255,255,255 +inactiveBackground=157,170,186 +inactiveForeground=65,142,220 diff --git a/plasma/netbook/desktoptheme/air-netbook/metadata.desktop b/plasma/netbook/desktoptheme/air-netbook/metadata.desktop new file mode 100644 index 00000000..03cfc192 --- /dev/null +++ b/plasma/netbook/desktoptheme/air-netbook/metadata.desktop @@ -0,0 +1,148 @@ +[Desktop Entry] +Name=Air for netbooks +Name[ar]=الهواء للحاسبات المحمولة الشبكيّة +Name[ast]=Air pa netbooks +Name[bg]=Тема "Въздух" за нетбук +Name[bn]=নেটবুক-এর জন্য এয়ার +Name[bs]=Vazduh za netbuke +Name[ca]=Air per a ordinadors ultraportàtils +Name[ca@valencia]=Air per a ordinadors ultraportàtils +Name[cs]=Air pro netbooky +Name[da]=Air til netbooks +Name[de]=Air für Netbooks +Name[el]=Αέρας για τα netbooks +Name[en_GB]=Air for netbooks +Name[eo]=Air por netbook-oj +Name[es]=Air para netbooks +Name[et]=Air väikesülearvutitele +Name[eu]=Netbooketarako "Air" +Name[fi]=Air miniläppäreille +Name[fr]=« Air » pour les ultra portables +Name[fy]=Air foar netbooks +Name[gl]=Air para ultraportátiles +Name[he]=‏Air לנטבוקים +Name[hr]=Zrak za netbooke +Name[hu]=Air téma netbookokra +Name[ia]=Air pro netbooks +Name[id]=Air untuk komputer mini +Name[is]=Air fyrir smáfartölvur +Name[ja]=ネットブック用の Air +Name[kk]=Нетбукке арналған Air +Name[km]=ខ្យល់​សម្រាប់ netbooks +Name[kn]=ನೆಟ್‌ಬುಕ್‌ಗಳಿಗಾಗಿನ ಏರ್ +Name[ko]=넷북을 위한 Air +Name[lt]=Oras netbukams +Name[lv]=Air mazdatoriem +Name[ml]=നെറ്റ്ബൂക്കിനുവേണ്ടിയുള്ള എയര്‍ +Name[mr]=नेटबूक करिता एअर +Name[nb]=Air for netbook-maskiner +Name[nds]=Luft för Nettböker +Name[nl]=Air voor netbooks +Name[nn]=Luft for mini-PC-ar +Name[pa]=ਨੈੱਟਬੁੱਕ ਲਈ ਏਅਰ +Name[pl]=Air dla netbooków +Name[pt]=Air para Netbooks +Name[pt_BR]=Ar para Netbooks +Name[ro]=Aer pentru netbook +Name[ru]=Air для нетбуков +Name[si]=නෙට්බුක් සඳහා Air +Name[sk]=Vzduch pre netbooky +Name[sl]=Zrak za male prenosnike +Name[sr]=Ваздух за нетбуке +Name[sr@ijekavian]=Ваздух за нетбуке +Name[sr@ijekavianlatin]=Vazduh za netbuke +Name[sr@latin]=Vazduh za netbuke +Name[sv]=Luft för bärbara nätdatorer +Name[tg]=Ҳаво барои нетбукҳо +Name[th]=รูปแบบ Air สำหรับเครื่องเน็ตบุ๊ก +Name[tr]=Netbooklar için Air +Name[ug]=تور كومپيۇتېر ھاۋا ئۆرنىكى +Name[uk]=«Air» для субноутбука +Name[vi]=Air cho netbook +Name[wa]=Air po les poirtåvès éndjoletes +Name[x-test]=xxAir for netbooksxx +Name[zh_CN]=上网本大气主题 +Name[zh_TW]=Netbooks 上的 Air +Comment=A breath of fresh air +Comment[ar]=نسمة من الهواء النقي +Comment[ast]=Un soplu d'aire frescu +Comment[bg]=Глътка свеж въздух +Comment[bs]=Dašak svježeg vazduha +Comment[ca]=Una alenada d'aire fresc +Comment[ca@valencia]=Una alenada d'aire fresc +Comment[cs]=Závan čerstvého vzduchu +Comment[csb]=Wiéw swiérzegò lëftu +Comment[da]=En mundfuld frisk luft +Comment[de]=Ein Atemzug frische Luft +Comment[el]=Μια ανάσα φρέσκου αέρα +Comment[en_GB]=A breath of fresh air +Comment[eo]=Spiro de freŝa aero +Comment[es]=Un soplo de aire fresco +Comment[et]=Värskendav tuulepuhang +Comment[eu]=Haize-bolada freskoa +Comment[fa]=نفسی از هوای تازه +Comment[fi]=Raikkaan ilman leyhähdys +Comment[fr]=Un souffle d'air frais +Comment[fy]=it sykheljen yn de frisse lucht +Comment[ga]=Béalán den aer cumhra +Comment[gl]=Un folgo de ar fresco +Comment[gu]=તાજી હવાનો અનુભવ +Comment[he]=נשימה של אוויר רענן +Comment[hi]=ताजी हवा का झोंका +Comment[hr]=Dašak svježeg zraka +Comment[hu]=Friss fuvallat +Comment[ia]=Un respiration de aere fresc +Comment[id]=Tarikan nafas udara segar +Comment[is]=Ferskir vindar +Comment[ja]=新鮮な空気 +Comment[kk]=Самал желдей жеңіл +Comment[km]=ខ្យល់ដង្ហើម​បរិសុទ្ធ +Comment[kn]=ಸ್ವಚ್ಛ ಗಾಳಿಯ ಶ್ವಾಸ +Comment[ko]=신선한 바람 +Comment[lt]=Gryno oro gurkšnis +Comment[lv]=Svaiga gaisa elpa +Comment[mai]=ताजा हवाक झौंका +Comment[mk]=Здив од свеж воздух +Comment[ml]=ശുദ്ധവായുവിന്റെ ഒരിളംകാറ്റ് +Comment[mr]=शुद्ध हवेचा श्वास +Comment[nb]=Et pust av frisk luft +Comment[nds]=Wat frische Luft +Comment[nl]=Een hap frisse lucht +Comment[nn]=Eit friskt pust +Comment[pa]=ਤਾਜ਼ਾ ਹਵਾ ਵਿੱਚ ਸਾਹ ਲਵੋ +Comment[pl]=Powiew świeżego powietrza +Comment[pt]=Uma brisa de ar fresco +Comment[pt_BR]=Uma brisa de ar fresco +Comment[ro]=O gură de aer proaspăt +Comment[ru]=Волшебные пузырьки +Comment[si]=නැවුමෙ වාතය සමඟ ආශ්වාසයක් +Comment[sk]=Závan čerstvého vzduchu +Comment[sl]=Svež vetrič +Comment[sr]=Дашак свежег ваздуха +Comment[sr@ijekavian]=Дашак свјежег ваздуха +Comment[sr@ijekavianlatin]=Dašak svježeg vazduha +Comment[sr@latin]=Dašak svežeg vazduha +Comment[sv]=Ett friskt andetag +Comment[tg]=Нафаскашии ҳавои тоза +Comment[th]=ลมหายใจของอากาศบริสุทธิ์ +Comment[tr]=Temiz havadan bir nefes +Comment[ug]=ساپ ھاۋادىن نەپەسلىنىش +Comment[uk]=Ковток свіжого повітря +Comment[wa]=On shofla d' frisse air +Comment[x-test]=xxA breath of fresh airxx +Comment[zh_CN]=呼吸清新空气 +Comment[zh_TW]=吸一口新鮮空氣 + + +X-KDE-PluginInfo-Author=The Oxygen Project +X-KDE-PluginInfo-Email=kde-artists@kde.org +X-KDE-PluginInfo-Name=air-netbook +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +[Settings] +FallbackTheme=default diff --git a/plasma/netbook/desktoptheme/air-netbook/widgets/background.svgz b/plasma/netbook/desktoptheme/air-netbook/widgets/background.svgz new file mode 100644 index 00000000..3bb14aed Binary files /dev/null and b/plasma/netbook/desktoptheme/air-netbook/widgets/background.svgz differ diff --git a/plasma/netbook/desktoptheme/air-netbook/widgets/panel-background.svgz b/plasma/netbook/desktoptheme/air-netbook/widgets/panel-background.svgz new file mode 100644 index 00000000..209e5253 Binary files /dev/null and b/plasma/netbook/desktoptheme/air-netbook/widgets/panel-background.svgz differ diff --git a/plasma/netbook/shell/CMakeLists.txt b/plasma/netbook/shell/CMakeLists.txt new file mode 100644 index 00000000..e2a83fd0 --- /dev/null +++ b/plasma/netbook/shell/CMakeLists.txt @@ -0,0 +1,41 @@ +include_directories(${KDEBASE_WORKSPACE_SOURCE_DIR}/libs ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/plasmagenericshell ${KDEBASE_WORKSPACE_SOURCE_DIR}/plasma/netbook/shell/scripting/ ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kephal ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kworkspace) + +add_subdirectory(nettoolbox) + +set(plasma-netbook_SRCS + scripting/netbookscriptengine.cpp + scripting/panel.cpp + scripting/newspaper.cpp + netcorona.cpp + netview.cpp + main.cpp + plasmaapp.cpp + netpanelcontroller.cpp + netdialogmanager.cpp +) + +set(ksmserver_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/org.kde.KSMServerInterface.xml) +qt4_add_dbus_interface(plasma-netbook_SRCS ${ksmserver_xml} ksmserver_interface) + +kde4_add_kdeinit_executable(plasma-netbook ${plasma-netbook_SRCS}) + +target_link_libraries(kdeinit_plasma-netbook ${KDE4_PLASMA_LIBS} kworkspace ${KDE4_KIO_LIBS} ${X11_LIBRARIES} ${KDE4_KFILE_LIBS} kephal plasmagenericshell ${QT_QTOPENGL_LIBRARY} ${QT_QTSCRIPT_LIBRARY}) +if(X11_Xrender_FOUND) + target_link_libraries(kdeinit_plasma-netbook ${X11_Xrender_LIB}) +endif(X11_Xrender_FOUND) + +install(TARGETS kdeinit_plasma-netbook DESTINATION ${LIB_INSTALL_DIR}) +install(TARGETS plasma-netbook ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES data/layouts/00-defaultLayout.js DESTINATION ${DATA_INSTALL_DIR}/plasma-netbook/init) + +install(FILES data/layouts/org.kde.plasma-netbook.defaultSal/metadata.desktop DESTINATION ${DATA_INSTALL_DIR}/plasma/layout-templates/org.kde.plasma-netbook.defaultSal/) +install(FILES data/layouts/org.kde.plasma-netbook.defaultSal/contents/layout.js DESTINATION ${DATA_INSTALL_DIR}/plasma/layout-templates/org.kde.plasma-netbook.defaultSal/contents/) +install(FILES data/layouts/plasma-layout-org.kde.plasma-netbook.defaultSal.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + +install(FILES data/layouts/org.kde.plasma-netbook.defaultPanel/metadata.desktop DESTINATION ${DATA_INSTALL_DIR}/plasma/layout-templates/org.kde.plasma-netbook.defaultPanel/) +install(FILES data/layouts/org.kde.plasma-netbook.defaultPanel/contents/layout.js DESTINATION ${DATA_INSTALL_DIR}/plasma/layout-templates/org.kde.plasma-netbook.defaultPanel/contents/) +install(FILES data/layouts/plasma-layout-org.kde.plasma-netbook.defaultPanel.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + +install(FILES data/layouts/org.kde.plasma-netbook.defaultPage/metadata.desktop DESTINATION ${DATA_INSTALL_DIR}/plasma/layout-templates/org.kde.plasma-netbook.defaultPage/) +install(FILES data/layouts/org.kde.plasma-netbook.defaultPage/contents/layout.js DESTINATION ${DATA_INSTALL_DIR}/plasma/layout-templates/org.kde.plasma-netbook.defaultPage/contents/) +install(FILES data/layouts/plasma-layout-org.kde.plasma-netbook.defaultPage.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/netbook/shell/Messages.sh b/plasma/netbook/shell/Messages.sh new file mode 100644 index 00000000..978f9a6e --- /dev/null +++ b/plasma/netbook/shell/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp scripting/*.cpp -o $podir/plasma-netbook.pot diff --git a/plasma/netbook/shell/data/layouts/00-defaultLayout.js b/plasma/netbook/shell/data/layouts/00-defaultLayout.js new file mode 100644 index 00000000..12adb46e --- /dev/null +++ b/plasma/netbook/shell/data/layouts/00-defaultLayout.js @@ -0,0 +1,6 @@ + + +loadTemplate("org.kde.plasma-netbook.defaultSal") +loadTemplate("org.kde.plasma-netbook.defaultPanel") +loadTemplate("org.kde.plasma-netbook.defaultPage") + diff --git a/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPage/contents/layout.js b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPage/contents/layout.js new file mode 100644 index 00000000..5c314b34 --- /dev/null +++ b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPage/contents/layout.js @@ -0,0 +1,13 @@ + + +var page = new Activity("newspaper") +page.screen = -1 +page.wallpaperPlugin = 'image' +page.wallpaperMode = 'SingleImage' +page.name = templateName + + +page.addWidgetAt("news", 0, 0) +page.addWidgetAt("weather", 1, 0) +page.addWidgetAt("opendesktop", 0, 1) +page.addWidgetAt("knowledgebase", 1, 1) \ No newline at end of file diff --git a/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPage/metadata.desktop b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPage/metadata.desktop new file mode 100644 index 00000000..ea260842 --- /dev/null +++ b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPage/metadata.desktop @@ -0,0 +1,139 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Page one +Name[ar]=الصفحة الأولى +Name[ast]=Páxina un +Name[bg]=Страница 1 +Name[bn]=প্রথম পাতা +Name[bs]=Prva stranica +Name[ca]=Pàgina u +Name[ca@valencia]=Pàgina u +Name[cs]=První stránka +Name[da]=Side ét +Name[de]=Seite eins +Name[el]=Σελίδα ένα +Name[en_GB]=Page one +Name[es]=Página uno +Name[et]=Esimene lehekülg +Name[eu]=Lehenengo orria +Name[fi]=Sivu yksi +Name[fr]=Page « Une » +Name[ga]=Leathanach a haon +Name[gl]=Páxina un +Name[he]=דף מספר אחד +Name[hi]=पेज एक +Name[hr]=Stranica jedan +Name[hu]=Első lap +Name[ia]=Pagina uno +Name[id]=Halaman satu +Name[is]=Síða eitt +Name[ja]=ページワン +Name[kk]=Бірінші парақ +Name[km]=ទំព័រ​មួយ +Name[kn]=ಹಾಳೆ ಒಂದು +Name[ko]=1쪽 +Name[lt]=Pirmas puslapis +Name[lv]=Page one +Name[mr]=पान एक +Name[nb]=Side én +Name[nds]=Eerst Siet +Name[nl]=Pagina één +Name[pa]=ਪੇਜ਼ ਇੱਕ +Name[pl]=Strona pierwsza +Name[pt]=Página um +Name[pt_BR]=Página um +Name[ro]=Pagina unu +Name[ru]=Первая страница +Name[si]=පිටුව එක +Name[sk]=Prvá stránka +Name[sl]=Prva stran +Name[sr]=Прва страница +Name[sr@ijekavian]=Прва страница +Name[sr@ijekavianlatin]=Prva stranica +Name[sr@latin]=Prva stranica +Name[sv]=Sida ett +Name[tg]=Саҳифаи якум +Name[th]=หน้าหนึ่ง +Name[tr]=Sayfa bir +Name[ug]=بىرىنچى بەت +Name[uk]=Перша сторінка +Name[wa]=Pådje ene +Name[x-test]=xxPage onexx +Name[zh_CN]=Page one +Name[zh_TW]=第 1 頁 +Comment=Default Netbook Page +Comment[ar]=الصفحة المبدئية للحاسب المحمول الشبكي +Comment[ast]=Páxina predeterminada pa netbooks +Comment[bg]=Подразбираща се страница за нетбук +Comment[bn]=ডিফল্ট নেটবুক পাতা +Comment[bs]=Podrazumijevana stranica na netbuku +Comment[ca]=Pàgina per omissió per ordinadors ultraportàtils +Comment[ca@valencia]=Pàgina per omissió per ordinadors ultraportàtils +Comment[cs]=Výchozí stránka Netbooku +Comment[da]=Standard netbook-side +Comment[de]=Standard-Netbook-Seite +Comment[el]=Προκαθορισμένη σελίδα Netbook +Comment[en_GB]=Default Netbook Page +Comment[es]=Página predeterminada para netbooks +Comment[et]=Vaikimisi väikesülearvuti lehekülg +Comment[eu]=Netbooketarako orri lehenetsia +Comment[fi]=Oletussivu miniläppäreille +Comment[fr]=Page par défaut pour ultra portable +Comment[gl]=Páxina predeterminada do Netbook +Comment[gu]=મૂળભૂત નેટબુક પાનું +Comment[he]=דף ברירת המחדל עבור נטבוקים +Comment[hi]=डिफ़ॉल्ट नेटबुक पृष्ठ +Comment[hr]=Zadana Netbook stranica +Comment[hu]=Alapértelmezett netbook oldal +Comment[ia]=Pagina de Netbook predefinite +Comment[id]=Halaman Netbook Standar +Comment[is]=Sjálfgefin síða fyrir smáfartölvur +Comment[ja]=標準のネットブックのページ +Comment[kk]=Нетбуктің әдетті парағы +Comment[km]=ទំព័រ​ Netbook លំនាំដើម +Comment[kn]=ಪೂರ್ವನಿಯೋಜಿತ (ಡಿಫಾಲ್ಟ್) ನೆಟ್ ಬುಕ್ ಹಾಳೆ +Comment[ko]=기본 넷북 쪽 +Comment[lt]=Numatytas netbook puslapis +Comment[lv]=Mazdatora noklusējuma lapa +Comment[mr]=मूलभूत नेटबूक पान +Comment[nb]=Standard nettbok-side +Comment[nds]=Standard-Nettbooksiet +Comment[nl]=Standaard netbook-pagina +Comment[pa]=ਡਿਫਾਲਟ ਨੈੱਟਬੁੱਕ ਪੇਜ਼ +Comment[pl]=Domyślna strona netbooka +Comment[pt]=Página Predefinida do Netbook +Comment[pt_BR]=Página padrão do Netbook +Comment[ro]=Pagină implicită de netbook +Comment[ru]=Стандартная страница для нетбуков +Comment[si]=පෙරනිමි නෝට්බුක් පිටුව +Comment[sk]=Štandardná stránka Netbook +Comment[sl]=Privzeta stran za male prenosnike +Comment[sr]=Подразумевана страница на нетбуку +Comment[sr@ijekavian]=Подразумијевана страница на нетбуку +Comment[sr@ijekavianlatin]=Podrazumijevana stranica na netbuku +Comment[sr@latin]=Podrazumevana stranica na netbuku +Comment[sv]=Standardsida för nätdator +Comment[tg]=Саҳифаи стандартии Netbook +Comment[th]=หน้าปริยายของเน็ตบุ๊ก +Comment[tr]=Öntanımlı Netbook Sayfası +Comment[ug]=كۆڭۈلدىكى تور كومپيۇتېر بەتلەر +Comment[uk]=Типова сторінка субноутбука +Comment[vi]=Trang Netbook mặc định +Comment[wa]=Pådje prémetowe po poirtåve éndjolete +Comment[x-test]=xxDefault Netbook Pagexx +Comment[zh_CN]=默认上网本页面 +Comment[zh_TW]=預設 Netbook 頁面 + +Type=Service +ServiceTypes=Plasma/LayoutTemplate +X-Plasma-Shell=plasma-netbook +X-Plasma-ContainmentCategories=desktop +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=org.kde.plasma-netbook.defaultPage +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPanel/contents/layout.js b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPanel/contents/layout.js new file mode 100644 index 00000000..01ecf51e --- /dev/null +++ b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPanel/contents/layout.js @@ -0,0 +1,12 @@ +var panel = new Panel("netpanel") +if (panelIds.length == 1) { + // we are the only panel, so set the location for the user + panel.location = 'top' +} +panel.locked = false; +panel.height = 28 +panel.addWidget("activitybar") +panel.addWidget("systemtray") +panel.addWidget("digital-clock") +panel.addWidget("currentappcontrol") +panel.locked = true; \ No newline at end of file diff --git a/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPanel/metadata.desktop b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPanel/metadata.desktop new file mode 100644 index 00000000..6d29e913 --- /dev/null +++ b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultPanel/metadata.desktop @@ -0,0 +1,78 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Default Netbook Panel +Name[ar]=الحاوية المبدئية للحاسب المحمول الشبكي +Name[ast]=Panel predetermináu pa netbooks +Name[bg]=Подразбиращ се панел за нетбук +Name[bn]=ডিফল্ট নেটবুক প্যানেল +Name[bs]=Podrazumijevani panel za netbuk +Name[ca]=Plafó per omissió pels ordinadors ultraportàtils +Name[ca@valencia]=Plafó per omissió pels ordinadors ultraportàtils +Name[cs]=Výchozí panel Netbooku +Name[da]=Standard netbook-panel +Name[de]=Standard-Netbook-Kontrollleiste +Name[el]=Προκαθορισμένος πίνακας Netbook +Name[en_GB]=Default Netbook Panel +Name[es]=Panel predeterminado para netbooks +Name[et]=Vaikimisi väikesülearvuti paneel +Name[eu]=Netbooketarako panel lehenetsia +Name[fi]=Oletuspaneeli miniläppäreille +Name[fr]=Tableau de bord par défaut pour les ultra portables +Name[gl]=Panel predeterminado do Netbook +Name[gu]=મૂળભૂત નેટબુક પેનલ +Name[he]=לוח ברירת המחדל עבור נטבוקים +Name[hi]=डिफ़ॉल्ट नेटबुक पटल +Name[hr]=Zadani Netbook panel +Name[hu]=Alapértelmezett netbook panel +Name[ia]=Pannello de Netbook predefinite +Name[id]=Panel Netbook Standar +Name[is]=Sjálfgefið spjald fyrir smáfartölvur +Name[ja]=標準のネットブックのパネル +Name[kk]=Нетбуктің әдетті панелі +Name[km]=បន្ទះ Netbook លំនាំដើម +Name[kn]=ಪೂರ್ವನಿಯೋಜಿತ (ಡಿಫಾಲ್ಟ್) ನೆಟ್ ಬುಕ್ ಪುಟಿಕೆ (ಪ್ಯಾನಲ್) +Name[ko]=기본 넷북 패널 +Name[lt]=Numatytas netbook skydelis +Name[lv]=Mazdatora noklusējuma panelis +Name[mr]=मूलभूत नेटबूक पटल +Name[nb]=Standard nettbok-panel +Name[nds]=Standard-Nettbookpaneel +Name[nl]=Standaard netbook-paneel +Name[pa]=ਡਿਫਾਲਟ ਨੈੱਟਬੁੱਕ ਪੈਨਲ +Name[pl]=Domyślny panel netbooka +Name[pt]=Painel Predefinido do Netbook +Name[pt_BR]=Painel padrão do Netbook +Name[ro]=Panou implicit de netbook +Name[ru]=Стандартная панель для нетбуков +Name[si]=පෙරනිමි නෝට්බුක් පැනලය +Name[sk]=Štandardný panel Netbook +Name[sl]=Privzeti pult za male prenosnike +Name[sr]=Подразумевани панел за нетбук +Name[sr@ijekavian]=Подразумијевани панел за нетбук +Name[sr@ijekavianlatin]=Podrazumijevani panel za netbuk +Name[sr@latin]=Podrazumevani panel za netbuk +Name[sv]=Standardpanel för nätdator +Name[tg]=Панели стандартии Netbook +Name[th]=พาเนลปริยายของเน็ตบุ๊ก +Name[tr]=Öntanımlı Netbook Paneli +Name[ug]=كۆڭۈلدىكى تور كومپيۇتېر تاختىسى +Name[uk]=Типова панель субноутбука +Name[vi]=Thanh điều khiển Netbook mặc định +Name[wa]=Sicriftôr prémetou po poirtåve éndjolete +Name[x-test]=xxDefault Netbook Panelxx +Name[zh_CN]=默认上网本面板 +Name[zh_TW]=預設 Netbook 面板 + +Type=Service +ServiceTypes=Plasma/LayoutTemplate +X-Plasma-Shell=plasma-netbook +X-Plasma-ContainmentCategories=panel +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=org.kde.plasma-netbook.defaultPanel +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultSal/contents/layout.js b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultSal/contents/layout.js new file mode 100644 index 00000000..f531d959 --- /dev/null +++ b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultSal/contents/layout.js @@ -0,0 +1,8 @@ + +var sal = new Activity("sal") +sal.screen = 0 +sal.wallpaperPlugin = 'image' +sal.wallpaperMode = 'SingleImage' +sal.name = templateName +sal.writeConfig("PackageManager", "kpackagekit") +sal.reloadConfig() diff --git a/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultSal/metadata.desktop b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultSal/metadata.desktop new file mode 100644 index 00000000..8d440fdc --- /dev/null +++ b/plasma/netbook/shell/data/layouts/org.kde.plasma-netbook.defaultSal/metadata.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Search and launch +Name[ar]=البحث والإطلاق +Name[ast]=Gueta y execución +Name[bg]=Търсене и стартиране +Name[bs]=Traženje i pokretanje +Name[ca]=Cerca i llançament +Name[ca@valencia]=Cerca i llançament +Name[cs]=Vyhledat a spustit +Name[da]=Søg og start +Name[de]=Suchen und ausführen +Name[el]=Αναζήτηση και εκτέλεση +Name[en_GB]=Search and launch +Name[es]=Búsqueda y ejecución +Name[et]=Otsimine ja käivitamine +Name[eu]=Bilatu eta abiarazi +Name[fi]=Etsi ja käynnistä +Name[fr]=Rechercher et lancer +Name[ga]=Cuardaigh agus tosaigh +Name[gl]=Buscar e executar +Name[he]=חיפוש והפעלה +Name[hi]=खोज व लाँच +Name[hr]=Pretraži i pokreni +Name[hu]=Keresés és indítás +Name[ia]=Cerca e Lancea +Name[id]=Cari dan jalankan +Name[is]=Leit að forritum og ræsing +Name[ja]=検索と起動 +Name[kk]=Іздеу және жегу +Name[km]=ស្វែងរក​ ហើយ​ចាប់ផ្ដើម +Name[kn]=ಹುಡುಕು ಹಾಗು ಪ್ರಕ್ಷೇಪನ +Name[ko]=찾아서 실행하기 +Name[lt]=Rasti ir paleisti +Name[lv]=Meklēt un palaist +Name[mr]=शोधा व प्रक्षेपण करा +Name[nb]=Søk og start +Name[nds]=Söken un opropen +Name[nl]=Zoeken en starten +Name[nn]=Søk og køyr +Name[pa]=ਖੋਜ ਅਤੇ ਚਲਾਓ +Name[pl]=Znajdź i uruchom +Name[pt]=Pesquisa e lançamento +Name[pt_BR]=Pesquisa e execução +Name[ro]=Căutare și lansare +Name[ru]=Поиск и запуск +Name[si]=සොයා දියත් කරන්න +Name[sk]=Hľadať a spustiť +Name[sl]=Iskanje in zaganjanje +Name[sr]=Тражење и покретање +Name[sr@ijekavian]=Тражење и покретање +Name[sr@ijekavianlatin]=Traženje i pokretanje +Name[sr@latin]=Traženje i pokretanje +Name[sv]=Sök och starta +Name[tg]=Ҷустуҷӯӣ ва оғозӣ +Name[th]=ค้นหาและเรียกใช้งาน +Name[tr]=Ara ve çalıştır +Name[ug]=ئىزدە ۋە ئىجرا قىل +Name[uk]=Рушій пошуку і запуску +Name[wa]=Trover ey enonder +Name[x-test]=xxSearch and launchxx +Name[zh_CN]=搜索与启动 +Name[zh_TW]=搜尋並啟動 + +Type=Service +ServiceTypes=Plasma/LayoutTemplate +X-Plasma-Shell=plasma-netbook +X-Plasma-ContainmentCategories=desktop +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=org.kde.plasma-netbook.defaultSal +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultPage.desktop b/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultPage.desktop new file mode 100644 index 00000000..56a39733 --- /dev/null +++ b/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultPage.desktop @@ -0,0 +1,138 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Page one +Name[ar]=الصفحة الأولى +Name[ast]=Páxina un +Name[bg]=Страница 1 +Name[bn]=প্রথম পাতা +Name[bs]=Prva stranica +Name[ca]=Pàgina u +Name[ca@valencia]=Pàgina u +Name[cs]=První stránka +Name[da]=Side ét +Name[de]=Seite eins +Name[el]=Σελίδα ένα +Name[en_GB]=Page one +Name[es]=Página uno +Name[et]=Esimene lehekülg +Name[eu]=Lehenengo orria +Name[fi]=Sivu yksi +Name[fr]=Page « Une » +Name[ga]=Leathanach a haon +Name[gl]=Páxina un +Name[he]=דף מספר אחד +Name[hi]=पेज एक +Name[hr]=Stranica jedan +Name[hu]=Első lap +Name[ia]=Pagina uno +Name[id]=Halaman satu +Name[is]=Síða eitt +Name[ja]=ページワン +Name[kk]=Бірінші парақ +Name[km]=ទំព័រ​មួយ +Name[kn]=ಹಾಳೆ ಒಂದು +Name[ko]=1쪽 +Name[lt]=Pirmas puslapis +Name[lv]=Page one +Name[mr]=पान एक +Name[nb]=Side én +Name[nds]=Eerst Siet +Name[nl]=Pagina één +Name[pa]=ਪੇਜ਼ ਇੱਕ +Name[pl]=Strona pierwsza +Name[pt]=Página um +Name[pt_BR]=Página um +Name[ro]=Pagina unu +Name[ru]=Первая страница +Name[si]=පිටුව එක +Name[sk]=Prvá stránka +Name[sl]=Prva stran +Name[sr]=Прва страница +Name[sr@ijekavian]=Прва страница +Name[sr@ijekavianlatin]=Prva stranica +Name[sr@latin]=Prva stranica +Name[sv]=Sida ett +Name[tg]=Саҳифаи якум +Name[th]=หน้าหนึ่ง +Name[tr]=Sayfa bir +Name[ug]=بىرىنچى بەت +Name[uk]=Перша сторінка +Name[wa]=Pådje ene +Name[x-test]=xxPage onexx +Name[zh_CN]=Page one +Name[zh_TW]=第 1 頁 +Comment=Default Netbook Page +Comment[ar]=الصفحة المبدئية للحاسب المحمول الشبكي +Comment[ast]=Páxina predeterminada pa netbooks +Comment[bg]=Подразбираща се страница за нетбук +Comment[bn]=ডিফল্ট নেটবুক পাতা +Comment[bs]=Podrazumijevana stranica na netbuku +Comment[ca]=Pàgina per omissió per ordinadors ultraportàtils +Comment[ca@valencia]=Pàgina per omissió per ordinadors ultraportàtils +Comment[cs]=Výchozí stránka Netbooku +Comment[da]=Standard netbook-side +Comment[de]=Standard-Netbook-Seite +Comment[el]=Προκαθορισμένη σελίδα Netbook +Comment[en_GB]=Default Netbook Page +Comment[es]=Página predeterminada para netbooks +Comment[et]=Vaikimisi väikesülearvuti lehekülg +Comment[eu]=Netbooketarako orri lehenetsia +Comment[fi]=Oletussivu miniläppäreille +Comment[fr]=Page par défaut pour ultra portable +Comment[gl]=Páxina predeterminada do Netbook +Comment[gu]=મૂળભૂત નેટબુક પાનું +Comment[he]=דף ברירת המחדל עבור נטבוקים +Comment[hi]=डिफ़ॉल्ट नेटबुक पृष्ठ +Comment[hr]=Zadana Netbook stranica +Comment[hu]=Alapértelmezett netbook oldal +Comment[ia]=Pagina de Netbook predefinite +Comment[id]=Halaman Netbook Standar +Comment[is]=Sjálfgefin síða fyrir smáfartölvur +Comment[ja]=標準のネットブックのページ +Comment[kk]=Нетбуктің әдетті парағы +Comment[km]=ទំព័រ​ Netbook លំនាំដើម +Comment[kn]=ಪೂರ್ವನಿಯೋಜಿತ (ಡಿಫಾಲ್ಟ್) ನೆಟ್ ಬುಕ್ ಹಾಳೆ +Comment[ko]=기본 넷북 쪽 +Comment[lt]=Numatytas netbook puslapis +Comment[lv]=Mazdatora noklusējuma lapa +Comment[mr]=मूलभूत नेटबूक पान +Comment[nb]=Standard nettbok-side +Comment[nds]=Standard-Nettbooksiet +Comment[nl]=Standaard netbook-pagina +Comment[pa]=ਡਿਫਾਲਟ ਨੈੱਟਬੁੱਕ ਪੇਜ਼ +Comment[pl]=Domyślna strona netbooka +Comment[pt]=Página Predefinida do Netbook +Comment[pt_BR]=Página padrão do Netbook +Comment[ro]=Pagină implicită de netbook +Comment[ru]=Стандартная страница для нетбуков +Comment[si]=පෙරනිමි නෝට්බුක් පිටුව +Comment[sk]=Štandardná stránka Netbook +Comment[sl]=Privzeta stran za male prenosnike +Comment[sr]=Подразумевана страница на нетбуку +Comment[sr@ijekavian]=Подразумијевана страница на нетбуку +Comment[sr@ijekavianlatin]=Podrazumijevana stranica na netbuku +Comment[sr@latin]=Podrazumevana stranica na netbuku +Comment[sv]=Standardsida för nätdator +Comment[tg]=Саҳифаи стандартии Netbook +Comment[th]=หน้าปริยายของเน็ตบุ๊ก +Comment[tr]=Öntanımlı Netbook Sayfası +Comment[ug]=كۆڭۈلدىكى تور كومپيۇتېر بەتلەر +Comment[uk]=Типова сторінка субноутбука +Comment[vi]=Trang Netbook mặc định +Comment[wa]=Pådje prémetowe po poirtåve éndjolete +Comment[x-test]=xxDefault Netbook Pagexx +Comment[zh_CN]=默认上网本页面 +Comment[zh_TW]=預設 Netbook 頁面 +Type=Service +ServiceTypes=Plasma/LayoutTemplate +X-Plasma-Shell=plasma-netbook +X-Plasma-ContainmentCategories=desktop +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=org.kde.plasma-netbook.defaultPage +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultPanel.desktop b/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultPanel.desktop new file mode 100644 index 00000000..fded6aad --- /dev/null +++ b/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultPanel.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Default Netbook Panel +Name[ar]=الحاوية المبدئية للحاسب المحمول الشبكي +Name[ast]=Panel predetermináu pa netbooks +Name[bg]=Подразбиращ се панел за нетбук +Name[bn]=ডিফল্ট নেটবুক প্যানেল +Name[bs]=Podrazumijevani panel za netbuk +Name[ca]=Plafó per omissió pels ordinadors ultraportàtils +Name[ca@valencia]=Plafó per omissió pels ordinadors ultraportàtils +Name[cs]=Výchozí panel Netbooku +Name[da]=Standard netbook-panel +Name[de]=Standard-Netbook-Kontrollleiste +Name[el]=Προκαθορισμένος πίνακας Netbook +Name[en_GB]=Default Netbook Panel +Name[es]=Panel predeterminado para netbooks +Name[et]=Vaikimisi väikesülearvuti paneel +Name[eu]=Netbooketarako panel lehenetsia +Name[fi]=Oletuspaneeli miniläppäreille +Name[fr]=Tableau de bord par défaut pour les ultra portables +Name[gl]=Panel predeterminado do Netbook +Name[gu]=મૂળભૂત નેટબુક પેનલ +Name[he]=לוח ברירת המחדל עבור נטבוקים +Name[hi]=डिफ़ॉल्ट नेटबुक पटल +Name[hr]=Zadani Netbook panel +Name[hu]=Alapértelmezett netbook panel +Name[ia]=Pannello de Netbook predefinite +Name[id]=Panel Netbook Standar +Name[is]=Sjálfgefið spjald fyrir smáfartölvur +Name[ja]=標準のネットブックのパネル +Name[kk]=Нетбуктің әдетті панелі +Name[km]=បន្ទះ Netbook លំនាំដើម +Name[kn]=ಪೂರ್ವನಿಯೋಜಿತ (ಡಿಫಾಲ್ಟ್) ನೆಟ್ ಬುಕ್ ಪುಟಿಕೆ (ಪ್ಯಾನಲ್) +Name[ko]=기본 넷북 패널 +Name[lt]=Numatytas netbook skydelis +Name[lv]=Mazdatora noklusējuma panelis +Name[mr]=मूलभूत नेटबूक पटल +Name[nb]=Standard nettbok-panel +Name[nds]=Standard-Nettbookpaneel +Name[nl]=Standaard netbook-paneel +Name[pa]=ਡਿਫਾਲਟ ਨੈੱਟਬੁੱਕ ਪੈਨਲ +Name[pl]=Domyślny panel netbooka +Name[pt]=Painel Predefinido do Netbook +Name[pt_BR]=Painel padrão do Netbook +Name[ro]=Panou implicit de netbook +Name[ru]=Стандартная панель для нетбуков +Name[si]=පෙරනිමි නෝට්බුක් පැනලය +Name[sk]=Štandardný panel Netbook +Name[sl]=Privzeti pult za male prenosnike +Name[sr]=Подразумевани панел за нетбук +Name[sr@ijekavian]=Подразумијевани панел за нетбук +Name[sr@ijekavianlatin]=Podrazumijevani panel za netbuk +Name[sr@latin]=Podrazumevani panel za netbuk +Name[sv]=Standardpanel för nätdator +Name[tg]=Панели стандартии Netbook +Name[th]=พาเนลปริยายของเน็ตบุ๊ก +Name[tr]=Öntanımlı Netbook Paneli +Name[ug]=كۆڭۈلدىكى تور كومپيۇتېر تاختىسى +Name[uk]=Типова панель субноутбука +Name[vi]=Thanh điều khiển Netbook mặc định +Name[wa]=Sicriftôr prémetou po poirtåve éndjolete +Name[x-test]=xxDefault Netbook Panelxx +Name[zh_CN]=默认上网本面板 +Name[zh_TW]=預設 Netbook 面板 +Type=Service +ServiceTypes=Plasma/LayoutTemplate +X-Plasma-Shell=plasma-netbook +X-Plasma-ContainmentCategories=panel +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=org.kde.plasma-netbook.defaultPanel +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultSal.desktop b/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultSal.desktop new file mode 100644 index 00000000..8d440fdc --- /dev/null +++ b/plasma/netbook/shell/data/layouts/plasma-layout-org.kde.plasma-netbook.defaultSal.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Search and launch +Name[ar]=البحث والإطلاق +Name[ast]=Gueta y execución +Name[bg]=Търсене и стартиране +Name[bs]=Traženje i pokretanje +Name[ca]=Cerca i llançament +Name[ca@valencia]=Cerca i llançament +Name[cs]=Vyhledat a spustit +Name[da]=Søg og start +Name[de]=Suchen und ausführen +Name[el]=Αναζήτηση και εκτέλεση +Name[en_GB]=Search and launch +Name[es]=Búsqueda y ejecución +Name[et]=Otsimine ja käivitamine +Name[eu]=Bilatu eta abiarazi +Name[fi]=Etsi ja käynnistä +Name[fr]=Rechercher et lancer +Name[ga]=Cuardaigh agus tosaigh +Name[gl]=Buscar e executar +Name[he]=חיפוש והפעלה +Name[hi]=खोज व लाँच +Name[hr]=Pretraži i pokreni +Name[hu]=Keresés és indítás +Name[ia]=Cerca e Lancea +Name[id]=Cari dan jalankan +Name[is]=Leit að forritum og ræsing +Name[ja]=検索と起動 +Name[kk]=Іздеу және жегу +Name[km]=ស្វែងរក​ ហើយ​ចាប់ផ្ដើម +Name[kn]=ಹುಡುಕು ಹಾಗು ಪ್ರಕ್ಷೇಪನ +Name[ko]=찾아서 실행하기 +Name[lt]=Rasti ir paleisti +Name[lv]=Meklēt un palaist +Name[mr]=शोधा व प्रक्षेपण करा +Name[nb]=Søk og start +Name[nds]=Söken un opropen +Name[nl]=Zoeken en starten +Name[nn]=Søk og køyr +Name[pa]=ਖੋਜ ਅਤੇ ਚਲਾਓ +Name[pl]=Znajdź i uruchom +Name[pt]=Pesquisa e lançamento +Name[pt_BR]=Pesquisa e execução +Name[ro]=Căutare și lansare +Name[ru]=Поиск и запуск +Name[si]=සොයා දියත් කරන්න +Name[sk]=Hľadať a spustiť +Name[sl]=Iskanje in zaganjanje +Name[sr]=Тражење и покретање +Name[sr@ijekavian]=Тражење и покретање +Name[sr@ijekavianlatin]=Traženje i pokretanje +Name[sr@latin]=Traženje i pokretanje +Name[sv]=Sök och starta +Name[tg]=Ҷустуҷӯӣ ва оғозӣ +Name[th]=ค้นหาและเรียกใช้งาน +Name[tr]=Ara ve çalıştır +Name[ug]=ئىزدە ۋە ئىجرا قىل +Name[uk]=Рушій пошуку і запуску +Name[wa]=Trover ey enonder +Name[x-test]=xxSearch and launchxx +Name[zh_CN]=搜索与启动 +Name[zh_TW]=搜尋並啟動 + +Type=Service +ServiceTypes=Plasma/LayoutTemplate +X-Plasma-Shell=plasma-netbook +X-Plasma-ContainmentCategories=desktop +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=notmart@gmail.com +X-KDE-PluginInfo-Name=org.kde.plasma-netbook.defaultSal +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasma/netbook/shell/main.cpp b/plasma/netbook/shell/main.cpp new file mode 100644 index 00000000..3aa7c983 --- /dev/null +++ b/plasma/netbook/shell/main.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2006-2008 Aaron Seigo + * + * 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, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include "plasmaapp.h" + +static const char description[] = I18N_NOOP( "The KDE workspace application optimized for Netbook devices." ); +static const char version[] = "0.2"; + +extern "C" +KDE_EXPORT int kdemain(int argc, char **argv) +{ + KAboutData aboutData("plasma-netbook", 0, ki18n("Plasma Netbook Shell"), + version, ki18n(description), KAboutData::License_GPL, + ki18n("Copyright 2006-2009, The KDE Team")); + aboutData.addAuthor(ki18n("Aaron J. Seigo"), + ki18n("Author and maintainer"), + "aseigo@kde.org"); + + + bool customGraphicsSystem = false; + for (int i = 0; i < argc; ++i) { + if (QString(argv[i]) == "-graphicssystem") { + customGraphicsSystem = true; + break; + } + } + + if (!customGraphicsSystem) { + KConfigGroup cg(KSharedConfig::openConfig("plasma-netbookrc"), "General"); + QApplication::setGraphicsSystem(cg.readEntry("GraphicsSystem", "native")); + } + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("nodesktop", ki18n("Starts as a normal application instead of as the primary user interface")); + options.add("opengl", ki18n("Use OpenGL to draw the main screen")); + options.add("screen ", ki18n("The geometry of the screen"), "800x480"); + KCmdLineArgs::addCmdLineOptions(options); + + PlasmaApp *app = PlasmaApp::self(); + QApplication::setWindowIcon(KIcon("plasma")); + app->disableSessionManagement(); // autostarted + int rc = app->exec(); + delete app; + return rc; +} + diff --git a/plasma/netbook/shell/netcorona.cpp b/plasma/netbook/shell/netcorona.cpp new file mode 100644 index 00000000..47a2f1fd --- /dev/null +++ b/plasma/netbook/shell/netcorona.cpp @@ -0,0 +1,234 @@ +/* + * Copyright 2008 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "netcorona.h" +#include "netdialogmanager.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "plasmaapp.h" +#include "netview.h" +#include +#include + +NetCorona::NetCorona(QObject *parent) + : Plasma::Corona(parent) +{ + init(); +} + +void NetCorona::init() +{ + setPreferredToolBoxPlugin(Plasma::Containment::DesktopContainment, "org.kde.nettoolbox"); + QDesktopWidget *desktop = QApplication::desktop(); + QObject::connect(desktop, SIGNAL(resized(int)), this, SLOT(screenResized(int))); + connect(PlasmaApp::self(), SIGNAL(controlBarChanged()), this, SIGNAL(availableScreenRegionChanged())); + + connect(this, SIGNAL(containmentAdded(Plasma::Containment*)), this, SLOT(containmentAdded(Plasma::Containment*))); + + Plasma::ContainmentActionsPluginsConfig desktopPlugins; + desktopPlugins.addPlugin(Qt::NoModifier, Qt::MidButton, "paste"); + desktopPlugins.addPlugin(Qt::NoModifier, Qt::RightButton, "contextmenu"); + Plasma::ContainmentActionsPluginsConfig panelPlugins; + panelPlugins.addPlugin(Qt::NoModifier, Qt::RightButton, "contextmenu"); + + setContainmentActionsDefaults(Plasma::Containment::DesktopContainment, desktopPlugins); + setContainmentActionsDefaults(Plasma::Containment::CustomContainment, desktopPlugins); + setContainmentActionsDefaults(Plasma::Containment::PanelContainment, panelPlugins); + setContainmentActionsDefaults(Plasma::Containment::CustomPanelContainment, panelPlugins); + + setDialogManager(new NetDialogManager(this)); + + QAction *a = new QAction(KIcon("view-pim-news"), i18n("Add page"), this); + addAction("add page", a); + connect(a, SIGNAL(triggered()), this, SLOT(addPage())); + + //we have a page-level lock action + a = action("lock widgets"); + delete a; + setImmutability(Plasma::Mutable); + setDefaultContainmentPlugin("newspaper"); +} + +void NetCorona::loadDefaultLayout() +{ + evaluateScripts(WorkspaceScripting::NetbookScriptEngine::defaultLayoutScripts()); + if (!containments().isEmpty()) { + return; + } + + QString defaultConfig = KStandardDirs::locate("appdata", "plasma-default-layoutrc"); + if (!defaultConfig.isEmpty()) { + kDebug() << "attempting to load the default layout from:" << defaultConfig; + + // gcc bug 36490: KConfig's copy constructor is private, so passing it as a + // temporary to importLayout, ie importLayout(KConfig(defaultConfig)) fails + // on gcc < 4.3.0 + KConfig c(defaultConfig); + importLayout(c.group(QByteArray())); + + return; + } +} + +Plasma::Applet *NetCorona::loadDefaultApplet(const QString &pluginName, Plasma::Containment *c) +{ + QVariantList args; + Plasma::Applet *applet = Plasma::Applet::load(pluginName, 0, args); + + if (applet) { + c->addApplet(applet); + } + + return applet; +} + +void NetCorona::addPage() +{ + //count the pages + int numPages = 0; + foreach (Plasma::Containment *containment, containments()) { + if (containment->location() == Plasma::Floating) { + ++numPages; + } + } + + Plasma::Containment *cont = addContainment(QString()); + if (!cont) { + //it may fail, for instance when widgets are locked + return; + } + + cont->setActivity(i18nc("Page number", "Page %1", numPages)); + cont->setScreen(0); + cont->setToolBoxOpen(true); +} + +void NetCorona::containmentAdded(Plasma::Containment *cont) +{ + if (cont->pluginName() == "sal") { + QAction *a = cont->action("remove"); + cont->removeAction(a); + delete a; + } + + foreach (QAction *action, actions()) { + cont->addToolBoxAction(action); + } +} + +Plasma::Containment *NetCorona::findFreeContainment() const +{ + foreach (Plasma::Containment *cont, containments()) { + if ((cont->containmentType() == Plasma::Containment::DesktopContainment || + cont->containmentType() == Plasma::Containment::CustomContainment) && + cont->screen() == -1 && !offscreenWidgets().contains(cont)) { + return cont; + } + } + + return 0; +} + +void NetCorona::screenResized(int screen) +{ + int numScreens = QApplication::desktop()->numScreens(); + if (screen < numScreens) { + foreach (Plasma::Containment *c, containments()) { + if (c->screen() == screen) { + // trigger a relayout + c->setScreen(screen); + } + } + } +} + +int NetCorona::numScreens() const +{ + return Kephal::ScreenUtils::numScreens(); +} + +QRect NetCorona::screenGeometry(int id) const +{ + return PlasmaApp::self()->mainView()->geometry(); +} + +QRegion NetCorona::availableScreenRegion(int id) const +{ + QRegion r(screenGeometry(id)); + NetView *view = PlasmaApp::self()->controlBar(); + if (view) { + r = r.subtracted(view->geometry()); + } + QWidget *explorer = PlasmaApp::self()->widgetExplorer(); + if (explorer) { + r = r.subtracted(explorer->geometry()); + } + + return r; +} + +void NetCorona::processUpdateScripts() +{ + evaluateScripts(WorkspaceScripting::NetbookScriptEngine::pendingUpdateScripts()); +} + +void NetCorona::evaluateScripts(const QStringList &scripts) +{ + foreach (const QString &script, scripts) { + WorkspaceScripting::NetbookScriptEngine scriptEngine(this); + connect(&scriptEngine, SIGNAL(printError(QString)), this, SLOT(printScriptError(QString))); + connect(&scriptEngine, SIGNAL(print(QString)), this, SLOT(printScriptMessage(QString))); + connect(&scriptEngine, SIGNAL(createPendingPanelViews()), PlasmaApp::self(), SLOT(createWaitingPanels())); + + QFile file(script); + if (file.open(QIODevice::ReadOnly | QIODevice::Text) ) { + QString code = file.readAll(); + kDebug() << "evaluating startup script:" << script; + scriptEngine.evaluateScript(code); + } + } +} + +void NetCorona::printScriptError(const QString &error) +{ + kWarning() << "Startup script errror:" << error; +} + +void NetCorona::printScriptMessage(const QString &error) +{ + kDebug() << "Startup script: " << error; +} + + +#include "netcorona.moc" + diff --git a/plasma/netbook/shell/netcorona.h b/plasma/netbook/shell/netcorona.h new file mode 100644 index 00000000..dc90b389 --- /dev/null +++ b/plasma/netbook/shell/netcorona.h @@ -0,0 +1,73 @@ +/* + * Copyright 2008 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NETVCORONA_H +#define NETVCORONA_H + +#include + +#include + +namespace Plasma +{ + class Applet; +} // namespace Plasma + +/** + * @short A Corona with desktop-y considerations + */ +class NetCorona : public Plasma::Corona +{ + Q_OBJECT + +public: + NetCorona(QObject * parent); + + /** + * Loads the default (system wide) layout for this user + **/ + void loadDefaultLayout(); + + Plasma::Containment *findFreeContainment() const; + + bool loadDefaultLayoutScripts(); + void processUpdateScripts(); + + virtual int numScreens() const; + virtual QRect screenGeometry(int id) const; + virtual QRegion availableScreenRegion(int id) const; + +protected Q_SLOTS: + void screenResized(int); + void evaluateScripts(const QStringList &scripts); + void printScriptError(const QString &error); + void printScriptMessage(const QString &error); + void containmentAdded(Plasma::Containment *cont); + void addPage(); + +private: + void init(); + Plasma::Applet *loadDefaultApplet(const QString &pluginName, Plasma::Containment *c); + + int m_numScreens; +}; + +#endif + + diff --git a/plasma/netbook/shell/netdialogmanager.cpp b/plasma/netbook/shell/netdialogmanager.cpp new file mode 100644 index 00000000..b3ba99d0 --- /dev/null +++ b/plasma/netbook/shell/netdialogmanager.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "netdialogmanager.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +NetDialogManager::NetDialogManager(Plasma::Corona *parent) + : Plasma::AbstractDialogManager(parent), + m_corona(parent) +{ +} + +NetDialogManager::~NetDialogManager() +{ +} + +void NetDialogManager::showDialog(QWidget *widget, Plasma::Applet *applet) +{ + Q_UNUSED(applet) + if (KWindowSystem::compositingActive()) { + widget->setAttribute(Qt::WA_WindowPropagation, false); + widget->setAttribute(Qt::WA_TranslucentBackground); + widget->setAttribute(Qt::WA_NoSystemBackground, false); + widget->setWindowFlags(Qt::FramelessWindowHint); + KWindowSystem::setState(widget->effectiveWinId(), NET::MaxVert|NET::MaxHoriz); + Plasma::WindowEffects::enableBlurBehind(widget->effectiveWinId(), true); + + QPalette palette = widget->palette(); + palette.setColor(QPalette::Window, QColor(0,0,0,100)); + widget->setAttribute(Qt::WA_WindowPropagation); + palette.setColor(QPalette::WindowText, Qt::white); + palette.setColor(QPalette::ToolTipText, Qt::white); + widget->setPalette(palette); + } + + Plasma::Containment *containment = applet->containment(); + if (containment) { + Plasma::Corona *corona = containment->corona(); + if (corona) { + QRect r = corona->availableScreenRegion(containment->screen()).boundingRect(); + //assumption: the panel is 100% wide + QRect screenRect = corona->screenGeometry(containment->screen()); + + widget->setContentsMargins(r.left() - screenRect.left(), + r.top() - screenRect.top(), + screenRect.right() - r.right(), + screenRect.bottom() - r.bottom()); + } + } + + widget->show(); +} + + +#include "netdialogmanager.moc" diff --git a/plasma/netbook/shell/netdialogmanager.h b/plasma/netbook/shell/netdialogmanager.h new file mode 100644 index 00000000..d117f880 --- /dev/null +++ b/plasma/netbook/shell/netdialogmanager.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NET_DIALOGMANAGER_H +#define NET_DIALOGMANAGER_H + +#include + +#include + + +namespace Plasma +{ + class Corona; +} + +class NetDialogManager : public Plasma::AbstractDialogManager +{ + Q_OBJECT + +public: + explicit NetDialogManager(Plasma::Corona *parent=0); + ~NetDialogManager(); + +public Q_SLOTS: + void showDialog(QWidget *widget, Plasma::Applet *applet); + +private: + Plasma::Corona *m_corona; +}; + +#endif diff --git a/plasma/netbook/shell/netpanelcontroller.cpp b/plasma/netbook/shell/netpanelcontroller.cpp new file mode 100644 index 00000000..c647d7b6 --- /dev/null +++ b/plasma/netbook/shell/netpanelcontroller.cpp @@ -0,0 +1,255 @@ +/* + * Copyright 2009 Marco Martin + * + * 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, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "netpanelcontroller.h" +#include "netview.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +NetPanelController::NetPanelController(QWidget *parent, NetView *view, Plasma::Containment *containment) + : Plasma::Dialog(parent), + m_containment(containment), + m_view(view), + m_watched(0) +{ + hide(); + + m_mainWidget = new QGraphicsWidget(containment); + if (containment && containment->corona()) { + containment->corona()->addOffscreenWidget(m_mainWidget); + } + + m_layout = new QGraphicsLinearLayout(Qt::Horizontal, m_mainWidget); + + m_iconSvg = new Plasma::Svg(this); + m_iconSvg->setImagePath("widgets/configuration-icons"); + m_iconSvg->setContainsMultipleImages(true); + m_iconSvg->resize(KIconLoader::SizeSmall, KIconLoader::SizeSmall); + + m_moveButton = new Plasma::ToolButton(m_mainWidget); + m_moveButton->nativeWidget()->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_moveButton->setIcon(m_iconSvg->pixmap("move")); + m_moveButton->setText(i18n("Screen edge")); + m_moveButton->setCursor(Qt::SizeAllCursor); + m_layout->addItem(m_moveButton); + + m_resizeButton = new Plasma::ToolButton(m_mainWidget); + m_resizeButton->nativeWidget()->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_resizeButton->setIcon(m_iconSvg->pixmap("size-vertical")); + m_resizeButton->setText(i18n("Height")); + m_layout->addItem(m_resizeButton); + + m_autoHideButton = new Plasma::ToolButton(m_mainWidget); + m_autoHideButton->nativeWidget()->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_autoHideButton->nativeWidget()->setCheckable(true); + m_autoHideButton->setIcon(m_iconSvg->pixmap("collapse")); + m_autoHideButton->setText(i18n("Auto Hide")); + m_layout->addItem(m_autoHideButton); + m_autoHideButton->nativeWidget()->setChecked(view->autoHide()); + connect(m_autoHideButton->nativeWidget(), SIGNAL(toggled(bool)), view, SLOT(setAutoHide(bool))); + connect(containment, SIGNAL(geometryChanged()), this, SLOT(updatePosition())); + + m_moveButton->installEventFilter(this); + m_resizeButton->installEventFilter(this); + setGraphicsWidget(m_mainWidget); + layout()->activate(); + m_layout->activate(); + m_mainWidget->resize(m_mainWidget->effectiveSizeHint(Qt::PreferredSize)); + updatePosition(); + show(); + Plasma::WindowEffects::slideWindow(this, containment->location()); + KWindowSystem::setState(winId(), NET::KeepAbove|NET::StaysOnTop); +} + +NetPanelController::~NetPanelController() +{ + Plasma::WindowEffects::slideWindow(this, m_containment->location()); +} + +void NetPanelController::updatePosition() +{ + QRect viewGeometry(m_view->geometry()); + switch (m_containment->location()) { + case Plasma::LeftEdge: + move(viewGeometry.right(), viewGeometry.center().y() - size().height()/2); + break; + case Plasma::RightEdge: + move(viewGeometry.left() - size().width(), viewGeometry.center().y() - size().height()/2); + break; + case Plasma::TopEdge: + move(viewGeometry.center().x() - size().width()/2, viewGeometry.bottom()); + break; + case Plasma::BottomEdge: + move(viewGeometry.center().x() - size().width()/2, viewGeometry.top() - size().height()); + break; + default: + break; + } + + updateFormFactor(); +} + +void NetPanelController::updateFormFactor() +{ + QRect viewGeometry(m_view->geometry()); + switch (m_containment->location()) { + case Plasma::LeftEdge: + case Plasma::RightEdge: + m_layout->setOrientation(Qt::Vertical); + m_resizeButton->setIcon(m_iconSvg->pixmap("size-horizontal")); + m_resizeButton->setText(i18n("Width")); + m_resizeButton->setCursor(Qt::SizeHorCursor); + break; + case Plasma::TopEdge: + case Plasma::BottomEdge: + m_layout->setOrientation(Qt::Horizontal); + m_resizeButton->setIcon(m_iconSvg->pixmap("size-vertical")); + m_resizeButton->setText(i18n("Height")); + m_resizeButton->setCursor(Qt::SizeVerCursor); + break; + default: + break; + } +} + +void NetPanelController::resizeEvent(QResizeEvent *e) +{ + updatePosition(); + Plasma::Dialog::resizeEvent(e); +} + +bool NetPanelController::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::GraphicsSceneMousePress) { + m_watched = qobject_cast(watched); + } else if (event->type() == QEvent::GraphicsSceneMouseRelease) { + m_watched = 0; + } else if (watched == m_moveButton && event->type() == QEvent::GraphicsSceneMouseMove) { + QGraphicsSceneMouseEvent *me = static_cast(event); + QRect screenGeom = Kephal::ScreenUtils::screenGeometry(m_containment->screen()); + + //only move when the mouse cursor is out of the controller to avoid an endless reposition cycle + if (geometry().contains(me->screenPos())) { + return false; + } + + if (!screenGeom.contains(me->screenPos())) { + //move panel to new screen if dragged there + int targetScreen = Kephal::ScreenUtils::screenId(me->screenPos()); + //kDebug() << "Moving panel from screen" << containment()->screen() << "to screen" << targetScreen; + m_containment->setScreen(targetScreen); + return false; + } + + //create a dead zone so you can go across the middle without having it hop to one side + float dzFactor = 0.35; + QPoint offset = QPoint(screenGeom.width()*dzFactor,screenGeom.height()*dzFactor); + QRect deadzone = QRect(screenGeom.topLeft()+offset, screenGeom.bottomRight()-offset); + if (deadzone.contains(me->screenPos())) { + //kDebug() << "In the deadzone:" << deadzone; + return false; + } + + const Plasma::Location oldLocation = m_containment->location(); + Plasma::Location newLocation = oldLocation; + float screenAspect = float(screenGeom.height())/screenGeom.width(); + + /* Use diagonal lines so we get predictable behavior when moving the panel + * y=topleft.y+(x-topleft.x)*aspectratio topright < bottomleft + * y=bottomleft.y-(x-topleft.x)*aspectratio topleft < bottomright + */ + if (me->screenPos().y() < screenGeom.y()+(me->screenPos().x()-screenGeom.x())*screenAspect) { + if (me->screenPos().y() < screenGeom.bottomLeft().y()-(me->screenPos().x()-screenGeom.x())*screenAspect) { + if (m_containment->location() == Plasma::TopEdge) { + return false; + } else { + newLocation = Plasma::TopEdge; + } + } else if (m_containment->location() == Plasma::RightEdge) { + return false; + } else { + newLocation = Plasma::RightEdge; + } + } else { + if (me->screenPos().y() < screenGeom.bottomLeft().y()-(me->screenPos().x()-screenGeom.x())*screenAspect) { + if (m_containment->location() == Plasma::LeftEdge) { + return false; + } else { + newLocation = Plasma::LeftEdge; + } + } else if(m_containment->location() == Plasma::BottomEdge) { + return false; + } else { + newLocation = Plasma::BottomEdge; + } + } + + m_containment->setLocation(newLocation); + + } else if (watched == m_resizeButton && event->type() == QEvent::GraphicsSceneMouseMove) { + QGraphicsSceneMouseEvent *me = static_cast(event); + QPointF deltaPos(me->screenPos() - me->lastScreenPos()); + + m_containment->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + + switch (m_containment->location()) { + case Plasma::LeftEdge: + + m_containment->setMinimumWidth(qBound((qreal)KIconLoader::SizeSmall, m_containment->size().width() + deltaPos.x(), (qreal)(KIconLoader::SizeEnormous*2))); + m_containment->setMaximumWidth(m_containment->minimumWidth()); + + break; + case Plasma::RightEdge: + + m_containment->setMinimumWidth(qBound((qreal)KIconLoader::SizeSmall, m_containment->size().width() - deltaPos.x(), (qreal)(KIconLoader::SizeEnormous*2))); + m_containment->setMaximumWidth(m_containment->minimumWidth()); + break; + case Plasma::TopEdge: + + m_containment->setMinimumHeight(qBound((qreal)KIconLoader::SizeSmall, m_containment->size().height() + deltaPos.y(), (qreal)(KIconLoader::SizeEnormous*2))); + m_containment->setMaximumHeight(m_containment->minimumHeight()); + break; + case Plasma::BottomEdge: + + m_containment->setMinimumHeight(qBound((qreal)KIconLoader::SizeSmall, m_containment->size().height() - deltaPos.y(), (qreal)(KIconLoader::SizeEnormous*2))); + m_containment->setMaximumHeight(m_containment->minimumHeight()); + break; + default: + break; + } + } + return Plasma::Dialog::eventFilter(watched, event); +} + +#include "netpanelcontroller.moc" diff --git a/plasma/netbook/shell/netpanelcontroller.h b/plasma/netbook/shell/netpanelcontroller.h new file mode 100644 index 00000000..7fcfec6f --- /dev/null +++ b/plasma/netbook/shell/netpanelcontroller.h @@ -0,0 +1,65 @@ +/* + * Copyright 2009 Marco Martin + * + * 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, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NETPANELCONTROLLER_H +#define NETPANELCONTROLLER_H + +#include + +namespace Plasma +{ + class Containment; + class ToolButton; + class Svg; + class View; +} + +class QGraphicsWidget; +class QGraphicsLinearLayout; + +class NetView; + +class NetPanelController : public Plasma::Dialog +{ + Q_OBJECT +public: + NetPanelController(QWidget *parent = 0, NetView *view = 0, Plasma::Containment *containment = 0); + ~NetPanelController(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + void updateFormFactor(); + void resizeEvent(QResizeEvent *e); + +private Q_SLOTS: + void updatePosition(); + +private: + Plasma::Containment *m_containment; + Plasma::View *m_view; + QGraphicsWidget *m_mainWidget; + QGraphicsLinearLayout *m_layout; + Plasma::ToolButton *m_moveButton; + Plasma::ToolButton *m_resizeButton; + Plasma::ToolButton *m_autoHideButton; + Plasma::ToolButton *m_watched; + Plasma::Svg *m_iconSvg; +}; + +#endif diff --git a/plasma/netbook/shell/nettoolbox/CMakeLists.txt b/plasma/netbook/shell/nettoolbox/CMakeLists.txt new file mode 100644 index 00000000..74c3c30a --- /dev/null +++ b/plasma/netbook/shell/nettoolbox/CMakeLists.txt @@ -0,0 +1,15 @@ +project(plasma-nettoolbox) + + +set(nettoolbox_SRCS nettoolbox.cpp) + + +kde4_add_plugin(plasma_toolbox_nettoolbox ${nettoolbox_SRCS}) +target_link_libraries(plasma_toolbox_nettoolbox + ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS}) + +install(TARGETS plasma_toolbox_nettoolbox + DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasma-toolbox-nettoolbox.desktop + DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasma/netbook/shell/nettoolbox/Messages.sh b/plasma/netbook/shell/nettoolbox/Messages.sh new file mode 100644 index 00000000..f3a944ea --- /dev/null +++ b/plasma/netbook/shell/nettoolbox/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_toolbox_nettoolbox.pot diff --git a/plasma/netbook/shell/nettoolbox/nettoolbox.cpp b/plasma/netbook/shell/nettoolbox/nettoolbox.cpp new file mode 100644 index 00000000..0f096808 --- /dev/null +++ b/plasma/netbook/shell/nettoolbox/nettoolbox.cpp @@ -0,0 +1,566 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "nettoolbox.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + + +class ToolContainer : public QGraphicsWidget +{ +public: + ToolContainer(QGraphicsWidget *parent) + : QGraphicsWidget(parent) + { + m_itemBackground = new Plasma::ItemBackground(this); + m_itemBackground->hide(); + + m_background = new Plasma::FrameSvg(this); + m_background->setImagePath("widgets/frame"); + m_background->setElementPrefix("raised"); + setLocation(Plasma::BottomEdge); + setAcceptHoverEvents(true); + } + + ~ToolContainer() + { + } + + void setLocation(Plasma::Location location) + { + m_location = location; + switch (location) { + case Plasma::TopEdge: + m_background->setEnabledBorders(Plasma::FrameSvg::BottomBorder); + break; + case Plasma::BottomEdge: + m_background->setEnabledBorders(Plasma::FrameSvg::TopBorder); + break; + case Plasma::LeftEdge: + m_background->setEnabledBorders(Plasma::FrameSvg::RightBorder); + break; + case Plasma::RightEdge: + m_background->setEnabledBorders(Plasma::FrameSvg::LeftBorder); + break; + default: + m_background->setEnabledBorders(Plasma::FrameSvg::AllBorders); + break; + } + qreal left, top, right, bottom; + m_background->getMargins(left, top, right, bottom); + setContentsMargins(left, top, right, bottom); + } + + Plasma::ItemBackground *itemBackground() const + { + return m_itemBackground; + } + + Plasma::Location location() const + { + return m_location; + } + + void hoverEnterEvent(QGraphicsSceneHoverEvent *event) + { + event->accept(); + } + + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) + { + Q_UNUSED(event); + m_itemBackground->hide(); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + Q_UNUSED(option) + Q_UNUSED(widget) + + m_background->paintFrame(painter); + } + +protected: + void resizeEvent(QGraphicsSceneResizeEvent *event) + { + m_background->resizeFrame(event->newSize()); + } + + void mousePressEvent(QGraphicsSceneMouseEvent *event) + { + event->accept(); + } + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const + { + QSizeF hint = QGraphicsWidget::sizeHint(which, constraint); + + if (which == Qt::PreferredSize) { + qreal left, top, right, bottom; + m_itemBackground->getContentsMargins(&left, &top, &right, &bottom); + + if (m_location == Plasma::TopEdge) { + hint.setHeight(KIconLoader::SizeSmallMedium + m_background->marginSize(Plasma::BottomMargin) + top + bottom); + } else if (m_location == Plasma::BottomEdge) { + hint.setHeight(KIconLoader::SizeSmallMedium + m_background->marginSize(Plasma::TopMargin) + top + bottom); + } + } + + return hint; + } + + bool eventFilter(QObject *watched, QEvent *event) + { + Plasma::IconWidget *icon = qobject_cast(watched); + if (icon) { + if (event->type() == QEvent::GraphicsSceneHoverEnter) { + m_itemBackground->setTargetItem(icon); + } else if (event->type() == QEvent::Show) { + //force the newly shown icon to have a sensible size + icon->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + layout()->invalidate(); + } else if (event->type() == QEvent::Hide) { + if (m_location == Plasma::TopEdge || m_location == Plasma::BottomEdge) { + icon->setMaximumWidth(0); + } else { + icon->setMaximumHeight(0); + } + layout()->invalidate(); + } + } + return false; + } + + +private: + Plasma::FrameSvg *m_background; + Plasma::ItemBackground *m_itemBackground; + Plasma::Location m_location; +}; + +NetToolBox::NetToolBox(Plasma::Containment *parent) + : Plasma::AbstractToolBox(parent) +{ + init(); +} + +NetToolBox::NetToolBox(QObject *parent, const QVariantList &args) + : AbstractToolBox(parent, args) +{ + init(); +} + +NetToolBox::~NetToolBox() +{ +} + +void NetToolBox::init() +{ + m_containment = containment(); + Q_ASSERT(m_containment); + + m_icon = KIcon("plasma"); + m_closeIcon = KIcon("dialog-close"); + m_iconSize = QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall); + m_animHighlightFrame = 0; + m_hovering = false; + m_showing = false; + m_location = Plasma::BottomEdge; + m_newToolsPosition = 0; + + setZValue(9000); + resize(KIconLoader::SizeMedium, KIconLoader::SizeMedium); + setAcceptHoverEvents(true); + + m_toolContainer = new ToolContainer(this); + m_toolContainer->hide(); + m_toolContainer->setFlag(QGraphicsWidget::ItemStacksBehindParent); + m_toolContainerLayout = new QGraphicsLinearLayout(m_toolContainer); + m_toolContainerLayout->addStretch(); + + m_background = new Plasma::Svg(this); + m_background->setImagePath("widgets/toolbox"); + m_background->setContainsMultipleImages(true); + setLocation(Plasma::BottomEdge); + + m_containment->installEventFilter(this); + connect(m_containment, SIGNAL(geometryChanged()), this, SLOT(containmentGeometryChanged())); + containmentGeometryChanged(); + + slideAnim = Plasma::Animator::create(Plasma::Animator::SlideAnimation, this); + slideAnim->setProperty("movementDirection", Plasma::Animation::MoveAny); + connect(slideAnim, SIGNAL(stateChanged(QAbstractAnimation::State, + QAbstractAnimation::State)), + this, SLOT(onMovement(QAbstractAnimation::State,QAbstractAnimation::State))); + connect(slideAnim, SIGNAL(finished()), this, SLOT(movementFinished())); + + anim = new QPropertyAnimation(this, "highlight", this); + anim->setDuration(250); + anim->setStartValue(0); + anim->setEndValue(1); +} + +bool NetToolBox::isShowing() const +{ + return m_showing; +} + +void NetToolBox::setShowing(const bool show) +{ + m_showing = show; + if (show != m_toolContainer->isVisible()) { + emit toggled(); + emit visibilityChanged(show); + } + + if (show) { + qreal left, top, right, bottom = 0; + + switch (m_location) { + case Plasma::TopEdge: + m_toolContainer->setPos(boundingRect().topLeft() - QPoint(0, m_toolContainer->size().height())); + slideAnim->setProperty("distancePointF", QPointF(0, m_toolContainer->size().height())); + top = m_toolContainer->size().height(); + break; + case Plasma::LeftEdge: + m_toolContainer->setPos(boundingRect().topLeft() - QPoint(m_toolContainer->size().width(), 0)); + slideAnim->setProperty("distancePointF", QPointF(m_toolContainer->size().width(), 0)); + left = m_toolContainer->size().width(); + break; + case Plasma::RightEdge: + m_toolContainer->setPos(boundingRect().topRight()); + slideAnim->setProperty("distancePointF", QPointF(-m_toolContainer->size().width(), 0)); + right = m_toolContainer->size().width(); + break; + case Plasma::BottomEdge: + default: + m_toolContainer->setPos(boundingRect().bottomLeft()); + slideAnim->setProperty("distancePointF", QPointF(0, -m_toolContainer->size().height())); + bottom = m_toolContainer->size().height(); + break; + } + + slideAnim->setTargetWidget(m_toolContainer); + slideAnim->setDirection(QAbstractAnimation::Forward); + slideAnim->start(); + + if (m_containment->layout()) { + m_containment->layout()->setContentsMargins(left, top, right, bottom); + } + + } else { + slideAnim->setDirection(QAbstractAnimation::Backward); + slideAnim->start(); + + if (m_containment->layout()) { + m_containment->layout()->setContentsMargins(0, 0, 0, 0); + } + } +} + + +void NetToolBox::addTool(QAction *action) +{ + Plasma::IconWidget *button = new Plasma::IconWidget(this); + button->setOrientation(Qt::Horizontal); + button->setTextBackgroundColor(QColor()); + button->installEventFilter(m_toolContainer); + button->setAction(action); + + qreal left, top, right, bottom; + m_toolContainer->itemBackground()->getContentsMargins(&left, &top, &right, &bottom); + button->setContentsMargins(left, top, right, bottom); + + if (m_location == Plasma::LeftEdge || m_location == Plasma::RightEdge) { + button->setOrientation(Qt::Vertical); + } else { + button->setOrientation(Qt::Horizontal); + } + + m_actionButtons[action] = button; + + if (action == m_containment->action("remove")) { + m_toolContainerLayout->addItem(button); + --m_newToolsPosition; + } else if (action == m_containment->action("add page")) { + m_toolContainerLayout->insertItem(m_newToolsPosition+1, button); + --m_newToolsPosition; + } else if (action == m_containment->action("add applications")) { + m_toolContainerLayout->insertItem(1, button); + --m_newToolsPosition; + } else { + m_toolContainerLayout->insertItem(m_newToolsPosition, button); + } + ++m_newToolsPosition; + + if (m_toolContainerLayout->count() == 1) { + m_toolContainer->itemBackground()->setTargetItem(button); + } +} + +void NetToolBox::removeTool(QAction *action) +{ + if (m_actionButtons.contains(action)) { + Plasma::IconWidget *button = m_actionButtons.value(action); + m_toolContainerLayout->removeItem(button); + m_actionButtons.remove(action); + button->deleteLater(); + if (action != m_containment->action("remove") || + action != m_containment->action("add page")) { + --m_newToolsPosition; + } + } +} + +QRectF NetToolBox::expandedGeometry() const +{ + QRectF containerGeometry = m_toolContainer->boundingRect(); + containerGeometry.moveBottomLeft(geometry().bottomLeft()); + return containerGeometry; +} + +void NetToolBox::setLocation(Plasma::Location location) +{ + m_location = location; + m_toolContainer->setLocation(location); + if (location == Plasma::LeftEdge || location == Plasma::RightEdge) { + m_toolContainerLayout->setOrientation(Qt::Vertical); + m_toolContainerLayout->setContentsMargins(0, size().height(), 0, 0); + foreach (Plasma::IconWidget *icon, m_actionButtons) { + icon->setOrientation(Qt::Vertical); + } + } else { + m_toolContainerLayout->setOrientation(Qt::Horizontal); + m_toolContainerLayout->setContentsMargins(size().width(), 0, 0, 0); + foreach (Plasma::IconWidget *icon, m_actionButtons) { + icon->setOrientation(Qt::Horizontal); + } + } + containmentGeometryChanged(); +} + +Plasma::Location NetToolBox::location() const +{ + return m_location; +} + +void NetToolBox::containmentGeometryChanged() +{ + m_toolContainerLayout->invalidate(); + m_toolContainerLayout->activate(); + + switch (m_location) { + case Plasma::TopEdge: + m_toolContainer->resize(m_containment->size().width(), m_toolContainer->effectiveSizeHint(Qt::PreferredSize).height()); + m_toolContainer->setPos(0, 0); + setPos(m_containment->contentsRect().topLeft()); + break; + case Plasma::BottomEdge: + m_toolContainer->resize(m_containment->size().width(), m_toolContainer->effectiveSizeHint(Qt::PreferredSize).height()); + m_toolContainer->setPos(0, size().height()-m_toolContainer->size().height()); + setPos(m_containment->contentsRect().left(), m_containment->contentsRect().bottom()-size().height()+1); + break; + case Plasma::LeftEdge: + m_toolContainer->resize(m_toolContainer->effectiveSizeHint(Qt::PreferredSize).width(), m_containment->size().height()); + m_toolContainer->setPos(0, 0); + setPos(m_containment->contentsRect().topLeft()); + break; + case Plasma::RightEdge: + m_toolContainer->resize(m_toolContainer->effectiveSizeHint(Qt::PreferredSize).width(), m_containment->size().height()); + m_toolContainer->setPos(size().width()-m_toolContainer->size().width(), 0); + setPos(m_containment->contentsRect().right()-size().width()+1, m_containment->contentsRect().top()); + break; + default: + m_toolContainer->resize(m_toolContainer->effectiveSizeHint(Qt::PreferredSize)); + m_toolContainer->setPos(m_containment->contentsRect().left(), size().height()-m_toolContainer->size().height()); + break; + } +} + +void NetToolBox::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + event->accept(); +} + +void NetToolBox::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event) + setShowing(!isShowing()); +} + +void NetToolBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option) + Q_UNUSED(widget) + QPoint iconPos; + QString svgElement; + + switch (m_location) { + case Plasma::TopEdge: + case Plasma::LeftEdge: + iconPos = QPoint(2, 2); + svgElement = "desktop-northwest"; + break; + case Plasma::RightEdge: + iconPos = QPoint(size().width() - m_iconSize.width() - 2, 2); + svgElement = "desktop-northeast"; + break; + case Plasma::BottomEdge: + default: + iconPos = QPoint(2, size().height() - m_iconSize.height() - 2); + svgElement = "desktop-southwest"; + break; + } + + m_background->paint(painter, boundingRect(), svgElement); + + KIcon icon; + if (isShowing()) { + icon = m_closeIcon; + } else { + icon = m_icon; + } + + if (qFuzzyCompare(qreal(1.0), m_animHighlightFrame)) { + icon.paint(painter, QRect(iconPos, m_iconSize)); + } else if (qFuzzyCompare(qreal(1.0), 1 + m_animHighlightFrame)) { + icon.paint(painter, QRect(iconPos, m_iconSize), + Qt::AlignCenter, QIcon::Disabled, QIcon::Off); + } else { + QPixmap disabled = icon.pixmap(m_iconSize, QIcon::Disabled, QIcon::Off); + QPixmap enabled = icon.pixmap(m_iconSize); + QPixmap result = Plasma::PaintUtils::transition( + icon.pixmap(m_iconSize, QIcon::Disabled, QIcon::Off), + icon.pixmap(m_iconSize), m_animHighlightFrame); + painter->drawPixmap(QRect(iconPos, m_iconSize), result); + } +} + +bool NetToolBox::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == m_containment && event->type() == QEvent::ContentsRectChange) { + qreal left, top, right, bottom; + m_containment->getContentsMargins(&left, &top, &right, &bottom); + + //left preferred over right + if (left > top && left > right && left > bottom) { + setLocation(Plasma::RightEdge); + } else if (right > top && right >= left && right > bottom) { + setLocation(Plasma::LeftEdge); + } else if (bottom > top && bottom > left && bottom > right) { + setLocation(Plasma::TopEdge); + //bottom is the default + } else { + setLocation(Plasma::BottomEdge); + } + } + + return AbstractToolBox::eventFilter(watched, event); +} + +void NetToolBox::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + if (isShowing() || m_hovering) { + QGraphicsWidget::hoverEnterEvent(event); + return; + } + + highlight(true); + + QGraphicsWidget::hoverEnterEvent(event); +} + +void NetToolBox::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + //kDebug() << event->pos() << event->scenePos() + // << d->toolBacker->rect().contains(event->scenePos().toPoint()); + if (!m_hovering || isShowing()) { + QGraphicsWidget::hoverLeaveEvent(event); + return; + } + + highlight(false); + + QGraphicsWidget::hoverLeaveEvent(event); +} + +void NetToolBox::highlight(bool highlighting) +{ + if (m_hovering == highlighting) { + return; + } + + m_hovering = highlighting; + + if (anim->state() != QAbstractAnimation::Stopped) { + anim->stop(); + } + + anim->start(); +} + +void NetToolBox::setHighlight(qreal progress) +{ + if (m_hovering) { + m_animHighlightFrame = progress; + } else { + m_animHighlightFrame = 1.0 - progress; + } + + update(); +} + +qreal NetToolBox::highlight() +{ + return m_animHighlightFrame; +} + +void NetToolBox::movementFinished() +{ + if (slideAnim) { + if (slideAnim->property("direction") == QAbstractAnimation::Forward) { + slideAnim->setProperty("direction", QAbstractAnimation::Backward); + } else { + slideAnim->setProperty("direction", QAbstractAnimation::Forward); + } + } + m_toolContainer->setVisible(m_showing); +} + +void NetToolBox::onMovement(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) +{ + Q_UNUSED(newState); + Q_UNUSED(oldState); + m_toolContainer->show(); +} + +#include "nettoolbox.moc" diff --git a/plasma/netbook/shell/nettoolbox/nettoolbox.h b/plasma/netbook/shell/nettoolbox/nettoolbox.h new file mode 100644 index 00000000..b17f5798 --- /dev/null +++ b/plasma/netbook/shell/nettoolbox/nettoolbox.h @@ -0,0 +1,109 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NETTOOLBOX_H +#define NETTOOLBOX_H + +#include +#include +#include + +#include +#include + + +class QGraphicsLinearLayout; + +namespace Plasma +{ + class Containment; + class IconWidget; + class Svg; +} + +class ToolContainer; + +class NetToolBox : public Plasma::AbstractToolBox +{ + Q_OBJECT + Q_PROPERTY(bool showing READ isShowing WRITE setShowing ) + Q_PROPERTY(qreal highlight READ highlight WRITE setHighlight) +public: + explicit NetToolBox(Plasma::Containment *parent = 0); + explicit NetToolBox(QObject *parent, const QVariantList &args); + ~NetToolBox(); + + bool isShowing() const; + void setShowing(const bool show); + + /** + * create a toolbox tool from the given action + * @p action the action to associate the tool with + */ + void addTool(QAction *action); + /** + * remove the tool associated with this action + */ + void removeTool(QAction *action); + + QRectF expandedGeometry() const; + + void setLocation(Plasma::Location location); + Plasma::Location location() const; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +protected: + void init(); + + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + bool eventFilter(QObject *watched, QEvent *event); + +private Q_SLOTS: + void containmentGeometryChanged(); + void setHighlight(qreal progress); + qreal highlight(); + void movementFinished(); + void onMovement(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); + +private: + void highlight(bool highlighting); + ToolContainer *m_toolContainer; + QGraphicsLinearLayout *m_toolContainerLayout; + QHash m_actionButtons; + Plasma::Containment *m_containment; + Plasma::Svg *m_background; + KIcon m_icon; + KIcon m_closeIcon; + QSize m_iconSize; + Plasma::Animation *slideAnim; + QPropertyAnimation *anim; + qreal m_animHighlightFrame; + bool m_hovering; + bool m_showing; + Plasma::Location m_location; + int m_newToolsPosition; +}; + +K_EXPORT_PLASMA_TOOLBOX(nettoolbox, NetToolBox) + +#endif diff --git a/plasma/netbook/shell/nettoolbox/plasma-toolbox-nettoolbox.desktop b/plasma/netbook/shell/nettoolbox/plasma-toolbox-nettoolbox.desktop new file mode 100644 index 00000000..3df2e8cf --- /dev/null +++ b/plasma/netbook/shell/nettoolbox/plasma-toolbox-nettoolbox.desktop @@ -0,0 +1,124 @@ +[Desktop Entry] +Comment=Default toolbox for the netbook shell +Comment[ast]=Caxa de ferramientes predeterminada de la shell pa netbooks +Comment[bg]=Стандартни инструменти за обвивка на нетбук +Comment[bs]=Podrazumijevana alatnica za netbuk školjku +Comment[ca]=Quadre d'eines per defecte per a l'àrea de treball dels ordinadors ultraportàtils +Comment[ca@valencia]=Quadre d'eines per defecte per a l'àrea de treball dels ordinadors ultraportàtils +Comment[cs]=Výchozí nástroje pro netbook shell +Comment[da]=Standard værktøjskasse til netbook-skallen +Comment[de]=Standard-Werkzeugkasten für die Plasma-Netbook-Oberfläche +Comment[el]=Προκαθορισμένη εργαλειοθήκη για το κέλυφος netbook +Comment[en_GB]=Default toolbox for the netbook shell +Comment[es]=Caja de herramientas predeterminada de la shell para netbooks +Comment[et]=Väikesülearvutikooriku vaikimisi tööriistakast +Comment[eu]=Netbooken shell-erako tresna-kutxa lehenetsia +Comment[fi]=Netbook-kuoren oletustyökalupakki +Comment[fr]=Boîte à outils par défaut pour le shell des ultra portables +Comment[gl]=A caixa de ferramentas predeterminada da shell netbook +Comment[he]=ארגז־כלים ברירת המחדל עבור מעטפת הנטבוק +Comment[hr]=Zadana alatna kutija za netbook ljusku +Comment[hu]=Alapértelmezett eszközkészlet a netbook héjhoz +Comment[ia]=Instrumentario predefinite pro le shell del netbook +Comment[is]=Sjálfgefið verkfærasafn fyrir smáfartölvuskelina +Comment[ja]=ネットブックシェル用の標準ツールボックス +Comment[kk]=Нетбук ортасының әдетті құралдар панелі +Comment[km]=ប្រអប់​ឧបករណ៍​លំនាំដើម សម្រាប់​សែល netbook +Comment[ko]=넷북 셸을 위한 기본 도구 상자 +Comment[lt]=Numatytoji netbook apvalkalo įrankinė +Comment[lv]=Noklusētā rīkkaste mazdatoru čaulai +Comment[mr]=नेटबूक शेलसाठी मूलभूत साधने +Comment[nb]=Standard verktøykasse for netbook-skallet +Comment[nds]=Standardwarktüüchkist för de Nettbook-Konsool +Comment[nl]=Standaard hulpmiddelen voor de netbook-shell +Comment[pa]=ਨੈੱਟਬੁੱਕ ਸ਼ੈੱਲ ਲਈ ਡਿਫਾਲਟ ਟੂਲਬਾਕਸ +Comment[pl]=Domyślny przybornik dla powłoki netbook +Comment[pt]=A barra predefinida para a consola do Netbook +Comment[pt_BR]=A barra padrão para o shell do netbook +Comment[ro]=Trusă de unelte implicită pentru învelișul de netbook +Comment[ru]=Стандартные инструменты настройки оболочки для нетбуков +Comment[sk]=Štandardné nástroje pre netbook shell +Comment[sl]=Privzeti nabor orodij za Namizno lupino Plasma za male prenosnike +Comment[sr]=Подразумевана алатница за нетбук шкољку +Comment[sr@ijekavian]=Подразумијевана алатница за нетбук шкољку +Comment[sr@ijekavianlatin]=Podrazumijevana alatnica za netbuk školjku +Comment[sr@latin]=Podrazumevana alatnica za netbuk školjku +Comment[sv]=Standardverktyg för nätdatorskalet +Comment[th]=กล่องเครื่องมือปริยายสำหรับเชลล์ของเน็ตบุ้ค +Comment[tr]=Netbook kabuğu için öntanımlı araçkutusu +Comment[ug]=تور كومپيۇتېر shell ئۈچۈن كۆڭۈلدىكى قورال قۇتىسى +Comment[uk]=Типовий набір інструментів для оболонки субноутбуків +Comment[vi]=Hộp công cụ mặc định cho vỏ netbook +Comment[wa]=Usteye prémetowe pol shell di poirtåve éndjolete +Comment[x-test]=xxDefault toolbox for the netbook shellxx +Comment[zh_CN]=上网本外壳的默认工具 +Comment[zh_TW]=netbook shell 的預設工具盒 +Icon=plasma +Name=Net toolbox +Name[ast]=Caxa de ferramientes netbook +Name[bs]=Netbuk alatnica +Name[ca]=Quadre d'eines de la xarxa +Name[ca@valencia]=Quadre d'eines de la xarxa +Name[cs]=Nástroje sítě +Name[da]=Netværktøjskasse +Name[de]=Werkzeugkasten für Netbooks +Name[el]=Εργαλειοθήκη δικτύου +Name[en_GB]=Net toolbox +Name[es]=Caja de herramientas netbook +Name[et]=Väikesülearvuti tööriistakast +Name[eu]=Netbooketarako tresna-kutxa +Name[fi]=Verkkotyökalupakki +Name[fr]=Boîte à outils réseau +Name[ga]=Bosca uirlisí líonra +Name[gl]=Caixa de ferramentas de rede +Name[he]=ארגז־כלי רשת +Name[hr]=Mrežna alatna kutija +Name[hu]=Hálózati eszközkészlet +Name[ia]=Instrumentario de rete +Name[is]=Net-verkfærasafn +Name[ja]=ネットワークツールボックス +Name[kk]=Желі құралдары +Name[km]=ប្រអប់​ឧបករណ៍​បណ្ដាញ +Name[kn]=ಜಾಲ ಉಪಕರಣಪಟ್ಟಿ +Name[ko]=넷북 도구 상자 +Name[lt]=Tinklo įrankinė +Name[lv]=Tīkla rīkkaste +Name[mr]=नेटबूक साधने +Name[nb]=Nettverksverktøykasse +Name[nds]=Nettbook-Warktüüchkist +Name[nl]=Netwerk-hulpmiddelen +Name[pa]=ਨੈੱਟ ਟੂਲਬਾਕਸ +Name[pl]=Przybornik Net +Name[pt]=Barra da rede +Name[pt_BR]=Barra da rede +Name[ro]=Trusă unelte de rețea +Name[ru]=Настройка оболочки для нетбуков +Name[sk]=Nástroje pre netbook +Name[sl]=Orodja za delovno okolje +Name[sr]=Нетбук алатница +Name[sr@ijekavian]=Нетбук алатница +Name[sr@ijekavianlatin]=Netbuk alatnica +Name[sr@latin]=Netbuk alatnica +Name[sv]=Nätverksverktyg +Name[th]=เครื่องมือระบบเครือข่าย +Name[tr]=Ağ araçkutusu +Name[ug]=تور قورال قۇتىسى +Name[uk]=Набір інструментів для субноутбуків +Name[wa]=Boesse ås usteye del rantoele +Name[x-test]=xxNet toolboxxx +Name[zh_CN]=网络工具箱 +Name[zh_TW]=網路工具盒 +Type=Service + +X-KDE-ServiceTypes=Plasma/ToolBox +X-KDE-Library=plasma_toolbox_nettoolbox +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-Email=mart@kde.org +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-Name=org.kde.nettoolbox +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ + diff --git a/plasma/netbook/shell/netview.cpp b/plasma/netbook/shell/netview.cpp new file mode 100644 index 00000000..a7825f36 --- /dev/null +++ b/plasma/netbook/shell/netview.cpp @@ -0,0 +1,338 @@ +/* + * Copyright 2007-2008 Aaron Seigo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "netview.h" +#include "netcorona.h" +#include "netpanelcontroller.h" + +#include +#include + +#ifndef QT_NO_OPENGL +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + +NetView::NetView(Plasma::Containment *containment, int uid, QWidget *parent) + : Plasma::View(containment, uid, parent), + m_panelController(0), + m_configurationMode(false), + m_useGL(false) +{ + setFocusPolicy(Qt::NoFocus); + connectContainment(containment); + + connect(this, SIGNAL(lostContainment()), SLOT(grabContainment())); + //setOptimizationFlags(QGraphicsView::DontSavePainterState); + + setAttribute(Qt::WA_TranslucentBackground, uid == controlBarId()); + + m_containmentSwitchAnimation = new QPropertyAnimation(this, "sceneRect", this); +} + +NetView::~NetView() +{ +} + +void NetView::setUseGL(const bool on) +{ +#ifndef QT_NO_OPENGL + if (on) { + QGLWidget *glWidget = new QGLWidget; + glWidget->setAutoFillBackground(false); + setViewport(glWidget); + } else { + QWidget *widget = new QWidget; + widget->setAutoFillBackground(false); + setViewport(widget); + } +#endif + m_useGL = on; +} + +bool NetView::useGL() const +{ + return m_useGL; +} + +void NetView::connectContainment(Plasma::Containment *containment) +{ + if (!containment) { + return; + } + + connect(containment, SIGNAL(activate()), this, SIGNAL(containmentActivated())); + connect(this, SIGNAL(sceneRectAboutToChange()), this, SLOT(updateGeometry())); + connect(containment, SIGNAL(toolBoxVisibilityChanged(bool)), this, SLOT(updateConfigurationMode(bool))); + connect(containment, SIGNAL(immutabilityChanged(ImmutabilityType)), this, SLOT(immutabilityChanged(ImmutabilityType))); + + QAction *a = containment->action("next containment"); + if (a) { + connect(a, SIGNAL(triggered()), this, SLOT(nextContainment())); + } + a = containment->action("previous containment"); + if (a) { + connect(a, SIGNAL(triggered()), this, SLOT(previousContainment())); + } +} + +void NetView::setContainment(Plasma::Containment *c) +{ + if (containment()) { + disconnect(containment(), 0, this, 0); + + QAction *a = containment()->action("next containment"); + if (a) { + disconnect(a, SIGNAL(triggered()), this, SLOT(nextContainment())); + } + a = containment()->action("previous containment"); + if (a) { + disconnect(a, SIGNAL(triggered()), this, SLOT(previousContainment())); + } + } + + if (containment() && id() == mainViewId()) { + setTrackContainmentChanges(false); + Plasma::WindowEffects::enableBlurBehind(effectiveWinId(), false); + } else if (containment() && id() == controlBarId()) { + Plasma::WindowEffects::enableBlurBehind(effectiveWinId(), true); + } + + Plasma::View::setContainment(c); + connectContainment(c); + updateGeometry(); + + if (containment() && id() == mainViewId()) { + if (c) { + m_containmentSwitchAnimation->setDuration(250); + m_containmentSwitchAnimation->setStartValue(sceneRect()); + m_containmentSwitchAnimation->setEndValue(c->geometry()); + m_containmentSwitchAnimation->start(); + } + setTrackContainmentChanges(true); + } +} + +bool NetView::autoHide() const +{ + return config().readEntry("panelAutoHide", true); +} + +void NetView::setAutoHide(bool hide) +{ + if (hide != autoHide()) { + emit autoHideChanged(hide); + } + config().writeEntry("panelAutoHide", hide); +} + +void NetView::immutabilityChanged(Plasma::ImmutabilityType immutability) +{ + if (m_configurationMode && immutability == Plasma::Mutable) { + updateConfigurationMode(true); + } else if (m_configurationMode) { + updateConfigurationMode(false); + } +} + +// This function is reimplemented from QGraphicsView to work around the problem +// that QPainter::fillRect(QRectF/QRect, QBrush), which QGraphicsView uses, is +// potentially slow when the anti-aliasing hint is set and as implemented won't +// hit accelerated code at all when it isn't set. This implementation avoids +// the problem by using integer coordinates and by using drawTiledPixmap() in +// the case of a texture brush, and fillRect(QRect, QColor) in the case of a +// solid pattern. As an additional optimization it draws the background with +// CompositionMode_Source. +void NetView::drawBackground(QPainter *painter, const QRectF &rect) +{ + if (!testAttribute(Qt::WA_TranslucentBackground)) { + painter->fillRect(rect.toAlignedRect(), Qt::black); + } else { + if (KWindowSystem::compositingActive()) { + painter->setCompositionMode(QPainter::CompositionMode_Source); + painter->fillRect(rect.toAlignedRect(), Qt::transparent); + } else { + Plasma::View::drawBackground(painter, rect); + } + } +} + + +void NetView::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event) + updateGeometry(); + emit geometryChanged(); +} + +bool NetView::event(QEvent *e) +{ + if (e->type() == QEvent::Close) { + //prevent ALT+F4 from killing the shell + e->ignore(); + return true; + } else { + return Plasma::View::event(e); + } +} + +void NetView::screenOwnerChanged(int wasScreen, int isScreen, Plasma::Containment* containment) +{ + kDebug() << "was, is, containment:" << wasScreen << isScreen << (QObject*)containment; + if (containment->containmentType() == Plasma::Containment::PanelContainment) { + // we don't care about panel containments changing screens on us + return; + } + + if (wasScreen == screen() && this->containment() == containment) { + setContainment(0); + } + + if ((isScreen == screen() || screen() == -1) && this->containment( )!= containment) { + setContainment(containment); + } +} + +Plasma::Location NetView::location() const +{ + return containment()->location(); +} + +Plasma::FormFactor NetView::formFactor() const +{ + return containment()->formFactor(); +} + +void NetView::updateGeometry() +{ + Plasma::Containment *c = containment(); + if (!c) { + return; + } + + kDebug() << "New containment geometry is" << c->geometry(); + + switch (c->location()) { + case Plasma::TopEdge: + case Plasma::BottomEdge: + setMinimumWidth(0); + setMaximumWidth(QWIDGETSIZE_MAX); + setFixedHeight(c->size().height()); + emit locationChanged(this); + break; + case Plasma::LeftEdge: + case Plasma::RightEdge: + setMinimumHeight(0); + setMaximumHeight(QWIDGETSIZE_MAX); + setFixedWidth(c->size().width()); + emit locationChanged(this); + break; + //ignore changes in the main view + default: + break; + } + + if (c->size().toSize() != size()) { + c->setMaximumSize(size()); + c->setMinimumSize(size()); + c->resize(size()); + } +} + +void NetView::grabContainment() +{ + + NetCorona *corona = qobject_cast(scene()); + if (!corona) { + kDebug() << "no corona :("; + return; + } + + Plasma::Containment *cont = corona->findFreeContainment(); + if (cont) { + cont->setScreen(screen(), desktop()); + } +} + +void NetView::updateConfigurationMode(bool config) +{ + m_configurationMode = config; + + Plasma::Containment *cont = containment(); + if (config && cont && cont->immutability() == Plasma::Mutable && + (cont->location() != Plasma::Desktop && cont->location() != Plasma::Floating)) { + m_panelController = new NetPanelController(0, this, cont); + } else { + delete m_panelController; + m_panelController = 0; + } +} + +void NetView::nextContainment() +{ + QList containments = containment()->corona()->containments(); + int start = containments.indexOf(containment()); + int i = (start + containments.size() - 1) % containments.size(); + Plasma::Containment *cont = containments.at(i); + + //FIXME this is a *horrible* way of choosing a "previous" containment. + while (i != start) { + if ((cont->location() == Plasma::Desktop || cont->location() == Plasma::Floating) && + cont->screen() == -1) { + break; + } + + if (--i < 0) { + i += containments.size(); + } + cont = containments.at(i); + } + + cont->setScreen(screen(), desktop()); +} + +void NetView::previousContainment() +{ + QList containments = containment()->corona()->containments(); + int start = containments.indexOf(containment()); + int i = (start + 1) % containments.size(); + Plasma::Containment *cont = containments.at(i); + //FIXME this is a *horrible* way of choosing a "next" containment. + while (i != start) { + if ((cont->location() == Plasma::Desktop || cont->location() == Plasma::Floating) && + cont->screen() == -1) { + break; + } + + i = (i + 1) % containments.size(); + cont = containments.at(i); + } + + cont->setScreen(screen(), desktop()); +} + +#include "netview.moc" + diff --git a/plasma/netbook/shell/netview.h b/plasma/netbook/shell/netview.h new file mode 100644 index 00000000..ef691aae --- /dev/null +++ b/plasma/netbook/shell/netview.h @@ -0,0 +1,89 @@ +/* + * Copyright 2007-2008 Aaron Seigo + * + * 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, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NETVIEW_H +#define NETVIEW_H + +#include +#include + +class NetPanelController; +class QPropertyAnimation; + +namespace Plasma +{ + class Containment; +} // namespace Plasma + +class NetView : public Plasma::View +{ + Q_OBJECT + +public: + typedef Plasma::ImmutabilityType ImmutabilityType; + NetView(Plasma::Containment *containment, int uid, QWidget *parent = 0); + ~NetView(); + + /** + * hook up all needed signals to a containment + */ + void connectContainment(Plasma::Containment *containment); + + Plasma::Location location() const; + Plasma::FormFactor formFactor() const; + KConfigGroup config() const {return Plasma::View::config();} + bool autoHide() const; + + static int mainViewId() { return 1; } + static int controlBarId() { return 2; } + + void setUseGL(const bool on); + bool useGL() const; + + +public Q_SLOTS: + void setContainment(Plasma::Containment *containment); + void screenOwnerChanged(int wasScreen, int isScreen, Plasma::Containment* containment); + void updateGeometry(); + void grabContainment(); + void updateConfigurationMode(bool config); + void setAutoHide(bool autoHide); + void immutabilityChanged(ImmutabilityType immutability); + void nextContainment(); + void previousContainment(); + +Q_SIGNALS: + void locationChanged(const NetView *view); + void geometryChanged(); + void containmentActivated(); + void autoHideChanged(bool autoHide); + +protected: + void drawBackground(QPainter *painter, const QRectF &rect); + void resizeEvent(QResizeEvent *event); + bool event(QEvent *e); + +private: + NetPanelController *m_panelController; + bool m_configurationMode; + bool m_useGL; + QPropertyAnimation *m_containmentSwitchAnimation; +}; + +#endif // multiple inclusion guard diff --git a/plasma/netbook/shell/plasmaapp.cpp b/plasma/netbook/shell/plasmaapp.cpp new file mode 100644 index 00000000..c364238b --- /dev/null +++ b/plasma/netbook/shell/plasmaapp.cpp @@ -0,0 +1,1306 @@ +/* + * Copyright 2006-2008 Aaron Seigo + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "plasmaapp.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include "netcorona.h" +#include "netview.h" + +#include "widgetsexplorer/widgetexplorer.h" +#include "plasmagenericshell/backgrounddialog.h" + +#ifdef Q_WS_X11 +#include +#include +#include +#endif + +PlasmaApp* PlasmaApp::self() +{ + if (!kapp) { + return new PlasmaApp(); + } + + return qobject_cast(kapp); +} + + +class GlowBar : public QWidget +{ +public: + GlowBar(Plasma::Direction direction, const QRect &triggerZone) + : QWidget(0), + m_strength(0.3), + m_svg(new Plasma::Svg(this)), + m_direction(direction) + { + setAttribute(Qt::WA_TranslucentBackground); + KWindowSystem::setOnAllDesktops(winId(), true); + unsigned long state = NET::Sticky | NET::StaysOnTop | NET::KeepAbove; + KWindowSystem::setState(winId(), state); + KWindowSystem::setType(winId(), NET::Dock); + m_svg->setImagePath("widgets/glowbar"); + +#ifdef Q_WS_X11 + QRegion region(QRect(0,0,1,1)); + XShapeCombineRegion(QX11Info::display(), winId(), ShapeInput, 0, 0, + region.handle(), ShapeSet); +#endif + + QPalette pal = palette(); + pal.setColor(backgroundRole(), Qt::transparent); + setPalette(pal); + + QRect glowGeom = triggerZone; + QSize s = sizeHint(); + switch (m_direction) { + case Plasma::Up: + glowGeom.setY(glowGeom.y() - s.height() + 1); + // fallthrough + case Plasma::Down: + glowGeom.setHeight(s.height()); + break; + case Plasma::Left: + glowGeom.setX(glowGeom.x() - s.width() + 1); + // fallthrough + case Plasma::Right: + glowGeom.setWidth(s.width()); + break; + } + + //kDebug() << "glow geom is" << glowGeom << "from" << triggerZone; + setGeometry(glowGeom); + m_buffer = QPixmap(size()); + } + + void paintEvent(QPaintEvent* e) + { + Q_UNUSED(e) + QPixmap pixmap; + const QSize glowRadius = m_svg->elementSize("hint-glow-radius"); + QPoint pixmapPosition(0, 0); + + m_buffer.fill(QColor(0, 0, 0, int(qreal(255)*m_strength))); + QPainter p(&m_buffer); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + + switch (m_direction) { + case Plasma::Down: + pixmap = m_svg->pixmap("bottom"); + pixmapPosition = QPoint(0, -glowRadius.height()); + break; + case Plasma::Up: + pixmap = m_svg->pixmap("top"); + break; + case Plasma::Right: + pixmap = m_svg->pixmap("right"); + pixmapPosition = QPoint(-glowRadius.width(), 0); + break; + case Plasma::Left: + pixmap = m_svg->pixmap("left"); + break; + } + + if (m_direction == Plasma::Left || m_direction == Plasma::Right) { + p.drawTiledPixmap(QRect(0, pixmapPosition.x(), pixmap.width(), height()), pixmap); + } else { + p.drawTiledPixmap(QRect(0, pixmapPosition.y(), width(), pixmap.height()), pixmap); + } + + p.end(); + p.begin(this); + p.drawPixmap(QPoint(0, 0), m_buffer); + } + + QSize sizeHint() const + { + return m_svg->elementSize("bottomright") - m_svg->elementSize("hint-glow-radius"); + } + + bool event(QEvent *event) + { + if (event->type() == QEvent::Paint) { + QPainter p(this); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(rect(), Qt::transparent); + } + return QWidget::event(event); + } + + void updateStrength(QPoint point) + { + QPoint localPoint = mapFromGlobal(point); + + qreal newStrength; + switch (m_direction) { + case Plasma::Up: // when the panel is at the bottom. + newStrength = 1 - qreal(-localPoint.y())/m_triggerDistance; + break; + case Plasma::Right: + newStrength = 1 - qreal(localPoint.x())/m_triggerDistance; + break; + case Plasma::Left: // when the panel is right-aligned + newStrength = 1 - qreal(-localPoint.x())/m_triggerDistance; + break; + case Plasma::Down: + default: + newStrength = 1- qreal(localPoint.y())/m_triggerDistance; + break; + } + if (qAbs(newStrength - m_strength) > 0.01 && newStrength >= 0 && newStrength <= 1) { + m_strength = newStrength; + update(); + } + } + + +private: + static const int m_triggerDistance = 30; + qreal m_strength; + Plasma::Svg *m_svg; + Plasma::Direction m_direction; + QPixmap m_buffer; +}; + + +class ShadowWindow : public QWidget +{ +public: + ShadowWindow(NetView *panel) + : QWidget(0), + m_panel(panel), + m_valid(false) + { + setAttribute(Qt::WA_TranslucentBackground); + setAttribute(Qt::WA_NoSystemBackground, false); + setAutoFillBackground(false); +#ifdef Q_WS_X11 + QRegion region(QRect(0,0,1,1)); + XShapeCombineRegion(QX11Info::display(), winId(), ShapeInput, 0, 0, + region.handle(), ShapeSet); +#endif + + m_shadow = new Plasma::FrameSvg(this); + } + + void setSvg(const QString &path) + { + m_shadow->setImagePath(path); + + if (!m_shadow->hasElementPrefix("shadow")) { + hide(); + m_valid = false; + } else { + m_valid = true; + } + + m_shadow->setElementPrefix("shadow"); + + adjustMargins(geometry()); + } + + bool isValid() const + { + return m_valid; + } + + void adjustMargins(const QRect &geo) + { + QRect screenRect = Kephal::ScreenUtils::screenGeometry(m_panel->screen()); + + Plasma::FrameSvg::EnabledBorders enabledBorders = Plasma::FrameSvg::AllBorders; + + if (geo.left() <= screenRect.left()) { + enabledBorders ^= Plasma::FrameSvg::LeftBorder; + } + if (geo.top() <= screenRect.top()) { + enabledBorders ^= Plasma::FrameSvg::TopBorder; + } + if (geo.bottom() >= screenRect.bottom()) { + enabledBorders ^= Plasma::FrameSvg::BottomBorder; + } + if (geo.right() >= screenRect.right()) { + enabledBorders ^= Plasma::FrameSvg::RightBorder; + } + + m_shadow->setEnabledBorders(enabledBorders); + + qreal left, top, right, bottom; + + m_shadow->getMargins(left, top, right, bottom); + setContentsMargins(left, top, right, bottom); + } + +protected: + bool event(QEvent *event) + { + Q_UNUSED(event) + + if (event->type() == QEvent::Paint) { + QPainter p(this); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(rect(), Qt::transparent); + } + return QWidget::event(event); + } + + void resizeEvent(QResizeEvent *event) + { + m_shadow->resizeFrame(event->size()); + + adjustMargins(geometry()); + } + + void paintEvent(QPaintEvent* e) + { + Q_UNUSED(e) + + QPainter p(this); + //p.setCompositionMode(QPainter::CompositionMode_Source); + m_shadow->paintFrame(&p); + } + +private: + Plasma::FrameSvg *m_shadow; + NetView *m_panel; + bool m_valid; +}; + +PlasmaApp::PlasmaApp() + : KUniqueApplication(), + m_corona(0), + m_widgetExplorerView(0), + m_widgetExplorer(0), + m_glowBar(0), + m_mousePollTimer(0), + m_controlBar(0), + m_mainView(0), + m_isDesktop(false), + m_autoHideControlBar(true), + m_unHideTimer(0), + m_shadowWindow(0), + m_startupSuspendWaitCount(0) +{ + PlasmaApp::suspendStartup(true); + KGlobal::locale()->insertCatalog("libplasma"); + KGlobal::locale()->insertCatalog("plasmagenericshell"); + + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + bool isDesktop = args->isSet("desktop"); + if (isDesktop) { + KCrash::setFlags(KCrash::AutoRestart); + } + + //TODO: decide how to handle the cache size; possibilities: + // * % of ram, as in desktop + // * fixed size, hardcoded (uck) + // * optional size, specified on command line + // * optional size, in a config file + // * don't do anything special at all + //QPixmapCache::setCacheLimit(cacheSize); + + KConfigGroup cg(KSharedConfig::openConfig("plasmarc"), "Theme-plasma-netbook"); + const QString themeName = cg.readEntry("name", "air-netbook"); + Plasma::Theme::defaultTheme()->setUseGlobalSettings(false); + Plasma::Theme::defaultTheme()->setThemeName(themeName); + + cg = KConfigGroup(KGlobal::config(), "General"); + + Plasma::Theme::defaultTheme()->setFont(cg.readEntry("desktopFont", font())); + + m_mainView = new NetView(0, NetView::mainViewId(), 0); + m_mainView->hide(); + + connect(m_mainView, SIGNAL(containmentActivated()), this, SLOT(mainContainmentActivated())); + connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(positionPanel())); + + bool useGL = args->isSet("opengl"); + m_mainView->setUseGL(useGL); + + connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(controlBarVisibilityUpdate())); + + int width = 400; + int height = 200; + if (isDesktop) { + QRect rect = Kephal::ScreenUtils::screenGeometry(m_mainView->screen()); + width = rect.width(); + height = rect.height(); + } else { + QAction *action = KStandardAction::quit(qApp, SLOT(quit()), m_mainView); + m_mainView->addAction(action); + + QString geom = args->getOption("screen"); + int x = geom.indexOf('x'); + + if (x > 0) { + width = qMax(width, geom.left(x).toInt()); + height = qMax(height, geom.right(geom.length() - x - 1).toInt()); + } + } + + m_mainView->setFixedSize(width, height); + m_mainView->move(0,0); + setIsDesktop(isDesktop); + + // this line initializes the corona. + corona(); + //setIsDesktop(isDesktop); + reserveStruts(); + + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(checkShadow())); + connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanup())); +} + +PlasmaApp::~PlasmaApp() +{ +} + +void PlasmaApp::cleanup() +{ + if (m_corona) { + m_corona->saveLayout(); + } + + if (!m_mainView->containment()) { + return; + } + + // save the mapping of Views to Containments at the moment + // of application exit so we can restore that when we start again. + KConfigGroup viewIds(KGlobal::config(), "ViewIds"); + viewIds.deleteGroup(); + viewIds.writeEntry(QString::number(m_mainView->containment()->id()), NetView::mainViewId()); + + if (m_controlBar) { + viewIds.writeEntry(QString::number(m_controlBar->containment()->id()), NetView::controlBarId()); + } + + delete m_mainView; + m_mainView = 0; + + delete m_corona; + m_corona = 0; + + //TODO: This manual sync() should not be necessary? + syncConfig(); +} + +void PlasmaApp::syncConfig() +{ + KGlobal::config()->sync(); +} + +void PlasmaApp::positionPanel() +{ + if (!m_controlBar) { + return; + } + + QRect screenRect = Kephal::ScreenUtils::screenGeometry(m_controlBar->screen()); + if (!m_isDesktop) { + screenRect = m_mainView->geometry(); + } + + //move + controlBarMoved(m_controlBar); + + if (m_controlBar->formFactor() == Plasma::Horizontal) { + m_controlBar->setFixedSize(screenRect.width(), m_controlBar->size().height()); + } else if (m_controlBar->formFactor() == Plasma::Vertical) { + m_controlBar->setFixedSize(m_controlBar->size().width(), screenRect.height()); + } + + + m_controlBar->containment()->setMaximumSize(m_controlBar->size()); + m_controlBar->containment()->setMinimumSize(m_controlBar->size()); + + if (m_autoHideControlBar && m_controlBar->isVisible()) { + destroyUnHideTrigger(); + createUnhideTrigger(); + } + + checkShadow(); + + emit controlBarChanged(); +} + +void PlasmaApp::checkShadow() +{ + if (!m_controlBar) { + return; + } + + if (KWindowSystem::compositingActive() && m_controlBar->containment()->property("shadowPath").isValid()) { + if (!m_shadowWindow) { + m_shadowWindow = new ShadowWindow(m_controlBar); + KWindowSystem::setOnAllDesktops(m_controlBar->winId(), true); + } + KWindowSystem::setType(m_shadowWindow->winId(), NET::Dock); + KWindowSystem::setState(m_shadowWindow->winId(), NET::KeepBelow); + KWindowSystem::setOnAllDesktops(m_shadowWindow->winId(), true); + m_shadowWindow->setSvg(m_controlBar->containment()->property("shadowPath").toString()); + int left, right, top, bottom; + m_shadowWindow->adjustMargins(m_controlBar->geometry()); + m_shadowWindow->getContentsMargins(&left, &top, &right, &bottom); + m_shadowWindow->setMinimumSize(-1, -1); + m_shadowWindow->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + m_shadowWindow->setGeometry(m_controlBar->geometry().adjusted(-left, -top, right, bottom)); + m_shadowWindow->setFixedSize(m_shadowWindow->size()); + if (m_shadowWindow->isValid()) { + m_shadowWindow->show(); + } + } else { + m_shadowWindow->deleteLater(); + m_shadowWindow = 0; + } +} + +void PlasmaApp::mainContainmentActivated() +{ + if (m_mainView->containment()) { + m_mainView->setWindowTitle(m_mainView->containment()->activity()); + } + + + const WId id = m_mainView->effectiveWinId(); + + QWidget * activeWindow = QApplication::activeWindow(); + KWindowSystem::raiseWindow(id); + + if (activeWindow) { + KWindowSystem::raiseWindow(activeWindow->effectiveWinId()); + m_mainView->activateWindow(); + activeWindow->setFocus(); + if (m_shadowWindow) { + KWindowSystem::clearState(m_shadowWindow->winId(), NET::KeepBelow); + KWindowSystem::setState(m_shadowWindow->winId(), NET::KeepAbove); + } + } else { + m_mainView->activateWindow(); + } +} + +void PlasmaApp::setIsDesktop(bool isDesktop) +{ + m_isDesktop = isDesktop; + + if (isDesktop) { + KWindowSystem::setType(m_mainView->winId(), NET::Normal); + m_mainView->setWindowFlags(m_mainView->windowFlags() | Qt::FramelessWindowHint); + KWindowSystem::setOnAllDesktops(m_mainView->winId(), true); + if (m_controlBar) { + KWindowSystem::setOnAllDesktops(m_controlBar->winId(), true); + } + m_mainView->show(); + } else { + m_mainView->setWindowFlags(m_mainView->windowFlags() & ~Qt::FramelessWindowHint); + KWindowSystem::setOnAllDesktops(m_mainView->winId(), false); + if (m_controlBar) { + KWindowSystem::setOnAllDesktops(m_controlBar->winId(), false); + } + KWindowSystem::setType(m_mainView->winId(), NET::Normal); + } +} + +bool PlasmaApp::isDesktop() const +{ + return m_isDesktop; +} + +void PlasmaApp::adjustSize(Kephal::Screen *screen) +{ + Q_UNUSED(screen) + + QRect rect = Kephal::ScreenUtils::screenGeometry(m_mainView->screen()); + + int width = rect.width(); + int height = rect.height(); + //FIXME: ugly hack there too + m_mainView->setFixedSize(width, height); + positionPanel(); + reserveStruts(); +} + +void PlasmaApp::reserveStruts() +{ + if (!m_controlBar) { + return; + } + + if (m_autoHideControlBar || !isDesktop()) { + KWindowSystem::setExtendedStrut(m_controlBar->winId(), + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0); + return; + } + + NETExtendedStrut strut; + + if (!m_autoHideControlBar || hasForegroundWindows()) { + switch (m_controlBar->location()) { + case Plasma::LeftEdge: + strut.left_width = m_controlBar->width(); + strut.left_start = m_controlBar->y(); + strut.left_end = m_controlBar->y() + m_controlBar->height() - 1; + break; + case Plasma::RightEdge: + strut.right_width = m_controlBar->width(); + strut.right_start = m_controlBar->y(); + strut.right_end = m_controlBar->y() + m_controlBar->height() - 1; + break; + case Plasma::TopEdge: + strut.top_width = m_controlBar->height(); + strut.top_start = m_controlBar->x(); + strut.top_end = m_controlBar->x() + m_controlBar->width() - 1; + break; + case Plasma::BottomEdge: + default: + strut.bottom_width = m_controlBar->height(); + strut.bottom_start = m_controlBar->x(); + strut.bottom_end = m_controlBar->x() + m_controlBar->width() - 1; + } + } + + KWindowSystem::setExtendedStrut(m_controlBar->winId(), + strut.left_width, strut.left_start, strut.left_end, + strut.right_width, strut.right_start, strut.right_end, + strut.top_width, strut.top_start, strut.top_end, + strut.bottom_width, strut.bottom_start, strut.bottom_end); + + //ensure the main view is at the proper position too + QRect screenRect = Kephal::ScreenUtils::screenGeometry(m_controlBar->screen()); + m_mainView->move(screenRect.topLeft()); +} + +NetView *PlasmaApp::controlBar() const +{ + return m_controlBar; +} + +NetView *PlasmaApp::mainView() const +{ + return m_mainView; +} + +QWidget *PlasmaApp::widgetExplorer() const +{ + return m_widgetExplorerView; +} + +Plasma::Corona* PlasmaApp::corona() +{ + if (!m_corona) { + m_corona = new NetCorona(this); + connect(m_corona, SIGNAL(containmentAdded(Plasma::Containment*)), + this, SLOT(createView(Plasma::Containment*))); + connect(m_corona, SIGNAL(configSynced()), this, SLOT(syncConfig())); + + connect(m_corona, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)), + m_mainView, SLOT(screenOwnerChanged(int,int,Plasma::Containment*))); + + m_corona->setItemIndexMethod(QGraphicsScene::NoIndex); + m_corona->initializeLayout(); + m_corona->processUpdateScripts(); + + m_mainView->show(); + } + + foreach (Plasma::Containment *containment, m_corona->containments()) { + if (containment->screen() != -1 && containment->wallpaper()) { + ++m_startupSuspendWaitCount; + connect(containment->wallpaper(), SIGNAL(update(QRectF)), this, SLOT(wallpaperCheckedIn())); + } + } + + QTimer::singleShot(5000, this, SLOT(wallpaperCheckInTimeout())); + + return m_corona; +} + +void PlasmaApp::wallpaperCheckInTimeout() +{ + if (m_startupSuspendWaitCount > 0) { + m_startupSuspendWaitCount = 0; + suspendStartup(false); + } +} + +void PlasmaApp::wallpaperCheckedIn() +{ + if (m_startupSuspendWaitCount < 1) { + return; + } + + --m_startupSuspendWaitCount; + if (m_startupSuspendWaitCount < 1) { + m_startupSuspendWaitCount = 0; + suspendStartup(false); + } +} + +bool PlasmaApp::hasComposite() +{ + return KWindowSystem::compositingActive(); +} + +void PlasmaApp::suspendStartup(bool suspend) +{ + org::kde::KSMServerInterface ksmserver("org.kde.ksmserver", "/KSMServer", QDBusConnection::sessionBus()); + + const QString startupID("netbook desktop"); + if (suspend) { + ksmserver.suspendStartup(startupID); + } else { + ksmserver.resumeStartup(startupID); + } +} + +void PlasmaApp::createView(Plasma::Containment *containment) +{ + connect(containment, SIGNAL(showAddWidgetsInterface(QPointF)), this, SLOT(showWidgetExplorer())); + connect(containment, SIGNAL(configureRequested(Plasma::Containment*)), + this, SLOT(configureContainment(Plasma::Containment*))); + connect(containment, SIGNAL(toolBoxVisibilityChanged(bool)), + this, SLOT(updateToolBoxVisibility(bool))); + + + KConfigGroup viewIds(KGlobal::config(), "ViewIds"); + int defaultId = 0; + if (containment->containmentType() == Plasma::Containment::PanelContainment && + (!m_controlBar || m_controlBar->containment() == 0) ) { + defaultId = NetView::controlBarId(); + } else if (containment->containmentType() == Plasma::Containment::PanelContainment && + m_mainView->containment() == 0 ) { + defaultId = NetView::mainViewId(); + } + + int id = viewIds.readEntry(QString::number(containment->id()), defaultId); + + + kDebug() << "new containment" << (QObject*)containment << containment->id() << "view id" << id; + + //is it a desktop -and- is it active? + if ((m_mainView && id == NetView::mainViewId()) || + (containment->containmentType() != Plasma::Containment::PanelContainment && + containment->containmentType() != Plasma::Containment::CustomPanelContainment && + !viewIds.exists() && containment->screen() == 0)) { + m_mainView->setContainment(containment); + containment->setScreen(0); + //is it a panel? + } else if (id == NetView::controlBarId()) { + if (!m_controlBar) { + m_controlBar = new NetView(0, NetView::controlBarId(), 0); + + Kephal::Screens *screens = Kephal::Screens::self(); + connect(screens, SIGNAL(screenResized(Kephal::Screen*,QSize,QSize)), + this, SLOT(adjustSize(Kephal::Screen*))); + + m_controlBar->setAutoFillBackground(false); + m_controlBar->viewport()->setAutoFillBackground(false); + m_controlBar->setAttribute(Qt::WA_TranslucentBackground); + + connect(m_controlBar, SIGNAL(locationChanged(const NetView*)), this, SLOT(positionPanel())); + connect(m_controlBar, SIGNAL(geometryChanged()), this, SLOT(positionPanel())); + connect(m_controlBar, SIGNAL(containmentActivated()), this, SLOT(showControlBar())); + connect(m_controlBar, SIGNAL(autoHideChanged(bool)), this, SLOT(setAutoHideControlBar(bool))); + } + + m_controlBar->setContainment(containment); + positionPanel(); + setControlBarVisible(true); + containment->setMaximumSize(m_controlBar->size()); + containment->setMinimumSize(m_controlBar->size()); + containment->setImmutability(Plasma::UserImmutable); + + m_autoHideControlBar = m_controlBar->config().readEntry("panelAutoHide", true); + + setAutoHideControlBar(m_autoHideControlBar); + emit controlBarChanged(); + setControlBarVisible(true); + } else { + containment->setScreen(-1); + } +} + +void PlasmaApp::closeWidgetExplorer() +{ + if (m_widgetExplorer) { + Plasma::WindowEffects::slideWindow(m_widgetExplorerView, m_controlBar->location()); + m_widgetExplorer->deleteLater(); + m_widgetExplorerView->deleteLater(); + } +} + +void PlasmaApp::updateToolBoxVisibility(bool visible) +{ + bool hadToolBoxOpen = false; + + foreach (Plasma::Containment *cont, m_corona->containments()) { + if (cont->isToolBoxOpen()) { + hadToolBoxOpen = true; + } + cont->setToolBoxOpen(visible); + } + + if (!visible && hadToolBoxOpen) { + closeWidgetExplorer(); + } +} + +void PlasmaApp::controlBarMoved(const NetView *controlBar) +{ + if (!m_controlBar || controlBar != m_controlBar) { + return; + } + + QRect screenRect = Kephal::ScreenUtils::screenGeometry(m_controlBar->screen()); + + Plasma::Containment *cont = m_controlBar->containment(); + + switch (controlBar->location()) { + case Plasma::LeftEdge: + m_controlBar->move(screenRect.topLeft()); + break; + case Plasma::RightEdge: + m_controlBar->move(screenRect.topRight()-QPoint(m_controlBar->size().width(), 0)); + break; + case Plasma::TopEdge: + m_controlBar->move(screenRect.topLeft()); + break; + case Plasma::BottomEdge: + m_controlBar->move(screenRect.bottomLeft()-QPoint(0,m_controlBar->size().height())); + default: + break; + } + + //flip height and width + if (controlBar->formFactor() == Plasma::Vertical) { + if (cont && m_controlBar->size().width() > m_controlBar->size().height()) { + cont->setMinimumSize(cont->size().height(), cont->size().width()); + cont->setMaximumSize(cont->minimumSize()); + } + } else if (controlBar->formFactor() == Plasma::Horizontal) { + if (cont && m_controlBar->size().width() < m_controlBar->size().height()) { + cont->setMinimumSize(cont->size().height(), cont->size().width()); + cont->setMaximumSize(cont->minimumSize()); + } + } + + reserveStruts(); +} + +void PlasmaApp::setAutoHideControlBar(bool autoHide) +{ + if (!m_controlBar) { + return; + } + + if (autoHide) { + if (!m_unHideTimer) { + m_unHideTimer = new QTimer(this); + m_unHideTimer->setSingleShot(true); + connect(m_unHideTimer, SIGNAL(timeout()), this, SLOT(controlBarVisibilityUpdate())); + } + + m_controlBar->installEventFilter(this); + controlBarVisibilityUpdate(); + } else { + m_controlBar->removeEventFilter(this); + destroyUnHideTrigger(); + delete m_unHideTimer; + m_unHideTimer = 0; + setControlBarVisible(true); + } + + m_autoHideControlBar = autoHide; + reserveStruts(); + m_controlBar->config().writeEntry("panelAutoHide", autoHide); +} + +void PlasmaApp::showWidgetExplorer() +{ + Plasma::Containment *containment = dynamic_cast(sender()); + + if (!containment) { + return; + } + + showWidgetExplorer(containment); +} + +void PlasmaApp::showWidgetExplorer(Plasma::Containment *containment) +{ + if (!containment) { + return; + } + + containment->setToolBoxOpen(true); + + if (!m_widgetExplorerView) { + + m_widgetExplorerView = new Plasma::Dialog(); + + KWindowSystem::setOnAllDesktops(m_widgetExplorerView->winId(), true); + m_widgetExplorerView->show(); + KWindowSystem::activateWindow(m_widgetExplorerView->winId()); + m_widgetExplorerView->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); + m_widgetExplorerView->setAttribute(Qt::WA_TranslucentBackground); + m_widgetExplorerView->setAttribute(Qt::WA_DeleteOnClose); + KWindowSystem::setState(m_widgetExplorerView->winId(), NET::StaysOnTop|NET::KeepAbove); + connect(m_widgetExplorerView, SIGNAL(destroyed()), this, SLOT(widgetExplorerDestroyed())); + + if (m_controlBar) { + switch (m_controlBar->location()) { + case Plasma::TopEdge: + m_widgetExplorerView->resize(m_mainView->size().width(), KIconLoader::SizeEnormous); + m_widgetExplorerView->move(m_controlBar->geometry().bottomLeft()); + break; + case Plasma::LeftEdge: + m_widgetExplorerView->resize(KIconLoader::SizeEnormous, m_mainView->size().height()); + m_widgetExplorerView->move(m_controlBar->geometry().topRight()); + break; + case Plasma::RightEdge: + m_widgetExplorerView->resize(KIconLoader::SizeEnormous, m_mainView->size().height()); + m_widgetExplorerView->move(m_controlBar->geometry().topLeft() - QPoint(m_widgetExplorerView->size().width(), 0)); + break; + case Plasma::BottomEdge: + default: + m_widgetExplorerView->resize(m_mainView->size().width(), KIconLoader::SizeEnormous); + m_widgetExplorerView->move(m_controlBar->geometry().topLeft() - QPoint(0, m_widgetExplorerView->size().height())); + break; + } + } else { + m_widgetExplorerView->resize(m_mainView->size().width(), KIconLoader::SizeEnormous); + m_widgetExplorerView->move(0,0); + } + + } + + if (!m_widgetExplorer) { + m_widgetExplorer = new Plasma::WidgetExplorer(m_controlBar->containment()); + connect(m_widgetExplorer, SIGNAL(closeClicked()), this, SLOT(closeWidgetExplorer())); + m_widgetExplorer->setContainment(m_mainView->containment()); + m_widgetExplorer->populateWidgetList(); + + m_corona->addOffscreenWidget(m_widgetExplorer); + + QSize viewSize = m_widgetExplorerView->size(); + m_widgetExplorerView->setGraphicsWidget(m_widgetExplorer); + + m_widgetExplorerView->installEventFilter(this); + } + + m_widgetExplorer->setLocation(m_controlBar->location()); + + if (m_widgetExplorer->location() == Plasma::LeftEdge || m_widgetExplorer->location() == Plasma::RightEdge) { + m_widgetExplorer->setMinimumWidth(-1); + m_widgetExplorer->setMinimumHeight(m_mainView->size().height()); + } else { + m_widgetExplorer->setMinimumWidth(m_mainView->size().width()); + m_widgetExplorer->setMinimumHeight(-1); + } + + positionPanel(); + + m_widgetExplorer->show(); + Plasma::WindowEffects::slideWindow(m_widgetExplorerView, m_controlBar->location()); + m_widgetExplorerView->show(); + emit controlBarChanged(); +} + +void PlasmaApp::widgetExplorerDestroyed() +{ + m_widgetExplorer = 0; + m_widgetExplorerView = 0; + positionPanel(); + if (m_mainView->containment()) { + m_mainView->containment()->setToolBoxOpen(false); + } +} + + +void PlasmaApp::configureContainment(Plasma::Containment *containment) +{ + const QString id = QString::number(containment->id()) + "settings" + containment->name(); + BackgroundDialog *configDialog = qobject_cast(KConfigDialog::exists(id)); + kDebug() << configDialog; + + if (configDialog) { + configDialog->reloadConfig(); + } else { + const QSize resolution = Kephal::ScreenUtils::screenGeometry(m_mainView->screen()).size(); + + + KConfigSkeleton *nullManager = new KConfigSkeleton(0); + configDialog = new BackgroundDialog(resolution, containment, m_mainView, 0, id, nullManager); + configDialog->setAttribute(Qt::WA_DeleteOnClose); + + connect(configDialog, SIGNAL(destroyed(QObject*)), nullManager, SLOT(deleteLater())); + } + + configDialog->show(); + KWindowSystem::setOnDesktop(configDialog->winId(), KWindowSystem::currentDesktop()); + KWindowSystem::activateWindow(configDialog->winId()); +} + +bool PlasmaApp::mainViewOnTop() const +{ + bool onTop = false; + + QSet ownWindows; + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + ownWindows.insert(widget->winId()); + } + + //search if the main view is actually one of the widgets on top, show the panel only in this case + QList windows = KWindowSystem::stackingOrder(); + for (int i = windows.size() - 1; i >= 0; --i) { + WId window = windows.at(i); + + if (window == m_mainView->winId()) { + onTop = true; + break; + } else if (!ownWindows.contains(window)) { + break; + } + } + + return onTop; +} + +bool PlasmaApp::eventFilter(QObject * watched, QEvent *event) +{ + if (watched == m_widgetExplorerView && event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Escape) { + closeWidgetExplorer(); + } + } else if (watched == m_widgetExplorerView && event->type() == QEvent::Resize) { + m_widgetExplorer->resize(m_widgetExplorerView->contentsRect().size()); + } else if (!m_isDesktop && watched == m_mainView && event->type() == QEvent::Close) { + exit(); + } + return false; +} + +bool PlasmaApp::x11EventFilter(XEvent *event) +{ + + if (m_controlBar && m_autoHideControlBar && !m_controlBar->isVisible() && event->xcrossing.window == m_unhideTrigger && + (event->xany.send_event != True && event->type == EnterNotify)) { + //delayed show + if (!m_glowBar && KWindowSystem::compositingActive() && !m_triggerZone.contains(QCursor::pos())) { + Plasma::Direction direction = Plasma::locationToDirection(m_controlBar->location()); + m_glowBar = new GlowBar(direction, m_triggerZone); + m_glowBar->show(); + XMoveResizeWindow(QX11Info::display(), m_unhideTrigger, m_triggerZone.x(), m_triggerZone.y(), m_triggerZone.width(), m_triggerZone.height()); + + //FIXME: This is ugly as hell but well, yeah + if (!m_mousePollTimer) { + m_mousePollTimer = new QTimer(this); + } + + disconnect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(unhideHintMousePoll())); + connect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(unhideHintMousePoll())); + m_mousePollTimer->start(200); + } else { + m_unHideTimer->start(400); + } + } else if ((event->xany.send_event != True && event->type == FocusOut)) { + QTimer::singleShot(100, this, SLOT(lowerMainView())); + } else if (m_controlBar && m_autoHideControlBar && m_controlBar->isVisible() && + (event->xany.send_event != True && event->type == LeaveNotify)) { + if (m_unHideTimer) { + m_unHideTimer->start(200); + } + } + + return KUniqueApplication::x11EventFilter(event); +} + +bool PlasmaApp::hasForegroundWindows() const +{ + return QApplication::activeWindow(); +} + +void PlasmaApp::lowerMainView() +{ + if (m_isDesktop && !hasForegroundWindows()) { + KWindowSystem::lowerWindow(m_mainView->winId()); + } + if (m_shadowWindow) { + KWindowSystem::clearState(m_shadowWindow->winId(), NET::KeepAbove); + KWindowSystem::setState(m_shadowWindow->winId(), NET::KeepBelow); + } +} + +void PlasmaApp::controlBarVisibilityUpdate() +{ + if (!m_controlBar) { + return; + } + + if (!m_autoHideControlBar) { + setControlBarVisible(true); + + if (m_shadowWindow && m_shadowWindow->isValid()) { + Plasma::WindowEffects::slideWindow(m_shadowWindow, m_controlBar->location()); + m_shadowWindow->show(); + if (hasForegroundWindows()) { + KWindowSystem::clearState(m_shadowWindow->winId(), NET::KeepBelow); + KWindowSystem::setState(m_shadowWindow->winId(), NET::KeepAbove); + } else { + KWindowSystem::clearState(m_shadowWindow->winId(), NET::KeepAbove); + KWindowSystem::setState(m_shadowWindow->winId(), NET::KeepBelow); + } + KWindowSystem::setOnAllDesktops(m_shadowWindow->winId(), true); + } + + return; + } else if (m_autoHideControlBar && hasForegroundWindows() && m_controlBar->isVisible()) { + return; + } + + if (sender() != m_unHideTimer) { + m_unHideTimer->start(200); + return; + } + + //would be nice to avoid this + QPoint cursorPos = QCursor::pos(); + + if (m_triggerZone.adjusted(-1, -1, 1, 1).contains(cursorPos) || hasForegroundWindows()) { + if (!m_controlBar->isVisible()) { + destroyUnHideTrigger(); + Plasma::WindowEffects::slideWindow(m_controlBar, m_controlBar->location()); + setControlBarVisible(true); + } + + if (m_shadowWindow && m_shadowWindow->isValid()) { + Plasma::WindowEffects::slideWindow(m_shadowWindow, m_controlBar->location()); + if (hasForegroundWindows()) { + KWindowSystem::clearState(m_shadowWindow->winId(), NET::KeepBelow); + KWindowSystem::setState(m_shadowWindow->winId(), NET::KeepAbove); + } + m_shadowWindow->show(); + KWindowSystem::setOnAllDesktops(m_shadowWindow->winId(), true); + } + } else if (!m_controlBar->geometry().contains(cursorPos) && !mainViewOnTop() && !hasForegroundWindows()) { + Plasma::WindowEffects::slideWindow(m_controlBar, m_controlBar->location()); + m_controlBar->hide(); + + if (m_shadowWindow) { + Plasma::WindowEffects::slideWindow(m_shadowWindow, m_controlBar->location()); + m_shadowWindow->hide(); + } + + createUnhideTrigger(); + } +} + +void PlasmaApp::showControlBar() +{ + setControlBarVisible(true); +} + +void PlasmaApp::hideControlBar() +{ + setControlBarVisible(false); +} + +void PlasmaApp::setControlBarVisible(bool visible) +{ + if (!m_controlBar || m_controlBar->isVisible() == visible) { + return; + } + + if (visible) { + destroyUnHideTrigger(); + Plasma::WindowEffects::slideWindow(m_controlBar, m_controlBar->location()); + m_controlBar->setWindowFlags(m_mainView->windowFlags() | Qt::FramelessWindowHint); + m_controlBar->setFrameShape(QFrame::NoFrame); + m_controlBar->show(); + KWindowSystem::setOnAllDesktops(m_controlBar->winId(), m_isDesktop); + unsigned long state = NET::Sticky | NET::StaysOnTop | NET::KeepAbove; + KWindowSystem::setState(m_controlBar->effectiveWinId(), state); + KWindowSystem::setType(m_controlBar->effectiveWinId(), NET::Dock); + + if (m_shadowWindow && m_shadowWindow->isValid()) { + Plasma::WindowEffects::slideWindow(m_shadowWindow, m_controlBar->location()); + m_shadowWindow->show(); + if (!m_autoHideControlBar) { + KWindowSystem::setState(m_shadowWindow->winId(), NET::KeepBelow); + } + KWindowSystem::setOnAllDesktops(m_shadowWindow->winId(), true); + } + } else if (!m_autoHideControlBar) { + Plasma::WindowEffects::slideWindow(m_controlBar, m_controlBar->location()); + m_controlBar->hide(); + createUnhideTrigger(); + + if (m_shadowWindow) { + Plasma::WindowEffects::slideWindow(m_shadowWindow, m_controlBar->location()); + m_shadowWindow->hide(); + } + } +} + +void PlasmaApp::toggleControlBarVisibility() +{ + setControlBarVisible(!m_controlBar->isVisible()); +} + +void PlasmaApp::unhideHintMousePoll() +{ +#ifdef Q_WS_X11 + QPoint mousePos = QCursor::pos(); + m_glowBar->updateStrength(mousePos); + + if (!m_unhideTriggerGeom.contains(mousePos)) { + //kDebug() << "hide the glow"; + if (m_mousePollTimer) { + m_mousePollTimer->stop(); + disconnect(m_mousePollTimer, SIGNAL(timeout()), this, SLOT(unhideHintMousePoll())); + } + + delete m_glowBar; + m_glowBar = 0; + XMoveResizeWindow(QX11Info::display(), m_unhideTrigger, m_unhideTriggerGeom.x(), m_unhideTriggerGeom.y(), m_unhideTriggerGeom.width(), m_unhideTriggerGeom.height()); + } else { + m_unHideTimer->start(0); + } +#endif +} + +void PlasmaApp::createUnhideTrigger() +{ +#ifdef Q_WS_X11 + //kDebug() << m_unhideTrigger << None; + if (!m_autoHideControlBar || m_unhideTrigger != None || !m_controlBar || m_controlBar->isVisible()) { + return; + } + + int actualWidth = 1; + int actualHeight = 1; + int triggerWidth = 1; + int triggerHeight = 1; + + if (KWindowSystem::compositingActive()) { + triggerWidth = 30; + triggerHeight = 30; + } + + QPoint actualTriggerPoint; + QPoint triggerPoint = actualTriggerPoint = QPoint(qMax(0, m_controlBar->pos().x()), qMax(0, m_controlBar->pos().y())); + + switch (m_controlBar->location()) { + case Plasma::TopEdge: + actualWidth = triggerWidth = m_controlBar->width() - 1; + actualHeight = 1; + triggerPoint += QPoint(1, 0); + + break; + case Plasma::BottomEdge: + actualWidth = triggerWidth = m_controlBar->width() - 1; + actualTriggerPoint = triggerPoint = m_controlBar->geometry().bottomLeft() + QPoint(1, 0); + + break; + case Plasma::RightEdge: + actualHeight = triggerHeight = m_controlBar->height() - 1; + actualTriggerPoint = triggerPoint = m_controlBar->geometry().topRight() + QPoint(0, 1); + + break; + case Plasma::LeftEdge: + actualHeight = triggerHeight = m_controlBar->height() - 1; + triggerPoint += QPoint(0, -1); + + break; + default: + // no hiding unless we're on an edge. + return; + break; + } + + + XSetWindowAttributes attributes; + attributes.override_redirect = True; + attributes.event_mask = EnterWindowMask; + + + attributes.event_mask = EnterWindowMask | LeaveWindowMask | PointerMotionMask | + KeyPressMask | ButtonPressMask | + ButtonReleaseMask | ButtonMotionMask | + KeymapStateMask | VisibilityChangeMask | + StructureNotifyMask | ResizeRedirectMask | + SubstructureNotifyMask | + SubstructureRedirectMask | FocusChangeMask | + PropertyChangeMask | ColormapChangeMask | OwnerGrabButtonMask; + + unsigned long valuemask = CWOverrideRedirect | CWEventMask; + m_unhideTrigger = XCreateWindow(QX11Info::display(), QX11Info::appRootWindow(), + triggerPoint.x(), triggerPoint.y(), triggerWidth, triggerHeight, + 0, CopyFromParent, InputOnly, CopyFromParent, + valuemask, &attributes); + + XMapWindow(QX11Info::display(), m_unhideTrigger); + m_unhideTriggerGeom = QRect(triggerPoint, QSize(triggerWidth, triggerHeight)); + m_triggerZone = QRect(actualTriggerPoint, QSize(actualWidth, actualHeight)); +#endif +} + +void PlasmaApp::destroyUnHideTrigger() +{ +#ifdef Q_WS_X11 + if (m_unhideTrigger != None) { + XDestroyWindow(QX11Info::display(), m_unhideTrigger); + m_unhideTrigger = None; + m_triggerZone = m_unhideTriggerGeom = QRect(); + } +#endif +} + +#include "plasmaapp.moc" diff --git a/plasma/netbook/shell/plasmaapp.h b/plasma/netbook/shell/plasmaapp.h new file mode 100644 index 00000000..8374e535 --- /dev/null +++ b/plasma/netbook/shell/plasmaapp.h @@ -0,0 +1,158 @@ +/* + * Copyright 2006-2008 Aaron Seigo + * Copyright 2009 Marco Martin + * + * 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, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLASMA_APP_H +#define PLASMA_APP_H + + +#include + +#include + +#ifdef Q_WS_X11 +#include +#include +#endif + +namespace Plasma +{ + class Containment; + class Corona; + class Dialog; + class View; + class WidgetExplorer; +} // namespace Plasma + +class NetView; +class NetCorona; +class QTimer; +class GlowBar; +class ShadowWindow; + +namespace Kephal +{ + class Screen; +} + +class PlasmaApp : public KUniqueApplication +{ + Q_OBJECT +public: + ~PlasmaApp(); + + static PlasmaApp* self(); + static bool hasComposite(); + + void suspendStartup(bool suspend); + Plasma::Corona* corona(); + + /** + * Sets the view to be a desktop window if @p isDesktop is true + * or an ordinary window otherwise. + * + * Desktop windows are displayed beneath all other windows, have + * no window decoration and occupy the full size of the screen. + * + * The default behaviour is not to register the view as the desktop + * window. + */ + void setIsDesktop(bool isDesktop); + + NetView *controlBar() const; + + NetView *mainView() const; + + QWidget *widgetExplorer() const; + + /** + * Returns true if this widget is currently a desktop window. + * See setIsDesktop() + */ + bool isDesktop() const; + + void showWidgetExplorer(Plasma::Containment *containment); + +public Q_SLOTS: + void setAutoHideControlBar(bool autoHide); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + bool x11EventFilter(XEvent *event); + //true if the application has an active window + bool hasForegroundWindows() const; + //more strict than hasForegroundWindows, the mainview has to be not only active, but also on top of other windows + bool mainViewOnTop() const; + +private: + PlasmaApp(); + void reserveStruts(); + void createUnhideTrigger(); + void destroyUnHideTrigger(); + +private Q_SLOTS: + void cleanup(); + void syncConfig(); + void positionPanel(); + void createView(Plasma::Containment *containment); + void adjustSize(Kephal::Screen *); + void controlBarMoved(const NetView *controlBar); + void showWidgetExplorer(); + void widgetExplorerDestroyed(); + void closeWidgetExplorer(); + void mainContainmentActivated(); + //TODO: probably those functions can go in netview + void controlBarVisibilityUpdate(); + void showControlBar(); + void hideControlBar(); + void setControlBarVisible(bool visible); + void toggleControlBarVisibility(); + void lowerMainView(); + void configureContainment(Plasma::Containment *containment); + void updateToolBoxVisibility(bool visible); + void unhideHintMousePoll(); + void wallpaperCheckedIn(); + void wallpaperCheckInTimeout(); + void checkShadow(); + +Q_SIGNALS: + void controlBarChanged(); + +private: + NetCorona *m_corona; + Plasma::Dialog *m_widgetExplorerView; + Plasma::WidgetExplorer *m_widgetExplorer; +#ifdef Q_WS_X11 + Window m_unhideTrigger; + QRect m_triggerZone; + QRect m_unhideTriggerGeom; +#endif + GlowBar *m_glowBar; + QTimer *m_mousePollTimer; + NetView *m_controlBar; + NetView *m_mainView; + bool m_isDesktop; + bool m_autoHideControlBar; + QTimer *m_unHideTimer; + ShadowWindow *m_shadowWindow; + int m_startupSuspendWaitCount; +}; + +#endif // multiple inclusion guard + diff --git a/plasma/netbook/shell/scripting/netbookscriptengine.cpp b/plasma/netbook/shell/scripting/netbookscriptengine.cpp new file mode 100644 index 00000000..7c538fe2 --- /dev/null +++ b/plasma/netbook/shell/scripting/netbookscriptengine.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2010 Aaron Seigo + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "netbookscriptengine.h" + +#include + +#include +#include + +#include "panel.h" +#include "newspaper.h" + +namespace WorkspaceScripting +{ + +NetbookScriptEngine::NetbookScriptEngine(Plasma::Corona *corona, QObject *parent) + : ScriptEngine(corona, parent) +{ +} + +QScriptValue NetbookScriptEngine::wrap(Plasma::Containment *c) +{ + Containment *wrapper; + + if (c->name() == "newspaper") { + wrapper = new Newspaper(c); + } else if (isPanel(c)) { + wrapper = new NetPanel(c); + } else { + wrapper = new Containment(c); + } + + QScriptValue v = wrap(wrapper); + v.setProperty("addWidgetAt", newFunction(Newspaper::addWidgetAt)); + return v; +} + +QScriptValue NetbookScriptEngine::wrap(Containment *c) +{ + return ScriptEngine::wrap(c); +} + +} + +#include "netbookscriptengine.moc" + diff --git a/plasma/netbook/shell/scripting/netbookscriptengine.h b/plasma/netbook/shell/scripting/netbookscriptengine.h new file mode 100644 index 00000000..d5d268ac --- /dev/null +++ b/plasma/netbook/shell/scripting/netbookscriptengine.h @@ -0,0 +1,42 @@ +/* + * Copyright 2010 Aaron Seigo + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NETBOOKSCRIPTENGINE_H +#define NETBOOKSCRIPTENGINE_H + +#include + +namespace WorkspaceScripting +{ + +class NetbookScriptEngine : public ScriptEngine +{ + Q_OBJECT + +public: + NetbookScriptEngine(Plasma::Corona *corona, QObject *parent = 0); + QScriptValue wrap(Plasma::Containment *c); + QScriptValue wrap(Containment *c); +}; + +} + +#endif + diff --git a/plasma/netbook/shell/scripting/newspaper.cpp b/plasma/netbook/shell/scripting/newspaper.cpp new file mode 100644 index 00000000..0f02b8a9 --- /dev/null +++ b/plasma/netbook/shell/scripting/newspaper.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2009 Aaron Seigo + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "newspaper.h" + +#include + +#include +#include + +#include "netview.h" +#include "plasmaapp.h" +#include +#include + +namespace WorkspaceScripting +{ + +Newspaper::Newspaper(Plasma::Containment *containment, QObject *parent) + : Containment(containment, parent) +{ +} + +Newspaper::~Newspaper() +{ +} + +QScriptValue Newspaper::addWidgetAt(QScriptContext *context, QScriptEngine *engine) +{ + if (context->argumentCount() < 3) { + return context->throwError(i18n("widgetById requires a name of a widget or a widget object, with the row and column coordinates")); + } + + Containment *c = qobject_cast(context->thisObject().toQObject()); + + if (!c || !c->containment()) { + return engine->undefinedValue(); + } + + QScriptValue v = context->argument(0); + int row = context->argument(1).toInt32(); + int column = context->argument(2).toInt32(); + Plasma::Applet *applet = 0; + if (v.isString()) { + kWarning()<containment(), "addApplet", Qt::DirectConnection, + Q_RETURN_ARG(Plasma::Applet *, applet), + Q_ARG(QString, v.toString()), + Q_ARG(int, row), + Q_ARG(int, column)); + if (applet) { + ScriptEngine *env = ScriptEngine::envFor(engine); + return env->wrap(applet); + } + } else if (Widget *widget = qobject_cast(v.toQObject())) { + applet = widget->applet(); + QMetaObject::invokeMethod(c->containment(), "addApplet", Qt::DirectConnection, + Q_ARG(Plasma::Applet *, applet), + Q_ARG(int, row), + Q_ARG(int, column)); + c->containment()->addApplet(applet); + return v; + } + + return engine->undefinedValue(); +} + +} + +#include "newspaper.moc" + + diff --git a/plasma/netbook/shell/scripting/newspaper.h b/plasma/netbook/shell/scripting/newspaper.h new file mode 100644 index 00000000..6b434ccc --- /dev/null +++ b/plasma/netbook/shell/scripting/newspaper.h @@ -0,0 +1,67 @@ +/* + * Copyright 2009 Aaron Seigo + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NEWSPAPER_H +#define NEWSPAPER_H + +#include +#include + +#include + +namespace WorkspaceScripting +{ + +class Newspaper : public Containment +{ + Q_OBJECT + Q_PROPERTY(QStringList configKeys READ configKeys) + Q_PROPERTY(QStringList configGroups READ configGroups) + Q_PROPERTY(QStringList currentConfigGroup WRITE setCurrentConfigGroup READ currentConfigGroup) + + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString type READ type) + Q_PROPERTY(QString formFactor READ formFactor) + Q_PROPERTY(QList widgetIds READ widgetIds) + Q_PROPERTY(int screen READ screen WRITE setScreen) + Q_PROPERTY(int desktop READ desktop WRITE setDesktop) + Q_PROPERTY(int id READ id) + + +public: + Newspaper(Plasma::Containment *containment, QObject *parent = 0); + ~Newspaper(); + + static QScriptValue addWidgetAt(QScriptContext *context, QScriptEngine *engine); + +public Q_SLOTS: + void remove() { Containment::remove(); } + void showConfigurationInterface() { Containment::showConfigurationInterface(); } + + // from the applet interface + QVariant readConfig(const QString &key, const QVariant &def = QString()) const { return Applet::readConfig(key, def); } + void writeConfig(const QString &key, const QVariant &value) { Applet::writeConfig(key, value); } + void reloadConfig() { Applet::reloadConfig(); } +}; + +} + +#endif + diff --git a/plasma/netbook/shell/scripting/panel.cpp b/plasma/netbook/shell/scripting/panel.cpp new file mode 100644 index 00000000..9d45a35e --- /dev/null +++ b/plasma/netbook/shell/scripting/panel.cpp @@ -0,0 +1,172 @@ +/* + * Copyright 2009 Aaron Seigo + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "panel.h" + + +#include +#include + +#include "netview.h" +#include "plasmaapp.h" +#include +#include + +namespace WorkspaceScripting +{ + +NetPanel::NetPanel(Plasma::Containment *containment, QObject *parent) + : Containment(containment, parent) +{ +} + +NetPanel::~NetPanel() +{ +} + +QString NetPanel::location() const +{ + Plasma::Containment *c = containment(); + if (!c) { + return "floating"; + } + + switch (c->location()) { + case Plasma::Floating: + return "floating"; + break; + case Plasma::Desktop: + return "desktop"; + break; + case Plasma::FullScreen: + return "fullscreen"; + break; + case Plasma::TopEdge: + return "top"; + break; + case Plasma::BottomEdge: + return "bottom"; + break; + case Plasma::LeftEdge: + return "left"; + break; + case Plasma::RightEdge: + return "right"; + break; + } + + return "floating"; +} + +void NetPanel::setLocation(const QString &locationString) +{ + Plasma::Containment *c = containment(); + if (!c) { + return; + } + + const QString lower = locationString.toLower(); + Plasma::Location loc = Plasma::Floating; + if (lower == "desktop") { + loc = Plasma::Desktop; + } else if (lower == "fullscreen") { + loc = Plasma::FullScreen; + } else if (lower == "top") { + loc = Plasma::TopEdge; + } else if (lower == "bottom") { + loc = Plasma::BottomEdge; + } else if (lower == "left") { + loc = Plasma::LeftEdge; + } else if (lower == "right") { + loc = Plasma::RightEdge; + } + + c->setLocation(loc); +} + +NetView *NetPanel::panel() const +{ + Plasma::Containment *c = containment(); + if (!c) { + return 0; + } + + return PlasmaApp::self()->controlBar(); +} + +int NetPanel::height() const +{ + Plasma::Containment *c = containment(); + if (!c) { + return 0; + } + + return c->formFactor() == Plasma::Vertical ? c->size().width() + : c->size().height(); +} + +void NetPanel::setHeight(int height) +{ + Plasma::Containment *c = containment(); + if (height < 16 || !c) { + return; + } + + NetView *v = panel(); + if (v) { + QRect screen = c->corona()->screenGeometry(v->screen()); + QSizeF size = c->size(); + const int max = (c->formFactor() == Plasma::Vertical ? screen.width() : screen.height()) / 3; + height = qBound(16, height, max); + + if (c->formFactor() == Plasma::Vertical) { + size.setWidth(height); + } else { + size.setHeight(height); + } + + c->resize(size); + c->setMinimumSize(size); + c->setMaximumSize(size); + } +} + +bool NetPanel::autoHide() const +{ + NetView *v = panel(); + if (v) { + return v->autoHide(); + } + + return false; +} + +void NetPanel::setAutoHide(const bool autoHide) +{ + NetView *v = panel(); + if (v && autoHide != v->autoHide()) { + v->setAutoHide(autoHide); + } +} + +} + +#include "panel.moc" + diff --git a/plasma/netbook/shell/scripting/panel.h b/plasma/netbook/shell/scripting/panel.h new file mode 100644 index 00000000..d0a56840 --- /dev/null +++ b/plasma/netbook/shell/scripting/panel.h @@ -0,0 +1,82 @@ +/* + * Copyright 2009 Aaron Seigo + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PANEL_NETBOOK +#define PANEL_NETBOOK + + +#include + +class NetView; + +namespace WorkspaceScripting +{ + +class NetPanel : public Containment +{ + Q_OBJECT + Q_PROPERTY(QStringList configKeys READ configKeys) + Q_PROPERTY(QStringList configGroups READ configGroups) + Q_PROPERTY(QStringList currentConfigGroup WRITE setCurrentConfigGroup READ currentConfigGroup) + + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString type READ type) + Q_PROPERTY(QString formFactor READ formFactor) + Q_PROPERTY(QList widgetIds READ widgetIds) + Q_PROPERTY(int screen READ screen WRITE setScreen) + Q_PROPERTY(int desktop READ desktop WRITE setDesktop) + Q_PROPERTY(QString location READ location WRITE setLocation) + Q_PROPERTY(int id READ id) + Q_PROPERTY(bool locked READ locked WRITE setLocked) + + // panel properties + Q_PROPERTY(int height READ height WRITE setHeight) + Q_PROPERTY(bool autoHide READ autoHide WRITE setAutoHide) + +public: + NetPanel(Plasma::Containment *containment, QObject *parent = 0); + ~NetPanel(); + + QString location() const; + void setLocation(const QString &location); + + int height() const; + void setHeight(int height); + + bool autoHide() const; + void setAutoHide(const bool autoHide); + +public Q_SLOTS: + void remove() { Containment::remove(); } + void showConfigurationInterface() { Containment::showConfigurationInterface(); } + + // from the applet interface + QVariant readConfig(const QString &key, const QVariant &def = QString()) const { return Applet::readConfig(key, def); } + void writeConfig(const QString &key, const QVariant &value) { Applet::writeConfig(key, value); } + void reloadConfig() { Applet::reloadConfig(); } + +private: + NetView *panel() const; +}; + +} + +#endif + diff --git a/plasma/screensaver/CMakeLists.txt b/plasma/screensaver/CMakeLists.txt new file mode 100644 index 00000000..514c8565 --- /dev/null +++ b/plasma/screensaver/CMakeLists.txt @@ -0,0 +1,6 @@ +add_subdirectory(containments) +if(NOT WIN32) +add_subdirectory(shell) +endif(NOT WIN32) + + diff --git a/plasma/screensaver/containments/CMakeLists.txt b/plasma/screensaver/containments/CMakeLists.txt new file mode 100644 index 00000000..48879e90 --- /dev/null +++ b/plasma/screensaver/containments/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(screensaver) + diff --git a/plasma/screensaver/containments/screensaver/CMakeLists.txt b/plasma/screensaver/containments/screensaver/CMakeLists.txt new file mode 100644 index 00000000..b18c2dbf --- /dev/null +++ b/plasma/screensaver/containments/screensaver/CMakeLists.txt @@ -0,0 +1,10 @@ +set(desktop_SRCS + desktop.cpp + ../../../desktop/toolboxes/internaltoolbox.cpp) + +kde4_add_plugin(plasma_containment_saverdesktop ${desktop_SRCS}) +target_link_libraries(plasma_containment_saverdesktop ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS}) + +install(TARGETS plasma_containment_saverdesktop DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-containment-saverdesktop.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + diff --git a/plasma/screensaver/containments/screensaver/Messages.sh b/plasma/screensaver/containments/screensaver/Messages.sh new file mode 100755 index 00000000..5bd4d899 --- /dev/null +++ b/plasma/screensaver/containments/screensaver/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/plasma_applet_saverdesktop.pot diff --git a/plasma/screensaver/containments/screensaver/desktop.cpp b/plasma/screensaver/containments/screensaver/desktop.cpp new file mode 100644 index 00000000..fff0e98e --- /dev/null +++ b/plasma/screensaver/containments/screensaver/desktop.cpp @@ -0,0 +1,116 @@ +/* +* Copyright 2007 by Aaron Seigo +* Copyright 2008 by Chani Armitage +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License version 2, +* or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "desktop.h" + +#include + +#include + +#include +#include + +//#define DEBUG_CONSOLE +#ifdef DEBUG_CONSOLE +#include +#include +#include +#endif + +#include <../../../desktop/toolboxes/internaltoolbox.h> + +using namespace Plasma; + +SaverDesktop::SaverDesktop(QObject *parent, const QVariantList &args) + : Containment(parent, args), + m_lockDesktopAction(0), + m_appletBrowserAction(0) +{ + setContainmentType(CustomContainment); + connect(this, SIGNAL(appletAdded(Plasma::Applet*,QPointF)), SLOT(newApplet(Plasma::Applet*,QPointF))); + setHasConfigurationInterface(true); +} + +SaverDesktop::~SaverDesktop() +{ +} + +void SaverDesktop::init() +{ + Containment::init(); + + // trigger the creation of the toolbox. ugly! :) but nicer than having our own toolbox plugin + // just for the screensaver? + QAction *dummy = new QAction(this); + addToolBoxAction(dummy); + removeToolBoxAction(dummy); + delete dummy; + + Plasma::AbstractToolBox *tools = toolBox(); + InternalToolBox *internal = dynamic_cast(tools); + +#ifdef DEBUG_CONSOLE + Plasma::Frame *f = new Plasma::Frame(this); + f->setGeometry(QRectF(100, 100, 500, 500)); + QGraphicsLinearLayout *l = new QGraphicsLinearLayout(f); + l->addItem(msgs); + Plasma::TextBrowser *msgs new Plasma::TextBrowser(this); + msgs->setText(QString("got %1 with %2 actions").arg((int)internal).arg(tools ? + tools->metaObject()->className() : "NADA")); +#endif + + if (internal) { + // remove all the actions pre-made for us here + foreach (QAction *action, internal->actions()) { + internal->removeTool(action); + } + } + + // add our own actions. huzzah. + QAction *leave = corona()->action("unlock desktop"); + if (leave) { + addToolBoxAction(leave); + } + + QAction *lock = corona()->action("unlock widgets"); + if (lock) { + addToolBoxAction(lock); + } + + QAction *a = action("configure"); + if (a) { + a->setText(i18n("Settings")); + addToolBoxAction(a); + } + + a = action("add widgets"); + if (a) { + addToolBoxAction(a); + } +} + +void SaverDesktop::newApplet(Plasma::Applet *applet, const QPointF &pos) +{ + Q_UNUSED(pos); + applet->installSceneEventFilter(this); +} + +K_EXPORT_PLASMA_APPLET(saverdesktop, SaverDesktop) + +#include "desktop.moc" diff --git a/plasma/screensaver/containments/screensaver/desktop.h b/plasma/screensaver/containments/screensaver/desktop.h new file mode 100644 index 00000000..45d68680 --- /dev/null +++ b/plasma/screensaver/containments/screensaver/desktop.h @@ -0,0 +1,53 @@ +/* +* Copyright 2007 by Aaron Seigo +* Copyright 2008 by Chani Armitage +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License version 2, +* or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef PLASMA_SAVERDESKTOP_H +#define PLASMA_SAVERDESKTOP_H + +#include +#include + +#include + +class QAction; + +/** + * SaverDesktop + * + * This is a minimal containment for plasma-overlay. + */ + +class SaverDesktop : public Plasma::Containment +{ + Q_OBJECT + +public: + SaverDesktop(QObject *parent, const QVariantList &args); + ~SaverDesktop(); + void init(); + +private slots: + void newApplet(Plasma::Applet *applet, const QPointF &pos); + +private: + QAction *m_lockDesktopAction; + QAction *m_appletBrowserAction; +}; + +#endif diff --git a/plasma/screensaver/containments/screensaver/plasma-containment-saverdesktop.desktop b/plasma/screensaver/containments/screensaver/plasma-containment-saverdesktop.desktop new file mode 100644 index 00000000..eb49a71f --- /dev/null +++ b/plasma/screensaver/containments/screensaver/plasma-containment-saverdesktop.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=SaverDesktop +Name[ar]=حافظ سطح المكتب +Name[ast]=Curiapantalles +Name[be@latin]=SaverDesktop +Name[bn]=SaverDesktop +Name[bn_IN]=SaverDesktop +Name[bs]=čuvar na površi +Name[ca]=SaverDesktop +Name[ca@valencia]=SaverDesktop +Name[cs]=Spořič plochy +Name[csb]=SaverDesktop +Name[da]=SaverDesktop +Name[de]=SaverDesktop +Name[el]=Προφύλαξη επιφάνειας εργασίας +Name[en_GB]=SaverDesktop +Name[eo]=SaverDesktop +Name[es]=Salvapantallas +Name[et]=Ekraanisäästja-töölaud +Name[eu]=SaverDesktop +Name[fi]=Säästäjätyöpöytä +Name[fr]=Économiseur d'écran +Name[fy]=SaverDesktop +Name[ga]=SaverDesktop +Name[gl]=SaverDesktop +Name[gu]=સર્વરડેસ્કટોપ +Name[he]=SaverDesktop +Name[hi]=सेवरडेस्कटॉप +Name[hne]=सेवर-डेस्कटाप +Name[hr]=Spremač radne površine +Name[hu]=Tárolóasztal +Name[ia]=SaverDesktop +Name[id]=Penyimpan Desktop +Name[is]=Skjáborð +Name[ja]=セーバーデスクトップ +Name[kk]=Үстел сақтағышы +Name[km]=SaverDesktop +Name[kn]=ಉಳಿಕೆಗಾರ ಗಣಕತೆರೆ +Name[ko]=SaverDesktop +Name[ku]=SermasêDîmenderParêzê +Name[lt]=SaverDesktop +Name[lv]=SaudzētājaDarbvirsma +Name[mai]=SaverDesktop +Name[ml]=സേവര്‍പണിയിടം +Name[mr]=SaverDesktop +Name[nb]=SparerSkrivebord +Name[nds]=SekerSchriefdisch +Name[nl]=SaverDesktop +Name[nn]=SaverDesktop +Name[or]=ସର୍ଭର ଡ଼େସ୍କଟପ +Name[pa]=ਸੇਵਰਡੈਸਕਟਾਪ +Name[pl]=Wygaszacz na pulpicie +Name[pt]=Ecrã de Protecção +Name[pt_BR]=Proteção da área de trabalho +Name[ro]=SaverDesktop +Name[ru]=Рабочий стол в качестве хранителя экрана +Name[si]=SaverDesktop +Name[sk]=Šetrič plochy +Name[sl]=OhranjevalnikNamizje +Name[sr]=чувар на површи +Name[sr@ijekavian]=чувар на површи +Name[sr@ijekavianlatin]=čuvar na površi +Name[sr@latin]=čuvar na površi +Name[sv]=Skrivbordsunderlägg +Name[ta]=பணிமேசை காப்பு +Name[te]=సేవిక‍డెస్‍క్ టాప్ +Name[tg]=Мизи корӣ, монанди пардаи экран +Name[th]=รักษาจอภาพ +Name[tr]=Ekran Koruyucu Masaüstü +Name[ug]=ئېكران قوغداش ئۈستەلئۈستى +Name[uk]=Зберігач стільниці +Name[wa]=SaverDesktop +Name[x-test]=xxSaverDesktopxx +Name[zh_CN]=屏幕保护桌面 +Name[zh_TW]=保護程式桌面 +Icon=Plasma +Type=Service +X-KDE-ServiceTypes=Plasma/Applet,Plasma/Containment +X-Plasma-ContainmentCategories=screensaver +NoDisplay=true + +X-KDE-Library=plasma_containment_saverdesktop +X-KDE-PluginInfo-Author=The Plasma Team +X-KDE-PluginInfo-Email=plasma-devel@kde.org +X-KDE-PluginInfo-Name=saverdesktop +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://plasma.kde.org/ +X-KDE-PluginInfo-Category=Containments +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Unused + diff --git a/plasma/screensaver/shell/BackgroundDialog.ui b/plasma/screensaver/shell/BackgroundDialog.ui new file mode 100644 index 00000000..c6b0aa7a --- /dev/null +++ b/plasma/screensaver/shell/BackgroundDialog.ui @@ -0,0 +1,108 @@ + + + BackgroundDialog + + + + 0 + 0 + 572 + 600 + + + + + 0 + 600 + + + + + 200 + 700 + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 13 + 17 + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Wallpaper + + + + + + + Type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + m_wallpaperMode + + + + + + + + 1 + 0 + + + + + 150 + 0 + + + + + + + + + + + 0 + 0 + + + + + + + + + diff --git a/plasma/screensaver/shell/CMakeLists.txt b/plasma/screensaver/shell/CMakeLists.txt new file mode 100644 index 00000000..5c52da69 --- /dev/null +++ b/plasma/screensaver/shell/CMakeLists.txt @@ -0,0 +1,39 @@ +include_directories( + ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs + ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kdm + ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/plasmagenericshell + ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/screenlocker/greeter/ + ${CMAKE_BINARY_DIR}/ksmserver/screenlocker/greeter/ + ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs/kworkspace + ${KDEBASE_WORKSPACE_SOURCE_DIR}/kcheckpass +) + +set(plasma-overlay_SRCS + backgrounddialog.cpp + main.cpp + plasmaapp.cpp + savercorona.cpp + saverview.cpp + ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/screenlocker/greeter/greeter.cpp + ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/screenlocker/greeter/sessions.cpp +) + +kde4_add_ui_files(plasma-overlay_SRCS BackgroundDialog.ui) + +kde4_add_kcfg_files(plasma-overlay_SRCS ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/screenlocker/kcfg/kscreensaversettings.kcfgc) + +set(plasmaapp_dbusXML org.kde.plasma-overlay.App.xml) +#qt4_generate_dbus_interface(plasmaapp.h ${plasmaapp_dbusXML} OPTIONS -S -M) +qt4_add_dbus_adaptor(plasma-overlay_SRCS ${plasmaapp_dbusXML} plasmaapp.h PlasmaApp) + +kde4_add_executable(plasma-overlay ${plasma-overlay_SRCS}) + +target_link_libraries(plasma-overlay ${KDE4_PLASMA_LIBS} kworkspace ${KDE4_KIO_LIBS} ${KDE4_KFILE_LIBS} + ${X11_X11_LIB} plasmagenericshell ${QT_QTDECLARATIVE_LIBRARY} kdeclarative) +if(X11_Xrender_FOUND) + target_link_libraries(plasma-overlay ${X11_Xrender_LIB}) +endif(X11_Xrender_FOUND) +set_target_properties(plasma-overlay PROPERTIES OUTPUT_NAME plasma-overlay) + +install(TARGETS plasma-overlay ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES plasma-overlayrc DESTINATION ${CONFIG_INSTALL_DIR}) diff --git a/plasma/screensaver/shell/Messages.sh b/plasma/screensaver/shell/Messages.sh new file mode 100755 index 00000000..b79d051d --- /dev/null +++ b/plasma/screensaver/shell/Messages.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/plasma-overlay.pot +rm -f rc.cpp + diff --git a/plasma/screensaver/shell/backgrounddialog.cpp b/plasma/screensaver/shell/backgrounddialog.cpp new file mode 100644 index 00000000..dc6ee8b0 --- /dev/null +++ b/plasma/screensaver/shell/backgrounddialog.cpp @@ -0,0 +1,211 @@ +/* + Copyright (c) 2007 Paolo Capriotti + Copyright (C) 2007 Ivan Cukic + Copyright (c) 2008 by Petri Damsten + + 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. +*/ + +#include "backgrounddialog.h" + +//#include +//#include +//#include + +#include +//#include +//#include +//#include + +#include +#include +#include +#include +//#include + +#include "plasmaapp.h" +#include "plasmagenericshell/wallpaperpreview.h" + +#include "../../../libs/kworkspace/screenpreviewwidget.h" + +typedef QPair WallpaperInfo; +Q_DECLARE_METATYPE(WallpaperInfo) + + +BackgroundDialog::BackgroundDialog(const QSize& res, Plasma::Containment *c, /*Plasma::View* view,*/ QWidget* parent) + : KDialog(parent), + m_wallpaper(0), + //m_view(view), + m_containment(c) +{ + //setWindowIcon(KIcon("preferences-desktop-wallpaper")); + setCaption(i18n("Background Settings")); + setButtons(Ok | Cancel | Apply); + + QWidget * main = new QWidget(this); + setupUi(main); + + // Size of monitor image: 200x186 + // Geometry of "display" part of monitor image: (23,14)-[151x115] + qreal previewRatio = (qreal)res.width() / (qreal)res.height(); + QSize monitorSize(200, int(200 * previewRatio)); + + connect(this, SIGNAL(finished(int)), this, SLOT(cleanup())); + connect(this, SIGNAL(okClicked()), this, SLOT(saveConfig())); + connect(this, SIGNAL(applyClicked()), this, SLOT(saveConfig())); + + setMainWidget(main); + reloadConfig(); + adjustSize(); + + if (c->view()) { + setParent(c->view()); + setBackgroundRole(QPalette::Window); + setAutoFillBackground(true); + move(c->view()->width()/2 - width()/2, y()); + } +} + +BackgroundDialog::~BackgroundDialog() +{ + cleanup(); +} + +void BackgroundDialog::cleanup() +{ + //FIXME could be bad if we get hidden and reshown + delete m_wallpaper; + m_wallpaper = 0; +} + +void BackgroundDialog::reloadConfig() +{ + // Wallpaper + disconnect(m_wallpaperMode, SIGNAL(currentIndexChanged(int)), this, SLOT(changeBackgroundMode(int))); + int wallpaperIndex = 0; + + bool doWallpaper = m_containment->drawWallpaper(); + m_wallpaperLabel->setVisible(doWallpaper); + m_wallpaperTypeLabel->setVisible(doWallpaper); + m_wallpaperMode->setVisible(doWallpaper); + m_wallpaperConfig->setVisible(doWallpaper); + + if (doWallpaper) { + // Load wallpaper plugins + QString currentPlugin; + QString currentMode; + + Plasma::Wallpaper *currentWallpaper = m_containment->wallpaper(); + if (currentWallpaper) { + currentPlugin = currentWallpaper->pluginName(); + currentMode = currentWallpaper->renderingMode().name(); + } + + const KPluginInfo::List plugins = Plasma::Wallpaper::listWallpaperInfo(); + m_wallpaperMode->clear(); + int i = 0; + QString placeholder = i18n("No Wallpaper"); + //m_wallpaperMode->addItem(KIcon(), i18n("No Wallpaper"), + // QVariant::fromValue(WallpaperInfo(QString(), QString()))); + foreach (const KPluginInfo& info, plugins) { + bool matches = info.pluginName() == currentPlugin; + const QList& modes = info.service()->actions(); + if (modes.count() > 0) { + foreach (const KServiceAction& mode, modes) { + m_wallpaperMode->addItem(KIcon(mode.icon()), mode.text(), + QVariant::fromValue(WallpaperInfo(info.pluginName(), mode.name()))); + if (matches && mode.name() == currentMode) { + wallpaperIndex = i; + } + ++i; + } + } else { + m_wallpaperMode->addItem(KIcon(info.icon()), info.name(), + QVariant::fromValue(WallpaperInfo(info.pluginName(), QString()))); + if (matches) { + wallpaperIndex = i; + } + ++i; + } + } + m_wallpaperMode->setCurrentIndex(wallpaperIndex); + changeBackgroundMode(wallpaperIndex); + } + + connect(m_wallpaperMode, SIGNAL(currentIndexChanged(int)), this, SLOT(changeBackgroundMode(int))); +} + +void BackgroundDialog::changeBackgroundMode(int mode) +{ + kDebug(); + QWidget* w = 0; + WallpaperInfo wallpaperInfo = m_wallpaperMode->itemData(mode).value(); + + if (!m_wallpaperConfig->layout()) { + new QVBoxLayout(m_wallpaperConfig); + } + + if (m_wallpaperConfig->layout()->count() > 0) { + delete dynamic_cast(m_wallpaperConfig->layout()->takeAt(0))->widget(); + } + + if (m_wallpaper && m_wallpaper->pluginName() != wallpaperInfo.first) { + delete m_wallpaper; + m_wallpaper = 0; + } + + if (wallpaperInfo.first.isEmpty()) { + return; + } + + if (!m_wallpaper) { + m_wallpaper = Plasma::Wallpaper::load(wallpaperInfo.first); + } + + if (m_wallpaper) { + m_wallpaper->setRenderingMode(wallpaperInfo.second); + KConfigGroup cfg = wallpaperConfig(wallpaperInfo.first); + kDebug() << "making a" << wallpaperInfo.first << "in mode" << wallpaperInfo.second; + m_wallpaper->restore(cfg); + w = m_wallpaper->createConfigurationInterface(m_wallpaperConfig); + } + + if (!w) { + w = new QWidget(m_wallpaperConfig); + } + + m_wallpaperConfig->layout()->addWidget(w); +} + +KConfigGroup BackgroundDialog::wallpaperConfig(const QString &plugin) +{ + Q_ASSERT(m_containment); + + //FIXME: we have details about the structure of the containment config duplicated here! + KConfigGroup cfg = m_containment->config(); + cfg = KConfigGroup(&cfg, "Wallpaper"); + return KConfigGroup(&cfg, plugin); +} + +void BackgroundDialog::saveConfig() +{ + // Wallpaper + QString wallpaperPlugin = m_wallpaperMode->itemData(m_wallpaperMode->currentIndex()).value().first; + QString wallpaperMode = m_wallpaperMode->itemData(m_wallpaperMode->currentIndex()).value().second; + + Plasma::Wallpaper *currentWallpaper = m_containment->wallpaper(); + if (currentWallpaper) { + KConfigGroup cfg = wallpaperConfig(currentWallpaper->pluginName()); + currentWallpaper->save(cfg); + } + + if (m_wallpaper) { + KConfigGroup cfg = wallpaperConfig(m_wallpaper->pluginName()); + m_wallpaper->save(cfg); + } + + m_containment->setWallpaper(wallpaperPlugin, wallpaperMode); +} diff --git a/plasma/screensaver/shell/backgrounddialog.h b/plasma/screensaver/shell/backgrounddialog.h new file mode 100644 index 00000000..04b507ae --- /dev/null +++ b/plasma/screensaver/shell/backgrounddialog.h @@ -0,0 +1,52 @@ +/* + Copyright (c) 2007 Paolo Capriotti + Copyright (c) 2008 by Petri Damsten + + 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. +*/ + +#ifndef BACKGROUNDDIALOG_H +#define BACKGROUNDDIALOG_H + +#include +#include "ui_BackgroundDialog.h" + +namespace Plasma { + class Wallpaper; + class Containment; + class View; +} + +class ScreenPreviewWidget; + +class BackgroundDialog : public KDialog, public Ui::BackgroundDialog +{ + Q_OBJECT +public: + BackgroundDialog(const QSize &res, Plasma::Containment *containment, + /*Plasma::View *view,*/ QWidget *parent = 0); + ~BackgroundDialog(); + + void reloadConfig(); + +public slots: + void saveConfig(); + +private: + KConfigGroup wallpaperConfig(const QString &plugin); + +private slots: + void changeBackgroundMode(int mode); + void cleanup(); + +private: + Plasma::Wallpaper* m_wallpaper; + //Plasma::View* m_view; + Plasma::Containment* m_containment; + ScreenPreviewWidget* m_preview; +}; + +#endif // BACKGROUNDDIALOG_H diff --git a/plasma/screensaver/shell/main.cpp b/plasma/screensaver/shell/main.cpp new file mode 100644 index 00000000..a70bcdfc --- /dev/null +++ b/plasma/screensaver/shell/main.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2006-2007 Aaron Seigo + * Copyright 2008 Chani Armitage + * + * 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, + * 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, see . + */ + +#include +#include +#include +#include + +#include + +#include + +#include +#include "plasmaapp.h" + +static const char description[] = I18N_NOOP( "Plasma widgets over the screensaver" ); +static const char version[] = "0.0"; + +//extern "C" +int main(int argc, char **argv) +{ + KAboutData aboutData("plasma-overlay",0 , ki18n("Plasma for the Screensaver"), + version, ki18n(description), KAboutData::License_GPL, + ki18n("Copyright 2006-2008, The KDE Team")); + aboutData.addAuthor(ki18n("Chani Armitage"), + ki18n("Author and maintainer"), + "chanika@gmail.com"); + aboutData.addAuthor(ki18n("Aaron J. Seigo"), + ki18n("Plasma Author and maintainer"), + "aseigo@kde.org"); + aboutData.addCredit(ki18n("John Lions"), + ki18n("In memory of his contributions, 1937-1998."), + 0, "http://en.wikipedia.org/wiki/John_Lions"); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KCmdLineOptions options; + options.add("cheats",ki18n("Enables some cheats that are useful for debugging.")); + options.add("setup",ki18n("Start unlocked for configuration.")); + KCmdLineArgs::addCmdLineOptions(options); + + PlasmaApp *app = PlasmaApp::self(); + QApplication::setWindowIcon(KIcon("plasma")); + KGlobal::locale()->insertCatalog(QLatin1String( "libkworkspace" )); + KGlobal::locale()->insertCatalog(QLatin1String( "kscreenlocker_greet" )); + app->disableSessionManagement(); // I assume we'd never want a screensaver thing reppearing on login? + // This allow ksmserver to know when the applicaion has actually finished setting itself up. + // Crucial for blocking until it is ready, ensuring locking happens before sleep, e.g. + std::cout << "Locked at " << QDateTime::currentDateTime().toTime_t() << std::endl; + int rc = app->exec(); + delete app; + return rc; +} diff --git a/plasma/screensaver/shell/org.kde.plasma-overlay.App.xml b/plasma/screensaver/shell/org.kde.plasma-overlay.App.xml new file mode 100644 index 00000000..54724a89 --- /dev/null +++ b/plasma/screensaver/shell/org.kde.plasma-overlay.App.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/plasma/screensaver/shell/plasma-overlayrc b/plasma/screensaver/shell/plasma-overlayrc new file mode 100644 index 00000000..393e2c95 --- /dev/null +++ b/plasma/screensaver/shell/plasma-overlayrc @@ -0,0 +1,10 @@ +[KDE Action Restrictions][$i] +plasma/allow_configure_when_locked=false + +[Constraints] +FileDialog=false +LaunchApp=false + +[General] +ExcludeCategories=Windows and Tasks,Application Launchers + diff --git a/plasma/screensaver/shell/plasmaapp.cpp b/plasma/screensaver/shell/plasmaapp.cpp new file mode 100644 index 00000000..ad061602 --- /dev/null +++ b/plasma/screensaver/shell/plasmaapp.cpp @@ -0,0 +1,514 @@ +/* + * Copyright 2006 Aaron Seigo + * Copyright 2008 Chani Armitage + * + * + * 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, + * 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, see . + */ + +// plasma.loadEngine("hardware") +// LineGraph graph +// plasma.connect(graph, "hardware", "cpu"); + +#include "plasmaapp.h" + +#include "greeter.h" +#include "sessions.h" + +#include + +#ifndef _SC_PHYS_PAGES + #ifdef Q_OS_FREEBSD + #include + #include + #endif + + #ifdef Q_OS_NETBSD + #include + #include + #endif +#endif + +#include +#include +#include +#include +#include + +//#include +#include +#include +#include + +//#include + +#include +#include +#include + +#include "appadaptor.h" +#include "savercorona.h" +#include "saverview.h" +#include "backgrounddialog.h" + + +#include +#include +#include + +Atom tag; //FIXME should this be a member var or what? +Atom tag2; + +const unsigned char DIALOG = 1; //FIXME this is really bad code +const unsigned char VIEW = 2; + +Display* dpy = 0; +Colormap colormap = 0; +Visual *visual = 0; +bool composite = false; + +void checkComposite() +{ + dpy = XOpenDisplay(0); // open default display + if (!dpy) { + kError() << "Cannot connect to the X server" << endl; + return; + } + if( qgetenv( "KDE_SKIP_ARGB_VISUALS" ) == "1" ) + return; + + int screen = DefaultScreen(dpy); + int eventBase, errorBase; + + if (XRenderQueryExtension(dpy, &eventBase, &errorBase)) { + int nvi; + XVisualInfo templ; + templ.screen = screen; + templ.depth = 32; + templ.c_class = TrueColor; + XVisualInfo *xvi = XGetVisualInfo(dpy, + VisualScreenMask | VisualDepthMask | VisualClassMask, + &templ, &nvi); + for (int i = 0; i < nvi; ++i) { + XRenderPictFormat *format = XRenderFindVisualFormat(dpy, xvi[i].visual); + if (format->type == PictTypeDirect && format->direct.alphaMask) { + visual = xvi[i].visual; + colormap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone); + break; + } + } + XFree(xvi); + } + + composite = KWindowSystem::compositingActive() && colormap; + + kDebug() << (colormap ? "Plasma has an argb visual" : "Plasma lacks an argb visual") << visual << colormap; + kDebug() << ((KWindowSystem::compositingActive() && colormap) ? "Plasma can use COMPOSITE for effects" + : "Plasma is COMPOSITE-less") << "on" << dpy; +} + +PlasmaApp* PlasmaApp::self() +{ + if (!kapp) { + checkComposite(); + return new PlasmaApp(dpy, visual ? Qt::HANDLE(visual) : 0, colormap ? Qt::HANDLE(colormap) : 0); + } + + return qobject_cast(kapp); +} + +PlasmaApp::PlasmaApp(Display* display, Qt::HANDLE visual, Qt::HANDLE colormap) + : KUniqueApplication(display, visual, colormap), + m_corona(0), + m_configDialog(0) +{ + const char *uri = "org.kde.kscreenlocker"; + qmlRegisterType(uri, 1, 0, "GreeterItem"); + qmlRegisterType(uri, 1, 0, "KeyboardItem"); + qmlRegisterType(uri, 1, 0, "Sessions"); + qmlRegisterType(); + //load translations for libplasma + KGlobal::locale()->insertCatalog("libplasma"); + KGlobal::locale()->insertCatalog("plasmagenericshell"); + + new AppAdaptor(this); + QDBusConnection::sessionBus().registerObject("/App", this); + + //FIXME this is probably totally invalid + // Enlarge application pixmap cache + // Calculate the size required to hold background pixmaps for all screens. + // Add 10% so that other (smaller) pixmaps can also be cached. + int cacheSize = 0; + QDesktopWidget *desktop = QApplication::desktop(); + int numScreens = desktop->numScreens(); + for (int i = 0; i < numScreens; i++) { + QRect geometry = desktop->screenGeometry(i); + cacheSize += 4 * geometry.width() * geometry.height() / 1024; + } + cacheSize += cacheSize / 10; + + // Calculate the size of physical system memory; _SC_PHYS_PAGES * + // _SC_PAGESIZE is documented to be able to overflow 32-bit integers, + // so apply a 10-bit shift. FreeBSD 6-STABLE doesn't have _SC_PHYS_PAGES + // (it is documented in FreeBSD 7-STABLE as "Solaris and Linux extension") + // so use sysctl in those cases. +#if defined(_SC_PHYS_PAGES) + int memorySize = sysconf(_SC_PHYS_PAGES); + memorySize *= sysconf(_SC_PAGESIZE) / 1024; +#else +#ifdef Q_OS_FREEBSD + int sysctlbuf[2]; + size_t size = sizeof(sysctlbuf); + int memorySize; + // This could actually use hw.physmem instead, but I can't find + // reliable documentation on how to read the value (which may + // not fit in a 32 bit integer). + if (!sysctlbyname("vm.stats.vm.v_page_size", sysctlbuf, &size, NULL, 0)) { + memorySize = sysctlbuf[0] / 1024; + size = sizeof(sysctlbuf); + if (!sysctlbyname("vm.stats.vm.v_page_count", sysctlbuf, &size, NULL, 0)) { + memorySize *= sysctlbuf[0]; + } + } +#endif +#ifdef Q_OS_NETBSD + size_t memorySize; + size_t len; + static int mib[] = { CTL_HW, HW_PHYSMEM }; + + len = sizeof(memorySize); + sysctl(mib, 2, &memorySize, &len, NULL, 0); + memorySize /= 1024; +#endif + // If you have no suitable sysconf() interface and are not FreeBSD, + // then you are out of luck and get a compile error. +#endif + + // Increase the pixmap cache size to 1% of system memory if it isn't already + // larger so as to maximize cache usage. 1% of 1GB ~= 10MB. + if (cacheSize < memorySize / 100) { + cacheSize = memorySize / 100; + } + + kDebug() << "Setting the pixmap cache size to" << cacheSize << "kilobytes"; + QPixmapCache::setCacheLimit(cacheSize); + + KConfigGroup cg(KGlobal::config(), "General"); + Plasma::Theme::defaultTheme()->setFont(cg.readEntry("desktopFont", font())); + + if (cg.readEntry("forceNoComposite", false)) { + composite = false; + } + + //we have to keep an eye on created windows + tag = XInternAtom(QX11Info::display(), "_KDE_SCREENSAVER_OVERRIDE", False); + tag2 = XInternAtom(QX11Info::display(), "_KDE_SCREEN_LOCKER", False); + qApp->installEventFilter(this); + + // this line initializes the corona. + corona(); + + connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanup())); + + setup(KCmdLineArgs::parsedArgs()->isSet("setup")); + + m_viewCreationTimer.setSingleShot(true); + m_viewCreationTimer.setInterval(0); + connect(&m_viewCreationTimer, SIGNAL(timeout()), this, SLOT(createWaitingViews())); +} + +PlasmaApp::~PlasmaApp() +{ +} + +void PlasmaApp::cleanup() +{ + if (m_corona) { + m_corona->saveLayout(); + } + + qDeleteAll(m_views); + delete m_corona; + m_corona = 0; + + KGlobal::config()->sync(); +} + +void PlasmaApp::createWaitingViews() +{ + const QList > containments = m_viewsWaiting; + m_viewsWaiting.clear(); + foreach(QWeakPointer weakContainment, containments) { + if (weakContainment) { + Plasma::Containment *containment = weakContainment.data(); + + KConfigGroup viewIds(KGlobal::config(), "ViewIds"); + + // we have a new screen. neat. + SaverView *view = viewForScreen(containment->screen()); + if (view) { + return; + } + + view = new SaverView(containment, 0); + if (m_corona) { + connect(m_corona, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)), + view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*))); + connect(m_corona, SIGNAL(shortcutsChanged()), view, SLOT(updateShortcuts())); + } + view->setGeometry(QApplication::desktop()->screenGeometry(containment->screen())); + + //FIXME why do I get BadWindow? + //unsigned char data = VIEW; + //XChangeProperty(QX11Info::display(), view->effectiveWinId(), tag, tag, 8, PropModeReplace, &data, 1); + + connect(containment, SIGNAL(configureRequested(Plasma::Containment*)), + this, SLOT(configureContainment(Plasma::Containment*))); + + //a hack to make sure the keyboard shortcut works + view->addAction(corona()->action("unlock desktop")); + view->addAction(corona()->action("unlock widgets")); + m_views.append(view); + connect(view, SIGNAL(hidden()), SLOT(lock())); + connect(view, SIGNAL(hidden()), SIGNAL(hidden())); + connect(this, SIGNAL(showViews()), view, SLOT(show())); + connect(this, SIGNAL(hideViews()), view, SLOT(hide())); + connect(this, SIGNAL(enableSetupMode()), view, SLOT(disableSetupMode())); + connect(this, SIGNAL(disableSetupMode()), view, SLOT(disableSetupMode())); + connect(this, SIGNAL(openToolBox()), view, SLOT(openToolBox())); + connect(this, SIGNAL(closeToolBox()), view, SLOT(closeToolBox())); + connect(QApplication::desktop(), SIGNAL(resized(int)), view, SLOT(adjustSize(int))); + emit(openToolBox()); + kDebug() << "view created"; + } + } + //activate the new views (yes, this is a lazy way to do it) + setActive(m_active); +} + + +void PlasmaApp::setActive(bool activate) +{ + m_active = activate; + //note: allow this to run even if the value isn't changed, + //because some views may need updating. + if (activate) { + emit showViews(); + emit openToolBox(); + } else { + emit hideViews(); + } +} + +void PlasmaApp::syncConfig() +{ + KGlobal::config()->sync(); +} + +Plasma::Corona* PlasmaApp::corona() +{ + if (!m_corona) { + m_corona = new SaverCorona(this); + connect(m_corona, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)), + this, SLOT(containmentScreenOwnerChanged(int,int,Plasma::Containment*))); + connect(m_corona, SIGNAL(configSynced()), SLOT(syncConfig())); + //kDebug() << "connected to containmentAdded"; + /* + foreach (DesktopView *view, m_desktops) { + connect(c, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)), + view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*))); + }*/ + + m_corona->setItemIndexMethod(QGraphicsScene::NoIndex); + m_corona->initializeLayout(); + + //we want this *after* init so that we ignore any lock/unlock spasms that might happen then + connect(m_corona, SIGNAL(immutabilityChanged(Plasma::ImmutabilityType)), this, SLOT(immutabilityChanged(Plasma::ImmutabilityType))); + + //kDebug() << "layout should exist"; + //c->checkScreens(); + } + + return m_corona; +} + +bool PlasmaApp::hasComposite() +{ + return composite; +} + +void PlasmaApp::containmentScreenOwnerChanged(int wasScreen, int isScreen, Plasma::Containment *containment) +{ + Q_UNUSED(wasScreen); + if (isScreen < 0) + return; + m_viewsWaiting.append(containment); + m_viewCreationTimer.start(); +} + +void PlasmaApp::setup(bool setupMode) +{ + kDebug() << "setup mode:" << setupMode; + + if (setupMode) { + emit enableSetupMode(); + if (m_corona->immutability() == Plasma::UserImmutable) { + m_corona->setImmutability(Plasma::Mutable); + } + setActive(true); + } else { + kDebug() << "checking lockprocess is still around"; + QDBusInterface lockprocess("org.kde.screenlocker", "/LockProcess", + "org.kde.screenlocker.LockProcess", QDBusConnection::sessionBus(), this); + if (lockprocess.isValid()) { + kDebug() << "success!"; + setActive(false); + } else { + kDebug() << "bailing out"; + qApp->quit(); //this failed once. why? + } + } +} + +bool PlasmaApp::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Show) { + //apparently this means we created a new window + //so, add a tag to prove it's our window + //FIXME using the show event means we tag on every show, not just the first. + //harmless but kinda wasteful. + QWidget *widget = qobject_cast(obj); + if (widget && widget->isWindow() && !(qobject_cast(widget) || + widget->testAttribute(Qt::WA_DontShowOnScreen))) { + unsigned char data = 0; + if (qobject_cast(widget)) { + data = VIEW; + } else if (m_dialogs.contains(widget)) { + data = DIALOG; + } else { + Qt::WindowFlags oldFlags = widget->windowFlags(); + Qt::WindowFlags newFlags = oldFlags |Qt::X11BypassWindowManagerHint; + if (oldFlags != newFlags) { + //now we're *really* fucking with things + //we force-disable window management and frames to cut off access to wm-y stuff + //and to make it easy to check the tag (frames are a pain) + kDebug() << "!!!!!!!setting flags on!!!!!" << widget; + QDesktopWidget *desktop = QApplication::desktop(); + if (qobject_cast(widget)) { + //this is a terrible horrible hack that breaks extenders but it mostly works + //weird thing is, it sometimes makes the calendar popup too small. + newFlags = Qt::Popup; + } else { + //plasmadialogs can't handle direct input + //but configdialogs need it + m_dialogs.append(widget); + connect(widget, SIGNAL(destroyed(QObject*)), SLOT(dialogDestroyed(QObject*))); + connect(this, SIGNAL(showDialogs()), widget, SLOT(show())); + connect(this, SIGNAL(hideDialogs()), widget, SLOT(hide())); + } + widget->setWindowFlags(newFlags); + //we do not know the screen this widget should appear on + QRect availableGeometry = desktop->availableGeometry(); + //if has weird position, move to the default screen + if (!availableGeometry.contains(widget->pos())) { + widget->move(availableGeometry.x(), availableGeometry.y()); + } + widget->show(); //setting the flags hid it :( + //qApp->setActiveWindow(widget); //gives kbd but not mouse events + //kDebug() << "parent" << widget->parentWidget(); + //FIXME why can I only activate these dialogs from this exact line? + widget->activateWindow(); //gives keyboard focus + return false; //we'll be back when we get the new show event + } else { + widget->activateWindow(); //gives keyboard focus + } + } + + XChangeProperty(QX11Info::display(), widget->effectiveWinId(), tag, tag, 8, PropModeReplace, &data, 1); + XChangeProperty(QX11Info::display(), widget->effectiveWinId(), tag2, tag2, 32, PropModeReplace, 0, 0); + kDebug() << "tagged" << widget << widget->effectiveWinId() << "as" << data; + } + } + return false; +} + +void PlasmaApp::dialogDestroyed(QObject *obj) +{ + m_dialogs.removeAll(qobject_cast(obj)); + //if (m_dialogs.isEmpty()) { + //FIXME multiview + //if (m_view) { + //this makes qactions work again + //m_view->activateWindow(); + //} + /*} else { failed attempt to fix kbd input after a subdialog closes + QWidget *top = m_dialogs.last(); + top->activateWindow(); + kDebug() << top;*/ + //} +} + +void PlasmaApp::configureContainment(Plasma::Containment *containment) +{ +// SaverView *view = viewForScreen(containment->screen()); +// if (!view) { +// return; +// } + + if (m_configDialog) { + m_configDialog->reloadConfig(); + } else { + const QSize resolution = QApplication::desktop()->screenGeometry(containment->screen()).size(); + + m_configDialog = new BackgroundDialog(resolution, containment); + m_configDialog->setAttribute(Qt::WA_DeleteOnClose); + } + + m_configDialog->show(); +} + +void PlasmaApp::lock() +{ + kDebug() << "lock"; + if (corona() && corona()->immutability() == Plasma::Mutable) { + corona()->setImmutability(Plasma::UserImmutable); + } +} + +void PlasmaApp::quit() +{ + qApp->quit(); +} + +void PlasmaApp::immutabilityChanged(Plasma::ImmutabilityType immutability) +{ + if (immutability == Plasma::Mutable) { + emit showDialogs(); + } else { + emit hideDialogs(); + emit hideWidgetExplorer(); + emit disableSetupMode(); + } +} + +SaverView *PlasmaApp::viewForScreen(int screen) +{ + foreach(SaverView *view, m_views) { + if (view->screen() == screen) + return view; + } + return 0; +} + +#include "plasmaapp.moc" diff --git a/plasma/screensaver/shell/plasmaapp.h b/plasma/screensaver/shell/plasmaapp.h new file mode 100644 index 00000000..fb795024 --- /dev/null +++ b/plasma/screensaver/shell/plasmaapp.h @@ -0,0 +1,129 @@ +/* + * Copyright 2006, 2007 Aaron Seigo + * Copyright 2008 Chani Armitage + * + * 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, + * 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, see . + */ + +#ifndef PLASMA_APP_H +#define PLASMA_APP_H + +#include +#include +#include + +#include + +#include + +namespace Plasma +{ + class Containment; + class Corona; +} // namespace Plasma + +class SaverView; +class BackgroundDialog; + +class PlasmaApp : public KUniqueApplication +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.plasmaoverlay.App") +public: + ~PlasmaApp(); + + static PlasmaApp* self(); + static bool hasComposite(); + + Plasma::Corona* corona(); + +Q_SIGNALS: + // DBUS interface. + //if you change stuff, remember to regenerate with: + //qdbuscpp2xml -S -M plasmaapp.h > org.kde.plasma-overlay.App.xml + + //XXX can this be deleted? probably. if lockprocess really cares it can use the unmapnotify + void hidden(); + +public Q_SLOTS: + // DBUS interface. + //if you change stuff, remember to regenerate ^^^ + /** + * tell plasma to go into active mode, ready for interaction + */ + void setActive(bool activate); + + /** + * lock widgets + */ + void lock(); + + //not really slots, but we want them in dbus: + + /** + * get plasma all set up and ready + * this makes sure things like visibility and locked-ness are set right + * normally this is called only by plasmaapp itself when it finishes initialization, but it's + * possible that it might need to be run again by lockprocess + * + * @param setupMode whether we're starting in setup mode + */ + void setup(bool setupMode); + + /** + * quit the application + * this is a duplicate so we can have everything we need in one dbus interface + */ + void quit(); + +private Q_SLOTS: + void cleanup(); + //void adjustSize(int screen); + void dialogDestroyed(QObject *obj); + void configureContainment(Plasma::Containment*); + void syncConfig(); + void immutabilityChanged(Plasma::ImmutabilityType immutability); + void createWaitingViews(); + void containmentScreenOwnerChanged(int, int, Plasma::Containment*); + +Q_SIGNALS: + void showViews(); + void hideViews(); + void showDialogs(); + void hideDialogs(); + void hideWidgetExplorer(); + void enableSetupMode(); + void disableSetupMode(); + void openToolBox(); + void closeToolBox(); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +private: + PlasmaApp(Display* display, Qt::HANDLE visual, Qt::HANDLE colormap); + SaverView *viewForScreen(int screen); + + Plasma::Corona *m_corona; + QList m_views; + QList m_dialogs; + QPointer m_configDialog; + + QList > m_viewsWaiting; + QTimer m_viewCreationTimer; + + bool m_active; +}; + +#endif // multiple inclusion guard diff --git a/plasma/screensaver/shell/savercorona.cpp b/plasma/screensaver/shell/savercorona.cpp new file mode 100644 index 00000000..36a7f5d2 --- /dev/null +++ b/plasma/screensaver/shell/savercorona.cpp @@ -0,0 +1,269 @@ +/* + * Copyright 2008 Aaron Seigo + * Copyright 2008 by Chani Armitage + * Copyright 2011 Martin Gräßlin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see .. + */ + +#include "savercorona.h" +#include "kscreensaversettings.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +static const char *DEFAULT_MAIN_PACKAGE = "org.kde.passworddialog"; + +SaverCorona::SaverCorona(QObject *parent) + : Plasma::Corona(parent) + , m_engine(NULL) + , m_greeterItem(NULL) + , m_mode(ScreenLock) + , m_capsLocked(false) +{ + init(); +} + +void SaverCorona::init() +{ + setPreferredToolBoxPlugin(Plasma::Containment::DesktopContainment, "org.kde.desktoptoolbox"); + setPreferredToolBoxPlugin(Plasma::Containment::CustomContainment, "org.kde.desktoptoolbox"); + setPreferredToolBoxPlugin(Plasma::Containment::PanelContainment, "org.kde.paneltoolbox"); + setPreferredToolBoxPlugin(Plasma::Containment::CustomPanelContainment, "org.kde.paneltoolbox"); + + QDesktopWidget *desktop = QApplication::desktop(); + connect(desktop,SIGNAL(screenCountChanged(int)), SLOT(numScreensUpdated(int))); + m_numScreens = desktop->numScreens(); + + Plasma::ContainmentActionsPluginsConfig plugins; + plugins.addPlugin(Qt::NoModifier, Qt::RightButton, "minimalcontextmenu"); + //should I add paste too? + setContainmentActionsDefaults(Plasma::Containment::CustomContainment, plugins); + + bool unlocked = immutability() == Plasma::Mutable; + + QAction *lock = action("lock widgets"); + if (lock) { + kDebug() << "unlock action"; + //rename the lock action so that corona doesn't mess with it + addAction("unlock widgets", lock); + //rewire the action so we can check for a password + lock->disconnect(SIGNAL(triggered(bool))); + connect(lock, SIGNAL(triggered()), this, SLOT(toggleLock())); + lock->setIcon(KIcon(unlocked ? "object-locked" : "configure")); + lock->setText(unlocked ? i18n("Lock Screen") : i18n("Configure Widgets")); + } + + //the most important action ;) + QAction *leave = new QAction(unlocked ? i18n("Leave Screensaver") : i18n("Unlock"), this); + leave->setIcon(KIcon("system-lock-screen")); + leave->setShortcut(QKeySequence("esc")); + connect(leave, SIGNAL(triggered()), this, SLOT(unlockDesktop())); + addAction("unlock desktop", leave); + + //updateShortcuts(); //just in case we ever get a config dialog + + // create the QML Component + m_engine = new QDeclarativeEngine(this); + KDeclarative kdeclarative; + kdeclarative.setDeclarativeEngine(m_engine); + kdeclarative.initialize(); + kdeclarative.setupBindings(); + + connect(this, SIGNAL(immutabilityChanged(Plasma::ImmutabilityType)), SLOT(updateActions(Plasma::ImmutabilityType))); + + installEventFilter(this); +} + +void SaverCorona::loadDefaultLayout() +{ + //kDebug(); + QDesktopWidget *desktop = QApplication::desktop(); + + // create a containment for the screens + Plasma::Containment *c; + for(int screen = 0; screen < m_numScreens; ++screen) + { + QRect g = desktop->screenGeometry(screen); + kDebug() << " screen" << screen << "geometry is" << g; + c = addContainment("saverdesktop"); + if (c) { + c->setScreen(screen); + c->setFormFactor(Plasma::Planar); + c->flushPendingConstraintsEvents(); + } + } + + // a default clock + c = containmentForScreen(desktop->primaryScreen()); + if (c) { + Plasma::Applet *clock = Plasma::Applet::load("clock"/*, c->id() + 1*/); + c->addApplet(clock, QPointF(KDialog::spacingHint(), KDialog::spacingHint()), true); + clock->init(); + clock->flushPendingConstraintsEvents(); + } + //emit containmentAdded(c); +} + +int SaverCorona::numScreens() const +{ + return m_numScreens; +} + +QRect SaverCorona::screenGeometry(int id) const +{ + return QApplication::desktop()->screenGeometry(id); +} + +void SaverCorona::updateActions(Plasma::ImmutabilityType immutability) +{ + bool unlocked = immutability == Plasma::Mutable; + QAction *a = action("unlock widgets"); + if (a) { + a->setIcon(KIcon(unlocked ? "object-locked" : "configure")); + a->setText(unlocked ? i18n("Lock Screen") : i18n("Configure Widgets")); + } + a = action("unlock desktop"); + if (a) { + a->setText(unlocked ? i18n("Leave Screensaver") : i18n("Unlock")); + } +} + +void SaverCorona::toggleLock() +{ + //require a password to unlock + if (immutability() == Plasma::Mutable) { + setImmutability(Plasma::UserImmutable); + kDebug() << "locking up!"; + } else if (immutability() == Plasma::UserImmutable) { + // show a greeter + if (!m_greeterItem) { + createGreeter(); + } + m_mode = AppletLock; + // TODO: disable session switching + m_greeterItem->setProperty("notification", i18n("Unlock widgets to configure them")); + m_greeterItem->setVisible(true); + } +} + +void SaverCorona::unlockDesktop() +{ + if (!m_greeterItem) { + createGreeter(); + } + m_mode = ScreenLock; + m_greeterItem->setProperty("notification", ""); + // TODO: enable session switching + m_greeterItem->setVisible(true); +} + +void SaverCorona::numScreensUpdated(int newCount) +{ + m_numScreens = newCount; + //do something? +} + +void SaverCorona::createGreeter() +{ + Plasma::PackageStructure::Ptr structure = Plasma::PackageStructure::load("Plasma/Generic"); + Plasma::Package *package = new Plasma::Package(KStandardDirs::locate("data", "ksmserver/screenlocker/"), KScreenSaverSettings::greeterQML(), structure); + + QString mainQmlPath = package->filePath("mainscript"); + if (mainQmlPath.isEmpty()) { + delete package; + package = new Plasma::Package(KStandardDirs::locate("data", "ksmserver/screenlocker/"), DEFAULT_MAIN_PACKAGE, structure); + mainQmlPath = package->filePath("mainscript"); + } + + QDeclarativeComponent component(m_engine, QUrl::fromLocalFile(mainQmlPath)); + + m_greeterItem = qobject_cast(component.create()); + QDeclarativeProperty lockProperty(m_greeterItem, "locked"); + lockProperty.write(true); + + addItem(m_greeterItem); + m_greeterItem->setFocus(); + connect(m_greeterItem, SIGNAL(unlockRequested()), SLOT(greeterAccepted())); + connect(m_greeterItem, SIGNAL(canceled()), SLOT(greeterCanceled())); + const QRect screenRect = screenGeometry(QApplication::desktop()->primaryScreen()); + // TODO: center on screen + m_greeterItem->setPos(screenRect.x() + screenRect.width()/2, + screenRect.y() + screenRect.height()/2); +} + +void SaverCorona::greeterAccepted() +{ + if (m_mode == ScreenLock) { + qApp->quit(); + } else if (m_mode == AppletLock) { + setImmutability(Plasma::Mutable); + // greeter has problems with reusing after success + delete m_greeterItem; + m_greeterItem = NULL; + } +} + +void SaverCorona::greeterCanceled() +{ + m_greeterItem->setVisible(false); +} + +bool SaverCorona::eventFilter(QObject* watched, QEvent* event) +{ + Q_UNUSED(watched) + if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { + capsLocked(); + } + return false; +} + +void SaverCorona::capsLocked() +{ + unsigned int lmask; + Window dummy1, dummy2; + int dummy3, dummy4, dummy5, dummy6; + XQueryPointer(QX11Info::display(), DefaultRootWindow( QX11Info::display() ), &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6, &lmask); + const bool before = m_capsLocked; + m_capsLocked = lmask & LockMask; + if (before != m_capsLocked) { + if (m_greeterItem) { + m_greeterItem->setProperty("capsLockOn", m_capsLocked); + } + } +} + +#include "savercorona.moc" + diff --git a/plasma/screensaver/shell/savercorona.h b/plasma/screensaver/shell/savercorona.h new file mode 100644 index 00000000..4f814769 --- /dev/null +++ b/plasma/screensaver/shell/savercorona.h @@ -0,0 +1,75 @@ +/* + * Copyright 2008 Aaron Seigo + * Copyright 2008 by Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SAVERCORONA_H +#define SAVERCORONA_H + +#include + +#include + +class QDeclarativeEngine; + +/** + * @short A Corona for the screensaver + */ +class SaverCorona : public Plasma::Corona +{ + Q_OBJECT + +public: + explicit SaverCorona(QObject * parent = 0); + + /** + * Loads the default (system wide) layout for this user + **/ + void loadDefaultLayout(); + + virtual int numScreens() const; + virtual QRect screenGeometry(int id) const; + +protected: + virtual bool eventFilter(QObject *watched, QEvent *event); + +private Q_SLOTS: + void updateActions(Plasma::ImmutabilityType immutability); + void toggleLock(); + void unlockDesktop(); + void numScreensUpdated(int newCount); + void greeterAccepted(); + void greeterCanceled(); + +private: + enum UnlockMode { + AppletLock, + ScreenLock + }; + void init(); + void createGreeter(); + void capsLocked(); + + int m_numScreens; + QDeclarativeEngine *m_engine; + QGraphicsObject *m_greeterItem; + UnlockMode m_mode; + bool m_capsLocked; +}; + +#endif + + diff --git a/plasma/screensaver/shell/saverview.cpp b/plasma/screensaver/shell/saverview.cpp new file mode 100644 index 00000000..8937df7d --- /dev/null +++ b/plasma/screensaver/shell/saverview.cpp @@ -0,0 +1,294 @@ +/* + * Copyright 2007 Aaron Seigo + * Copyright 2007 Matt Broadstone + * Copyright 2007 André Duffeck + * Copyright 2008 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "saverview.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include "plasmaapp.h" + +static const int SUPPRESS_SHOW_TIMEOUT = 500; // Number of millis to prevent reshow of dashboard + + +class ScreenSaverWidgetExplorer : public Plasma::WidgetExplorer +{ +public: + ScreenSaverWidgetExplorer(QGraphicsWidget *parent) + : Plasma::WidgetExplorer(parent) + { + connect(this, SIGNAL(closeClicked()), this, SLOT(deleteLater())); + m_svg = new Plasma::FrameSvg(this); + m_svg->setImagePath("widgets/frame"); + m_svg->setElementPrefix("raised"); + m_svg->setEnabledBorders(Plasma::FrameSvg::TopBorder); + } + +protected: + void resizeEvent(QGraphicsSceneResizeEvent *event) + { + m_svg->resizeFrame(event->newSize()); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + Q_UNUSED(option) + Q_UNUSED(widget) + m_svg->paintFrame(painter); + } + +private: + Plasma::FrameSvg *m_svg; +}; + +SaverView::SaverView(Plasma::Containment *containment, QWidget *parent) + : Plasma::View(containment, parent), + m_suppressShow(false), + m_setupMode(false), + m_init(false) +{ + setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | + Qt::X11BypassWindowManagerHint); + + //app is doing this for us - if needed + //QDesktopWidget *desktop = QApplication::desktop(); + //setGeometry(desktop->screenGeometry(containment->screen())); + + setWallpaperEnabled(true); + + containment->corona()->installEventFilter(this); +} + +SaverView::~SaverView() +{ + delete m_widgetExplorer.data(); +} + +void SaverView::enableSetupMode() +{ + if (!m_setupMode) { + m_setupMode = true; + update(); + } +} + +void SaverView::disableSetupMode() +{ + if (m_setupMode) { + m_setupMode = false; + update(); + } +} + +void SaverView::drawBackground(QPainter *painter, const QRectF & rect) +{ + if (PlasmaApp::hasComposite()) { + painter->setCompositionMode(QPainter::CompositionMode_Source); + painter->fillRect(rect, Qt::transparent); + } else { + Plasma::View::drawBackground(painter, rect); + } +} + +void SaverView::showWidgetExplorer() +{ + Plasma::Containment *c = containment(); + if (!c) { + return; + } + + if (m_widgetExplorer) { + delete m_widgetExplorer.data(); + } else { + ScreenSaverWidgetExplorer *widgetExplorer = new ScreenSaverWidgetExplorer(c); + widgetExplorer->installEventFilter(this); + widgetExplorer->setContainment(c); + widgetExplorer->setLocation(Plasma::BottomEdge); + widgetExplorer->populateWidgetList(); + widgetExplorer->setMaximumWidth(width()); + widgetExplorer->adjustSize(); + widgetExplorer->setZValue(1000000); + widgetExplorer->resize(width(), widgetExplorer->size().height()); + widgetExplorer->setPos(0, containment()->geometry().height() - widgetExplorer->geometry().height()); + m_widgetExplorer = widgetExplorer; + } +} + +void SaverView::hideWidgetExplorer() +{ + delete m_widgetExplorer.data(); +} + +void SaverView::paintEvent(QPaintEvent *event) +{ + Plasma::View::paintEvent(event); + if (!m_setupMode) { + return; + } + + // now draw a little label reminding the user their screen's not quite locked + const QRect r = rect(); + const QString text = i18n("Setup Mode - Screen is NOT locked"); + QFont f = font(); + f.bold(); + const QFontMetrics fm(f); + const int margin = 6; + const int textWidth = fm.width(text); + const QPoint centered(r.width() / 2 - textWidth / 2 - margin, r.y()); + const QRect boundingBox(centered, QSize(margin * 2 + textWidth, fm.height() + margin * 2)); + + if (!viewport() || !event->rect().intersects(boundingBox)) { + return; + } + + QPainterPath box; + box.moveTo(boundingBox.topLeft()); + box.lineTo(boundingBox.bottomLeft() + QPoint(0, -margin * 2)); + box.quadTo(boundingBox.bottomLeft(), boundingBox.bottomLeft() + QPoint(margin * 2, 0)); + box.lineTo(boundingBox.bottomRight() + QPoint(-margin * 2, 0)); + box.quadTo(boundingBox.bottomRight(), boundingBox.bottomRight() + QPoint(0, -margin * 2)); + box.lineTo(boundingBox.topRight()); + box.closeSubpath(); + + QPainter painter(viewport()); + painter.setRenderHint(QPainter::Antialiasing); + painter.setFont(f); + //kDebug() << "******************** painting from" << centered << boundingBox << rect() << event->rect(); + QColor highlight = palette().highlight().color(); + highlight.setAlphaF(0.7); + painter.setPen(highlight.darker()); + painter.setBrush(highlight); + painter.drawPath(box); + painter.setPen(palette().highlightedText().color()); + painter.drawText(boundingBox, Qt::AlignCenter | Qt::AlignVCenter, text); +} + +bool SaverView::eventFilter(QObject *watched, QEvent *event) +{ + if (containment() && (watched == (QObject*)m_widgetExplorer.data()) && + (event->type() == QEvent::GraphicsSceneResize || event->type() == QEvent::GraphicsSceneMove)) { + Plasma::WidgetExplorer *widgetExplorer = m_widgetExplorer.data(); + widgetExplorer->setPos(0, containment()->geometry().height() - widgetExplorer->geometry().height()); + } else if (watched == containment()->corona() && event->type() == QEvent::GraphicsSceneMousePress) { + activateWindow(); + grabKeyboard(); + } + + return false; +} + +void SaverView::showView() +{ + if (isHidden()) { + if (m_suppressShow) { + kDebug() << "show was suppressed"; + return; + } + + setWindowState(Qt::WindowFullScreen); + //KWindowSystem::setOnAllDesktops(winId(), true); + //KWindowSystem::setState(winId(), NET::KeepAbove|NET::SkipTaskbar); + + show(); + raise(); + + m_suppressShow = true; + QTimer::singleShot(SUPPRESS_SHOW_TIMEOUT, this, SLOT(suppressShowTimeout())); + activateWindow(); + grabKeyboard(); + } +} + +void SaverView::setContainment(Plasma::Containment *newContainment) +{ + if (m_init && newContainment == containment()) { + return; + } + + m_init = true; + + if (containment()) { + disconnect(containment(), SIGNAL(showAddWidgetsInterface(QPointF)), this, SLOT(showWidgetExplorer())); + } + + if (newContainment) { + connect(newContainment, SIGNAL(showAddWidgetsInterface(QPointF)), this, SLOT(showWidgetExplorer())); + } + + if (m_widgetExplorer) { + m_widgetExplorer.data()->setContainment(newContainment); + } + + View::setContainment(newContainment); +} + +void SaverView::hideView() +{ + if (isHidden()) { + return; + } + + hideWidgetExplorer(); + + if (containment()) { + containment()->closeToolBox(); + } + + hide(); + //let the lockprocess know + emit hidden(); +} + +void SaverView::suppressShowTimeout() +{ + kDebug() << "SaverView::suppressShowTimeout"; + m_suppressShow = false; +} + +void SaverView::openToolBox() +{ + kDebug() << "close toolbox"; + containment()->openToolBox(); +} + +void SaverView::closeToolBox() +{ + kDebug() << "close toolbox"; + containment()->closeToolBox(); +} + +void SaverView::adjustSize(int screen) +{ + QDesktopWidget *desktop = QApplication::desktop(); + int thisScreen = desktop->screenNumber(this); + if(screen == thisScreen) + { + setGeometry(desktop->screenGeometry(screen)); + } +} + +#include "saverview.moc" diff --git a/plasma/screensaver/shell/saverview.h b/plasma/screensaver/shell/saverview.h new file mode 100644 index 00000000..dbf00cde --- /dev/null +++ b/plasma/screensaver/shell/saverview.h @@ -0,0 +1,82 @@ +/* + * Copyright 2007 Aaron Seigo + * Copyright 2007 André Duffeck + * Copyright 2008 Chani Armitage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SAVERVIEW_H +#define SAVERVIEW_H + +#include + +#include +#include + +namespace Plasma +{ + class Containment; + class WidgetExplorer; +} + +class SaverView : public Plasma::View +{ + Q_OBJECT + +public: + SaverView(Plasma::Containment* containment, QWidget *parent); + ~SaverView(); + + bool eventFilter(QObject *watched, QEvent *event); + +signals: + void hidden(); + +protected: + void drawBackground(QPainter *painter, const QRectF & rect); + void paintEvent(QPaintEvent *event); + +public slots: + void showView(); + void hideView(); + void adjustSize(int screen); + + /** + * Sets the containment for this view, which will also cause the view + * to track the geometry of the containment. + * + * @arg containment the containment to center the view on + */ + void setContainment(Plasma::Containment *newContainment); + void hideWidgetExplorer(); + + void enableSetupMode(); + void disableSetupMode(); + +protected slots: + void showWidgetExplorer(); //FIXME actually this is toggle + void suppressShowTimeout(); + void openToolBox(); + void closeToolBox(); + +private: + QWeakPointer m_widgetExplorer; + QPoint m_appletBrowserDragStart; + bool m_suppressShow : 1; + bool m_setupMode : 1; + bool m_init : 1; +}; + +#endif // multiple inclusion guard diff --git a/powerdevil/.krazy b/powerdevil/.krazy new file mode 100644 index 00000000..74563658 --- /dev/null +++ b/powerdevil/.krazy @@ -0,0 +1,3 @@ +EXTRA null +EXTRA kdebug +EXTRA defines diff --git a/powerdevil/CMakeLists.txt b/powerdevil/CMakeLists.txt new file mode 100644 index 00000000..0bede398 --- /dev/null +++ b/powerdevil/CMakeLists.txt @@ -0,0 +1,11 @@ + +include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/daemon +) + +add_subdirectory(daemon) +add_subdirectory(kcmodule) + +install( FILES powerdevil.notifyrc DESTINATION ${DATA_INSTALL_DIR}/powerdevil ) diff --git a/powerdevil/COPYING b/powerdevil/COPYING new file mode 100644 index 00000000..5185fd3f --- /dev/null +++ b/powerdevil/COPYING @@ -0,0 +1,346 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + 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 Library 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. + + + Copyright (C) 19yy + + 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) 19yy 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. + + , 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 Library General +Public License instead of this License. diff --git a/powerdevil/PowerDevilSettings.kcfg b/powerdevil/PowerDevilSettings.kcfg new file mode 100644 index 00000000..cd103c6d --- /dev/null +++ b/powerdevil/PowerDevilSettings.kcfg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + + + + 20 + + + 5 + + + 2 + + + diff --git a/powerdevil/PowerDevilSettings.kcfgc b/powerdevil/PowerDevilSettings.kcfgc new file mode 100644 index 00000000..4d4f6361 --- /dev/null +++ b/powerdevil/PowerDevilSettings.kcfgc @@ -0,0 +1,5 @@ +ClassName=PowerDevilSettings +File=PowerDevilSettings.kcfg +Mutators=true +Singleton=true +Visibility=KDE_EXPORT diff --git a/powerdevil/daemon/BackendConfig.cmake b/powerdevil/daemon/BackendConfig.cmake new file mode 100644 index 00000000..41c8812a --- /dev/null +++ b/powerdevil/daemon/BackendConfig.cmake @@ -0,0 +1,66 @@ +# This files sets the needed sources for powerdevil's backend +# TODO 4.7: Compile only one backend instead of doing runtime checks + + +########################## UPower Backend ##################################### +if (UDEV_FOUND) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/backends/upower + ${X11_INCLUDE_DIR} + ${X11_Xrandr_INCLUDE_PATH}) + + set(powerdevilupowerbackend_SRCS + backends/upower/upowersuspendjob.cpp + backends/upower/login1suspendjob.cpp + backends/upower/powerdevilupowerbackend.cpp + backends/upower/xrandrbrightness.cpp + backends/upower/xrandrx11helper.cpp + backends/upower/udevqtclient.cpp + backends/upower/udevqtdevice.cpp + ) + + set_source_files_properties( + ${CMAKE_CURRENT_SOURCE_DIR}/backends/upower/dbus/org.freedesktop.UPower.xml + ${CMAKE_CURRENT_SOURCE_DIR}/backends/upower/dbus/org.freedesktop.UPower.Device.xml + PROPERTIES NO_NAMESPACE TRUE) + + qt4_add_dbus_interface(powerdevilupowerbackend_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/backends/upower/dbus/org.freedesktop.UPower.xml + upower_interface) + + qt4_add_dbus_interface(powerdevilupowerbackend_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/backends/upower/dbus/org.freedesktop.UPower.Device.xml + upower_device_interface) + + qt4_add_dbus_interface(powerdevilupowerbackend_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/backends/upower/dbus/org.freedesktop.UPower.KbdBacklight.xml + upower_kbdbacklight_interface) + + qt4_add_dbus_interface(powerdevilupowerbackend_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/backends/upower/dbus/com.ubuntu.Upstart.xml + upstart_interface) + + set(powerdevilupowerbackend_LIBS ${X11_LIBRARIES} ${QT_QTGUI_LIBRARY} ${X11_Xrandr_LIB} ${KDE4_KDEUI_LIBRARY} ${UDEV_LIBS}) + + ## backlight helper executable + kde4_add_executable(backlighthelper backends/upower/backlighthelper.cpp ${backlighthelper_mocs}) + target_link_libraries(backlighthelper ${KDE4_KDECORE_LIBS}) + install(TARGETS backlighthelper DESTINATION ${LIBEXEC_INSTALL_DIR}) + kde4_install_auth_helper_files(backlighthelper org.kde.powerdevil.backlighthelper root) + kde4_install_auth_actions(org.kde.powerdevil.backlighthelper ${CMAKE_CURRENT_SOURCE_DIR}/backends/upower/backlight_helper_actions.actions) +endif (UDEV_FOUND) + +########################## HAL Backend ##################################### + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/backends/hal) + +set(powerdevilhalbackend_SRCS + backends/hal/halsuspendjob.cpp + backends/hal/powerdevilhalbackend.cpp +) + +set(powerdevilhalbackend_LIBS ${KDE4_SOLID_LIBS}) + +########################## Daemon variables ################################ + +set(POWERDEVIL_BACKEND_SRCS ${powerdevilupowerbackend_SRCS} ${powerdevilhalbackend_SRCS}) +set(POWERDEVIL_BACKEND_LIBS ${powerdevilupowerbackend_LIBS} ${powerdevilhalbackend_LIBS}) diff --git a/powerdevil/daemon/CMakeLists.txt b/powerdevil/daemon/CMakeLists.txt new file mode 100644 index 00000000..0a965ff6 --- /dev/null +++ b/powerdevil/daemon/CMakeLists.txt @@ -0,0 +1,112 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) + +add_subdirectory(actions) + +set(POWERDEVIL_CORE_VERSION_MAJOR 0) +set(POWERDEVIL_CORE_VERSION_MINOR 1) +set(POWERDEVIL_CORE_VERSION_MICRO 0) +set(POWERDEVIL_CORE_VERSION_STRING ${POWERDEVIL_CORE_VERSION_MAJOR}.${POWERDEVIL_CORE_VERSION_MINOR}.${POWERDEVIL_CORE_VERSION_MICRO}) + +# Add bundled actions +set(powerdevil_bundled_actions_SRCS + actions/bundled/suspendsession.cpp + actions/bundled/brightnesscontrol.cpp + actions/bundled/keyboardbrightnesscontrol.cpp + actions/bundled/dimdisplay.cpp + actions/bundled/runscript.cpp + actions/bundled/handlebuttonevents.cpp +) + +# target no.1 - powerdevil core library +set(powerdevilcore_SRCS + powerdevilaction.cpp + powerdevilactionpool.cpp + powerdevilbackendinterface.cpp + powerdevilcore.cpp + powerdevilpolicyagent.cpp + powerdevilprofilegenerator.cpp + + brightnessosdwidget.cpp +) + +kde4_add_kcfg_files(powerdevilcore_SRCS ../PowerDevilSettings.kcfgc) + +set(screensaver_xml "${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/screenlocker/dbus/org.freedesktop.ScreenSaver.xml") +qt4_add_dbus_interface(powerdevilcore_SRCS ${screensaver_xml} screensaver_interface ) + +# Action DBus Adaptors +qt4_add_dbus_adaptor(powerdevilcore_SRCS actions/bundled/org.kde.Solid.PowerManagement.Actions.BrightnessControl.xml + actions/bundled/brightnesscontrol.h PowerDevil::BundledActions::BrightnessControl) +qt4_add_dbus_adaptor(powerdevilcore_SRCS actions/bundled/org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl.xml + actions/bundled/keyboardbrightnesscontrol.h PowerDevil::BundledActions::KeyboardBrightnessControl) +qt4_add_dbus_adaptor(powerdevilcore_SRCS actions/bundled/org.kde.Solid.PowerManagement.Actions.HandleButtonEvents.xml + actions/bundled/handlebuttonevents.h PowerDevil::BundledActions::HandleButtonEvents) +qt4_add_dbus_adaptor(powerdevilcore_SRCS actions/bundled/org.kde.Solid.PowerManagement.Actions.SuspendSession.xml + actions/bundled/suspendsession.h PowerDevil::BundledActions::SuspendSession) + +kde4_add_library(powerdevilcore SHARED ${powerdevilcore_SRCS} ${powerdevil_bundled_actions_SRCS}) +set_target_properties(powerdevilcore PROPERTIES VERSION ${POWERDEVIL_CORE_VERSION_STRING} SOVERSION ${POWERDEVIL_CORE_VERSION_MAJOR}) + +target_link_libraries(powerdevilcore + ${KDE4_KDECORE_LIBS} + ${KDE4_SOLID_LIBS} + ${KDE4_KIDLETIME_LIBS} + ${KDE4_PLASMA_LIBS} + ${KACTIVITIES_LIBRARY} + kworkspace +) + +# target no.2 - powerdevil kded module +set(kded_powerdevil_SRCS + kdedpowerdevil.cpp + powerdevilbackendloader.cpp + powerdevilfdoconnector.cpp +) + +# DBus Adaptors +qt4_add_dbus_adaptor(kded_powerdevil_SRCS org.kde.Solid.PowerManagement.xml powerdevilcore.h PowerDevil::Core) +qt4_add_dbus_adaptor(kded_powerdevil_SRCS ${KDE4_DBUS_INTERFACES_DIR}/org.kde.Solid.PowerManagement.PolicyAgent.xml + powerdevilpolicyagent.h PowerDevil::PolicyAgent + powermanagementpolicyagentadaptor PowerManagementPolicyAgentAdaptor) + +qt4_add_dbus_adaptor(kded_powerdevil_SRCS ${KDE4_DBUS_INTERFACES_DIR}/org.freedesktop.PowerManagement.xml powerdevilfdoconnector.h PowerDevil::FdoConnector powermanagementfdoadaptor PowerManagementFdoAdaptor) +qt4_add_dbus_adaptor(kded_powerdevil_SRCS ${KDE4_DBUS_INTERFACES_DIR}/org.freedesktop.PowerManagement.Inhibit.xml powerdevilfdoconnector.h PowerDevil::FdoConnector powermanagementinhibitadaptor PowerManagementInhibitAdaptor) + + +# Backends +include(BackendConfig.cmake) + +kde4_add_plugin(kded_powerdevil ${kded_powerdevil_SRCS} ${POWERDEVIL_BACKEND_SRCS}) + +target_link_libraries(kded_powerdevil + ${KDE4_KDECORE_LIBS} + ${POWERDEVIL_BACKEND_LIBS} + powerdevilcore +) + +if (UDEV_FOUND) + target_link_libraries(kded_powerdevil ${UDEV_LIBS}) +endif (UDEV_FOUND) + +install(TARGETS kded_powerdevil DESTINATION ${PLUGIN_INSTALL_DIR}) +install(TARGETS powerdevilcore ${INSTALL_TARGETS_DEFAULT_ARGS}) + +# target no.3 - powerdevil ui library +set(powerdevilui_SRCS + powerdevilactionconfig.cpp +) + +kde4_add_library(powerdevilui SHARED ${powerdevilui_SRCS}) +set_target_properties(powerdevilui PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) + +target_link_libraries(powerdevilui + ${KDE4_KDECORE_LIBS} + ${QT_QTGUI_LIBRARY} +) + +macro_bool_to_01(UDEV_FOUND HAVE_UDEV) +configure_file(config-powerdevil.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-powerdevil.h ) + +install(TARGETS powerdevilui ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES powerdevil.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded) diff --git a/powerdevil/daemon/Messages.sh b/powerdevil/daemon/Messages.sh new file mode 100755 index 00000000..ded50a52 --- /dev/null +++ b/powerdevil/daemon/Messages.sh @@ -0,0 +1,5 @@ +#! /bin/sh +$EXTRACTRC `find -name \*.ui -o -name \*.rc -o -name \*.kcfg` >> rc.cpp || exit 11 +$XGETTEXT `find -name \*.cpp -o -name \*.h` -o $podir/powerdevil.pot +rm -f rc.cpp + diff --git a/powerdevil/daemon/actions/CMakeLists.txt b/powerdevil/daemon/actions/CMakeLists.txt new file mode 100644 index 00000000..db9ca479 --- /dev/null +++ b/powerdevil/daemon/actions/CMakeLists.txt @@ -0,0 +1,6 @@ +install(FILES powerdevilaction.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) + +add_subdirectory(bundled) +if(HAVE_DPMS) + add_subdirectory(dpms) +endif(HAVE_DPMS) \ No newline at end of file diff --git a/powerdevil/daemon/actions/bundled/CMakeLists.txt b/powerdevil/daemon/actions/bundled/CMakeLists.txt new file mode 100644 index 00000000..d3470016 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/CMakeLists.txt @@ -0,0 +1,19 @@ +function(add_powerdevil_bundled_action _name) + set(actionconfig_SRCS ${_name}config.cpp) + kde4_add_plugin(powerdevil${_name}action_config + ${actionconfig_SRCS}) + target_link_libraries(powerdevil${_name}action_config + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + powerdevilui + ${ARGN}) + install(TARGETS powerdevil${_name}action_config DESTINATION ${PLUGIN_INSTALL_DIR}) + install(FILES powerdevil${_name}action.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +endfunction(add_powerdevil_bundled_action _name) + +add_powerdevil_bundled_action(brightnesscontrol) +add_powerdevil_bundled_action(keyboardbrightnesscontrol) +add_powerdevil_bundled_action(dimdisplay) +add_powerdevil_bundled_action(runscript ${KDE4_KIO_LIBS}) +add_powerdevil_bundled_action(suspendsession ${KDE4_KIO_LIBS} ${KDE4_SOLID_LIBS}) +add_powerdevil_bundled_action(handlebuttonevents ${KDE4_SOLID_LIBS}) diff --git a/powerdevil/daemon/actions/bundled/brightnesscontrol.cpp b/powerdevil/daemon/actions/bundled/brightnesscontrol.cpp new file mode 100644 index 00000000..49026ab8 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/brightnesscontrol.cpp @@ -0,0 +1,191 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "brightnesscontrol.h" + +#include "brightnessosdwidget.h" + +#include "brightnesscontroladaptor.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace PowerDevil { +namespace BundledActions { + +BrightnessControl::BrightnessControl(QObject* parent) + : Action(parent) +{ + // DBus + new BrightnessControlAdaptor(this); + + setRequiredPolicies(PowerDevil::PolicyAgent::ChangeScreenSettings); + + connect(core()->backend(), SIGNAL(brightnessChanged(float,PowerDevil::BackendInterface::BrightnessControlType)), + this, SLOT(onBrightnessChangedFromBackend(float,PowerDevil::BackendInterface::BrightnessControlType))); + + KActionCollection* actionCollection = new KActionCollection( this ); + + KAction* globalAction = actionCollection->addAction("Increase Screen Brightness"); + globalAction->setText(i18nc("@action:inmenu Global shortcut", "Increase Screen Brightness")); + globalAction->setGlobalShortcut(KShortcut(Qt::Key_MonBrightnessUp)); + connect(globalAction, SIGNAL(triggered(bool)), SLOT(increaseBrightness())); + + globalAction = actionCollection->addAction("Decrease Screen Brightness"); + globalAction->setText(i18nc("@action:inmenu Global shortcut", "Decrease Screen Brightness")); + globalAction->setGlobalShortcut(KShortcut(Qt::Key_MonBrightnessDown)); + connect(globalAction, SIGNAL(triggered(bool)), SLOT(decreaseBrightness())); +} + +BrightnessControl::~BrightnessControl() +{ + if (!m_brightnessOSD.isNull()) { + m_brightnessOSD.data()->deleteLater(); + } +} + +void BrightnessControl::onProfileUnload() +{ + // +} + +void BrightnessControl::onWakeupFromIdle() +{ + // +} + +void BrightnessControl::onIdleTimeout(int msec) +{ + Q_UNUSED(msec); +} + +void BrightnessControl::onProfileLoad() +{ + // This unparsable conditional block means: if the current profile is more + // conservative than the previous one and the current brightness is lower + // than the new profile + if (((m_currentProfile == "Battery" && m_lastProfile == "AC") || + (m_currentProfile == "LowBattery" && (m_lastProfile == "AC" || m_lastProfile == "Battery"))) && + m_defaultValue > brightness()) { + // We don't want to change anything here + kDebug() << "Not changing brightness, the current one is lower and the profile is more conservative"; + } else if (m_defaultValue >= 0) { + QVariantMap args; + args["Value"] = QVariant::fromValue((float)m_defaultValue); + trigger(args); + } +} + +void BrightnessControl::triggerImpl(const QVariantMap& args) +{ + backend()->setBrightness(args["Value"].toFloat()); + if (args["Explicit"].toBool()) { + showBrightnessOSD(backend()->brightness()); + } +} + +bool BrightnessControl::isSupported() +{ + BackendInterface::BrightnessControlsList controls = backend()->brightnessControlsAvailable(); + if (controls.key(BackendInterface::Screen).isEmpty()) { + return false; + } + + return true; +} + +bool BrightnessControl::loadAction(const KConfigGroup& config) +{ + // Handle profile changes + m_lastProfile = m_currentProfile; + m_currentProfile = config.parent().name(); + + kDebug() << "Profiles: " << m_currentProfile << m_lastProfile; + + if (config.hasKey("value")) { + m_defaultValue = config.readEntry("value", 50); + } else { + m_defaultValue = -1; + } + + return true; +} + +void BrightnessControl::showBrightnessOSD(int brightness) +{ + // code adapted from KMix + if (m_brightnessOSD.isNull()) { + m_brightnessOSD = new BrightnessOSDWidget(BackendInterface::Screen); + } + + m_brightnessOSD.data()->setCurrentBrightness(brightness); + m_brightnessOSD.data()->show(); + m_brightnessOSD.data()->activateOSD(); //Enable the hide timer + + //Center the OSD + QDesktopWidget * desktop = qApp->desktop(); + QRect rect = desktop->screenGeometry(desktop->primaryScreen()); + QSize size = m_brightnessOSD.data()->sizeHint(); + int posX = rect.x() + (rect.width() - size.width()) / 2; + int posY = rect.y() + 4 * rect.height() / 5; + m_brightnessOSD.data()->setGeometry(posX, posY, size.width(), size.height()); +} + +void BrightnessControl::onBrightnessChangedFromBackend(float brightness, PowerDevil::BackendInterface::BrightnessControlType type) +{ + if (type == BackendInterface::Screen) { + showBrightnessOSD(brightness); + Q_EMIT brightnessChanged(brightness); + } +} + +int BrightnessControl::brightness() const +{ + return backend()->brightness(); +} + +void BrightnessControl::setBrightness(int percent) +{ + QVariantMap args; + args["Value"] = QVariant::fromValue((float)percent); + args["Explicit"] = true; + trigger(args); +} + +void BrightnessControl::increaseBrightness() +{ + backend()->brightnessKeyPressed(BackendInterface::Increase); +} + +void BrightnessControl::decreaseBrightness() +{ + backend()->brightnessKeyPressed(BackendInterface::Decrease); +} + +} +} diff --git a/powerdevil/daemon/actions/bundled/brightnesscontrol.h b/powerdevil/daemon/actions/bundled/brightnesscontrol.h new file mode 100644 index 00000000..c4844f07 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/brightnesscontrol.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_BRIGHTNESSCONTROL_H +#define POWERDEVIL_BUNDLEDACTIONS_BRIGHTNESSCONTROL_H + +#include +#include + +class BrightnessOSDWidget; + +namespace PowerDevil { +namespace BundledActions { + +class BrightnessControl : public PowerDevil::Action +{ + Q_OBJECT + Q_DISABLE_COPY(BrightnessControl) + Q_CLASSINFO("D-Bus Interface", "org.kde.Solid.PowerManagement.Actions.BrightnessControl") + +public: + explicit BrightnessControl(QObject* parent); + virtual ~BrightnessControl(); + +protected: + virtual void onProfileUnload(); + virtual void onWakeupFromIdle(); + virtual void onIdleTimeout(int msec); + virtual void onProfileLoad(); + virtual void triggerImpl(const QVariantMap& args); + virtual bool isSupported(); + +public: + virtual bool loadAction(const KConfigGroup& config); + +public Q_SLOTS: + void showBrightnessOSD(int brightness); + + // DBus export + void increaseBrightness(); + void decreaseBrightness(); + int brightness() const; + void setBrightness(int percent); + +private Q_SLOTS: + void onBrightnessChangedFromBackend(float brightness, PowerDevil::BackendInterface::BrightnessControlType type); + +Q_SIGNALS: + void brightnessChanged(int percent); + +private: + int m_defaultValue; + QWeakPointer< BrightnessOSDWidget > m_brightnessOSD; + QString m_lastProfile; + QString m_currentProfile; +}; + +} + +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_BRIGHTNESSCONTROL_H diff --git a/powerdevil/daemon/actions/bundled/brightnesscontrolconfig.cpp b/powerdevil/daemon/actions/bundled/brightnesscontrolconfig.cpp new file mode 100644 index 00000000..1ce410f6 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/brightnesscontrolconfig.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "brightnesscontrolconfig.h" + +#include +#include +#include + +#include +#include + +K_PLUGIN_FACTORY(PowerDevilBrightnessControlConfigFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(PowerDevilBrightnessControlConfigFactory("powerdevilbrightnesscontrolaction_config")) + +namespace PowerDevil { +namespace BundledActions { + +BrightnessControlConfig::BrightnessControlConfig(QObject *parent, const QVariantList& ) + : ActionConfig(parent) +{ + +} + +BrightnessControlConfig::~BrightnessControlConfig() +{ + +} + +void BrightnessControlConfig::save() +{ + configGroup().writeEntry("value", m_slider->value()); + configGroup().sync(); +} + +void BrightnessControlConfig::load() +{ + configGroup().config()->reparseConfiguration(); + m_slider->setValue(configGroup().readEntry("value", 50)); +} + +QList< QPair< QString, QWidget* > > BrightnessControlConfig::buildUi() +{ + QList< QPair< QString, QWidget* > > retlist; + m_slider = new QSlider(Qt::Horizontal); + m_slider->setMaximumWidth(300); + m_slider->setRange(0, 100); + retlist.append(qMakePair< QString, QWidget* >(i18nc("Brightness level, label for the slider", "Level"), m_slider)); + + connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(setChanged())); + + return retlist; +} + + +} +} + +#include "brightnesscontrolconfig.moc" diff --git a/powerdevil/daemon/actions/bundled/brightnesscontrolconfig.h b/powerdevil/daemon/actions/bundled/brightnesscontrolconfig.h new file mode 100644 index 00000000..2419bc88 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/brightnesscontrolconfig.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_BRIGHTNESSCONTROLCONFIG_H +#define POWERDEVIL_BUNDLEDACTIONS_BRIGHTNESSCONTROLCONFIG_H + +#include + +#include + +class QSlider; + +namespace PowerDevil { +namespace BundledActions { + +class KDE_EXPORT BrightnessControlConfig : public PowerDevil::ActionConfig +{ + Q_OBJECT + Q_DISABLE_COPY(BrightnessControlConfig) +public: + BrightnessControlConfig(QObject*, const QVariantList&); + virtual ~BrightnessControlConfig(); + + virtual void save(); + virtual void load(); + virtual QList< QPair< QString, QWidget* > > buildUi(); + +private: + QSlider *m_slider; +}; + +} +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_BRIGHTNESSCONTROLCONFIG_H diff --git a/powerdevil/daemon/actions/bundled/dimdisplay.cpp b/powerdevil/daemon/actions/bundled/dimdisplay.cpp new file mode 100644 index 00000000..fc265855 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/dimdisplay.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "dimdisplay.h" + +#include + +#include +#include +#include + +namespace PowerDevil { +namespace BundledActions { + +DimDisplay::DimDisplay(QObject* parent) + : Action(parent), m_dimmed(false) +{ + setRequiredPolicies(PowerDevil::PolicyAgent::ChangeScreenSettings); +} + +DimDisplay::~DimDisplay() +{ + +} + +void DimDisplay::onProfileUnload() +{ +} + +void DimDisplay::onWakeupFromIdle() +{ + if (!m_dimmed) { + return; + } + setBrightnessHelper(m_oldBrightness); + m_dimmed = false; +} + +void DimDisplay::onIdleTimeout(int msec) +{ + if (qFuzzyIsNull(backend()->brightness())) { + //Some drivers report brightness == 0 when display is off because of DPMS + //(especially Intel driver). Don't change brightness in this case, or + //backlight won't switch on later. + //Furthermore, we can't dim if brightness is 0 already. + return; + } + + if (msec == m_dimOnIdleTime) { + setBrightnessHelper(0); + } else if (msec == (m_dimOnIdleTime * 3 / 4)) { + float newBrightness = backend()->brightness() / 4; + setBrightnessHelper(newBrightness); + } else if (msec == (m_dimOnIdleTime * 1 / 2)) { + m_oldBrightness = backend()->brightness(); + float newBrightness = backend()->brightness() / 2; + setBrightnessHelper(newBrightness); + } + + m_dimmed = true; +} + +void DimDisplay::onProfileLoad() +{ + // +} + +void DimDisplay::setBrightnessHelper(float brightness) +{ + QVariantMap args; + args["_BrightnessValue"] = QVariant::fromValue(brightness); + trigger(args); +} + +void DimDisplay::triggerImpl(const QVariantMap& args) +{ + backend()->setBrightness(args["_BrightnessValue"].toFloat()); +} + +bool DimDisplay::isSupported() +{ + BackendInterface::BrightnessControlsList controls = backend()->brightnessControlsAvailable(); + if (controls.key(BackendInterface::Screen).isEmpty()) { + return false; + } + + return true; +} + +bool DimDisplay::loadAction(const KConfigGroup& config) +{ + kDebug(); + if (config.hasKey("idleTime")) { + m_dimOnIdleTime = config.readEntry("idleTime", 10000000); + kDebug() << "Loading timeouts with " << m_dimOnIdleTime; + registerIdleTimeout(m_dimOnIdleTime * 3 / 4); + registerIdleTimeout(m_dimOnIdleTime / 2); + registerIdleTimeout(m_dimOnIdleTime); + } + + return true; +} + +} +} diff --git a/powerdevil/daemon/actions/bundled/dimdisplay.h b/powerdevil/daemon/actions/bundled/dimdisplay.h new file mode 100644 index 00000000..1564df12 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/dimdisplay.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_DIMDISPLAY_H +#define POWERDEVIL_BUNDLEDACTIONS_DIMDISPLAY_H + +#include + + +namespace PowerDevil { +namespace BundledActions { + +class DimDisplay : public PowerDevil::Action +{ + Q_OBJECT + Q_DISABLE_COPY(DimDisplay) + +public: + explicit DimDisplay(QObject *parent); + virtual ~DimDisplay(); + +protected: + virtual void onProfileUnload(); + virtual void onWakeupFromIdle(); + virtual void onIdleTimeout(int msec); + virtual void onProfileLoad(); + virtual void triggerImpl(const QVariantMap& args); + virtual bool isSupported(); + +public: + virtual bool loadAction(const KConfigGroup& config); + +private: + void setBrightnessHelper(float brightness); + + int m_dimOnIdleTime; + float m_oldBrightness; + bool m_dimmed; +}; + +} + +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_DIMDISPLAY_H diff --git a/powerdevil/daemon/actions/bundled/dimdisplayconfig.cpp b/powerdevil/daemon/actions/bundled/dimdisplayconfig.cpp new file mode 100644 index 00000000..ac26e05c --- /dev/null +++ b/powerdevil/daemon/actions/bundled/dimdisplayconfig.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "dimdisplayconfig.h" + +#include +#include + +#include +#include +#include + +K_PLUGIN_FACTORY(PowerDevilDimDisplayConfigFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(PowerDevilDimDisplayConfigFactory("powerdevildimdisplayaction_config")) + +namespace PowerDevil { +namespace BundledActions { + +DimDisplayConfig::DimDisplayConfig(QObject *parent, const QVariantList& ) + : ActionConfig(parent) +{ + +} + +DimDisplayConfig::~DimDisplayConfig() +{ + +} + +void DimDisplayConfig::save() +{ + configGroup().writeEntry("idleTime", m_spinBox->value() * 60 * 1000); +} + +void DimDisplayConfig::load() +{ + configGroup().config()->reparseConfiguration(); + m_spinBox->setValue((configGroup().readEntry("idleTime", 600000) / 60) / 1000); +} + +QList< QPair< QString, QWidget* > > DimDisplayConfig::buildUi() +{ + QList< QPair< QString, QWidget* > > retlist; + m_spinBox = new KIntSpinBox(0, 180, 1, 0, 0); + m_spinBox->setMaximumWidth(150); + m_spinBox->setMinimum(1); + m_spinBox->setMaximum(360); + m_spinBox->setSuffix(i18n(" min")); + retlist.append(qMakePair< QString, QWidget* >(i18n("After"), m_spinBox)); + + connect(m_spinBox, SIGNAL(valueChanged(int)), this, SLOT(setChanged())); + + return retlist; +} + +} +} + +#include "dimdisplayconfig.moc" diff --git a/powerdevil/daemon/actions/bundled/dimdisplayconfig.h b/powerdevil/daemon/actions/bundled/dimdisplayconfig.h new file mode 100644 index 00000000..14b78793 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/dimdisplayconfig.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_DIMDISPLAYCONFIG_H +#define POWERDEVIL_BUNDLEDACTIONS_DIMDISPLAYCONFIG_H + +#include + +class KIntSpinBox; + +namespace PowerDevil { +namespace BundledActions { + +class DimDisplayConfig : public PowerDevil::ActionConfig +{ + Q_OBJECT + Q_DISABLE_COPY(DimDisplayConfig) +public: + DimDisplayConfig(QObject *, const QVariantList&); + virtual ~DimDisplayConfig(); + + virtual void save(); + virtual void load(); + virtual QList< QPair< QString, QWidget* > > buildUi(); + +private: + KIntSpinBox *m_spinBox; +}; + +} + +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_DIMDISPLAYCONFIG_H diff --git a/powerdevil/daemon/actions/bundled/handlebuttonevents.cpp b/powerdevil/daemon/actions/bundled/handlebuttonevents.cpp new file mode 100644 index 00000000..571e8f69 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/handlebuttonevents.cpp @@ -0,0 +1,207 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "handlebuttonevents.h" +#include "handlebuttoneventsadaptor.h" + +#include "suspendsession.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "PowerDevilSettings.h" +#include "screensaver_interface.h" + +namespace PowerDevil { +namespace BundledActions { + +HandleButtonEvents::HandleButtonEvents(QObject* parent) + : Action(parent) + , m_lidAction(0) + , m_powerButtonAction(0) + , m_sleepButtonAction(1) + , m_hibernateButtonAction(2) +{ + new HandleButtonEventsAdaptor(this); + // We enforce no policies here - after all, we just call other actions - which have their policies. + setRequiredPolicies(PowerDevil::PolicyAgent::None); + connect(backend(), SIGNAL(buttonPressed(PowerDevil::BackendInterface::ButtonType)), + this, SLOT(onButtonPressed(PowerDevil::BackendInterface::ButtonType))); + + KActionCollection* actionCollection = new KActionCollection( this ); + + KAction *globalAction = actionCollection->addAction("Sleep"); + globalAction->setText(i18nc("@action:inmenu Global shortcut", "Sleep")); + globalAction->setGlobalShortcut(KShortcut(Qt::Key_Sleep)); + connect(globalAction, SIGNAL(triggered(bool)), SLOT(suspendToRam())); + + globalAction = actionCollection->addAction("Hibernate"); + globalAction->setText(i18nc("@action:inmenu Global shortcut", "Hibernate")); + globalAction->setGlobalShortcut(KShortcut(Qt::Key_Hibernate)); + connect(globalAction, SIGNAL(triggered(bool)), SLOT(suspendToDisk())); + + globalAction = actionCollection->addAction("PowerOff"); + //globalAction->setText(i18nc("Global shortcut", "Power Off button")); + globalAction->setGlobalShortcut(KShortcut(Qt::Key_PowerOff)); + connect(globalAction, SIGNAL(triggered(bool)), SLOT(powerOffButtonTriggered())); +} + +HandleButtonEvents::~HandleButtonEvents() +{ + +} + +bool HandleButtonEvents::isSupported() +{ + // get a list of all devices that are Buttons + foreach (Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::Button, QString())) { + Solid::Button *button = device.as(); + if (button->type() == Solid::Button::LidButton || button->type() == Solid::Button::PowerButton) { + return true; + } + } + + return false; +} + +void HandleButtonEvents::onProfileUnload() +{ + m_lidAction = 0; + m_powerButtonAction = 0; +} + +void HandleButtonEvents::onWakeupFromIdle() +{ + // +} + +void HandleButtonEvents::onIdleTimeout(int msec) +{ + Q_UNUSED(msec) +} + +void HandleButtonEvents::onProfileLoad() +{ + // +} + +void HandleButtonEvents::onButtonPressed(BackendInterface::ButtonType type) +{ + switch (type) { + case BackendInterface::LidClose: + // Check if the configuration makes it explicit or not + processAction(m_lidAction, PowerDevilSettings::doNotInhibitOnLidClose()); + break; + case BackendInterface::LidOpen: + // In this case, let's send a wakeup event + KIdleTime::instance()->simulateUserActivity(); + break; + case BackendInterface::PowerButton: + // This one is always explicit + processAction(m_powerButtonAction, true); + break; + case BackendInterface::SleepButton: + // This one is always explicit + processAction(m_sleepButtonAction, true); + break; + case BackendInterface::HibernateButton: + // This one is always explicit + processAction(m_hibernateButtonAction, true); + break; + default: + break; + } +} + +void HandleButtonEvents::processAction(uint action, bool isExplicit) +{ + // Basically, we simply trigger other actions :) + switch ((SuspendSession::Mode)action) { + case SuspendSession::TurnOffScreenMode: + // Turn off screen + triggerAction("DPMSControl", qVariantFromValue< QString >("TurnOff"), isExplicit); + break; + default: + triggerAction("SuspendSession", qVariantFromValue< uint >(action), isExplicit); + break; + } +} + +void HandleButtonEvents::triggerAction(const QString& action, const QVariant &type, bool isExplicit) +{ + PowerDevil::Action *helperAction = ActionPool::instance()->loadAction(action, KConfigGroup(), core()); + if (helperAction) { + QVariantMap args; + args["Type"] = type; + args["Explicit"] = QVariant::fromValue(isExplicit); + helperAction->trigger(args); + } +} + +void HandleButtonEvents::triggerImpl(const QVariantMap& args) +{ + // For now, let's just accept the phantomatic "32" button. It is also always explicit + if (args["Button"].toInt() == 32) { + if (args.contains("Type")) { + triggerAction("SuspendSession", args["Type"], true); + } + } +} + +bool HandleButtonEvents::loadAction(const KConfigGroup& config) +{ + // Read configs + m_lidAction = config.readEntry("lidAction", 0); + m_powerButtonAction = config.readEntry("powerButtonAction", 0); + + return true; +} + +int HandleButtonEvents::lidAction() const +{ + return m_lidAction; +} + +void HandleButtonEvents::powerOffButtonTriggered() +{ + onButtonPressed(BackendInterface::PowerButton); +} + +void HandleButtonEvents::suspendToDisk() +{ + onButtonPressed(BackendInterface::HibernateButton); +} + +void HandleButtonEvents::suspendToRam() +{ + onButtonPressed(BackendInterface::SleepButton); +} + +} +} + +#include "handlebuttonevents.moc" diff --git a/powerdevil/daemon/actions/bundled/handlebuttonevents.h b/powerdevil/daemon/actions/bundled/handlebuttonevents.h new file mode 100644 index 00000000..8ea23f6e --- /dev/null +++ b/powerdevil/daemon/actions/bundled/handlebuttonevents.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_HANDLEBUTTONEVENTS_H +#define POWERDEVIL_BUNDLEDACTIONS_HANDLEBUTTONEVENTS_H + +#include +#include + +namespace PowerDevil { +namespace BundledActions { + +class HandleButtonEvents : public PowerDevil::Action +{ + Q_OBJECT + Q_DISABLE_COPY(HandleButtonEvents) + Q_CLASSINFO("D-Bus Interface", "org.kde.Solid.PowerManagement.Actions.HandleButtonEvents") + +public: + explicit HandleButtonEvents(QObject* parent); + virtual ~HandleButtonEvents(); + + virtual bool loadAction(const KConfigGroup& config); + virtual bool isSupported(); + +protected: + virtual void triggerImpl(const QVariantMap& args); + virtual void onProfileUnload(); + virtual void onWakeupFromIdle(); + virtual void onIdleTimeout(int msec); + virtual void onProfileLoad(); + +public Q_SLOTS: + int lidAction() const; + +private Q_SLOTS: + void onButtonPressed(PowerDevil::BackendInterface::ButtonType type); + void powerOffButtonTriggered(); + void suspendToRam(); + void suspendToDisk(); + +private: + void processAction(uint action, bool isExplicit); + void triggerAction(const QString &action, const QVariant &type, bool isExplicit); + + uint m_lidAction; + uint m_powerButtonAction; + uint m_sleepButtonAction; + uint m_hibernateButtonAction; +}; + +} + +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_HANDLEBUTTONEVENTS_H diff --git a/powerdevil/daemon/actions/bundled/handlebuttoneventsconfig.cpp b/powerdevil/daemon/actions/bundled/handlebuttoneventsconfig.cpp new file mode 100644 index 00000000..0ab276af --- /dev/null +++ b/powerdevil/daemon/actions/bundled/handlebuttoneventsconfig.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "handlebuttoneventsconfig.h" + +#include "suspendsession.h" + +#include +#include +#include + +#include +#include +#include +#include + +K_PLUGIN_FACTORY(PowerDevilSuspendSessionConfigFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(PowerDevilSuspendSessionConfigFactory("powerdevilhandlebuttoneventsaction_config")) + +namespace PowerDevil { +namespace BundledActions { + +HandleButtonEventsConfig::HandleButtonEventsConfig(QObject* parent, const QVariantList& ) + : ActionConfig(parent) +{ + +} + +HandleButtonEventsConfig::~HandleButtonEventsConfig() +{ + +} + + +void HandleButtonEventsConfig::save() +{ + if (m_lidCloseCombo) { + configGroup().writeEntry< uint >("lidAction", m_lidCloseCombo->itemData(m_lidCloseCombo->currentIndex()).toUInt()); + } + if (m_powerButtonCombo) { + configGroup().writeEntry< uint >("powerButtonAction", m_powerButtonCombo->itemData(m_powerButtonCombo->currentIndex()).toUInt()); + } + + configGroup().sync(); +} + +void HandleButtonEventsConfig::load() +{ + configGroup().config()->reparseConfiguration(); + + if (m_lidCloseCombo) { + m_lidCloseCombo->setCurrentIndex(m_lidCloseCombo->findData(QVariant::fromValue(configGroup().readEntry< uint >("lidAction", 0)))); + } + if (m_powerButtonCombo) { + m_powerButtonCombo->setCurrentIndex(m_powerButtonCombo->findData(QVariant::fromValue(configGroup().readEntry< uint >("powerButtonAction", 0)))); + } +} + +QList< QPair< QString, QWidget* > > HandleButtonEventsConfig::buildUi() +{ + // Create the boxes + m_lidCloseCombo = new KComboBox; + m_powerButtonCombo = new KComboBox; + + // Fill the boxes with options! + { + QList< KComboBox* > boxes; + boxes << m_lidCloseCombo << m_powerButtonCombo; + + QSet< Solid::PowerManagement::SleepState > methods = Solid::PowerManagement::supportedSleepStates(); + + foreach (KComboBox *box, boxes) { + box->addItem(KIcon("dialog-cancel"), i18n("Do nothing"), (uint)SuspendSession::None); + if (methods.contains(Solid::PowerManagement::SuspendState)) { + box->addItem(KIcon("system-suspend"), i18n("Sleep"), (uint)SuspendSession::ToRamMode); + } + if (methods.contains(Solid::PowerManagement::HibernateState)) { + box->addItem(KIcon("system-suspend-hibernate"), i18n("Hibernate"), (uint)SuspendSession::ToDiskMode); + } + box->addItem(KIcon("system-shutdown"), i18n("Shutdown"), (uint)SuspendSession::ShutdownMode); + box->addItem(KIcon("system-lock-screen"), i18n("Lock screen"), (uint)SuspendSession::LockScreenMode); + if (box != m_lidCloseCombo) { + box->addItem(KIcon("system-log-out"), i18n("Prompt log out dialog"), (uint)SuspendSession::LogoutDialogMode); + } + box->addItem(KIcon("preferences-desktop-screensaver"), i18n("Turn off screen"), (uint)SuspendSession::TurnOffScreenMode); + } + } + + connect(m_lidCloseCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setChanged())); + connect(m_powerButtonCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setChanged())); + + m_lidCloseCombo->setMaximumWidth(300); + m_powerButtonCombo->setMaximumWidth(300); + + bool lidFound = false; + bool powerFound = false; + // get a list of all devices that are Buttons + foreach (Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::Button, QString())) { + Solid::Button *button = device.as(); + if (button->type() == Solid::Button::LidButton) { + lidFound = true; + } else if (button->type() == Solid::Button::PowerButton) { + powerFound = true; + } + } + + QList< QPair< QString, QWidget* > > retlist; + + if (lidFound) { + retlist.append(qMakePair< QString, QWidget* >(i18n("When laptop lid closed"), m_lidCloseCombo)); + } else { + m_lidCloseCombo->deleteLater(); + m_lidCloseCombo = 0; + } + + if (powerFound) { + retlist.append(qMakePair< QString, QWidget* >(i18n("When power button pressed"), m_powerButtonCombo)); + } else { + m_powerButtonCombo->deleteLater(); + m_powerButtonCombo = 0; + } + + return retlist; +} + +} +} + +#include "handlebuttoneventsconfig.moc" diff --git a/powerdevil/daemon/actions/bundled/handlebuttoneventsconfig.h b/powerdevil/daemon/actions/bundled/handlebuttoneventsconfig.h new file mode 100644 index 00000000..a55bca7d --- /dev/null +++ b/powerdevil/daemon/actions/bundled/handlebuttoneventsconfig.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_HANDLEBUTTONEVENTSCONFIG_H +#define POWERDEVIL_BUNDLEDACTIONS_HANDLEBUTTONEVENTSCONFIG_H + +#include + +class KComboBox; +namespace PowerDevil { +namespace BundledActions { + +class HandleButtonEventsConfig : public PowerDevil::ActionConfig +{ + Q_OBJECT + Q_DISABLE_COPY(HandleButtonEventsConfig) + +public: + HandleButtonEventsConfig(QObject* parent, const QVariantList&); + virtual ~HandleButtonEventsConfig(); + + virtual void save(); + virtual void load(); + virtual QList< QPair< QString, QWidget* > > buildUi(); + +private: + KComboBox *m_lidCloseCombo; + KComboBox *m_powerButtonCombo; +}; + +} + +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_HANDLEBUTTONEVENTSCONFIG_H diff --git a/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrol.cpp b/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrol.cpp new file mode 100644 index 00000000..d712b4c2 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrol.cpp @@ -0,0 +1,199 @@ +/*************************************************************************** + * Copyright (C) 2012 by Michael Zanetti * + * * + * 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 "keyboardbrightnesscontrol.h" + +#include "brightnessosdwidget.h" +#include "keyboardbrightnesscontroladaptor.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace PowerDevil { +namespace BundledActions { + +KeyboardBrightnessControl::KeyboardBrightnessControl(QObject* parent) + : Action(parent) +{ + // DBus + new KeyboardBrightnessControlAdaptor(this); + + setRequiredPolicies(PowerDevil::PolicyAgent::ChangeScreenSettings); + + connect(core()->backend(), SIGNAL(brightnessChanged(float,PowerDevil::BackendInterface::BrightnessControlType)), + this, SLOT(onBrightnessChangedFromBackend(float,PowerDevil::BackendInterface::BrightnessControlType))); + + KActionCollection* actionCollection = new KActionCollection( this ); + + KAction *globalAction = actionCollection->addAction("Increase Keyboard Brightness"); + globalAction->setText(i18nc("@action:inmenu Global shortcut", "Increase Keyboard Brightness")); + globalAction->setGlobalShortcut(KShortcut(Qt::Key_KeyboardBrightnessUp)); + connect(globalAction, SIGNAL(triggered(bool)), SLOT(increaseKeyboardBrightness())); + + globalAction = actionCollection->addAction("Decrease Keyboard Brightness"); + globalAction->setText(i18nc("@action:inmenu Global shortcut", "Decrease Keyboard Brightness")); + globalAction->setGlobalShortcut(KShortcut(Qt::Key_KeyboardBrightnessDown)); + connect(globalAction, SIGNAL(triggered(bool)), SLOT(decreaseKeyboardBrightness())); + + globalAction = actionCollection->addAction("Toggle Keyboard Backlight"); + globalAction->setText(i18nc("@action:inmenu Global shortcut", "Toggle Keyboard Backlight")); + globalAction->setGlobalShortcut(KShortcut(Qt::Key_KeyboardLightOnOff)); + connect(globalAction, SIGNAL(triggered(bool)), SLOT(toggleKeyboardBacklight())); +} + +KeyboardBrightnessControl::~KeyboardBrightnessControl() +{ + if (!m_brightnessOSD.isNull()) { + m_brightnessOSD.data()->deleteLater(); + } +} + +void KeyboardBrightnessControl::onProfileUnload() +{ + // +} + +void KeyboardBrightnessControl::onWakeupFromIdle() +{ + // +} + +void KeyboardBrightnessControl::onIdleTimeout(int msec) +{ + Q_UNUSED(msec); +} + +void KeyboardBrightnessControl::onProfileLoad() +{ + // This unparsable conditional block means: if the current profile is more + // conservative than the previous one and the current brightness is lower + // than the new profile + if (((m_currentProfile == "Battery" && m_lastProfile == "AC") || + (m_currentProfile == "LowBattery" && (m_lastProfile == "AC" || m_lastProfile == "Battery"))) && + m_defaultValue > keyboardBrightness()) { + // We don't want to change anything here + kDebug() << "Not changing keyboard brightness, the current one is lower and the profile is more conservative"; + } else if (m_defaultValue > 0) { + QVariantMap args; + args["Value"] = QVariant::fromValue((float)m_defaultValue); + trigger(args); + } +} + +void KeyboardBrightnessControl::triggerImpl(const QVariantMap& args) +{ + backend()->setBrightness(args["Value"].toFloat(), BackendInterface::Keyboard); + if (args["Explicit"].toBool()) { + showBrightnessOSD(backend()->brightness(BackendInterface::Keyboard)); + } +} + +bool KeyboardBrightnessControl::isSupported() +{ + BackendInterface::BrightnessControlsList controls = backend()->brightnessControlsAvailable(); + if (controls.key(BackendInterface::Keyboard).isEmpty()) { + return false; + } + + return true; +} + +bool KeyboardBrightnessControl::loadAction(const KConfigGroup& config) +{ + // Handle profile changes + m_lastProfile = m_currentProfile; + m_currentProfile = config.parent().name(); + + kDebug() << "Profiles: " << m_currentProfile << m_lastProfile; + + if (config.hasKey("value")) { + m_defaultValue = config.readEntry("value", 50); + } else { + m_defaultValue = -1; + } + + return true; +} + +void KeyboardBrightnessControl::showBrightnessOSD(int brightness) +{ + // code adapted from KMix + if (m_brightnessOSD.isNull()) { + m_brightnessOSD = new BrightnessOSDWidget(BackendInterface::Keyboard); + } + + m_brightnessOSD.data()->setCurrentBrightness(brightness); + m_brightnessOSD.data()->show(); + m_brightnessOSD.data()->activateOSD(); //Enable the hide timer + + //Center the OSD + QRect rect = KApplication::kApplication()->desktop()->screenGeometry(QCursor::pos()); + QSize size = m_brightnessOSD.data()->sizeHint(); + int posX = rect.x() + (rect.width() - size.width()) / 2; + int posY = rect.y() + 4 * rect.height() / 5; + m_brightnessOSD.data()->setGeometry(posX, posY, size.width(), size.height()); +} + +void KeyboardBrightnessControl::onBrightnessChangedFromBackend(float brightness, PowerDevil::BackendInterface::BrightnessControlType type) +{ + if (type == BackendInterface::Keyboard) { + showBrightnessOSD(brightness); + Q_EMIT keyboardBrightnessChanged(brightness); + } +} + +void KeyboardBrightnessControl::increaseKeyboardBrightness() +{ + backend()->brightnessKeyPressed(BackendInterface::Increase, BackendInterface::Keyboard); +} + +void KeyboardBrightnessControl::decreaseKeyboardBrightness() +{ + backend()->brightnessKeyPressed(BackendInterface::Decrease, BackendInterface::Keyboard); +} + +void KeyboardBrightnessControl::toggleKeyboardBacklight() +{ + backend()->brightnessKeyPressed(BackendInterface::Toggle, BackendInterface::Keyboard); +} + +int KeyboardBrightnessControl::keyboardBrightness() const +{ + return backend()->brightness(BackendInterface::Keyboard); +} + +void KeyboardBrightnessControl::setKeyboardBrightness(int percent) +{ + QVariantMap args; + args["Value"] = QVariant::fromValue((float)percent); + args["Explicit"] = true; + trigger(args); +} + +} +} diff --git a/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrol.h b/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrol.h new file mode 100644 index 00000000..59affda3 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrol.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2012 by Michael Zanetti * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_KEYBOARDBRIGHTNESSCONTROL_H +#define POWERDEVIL_BUNDLEDACTIONS_KEYBOARDBRIGHTNESSCONTROL_H + +#include +#include + +class BrightnessOSDWidget; + +namespace PowerDevil { +namespace BundledActions { + +class KeyboardBrightnessControl : public PowerDevil::Action +{ + Q_OBJECT + Q_DISABLE_COPY(KeyboardBrightnessControl) + Q_CLASSINFO("D-Bus Interface", "org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl") + +public: + explicit KeyboardBrightnessControl(QObject* parent); + virtual ~KeyboardBrightnessControl(); + +protected: + virtual void onProfileUnload(); + virtual void onWakeupFromIdle(); + virtual void onIdleTimeout(int msec); + virtual void onProfileLoad(); + virtual void triggerImpl(const QVariantMap& args); + virtual bool isSupported(); + +public: + virtual bool loadAction(const KConfigGroup& config); + +public Q_SLOTS: + void showBrightnessOSD(int brightness); + void onBrightnessChangedFromBackend(float brightness, PowerDevil::BackendInterface::BrightnessControlType type); + + // DBus export + void increaseKeyboardBrightness(); + void decreaseKeyboardBrightness(); + void toggleKeyboardBacklight(); + + int keyboardBrightness() const; + void setKeyboardBrightness(int percent); + +Q_SIGNALS: + void keyboardBrightnessChanged(int percent); + +private: + int m_defaultValue; + QWeakPointer< BrightnessOSDWidget > m_brightnessOSD; + QString m_lastProfile; + QString m_currentProfile; +}; + +} + +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_KEYBOARDBRIGHTNESSCONTROL_H diff --git a/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrolconfig.cpp b/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrolconfig.cpp new file mode 100644 index 00000000..9887b3ba --- /dev/null +++ b/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrolconfig.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "keyboardbrightnesscontrolconfig.h" + +#include +#include +#include + +#include +#include + +K_PLUGIN_FACTORY(PowerDevilKeyboardBrightnessControlConfigFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(PowerDevilKeyboardBrightnessControlConfigFactory("powerdevilkeyboardbrightnesscontrolaction_config")) + +namespace PowerDevil { +namespace BundledActions { + +KeyboardBrightnessControlConfig::KeyboardBrightnessControlConfig(QObject *parent, const QVariantList& ) + : ActionConfig(parent) +{ + +} + +KeyboardBrightnessControlConfig::~KeyboardBrightnessControlConfig() +{ + +} + +void KeyboardBrightnessControlConfig::save() +{ + configGroup().writeEntry("value", m_slider->value()); + configGroup().sync(); +} + +void KeyboardBrightnessControlConfig::load() +{ + configGroup().config()->reparseConfiguration(); + m_slider->setValue(configGroup().readEntry("value", 50)); +} + +QList< QPair< QString, QWidget* > > KeyboardBrightnessControlConfig::buildUi() +{ + QList< QPair< QString, QWidget* > > retlist; + m_slider = new QSlider(Qt::Horizontal); + m_slider->setMaximumWidth(300); + m_slider->setRange(0, 100); + retlist.append(qMakePair< QString, QWidget* >(i18nc("@label:slider Brightness level", "Level"), m_slider)); + + connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(setChanged())); + + return retlist; +} + + +} +} + +#include "keyboardbrightnesscontrolconfig.moc" diff --git a/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrolconfig.h b/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrolconfig.h new file mode 100644 index 00000000..08126d1b --- /dev/null +++ b/powerdevil/daemon/actions/bundled/keyboardbrightnesscontrolconfig.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_KEYBOARDBRIGHTNESSCONTROLCONFIG_H +#define POWERDEVIL_BUNDLEDACTIONS_KEYBOARDBRIGHTNESSCONTROLCONFIG_H + +#include + +#include + +class QSlider; + +namespace PowerDevil { +namespace BundledActions { + +class KDE_EXPORT KeyboardBrightnessControlConfig : public PowerDevil::ActionConfig +{ + Q_OBJECT + Q_DISABLE_COPY(KeyboardBrightnessControlConfig) +public: + KeyboardBrightnessControlConfig(QObject*, const QVariantList&); + virtual ~KeyboardBrightnessControlConfig(); + + virtual void save(); + virtual void load(); + virtual QList< QPair< QString, QWidget* > > buildUi(); + +private: + QSlider *m_slider; +}; + +} +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_KEYBOARDBRIGHTNESSCONTROLCONFIG_H diff --git a/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.BrightnessControl.xml b/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.BrightnessControl.xml new file mode 100644 index 00000000..9c4d3df5 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.BrightnessControl.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.HandleButtonEvents.xml b/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.HandleButtonEvents.xml new file mode 100644 index 00000000..68b21653 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.HandleButtonEvents.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl.xml b/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl.xml new file mode 100644 index 00000000..08b54077 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.KeyboardBrightnessControl.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.SuspendSession.xml b/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.SuspendSession.xml new file mode 100644 index 00000000..7e4cab44 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.SuspendSession.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/powerdevil/daemon/actions/bundled/powerdevilbrightnesscontrolaction.desktop b/powerdevil/daemon/actions/bundled/powerdevilbrightnesscontrolaction.desktop new file mode 100644 index 00000000..45d059a2 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/powerdevilbrightnesscontrolaction.desktop @@ -0,0 +1,106 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevil/Action +X-KDE-Library=powerdevilbrightnesscontrolaction_config +Icon=preferences-system-power-management +Name=Screen Brightness +Name[bs]=Osvetljaj ekrana +Name[ca]=Lluminositat de la pantalla +Name[ca@valencia]=Lluminositat de la pantalla +Name[cs]=Jas obrazovky +Name[da]=Skærmens lysstyrke +Name[de]=Bildschirmhelligkeit +Name[el]=Φωτεινότητα οθόνης +Name[en_GB]=Screen Brightness +Name[es]=Brillo de la pantalla +Name[et]=Ekraani heledus +Name[eu]=Pantailaren distira +Name[fi]=Näytön kirkkaus +Name[fr]=Luminosité de l'écran +Name[gl]=Brillo da pantalla +Name[hu]=Képernyő fényessége +Name[ia]=Brillantia de Schermo +Name[kk]=Экран жарықтығы +Name[ko]=화면 밝기 +Name[lt]=Ekrano šviesumas +Name[nb]=Skjermlysstyrke +Name[nds]=Schirm-Helligkeit +Name[nl]=Schermhelderheid +Name[pa]=ਸਕਰੀਨ ਚਮਕ +Name[pl]=Jasność ekranu +Name[pt]=Brilho do Ecrã +Name[pt_BR]=Brilho da tela +Name[ro]=Luminozitate ecran +Name[ru]=Яркость экрана +Name[sk]=Jas obrazovky +Name[sl]=Svetlost zaslona +Name[sr]=Осветљај екрана +Name[sr@ijekavian]=Освјетљај екрана +Name[sr@ijekavianlatin]=Osvjetljaj ekrana +Name[sr@latin]=Osvetljaj ekrana +Name[sv]=Skärmljusstyrka +Name[tr]=Ekran Parlaklığı +Name[uk]=Яскравість екрана +Name[x-test]=xxScreen Brightnessxx +Name[zh_CN]=屏幕亮度 +Name[zh_TW]=螢幕亮度 +Comment=Basic Controls for brightness +Comment[ast]=Control básicu del brillu +Comment[bg]=Основни настройки на яркостта +Comment[bs]=Osnovne kontrole osvetljaja +Comment[ca]=Controls bàsics per la lluminositat +Comment[ca@valencia]=Controls bàsics per la lluminositat +Comment[cs]=Základní ovládání jasu +Comment[da]=Basal kontrol af lysstyrke +Comment[de]=Grundeinstellungen zur Bildschirmhelligkeit +Comment[el]=Βασικά στοιχεία ελέγχου λαμπρότητας +Comment[en_GB]=Basic Controls for brightness +Comment[es]=Control básico del brillo +Comment[et]=Heleduse lihtne juhtimine +Comment[eu]=Distiraren oinarrizko kontrolak +Comment[fi]=Kirkkauden perussäätimet +Comment[fr]=Contrôles simples de la luminosité +Comment[gl]=Controis básicos do brillo +Comment[he]=בקרים בסיסיים לשליטה בבהירות +Comment[hr]=Osnovne kontrole za osvjetljenje +Comment[hu]=Alap fényerő-beállítások +Comment[ia]=Controlos basic pro brillantia +Comment[is]=Grunnstýringar fyrir birtustig +Comment[kk]=Жарықтығының негізгі тұтқалары +Comment[km]=ការ​ត្រួតពិនិត្យ​ពន្លឺ​ជា​មូលដ្ឋាន +Comment[ko]=기본 밝기 제어 +Comment[lt]=Pagrindiniai šviesumo valdikliai +Comment[lv]=Pamata gaišuma vadīklas +Comment[mr]=प्रखरतेसाठी मूलभूत नियंत्रण +Comment[nb]=Grunnleggende lysstyrkestyring +Comment[nds]=Eenfach Helligkeit-Instellen +Comment[nl]=Basisbesturing voor helderheid +Comment[pa]=ਚਮਕ ਲਈ ਮੁੱਢਲੇ ਕੰਟਰੋਲ +Comment[pl]=Podstawowe sterowanie jasnością +Comment[pt]=Controlos básicos do brilho +Comment[pt_BR]=Controles básicos do brilho +Comment[ro]=Controale de bază pentru luminozitate +Comment[ru]=Базовые функции управления яркостью +Comment[sk]=Základné ovládanie jasu +Comment[sl]=Osnovni nadzor svetlosti +Comment[sr]=Основне контроле осветљаја +Comment[sr@ijekavian]=Основне контроле освјетљаја +Comment[sr@ijekavianlatin]=Osnovne kontrole osvjetljaja +Comment[sr@latin]=Osnovne kontrole osvetljaja +Comment[sv]=Grundkontroller för ljusstyrka +Comment[th]=การควบคุมพื้นฐานสำหรับความสว่าง +Comment[tr]=Parlaklık için temel kontroller +Comment[ug]=يورۇقلۇقنىڭ ئاساسىي تىزگىنى +Comment[uk]=Базове керування яскравістю +Comment[vi]=Điều khiển độ sáng cơ bản +Comment[wa]=Controles di båze pol rilujhance +Comment[x-test]=xxBasic Controls for brightnessxx +Comment[zh_CN]=亮度基本控制 +Comment[zh_TW]=基本亮度控制 + +X-KDE-PowerDevil-Action-ID=BrightnessControl +X-KDE-PowerDevil-Action-IsBundled=true +X-KDE-PowerDevil-Action-UIComponentLibrary=powerdevilbrightnesscontrolaction_config +X-KDE-PowerDevil-Action-ConfigPriority=100 +X-KDE-PowerDevil-Action-HasRuntimeRequirement=true +X-KDE-PowerDevil-Action-RegistersDBusInterface=true diff --git a/powerdevil/daemon/actions/bundled/powerdevildimdisplayaction.desktop b/powerdevil/daemon/actions/bundled/powerdevildimdisplayaction.desktop new file mode 100644 index 00000000..1aad371a --- /dev/null +++ b/powerdevil/daemon/actions/bundled/powerdevildimdisplayaction.desktop @@ -0,0 +1,106 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevil/Action +# X-KDE-Library=powerdevildimdisplayaction +Icon=preferences-desktop-display +Name=Dim Screen +Name[bs]=Dim ekran +Name[ca]=Enfosquiment de pantalla +Name[ca@valencia]=Enfosquiment de pantalla +Name[cs]=Ztmavit obrazovku +Name[da]=Dæmp skærmen +Name[de]=Bildschirm abdunkeln +Name[el]=Σκίαση οθόνης +Name[en_GB]=Dim Screen +Name[es]=Oscurecer pantalla +Name[et]=Ekraani tumendamine +Name[eu]=Ilundu leihoa +Name[fi]=Näytön himmennys +Name[fr]=Régler la luminosité de l'écran +Name[gl]=Atenuar a pantalla +Name[hu]=Képernyő homályosítása +Name[ia]=Obscura Schermo +Name[kk]=Экранды қараңғы қылу +Name[ko]=화면 어둡게 하기 +Name[lt]=Užtemdyti ekraną +Name[nb]=Mørklegg skjerm +Name[nds]=Schirmafdüüstern +Name[nl]=Scherm dimmen +Name[pa]=ਸਕਰੀਨ ਡਿਮ +Name[pl]=Przyciemnij ekran +Name[pt]=Escurecer o Ecrã +Name[pt_BR]=Escurecer a tela +Name[ro]=Întunecă ecranul +Name[ru]=Потухание экрана +Name[sk]=Stmaviť obrazovku +Name[sl]=Potemni zaslon +Name[sr]=Пригуши екран +Name[sr@ijekavian]=Пригуши екран +Name[sr@ijekavianlatin]=Priguši ekran +Name[sr@latin]=Priguši ekran +Name[sv]=Dämpa skärmen +Name[tr]=Ekranı kapat +Name[uk]=Зменшення яскравості екрана +Name[x-test]=xxDim Screenxx +Name[zh_CN]=暗淡屏幕 +Name[zh_TW]=將螢幕變暗 +Comment=Dims gradually the display on a time basis +Comment[ast]=Atenúa la pantalla gradualmente según pasa'l tiempu +Comment[bg]=Постепенно затъмняване на екрана след определено време +Comment[bs]=Postepeno prigušuje ekran na zadato vrijeme +Comment[ca]=Atenua gradualment la pantalla en funció del temps +Comment[ca@valencia]=Atenua gradualment la pantalla en funció del temps +Comment[cs]=Postupné ztmavení obrazovky +Comment[da]=Dæmper skærmen gradvist baseret på tid +Comment[de]=Dunkelt den Bildschirm zeitgesteuert ab +Comment[el]=Μειώνει σταδιακά στο χρόνο την φωτεινότητα της οθόνης +Comment[en_GB]=Dims gradually the display on a time basis +Comment[es]=Oscurece la pantalla gradualmente según pasa el tiempo +Comment[et]=Kuva järkjärguline tumendamine aega arvestades +Comment[eu]=Bistaratzea pixkanaka iluntzen du +Comment[fi]=Himmentää näyttöä vaiheittain ajan perusteella +Comment[fr]=Assombrit graduellement l'affichage sur une base de temps +Comment[gl]=Escurece progresivamente a pantalla segundo o tempo +Comment[he]=משמש לעמעום הדרגתי של הצג על בסיס זמן +Comment[hr]=Postepeno prigušuje zaslon na vremenskoj osnovi +Comment[hu]=Fokozatos elhalványítja a kijelzőt egy adott idő után +Comment[ia]=Obscura gradualmente le monstrator usante como base le tempore +Comment[is]=Dimmir skjáborðið smátt og smátt +Comment[ja]=ディスプレイを時間とともに徐々に暗くする +Comment[kk]=Дисплей жарықтығын біртіндеп азайту +Comment[km]=ធ្វើ​ឲ្យ​​ការ​បង្ហាញ​ព្រិល​ៗ​ទៅ​តាម​​ពេលវេលា​ +Comment[kn]=ಸಮಯಕ್ಕೆ ಅನುಗುಣವಾಗಿ ಪ್ರದರ್ಶಕವನ್ನು ನಿಧಾನವಾಗಿ ಮಬ್ಬುಗೊಳಿಸುತ್ತದೆ +Comment[ko]=밝기를 단계적으로 어둡게 합니다 +Comment[lt]=Laikui bėgant, dalinai pritamsina ekraną +Comment[lv]=Pakāpeniski patumšina ekrānu atkarībā no laika +Comment[mr]=वेळे नुसार क्रमाक्रमाने डिस्प्ले फीका करतो +Comment[nb]=Mørklegger skjermen gradvis etter som tiden går +Comment[nds]=Maakt de Schirm na en vörinstellt Tiet düüsterer +Comment[nl]=Dimt geleidelijk het beeldscherm op basis van tijd +Comment[pa]=ਸਮੇਂ ਨਾਲ ਡਿਸਪਲੇਅ ਨੂੰ ਲਗਾਤਾਰ ਡਿਮ ਕਰੋ +Comment[pl]=Po podanym czasie, stopniowo przyciemnia wyświetlacz +Comment[pt]=Escurece gradualmente o ecrã durante um dado período +Comment[pt_BR]=Escurece gradualmente a tela durante um período +Comment[ro]=Întunecă gradual ecranul în dependență de timp +Comment[ru]=Экран медленно затухает со временем +Comment[sk]=Postupne stmavie obrazovku v závislosti na čase +Comment[sl]=Postopoma potemni zaslon +Comment[sr]=Постепено пригушује екран на задато време +Comment[sr@ijekavian]=Постепено пригушује екран на задато вријеме +Comment[sr@ijekavianlatin]=Postepeno prigušuje ekran na zadato vrijeme +Comment[sr@latin]=Postepeno prigušuje ekran na zadato vreme +Comment[sv]=Dämpa bildskärmen gradvis baserat på tid +Comment[th]=ลดความสว่างจอภาพลงเมื่อถึงช่วงเวลาตามที่กำหนด +Comment[tr]=Zamana bağlı olarak ekranı karart +Comment[uk]=Поступове зменшення яскравості дисплея з часом +Comment[vi]=Làm tối dần màn hình theo thời gian +Comment[wa]=Baxhe pitchote a midjote li håynaedje so ene båze di tins +Comment[x-test]=xxDims gradually the display on a time basisxx +Comment[zh_CN]=在一定时间逐步变暗屏幕 +Comment[zh_TW]=依時間逐漸讓顯示變暗 + +X-KDE-PowerDevil-Action-ID=DimDisplay +X-KDE-PowerDevil-Action-IsBundled=true +X-KDE-PowerDevil-Action-UIComponentLibrary=powerdevildimdisplayaction_config +X-KDE-PowerDevil-Action-ConfigPriority=99 +X-KDE-PowerDevil-Action-HasRuntimeRequirement=true diff --git a/powerdevil/daemon/actions/bundled/powerdevilhandlebuttoneventsaction.desktop b/powerdevil/daemon/actions/bundled/powerdevilhandlebuttoneventsaction.desktop new file mode 100644 index 00000000..081d5861 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/powerdevilhandlebuttoneventsaction.desktop @@ -0,0 +1,119 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevil/Action +# X-KDE-Library=powerdevilhandlebuttoneventsaction +Icon=system-suspend + +Name=Button events handling +Name[ast]=Remanar eventos botón +Name[bg]=Събития при натискане бутони +Name[bs]=Rukovanje događajima dugmadi +Name[ca]=Gestió d'esdeveniments de botons +Name[ca@valencia]=Gestió d'esdeveniments de botons +Name[cs]=Řízení událostí tlačítek +Name[da]=Håndtering af knaphændelser +Name[de]=Knopf-Ereignisbehandlung +Name[el]=Διαχείριση συμβάντων +Name[en_GB]=Button events handling +Name[es]=Gestión de eventos de botón +Name[et]=Nupusündmuste kohtlemine +Name[eu]=Botoi-gertaeren kudeaketa +Name[fi]=Näppäintapahtumien käsittely +Name[fr]=Prise en charge des évènements de boutons +Name[gl]=Xestión dos acontecementos nos botóns +Name[he]=טיפול באירועי לחצנים +Name[hr]=Rukovanje događajima gumbiju +Name[hu]=Gombesemények kezelése +Name[ia]=Button maneante de eventos +Name[is]=Meðhöndlun hnappaatburða +Name[kk]=Батырма басуға көңіл болу +Name[km]=ការ​គ្រប់គ្រង​ប៊ូតុង​​ព្រឹត្តិការណ៍​​ +Name[ko]=단추 이벤트 처리 +Name[lt]=Mygtukų įvykių valdymas +Name[lv]=Taustiņu darbību apstrāde +Name[mr]=बटन घटना हाताळणी +Name[nb]=Håndtering av knappehendelser +Name[nds]=Knoop för't Ümgahn mit Begeefnissen +Name[nl]=Knop voor afhandelen van evenementen +Name[pa]=ਬਟਨ ਈਵੈਂਟ ਹੈਡਲਿੰਗ +Name[pl]=Obsługuj następujące zdarzenia +Name[pt]=Tratamento dos eventos dos botões +Name[pt_BR]=Tratamento de eventos dos botões +Name[ro]=Manipularea evenimentelor de la butoane +Name[ru]=Обработка событий от кнопок +Name[sk]=Spracovanie udalostí tlačidiel +Name[sl]=Rokovanje z dogodki gumbov +Name[sr]=Руковање догађајима дугмади +Name[sr@ijekavian]=Руковање догађајима дугмади +Name[sr@ijekavianlatin]=Rukovanje događajima dugmadi +Name[sr@latin]=Rukovanje događajima dugmadi +Name[sv]=Händelsehantering för knappar +Name[th]=การจัดการกับเหตุการณ์ของปุ่ม +Name[tr]=Düğme işlevlerini ata +Name[ug]=توپچا ھادىسىنى باشقۇرۇش +Name[uk]=Обробка натискань кнопок +Name[vi]=Xử lý sự kiện nhấn nút +Name[wa]=Apougnaedje des evenmints des botons +Name[x-test]=xxButton events handlingxx +Name[zh_CN]=按键事件处理 +Name[zh_TW]=按鍵事件處理 + +Comment=Performs an action whenever a button is pressed +Comment[ast]=Facer aiciones cuando se calque un botón +Comment[bg]=Изпълнява действие при натискане на бутони +Comment[bs]=Izvršava radnju na svaki pritisak dugmeta +Comment[ca]=Porta a terme una acció quan es prem un botó +Comment[ca@valencia]=Porta a terme una acció quan es prem un botó +Comment[cs]=Vykoná akci kdykoli je tlačítko stisknuto +Comment[da]=Udfører en handling når der trykkes på en knap +Comment[de]=Führt eine Aktion aus, sobald ein Knopf gedrückt wird +Comment[el]=Εκτελεί μία λειτουργία όποτε ένα κουμπί πιέζεται +Comment[en_GB]=Performs an action whenever a button is pressed +Comment[es]=Realiza una acción cuando se presiona un botón +Comment[et]=Toimingu sooritamine, kui vajutatakse nuppu +Comment[eu]=Ekintza bat gauzatzen du botoi bat sakatzen den bakoitzean +Comment[fi]=Suorittaa toiminnon painiketta painettaessa +Comment[fr]=Effectue une action à chaque fois qu'un bouton est pressé +Comment[gl]=Realiza unha acción cando se prema un botón +Comment[he]=משמש לביצוע פעולה בלחיצה על לחצן +Comment[hr]=Izvršava radnju kad god se pritisne gumb +Comment[hu]=Végrehajt egy műveletet, valahányszor egy gomb megnyomásra kerül +Comment[ia]=Il executa un action quando un button es pressate +Comment[is]=Framkvæmir aðgerð í hvert skipti sem ýtt er á hnapp +Comment[kk]=Әрқашанда батырмасы басылғанда әрекетін орындау +Comment[km]=អនុវត្ត​សកម្មភាព​នៅពេល​ដែល​ចុច​ប៊ូតុង +Comment[ko]=단추가 눌렸을 때 동작을 실행합니다 +Comment[lt]=Įvykdo veiksmą kiekvieną kartą paspaudus mygtuką +Comment[lv]=Izpilda darbību, kad tiek nospiests taustiņš +Comment[mr]=कधीही बटन दाबल्यावर एक क्रिया कार्यान्वित करतो +Comment[nb]=Utfører en handling hver gang en knapp trykkes +Comment[nds]=Föhrt en Akschoon ut, wenn en Knoop drückt warrt +Comment[nl]=Voer een actie uit als er een knop wordt ingedrukt +Comment[pa]=ਜਦੋਂ ਬਟਨ ਦੱਬਿਆ ਜਾਵੇ ਤਾਂ ਕਾਰਵਾਈ ਕਰੋ +Comment[pl]=Wykonuje działanie przy każdorazowym naciśnięciu przycisku +Comment[pt]=Efectua uma acção quando carregar num botão +Comment[pt_BR]=Executa uma ação sempre que um botão é pressionado +Comment[ro]=Îndeplinește o acțiune la apăsarea unui buton +Comment[ru]=Выполняет действие при нажатии кнопки +Comment[sk]=Vykoná akcie kedykoľvek je stlačené tlačidlo +Comment[sl]=Ob pritisku na gumb izvede dejanje +Comment[sr]=Извршава радњу на сваки притисак дугмета +Comment[sr@ijekavian]=Извршава радњу на сваки притисак дугмета +Comment[sr@ijekavianlatin]=Izvršava radnju na svaki pritisak dugmeta +Comment[sr@latin]=Izvršava radnju na svaki pritisak dugmeta +Comment[sv]=Utför en åtgärd så fort en knapp trycks ner +Comment[th]=ดำเนินการการกระทำเมื่อกดปุ่ม +Comment[tr]=Bir düğmeye basıldığında bir eylem gerçekleştirir +Comment[ug]=بىر توپچا بېسىلغاندا بىر مەشغۇلاتنى جەزملەيدۇ +Comment[uk]=Виконання дій у відповідь на натискання кнопки +Comment[wa]=Fwait on faitindje cwand on boton est tchôkî +Comment[x-test]=xxPerforms an action whenever a button is pressedxx +Comment[zh_CN]=按键时执行一个动作 +Comment[zh_TW]=按鍵被按下時執行動作 + +X-KDE-PowerDevil-Action-ID=HandleButtonEvents +X-KDE-PowerDevil-Action-IsBundled=true +X-KDE-PowerDevil-Action-UIComponentLibrary=powerdevilhandlebuttoneventsaction_config +X-KDE-PowerDevil-Action-ConfigPriority=80 +X-KDE-PowerDevil-Action-HasRuntimeRequirement=true +X-KDE-PowerDevil-Action-RegistersDBusInterface=true diff --git a/powerdevil/daemon/actions/bundled/powerdevilkeyboardbrightnesscontrolaction.desktop b/powerdevil/daemon/actions/bundled/powerdevilkeyboardbrightnesscontrolaction.desktop new file mode 100644 index 00000000..069f6e46 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/powerdevilkeyboardbrightnesscontrolaction.desktop @@ -0,0 +1,98 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevil/Action +X-KDE-Library=powerdevilkeyboardbrightnesscontrolaction_config +Icon=input-keyboard +Name=Keyboard Backlight +Name[bs]=Pozadinsko osvjetljenje tastature +Name[ca]=Retroil·luminació del teclat +Name[ca@valencia]=Retroil·luminació del teclat +Name[cs]=Podsvícení klávesnice +Name[da]=Tastaturets baglys +Name[de]=Tastatur-Hintergrundhelligkeit +Name[el]=Φωτισμός πληκτρολογίου +Name[en_GB]=Keyboard Backlight +Name[es]=Luz trasera del teclado +Name[et]=Klaviatuuri tagavalgustus +Name[eu]=Teklatuaren atzeko argia +Name[fi]=Näppäimistön taustavalo +Name[fr]=Rétroéclairage du clavier +Name[gl]=Luz do teclado +Name[he]=תאורה אחורית של מקלדת +Name[hu]=Billentyűzet háttérvilágítás +Name[ia]=Luce de retro (Backlight) de claviero +Name[kk]=Перенетақта жарықтығы +Name[ko]=키보드 백라이트 +Name[lt]=Klaviatūros apšvietimas +Name[mr]=कळफलक मागील प्रकाश +Name[nb]=Tastaturbaklys +Name[nds]=Tastatuur-Achterlicht +Name[nl]=Toetsenbordverlichting +Name[pa]=ਕੀ-ਬੋਰਡ ਬੈਕਲਾਈਟ +Name[pl]=Podświetlenie klawiatury +Name[pt]=Luz Traseira do Teclado +Name[pt_BR]=Iluminação do teclado +Name[ro]=Iluminarea tastaturii +Name[ru]=Подсветка клавиатуры +Name[sk]=Spätné svetlo klávesnice +Name[sl]=Osvetlitev tipkovnice +Name[sr]=Осветљење тастатуре +Name[sr@ijekavian]=Осветљење тастатуре +Name[sr@ijekavianlatin]=Osvetljenje tastature +Name[sr@latin]=Osvetljenje tastature +Name[sv]=Bakgrundsbelysning på tangentbord +Name[tr]=Klavye Arkaışığı +Name[uk]=Підсвічування клавіатури +Name[x-test]=xxKeyboard Backlightxx +Name[zh_CN]=键盘背光 +Name[zh_TW]=鍵盤背光 +Comment=Basic Controls for the keyboard backlight brightness +Comment[bs]=Osnovne kontrole osvetljaja pozadine tastature +Comment[ca]=Controls bàsics per la brillantor de la retroil·luminació del teclat +Comment[ca@valencia]=Controls bàsics per la brillantor de la retroil·luminació del teclat +Comment[cs]=Základní ovládání jasu podsvícení klávesnice +Comment[da]=Basal kontrol af lysstyrke på tastaturets baglys +Comment[de]=Grundeinstellungen zur Hintergrundhelligkeit der Tastatur +Comment[el]=Βασικά στοιχεία ελέγχου λαμπρότητας στο φωτισμό του πληκτρολογίου +Comment[en_GB]=Basic Controls for the keyboard backlight brightness +Comment[es]=Control básico del brillo de la luz trasera del teclado +Comment[et]=Klaviatuuri tagavalgustuse lihtne juhtimine +Comment[eu]=Teklatuaren atzeko-argi distiraren oinarrizko aginteak +Comment[fi]=Näppäimistön taustavalon kirkkauden perussäätimet +Comment[fr]=Contrôles simples de la luminosité pour le rétro-éclairage du clavier +Comment[gl]=Controis básicos do brillo da luz do teclado +Comment[hu]=Alap vezérlők a billentyűzet háttérvilágításának fényerejéhez +Comment[ia]=Controlos basic pro intensitatede illumination de luce de retro de claviero +Comment[is]=Grunnstýringar fyrir baklýsingarbirtustig lyklaborðs +Comment[kk]=Пернетақта жарықтық күшінің негізгі тұтқалары +Comment[ko]=키보드 백라이트 기본 밝기 제어 +Comment[lt]=Pagrindiniai klaviatūros apšvietimo valdikliai +Comment[mr]=कळफलक मागील प्रकाशाच्या प्रखरतेसाठी मूलभूत नियंत्रण +Comment[nb]=Enkel styring av lysstyrke for tastaturbaklys +Comment[nds]=Helligkeit-Instellen för't Tastatuur-Achterlicht +Comment[nl]=Basisbesturing voor helderheid van de toetsenbordverlichting +Comment[pa]=ਕੀਬੋਰਡ ਬੈਕਲਿਟ ਚਮਕ ਲਈ ਮੁੱਢਲੇ ਕੰਟਰੋਲ +Comment[pl]=Podstawowe sterowanie dla jasności podświetlenia klawiatury +Comment[pt]=Controlos básicos do brilho da luz traseira do teclado +Comment[pt_BR]=Controles básicos da iluminação do teclado +Comment[ro]=Controale de bază pentru luminozitatea iluminării tastaturii +Comment[ru]=Базовое управление подсветкой клавиатуры +Comment[sk]=Základné ovládacie prvky pre jas spätného svetla klávesnice +Comment[sl]=Osnovni nadzor osvetlitve tipkovnice +Comment[sr]=Основне контроле осветљења тастатуре +Comment[sr@ijekavian]=Основне контроле осветљења тастатуре +Comment[sr@ijekavianlatin]=Osnovne kontrole osvetljenja tastature +Comment[sr@latin]=Osnovne kontrole osvetljenja tastature +Comment[sv]=Grundkontroller för ljusstyrka av tangentbordets bakgrundsbelysning +Comment[tr]=Klavyenin arkaışık parlaklığı için Temel Kontroller +Comment[uk]=Базове керування яскравістю підсвічування клавіатури +Comment[x-test]=xxBasic Controls for the keyboard backlight brightnessxx +Comment[zh_CN]=键盘背光亮度基本控制 +Comment[zh_TW]=鍵盤背光亮度的基本控制 + +X-KDE-PowerDevil-Action-ID=KeyboardBrightnessControl +X-KDE-PowerDevil-Action-IsBundled=true +X-KDE-PowerDevil-Action-UIComponentLibrary=powerdevilkeyboardbrightnesscontrolaction_config +X-KDE-PowerDevil-Action-ConfigPriority=100 +X-KDE-PowerDevil-Action-HasRuntimeRequirement=true +X-KDE-PowerDevil-Action-RegistersDBusInterface=true diff --git a/powerdevil/daemon/actions/bundled/powerdevilrunscriptaction.desktop b/powerdevil/daemon/actions/bundled/powerdevilrunscriptaction.desktop new file mode 100644 index 00000000..3b157228 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/powerdevilrunscriptaction.desktop @@ -0,0 +1,120 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevil/Action +# X-KDE-Library=powerdevilrunscriptaction +Icon=system-run +Name=Run Script +Name[ar]=تشغيل سكربت +Name[ast]=Executar guión +Name[bg]=Изпълнение на скрипт +Name[bs]=Izvrši skriptu +Name[ca]=Executa un script +Name[ca@valencia]=Executa un script +Name[cs]=Spustit skript +Name[da]=Kør script +Name[de]=Skript ausführen +Name[el]=Εκτέλεση σεναρίου +Name[en_GB]=Run Script +Name[es]=Ejecutar guion +Name[et]=Skripti käivitamine +Name[eu]=Exekutatu scripta +Name[fi]=Suorita skripti +Name[fr]=Démarrer un script +Name[ga]=Rith Script +Name[gl]=Executar un script +Name[he]=הרצת תסריט +Name[hi]=स्क्रिप्ट चलाएँ +Name[hr]=Pokreni skriptu +Name[hu]=Parancsfájl futtatása +Name[ia]=Exeque script +Name[is]=Keyra skriftu +Name[ja]=スクリプトを実行 +Name[kk]=Скриптті орындау +Name[km]=ដំណើរការ​ស្គ្រីប +Name[ko]=스크립트 실행 +Name[lt]=Paleisti scenarijų +Name[lv]=Palaist skriptu +Name[mr]=स्क्रिप्ट चालवा +Name[nb]=Kjør skript +Name[nds]=Skript utföhren +Name[nl]=Script uitvoeren +Name[pa]=ਸਕ੍ਰਿਪਟ ਚਲਾਓ +Name[pl]=Uruchom skrypt +Name[pt]=Executar um Programa +Name[pt_BR]=Executar script +Name[ro]=Rulează script +Name[ru]=Запустить сценарий +Name[sk]=Spustiť skript +Name[sl]=Zaženi skript +Name[sr]=Изврши скрипту +Name[sr@ijekavian]=Изврши скрипту +Name[sr@ijekavianlatin]=Izvrši skriptu +Name[sr@latin]=Izvrši skriptu +Name[sv]=Kör skript +Name[th]=ให้สคริปต์ทำงาน +Name[tr]=Betik Çalıştır +Name[ug]=قوليازما ئىجرا قىل +Name[uk]=Виконати скрипт +Name[wa]=Enonder scripe +Name[x-test]=xxRun Scriptxx +Name[zh_CN]=运行脚本 +Name[zh_TW]=執行文稿 +Comment=Runs a custom script +Comment[ast]=Executa un guión personalizáu +Comment[bg]=Изпълнение на потребителски скрипт +Comment[bs]=Izvršava posebnu skriptu +Comment[ca]=Executa un script personalitzat +Comment[ca@valencia]=Executa un script personalitzat +Comment[cs]=Spustit vlastní skript +Comment[da]=Kører et brugerdefineret script +Comment[de]=Führt ein benutzerdefiniertes Skript aus +Comment[el]=Εκτελεί ένα προσαρμοσμένο σενάριο +Comment[en_GB]=Runs a custom script +Comment[es]=Ejecuta un guion personalizado +Comment[et]=Kohandatud skripti käivitamine +Comment[eu]=Script pertsonalizatu bat exekutatzen du +Comment[fi]=Suorittaa mukautetun skriptin +Comment[fr]=Démarre un script personnalisé +Comment[ga]=Rith script shaincheaptha +Comment[gl]=Executa un script +Comment[he]=משמש להרצת תסריט מותאם אישית +Comment[hr]=Pokreće prilagođene skripte +Comment[hu]=Egyéni parancsfájl futtatása +Comment[ia]=Il exeque un script personalisate +Comment[is]=Keyra sérsniðna skriftu +Comment[ja]=カスタムスクリプトを実行 +Comment[kk]=Пайдаланушының скриптін орындау +Comment[km]=ដំណើរការ​ស្គ្រីប​ផ្ទាល់ខ្លួន +Comment[ko]=사용자 정의 스크립트를 실행합니다 +Comment[lt]=Paleisti savo scenarijų +Comment[lv]=Palaiž pielāgotu skriptu +Comment[mr]=ऐच्छिक स्क्रिप्ट चालवा +Comment[nb]=Kjører et egendefinert skript +Comment[nds]=Föhrt en egen Skript ut +Comment[nl]=Een eigen script uitvoeren +Comment[pa]=ਪਸੰਦੀਦਾ ਸਕ੍ਰਿਪਟ ਚਲਾਓ +Comment[pl]=Uruchomia własny skrypt +Comment[pt]=Executa um programa personalizado +Comment[pt_BR]=Executa um script personalizado +Comment[ro]=Rulează un script personalizat +Comment[ru]=Запускает пользовательский сценарий +Comment[sk]=Spustí vlastný skript +Comment[sl]=Zažene skript po meri +Comment[sr]=Извршава посебну скрипту +Comment[sr@ijekavian]=Извршава посебну скрипту +Comment[sr@ijekavianlatin]=Izvršava posebnu skriptu +Comment[sr@latin]=Izvršava posebnu skriptu +Comment[sv]=Kör ett eget skript +Comment[th]=ให้สคริปตท์ที่กำหนดเองทำงาน +Comment[tr]=Özel bir betik çalıştır +Comment[ug]=ئۆزلەشتۈرگەن قوليازمىدىن بىرنى ئىجرا قىلىدۇ +Comment[uk]=Запускає вказаний користувачем скрипт +Comment[wa]=Enonde on scripe da vosse +Comment[x-test]=xxRuns a custom scriptxx +Comment[zh_CN]=运行自定义脚本 +Comment[zh_TW]=執行自訂文稿 + +X-KDE-PowerDevil-Action-ID=RunScript +X-KDE-PowerDevil-Action-IsBundled=true +X-KDE-PowerDevil-Action-UIComponentLibrary=powerdevilrunscriptaction_config +X-KDE-PowerDevil-Action-ConfigPriority=70 diff --git a/powerdevil/daemon/actions/bundled/powerdevilsuspendsessionaction.desktop b/powerdevil/daemon/actions/bundled/powerdevilsuspendsessionaction.desktop new file mode 100644 index 00000000..4cebd703 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/powerdevilsuspendsessionaction.desktop @@ -0,0 +1,118 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevil/Action +# X-KDE-Library=powerdevilsuspendsessionaction +Icon=system-shutdown +Name=Suspend Session +Name[ast]=Suspender la sesión +Name[bg]=Прекратяване на сесията +Name[bs]=Suspenduj sesiju +Name[ca]=Suspèn la sessió +Name[ca@valencia]=Suspèn la sessió +Name[cs]=Pozastavit sezení +Name[da]=Suspendér session +Name[de]=Sitzung in den Ruhezustand versetzen +Name[el]=Αναστολή συνεδρίας +Name[en_GB]=Suspend Session +Name[es]=Suspender la sesión +Name[et]=Seansi peatamine +Name[eu]=Egonean utzi saioa +Name[fi]=Keskeytä istunto +Name[fr]=Suspendre la session +Name[gl]=Suspender a sesión +Name[he]=השהיית ההפעלה +Name[hi]=सत्र स्थगिक +Name[hr]=Obustavljanje sesije +Name[hu]=Munkamenet felfüggesztése +Name[ia]=Suspende session +Name[is]=Setja skjáborðssetu í bið +Name[ja]=セッションをサスペンド +Name[kk]=Сеансын аялдату +Name[km]=ផ្អាក​សម័យ +Name[ko]=세션 일시 중지 +Name[lt]=Užlaikyti sesiją +Name[lv]=Iemidzināt sesiju +Name[mr]=सत्र अकार्यक्षम करा +Name[nb]=Suspender økt +Name[nds]=Törn utsetten +Name[nl]=Sessie onderbreken +Name[pa]=ਸ਼ੈਸ਼ਨ ਸਸਪੈਂਡ +Name[pl]=Wstrzymaj sesję +Name[pt]=Suspender a Sessão +Name[pt_BR]=Suspender sessão +Name[ro]=Suspendă sesiunea +Name[ru]=Приостановить сеанс +Name[sk]=Pozastaviť sedenie +Name[sl]=Prestavi sejo v pripravljenost +Name[sr]=Суспендуј сесију +Name[sr@ijekavian]=Суспендуј сесију +Name[sr@ijekavianlatin]=Suspenduj sesiju +Name[sr@latin]=Suspenduj sesiju +Name[sv]=Stoppa tillfälligt session +Name[th]=หยุดวาระ +Name[tr]=Oturumu Askıya Al +Name[ug]=ئەڭگىمە توڭلىتىش +Name[uk]=Призупинити сеанс +Name[wa]=Mete doirmi l' session +Name[x-test]=xxSuspend Sessionxx +Name[zh_CN]=挂起会话 +Name[zh_TW]=暫停工作階段 +Comment=Suspends the session +Comment[ast]=Suspende la sesión +Comment[bg]=Прекратява сесията +Comment[bs]=Suspenduje sesiju +Comment[ca]=Suspèn la sessió +Comment[ca@valencia]=Suspèn la sessió +Comment[cs]=Pozastaví sezení +Comment[da]=Suspenderer sessionen +Comment[de]=Versetzt die Sitzung in den Ruhezustand +Comment[el]=Αναστέλλει την συνεδρία +Comment[en_GB]=Suspends the session +Comment[es]=Suspende la sesión +Comment[et]=Seansi peatamine +Comment[eu]=Saioa egonean uzten du +Comment[fi]=Keskeyttää istunnon +Comment[fr]=Suspend la session +Comment[gl]=Suspende a sesión +Comment[he]=משמש להשהיית ההפעלה +Comment[hr]=Obustavljanje ove sesije +Comment[hu]=A munkamenet felfüggesztése +Comment[ia]=Il suspende le session +Comment[is]=Setur setuna í bið +Comment[ja]=セッションをサスペンドします +Comment[kk]=Сеансын тоқтата тұру +Comment[km]=ផ្អាក​សម័យ +Comment[ko]=세션을 일시 중단합니다 +Comment[lt]=Užlaiko sesiją +Comment[lv]=Iemidzina sesiju +Comment[mr]=सत्र अकार्यक्षम करतो +Comment[nb]=Suspenderer økta +Comment[nds]=Sett den Törn ut +Comment[nl]=De sessie onderbreken +Comment[pa]=ਸ਼ੈਸ਼ਨ ਸਸਪੈਂਡ ਕਰੋ +Comment[pl]=Wstrzymuje sesję +Comment[pt]=Suspende a sessão +Comment[pt_BR]=Suspende a sessão +Comment[ro]=Suspendă sesiunea +Comment[ru]=Приостанавливает текущий сеанс KDE +Comment[sk]=Pozastaví sedenie +Comment[sl]=Prestavi sejo v pripravljenost +Comment[sr]=Суспендује сесију +Comment[sr@ijekavian]=Суспендује сесију +Comment[sr@ijekavianlatin]=Suspenduje sesiju +Comment[sr@latin]=Suspenduje sesiju +Comment[sv]=Stoppar sessionen tillfälligt +Comment[th]=หยุดวาระ +Comment[tr]=Oturumu askıya alır +Comment[ug]=ئەڭگىمەنى توڭلىتىدۇ +Comment[uk]=Призупиняє сеанс +Comment[wa]=Met doirmi l' session +Comment[x-test]=xxSuspends the sessionxx +Comment[zh_CN]=挂起会话 +Comment[zh_TW]=暫停工作階段 + +X-KDE-PowerDevil-Action-ID=SuspendSession +X-KDE-PowerDevil-Action-IsBundled=true +X-KDE-PowerDevil-Action-UIComponentLibrary=powerdevilsuspendsessionaction_config +X-KDE-PowerDevil-Action-ConfigPriority=90 +X-KDE-PowerDevil-Action-RegistersDBusInterface=true diff --git a/powerdevil/daemon/actions/bundled/runscript.cpp b/powerdevil/daemon/actions/bundled/runscript.cpp new file mode 100644 index 00000000..863f2a5b --- /dev/null +++ b/powerdevil/daemon/actions/bundled/runscript.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "runscript.h" + +#include + +#include + +namespace PowerDevil { +namespace BundledActions { + +RunScript::RunScript(QObject* parent) + : Action(parent) +{ + // TODO: Which policy should we enforce here? Let's go for the less restrictive one + setRequiredPolicies(PowerDevil::PolicyAgent::ChangeScreenSettings); +} + +RunScript::~RunScript() +{ + +} + +void RunScript::onProfileUnload() +{ + if (m_scriptPhase == 1) { + QProcess::startDetached(m_scriptCommand); + } +} + +void RunScript::onWakeupFromIdle() +{ + // +} + +void RunScript::onIdleTimeout(int msec) +{ + Q_UNUSED(msec); + QProcess::startDetached(m_scriptCommand); +} + +void RunScript::onProfileLoad() +{ + if (m_scriptPhase == 0) { + QProcess::startDetached(m_scriptCommand); + } +} + +void RunScript::triggerImpl(const QVariantMap& args) +{ + Q_UNUSED(args); +} + +bool RunScript::loadAction(const KConfigGroup& config) +{ + if (config.hasKey("scriptCommand") && config.hasKey("scriptPhase")) { + m_scriptCommand = config.readEntry("scriptCommand", QString()); + m_scriptPhase = config.readEntry("scriptPhase", 0); + if (m_scriptPhase == 2) { + if (!config.hasKey("idleTime")) { + return false; + } + registerIdleTimeout(config.readEntry("idleTime", 10000000)); + } + } + + return true; +} + +} +} diff --git a/powerdevil/daemon/actions/bundled/runscript.h b/powerdevil/daemon/actions/bundled/runscript.h new file mode 100644 index 00000000..41498ac2 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/runscript.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_RUNSCRIPT_H +#define POWERDEVIL_BUNDLEDACTIONS_RUNSCRIPT_H + +#include + + +namespace PowerDevil { +namespace BundledActions { + +class RunScript : public PowerDevil::Action +{ + Q_OBJECT + Q_DISABLE_COPY(RunScript) + +public: + explicit RunScript(QObject* parent); + virtual ~RunScript(); + +protected: + virtual void onProfileUnload(); + virtual void onWakeupFromIdle(); + virtual void onIdleTimeout(int msec); + virtual void onProfileLoad(); + virtual void triggerImpl(const QVariantMap& args); + +public: + virtual bool loadAction(const KConfigGroup& config); + +private: + int m_scriptPhase; + QString m_scriptCommand; +}; + +} + +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_RUNSCRIPT_H diff --git a/powerdevil/daemon/actions/bundled/runscriptconfig.cpp b/powerdevil/daemon/actions/bundled/runscriptconfig.cpp new file mode 100644 index 00000000..63850d65 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/runscriptconfig.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "runscriptconfig.h" + +#include + +#include +#include +#include +#include +#include + +K_PLUGIN_FACTORY(PowerDevilRunScriptConfigFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(PowerDevilRunScriptConfigFactory("powerdevilrunscriptaction_config")) + +namespace PowerDevil { +namespace BundledActions { + +RunScriptConfig::RunScriptConfig(QObject* parent, const QVariantList&) + : ActionConfig(parent) +{ + +} + +RunScriptConfig::~RunScriptConfig() +{ + +} + +void RunScriptConfig::save() +{ + configGroup().writeEntry("scriptCommand", m_urlRequester->text()); + configGroup().writeEntry("scriptPhase", m_comboBox->currentIndex()); + configGroup().writeEntry("idleTime", m_idleTime->value() * 60 * 1000); + + configGroup().sync(); +} + +void RunScriptConfig::load() +{ + configGroup().config()->reparseConfiguration(); + m_urlRequester->setText(configGroup().readEntry("scriptCommand", QString())); + m_comboBox->setCurrentIndex(configGroup().readEntry("scriptPhase", 0)); + m_idleTime->setValue((configGroup().readEntry("idleTime", 600000) / 60) / 1000); +} + +QList< QPair< QString, QWidget* > > RunScriptConfig::buildUi() +{ + QList< QPair< QString, QWidget* > > retlist; + m_urlRequester = new KUrlRequester(); + m_urlRequester->setMode(KFile::File | KFile::LocalOnly | KFile::ExistingOnly); + m_urlRequester->setMaximumWidth(300); + retlist.append(qMakePair< QString, QWidget* >(i18n("Script"), m_urlRequester)); + + QWidget *tempWidget = new QWidget; + QHBoxLayout *hlay = new QHBoxLayout; + m_comboBox = new KComboBox; + m_idleTime = new KIntSpinBox(0, 180, 1, 0, 0); + m_idleTime->setMaximumWidth(150); + m_idleTime->setMinimum(1); + m_idleTime->setMaximum(360); + m_idleTime->setDisabled(true); + m_idleTime->setSuffix(i18n(" min")); + m_comboBox->addItem(i18n("On Profile Load")); + m_comboBox->addItem(i18n("On Profile Unload")); + m_comboBox->addItem(i18n("After")); + connect(m_comboBox, SIGNAL(currentIndexChanged(QString)), + this, SLOT(onIndexChanged(QString))); + + hlay->addWidget(m_comboBox); + hlay->addWidget(m_idleTime); + hlay->addStretch(); + + tempWidget->setLayout(hlay); + + retlist.append(qMakePair< QString, QWidget* >(i18n("Run script"), tempWidget)); + + connect(m_urlRequester, SIGNAL(textChanged(QString)), this, SLOT(setChanged())); + connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setChanged())); + connect(m_idleTime, SIGNAL(valueChanged(int)), this, SLOT(setChanged())); + + return retlist; +} + +void RunScriptConfig::onIndexChanged(const QString &text) +{ + m_idleTime->setEnabled(text == i18n("After")); +} + +} +} + +#include "runscriptconfig.moc" diff --git a/powerdevil/daemon/actions/bundled/runscriptconfig.h b/powerdevil/daemon/actions/bundled/runscriptconfig.h new file mode 100644 index 00000000..7ad61cfb --- /dev/null +++ b/powerdevil/daemon/actions/bundled/runscriptconfig.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_RUNSCRIPTCONFIG_H +#define POWERDEVIL_BUNDLEDACTIONS_RUNSCRIPTCONFIG_H + +#include + +class KIntSpinBox; +class KComboBox; +class KUrlRequester; + +namespace PowerDevil { +namespace BundledActions { + +class RunScriptConfig : public PowerDevil::ActionConfig +{ + Q_OBJECT + Q_DISABLE_COPY(RunScriptConfig) + +public: + RunScriptConfig(QObject* parent, const QVariantList&); + virtual ~RunScriptConfig(); + + virtual void save(); + virtual void load(); + virtual QList< QPair< QString, QWidget* > > buildUi(); + +private: + KUrlRequester *m_urlRequester; + KComboBox *m_comboBox; + KIntSpinBox *m_idleTime; + +private Q_SLOTS: + void onIndexChanged(const QString&); +}; + +} +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_RUNSCRIPTCONFIG_H diff --git a/powerdevil/daemon/actions/bundled/suspendsession.cpp b/powerdevil/daemon/actions/bundled/suspendsession.cpp new file mode 100644 index 00000000..c6d2456d --- /dev/null +++ b/powerdevil/daemon/actions/bundled/suspendsession.cpp @@ -0,0 +1,207 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "suspendsession.h" + +#include "powerdevilbackendinterface.h" +#include "powerdevilcore.h" + +#include "suspendsessionadaptor.h" + +#include +#include +#include +#include + +#include + +#include "screensaver_interface.h" +#include + +namespace PowerDevil +{ +namespace BundledActions +{ + +SuspendSession::SuspendSession(QObject* parent) + : Action(parent), + m_dbusWatcher(0) +{ + // DBus + new SuspendSessionAdaptor(this); + + setRequiredPolicies(PowerDevil::PolicyAgent::InterruptSession); + + connect(backend(), SIGNAL(resumeFromSuspend()), + this, SLOT(onResumeFromSuspend())); +} + +SuspendSession::~SuspendSession() +{ + +} + +void SuspendSession::onProfileUnload() +{ + // Nothing to do +} + +void SuspendSession::onWakeupFromIdle() +{ + // Nothing to do +} + +void SuspendSession::onIdleTimeout(int msec) +{ + Q_UNUSED(msec); + QVariantMap args; + args.insert("Type", m_autoType); + trigger(args); +} + +void SuspendSession::onProfileLoad() +{ + // Nothing to do +} + +void SuspendSession::triggerImpl(const QVariantMap& args) +{ + kDebug() << "Triggered with " << args["Type"].toString() << args["SkipLocking"].toBool(); + + // Switch for screen lock + QVariantMap recallArgs; + switch ((Mode) (args["Type"].toUInt())) { + case ToRamMode: + case ToDiskMode: + case SuspendHybridMode: + // Do we want to lock the screen? + if (PowerDevilSettings::configLockScreen() && !args["SkipLocking"].toBool()) { + // Yeah, we do. + m_savedArgs = args; + recallArgs["Type"] = (uint)LockScreenMode; + triggerImpl(recallArgs); + return; + } + break; + default: + break; + } + + // Switch for real action + KJob *suspendJob = 0; + switch ((Mode) (args["Type"].toUInt())) { + case ToRamMode: + suspendJob = backend()->suspend(PowerDevil::BackendInterface::ToRam); + break; + case ToDiskMode: + suspendJob = backend()->suspend(PowerDevil::BackendInterface::ToDisk); + break; + case SuspendHybridMode: + suspendJob = backend()->suspend(PowerDevil::BackendInterface::HybridSuspend); + break; + case ShutdownMode: + KWorkSpace::requestShutDown(KWorkSpace::ShutdownConfirmNo, KWorkSpace::ShutdownTypeHalt); + break; + case LogoutDialogMode: + KWorkSpace::requestShutDown(KWorkSpace::ShutdownConfirmYes); + break; + case LockScreenMode: + lockScreenAndWait(); + break; + default: + break; + } + + if (suspendJob) { + suspendJob->start(); + } +} + +void SuspendSession::lockScreenAndWait() +{ + OrgFreedesktopScreenSaverInterface iface("org.freedesktop.ScreenSaver", + "/ScreenSaver", + QDBusConnection::sessionBus()); + QDBusPendingReply< void > reply = iface.Lock(); + m_dbusWatcher = new QDBusPendingCallWatcher(reply, this); + connect(m_dbusWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(lockCompleted())); +} + +void SuspendSession::lockCompleted() +{ + QVariantMap args = m_savedArgs; + + m_dbusWatcher->deleteLater(); + m_dbusWatcher = 0; + m_savedArgs.clear(); + + args["SkipLocking"] = true; + triggerImpl(args); +} + +bool SuspendSession::loadAction(const KConfigGroup& config) +{ + if (config.isValid() && config.hasKey("idleTime") && config.hasKey("suspendType")) { + // Add the idle timeout + registerIdleTimeout(config.readEntry("idleTime", 0)); + m_autoType = config.readEntry("suspendType", 0); + } + + return true; +} + +void SuspendSession::suspendHybrid() +{ + triggerSuspendSession(SuspendHybridMode); +} + +void SuspendSession::suspendToDisk() +{ + triggerSuspendSession(ToDiskMode); +} + +void SuspendSession::suspendToRam() +{ + triggerSuspendSession(ToRamMode); +} + +void SuspendSession::triggerSuspendSession(uint action) +{ + QVariantMap args; + args["Type"] = action; + args["Explicit"] = true; + trigger(args); +} + +void SuspendSession::onResumeFromSuspend() +{ + // Notify the screensaver + OrgFreedesktopScreenSaverInterface iface("org.freedesktop.ScreenSaver", + "/ScreenSaver", + QDBusConnection::sessionBus()); + iface.SimulateUserActivity(); + PowerDevil::PolicyAgent::instance()->setupSystemdInhibition(); + + Q_EMIT resumingFromSuspend(); +} + +} +} + +#include "suspendsession.moc" diff --git a/powerdevil/daemon/actions/bundled/suspendsession.h b/powerdevil/daemon/actions/bundled/suspendsession.h new file mode 100644 index 00000000..0c319f26 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/suspendsession.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_SUSPENDSESSION_H +#define POWERDEVIL_BUNDLEDACTIONS_SUSPENDSESSION_H + +#include + +class QDBusPendingCallWatcher; + +namespace PowerDevil +{ +namespace BundledActions +{ + +class SuspendSession : public PowerDevil::Action +{ + Q_OBJECT + Q_DISABLE_COPY(SuspendSession) + Q_CLASSINFO("D-Bus Interface", "org.kde.Solid.PowerManagement.Actions.SuspendSession") + +public: + enum Mode { + None = 0, + ToRamMode = 1, + ToDiskMode = 2, + SuspendHybridMode = 4, + ShutdownMode = 8, + LogoutDialogMode = 16, + LockScreenMode = 32, + TurnOffScreenMode = 64 + }; + + explicit SuspendSession(QObject *parent); + virtual ~SuspendSession(); + + virtual bool loadAction(const KConfigGroup& config); + +protected: + virtual void onProfileUnload(); + virtual void onWakeupFromIdle(); + virtual void onIdleTimeout(int msec); + virtual void onProfileLoad(); + virtual void triggerImpl(const QVariantMap& args); + +public Q_SLOTS: + void suspendToRam(); + void suspendToDisk(); + void suspendHybrid(); + + void onResumeFromSuspend(); + +Q_SIGNALS: + void resumingFromSuspend(); + +private slots: + void lockCompleted(); + void triggerSuspendSession(uint action); + +private: + uint m_autoType; + QVariantMap m_savedArgs; + QDBusPendingCallWatcher *m_dbusWatcher; + + void lockScreenAndWait(); +}; + +} + +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_SUSPENDSESSION_H diff --git a/powerdevil/daemon/actions/bundled/suspendsessionconfig.cpp b/powerdevil/daemon/actions/bundled/suspendsessionconfig.cpp new file mode 100644 index 00000000..7443e00c --- /dev/null +++ b/powerdevil/daemon/actions/bundled/suspendsessionconfig.cpp @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "suspendsessionconfig.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include "suspendsession.h" + +K_PLUGIN_FACTORY(PowerDevilSuspendSessionConfigFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(PowerDevilSuspendSessionConfigFactory("powerdevilsuspendsessionaction_config")) + +namespace PowerDevil { +namespace BundledActions { + +SuspendSessionConfig::SuspendSessionConfig(QObject* parent, const QVariantList&) + : ActionConfig(parent) +{ + +} + +SuspendSessionConfig::~SuspendSessionConfig() +{ + +} + +void SuspendSessionConfig::save() +{ + configGroup().writeEntry< uint >("suspendType", m_comboBox->itemData(m_comboBox->currentIndex()).toUInt()); + configGroup().writeEntry("idleTime", m_idleTime->value() * 60 * 1000); + + configGroup().sync(); +} + +void SuspendSessionConfig::load() +{ + configGroup().config()->reparseConfiguration(); + + uint suspendType = configGroup().readEntry< uint >("suspendType", 0); + m_comboBox->setCurrentIndex(m_comboBox->findData(suspendType)); + m_idleTime->setValue((configGroup().readEntry("idleTime", 600000) / 60) / 1000); +} + +QList< QPair< QString, QWidget* > > SuspendSessionConfig::buildUi() +{ + QWidget *tempWidget = new QWidget; + QHBoxLayout *hlay = new QHBoxLayout; + m_comboBox = new KComboBox; + m_idleTime = new KIntSpinBox(0, 180, 1, 0, 0); + m_idleTime->setMaximumWidth(150); + m_idleTime->setMinimum(1); + m_idleTime->setMaximum(360); + m_idleTime->setSuffix(i18n(" min")); + + QSet< Solid::PowerManagement::SleepState > methods = Solid::PowerManagement::supportedSleepStates(); + + if (methods.contains(Solid::PowerManagement::SuspendState)) { + m_comboBox->addItem(KIcon("system-suspend"), i18n("Sleep"), (uint)SuspendSession::ToRamMode); + } + if (methods.contains(Solid::PowerManagement::HibernateState)) { + m_comboBox->addItem(KIcon("system-suspend-hibernate"), i18n("Hibernate"), (uint)SuspendSession::ToDiskMode); + } + m_comboBox->addItem(KIcon("system-shutdown"), i18n("Shutdown"), (uint)SuspendSession::ShutdownMode); + m_comboBox->addItem(KIcon("system-lock-screen"), i18n("Lock screen"), (uint)SuspendSession::LockScreenMode); + + hlay->addWidget(m_idleTime); + hlay->addWidget(m_comboBox); + hlay->addStretch(); + + tempWidget->setLayout(hlay); + + QList< QPair< QString, QWidget* > > retlist; + retlist.append(qMakePair< QString, QWidget* >(i18n("After"), tempWidget)); + + connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setChanged())); + connect(m_idleTime, SIGNAL(valueChanged(int)), this, SLOT(setChanged())); + + return retlist; +} + +} +} diff --git a/powerdevil/daemon/actions/bundled/suspendsessionconfig.h b/powerdevil/daemon/actions/bundled/suspendsessionconfig.h new file mode 100644 index 00000000..cf94b871 --- /dev/null +++ b/powerdevil/daemon/actions/bundled/suspendsessionconfig.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BUNDLEDACTIONS_SUSPENDSESSIONCONFIG_H +#define POWERDEVIL_BUNDLEDACTIONS_SUSPENDSESSIONCONFIG_H + +#include + +class KComboBox; +class KIntSpinBox; + +namespace PowerDevil { +namespace BundledActions { + +class SuspendSessionConfig : public PowerDevil::ActionConfig +{ + Q_OBJECT + Q_DISABLE_COPY(SuspendSessionConfig) +public: + SuspendSessionConfig(QObject* parent, const QVariantList&); + virtual ~SuspendSessionConfig(); + + virtual void save(); + virtual void load(); + virtual QList< QPair< QString, QWidget* > > buildUi(); + +private: + KIntSpinBox *m_idleTime; + KComboBox *m_comboBox; +}; + +} +} + +#endif // POWERDEVIL_BUNDLEDACTIONS_SUSPENDSESSIONCONFIG_H diff --git a/powerdevil/daemon/actions/dpms/CMakeLists.txt b/powerdevil/daemon/actions/dpms/CMakeLists.txt new file mode 100644 index 00000000..5a0b0e73 --- /dev/null +++ b/powerdevil/daemon/actions/dpms/CMakeLists.txt @@ -0,0 +1,24 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${X11_dpms_INCLUDE_PATH}) + +set(powerdevildpmsaction_SRCS powerdevildpmsaction.cpp) + +kde4_add_plugin(powerdevildpmsaction ${powerdevildpmsaction_SRCS}) +target_link_libraries(powerdevildpmsaction + ${X11_LIBRARIES} + ${KDE4_KDECORE_LIBS} + ${QT_QTGUI_LIBRARY} + powerdevilcore) +install(TARGETS powerdevildpmsaction DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES powerdevildpmsaction.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + +# Action config +set(dpmsconfig_SRCS powerdevildpmsactionconfig.cpp) +kde4_add_plugin(powerdevildpmsaction_config + ${dpmsconfig_SRCS}) +target_link_libraries(powerdevildpmsaction_config + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + powerdevilui) +install(TARGETS powerdevildpmsaction_config DESTINATION ${PLUGIN_INSTALL_DIR}) \ No newline at end of file diff --git a/powerdevil/daemon/actions/dpms/powerdevildpmsaction.cpp b/powerdevil/daemon/actions/dpms/powerdevildpmsaction.cpp new file mode 100644 index 00000000..29c0e5f9 --- /dev/null +++ b/powerdevil/daemon/actions/dpms/powerdevildpmsaction.cpp @@ -0,0 +1,233 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevildpmsaction.h" + +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +extern "C" { +#include + int __kde_do_not_unload = 1; + +#ifndef HAVE_DPMSCAPABLE_PROTO + Bool DPMSCapable(Display *); +#endif + +#ifndef HAVE_DPMSINFO_PROTO + Status DPMSInfo(Display *, CARD16 *, BOOL *); +#endif + +int dropError(Display *, XErrorEvent *); +typedef int (*XErrFunc)(Display *, XErrorEvent *); +} + +int dropError(Display *, XErrorEvent *) +{ + return 0; +} + +class PowerDevilDPMSAction::Private +{ +public: + XErrorHandler defaultHandler; +}; + +K_PLUGIN_FACTORY(PowerDevilDPMSActionFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(PowerDevilDPMSActionFactory("powerdevildpmsaction")) + +PowerDevilDPMSAction::PowerDevilDPMSAction(QObject* parent, const QVariantList &args) + : Action(parent) + , m_idleTime(0) + , m_inhibitScreen(0) // can't use PowerDevil::PolicyAgent enum because X11/X.h defines None as 0L + , d(new Private) +{ + setRequiredPolicies(PowerDevil::PolicyAgent::ChangeScreenSettings); + + // We want to query for DPMS in the constructor, before anything else happens + d->defaultHandler = XSetErrorHandler(dropError); + + // Since we are in the constructor, we should check for support manually + if (!isSupported()) { + XSetErrorHandler(d->defaultHandler); + return; + } + + // Is the action being loaded outside the core? + if (args.size() > 0) { + if (args.first().toBool()) { + kDebug() << "Action loaded from outside the core, skipping early init"; + return; + } + } + + // Pretend we're unloading profiles here, as if the action is not enabled, DPMS should be switched off. + onProfileUnload(); + + // Listen to the policy agent + connect(PowerDevil::PolicyAgent::instance(), + SIGNAL(unavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies)), + this, + SLOT(onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies))); + // inhibitions persist over kded module unload/load + m_inhibitScreen = PowerDevil::PolicyAgent::instance()->unavailablePolicies() & PowerDevil::PolicyAgent::ChangeScreenSettings; +} + +PowerDevilDPMSAction::~PowerDevilDPMSAction() +{ + delete d; +} + +bool PowerDevilDPMSAction::isSupported() +{ + Display *dpy = QX11Info::display(); + int dummy; + + return DPMSQueryExtension(dpy, &dummy, &dummy) && DPMSCapable(dpy); +} + +void PowerDevilDPMSAction::onProfileUnload() +{ + using namespace PowerDevil; + Display *dpy = QX11Info::display(); + if (!(PolicyAgent::instance()->unavailablePolicies() & PolicyAgent::ChangeScreenSettings)) { + DPMSDisable(dpy); + } else { + kDebug() << "Not performing DPMS action due to inhibition"; + } + DPMSSetTimeouts(dpy, 0, 0, 0); +} + +void PowerDevilDPMSAction::onWakeupFromIdle() +{ + // +} + +void PowerDevilDPMSAction::onIdleTimeout(int msec) +{ + Q_UNUSED(msec); +} + +void PowerDevilDPMSAction::onProfileLoad() +{ + using namespace PowerDevil; + Display *dpy = QX11Info::display(); + if (!(PolicyAgent::instance()->unavailablePolicies() & PolicyAgent::ChangeScreenSettings)) { + DPMSEnable(dpy); + } else { + kDebug() << "Not performing DPMS action due to inhibition"; + return; + } + + XFlush(dpy); + XSetErrorHandler(d->defaultHandler); + + // An unloaded action will have m_idleTime = 0: + // DPMS enabled with zeroed timeouts is effectively disabled. + // So onProfileLoad is always safe + DPMSSetTimeouts(dpy, (CARD16)m_idleTime, (CARD16)(m_idleTime * 1.5), (CARD16)(m_idleTime * 2)); + + XFlush(dpy); + XSetErrorHandler(d->defaultHandler); +} + +void PowerDevilDPMSAction::triggerImpl(const QVariantMap& args) +{ + CARD16 dummy; + BOOL enabled; + Display *dpy = QX11Info::display(); + DPMSInfo(dpy, &dummy, &enabled); + + if (args["Type"].toString() == "TurnOff") { + if (enabled) { + DPMSForceLevel(dpy, DPMSModeOff); + } else { + DPMSEnable(dpy); + DPMSForceLevel(dpy, DPMSModeOff); + } + } else if (args["Type"].toString() == "Standby") { + if (enabled) { + DPMSForceLevel(dpy, DPMSModeStandby); + } else { + DPMSEnable(dpy); + DPMSForceLevel(dpy, DPMSModeStandby); + } + } else if (args["Type"].toString() == "Suspend") { + if (enabled) { + DPMSForceLevel(dpy, DPMSModeSuspend); + } else { + DPMSEnable(dpy); + DPMSForceLevel(dpy, DPMSModeSuspend); + } + } + + // this leaves DPMS enabled but if it's meant to be disabled + // then the timeouts will be zero and so effectively disabled +} + +bool PowerDevilDPMSAction::loadAction(const KConfigGroup& config) +{ + m_idleTime = config.readEntry("idleTime", -1); + + return true; +} + +bool PowerDevilDPMSAction::onUnloadAction() +{ + m_idleTime = 0; + return Action::onUnloadAction(); +} + +void PowerDevilDPMSAction::onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies policies) +{ + // only take action if screen inhibit changed + PowerDevil::PolicyAgent::RequiredPolicies oldPolicy = m_inhibitScreen; + m_inhibitScreen = policies & PowerDevil::PolicyAgent::ChangeScreenSettings; + if (oldPolicy == m_inhibitScreen) { + return; + } + + if (m_inhibitScreen) { + // Inhibition triggered: disable DPMS + kDebug() << "Disabling DPMS due to inhibition"; + Display *dpy = QX11Info::display(); + DPMSSetTimeouts(dpy, 0, 0, 0); + DPMSDisable(dpy); // wakes the screen - do we want this? + } else { + // Inhibition removed: let's start again + onProfileLoad(); + kDebug() << "Restoring DPMS features after inhibition release"; + } +} + +#include "powerdevildpmsaction.moc" diff --git a/powerdevil/daemon/actions/dpms/powerdevildpmsaction.desktop b/powerdevil/daemon/actions/dpms/powerdevildpmsaction.desktop new file mode 100644 index 00000000..adbcece7 --- /dev/null +++ b/powerdevil/daemon/actions/dpms/powerdevildpmsaction.desktop @@ -0,0 +1,119 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevil/Action +X-KDE-Library=powerdevildpmsaction +Icon=preferences-desktop-screensaver +Name=Screen Energy Saving +Name[ast]=Aforru d'enerxía de la pantalla +Name[bg]=Пестене на енергия за екрана +Name[bs]=Štednja energije ekrana +Name[ca]=Estalvi d'energia de pantalla +Name[ca@valencia]=Estalvi d'energia de pantalla +Name[cs]=Úsporný režim obrazovky +Name[da]=Strømbesparelse for skærm +Name[de]=Bildschirm-Energiesparmodus +Name[el]=Εξοικονόμηση ενέργειας οθόνης +Name[en_GB]=Screen Energy Saving +Name[es]=Ahorro de energía de la pantalla +Name[et]=Ekraanisäästja +Name[eu]=Pantaila-energia aurreztea +Name[fi]=Näytön virransäästö +Name[fr]=Économie d'énergie pour l'écran +Name[gl]=Aforro enerxético da pantalla +Name[he]=חיסכון באנרגיית המסך +Name[hr]=Zaslonska štednja energije +Name[hu]=Kijelző kikapcsolása +Name[ia]=Sparnio de energia de schermo +Name[is]=Orkusparnaðarstillingar fyrir skjá +Name[kk]=Экран қуатын үнемдеу +Name[km]=សន្សំ​ថាមពល​អេក្រង់ +Name[ko]=화면 에너지 절약 +Name[lt]=Ekrano energijos taupymas +Name[lv]=Ekrāna enerģijas taupīšana +Name[mr]=स्क्रीन ऊर्जा बचत +Name[nb]=Energisparing for skjerm +Name[nds]=Monitor-Stroomspoorbedrief +Name[nl]=Energiebesparing bij het beeldscherm +Name[pa]=ਸਕਰੀਨ ਊਰਜਾ ਬਚਾਉਣੀ +Name[pl]=Oszczędzaj energię ekranu +Name[pt]=Configuração da Energia do Ecrã +Name[pt_BR]=Configurações da energia da tela +Name[ro]=Economisire energie ecran +Name[ru]=Энергосбережение монитора +Name[sk]=Šetrenie energie obrazovky +Name[sl]=Varčevanje z energijo zaslona +Name[sr]=Штедња енергије екрана +Name[sr@ijekavian]=Штедња енергије екрана +Name[sr@ijekavianlatin]=Štednja energije ekrana +Name[sr@latin]=Štednja energije ekrana +Name[sv]=Strömsparhantering av bildskärmen +Name[th]=การรักษาพลังงานของหน้าจอ +Name[tr]=Ekran Enerji Tasarrufu +Name[ug]=ئېكران ئېنېرگىيە تېجەش +Name[uk]=Заощадження енергії екраном +Name[wa]=Spårgnaedje di l' enerdjeye del waitroûle +Name[x-test]=xxScreen Energy Savingxx +Name[zh_CN]=屏幕节能 +Name[zh_TW]=螢幕節能 +Comment=Controls DPMS settings +Comment[ast]=Configuraciones control DPMS +Comment[bg]=Управление настройките на DPMS +Comment[bs]=Upravlja DPMS postavkama +Comment[ca]=Controla l'arranjament del DPMS +Comment[ca@valencia]=Controla l'arranjament del DPMS +Comment[cs]=Ovládání nastavení DPMS +Comment[da]=Styrer DPMS-indstillinger +Comment[de]=DPMS-Einstellungen +Comment[el]=Ελέγχει τις ρυθμίσεις DPMS +Comment[en_GB]=Controls DPMS settings +Comment[es]=Controla preferencias de DPMS +Comment[et]=Monitori toiteseadistused +Comment[eu]=DPMS ezarpenak kontrolatzen ditu +Comment[fi]=Hallitsee DPMS-asetuksia +Comment[fr]=Contrôle les paramètres DPMS +Comment[gl]=Controla a configuración do DPMS +Comment[he]=משמש לשליטה בהגדרות DPMS +Comment[hr]=Kontrola DPMS postavki +Comment[hu]=DPMS-beállítások irányítása +Comment[ia]=Preferentias de controlos DPMS +Comment[is]=Stillingar DPMS +Comment[ja]=DPMS の設定 +Comment[kk]=DPMS параметрлерін басқару +Comment[km]=ការ​កំណត់​វត្ថុ​បញ្ជា DPMS +Comment[kn]=DPMA ಸಂಯೋಜನೆಗಳನ್ನು ನಿಯಂತ್ರಿಸುತ್ತದೆ +Comment[ko]=DPMS 설정 +Comment[lt]=Valdo DPMS nustatymus +Comment[lv]=Kontrolē DPMS iestatījumus +Comment[mr]=DPMS संयोजना नियंत्रीत करतो +Comment[nb]=Styrer DPMS-innstillinger +Comment[nds]=Monitor-Stroomspoorbedrief instellen +Comment[nl]=DPMS-instellingen besturen +Comment[pa]=DPMS ਕੰਟਰੋਲ ਕਰੋ +Comment[pl]=Steruje ustawieniami DPMS +Comment[pt]=Controla a configuração do DPMS +Comment[pt_BR]=Controla as configurações do DPMS +Comment[ro]=Controlează configurările DPMS +Comment[ru]=Управление настройками энергопотребления монитора +Comment[sk]=Ovláda nastavenie DPMS +Comment[sl]=Nadzira nastavitve upravljanja z energijo zaslona +Comment[sr]=Управља ДПМС поставкама +Comment[sr@ijekavian]=Управља ДПМС поставкама +Comment[sr@ijekavianlatin]=Upravlja DPMS postavkama +Comment[sr@latin]=Upravlja DPMS postavkama +Comment[sv]=Styr DPMS-inställningar +Comment[th]=ควบคุมการตั้งค่า DPMS +Comment[tr]=DPMS ayarlarını kontrol eder +Comment[ug]=DPMS تەڭشەكلىرىنى تىزگىنلەيدۇ +Comment[uk]=Керування параметрами DPMS +Comment[vi]=Điều khiển các thiết lập DPMS +Comment[wa]=Controle les tchuzes DPMS +Comment[x-test]=xxControls DPMS settingsxx +Comment[zh_CN]=控制屏幕电源设置 +Comment[zh_TW]=控制 DPMS 設定 + +X-KDE-PowerDevil-Action-ID=DPMSControl +X-KDE-PowerDevil-Action-IsBundled=false +X-KDE-PowerDevil-Action-ForceInstantLoad=true +X-KDE-PowerDevil-Action-UIComponentLibrary=powerdevildpmsaction_config +X-KDE-PowerDevil-Action-ConfigPriority=98 +X-KDE-PowerDevil-Action-HasRuntimeRequirement=true diff --git a/powerdevil/daemon/actions/dpms/powerdevildpmsaction.h b/powerdevil/daemon/actions/dpms/powerdevildpmsaction.h new file mode 100644 index 00000000..71f9ccee --- /dev/null +++ b/powerdevil/daemon/actions/dpms/powerdevildpmsaction.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVILDPMSACTION_H +#define POWERDEVILDPMSACTION_H + +#include + +class PowerDevilDPMSAction : public PowerDevil::Action +{ + Q_OBJECT + Q_DISABLE_COPY(PowerDevilDPMSAction) + +public: + explicit PowerDevilDPMSAction(QObject* parent, const QVariantList&); + virtual ~PowerDevilDPMSAction(); + +protected: + virtual void onProfileUnload(); + virtual bool onUnloadAction(); + virtual void onWakeupFromIdle(); + virtual void onIdleTimeout(int msec); + virtual void onProfileLoad(); + virtual void triggerImpl(const QVariantMap& args); + bool isSupported(); + +public: + virtual bool loadAction(const KConfigGroup& config); + +private Q_SLOTS: + void onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies policies); + +private: + int m_idleTime; + PowerDevil::PolicyAgent::RequiredPolicies m_inhibitScreen; + + class Private; + Private * const d; +}; + +#endif // POWERDEVILDPMSACTION_H diff --git a/powerdevil/daemon/actions/dpms/powerdevildpmsactionconfig.cpp b/powerdevil/daemon/actions/dpms/powerdevildpmsactionconfig.cpp new file mode 100644 index 00000000..968b521f --- /dev/null +++ b/powerdevil/daemon/actions/dpms/powerdevildpmsactionconfig.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevildpmsactionconfig.h" + +#include +#include +#include + +K_PLUGIN_FACTORY(PowerDevilDPMSConfigFactory, registerPlugin(); ) +K_EXPORT_PLUGIN(PowerDevilDPMSConfigFactory("powerdevildpmsaction_config")) + +PowerDevilDPMSActionConfig::PowerDevilDPMSActionConfig(QObject* parent, const QVariantList& ) + : ActionConfig(parent) +{ + +} +PowerDevilDPMSActionConfig::~PowerDevilDPMSActionConfig() +{ + +} + +void PowerDevilDPMSActionConfig::save() +{ + configGroup().writeEntry("idleTime", m_spinBox->value() * 60); + + configGroup().sync(); +} + +void PowerDevilDPMSActionConfig::load() +{ + configGroup().config()->reparseConfiguration(); + m_spinBox->setValue(configGroup().readEntry("idleTime", 600) / 60); +} + +QList< QPair< QString, QWidget* > > PowerDevilDPMSActionConfig::buildUi() +{ + QList< QPair< QString, QWidget* > > retlist; + + m_spinBox = new KIntSpinBox(0, 180, 1, 0, 0); + m_spinBox->setMaximumWidth(150); + m_spinBox->setMinimum(1); + m_spinBox->setMaximum(360); + m_spinBox->setSuffix(i18n(" min")); + retlist.append(qMakePair< QString, QWidget* >(i18n("Switch off after"), m_spinBox)); + + connect(m_spinBox, SIGNAL(valueChanged(int)), this, SLOT(setChanged())); + + return retlist; +} + diff --git a/powerdevil/daemon/actions/dpms/powerdevildpmsactionconfig.h b/powerdevil/daemon/actions/dpms/powerdevildpmsactionconfig.h new file mode 100644 index 00000000..b6271ff2 --- /dev/null +++ b/powerdevil/daemon/actions/dpms/powerdevildpmsactionconfig.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVILDPMSACTIONCONFIG_H +#define POWERDEVILDPMSACTIONCONFIG_H + +#include + +class KIntSpinBox; +class PowerDevilDPMSActionConfig : public PowerDevil::ActionConfig +{ + Q_OBJECT + Q_DISABLE_COPY(PowerDevilDPMSActionConfig) +public: + PowerDevilDPMSActionConfig(QObject* parent, const QVariantList&); + virtual ~PowerDevilDPMSActionConfig(); + + virtual void save(); + virtual void load(); + virtual QList< QPair< QString, QWidget* > > buildUi(); + +private: + KIntSpinBox *m_spinBox; +}; + +#endif // POWERDEVILDPMSACTIONCONFIG_H diff --git a/powerdevil/daemon/actions/powerdevilaction.desktop b/powerdevil/daemon/actions/powerdevilaction.desktop new file mode 100644 index 00000000..d3a44409 --- /dev/null +++ b/powerdevil/daemon/actions/powerdevilaction.desktop @@ -0,0 +1,71 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=PowerDevil/Action + +Comment=Power Management Action Extension +Comment[ast]=Estensión aiciones xestión d'enerxía +Comment[bg]=Разширение за действия по управление на захранването +Comment[bs]=Proširenje radnji za upravljanje napajanjem +Comment[ca]=Extensió d'accions de gestió d'energia +Comment[ca@valencia]=Extensió d'accions de gestió d'energia +Comment[cs]=Rozšiřující akce správy napájení +Comment[da]=Udvidelse af strømstyringshandling +Comment[de]=Erweiterung für Energieverwaltungs-Aktionen +Comment[el]=Επέκταση ενεργών διαχείρισης ενέργειας +Comment[en_GB]=Power Management Action Extension +Comment[es]=Extensión de acción de gestión de energía +Comment[et]=Toitehalduse laiendus +Comment[eu]=Energia kudeatzeko ekintzen hedapena +Comment[fi]=Virranhallinnan toimintolaajennus +Comment[fr]=Extension des actions de gestion de l'énergie +Comment[gl]=Extensión de accións de xestión da enerxía +Comment[he]=Power Management Action Extension +Comment[hr]=Proširenje radnje za upravljanje potrošnjom energije +Comment[hu]=Energiakezelő-műveletek kiterjesztés +Comment[ia]=Extension de action de gestion de energia +Comment[is]=Orkustýringarbakendi +Comment[kk]=Қуаттандыруды басқару әрекетін кеңейтуі +Comment[km]=ផ្នែក​បន្ថែម​សកម្មភាព​គ្រប់គ្រង​ថាមពល +Comment[ko]=전원 관리 동작 확장 +Comment[lt]=Energijos valdymo veiksmų plėtinys +Comment[lv]=Energokontroles darbības papildinājums +Comment[mr]=वीज व्यवस्थापन क्रिया एक्सटेंशन +Comment[nb]=Handlingsutvidelse for strømstyring +Comment[nds]=Verwiedern för Stroomkuntrullakschonen +Comment[nl]=Uitbreiding voor energiebeheeractie +Comment[pa]=ਪਾਵਰ ਮੈਨਿਜਮੈਂਟ ਐਕਸ਼ਣ ਇਕਸਟੈਸ਼ਨ +Comment[pl]=Rozszerzenie do działań związanych z zarządzaniem energią +Comment[pt]=Extensão da Acção de Gestão da Energia +Comment[pt_BR]=Extensão da ação do gerenciamento de energia +Comment[ro]=Extensie pentru acțiunea de gestiune a alimentării +Comment[ru]=Расширение для комнаты управления питанием +Comment[sk]=Rozširujúce akcie správy napájania +Comment[sl]=Razširitev za dejanja za upravljanje z energijo +Comment[sr]=Проширење радњи за управљање напајањем +Comment[sr@ijekavian]=Проширење радњи за управљање напајањем +Comment[sr@ijekavianlatin]=Proširenje radnji za upravljanje napajanjem +Comment[sr@latin]=Proširenje radnji za upravljanje napajanjem +Comment[sv]=Åtgärdsutökning för strömsparhantering +Comment[th]=ส่วนขยายการกระทำเกี่ยวกับการจัดการพลังงาน +Comment[tr]=Güç Yönetimi Eylem Eklentisi +Comment[ug]=توك مەنبە باشقۇرۇش مەشغۇلات كېڭەيتىلمىسى +Comment[uk]=Розширення дій керування живленням +Comment[wa]=Sitindaedje des faitindjes do Manaedjmint di l' enerdjeye +Comment[x-test]=xxPower Management Action Extensionxx +Comment[zh_CN]=电源管理动作扩展 +Comment[zh_TW]=電源管理動作延伸 + +[PropertyDef::X-KDE-PowerDevil-Action-ID] +Type=QString +[PropertyDef::X-KDE-PowerDevil-Action-IsBundled] +Type=bool +[PropertyDef::X-KDE-PowerDevil-Action-RegistersDBusInterface] +Type=bool +[PropertyDef::X-KDE-PowerDevil-Action-ForceInstantLoad] +Type=bool +[PropertyDef::X-KDE-PowerDevil-Action-UIComponentLibrary] +Type=QString +[PropertyDef::X-KDE-PowerDevil-Action-ConfigPriority] +Type=int +[PropertyDef::X-KDE-PowerDevil-Action-HasRuntimeRequirement] +Type=bool diff --git a/powerdevil/daemon/backends/hal/halsuspendjob.cpp b/powerdevil/daemon/backends/hal/halsuspendjob.cpp new file mode 100644 index 00000000..d0b07ee2 --- /dev/null +++ b/powerdevil/daemon/backends/hal/halsuspendjob.cpp @@ -0,0 +1,136 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "halsuspendjob.h" + +#include +#include +#include +#include +#include + +HalSuspendJob::HalSuspendJob(QDBusInterface &powermanagement, QDBusInterface &computer, + PowerDevil::BackendInterface::SuspendMethod method, + PowerDevil::BackendInterface::SuspendMethods supported) + : KJob(), m_halPowerManagement(powermanagement), m_halComputer(computer) +{ + if (supported & method) + { + QDBusReply reply; + + switch(method) + { + case PowerDevil::BackendInterface::ToRam: + reply = m_halComputer.call("GetPropertyBoolean", "power_management.can_suspend_hybrid"); + + if (reply.isValid()) + { + bool can_hybrid = reply; + if (can_hybrid) + { + // Temporary: let's check if system is configured to use Hybrid suspend. Default is no. + KConfig sconf("suspendpreferencesrc"); + KConfigGroup group(&sconf, "Preferences"); + if (group.readEntry("use_hybrid", false)) { + m_dbusMethod = "SuspendHybrid"; + } else { + m_dbusMethod = "Suspend"; + } + } + else + { + m_dbusMethod = "Suspend"; + } + } + else + { + m_dbusMethod = "Suspend"; + } + m_dbusParam = 0; + break; + case PowerDevil::BackendInterface::ToDisk: + m_dbusMethod = "Hibernate"; + m_dbusParam = -1; + break; + default: + break; + } + } +} + +HalSuspendJob::~HalSuspendJob() +{ + +} + +void HalSuspendJob::start() +{ + QTimer::singleShot(0, this, SLOT(doStart())); +} + +void HalSuspendJob::kill(bool /*quietly */) +{ + +} + +void HalSuspendJob::doStart() +{ + if (m_dbusMethod.isEmpty()) + { + setError(1); + setErrorText("Unsupported suspend method"); + emitResult(); + return; + } + + QList args; + + if (m_dbusParam>=0) + { + args << m_dbusParam; + } + + if (!m_halPowerManagement.callWithCallback(m_dbusMethod, args, + this, SLOT(resumeDone(QDBusMessage)))) + { + setError(1); + setErrorText(m_halPowerManagement.lastError().name()+": " + +m_halPowerManagement.lastError().message()); + emitResult(); + } +} + + +void HalSuspendJob::resumeDone(const QDBusMessage &reply) +{ + if (reply.type() == QDBusMessage::ErrorMessage) + { + // We ignore the NoReply error, since we can timeout anyway + // if the computer is suspended for too long. + if (reply.errorName() != "org.freedesktop.DBus.Error.NoReply") + { + setError(1); + setErrorText(reply.errorName()+": "+reply.arguments().at(0).toString()); + } + } + + emitResult(); +} + +#include "halsuspendjob.moc" diff --git a/powerdevil/daemon/backends/hal/halsuspendjob.h b/powerdevil/daemon/backends/hal/halsuspendjob.h new file mode 100644 index 00000000..ba0bd7ff --- /dev/null +++ b/powerdevil/daemon/backends/hal/halsuspendjob.h @@ -0,0 +1,52 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef HALSUSPENDJOB_H +#define HALSUSPENDJOB_H + +#include +#include +#include + +#include "powerdevilhalbackend.h" + +class HalSuspendJob : public KJob +{ + Q_OBJECT +public: + HalSuspendJob(QDBusInterface &powermanagement, QDBusInterface &computer, + PowerDevil::BackendInterface::SuspendMethod method, + PowerDevil::BackendInterface::SuspendMethods supported); + virtual ~HalSuspendJob(); + + void start(); + void kill(bool quietly); + +private Q_SLOTS: + void doStart(); + void resumeDone(const QDBusMessage &reply); + +private: + QDBusInterface &m_halPowerManagement; + QDBusInterface &m_halComputer; + QString m_dbusMethod; + int m_dbusParam; +}; + +#endif diff --git a/powerdevil/daemon/backends/hal/powerdevilhalbackend.cpp b/powerdevil/daemon/backends/hal/powerdevilhalbackend.cpp new file mode 100644 index 00000000..726261d5 --- /dev/null +++ b/powerdevil/daemon/backends/hal/powerdevilhalbackend.cpp @@ -0,0 +1,519 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + Copyright (C) 2008-2010 Dario Freddi + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + + +#include "powerdevilhalbackend.h" +#include +#include +#include +#include +#include "halsuspendjob.h" +#include +#include +#include +#include +#include +#include +#include + +PowerDevilHALBackend::PowerDevilHALBackend(QObject* parent) + : BackendInterface(parent), + m_screenBrightnessInHardware(false), + m_halComputer("org.freedesktop.Hal", + "/org/freedesktop/Hal/devices/computer", + "org.freedesktop.Hal.Device", + QDBusConnection::systemBus()), + m_halPowerManagement("org.freedesktop.Hal", + "/org/freedesktop/Hal/devices/computer", + "org.freedesktop.Hal.Device.SystemPowerManagement", + QDBusConnection::systemBus()), + m_halCpuFreq("org.freedesktop.Hal", + "/org/freedesktop/Hal/devices/computer", + "org.freedesktop.Hal.Device.CPUFreq", + QDBusConnection::systemBus()), + m_halManager("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + QDBusConnection::systemBus()) +{ +} + +PowerDevilHALBackend::~PowerDevilHALBackend() +{ + qDeleteAll(m_acAdapters); + qDeleteAll(m_batteries); + qDeleteAll(m_buttons); +} + +bool PowerDevilHALBackend::isAvailable() +{ + return QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.Hal"); +} + +void PowerDevilHALBackend::init() +{ + setCapabilities(NoCapabilities); + + connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(QString)), + this, SLOT(slotDeviceRemoved(QString))); + connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(QString)), + this, SLOT(slotDeviceAdded(QString))); + + m_pluggedAdapterCount = 0; + computeAcAdapters(); + + computeBatteries(); + updateBatteryStats(); + + computeButtons(); + + // Brightness Control available + BrightnessControlsList controls; + { + QDBusPendingReply reply = m_halManager.asyncCall("FindDeviceByCapability", "laptop_panel"); + reply.waitForFinished(); + if (reply.isValid()) { + foreach(const QString &name, reply.value()) { + controls.insert(name, Screen); + } + } + reply = m_halManager.call("FindDeviceByCapability", "keyboard_backlight"); + if (reply.isValid()) { + foreach(const QString &name, reply.value()) { + controls.insert(name, Keyboard); + } + } + } + + QList screenControls = controls.keys(Screen); + + if (!screenControls.isEmpty()) { + m_cachedScreenBrightness = brightness(Screen); + + QDBusInterface deviceInterface("org.freedesktop.Hal", + screenControls.at(0), + "org.freedesktop.Hal.Device", + QDBusConnection::systemBus()); + QDBusReply replyInHardware = deviceInterface.call("GetPropertyBoolean", + "laptop_panel.brightness_in_hardware"); + if (replyInHardware.isValid()) { + m_screenBrightnessInHardware = replyInHardware; + } + } + + // Supported suspend methods + SuspendMethods supported = UnknownSuspendMethod; + { + QDBusPendingReply reply = m_halComputer.asyncCall("GetPropertyBoolean", "power_management.can_suspend"); + reply.waitForFinished(); + + if (reply.isValid()) { + bool can_suspend = reply; + if (can_suspend) { + supported |= ToRam; + } + } else { + kDebug() << reply.error().name() << ": " << reply.error().message(); + } + + reply = m_halComputer.asyncCall("GetPropertyBoolean", "power_management.can_hibernate"); + reply.waitForFinished(); + + if (reply.isValid()) { + bool can_hibernate = reply; + if (can_hibernate) { + supported |= ToDisk; + } + } else { + kDebug() << reply.error().name() << ": " << reply.error().message(); + } + } + + // Battery capacity + { + foreach (Solid::Device *d, m_batteries) { + Solid::GenericInterface *interface = d->as(); + + if (interface == 0) continue; + + if (interface->property("battery.reporting.design").toInt() > 0) { + uint capacity = ((float)(interface->property("battery.reporting.last_full").toInt()) / + (float)(interface->property("battery.reporting.design").toInt())) * 100; + + if (capacity > 0) { + setCapacityForBattery(d->udi(), capacity); + } else { + // Not supported, set capacity to 100% + setCapacityForBattery(d->udi(), 100); + } + } else { + // Not supported, set capacity to 100% + setCapacityForBattery(d->udi(), 100); + } + } + } + + setBackendIsReady(controls, supported); +} + +void PowerDevilHALBackend::brightnessKeyPressed(PowerDevil::BackendInterface::BrightnessKeyType type, BrightnessControlType controlType) +{ + BrightnessControlsList allControls = brightnessControlsAvailable(); + QList controls = allControls.keys(controlType); + + if (controls.isEmpty()) { + return; // ignore as we are not able to determine the brightness level + } + + if (type == Toggle && controlType == Screen) { + return; // ignore as we wont toggle the display off + } + + float currentBrightness = brightness(controlType); + + float cachedBrightness; + + if (controlType == Screen) { + cachedBrightness = m_cachedScreenBrightness; + } else { + cachedBrightness = m_cachedKeyboardBrightness; + } + + if (qFuzzyCompare(currentBrightness, cachedBrightness) && (!m_screenBrightnessInHardware || controlType == Screen)) { + float newBrightness; + if (type == Increase) { + newBrightness = qMin(100.0f, currentBrightness + 10); + } else if (type == Decrease) { + newBrightness = qMax(0.0f, currentBrightness - 10); + } else { // Toggle + newBrightness = currentBrightness > 0 ? 0 : 100; + } + + if (setBrightness(newBrightness, controlType)) { + newBrightness = brightness(controlType); + if (!qFuzzyCompare(newBrightness, cachedBrightness)) { + cachedBrightness = newBrightness; + onBrightnessChanged(controlType, cachedBrightness); + } + } + } else { + cachedBrightness = currentBrightness; + } + + if (controlType == Screen) { + m_cachedScreenBrightness = cachedBrightness; + } else { + m_cachedKeyboardBrightness = cachedBrightness; + } +} + +float PowerDevilHALBackend::brightness(PowerDevil::BackendInterface::BrightnessControlType type) const +{ + float brightness; + if (type == Screen) { + QDBusPendingReply reply = m_halManager.asyncCall("FindDeviceByCapability", "laptop_panel"); + reply.waitForFinished(); + if(reply.isValid()) { + foreach (const QString &device, reply.value()) { + QDBusInterface deviceInterface("org.freedesktop.Hal", device, + "org.freedesktop.Hal.Device.LaptopPanel", QDBusConnection::systemBus()); + QDBusReply brightnessReply = deviceInterface.call("GetBrightness"); + if(!brightnessReply.isValid()) { + return 0.0; + } + brightness = brightnessReply; + + QDBusInterface propertyInterface("org.freedesktop.Hal", device, + "org.freedesktop.Hal.Device", QDBusConnection::systemBus()); + QDBusReply levelsReply = propertyInterface.call("GetProperty", "laptop_panel.num_levels"); + if (levelsReply.isValid()) { + int levels = levelsReply; + return (float)(100*(brightness/(levels-1))); + } + } + } + } else { + QDBusPendingReply reply = m_halManager.asyncCall("FindDeviceByCapability", "keyboard_backlight"); + reply.waitForFinished(); + if(reply.isValid()) { + foreach (const QString &device, reply.value()) { + //TODO - I do not have a backlight enabled keyboard, so I'm guessing a bit here. Could someone please check this. + QDBusInterface deviceInterface("org.freedesktop.Hal", device, + "org.freedesktop.Hal.Device.KeyboardBacklight", QDBusConnection::systemBus()); + + QDBusReply brightnessReply = deviceInterface.call("GetBrightness"); + if (!brightnessReply.isValid()) { + return 0.0; + } + brightness = brightnessReply; + + QDBusInterface propertyInterface("org.freedesktop.Hal", device, + "org.freedesktop.Hal.Device", QDBusConnection::systemBus()); + QDBusReply levelsReply = propertyInterface.call("GetProperty", "keyboard_backlight.num_levels"); + if (levelsReply.isValid()) { + int levels = levelsReply; + return (float)(100*(brightness/(levels-1))); + } + } + } + } + return 0.0; +} + +bool PowerDevilHALBackend::setBrightness(float brightnessValue, PowerDevil::BackendInterface::BrightnessControlType type) +{ + if (type == Screen) { + QDBusPendingReply reply = m_halManager.asyncCall("FindDeviceByCapability", "laptop_panel"); + reply.waitForFinished(); + if(reply.isValid()) { + foreach (const QString &device, reply.value()) { + QDBusInterface propertyInterface("org.freedesktop.Hal", device, + "org.freedesktop.Hal.Device", QDBusConnection::systemBus()); + int levels = propertyInterface.call("GetProperty", "laptop_panel.num_levels").arguments().at(0).toInt(); + QDBusInterface deviceInterface("org.freedesktop.Hal", device, + "org.freedesktop.Hal.Device.LaptopPanel", QDBusConnection::systemBus()); + deviceInterface.call("SetBrightness", qRound((levels-1)*(brightnessValue/100.0))); // .0? The right way? Feels hackish. + if (!deviceInterface.lastError().isValid()) { + return true; + } + } + } + } else { + QDBusPendingReply reply = m_halManager.asyncCall("FindDeviceByCapability", "keyboard_backlight"); + reply.waitForFinished(); + if(reply.isValid()) { + foreach (const QString &device, reply.value()) { + QDBusInterface propertyInterface("org.freedesktop.Hal", device, + "org.freedesktop.Hal.Device", QDBusConnection::systemBus()); + int levels = propertyInterface.call("GetProperty", "keyboard_backlight.num_levels").arguments().at(0).toInt(); + //TODO - I do not have a backlight enabled keyboard, so I'm guessing a bit here. Could someone please check this. + QDBusInterface deviceInterface("org.freedesktop.Hal", device, + "org.freedesktop.Hal.Device.KeyboardBacklight", QDBusConnection::systemBus()); + + deviceInterface.call("SetBrightness", qRound((levels-1)*(brightnessValue/100.0))); + if(!deviceInterface.lastError().isValid()) { + return true; + } + } + } + } + return false; +} + +KJob* PowerDevilHALBackend::suspend(PowerDevil::BackendInterface::SuspendMethod method) +{ + // Ok, that's not cool, but it's all HAL really gives us, so. + QTimer::singleShot(0, this, SLOT(setResumeFromSuspend())); + return new HalSuspendJob(m_halPowerManagement, m_halComputer, + method, supportedSuspendMethods()); +} + +void PowerDevilHALBackend::computeAcAdapters() +{ + QList adapters + = Solid::Device::listFromType(Solid::DeviceInterface::AcAdapter); + + foreach (const Solid::Device &adapter, adapters) { + m_acAdapters[adapter.udi()] = new Solid::Device(adapter); + connect(m_acAdapters[adapter.udi()]->as(), SIGNAL(plugStateChanged(bool,QString)), + this, SLOT(slotPlugStateChanged(bool))); + + if (m_acAdapters[adapter.udi()]->as()!=0 + && m_acAdapters[adapter.udi()]->as()->isPlugged()) { + m_pluggedAdapterCount++; + } + } + + if (m_pluggedAdapterCount > 0) { + setAcAdapterState(Plugged); + } else { + setAcAdapterState(Unplugged); + } +} + +void PowerDevilHALBackend::computeBatteries() +{ + QList batteries + = Solid::Device::listFromQuery("Battery.type == 'PrimaryBattery'"); + + foreach (const Solid::Device &battery, batteries) { + m_batteries[battery.udi()] = new Solid::Device(battery); + connect(m_batteries[battery.udi()]->as(), SIGNAL(chargePercentChanged(int,QString)), + this, SLOT(updateBatteryStats())); + connect(m_batteries[battery.udi()]->as(), SIGNAL(propertyChanged(QMap)), + this, SLOT(slotBatteryPropertyChanged(QMap))); + } + + updateBatteryStats(); +} + +void PowerDevilHALBackend::computeButtons() +{ + QList buttons + = Solid::Device::listFromType(Solid::DeviceInterface::Button); + + foreach (const Solid::Device &button, buttons) { + m_buttons[button.udi()] = new Solid::Device(button); + connect(m_buttons[button.udi()]->as(), SIGNAL(pressed(Solid::Button::ButtonType,QString)), + this, SLOT(slotButtonPressed(Solid::Button::ButtonType))); + } +} + +void PowerDevilHALBackend::slotPlugStateChanged(bool newState) +{ + if (newState) { + if(m_pluggedAdapterCount == 0) { + setAcAdapterState(Plugged); + } + m_pluggedAdapterCount++; + } else { + if(m_pluggedAdapterCount == 1) { + setAcAdapterState(Unplugged); + } + m_pluggedAdapterCount--; + } +} + +void PowerDevilHALBackend::slotButtonPressed(Solid::Button::ButtonType type) +{ + Solid::Button *button = qobject_cast(sender()); + + if (button == 0) return; + + switch(type) { + case Solid::Button::PowerButton: + setButtonPressed(PowerButton); + break; + case Solid::Button::SleepButton: + setButtonPressed(SleepButton); + break; + case Solid::Button::LidButton: + if (button->stateValue()) { + setButtonPressed(LidClose); + } else { + setButtonPressed(LidOpen); + } + break; + default: + //kWarning() << "Unknown button type"; + break; + } +} + +void PowerDevilHALBackend::slotDeviceAdded(const QString &udi) +{ + Solid::Device *device = new Solid::Device(udi); + if (device->is()) { + m_acAdapters[udi] = device; + connect(m_acAdapters[udi]->as(), SIGNAL(plugStateChanged(bool,QString)), + this, SLOT(slotPlugStateChanged(bool))); + + if (m_acAdapters[udi]->as()!=0 + && m_acAdapters[udi]->as()->isPlugged()) { + m_pluggedAdapterCount++; + } + } else if (device->is()) { + m_batteries[udi] = device; + connect(m_batteries[udi]->as(), SIGNAL(chargePercentChanged(int,QString)), + this, SLOT(updateBatteryStats())); + connect(m_batteries[udi]->as(), SIGNAL(propertyChanged(QMap)), + this, SLOT(slotBatteryPropertyChanged(QMap))); + } else if (device->is()) { + m_buttons[udi] = device; + connect(m_buttons[udi]->as(), SIGNAL(pressed(int,QString)), + this, SLOT(slotButtonPressed(int))); + } else { + delete device; + } +} + +void PowerDevilHALBackend::slotDeviceRemoved(const QString &udi) +{ + Solid::Device *device = 0; + + device = m_acAdapters.take(udi); + + if (device != 0) { + delete device; + + m_pluggedAdapterCount = 0; + + foreach (Solid::Device *d, m_acAdapters) { + if (d->as()!=0 + && d->as()->isPlugged()) { + m_pluggedAdapterCount++; + } + } + + return; + } + + device = m_batteries.take(udi); + + if (device!=0) { + delete device; + updateBatteryStats(); + return; + } + + device = m_buttons.take(udi); + + if (device!=0) { + delete device; + return; + } +} + +void PowerDevilHALBackend::slotBatteryPropertyChanged(const QMap &changes) +{ + /* This slot catches property changes on battery devices. At + * the moment it is used to find out remaining time on batteries. + */ + + if (changes.contains("battery.remaining_time")) { + updateBatteryStats(); + + setBatteryRemainingTime(m_estimatedBatteryTime); + } +} + +void PowerDevilHALBackend::updateBatteryStats() +{ + m_currentBatteryCharge = 0; + m_maxBatteryCharge = 0; + m_lowBatteryCharge = 0; + m_criticalBatteryCharge = 0; + m_estimatedBatteryTime = 0; + + foreach (Solid::Device *d, m_batteries) { + Solid::GenericInterface *interface = d->as(); + + if (interface == 0) continue; + + m_currentBatteryCharge += interface->property("battery.charge_level.current").toInt(); + m_maxBatteryCharge += interface->property("battery.charge_level.last_full").toInt(); + m_lowBatteryCharge += interface->property("battery.charge_level.low").toInt(); + m_estimatedBatteryTime += interface->property("battery.remaining_time").toInt() * 1000; + } + + m_criticalBatteryCharge = m_lowBatteryCharge/2; +} + +#include "powerdevilhalbackend.moc" diff --git a/powerdevil/daemon/backends/hal/powerdevilhalbackend.desktop b/powerdevil/daemon/backends/hal/powerdevilhalbackend.desktop new file mode 100644 index 00000000..f249dc66 --- /dev/null +++ b/powerdevil/daemon/backends/hal/powerdevilhalbackend.desktop @@ -0,0 +1,115 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevilBackend +X-KDE-Library=powerdevilhalbackend +InitialPreference=100 +Icon=preferences-system-power-management +Name=HAL PowerDevil Backend +Name[ast]=HAL PowerDevil Backend +Name[bg]=Ядро HAL PowerDevil +Name[bs]=HAL kao pozadina Strujnog đavola +Name[ca]=Dorsal de HAL per al PowerDevil +Name[ca@valencia]=Dorsal de HAL per al PowerDevil +Name[cs]=Podpůrná vrstva HAL PowerDevil +Name[da]=HAL-motor til PowerDevil +Name[de]=HAL-PowerDevil-Backend +Name[el]=Σύστημα υποστήριξης HAL για το PowerDevil +Name[en_GB]=HAL PowerDevil Backend +Name[es]=Motor HAL para PowerDevil +Name[et]=HAL-i PowerDevili taustaprogramm +Name[eu]=PowerDevil-erako HAL bizkarraldekoa +Name[fi]=HAL PowerDevil-taustaosa +Name[fr]=Module HAL de PowerDevil +Name[ga]=Inneall HAL PowerDevil +Name[gl]=Infraestrutura de HAL do PowerDevil +Name[he]=מנגנון HAL PowerDevil +Name[hr]=HAL pozadinski servis za PowerDevil +Name[hu]=HAL Powerdevil-modul +Name[ia]=HAL PowerDevil Backend (retro-administration de PowerDevil de HAL) +Name[is]=HAL OrkuPúki +Name[ja]=HAL PowerDevil バックエンド +Name[kk]=HAL PowerDevil тетігі +Name[km]=កម្មវិធី​ខាងក្រោយ HAL PowerDevil +Name[kn]=HAL PowerDevil ಬ್ಯಾಕೆಂಡ್ +Name[ko]=HAL PowerDevil 백엔드 +Name[lt]=HAL PowerDevil programinė sąsaja +Name[lv]=HAL PowerDevil aizmugure +Name[mr]=HAL पॉवरडेव्हिल बॅकएन्ड +Name[nb]=HAL PowerDevil-motor +Name[nds]=Hülpprogramm för den HAL-Stroomdüvel +Name[nl]=Backend voor HAL PowerDevil +Name[pa]=HAL ਪਾਵਰ-ਡੀਵਿਲ ਬੈਕਐਂਡ +Name[pl]=Moduł HAL dla PowerDevil +Name[pt]=Infra-Estrutura de HAL para o PowerDevil +Name[pt_BR]=Infraestrutura de HAL para o PowerDevil +Name[ro]=Suport PowerDevil HAL +Name[ru]=Модуль поддержки HAL для PowerDevil +Name[sk]=Backend HAL PowerDevil +Name[sl]=Zaledje HAL za PowerDevil +Name[sr]=ХАЛ као позадина Струјног ђавола +Name[sr@ijekavian]=ХАЛ као позадина Струјног ђавола +Name[sr@ijekavianlatin]=HAL kao pozadina Strujnog đavola +Name[sr@latin]=HAL kao pozadina Strujnog đavola +Name[sv]=HAL Powerdevil-gränssnitt +Name[th]=โปรแกรมเบื้องหลัง HAL PowerDevil +Name[tr]=HAL PowerDevil Arkaucu +Name[ug]=HAL PowerDevil ئارقا ئۇچى +Name[uk]=Сервер PowerDevil HAL +Name[wa]=Bouye di fond HAL do Diâle d' Enerdjeye +Name[x-test]=xxHAL PowerDevil Backendxx +Name[zh_CN]=HAL PowerDevil 后端 +Name[zh_TW]=HAL PowerDevil 後端介面 +Comment=Use KDE Power Management system through freedesktop.org HAL daemon +Comment[ast]=Usar la xestión de enerxía del sistema KDE a traviés del degorriu HAL de freedesktop.org +Comment[bg]=Управление на захранването на KDE чрез демона HAL на freedesktop.org +Comment[bs]=KDE‑ov sistem za upravljanje napajanjem preko demona HAL‑a +Comment[ca]=Usa el sistema de gestió d'energia del KDE mitjançant el dimoni HAL del freedesktop.org +Comment[ca@valencia]=Usa el sistema de gestió d'energia del KDE mitjançant el dimoni HAL del freedesktop.org +Comment[cs]=Využít démon freedesktop.org HAL pro systém správy napájení KDE +Comment[da]=Brug KDE strømstyring via HAL-dæmonen fra freedesktop.org +Comment[de]=Das KDE-Energieverwaltungssystem mit Hilfe des HAL-Dienstes von freedesktop.org verwenden +Comment[el]=Διαχείριση ενέργειας ΚDE με χρήση του δαίμονα HAL του freedesktop.org +Comment[en_GB]=Use KDE Power Management system through freedesktop.org HAL dæmon +Comment[es]=Usar el sistema de gestión de energía de KDE mediante el demonio HAL de freedesktop.org +Comment[et]=KDE toitehalduse süsteemi kasutamine freedesktop.org-i HAL-deemoni abil +Comment[eu]=Erabili KDEren energia kudeatzeko sistema freedesktop.org-eko HAL daimonaren bidez +Comment[fi]=KDE:n virranhallintajärjestelmän käyttö freedesktop.org HAL-taustaprosessilla +Comment[fr]=Utiliser le système de gestion de l'énergie du matériel via le démon HAL de « freedesktop.org » +Comment[gl]=Usa o sistema de xestión enerxética de KDE mediante o daemon HAL de freedesktop.org +Comment[he]=שימוש במנהל צריכת החשמל של KDE דרך תהליך הרקע של freedesktop.org HAL +Comment[hr]=Koristi KDE-ovo upravljanje potrošnjom energije kroz servis freedesktop.org HAL +Comment[hu]=A KDE energiakezelő rendszerének használata a freedesktop.org HAL-démonán keresztül +Comment[ia]=Usa systema de gestion de energia de KDE usante demone HAL de freedesktop.org +Comment[is]=KDE-orkustilling vélbúnaðar með HAL púkanum frá freedesktop.org +Comment[ja]=freedesktop.org の HAL デーモンを介して KDE 電源管理を使用 +Comment[kk]=freedesktop.org HAL қызметі көмегімен KDE қуаттандыру жүйесін басқару +Comment[km]=ប្រើ​ប្រព័ន្ធ​គ្រប់គ្រង​ថាមពល​របស់ KDE តាមរយៈ​ដេមិន freedesktop.org HAL +Comment[kn]=freedesktop.org ನ HAL ನೇಪಥಿಕ (ಡೀಮನ್) ಬಳಸಿ KDE ವಿದ್ಯುಚ್ಛಕ್ತಿ ನಿರ್ವಹಣಾ ವ್ಯವಸ್ಥೆಯನ್ನು ಬಳಸಿ +Comment[ko]=freedesktop.org HAL 데몬을 사용하는 KDE 전원 관리 시스템 +Comment[lt]=Naudoti KDE energijos valdymo sistemą, naudojant freedesktop.org HAL tarnybą +Comment[lv]=Lietot KDE energokontroles sistēmu, izmantojot freedesktop.org HAL dēmonu +Comment[mr]=freedesktop.org HAL डीमनने केडीई वीज व्यवस्थापन वापरा +Comment[nb]=Bruk KDE strømstyringssystem med HAL-nissen fra freedesktop.org +Comment[nds]=Den HAL-Dämoon vun freedesktop.org för de KDE-Stroomkuntrull bruken +Comment[nl]=KDE energiebeheer gebruiken via de HAL-daemon van freedesktop.org +Comment[pa]=freedesktop.org HAL ਡੈਮਨ ਦੀ ਵਰਤੋਂ ਨਾਲ KDE ਪਾਵਰ ਮੈਨਿਜਮੈਂਟ ਸਿਸਟਮ +Comment[pl]=Zarządzanie zasilaniem za pomocą usługi HAL z freedesktop.org +Comment[pt]=Usar o sistema de gestão de energia do KDE através do servidor de HAL do freedesktop.org +Comment[pt_BR]=Usar o sistema de gerenciamento de energia do KDE através do daemon HAL do freedesktop.org +Comment[ro]=Folosește sistemul KDE de gestiune a alimentării prin intermediul demonului HAL de la freedesktop.org +Comment[ru]=Управление питанием с использованием службы HAL от freedesktop.org +Comment[sk]=Správa napájania KDE pomocou démona HAL z freedesktop.org +Comment[sl]=Uporaba KDE-jevega sistema za upravljanje z energijo prek ozadnjega programa HAL +Comment[sr]=КДЕ‑ов систем за управљање напајањем преко демона ХАЛ‑а +Comment[sr@ijekavian]=КДЕ‑ов систем за управљање напајањем преко демона ХАЛ‑а +Comment[sr@ijekavianlatin]=KDE‑ov sistem za upravljanje napajanjem preko demona HAL‑a +Comment[sr@latin]=KDE‑ov sistem za upravljanje napajanjem preko demona HAL‑a +Comment[sv]=Använd KDE:s strömsparhantering via HAL-demon från freedesktop.org +Comment[th]=ใช้ระบบจัดการพลังงานของ KDE โดยใช้ดีมอน HAL จาก freedesktop.org +Comment[tr]=KDE Güç Yönetim sisteminde freedesktop.org HAL servisini kullan +Comment[ug]=KDE توك مەنبە باشقۇرغۇچ سىستېمىسىدا freedesktop.org HAL نازارەتچىنى ئىشلەت +Comment[uk]=Використання системи керування живленням KDE за допомогою фонової служби HAL freedesktop.org +Comment[wa]=Eployî l' sistinme di manaedjmint di l' enerdjeye di KDE åd triviè do démon HAL di freedesktop.org +Comment[x-test]=xxUse KDE Power Management system through freedesktop.org HAL daemonxx +Comment[zh_CN]=用 freedesktop.org HAL 守护程序进行 KDE 电源管理 +Comment[zh_TW]=透過 freedesktop.org 的 HAL 伺服程式使用 KDE 電源管理系統 diff --git a/powerdevil/daemon/backends/hal/powerdevilhalbackend.h b/powerdevil/daemon/backends/hal/powerdevilhalbackend.h new file mode 100644 index 00000000..8f9769af --- /dev/null +++ b/powerdevil/daemon/backends/hal/powerdevilhalbackend.h @@ -0,0 +1,93 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + Copyright (C) 2008-2010 Dario Freddi + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef POWERDEVILHALBACKEND_H +#define POWERDEVILHALBACKEND_H + +#include + +#include +#include + +#include + +#include +#include +#include + +namespace Solid { +class Device; +} + + +class KDE_EXPORT PowerDevilHALBackend : public PowerDevil::BackendInterface +{ + Q_OBJECT + Q_DISABLE_COPY(PowerDevilHALBackend) +public: + explicit PowerDevilHALBackend(QObject* parent); + virtual ~PowerDevilHALBackend(); + + virtual void init(); + static bool isAvailable(); + + virtual float brightness(BrightnessControlType type = Screen) const; + + virtual void brightnessKeyPressed(PowerDevil::BackendInterface::BrightnessKeyType type, PowerDevil::BackendInterface::BrightnessControlType controlType = Screen); + virtual bool setBrightness(float brightness, PowerDevil::BackendInterface::BrightnessControlType type = Screen); + virtual KJob* suspend(PowerDevil::BackendInterface::SuspendMethod method); + +private: + void computeAcAdapters(); + void computeBatteries(); + void computeButtons(); + +private slots: + void updateBatteryStats(); + void slotPlugStateChanged(bool newState); + void slotButtonPressed(Solid::Button::ButtonType type); + void slotDeviceAdded(const QString &udi); + void slotDeviceRemoved(const QString &udi); + void slotBatteryPropertyChanged(const QMap &changes); + +private: + QMap m_acAdapters; + QMap m_batteries; + QMap m_buttons; + + int m_pluggedAdapterCount; + + int m_currentBatteryCharge; + int m_maxBatteryCharge; + int m_lowBatteryCharge; + int m_criticalBatteryCharge; + int m_estimatedBatteryTime; + + bool m_screenBrightnessInHardware; + float m_cachedScreenBrightness; + float m_cachedKeyboardBrightness; + + mutable QDBusInterface m_halComputer; + mutable QDBusInterface m_halPowerManagement; + mutable QDBusInterface m_halCpuFreq; + mutable QDBusInterface m_halManager; +}; + +#endif // POWERDEVILHALBACKEND_H diff --git a/powerdevil/daemon/backends/upower/backlight_helper_actions.actions b/powerdevil/daemon/backends/upower/backlight_helper_actions.actions new file mode 100644 index 00000000..e3586d07 --- /dev/null +++ b/powerdevil/daemon/backends/upower/backlight_helper_actions.actions @@ -0,0 +1,369 @@ +[Domain] +Name=KDE +Name[ar]=كدي +Name[bg]=KDE +Name[bs]=KDE +Name[ca]=KDE +Name[ca@valencia]=KDE +Name[cs]=KDE +Name[da]=KDE +Name[de]=KDE +Name[el]=KDE +Name[en_GB]=KDE +Name[es]=KDE +Name[et]=KDE +Name[eu]=KDE +Name[fa]=KDE +Name[fi]=KDE +Name[fr]=KDE +Name[ga]=KDE +Name[gl]=KDE +Name[gu]=KDE +Name[he]=KDE +Name[hi]=केडीई +Name[hr]=KDE +Name[hu]=KDE +Name[ia]=KDE +Name[is]=KDE +Name[ja]=KDE +Name[kk]=KDE +Name[km]=KDE +Name[kn]=KDE +Name[ko]=KDE +Name[lt]=KDE +Name[lv]=KDE +Name[mr]=केडीई +Name[nb]=KDE +Name[nds]=KDE +Name[nl]=KDE +Name[pa]=KDE +Name[pl]=KDE +Name[pt]=KDE +Name[pt_BR]=KDE +Name[ro]=KDE +Name[ru]=KDE +Name[sk]=KDE +Name[sl]=KDE +Name[sr]=КДЕ +Name[sr@ijekavian]=КДЕ +Name[sr@ijekavianlatin]=KDE +Name[sr@latin]=KDE +Name[sv]=KDE +Name[th]=KDE +Name[tr]=KDE +Name[ug]=ك د ئې(KDE) +Name[uk]=KDE +Name[vi]=KDE +Name[wa]=KDE +Name[x-test]=xxKDExx +Name[zh_CN]=KDE +Name[zh_TW]=KDE +Icon=kde + +[org.kde.powerdevil.backlighthelper.brightness] +Name=Get brightness +Name[bg]=Ниво на яркост +Name[bs]=Dobavi osvetljaj +Name[ca]=Lluminositat de la pantalla +Name[ca@valencia]=Lluminositat de la pantalla +Name[cs]=Získat jas +Name[da]=Hent lysstyrke +Name[de]=Bildschirmhelligkeit abrufen +Name[el]=Ανάκτηση λαμπρότητας +Name[en_GB]=Get brightness +Name[es]=Obtener brillo +Name[et]=Heleduse hankimine +Name[eu]=Eskuratu distira +Name[fi]=Lue kirkkaus +Name[fr]=Obtenir la luminosité +Name[ga]=Faigh an ghile +Name[gl]=Obter o brillo +Name[he]=קבלת ערך הבהירות +Name[hi]=चमक लाएँ +Name[hr]=Dohvati osvjetljenje +Name[hu]=Fényesség lekérdezése +Name[ia]=Obtene brillantia +Name[is]=Ná í upplýsingar um birtu skjás +Name[kk]=Жарықтығын білу +Name[km]=យក​ពន្លឺ +Name[kn]=ಪ್ರದರ್ಶಕದ ಹೊಳಪನ್ನು ತಿಳಿದುಕೊಳ್ಳಿ +Name[ko]=밝기 가져오기 +Name[lt]=Gauti šviesumą +Name[lv]=Iegūt gaišumu +Name[mr]=प्रखरता घ्या +Name[nb]=Hent lysstyrke +Name[nds]=Helligkeit afropen +Name[nl]=Helderheid verkrijgen +Name[pa]=ਚਮਕ ਲਵੋ +Name[pl]=Pobierz jasność +Name[pt]=Obter o brilho +Name[pt_BR]=Obter brilho +Name[ro]=Obține luminozitatea +Name[ru]=Настройка яркости +Name[sk]=Získať jas +Name[sl]=Dobi svetlost +Name[sr]=Добави осветљај +Name[sr@ijekavian]=Добави освјетљај +Name[sr@ijekavianlatin]=Dobavi osvjetljaj +Name[sr@latin]=Dobavi osvetljaj +Name[sv]=Hämta ljusstyrka +Name[th]=แสดงความสว่างของการแสดงผล +Name[tr]=Parlaklık bilgisi al +Name[ug]=يورۇقلۇققا ئېرىش +Name[uk]=Отримання рівня яскравості +Name[vi]=Lấy độ sáng +Name[wa]=Awè l' rilujhance +Name[x-test]=xxGet brightnessxx +Name[zh_CN]=获取亮度 +Name[zh_TW]=取得亮度 +Description=System policies prevent you from getting the brightness level. +Description[bg]=Системни правила забраняват показването на нивото на яркостта +Description[bs]=Sistemske smjernice sprečavaju dobavljanje postavki nivoa osvetljaja. +Description[ca]=Les polítiques del sistema impedeixen que conegueu el nivell de brillantor de la pantalla. +Description[ca@valencia]=Les polítiques del sistema impedeixen que conegueu el nivell de brillantor de la pantalla. +Description[cs]=Nastavení systému vám znemožňuje získat úroveň podsvícení. +Description[da]=Systempolitikker forhindrer dig i at hente lysstyrkeniveauet. +Description[de]=Die Stufe der Bildschirmhelligkeit kann aufgrund einer Systemrichtlinie nicht abgerufen werden. +Description[el]=Οι πολιτικές του συστήματος αποτρέπουν τη λήψη του επίπεδου λαμπρότητας. +Description[en_GB]=System policies prevent you from getting the brightness level. +Description[es]=Las políticas del sistema le impiden guardar el nivel de brillo. +Description[et]=Süsteemi reeglid takistavad heledustaseme hankimist. +Description[eu]=Sistemako gidalerroek distira-maila eskuratzea galarazten dizute. +Description[fi]=Järjestelmämenettelytavat estävät sinua saamasta kirkkauden tasoa selville. +Description[fr]=La stratégie système vous empêche d'obtenir le niveau de luminosité. +Description[ga]=Mar gheall ar pholasaí an chórais, níl cead agat an ghile a fháil. +Description[gl]=As políticas do sistema evitan que coñeza o nivel de brillo. +Description[he]=מדינויות מערכת מונעות קבלת ערך הבהירות. +Description[hr]=Pravila sustava vam onemogućuju dohvaćanje razine osvjetljenja. +Description[hu]=A rendszer házirendjei nem engedik meg Önnek a fényesség lekérdezését. +Description[ia]=Le politicas de systema preveni te ex obtener le nivello de brillantia. +Description[is]=Öryggisstillingar kerfisins koma í veg fyrir að þú getir náð í upplýsingar um birtustig. +Description[kk]=Жарықтық деңгейін білуді болдырмайтын жүйелік ережелері. +Description[km]=គោលនយោបាយ​ប្រព័ន្ធ​ ការពារ​អ្នក​​មិន​ឲ្យ​យក​កម្រិត​ពន្លឺ ។ +Description[kn]=ವ್ಯವಸ್ಥೆಯ ಕಾರ್ಯನೀತಿಯು ನಿಮ್ಮನ್ನು ಪ್ರದರ್ಶಕದ ಹೊಳಪನ್ನು ತಿಳಿದುಕೊಳ್ಳದಂತೆ ತಡೆಯುತ್ತಿದೆ. +Description[ko]=시스템 정책 때문에 밝기를 가져올 수 없습니다. +Description[lt]=Sistemos taisyklės neleidžia jums gauti šviesumo lygio. +Description[lv]=Sistēmas politikas jums neļauj iegūt gaišuma līmeni. +Description[mr]=प्रणाली धोरण प्रखरता पातळी घेण्यास प्रतिबंध करत आहे. +Description[nb]=Systembestemmelser gjør at du ikke kan hente lysstyrkenivået. +Description[nds]=De Systeemregeln verlöövt nich, dat Du de Instellen för de Helligkeit afröppst. +Description[nl]=Systeembeleid voorkwam dat u het helderheidsniveau kon verkrijgen. +Description[pa]=ਸਿਸਟਮ ਪਾਲਸੀ ਤੁਹਾਨੂੰ ਚਮਕ (brightness) ਲੈਵਲ ਲੈਣ ਤੋਂ ਰੋਕਦੀ ਹੈ। +Description[pl]=Polityka systemu nie pozwala Ci na pobranie poziomu jasności. +Description[pt]=As políticas do sistema proíbem a leitura do nível do brilho. +Description[pt_BR]=As políticas do sistema não permitem a modificação do nível de brilho. +Description[ro]=Politicile sistemului vă interzic obținerea nivelului de luminozitate. +Description[ru]=Правила безопасности запрещают вам узнавать уровень яркости. +Description[sk]=Systémové politiky vám zabránili získať úroveň jasu. +Description[sl]=Sistemski pravilniki vam onemogočajo, da bi prebrali svetlost. +Description[sr]=Системске смернице спречавају добављање поставки нивоа осветљаја. +Description[sr@ijekavian]=Системске смјернице спречавају добављање поставки нивоа освјетљаја. +Description[sr@ijekavianlatin]=Sistemske smjernice sprečavaju dobavljanje postavki nivoa osvjetljaja. +Description[sr@latin]=Sistemske smernice sprečavaju dobavljanje postavki nivoa osvetljaja. +Description[sv]=Systemets policy förhindrar att du hämtar ljusstyrkans nivå. +Description[th]=นโยบายของระบบเพื่อป้องกันการแสดงระดับความสว่าง +Description[tr]=Sistem politikaları parlaklık seviye bilgisini almanızı engelliyor +Description[ug]=سىستېما بىخەتەرلىك تەدبىرىڭىز يورۇقلۇق دەرىجىسىگە ئېرىشىشكە يول قويمايدۇ. +Description[uk]=Відповідно до загальносистемних правил, ви не можете отримувати даних щодо рівня яскравості. +Description[wa]=Les politikes do sistinme vos espaitchèt d' awè l' livea del rilujhance. +Description[x-test]=xxSystem policies prevent you from getting the brightness level.xx +Description[zh_CN]=系统安全策略不允许获取亮度级别。 +Description[zh_TW]=系統政策不允許您取得亮度設定。 +Policy=yes +PolicyInactive=yes + +[org.kde.powerdevil.backlighthelper.setbrightness] +Name=Set brightness +Name[bg]=Задаване на яркост +Name[bs]=Postavi osvetljaj +Name[ca]=Ajusta la lluminositat +Name[ca@valencia]=Ajusta la lluminositat +Name[cs]=Nastavit jas +Name[da]=Sæt lysstyrke +Name[de]=Bildschirmhelligkeit einstellen +Name[el]=Ρύθμιση λαμπρότητας +Name[en_GB]=Set brightness +Name[es]=Establecer brillo +Name[et]=Heleduse määramine +Name[eu]=Ezarri distira +Name[fi]=Aseta kirkkaus +Name[fr]=Fixer la luminosité +Name[ga]=Socraigh an ghile +Name[gl]=Axustar o brillo +Name[he]=קביעת הבהירות +Name[hi]=चमक लगाएँ +Name[hr]=Postavi osvjetljenje +Name[hu]=Fényesség beállítása +Name[ia]=Fixa brillantia +Name[is]=Setja birtustig +Name[ja]=明るさを設定 +Name[kk]=Жарықтығын орнату +Name[km]=កំណត់​ពន្លឺ +Name[kn]=ಪ್ರದರ್ಶಕದ ಹೊಳಪನ್ನು ಬದಲಾಯಿಸಿ +Name[ko]=밝기 설정하기 +Name[lt]=Nustatyti šviesumą +Name[lv]=Iestatīt gaišumu +Name[mr]=प्रखरता संयोजना +Name[nb]=Sett lysstyrke +Name[nds]=Helligkeit instellen +Name[nl]=Helderheid instellen +Name[pa]=ਚਮਕ ਸੈੱਟ ਕਰੋ +Name[pl]=Ustaw jasność +Name[pt]=Mudar o brilho +Name[pt_BR]=Definir o brilho +Name[ro]=Stabilește luminozitatea +Name[ru]=Настройка яркости +Name[sk]=Nastaviť jas +Name[sl]=Nastavi svetlost +Name[sr]=Постави осветљај +Name[sr@ijekavian]=Постави освјетљај +Name[sr@ijekavianlatin]=Postavi osvjetljaj +Name[sr@latin]=Postavi osvetljaj +Name[sv]=Ställ in ljusstyrka +Name[th]=ปรับความสว่างของการแสดงผล +Name[tr]=Parlaklığı ayarla +Name[ug]=يورۇقلۇق تەڭشىكى +Name[uk]=Встановлення рівня яскравості +Name[wa]=Defini l' rilujhance +Name[x-test]=xxSet brightnessxx +Name[zh_CN]=设置亮度 +Name[zh_TW]=設定亮度 +Description=System policies prevent you from setting the brightness level. +Description[bg]=Системни правила забраняват настройването на нивото на яркостта +Description[bs]=Sistemske smjernice sprečavaju postavljanje nivoa osvetljaja. +Description[ca]=Les polítiques del sistema impedeixen que ajusteu la lluminositat de la pantalla. +Description[ca@valencia]=Les polítiques del sistema impedeixen que ajusteu la lluminositat de la pantalla. +Description[cs]=Systémové omezení vám neumožňuje nastavit úroveň podsvícení. +Description[da]=Systempolitikker forhindrer dig i at sætte lysstyrkeniveauet. +Description[de]=Die Bildschirmhelligkeit kann aufgrund einer Systemrichtlinie nicht geändert werden. +Description[el]=Οι πολιτικές του συστήματος αποτρέπουν τον ορισμό του επίπεδου λαμπρότητας. +Description[en_GB]=System policies prevent you from setting the brightness level. +Description[es]=Las políticas del sistema le impiden establecer el nivel de brillo. +Description[et]=Süsteemi reeglid takistavad heleduse määramist. +Description[eu]=Sistemako gidalerroek distira-maila ezartzea galarazten dizute. +Description[fi]=Järjestelmämenettelytavat estävät sinua asettamasta kirkkauden tasoa. +Description[fr]=La stratégie système vous empêche de fixer le niveau de luminosité. +Description[ga]=Mar gheall ar pholasaí an chórais, níl cead agat an ghile a shocrú. +Description[gl]=As políticas do sistema evitan que modifique o nivel de brillo. +Description[he]=מדינויות מערכת מונעות קביעת ערך הבהירות. +Description[hr]=Pravila sustava vam onemogućuju postavljanje razine osvjetljenja. +Description[hu]=A rendszer házirendjei nem engedik meg Önnek a fényesség beállítását. +Description[ia]=Le politicas de systema preveni te ex fixar le nivello de brillantia. +Description[is]=Öryggisstillingar kerfisins koma í veg fyrir að þú getir breytt birtustigi. +Description[ja]=システムポリシーにより、明るさを設定することができません。 +Description[kk]=Жарықтық деңгейін орнатуды болдырмайтын жүйелік ережелері. +Description[km]=គោលនយោបាយ​ប្រព័ន្ធ​ការពារ​អ្នក​មិន​​ឲ្យ​កំណត់​កម្រិត​ពន្លឺ ។ +Description[kn]=ವ್ಯವಸ್ಥೆಯ ಕಾರ್ಯನೀತಿಯು ನಿಮ್ಮನ್ನು ಪ್ರದರ್ಶಕದ ಹೊಳಪನ್ನು ಬದಲಾಯಿಸದಂತೆ ತಡೆಯುತ್ತಿದೆ. +Description[ko]=시스템 정책 때문에 밝기를 지정할 수 없습니다. +Description[lt]=Sistemos taisyklės neleidžia jums nustatyti šviesumo lygio. +Description[lv]=Sistēmas politikas jums neļauj iestatīt gaišuma līmeni. +Description[mr]=प्रणाली धोरण प्रखरता पातळी संयोजीत करण्यास प्रतिबंध करत आहे. +Description[nb]=Systembestemmelser gjør at du ikke kan sette lysstyrkenivået. +Description[nds]=De Systeemregeln verlöövt nich, dat Du de Instellen för de Helligkeit instellst. +Description[nl]=Systeembeleid voorkwam dat u het helderheidsniveau kon instellen. +Description[pa]=ਸਿਸਟਮ ਪਾਲਸੀ, ਜੋ ਤੁਹਾਨੂੰ ਚਮਕ ਲੈਵਲ ਸੈੱਟ ਕਰਨ ਤੋਂ ਰੋਕਦੀ ਹੈ। +Description[pl]=Polityka systemu nie pozwala Ci na ustawienie jasności. +Description[pt]=As políticas do sistema proíbem a mudança do nível do brilho. +Description[pt_BR]=As políticas do sistema não permitem a modificação das configurações do nível de brilho. +Description[ro]=Politicile sistemului vă interzic stabilirea nivelului de luminozitate. +Description[ru]=Правила безопасности запрещают вам устанавливать уровень яркости. +Description[sk]=Systémové politiky vám zabránili nastaviť úroveň jasu. +Description[sl]=Sistemski pravilniki vam onemogočajo, da bi nastavili svetlost. +Description[sr]=Системске смернице спречавају постављање нивоа осветљаја. +Description[sr@ijekavian]=Системске смјернице спречавају постављање нивоа освјетљаја. +Description[sr@ijekavianlatin]=Sistemske smjernice sprečavaju postavljanje nivoa osvjetljaja. +Description[sr@latin]=Sistemske smernice sprečavaju postavljanje nivoa osvetljaja. +Description[sv]=Systemets policy förhindrar att du ställer in ljusstyrkans nivå. +Description[th]=นโยบายของระบบเพื่อป้องกันการตั้งระดับความสว่าง +Description[tr]=Sistem politikaları parlaklık seviyesini ayarlamanızı engelliyor +Description[ug]=سىستېما بىخەتەرلىك تەدبىرىڭىز يورۇقلۇق دەرىجىسىنى تەڭشىشىڭىزگە يول قويمايدۇ. +Description[uk]=Відповідно до загальносистемних правил, ви не можете встановлювати рівень яскравості. +Description[wa]=Les politikes do sistinme vos espaitchèt d' defini l' livea del rilujhance. +Description[x-test]=xxSystem policies prevent you from setting the brightness level.xx +Description[zh_CN]=系统安全策略不允许设置亮度级别。 +Description[zh_TW]=系統政策不允許您設定亮度。 +Policy=yes + +[org.kde.powerdevil.backlighthelper.syspath] +Name=Get syspath +Name[bs]=Dobavi sistemsku stazu +Name[ca]=Obtén el «syspath» +Name[ca@valencia]=Obtén el «syspath» +Name[cs]=Získat syspath +Name[da]=Hent syspath +Name[de]=„syspath“ holen +Name[el]=Λήψη syspath +Name[en_GB]=Get syspath +Name[es]=Obtener ruta del sistema +Name[et]=Süsteemse asukoha hankimine +Name[eu]="Syspath", Sistemaren bide-izenak, eskuratu +Name[fi]=Lue järjestelmäpolku +Name[fr]=Obtenir « syspath » +Name[gl]=Obter syspath +Name[hu]=Rendszerútvonal lekérése +Name[ia]=Obtene syspath +Name[kk]=Жүйелік жолды табу +Name[ko]=syspath 가져오기 +Name[lt]=Gauti syspath +Name[nb]=Hent syspath +Name[nds]=Syspadd halen +Name[nl]=Systeempad ophalen +Name[pa]=syspath ਲਵੋ +Name[pl]=Pobierz ścieżkę systemową +Name[pt]=Obter o 'syspath' +Name[pt_BR]=Obter o syspath +Name[ru]=Получение системного пути +Name[sk]=Získať systémovú cestu +Name[sl]=Dobi syspath +Name[sr]=Добави сис‑путању +Name[sr@ijekavian]=Добави сис‑путању +Name[sr@ijekavianlatin]=Dobavi sis‑putanju +Name[sr@latin]=Dobavi sis‑putanju +Name[sv]=Hämta systemsökväg +Name[tr]=Syspath'i al +Name[uk]=Отримання шляху у системі +Name[x-test]=xxGet syspathxx +Name[zh_CN]=获取 syspath +Name[zh_TW]=取得系統路徑 +Description=System policies prevent you from getting the syspath +Description[bs]=Sistemske smjernice sprečavaju dobavljanje sistemske staze. +Description[ca]=Les polítiques del sistema impedeixen que conegueu el camí del sistema «syspath» +Description[ca@valencia]=Les polítiques del sistema impedeixen que conegueu el camí del sistema «syspath» +Description[cs]=Nastavení systému vám znemožňuje získat syspath +Description[da]=Systempolitikker forhindrer dig i at hente syspath +Description[de]=Systemrichtlinien verhindern das Holen von „syspath“ +Description[el]=Οι πολιτικές του συστήματος αποτρέπουν τη λήψη του syspath +Description[en_GB]=System policies prevent you from getting the syspath +Description[es]=Las políticas del sistema le impiden obtener la ruta del sistema. +Description[et]=Süsteemi reeglid takistavad süsteemse asukoha hankimist +Description[eu]=Sistemaren gidalerroek syspath, sistemaren bide-izenak eskuratzea galarazten dizu. +Description[fi]=Järjestelmämenettelytavat estävät sinua saamasta järjestelmäpolkua selville. +Description[fr]=La stratégie système vous empêche d'obtenir « syspath ». +Description[gl]=As políticas do sistema evitan que coñeza syspath +Description[hu]=A rendszer házirendjei nem engedik meg Önnek a rendszerútvonal lekérdezését. +Description[ia]=Le politicas de systema preveni te ex obtener le syspath +Description[kk]=Жүйелік жолын білуді болдырмайтын жүйелік ережелері. +Description[ko]=시스템 정책 때문에 syspath를 가져올 수 없습니다. +Description[lt]=Sistemos taisyklės neleidžia jums gauti syspath +Description[nb]=Systembestemmelser gjør at du ikke kan hente syspath-en +Description[nds]=De Systeemregeln verlöövt nich, dat Du den Syspadd afröppst. +Description[nl]=Systeembeleid voorkwam dat u het systeempad kon ophalen +Description[pa]=ਸਿਸਟਮ ਪਾਲਸੀ ਤੁਹਾਨੂੰ syspath ਲੈਣ ਤੋਂ ਰੋਕਦੀ ਹੈ। +Description[pl]=Polityka systemu nie pozwala Ci na pobranie ścieżki systemowej +Description[pt]=As políticas de sistema impedem-no de obter o 'syspath' +Description[pt_BR]=As políticas do sistema não permitem a modificação do syspath +Description[ru]=Правила безопасности не позволяют вам получить системный путь. +Description[sk]=Systémové politiky vám zabránili získať systémovú cestu +Description[sl]=Sistemski pravilniki vam onemogočajo, da bi prebrali syspath. +Description[sr]=Системске смернице спречавају добављање сис‑путање. +Description[sr@ijekavian]=Системске смјернице спречавају добављање сис‑путање. +Description[sr@ijekavianlatin]=Sistemske smjernice sprečavaju dobavljanje sis‑putanje. +Description[sr@latin]=Sistemske smernice sprečavaju dobavljanje sis‑putanje. +Description[sv]=Systemets policy förhindrar att du hämtar systemsökvägen. +Description[tr]=Sistem politikaları syspath almanızı engelliyor +Description[uk]=Відповідно до загальносистемних правил, ви не можете отримувати даних щодо шляхів у системі +Description[x-test]=xxSystem policies prevent you from getting the syspathxx +Description[zh_CN]=系统安全策略不允许获取系统路径 +Description[zh_TW]=系統政策不允許您取得系統路徑 +Policy=yes +PolicyInactive=yes diff --git a/powerdevil/daemon/backends/upower/backlighthelper.cpp b/powerdevil/daemon/backends/upower/backlighthelper.cpp new file mode 100644 index 00000000..a94217ae --- /dev/null +++ b/powerdevil/daemon/backends/upower/backlighthelper.cpp @@ -0,0 +1,373 @@ +/* This file is part of the KDE project + * Copyright (C) 2010-2011 Lukas Tinkl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "backlighthelper.h" + +#include +#include + +#include + +#ifdef Q_OS_FREEBSD +#define USE_SYSCTL +#endif + +#ifdef USE_SYSCTL +#include +#include + +#define HAS_SYSCTL(n) (sysctlbyname(n, NULL, NULL, NULL, 0) == 0) +#endif + +#define PREFIX "/sys/class/backlight/" + +BacklightHelper::BacklightHelper(QObject * parent) + : QObject(parent), m_isSupported(false) +{ + init(); +} + +void BacklightHelper::init() +{ + + if (useWhitelistInit()) { + initUsingWhitelist(); + } else { + initUsingBacklightType(); + } + + if (m_dirname.isEmpty()) { + initUsingSysctl(); + + if (m_sysctlDevice.isEmpty() || m_sysctlBrightnessLevels.isEmpty()) { + qWarning() << "no kernel backlight interface found"; + return; + } + } + + m_isSupported = true; +} + +void BacklightHelper::initUsingBacklightType() +{ + QDir dir(PREFIX); + dir.setFilter(QDir::AllDirs | QDir::NoDot | QDir::NoDotDot | QDir::NoDotAndDotDot | QDir::Readable); + dir.setSorting(QDir::Name | QDir::Reversed);// Reverse is needed to priorize acpi_video1 over 0 + + QStringList interfaces = dir.entryList(); + + if (interfaces.isEmpty()) { + return; + } + + QFile file; + QByteArray buffer; + QStringList firmware, platform, raw; + + foreach(const QString & interface, interfaces) { + file.setFileName(PREFIX + interface + "/type"); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + continue; + } + + buffer = file.readLine().trimmed(); + if (buffer == "firmware") { + firmware.append(interface); + } else if(buffer == "platform") { + platform.append(interface); + } else if (buffer == "raw") { + raw.append(interface); + } else { + qWarning() << "Interface type not handled" << buffer; + } + + file.close(); + } + + if (!firmware.isEmpty()) { + m_dirname = PREFIX + firmware.first(); + return; + } + + if (!platform.isEmpty()) { + m_dirname = PREFIX + platform.first(); + return; + } + + if (!raw.isEmpty()) { + m_dirname = PREFIX + raw.first(); + return; + } +} + + +void BacklightHelper::initUsingWhitelist() +{ + QStringList interfaces; + interfaces << "nv_backlight" << "radeon_bl" << "mbp_backlight" << "asus_laptop" + << "toshiba" << "eeepc" << "thinkpad_screen" << "acpi_video1" << "acpi_video0" + << "intel_backlight" << "apple_backlight" << "fujitsu-laptop" << "samsung" + << "nvidia_backlight" << "dell_backlight" << "sony" << "pwm-backlight" + ; + + QDir dir; + foreach (const QString & interface, interfaces) { + dir.setPath(PREFIX + interface); + //qDebug() << "searching dir:" << dir; + if (dir.exists()) { + m_dirname = dir.path(); + //qDebug() << "kernel backlight support found in" << m_dirname; + break; + } + } + + //If none of our whitelisted interface is available, get the first one (if any) + if (m_dirname.isEmpty()) { + dir.setPath(PREFIX); + dir.setFilter(QDir::AllDirs | QDir::NoDot | QDir::NoDotDot | QDir::NoDotAndDotDot | QDir::Readable); + QStringList dirList = dir.entryList(); + if (!dirList.isEmpty()) { + m_dirname = dirList.first(); + } + } +} + +bool BacklightHelper::useWhitelistInit() +{ + struct utsname uts; + uname(&uts); + + int major, minor, patch, result; + result = sscanf(uts.release, "%d.%d", &major, &minor); + + if (result != 2) { + return true; // Malformed version + } + + if (major == 3) { + return false; //Kernel 3, we want type based init + } + + result = sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch); + + if (result != 3) { + return true; // Malformed version + } + + if (patch < 37) { + return true; //Minor than 2.6.37, use whiteList based + } + + return false;//Use Type based interafce +} + +void BacklightHelper::initUsingSysctl() +{ +#ifdef USE_SYSCTL + /* + * lcd0 is, in theory, the correct device, but some vendors have custom ACPI implementations + * which cannot be interpreted. In that case, devices should be reported as "out", but + * FreeBSD doesn't care (yet), so they can appear as any other type. Let's search for the first + * device with brightness management, then. + */ + QStringList types; + types << "lcd" << "out" << "crt" << "tv" << "ext"; + foreach (const QString &type, types) { + for (int i = 0; m_sysctlDevice.isEmpty(); i++) { + QString device = QString("%1%2").arg(type, QString::number(i)); + // We don't care about the value, we only want the sysctl to be there. + if (!HAS_SYSCTL(qPrintable(QString("hw.acpi.video.%1.active").arg(device)))) { + break; + } + if (HAS_SYSCTL(qPrintable(QString("hw.acpi.video.%1.brightness").arg(device))) && + HAS_SYSCTL(qPrintable(QString("hw.acpi.video.%1.levels").arg(device)))) { + m_sysctlDevice = device; + break; + } + } + } + + if (m_sysctlDevice.isEmpty()) { + return; + } + + size_t len; + if (sysctlbyname(qPrintable(QString("hw.acpi.video.%1.levels").arg(m_sysctlDevice)), NULL, &len, NULL, 0) != 0 || + len == 0) { + return; + } + int *levels = (int *)malloc(len); + if (!levels) { + return; + } + if (sysctlbyname(qPrintable(QString("hw.acpi.video.%1.levels").arg(m_sysctlDevice)), levels, &len, NULL, 0) != 0) { + free(levels); + return; + } + // acpi_video(4) supports only some predefined brightness levels. + int nlevels = len / sizeof(int); + for (int i = 0; i < nlevels; i++) { + m_sysctlBrightnessLevels << levels[i]; + } + free(levels); + // Sorting helps when finding max value and when scanning for the nearest level in setbrightness(). + qSort(m_sysctlBrightnessLevels.begin(), m_sysctlBrightnessLevels.end()); +#endif +} + +ActionReply BacklightHelper::brightness(const QVariantMap & args) +{ + Q_UNUSED(args); + + ActionReply reply; + + if (!m_isSupported) { + reply = ActionReply::HelperErrorReply; + return reply; + } + + // current brightness + int brightness; + +#ifdef USE_SYSCTL + size_t len = sizeof(int); + if (sysctlbyname(qPrintable(QString("hw.acpi.video.%1.brightness").arg(m_sysctlDevice)), &brightness, &len, NULL, 0) != 0) { + reply = ActionReply::HelperErrorReply; + return reply; + } +#else + QFile file(m_dirname + "/brightness"); + if (!file.open(QIODevice::ReadOnly)) { + reply = ActionReply::HelperErrorReply; + reply.setErrorCode(file.error()); + qWarning() << "reading brightness failed with error code " << file.error() << file.errorString(); + return reply; + } + + QTextStream stream(&file); + stream >> brightness; + file.close(); +#endif + + //qDebug() << "brightness:" << brightness; + reply.addData("brightness", brightness * 100 / maxBrightness()); + //qDebug() << "data contains:" << reply.data()["brightness"]; + + return reply; +} + +ActionReply BacklightHelper::setbrightness(const QVariantMap & args) +{ + ActionReply reply; + + if (!m_isSupported) { + reply = ActionReply::HelperErrorReply; + return reply; + } + + int actual_brightness = qRound(args["brightness"].toFloat() * maxBrightness() / 100); + //qDebug() << "setting brightness:" << actual_brightness; + +#ifdef USE_SYSCTL + int actual_level = -1; + int d1 = 101; + // Search for the nearest level. + foreach (int level, m_sysctlBrightnessLevels) { + int d2 = qAbs(level - actual_brightness); + /* + * The list is sorted, so we break when it starts diverging. There may be repeated values, + * so we keep going on equal gap (e.g., value = 7.5, levels = 0 0 10 ...: we don't break at + * the second '0' so we can get to the '10'). This also means that the value will always + * round off to the bigger level when in the middle (e.g., value = 5, levels = 0 10 ...: + * value rounds off to 10). + */ + if (d2 > d1) { + break; + } + actual_level = level; + d1 = d2; + } + size_t len = sizeof(int); + if (sysctlbyname(qPrintable(QString("hw.acpi.video.%1.brightness").arg(m_sysctlDevice)), NULL, NULL, &actual_level, len) != 0) { + reply = ActionReply::HelperErrorReply; + return reply; + } +#else + QFile file(m_dirname + "/brightness"); + if (!file.open(QIODevice::WriteOnly)) { + reply = ActionReply::HelperErrorReply; + reply.setErrorCode(file.error()); + qWarning() << "writing brightness failed with error code " << file.error() << file.errorString(); + return reply; + } + + int result = file.write(QByteArray::number(actual_brightness)); + file.close(); + + if (result == -1) { + reply = ActionReply::HelperErrorReply; + reply.setErrorCode(file.error()); + qWarning() << "writing brightness failed with error code " << file.error() << file.errorString(); + } +#endif + + return reply; +} + +ActionReply BacklightHelper::syspath(const QVariantMap& args) +{ + Q_UNUSED(args); + + ActionReply reply; + + if (!m_isSupported || m_dirname.isEmpty()) { + reply = ActionReply::HelperErrorReply; + return reply; + } + + reply.addData("syspath", m_dirname); + + return reply; +} + +int BacklightHelper::maxBrightness() const +{ + // maximum brightness + int max_brightness; + +#ifdef USE_SYSCTL + max_brightness = m_sysctlBrightnessLevels.last(); +#else + QFile file(m_dirname + "/max_brightness"); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "reading max brightness failed with error code " << file.error() << file.errorString(); + return -1; // some non-zero value + } + + QTextStream stream(&file); + stream >> max_brightness; + file.close(); +#endif + + //qDebug() << "max brightness:" << max_brightness; + + return max_brightness ? max_brightness : -1; +} + +KDE4_AUTH_HELPER_MAIN("org.kde.powerdevil.backlighthelper", BacklightHelper) diff --git a/powerdevil/daemon/backends/upower/backlighthelper.h b/powerdevil/daemon/backends/upower/backlighthelper.h new file mode 100644 index 00000000..5ab9298d --- /dev/null +++ b/powerdevil/daemon/backends/upower/backlighthelper.h @@ -0,0 +1,72 @@ +/* This file is part of the KDE project + * Copyright (C) 2010 Lukas Tinkl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef BACKLIGHTHELPER_H +#define BACKLIGHTHELPER_H + +#include +#include + +using namespace KAuth; + +class BacklightHelper: public QObject +{ + Q_OBJECT +public: + BacklightHelper(QObject * parent = 0); + +public slots: + ActionReply brightness(const QVariantMap & args); + ActionReply setbrightness(const QVariantMap & args); + ActionReply syspath(const QVariantMap & args); + +private: + void init(); + /** + * For older kernels that doesn't indicate which type the interface use we have + * a whitelsit based on the feedback given by our users, if the interface is not + * within our whitelist we will look for a random one within the backlight folder + */ + void initUsingWhitelist(); + + /** + * The kernel offer from version 2.6.37 the type of the interface, and based on that + * we can decide which interface is better for us, being the order + * firmware-platform-raw + */ + void initUsingBacklightType(); + + /** + * FreeBSD (and other BSDs) can control backlight via acpi_video(4) + */ + void initUsingSysctl(); + + /** + * If Kernel older than 2.6.37 use whitelsit, otherwise use backlight/type + * @see https://bugs.kde.org/show_bug.cgi?id=288180 + */ + bool useWhitelistInit(); + int maxBrightness() const; + bool m_isSupported; + QString m_dirname; + QString m_sysctlDevice; + QList m_sysctlBrightnessLevels; +}; + +#endif // BACKLIGHTHELPER_H diff --git a/powerdevil/daemon/backends/upower/dbus/com.ubuntu.Upstart.xml b/powerdevil/daemon/backends/upower/dbus/com.ubuntu.Upstart.xml new file mode 100644 index 00000000..dc7ae42d --- /dev/null +++ b/powerdevil/daemon/backends/upower/dbus/com.ubuntu.Upstart.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.Device.xml b/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.Device.xml new file mode 100644 index 00000000..3c408ee0 --- /dev/null +++ b/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.Device.xml @@ -0,0 +1,613 @@ + +]> + + + + + + Objects implementing this interface are usually discovered through + the org.freedesktop.UPower interface on + the /org/freedesktop/UPower object on + the D-Bus system bus service with the well-known + name org.freedesktop.UPower using + the + EnumerateDevices + method. + + + + +$ dbus-send --print-reply \ + --system \ + --dest=org.freedesktop.UPower \ + /org/freedesktop/UPower/devices/battery_BAT0 \ + org.freedesktop.DBus.Properties.GetAll \ + string:org.freedesktop.UPower.Device + +method return sender=:1.386 -> dest=:1.477 reply_serial=2 + array [ + dict entry( + string "native-path" + variant string "/sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/PNP0C0A:00/power_supply/BAT0" + ) + dict entry( + string "vendor" + variant string "SONY" + ) + dict entry( + string "model" + variant string "42T4568" + ) + dict entry( + string "serial" + variant string "4179" + ) + dict entry( + string "update-time" + variant uint64 1226417875 + ) + dict entry( + string "type" + variant uint 2 + ) + dict entry( + string "power-supply" + variant boolean true + ) + dict entry( + string "has-history" + variant boolean true + ) + dict entry( + string "has-statistics" + variant boolean true + ) + dict entry( + string "online" + variant boolean false + ) + dict entry( + string "energy" + variant double 72.85 + ) + dict entry( + string "energy-empty" + variant double 0 + ) + dict entry( + string "energy-full" + variant double 74.55 + ) + dict entry( + string "energy-full-design" + variant double 74.88 + ) + dict entry( + string "energy-rate" + variant double 0 + ) + dict entry( + string "voltage" + variant double 16.415 + ) + dict entry( + string "time-to-empty" + variant int64 0 + ) + dict entry( + string "time-to-full" + variant int64 0 + ) + dict entry( + string "percentage" + variant double 97.7197 + ) + dict entry( + string "is-present" + variant boolean true + ) + dict entry( + string "state" + variant uint 3 + ) + dict entry( + string "is-rechargeable" + variant boolean true + ) + dict entry( + string "capacity" + variant double 100 + ) + dict entry( + string "technology" + variant uint 1 + ) + ] + + + + + Unless otherwise noted, an empty string or the value 0 in a + property on this interface means not set. + + + + + + + + + + + + Refreshes the data collected from the power source. + + + Callers need the org.freedesktop.upower.refresh-power-source authorization + + if an error occured while refreshing + + + + + + + + + + Some value on the power source changed. + + + + + + + + + + + OS specific native path of the power source. On Linux this + is the sysfs path, for + example /sys/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT0. Is + blank if the device is being driven by a user space + driver. + + + + + + + + + + Name of the vendor of the battery. + + + + + + + + + + Name of the model of this battery. + + + + + + + + + + Unique serial number of the battery. + + + + + + + + + + The point in time (seconds since the Epoch Jan 1, 1970 + 0:00 UTC) that data was read from the power source. + + + + + + + + + + Type of power source. + + + + 0Unknown + + + 1Line Power + + + 2Battery + + + 3Ups + + + 4Monitor + + + 5Mouse + + + 6Keyboard + + + 7Pda + + + 8Phone + + + + + + + + + + + If the power device is used to supply the system. + This would be set TRUE for laptop batteries and UPS devices, + but set FALSE for wireless mice or PDAs. + + + + + + + + + + If the power device has history. + + + + + + + + + + If the power device has statistics. + + + + + + + + + + Whether power is currently being provided through line power. + This property is only valid if the property + type + has the value "line-power". + + + + + + + + + + Amount of energy (measured in Wh) currently available in + the power source. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Amount of energy (measured in Wh) in the power source when + it's considered to be empty. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Amount of energy (measured in Wh) in the power source when + it's considered full. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Amount of energy (measured in Wh) the power source is + designed to hold when it's considered full. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Amount of energy being drained from the source, measured + in W. If positive, the source is being discharged, if + negative it's being charged. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Voltage in the Cell or being recorded by the meter. + + + + + + + + + + Number of seconds until the power source is considered empty. + Is set to 0 if unknown. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Number of seconds until the power source is considered full. + Is set to 0 if unknown. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + The amount of energy left in the power source expressed as + a percentage between 0 and 100. Typically this is the same as + (energy - + energy-empty) / + (energy-full - + energy-empty). + However, some primitive power sources are capable of only + reporting percentages and in this case the energy-* + properties will be unset while this property is set. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + If the power source is present in the bay. + This field is required as some batteries are hot-removable, for example + expensive UPS and most laptop batteries. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + The battery power state. + + + + 0Unknown + + + 1Charging + + + 2Discharging + + + 3Empty + + + 4Fully charged + + + 5Pending charge + + + 6Pending discharge + + + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + If the power source is rechargeable. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + The capacity of the power source expressed as a percentage between 0 and 100. + The capacity of the battery will reduce with age. + A capacity value less than 75% is usually a sign that you should renew your battery. + Typically this value is the same as + (full-design / + full) * 100. + However, some primitive power sources are not capable reporting capacity + and in this case the capacity property will be unset. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Technology used in the battery: + + + + 0Unknown + + + 1Lithium ion + + + 2Lithium polymer + + + 3Lithium iron phosphate + + + 4Lead acid + + + 5Nickel cadmium + + + 6Nickel metal hydride + + + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + If the device may have been recalled by the vendor due to a suspected + fault. + This key does not imply the device is faulty, only that it approximatly + matches the description from the vendor of units that were recalled. + + + + + + + + + + The vendor that is handling the hardware recall. + + + This property is only valid if the property recall-notice is true. + + + + + + + + + + The URL to visit about the hardware recall. + + + This property is only valid if the property recall-notice is true. + + + + + + + + diff --git a/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.KbdBacklight.xml b/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.KbdBacklight.xml new file mode 100644 index 00000000..3ccc2113 --- /dev/null +++ b/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.KbdBacklight.xml @@ -0,0 +1,101 @@ + +]> + + + + + + org.freedesktop.UPower.KbdBacklight is a DBus interface implimented + by UPower. + It allows the keyboard backlight (if present) to be controlled. + + + + + + + + + + The maximum value of the keyboard backlight brightness. + + + + + + + Get the maximum brightness level for the keyboard backlight. + + + + if an error occured while getting the maximum brightness + + + + + + + + + + The current value of the keyboard backlight brightness. + + + + + + + Get the brightness level of the keyboard backlight. + + + + if an error occured while getting the brightness + + + + + + + + + + The value to set the KbdBacklight brightness. + + + + + + + Set the brightness level of the keyboard backlight. + + + + if an error occured while setting the brightness + + + + + + + + + + The new brightness value of the keyboard backlight. + + + + + + + The keyboard backlight brightness level has changed. + + + + + + + + diff --git a/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.xml b/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.xml new file mode 100644 index 00000000..807f4e6a --- /dev/null +++ b/powerdevil/daemon/backends/upower/dbus/org.freedesktop.UPower.xml @@ -0,0 +1,395 @@ + + + + + + + + The UPower service is available via the system message + bus. To access the service, use + the org.freedesktop.UPower interface on + the /org/freedesktop/UPower object on + the D-Bus system bus service with the well-known + name org.freedesktop.UPower. + + + + +$ dbus-send --print-reply \ + --system \ + --dest=org.freedesktop.UPower \ + /org/freedesktop/UPower \ + org.freedesktop.UPower.EnumerateDevices + +method return sender=:1.386 -> dest=:1.451 reply_serial=2 + array [ + object path "/org/freedesktop/UPower/devices/line_power_AC" + object path "/org/freedesktop/UPower/devices/battery_BAT0" + ] + + + + + + + + + + + + An array of object paths for devices. + + + + + + Enumerate all power objects on the system. + + + + + + + + + + Object path of device that was added. + + + + + + Emitted when a device is added. + + + + + + + + + + Object path of device that was removed. + + + + + + Emitted when a device is removed. + + + + + + + + + + Object path of device that was changed. + + + + + + Emitted when a device changed. + + + + + + + + + + + + Emitted when one or more properties on the object changes. + + + + + + + + + + + + This signal is sent when the session is about to be suspended or + hibernated. + + + This signal is DEPRECATED. Use NotifySleep() instead. + + + + + + + + + + + + This signal is sent when the session is about to be suspended or + hibernated. + Session and system programs have one second to do anything required + before the sleep action is taken (such as sending out Avahi or + Jabber messages). + + + + + + + The sleep action type, e.g. suspend, + hibernate or hybrid. + + + + + + + + + + + + This signal is sent when the session has just returned from + Suspend() or Hibernate(). + + + This signal is DEPRECATED. Use NotifyResume() instead. + + + + + + + + + + + + This signal is sent when the session has just returned from + Suspend() or Hibernate(). + Session and system programs can then do anything required (such as + sending out Avahi or Jabber messages). + + + + + + + The sleep action type, e.g. suspend, + hibernate or hybrid. + + + + + + + + + + + + + This method tells UPower that the Suspend() or Hibernate() method + is about to be called. + This allows UPower to emit the Suspending signal whilst + session activities are happening that have to be done before the + suspend process is started. + + + This method would typically be called by the session power + management daemon, before it locks the screen and waits for the + screen to fade to black. + The session power management component would then call Suspend() or + Hibernate() when these syncronous tasks have completed. + + + If this method is not called than nothing bad will happen and + Suspend() or Hibernate() will block for the required second. + + + + + + + The sleep action type, e.g. suspend or + hibernate. + + + + + + + + + + + + + Suspends the computer into a low power state. + System state is not preserved if the power is lost. + + + If AboutToRequestSleep() has not been called then UPower will send + the Sleeping() signal and block for one second. + + + If AboutToRequestSleep() has been called less than one second + before this method is called then UPower will block for the + remaining time to complete one second of delay. + + + + + + + + + + + TRUE if allowed, otherwise FALSE + + + + + Check if the caller has (or can get) the PolicyKit privilege to call + Suspend. + + + + + + + + + + + + + Hibernates the computer into a low power state. + System state is preserved if the power is lost. + + + If AboutToRequestSleep() has not been called then UPower will send + the Sleeping() signal and block for one second. + + + If AboutToRequestSleep() has been called less than one second + before this method is called then UPower will block for the + remaining time to complete one second of delay. + + + + + + + + + + + TRUE if allowed, otherwise FALSE + + + + + Check if the caller has (or can get) the PolicyKit privilege to call + Hibernate. + + + + + + + + + + Version of the running daemon, e.g. 002. + + + + + + Whether the system is able to suspend. + + + + + + Whether the system is able to hibernate. + + + + + + Indicates whether the system is running on battery power. + This property is provided for convenience. + + + + + + Indicates whether the system is running on battery power and if the battery is critically low. + This property is provided for convenience. + + + + + + + + Indicates if the laptop lid is closed where the display cannot be seen. + + + + + + + + + + If the system has a lid device. + + + + + + + + + + If the system really has to sleep when the lid is closed. + Some laptops actually melt (!) if the lid is closed and the + computer keeps running. We blacklist those, and do something + sane for the other machines. + + + This allows us to set the default session policy to not + suspend on lid close if the laptop is docked, and be sure + the machine is not going to melt. + + + + + + + + + + If the system is currently docked. + Note: the "is-docked" value is the result of a heuristic, + which may involve testing the display output. + + + + + + + + diff --git a/powerdevil/daemon/backends/upower/login1suspendjob.cpp b/powerdevil/daemon/backends/upower/login1suspendjob.cpp new file mode 100644 index 00000000..54371c8c --- /dev/null +++ b/powerdevil/daemon/backends/upower/login1suspendjob.cpp @@ -0,0 +1,107 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + Copyright (C) 2010 Alejandro Fiestas + Copyright (C) 2013 Lukáš Tinkl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "login1suspendjob.h" + +#include +#include +#include +#include +#include + +Login1SuspendJob::Login1SuspendJob(QDBusInterface *login1Interface, + PowerDevil::BackendInterface::SuspendMethod method, + PowerDevil::BackendInterface::SuspendMethods supported) + : KJob(), m_login1Interface(login1Interface) +{ + kDebug() << "Starting Login1 suspend job"; + m_method = method; + m_supported = supported; + + connect(m_login1Interface, SIGNAL(PrepareForSleep(bool)), this, SLOT(slotLogin1Resuming(bool))); +} + +Login1SuspendJob::~Login1SuspendJob() +{ + +} + +void Login1SuspendJob::start() +{ + QTimer::singleShot(0, this, SLOT(doStart())); +} + +void Login1SuspendJob::kill(bool /*quietly */) +{ + +} + +void Login1SuspendJob::doStart() +{ + if (m_supported & m_method) + { + QVariantList args; + args << true; // interactive, ie. with polkit dialogs + + QDBusPendingReply reply; + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(sendResult(QDBusPendingCallWatcher*))); + + switch(m_method) + { + case PowerDevil::BackendInterface::ToRam: + reply = m_login1Interface->asyncCallWithArgumentList("Suspend", args); + break; + case PowerDevil::BackendInterface::ToDisk: + reply = m_login1Interface->asyncCallWithArgumentList("Hibernate", args); + break; + case PowerDevil::BackendInterface::HybridSuspend: + reply = m_login1Interface->asyncCallWithArgumentList("HybridSleep", args); + break; + default: + kDebug() << "Unsupported suspend method"; + setError(1); + setErrorText(i18n("Unsupported suspend method")); + break; + } + } +} + +void Login1SuspendJob::sendResult(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply reply = *watcher; + if (!reply.isError()) { + emitResult(); + } else { + kWarning() << "Failed to start suspend job" << reply.error().name() << reply.error().message(); + } + + watcher->deleteLater(); +} + +void Login1SuspendJob::slotLogin1Resuming(bool active) +{ + if (!active) + emitResult(); +} + + +#include "login1suspendjob.moc" diff --git a/powerdevil/daemon/backends/upower/login1suspendjob.h b/powerdevil/daemon/backends/upower/login1suspendjob.h new file mode 100644 index 00000000..e1c2ff42 --- /dev/null +++ b/powerdevil/daemon/backends/upower/login1suspendjob.h @@ -0,0 +1,55 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + Copyright (C) 2010 Alejandro Fiestas + Copyright (C) 2013 Lukáš Tinkl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef LOGIN1SUSPENDJOB_H +#define LOGIN1SUSPENDJOB_H + +#include +#include +#include +#include + +#include "powerdevilbackendinterface.h" + +class Login1SuspendJob : public KJob +{ + Q_OBJECT +public: + Login1SuspendJob(QDBusInterface *login1Interface, + PowerDevil::BackendInterface::SuspendMethod method, + PowerDevil::BackendInterface::SuspendMethods supported); + virtual ~Login1SuspendJob(); + + void start(); + void kill(bool quietly); + +private Q_SLOTS: + void doStart(); + void sendResult(QDBusPendingCallWatcher* watcher); + void slotLogin1Resuming(bool active); + +private: + QDBusInterface *m_login1Interface; + PowerDevil::BackendInterface::SuspendMethod m_method; + PowerDevil::BackendInterface::SuspendMethods m_supported; +}; + +#endif //LOGIN1SUSPENDJOB_H diff --git a/powerdevil/daemon/backends/upower/powerdevilupowerbackend.cpp b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.cpp new file mode 100644 index 00000000..cc20dc73 --- /dev/null +++ b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.cpp @@ -0,0 +1,570 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + Copyright (C) 2008-2010 Dario Freddi + Copyright (C) 2010 Alejandro Fiestas + Copyright (C) 2010-2013 Lukáš Tinkl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "powerdevilupowerbackend.h" + +#include +#include + +#include +#include +#include + +#include "xrandrx11helper.h" +#include "xrandrbrightness.h" +#include "upowersuspendjob.h" +#include "login1suspendjob.h" +#include "upstart_interface.h" +#include "udevqt.h" + +#define HELPER_ID "org.kde.powerdevil.backlighthelper" + +bool checkSystemdVersion(uint requiredVersion) +{ + + QDBusInterface systemdIface("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", + QDBusConnection::systemBus(), 0); + + const QString reply = systemdIface.property("Version").toString(); + + QRegExp expsd("(systemd )?([0-9]+)"); + + if (expsd.exactMatch(reply)) { + const uint version = expsd.cap(2).toUInt(); + return (version >= requiredVersion); + } + + // Since version 1.11 Upstart user sessions implement the exact same API as logind + // and are going to the maintain the API in future releases. + // Hence, powerdevil can support this init system as well + // This has no effect on systemd integration since the check is done after systemd + ComUbuntuUpstart0_6Interface upstartInterface(QLatin1String("com.ubuntu.Upstart"), + QLatin1String("/com/ubuntu/Upstart"), + QDBusConnection::sessionBus()); + + QRegExp exp("(?:init \\()?upstart ([0-9.]+)(?:\\))?"); + if(exp.exactMatch(upstartInterface.version())) { + // Only keep the X.Y part of a X.Y.Z version + QStringList items = exp.cap(1).split('.').mid(0, 2); + const float upstartVersion = items.join(QString('.')).toFloat(); + return upstartVersion >= 1.1; + } + + kDebug() << "No appropriate systemd version or upstart version found"; + return false; +} + +PowerDevilUPowerBackend::PowerDevilUPowerBackend(QObject* parent) + : BackendInterface(parent), + m_brightnessControl(0), m_kbdMaxBrightness(0), + m_lidIsPresent(false), m_lidIsClosed(false), m_onBattery(false) +{ + +} + +PowerDevilUPowerBackend::~PowerDevilUPowerBackend() +{ + delete m_brightnessControl; +} + +bool PowerDevilUPowerBackend::isAvailable() +{ + if (!QDBusConnection::systemBus().interface()->isServiceRegistered(UPOWER_SERVICE)) { + // Is it pending activation? + kDebug() << "UPower service, " << UPOWER_SERVICE << ", is not registered on the bus. Trying to find out if it is activated."; + QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ListActivatableNames"); + + QDBusPendingReply< QStringList > reply = QDBusConnection::systemBus().asyncCall(message); + reply.waitForFinished(); + + if (reply.isValid()) { + if (reply.value().contains(UPOWER_SERVICE)) { + kDebug() << "UPower was found, activating service..."; + QDBusConnection::systemBus().interface()->startService(UPOWER_SERVICE); + if (!QDBusConnection::systemBus().interface()->isServiceRegistered(UPOWER_SERVICE)) { + // Wait for it + QEventLoop e; + QTimer *timer = new QTimer; + timer->setInterval(10000); + timer->setSingleShot(true); + + connect(QDBusConnection::systemBus().interface(), SIGNAL(serviceRegistered(QString)), + &e, SLOT(quit())); + connect(timer, SIGNAL(timeout()), &e, SLOT(quit())); + + timer->start(); + + while (!QDBusConnection::systemBus().interface()->isServiceRegistered(UPOWER_SERVICE)) { + e.exec(); + + if (!timer->isActive()) { + kDebug() << "Activation of UPower timed out. There is likely a problem with your configuration."; + timer->deleteLater(); + return false; + } + } + + timer->deleteLater(); + } + return true; + } else { + kDebug() << "UPower cannot be found on this system."; + return false; + } + } else { + kWarning() << "Could not request activatable names to DBus!"; + return false; + } + } else { + return true; + } +} + +void PowerDevilUPowerBackend::init() +{ + // interfaces + if (!QDBusConnection::systemBus().interface()->isServiceRegistered(LOGIN1_SERVICE)) { + // Activate it. + QDBusConnection::systemBus().interface()->startService(LOGIN1_SERVICE); + } + + if (!QDBusConnection::systemBus().interface()->isServiceRegistered(UPOWER_SERVICE)) { + // Activate it. + QDBusConnection::systemBus().interface()->startService(UPOWER_SERVICE); + } + + if (QDBusConnection::systemBus().interface()->isServiceRegistered(LOGIN1_SERVICE)) { + m_login1Interface = new QDBusInterface(LOGIN1_SERVICE, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus(), this); + } + + bool screenBrightnessAvailable = false; + m_upowerInterface = new OrgFreedesktopUPowerInterface(UPOWER_SERVICE, "/org/freedesktop/UPower", QDBusConnection::systemBus(), this); + m_brightnessControl = new XRandrBrightness(); + if (!m_brightnessControl->isSupported()) { + kDebug() << "Using helper"; + KAuth::Action action("org.kde.powerdevil.backlighthelper.syspath"); + action.setHelperID(HELPER_ID); + KAuth::ActionReply reply = action.execute(); + if (reply.succeeded()) { + m_syspath = reply.data()["syspath"].toString(); + m_syspath = QFileInfo(m_syspath).readLink(); + + UdevQt::Client *client = new UdevQt::Client(QStringList("backlight"), this); + connect(client, SIGNAL(deviceChanged(UdevQt::Device)), SLOT(onDeviceChanged(UdevQt::Device))); + screenBrightnessAvailable = true; + } + } else { + kDebug() << "Using XRandR"; + m_randrHelper = new XRandRX11Helper(); + connect(m_randrHelper, SIGNAL(brightnessChanged()), this, SLOT(slotScreenBrightnessChanged())); + screenBrightnessAvailable = true; + } + + // Capabilities + setCapabilities(SignalResumeFromSuspend); + + // devices + enumerateDevices(); + + connect(m_upowerInterface, SIGNAL(Changed()), this, SLOT(slotPropertyChanged())); + // for UPower >= 0.99.0, missing Changed() signal + QDBusConnection::systemBus().connect(UPOWER_SERVICE, UPOWER_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, + SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))); + + connect(m_upowerInterface, SIGNAL(DeviceAdded(QString)), this, SLOT(slotDeviceAdded(QString))); + connect(m_upowerInterface, SIGNAL(DeviceRemoved(QString)), this, SLOT(slotDeviceRemoved(QString))); + // for UPower >= 0.99.0, changed signature :o/ + QDBusConnection::systemBus().connect(UPOWER_SERVICE, UPOWER_PATH, UPOWER_IFACE, "DeviceAdded", + this, SLOT(slotDeviceAdded(QDBusObjectPath))); + QDBusConnection::systemBus().connect(UPOWER_SERVICE, UPOWER_PATH, UPOWER_IFACE, "DeviceRemoved", + this, SLOT(slotDeviceRemoved(QDBusObjectPath))); + + connect(m_upowerInterface, SIGNAL(DeviceChanged(QString)), this, SLOT(slotDeviceChanged(QString))); + // for UPower >= 0.99.0, see slotDeviceAdded(const QString & device) + + // Brightness Controls available + BrightnessControlsList controls; + if (screenBrightnessAvailable) { + controls.insert(QLatin1String("LVDS1"), Screen); + m_cachedBrightnessMap.insert(Screen, brightness(Screen)); + kDebug() << "current screen brightness: " << m_cachedBrightnessMap.value(Screen); + } + + m_kbdBacklight = new OrgFreedesktopUPowerKbdBacklightInterface(UPOWER_SERVICE, "/org/freedesktop/UPower/KbdBacklight", QDBusConnection::systemBus(), this); + if (m_kbdBacklight->isValid()) { + // Cache max value + QDBusPendingReply rep = m_kbdBacklight->GetMaxBrightness(); + rep.waitForFinished(); + if (rep.isValid()) { + m_kbdMaxBrightness = rep.value(); + } + // TODO Do a proper check if the kbd backlight dbus object exists. But that should work for now .. + if (m_kbdMaxBrightness) { + controls.insert(QLatin1String("KBD"), Keyboard); + m_cachedBrightnessMap.insert(Keyboard, brightness(Keyboard)); + kDebug() << "current keyboard backlight brightness: " << m_cachedBrightnessMap.value(Keyboard); + connect(m_kbdBacklight, SIGNAL(BrightnessChanged(int)), this, SLOT(onKeyboardBrightnessChanged(int))); + } + } + + // Supported suspend methods + SuspendMethods supported = UnknownSuspendMethod; + if (m_login1Interface && checkSystemdVersion(195)) { + QDBusPendingReply canSuspend = m_login1Interface.data()->asyncCall("CanSuspend"); + canSuspend.waitForFinished(); + if (canSuspend.isValid() && (canSuspend.value() == "yes" || canSuspend.value() == "challenge")) + supported |= ToRam; + + QDBusPendingReply canHibernate = m_login1Interface.data()->asyncCall("CanHibernate"); + canHibernate.waitForFinished(); + if (canHibernate.isValid() && (canHibernate.value() == "yes" || canHibernate.value() == "challenge")) + supported |= ToDisk; + + QDBusPendingReply canHybridSleep = m_login1Interface.data()->asyncCall("CanHybridSleep"); + canHybridSleep.waitForFinished(); + if (canHybridSleep.isValid() && (canHybridSleep.value() == "yes" || canHybridSleep.value() == "challenge")) + supported |= HybridSuspend; + } else { + if (m_upowerInterface->canSuspend() && m_upowerInterface->SuspendAllowed()) { + kDebug() << "Can suspend"; + supported |= ToRam; + } + + if (m_upowerInterface->canHibernate() && m_upowerInterface->HibernateAllowed()) { + kDebug() << "Can hibernate"; + supported |= ToDisk; + } + } + + // "resuming" signal + if (m_login1Interface && checkSystemdVersion(198)) { + connect(m_login1Interface.data(), SIGNAL(PrepareForSleep(bool)), this, SLOT(slotLogin1Resuming(bool))); + } else { + connect(m_upowerInterface, SIGNAL(Resuming()), this, SIGNAL(resumeFromSuspend())); + } + + // battery + QList recallList; + foreach(OrgFreedesktopUPowerDeviceInterface * upowerDevice, m_devices) { + if (upowerDevice->type() == 2 && upowerDevice->powerSupply()) { + QString udi = upowerDevice->path(); + setCapacityForBattery(udi, qRound(upowerDevice->capacity())); // acknowledge capacity + + if (upowerDevice->recallNotice()) { // check for recall notices + RecallNotice notice; + notice.batteryId = udi; + notice.url = upowerDevice->recallUrl(); + notice.vendor = upowerDevice->recallVendor(); + + recallList.append(notice); + } + } + } + if (!recallList.isEmpty()) + setRecallNotices(recallList); + + // backend ready + setBackendIsReady(controls, supported); +} + +void PowerDevilUPowerBackend::onDeviceChanged(const UdevQt::Device &device) +{ + kDebug() << "Udev device changed" << m_syspath << device.sysfsPath(); + if (device.sysfsPath() != m_syspath) { + return; + } + + int maxBrightness = device.sysfsProperty("max_brightness").toInt(); + if (maxBrightness <= 0) { + return; + } + float newBrightness = device.sysfsProperty("brightness").toInt() * 100 / maxBrightness; + + if (!qFuzzyCompare(newBrightness, m_cachedBrightnessMap[Screen])) { + m_cachedBrightnessMap[Screen] = newBrightness; + onBrightnessChanged(Screen, m_cachedBrightnessMap[Screen]); + } +} + +void PowerDevilUPowerBackend::brightnessKeyPressed(PowerDevil::BackendInterface::BrightnessKeyType type, BrightnessControlType controlType) +{ + BrightnessControlsList allControls = brightnessControlsAvailable(); + QList controls = allControls.keys(controlType); + + if (controls.isEmpty()) { + return; // ignore as we are not able to determine the brightness level + } + + if (type == Toggle && controlType == Screen) { + return; // ignore as we wont toggle the screen off + } + + float currentBrightness = brightness(controlType); + + int step = 10; + if (controlType == Keyboard) { + // In case the keyboard backlight has only 5 or less possible values, + // 10% are not enough to hit the next value. Lets use 30% because + // that jumps exactly one value for 2, 3, 4 and 5 possible steps + // when rounded. + if (m_kbdMaxBrightness < 6) { + step = 30; + } + } + + if (qFuzzyCompare(currentBrightness, m_cachedBrightnessMap.value(controlType))) { + float newBrightness; + if (type == Increase) { + newBrightness = qMin(100.0f, currentBrightness + step); + } else if (type == Decrease) { + newBrightness = qMax(0.0f, currentBrightness - step); + } else { // Toggle On/off + newBrightness = currentBrightness > 0 ? 0 : 100; + } + + setBrightness(newBrightness, controlType); + } else { + m_cachedBrightnessMap[controlType] = currentBrightness; + } +} + +float PowerDevilUPowerBackend::brightness(PowerDevil::BackendInterface::BrightnessControlType type) const +{ + float result = 0.0; + + if (type == Screen) { + if (m_brightnessControl->isSupported()) { + //kDebug() << "Calling xrandr brightness"; + result = m_brightnessControl->brightness(); + } else { + //kDebug() << "Falling back to helper to get brightness"; + KAuth::Action action("org.kde.powerdevil.backlighthelper.brightness"); + action.setHelperID(HELPER_ID); + KAuth::ActionReply reply = action.execute(); + if (reply.succeeded()) { + result = reply.data()["brightness"].toFloat(); + //kDebug() << "org.kde.powerdevil.backlighthelper.brightness succeeded: " << reply.data()["brightness"]; + } + else + kWarning() << "org.kde.powerdevil.backlighthelper.brightness failed"; + + } + kDebug() << "Screen brightness: " << result; + } else if (type == Keyboard) { + kDebug() << "Kbd backlight brightness: " << m_kbdBacklight->GetBrightness(); + result = 1.0 * m_kbdBacklight->GetBrightness() / m_kbdMaxBrightness * 100; + } + + return result; +} + +bool PowerDevilUPowerBackend::setBrightness(float brightnessValue, PowerDevil::BackendInterface::BrightnessControlType type) +{ + bool success = false; + if (type == Screen) { + kDebug() << "set screen brightness: " << brightnessValue; + if (m_brightnessControl->isSupported()) { + m_brightnessControl->setBrightness(brightnessValue); + } else { + //kDebug() << "Falling back to helper to set brightness"; + KAuth::Action action("org.kde.powerdevil.backlighthelper.setbrightness"); + action.setHelperID(HELPER_ID); + action.addArgument("brightness", brightnessValue); + KAuth::ActionReply reply = action.execute(); + if (reply.failed()) { + kWarning() << "org.kde.powerdevil.backlighthelper.setbrightness failed"; + return false; + } + } + + success = true; + } else if (type == Keyboard) { + kDebug() << "set kbd backlight: " << brightnessValue; + m_kbdBacklight->SetBrightness(qRound(brightnessValue / 100 * m_kbdMaxBrightness)); + success = true; + } + + return success; +} + +void PowerDevilUPowerBackend::slotScreenBrightnessChanged() +{ + float newBrightness = brightness(Screen); + kDebug() << "Brightness changed!!"; + if (!qFuzzyCompare(newBrightness, m_cachedBrightnessMap[Screen])) { + m_cachedBrightnessMap[Screen] = newBrightness; + onBrightnessChanged(Screen, m_cachedBrightnessMap[Screen]); + } +} + +void PowerDevilUPowerBackend::onKeyboardBrightnessChanged(int value) +{ + kDebug() << "Keyboard brightness changed!!"; + float realValue = 1.0 * value / m_kbdMaxBrightness * 100; + if (!qFuzzyCompare(realValue, m_cachedBrightnessMap[Keyboard])) { + m_cachedBrightnessMap[Keyboard] = realValue; + onBrightnessChanged(Keyboard, m_cachedBrightnessMap[Keyboard]); + } +} + +KJob* PowerDevilUPowerBackend::suspend(PowerDevil::BackendInterface::SuspendMethod method) +{ + if (m_login1Interface && checkSystemdVersion(195)) { + return new Login1SuspendJob(m_login1Interface.data(), method, supportedSuspendMethods()); + } else { + return new UPowerSuspendJob(m_upowerInterface, method, supportedSuspendMethods()); + } +} + +void PowerDevilUPowerBackend::enumerateDevices() +{ + m_lidIsPresent = m_upowerInterface->lidIsPresent(); + m_lidIsClosed = m_upowerInterface->lidIsClosed(); + m_onBattery = m_upowerInterface->onBattery(); + + QList deviceList = m_upowerInterface->EnumerateDevices(); + foreach (const QDBusObjectPath & device, deviceList) { + OrgFreedesktopUPowerDeviceInterface * upowerDevice = + new OrgFreedesktopUPowerDeviceInterface(UPOWER_SERVICE, device.path(), QDBusConnection::systemBus(), this); + m_devices.insert(device.path(), upowerDevice); + } + + updateDeviceProps(); + + if (m_onBattery) + setAcAdapterState(Unplugged); + else + setAcAdapterState(Plugged); +} + +void PowerDevilUPowerBackend::slotDeviceAdded(const QString & device) +{ + OrgFreedesktopUPowerDeviceInterface * upowerDevice = + new OrgFreedesktopUPowerDeviceInterface(UPOWER_SERVICE, device, QDBusConnection::systemBus(), this); + m_devices.insert(device, upowerDevice); + + // for UPower >= 0.99.0 which doesn't emit the DeviceChanged(QString) signal + QDBusConnection::systemBus().connect(UPOWER_SERVICE, device, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, + SLOT(onDevicePropertiesChanged(QString,QVariantMap,QStringList))); + + updateDeviceProps(); +} + +void PowerDevilUPowerBackend::slotDeviceRemoved(const QString & device) +{ + OrgFreedesktopUPowerDeviceInterface * upowerDevice = m_devices.take(device); + + delete upowerDevice; + + updateDeviceProps(); +} + +void PowerDevilUPowerBackend::slotDeviceAdded(const QDBusObjectPath &path) +{ + slotDeviceAdded(path.path()); +} + +void PowerDevilUPowerBackend::slotDeviceRemoved(const QDBusObjectPath &path) +{ + slotDeviceRemoved(path.path()); +} + +void PowerDevilUPowerBackend::slotDeviceChanged(const QString & /*device*/) +{ + updateDeviceProps(); +} + +void PowerDevilUPowerBackend::updateDeviceProps() +{ + qlonglong remainingTime = 0; + + foreach(OrgFreedesktopUPowerDeviceInterface * upowerDevice, m_devices) { + const uint type = upowerDevice->type(); + if (( type == 2 || type == 3) && upowerDevice->powerSupply()) { + const uint state = upowerDevice->state(); + if (state == 1) // charging + remainingTime += upowerDevice->timeToFull(); + else if (state == 2) //discharging + remainingTime += upowerDevice->timeToEmpty(); + } + } + + setBatteryRemainingTime(remainingTime * 1000); +} + +void PowerDevilUPowerBackend::slotPropertyChanged() +{ + // check for lid button changes + if (m_lidIsPresent) { + const bool lidIsClosed = m_upowerInterface->lidIsClosed(); + if (lidIsClosed != m_lidIsClosed) { + if (lidIsClosed) + setButtonPressed(LidClose); + else + setButtonPressed(LidOpen); + } + m_lidIsClosed = lidIsClosed; + } + + // check for AC adapter changes + const bool onBattery = m_upowerInterface->onBattery(); + if (m_onBattery != onBattery) { + if (onBattery) + setAcAdapterState(Unplugged); + else + setAcAdapterState(Plugged); + } + + m_onBattery = onBattery; +} + +void PowerDevilUPowerBackend::onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps) +{ + Q_UNUSED(changedProps); + Q_UNUSED(invalidatedProps); + + if (ifaceName == UPOWER_IFACE) { + slotPropertyChanged(); // TODO maybe process the 2 properties separately? + } +} + +void PowerDevilUPowerBackend::onDevicePropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps) +{ + Q_UNUSED(changedProps); + Q_UNUSED(invalidatedProps); + + if (ifaceName == UPOWER_IFACE_DEVICE) { + updateDeviceProps(); // TODO maybe process the properties separately? + } +} + +void PowerDevilUPowerBackend::slotLogin1Resuming(bool active) +{ + if (!active) { + emit resumeFromSuspend(); + } +} + +#include "powerdevilupowerbackend.moc" diff --git a/powerdevil/daemon/backends/upower/powerdevilupowerbackend.desktop b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.desktop new file mode 100644 index 00000000..1ae15ee0 --- /dev/null +++ b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.desktop @@ -0,0 +1,115 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=PowerDevilBackend +X-KDE-Library=powerdevilupowerbackend +InitialPreference=200 +Icon=preferences-system-power-management +Name=UPower PowerDevil Backend +Name[ast]=UPower PowerDevil Backend +Name[bg]=PowerDevil поддръжка на UPower +Name[bs]=U‑pauer kao pozadina Strujnog đavola +Name[ca]=Dorsal d'UPower per al PowerDevil +Name[ca@valencia]=Dorsal d'UPower per al PowerDevil +Name[cs]=Podpůrná vrstva UPower PowerDevil +Name[da]=UPower-motor til PowerDevil +Name[de]=UPower-PowerDevil-Modul +Name[el]=Σύστημα υποστήριξης UPower για το PowerDevil +Name[en_GB]=UPower PowerDevil Backend +Name[es]=Motor UPower para PowerDevil +Name[et]=UPoweri PowerDevili taustaprogramm +Name[eu]=UPower, PowerDevil-erako bizkarraldeakoa +Name[fi]=UPower PowerDevil-taustaosa +Name[fr]=Module « UPower » de PowerDevil +Name[ga]=Inneall UPower PowerDevil +Name[gl]=Infraestrutura UPower de PowerDevil +Name[he]=מנגנון UPower PowerDevil +Name[hr]=UPower pozadinski servis za PowerDevil +Name[hu]=UPower Powerdevil-modul +Name[ia]=UPower PowerDevil Backend (RetroAdministration de Powerdevil de UPower) +Name[is]=UPower OrkuPúki +Name[ja]=UPower PowerDevil バックエンド +Name[kk]=UPower PowerDevil тетігі +Name[km]=កម្មវិធី​ខាងក្រោយ UPower PowerDevil +Name[kn]=UPower PowerDevil ಬ್ಯಾಕೆಂಡ್ +Name[ko]=UPower PowerDevil 백엔드 +Name[lt]=UPower PowerDevil programinė sąsaja +Name[lv]=UPower PowerDevil aizmugure +Name[mr]=UPower पॉवरडेव्हिल बॅकएन्ड +Name[nb]=UPower PowerDevil-motor +Name[nds]=Hülpprogramm för den UPower-Stroomdüvel +Name[nl]=Backend voor UPower PowerDevil +Name[pa]=UPower ਪਾਵਰ-ਡੀਵਿਲ ਬੈਕਐਂਡ +Name[pl]=Moduł UPower dla PowerDevil +Name[pt]=Infra-Estrutura de UPower para o PowerDevil +Name[pt_BR]=Infraestrutura de UPower para o PowerDevil +Name[ro]=Platformă PowerDevil UPower +Name[ru]=Модуль поддержки UPower для PowerDevil +Name[sk]=Backend UPower PowerDevil +Name[sl]=Zaledje UPower za PowerDevil +Name[sr]=У‑пауер као позадина Струјног ђавола +Name[sr@ijekavian]=У‑пауер као позадина Струјног ђавола +Name[sr@ijekavianlatin]=UPower kao pozadina Strujnog đavola +Name[sr@latin]=UPower kao pozadina Strujnog đavola +Name[sv]=Upower Powerdevil-gränssnitt +Name[th]=โปรแกรมเบื้องหลัง PowerDevil ของ UPower +Name[tr]=UPower PowerDevil Arkaucu +Name[ug]=UPower PowerDevil ئارقا ئۇچى +Name[uk]=Сервер PowerDevil UPower +Name[wa]=Bouye di fond UPower do Diâle d' enerdjeye +Name[x-test]=xxUPower PowerDevil Backendxx +Name[zh_CN]=UPower PowerDevil 后端 +Name[zh_TW]=UPower PowerDevil 後端介面 +Comment=Use KDE Power Management system through freedesktop.org upower daemon +Comment[ast]=Usar la xestión d'enerxía del sistema KDE a traviés del degorriu HAL de freedesktop.org sobre'l degorriu +Comment[bg]=Управление на захранването на KDE чрез демона upower на freedesktop.org +Comment[bs]=KDE‑ov sistem za upravljanje napajanjem preko demona U‑pauera +Comment[ca]=Usa el sistema de gestió d'energia del KDE mitjançant el dimoni upower del freedesktop.org +Comment[ca@valencia]=Usa el sistema de gestió d'energia del KDE mitjançant el dimoni upower del freedesktop.org +Comment[cs]=Využít démon freedesktop.org upower pro systém správy napájení KDE +Comment[da]=Brug KDE strømstyring via upower-dæmonen fra freedesktop.org +Comment[de]=Das KDE-Energieverwaltungssystem mit Hilfe des upower-Dienstes von freedesktop.org verwenden +Comment[el]=Διαχείριση ενέργειας ΚDE με χρήση του δαίμονα upower του freedesktop.org +Comment[en_GB]=Use KDE Power Management system through freedesktop.org upower dæmon +Comment[es]=Usar el sistema de gestión de energía de KDE mediante el demonio UPower de freedesktop.org +Comment[et]=KDE toitehalduse süsteemi kasutamine freedesktop.org-i upoweri deemoni abil +Comment[eu]=Erabili KDE-ren energia kudeatzeko sistema freedesktop.org upower deabruaren bitartez +Comment[fi]=KDE:n virranhallintajärjestelmän käyttö freedesktop.org upower-taustaprosessilla +Comment[fr]=Utiliser la gestion de l'énergie du matériel de KDE via le démon « UPower » de « freedesktop.org » +Comment[gl]=Usa o sistema de xestión enerxética de KDE mediante o daemon upower de freedesktop.org +Comment[he]=שימוש במנהל צריכת החשמל של KDE דרך תהליך הרקע freedesktop.org upower +Comment[hr]=Koristi KDE-ovo upravljanje potrošnjom energije kroz servis freedesktop.org upower +Comment[hu]=A KDE energiakezelő rendszerének használata a freedesktop.org upower démonán keresztül +Comment[ia]=Usa systema de gestion de energia de KDE usante demone upower de freedesktop.org +Comment[is]=KDE-orkustilling vélbúnaðar með upower púkanum frá freedesktop.org +Comment[ja]=freedesktop.org の upower デーモンを介して KDE 電源管理を使用 +Comment[kk]=freedesktop.org upower қызметі көмегімен KDE қуаттандыру жүйесін басқару +Comment[km]=ប្រើ​ប្រព័ន្ធ​គ្រប់គ្រង​ថាមពល​របស់ KDE តាមរយៈ​ដេមិន freedesktop.org upower +Comment[kn]=freedesktop.org ನ upower ನೇಪಥಿಕ (ಡೀಮನ್) ಬಳಸಿ KDE ವಿದ್ಯುಚ್ಛಕ್ತಿ ನಿರ್ವಹಣಾ ವ್ಯವಸ್ಥೆಯನ್ನು ಬಳಸಿ +Comment[ko]=freedesktop.org UPower 데몬을 사용하는 KDE 전원 관리 시스템 +Comment[lt]=Naudoti KDE energijos valdymo sistemą, naudojant freedesktop.org HAL tarnybą +Comment[lv]=Lietot KDE energokontroles sistēmu, izmantojot freedesktop.org upower dēmonu +Comment[mr]=freedesktop.org upower डीमनने केडीई वीज व्यवस्थापन प्रणाली वापरा +Comment[nb]=Bruk KDE strømstyringssystem med upower-nissen fra freedesktop.org +Comment[nds]=Den UPower-Dämoon vun freedesktop.org för de KDE-Stroomkuntrull bruken +Comment[nl]=KDE energiebeheer gebruiken via de upower-daemon van freedesktop.org +Comment[pa]=freedesktop.org upower ਡੈਮਨ ਰਾਹੀਂ KDE ਪਾਵਰ ਪਰਬੰਧ ਵਰਤੋਂ +Comment[pl]=Zarządzanie zasilaniem za pomocą usługi upower z freedesktop.org +Comment[pt]=Usar o sistema de gestão de energia do KDE através do servidor 'upower' do freedesktop.org +Comment[pt_BR]=Usar o sistema de gerenciamento de energia do KDE através do daemon upower do freedesktop.org +Comment[ro]=Folosește sistemul KDE de gestiune a alimentării prin intermediul demonului upower de la freedesktop.org +Comment[ru]=Управление питанием с использованием службы upower от freedesktop.org +Comment[sk]=Správa napájania KDE pomocou démona upower z freedesktop.org +Comment[sl]=Uporaba KDE-jevega sistema za upravljanje z energijo prek ozadnjega programa freedesktop.org upower +Comment[sr]=КДЕ‑ов систем за управљање напајањем преко демона У‑пауера +Comment[sr@ijekavian]=КДЕ‑ов систем за управљање напајањем преко демона У‑пауера +Comment[sr@ijekavianlatin]=KDE‑ov sistem za upravljanje napajanjem preko demona UPowera +Comment[sr@latin]=KDE‑ov sistem za upravljanje napajanjem preko demona UPowera +Comment[sv]=Använd KDE:s strömsparhantering via Upower-demon från freedesktop.org +Comment[th]=ใช้ระบบจัดการพลังงานของ KDE โดยใช้ดีมอน upower จาก freedesktop.org +Comment[tr]=KDE Güç Yönetim sisteminde freedesktop.org upower servisini kullan +Comment[ug]=KDE توك مەنبە باشقۇرغۇچ سىستېمىسىدا freedesktop.org upower نازارەتچىنى ئىشلەت +Comment[uk]=Використання системи керування живленням KDE за допомогою фонової служби upower freedesktop.org +Comment[wa]=Eployî l' sistinme di manaedjmint di l' enerdjeye di KDE åd triviè do démon upower di freedesktop.org +Comment[x-test]=xxUse KDE Power Management system through freedesktop.org upower daemonxx +Comment[zh_CN]=用 freedesktop.org upower 守护程序进行 KDE 电源管理 +Comment[zh_TW]=透過 freedesktop.org 的 upower 伺服程式使用 KDE 電源管理系統 diff --git a/powerdevil/daemon/backends/upower/powerdevilupowerbackend.h b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.h new file mode 100644 index 00000000..c6563b0d --- /dev/null +++ b/powerdevil/daemon/backends/upower/powerdevilupowerbackend.h @@ -0,0 +1,109 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + Copyright (C) 2008-2010 Dario Freddi + Copyright (C) 2010 Alejandro Fiestas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef POWERDEVILUPOWERBACKEND_H +#define POWERDEVILUPOWERBACKEND_H + +#include + +#include +#include + +#include + +#include "upower_device_interface.h" +#include "upower_interface.h" +#include "upower_kbdbacklight_interface.h" +#include "udevqt.h" + +#define UPOWER_SERVICE "org.freedesktop.UPower" +#define UPOWER_PATH "/org/freedesktop/UPower" +#define UPOWER_IFACE "org.freedesktop.UPower" +#define UPOWER_IFACE_DEVICE "org.freedesktop.UPower.Device" + +#define LOGIN1_SERVICE "org.freedesktop.login1" + +class UdevHelper; +class XRandRX11Helper; +class XRandrBrightness; + +class KDE_EXPORT PowerDevilUPowerBackend : public PowerDevil::BackendInterface +{ + Q_OBJECT + Q_DISABLE_COPY(PowerDevilUPowerBackend) +public: + explicit PowerDevilUPowerBackend(QObject* parent); + virtual ~PowerDevilUPowerBackend(); + + virtual void init(); + static bool isAvailable(); + + virtual float brightness(BrightnessControlType type = Screen) const; + + virtual void brightnessKeyPressed(PowerDevil::BackendInterface::BrightnessKeyType type, PowerDevil::BackendInterface::BrightnessControlType controlType); + virtual bool setBrightness(float brightness, PowerDevil::BackendInterface::BrightnessControlType type = Screen); + virtual KJob* suspend(PowerDevil::BackendInterface::SuspendMethod method); + +private: + void enumerateDevices(); + +private slots: + void updateDeviceProps(); + void slotDeviceAdded(const QString &); + void slotDeviceRemoved(const QString &); + void slotDeviceAdded(const QDBusObjectPath & path); + void slotDeviceRemoved(const QDBusObjectPath & path); + void slotDeviceChanged(const QString &); + void slotPropertyChanged(); + void slotLogin1Resuming(bool active); + void slotScreenBrightnessChanged(); + void onDeviceChanged(const UdevQt::Device &device); + void onKeyboardBrightnessChanged(int); + + void onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps); + void onDevicePropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps); + +private: + // upower devices + QMap m_devices; + + // brightness + QMap m_cachedBrightnessMap; + XRandrBrightness *m_brightnessControl; + XRandRX11Helper *m_randrHelper; + + OrgFreedesktopUPowerInterface *m_upowerInterface; + OrgFreedesktopUPowerKbdBacklightInterface *m_kbdBacklight; + int m_kbdMaxBrightness; + + // login1 interface + QWeakPointer m_login1Interface; + + // buttons + bool m_lidIsPresent; + bool m_lidIsClosed; + bool m_onBattery; + + //helper path + QString m_syspath; +}; + +#endif // POWERDEVILUPOWERBACKEND_H diff --git a/powerdevil/daemon/backends/upower/udevqt.h b/powerdevil/daemon/backends/upower/udevqt.h new file mode 100644 index 00000000..228687e4 --- /dev/null +++ b/powerdevil/daemon/backends/upower/udevqt.h @@ -0,0 +1,109 @@ +/* + Copyright 2009 Benjamin K. Stuhl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef UDEVQT_H +#define UDEVQT_H + +#include +#include +#include +#include +#include + +namespace UdevQt +{ + +class DevicePrivate; +class Device +{ + public: + Device(); + Device(const Device &other); + ~Device(); + Device &operator= (const Device &other); + + bool isValid() const; + QString subsystem() const; + QString devType() const; + QString name() const; + QString sysfsPath() const; + int sysfsNumber() const; + QString driver() const; + QString primaryDeviceFile() const; + QStringList alternateDeviceSymlinks() const; + QStringList deviceProperties() const; + QStringList sysfsProperties() const; + Device parent() const; + + // ### should this really be a QVariant? as far as udev knows, everything is a string... + // see also Client::devicesByProperty + QVariant deviceProperty(const QString &name) const; + QString decodedDeviceProperty(const QString &name) const; + QVariant sysfsProperty(const QString &name) const; + Device ancestorOfType(const QString &subsys, const QString &devtype) const; + + private: + Device(DevicePrivate *devPrivate); + friend class Client; + friend class ClientPrivate; + + DevicePrivate *d; +}; + +typedef QList DeviceList; + +class ClientPrivate; +class Client : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QStringList watchedSubsystems READ watchedSubsystems WRITE setWatchedSubsystems) + + public: + Client(QObject *parent = 0); + Client(const QStringList &subsystemList, QObject *parent = 0); + ~Client(); + + QStringList watchedSubsystems() const; + void setWatchedSubsystems(const QStringList &subsystemList); + + DeviceList allDevices(); + DeviceList devicesByProperty(const QString &property, const QVariant &value); + DeviceList devicesBySubsystem(const QString &subsystem); + Device deviceByDeviceFile(const QString &deviceFile); + Device deviceBySysfsPath(const QString &sysfsPath); + Device deviceBySubsystemAndName(const QString &subsystem, const QString &name); + + signals: + void deviceAdded(const UdevQt::Device &dev); + void deviceRemoved(const UdevQt::Device &dev); + void deviceChanged(const UdevQt::Device &dev); + void deviceOnlined(const UdevQt::Device &dev); + void deviceOfflined(const UdevQt::Device &dev); + + private: + friend class ClientPrivate; + Q_PRIVATE_SLOT(d, void _uq_monitorReadyRead(int fd)) + ClientPrivate *d; +}; + +} + +#endif diff --git a/powerdevil/daemon/backends/upower/udevqt_p.h b/powerdevil/daemon/backends/upower/udevqt_p.h new file mode 100644 index 00000000..189a5ff8 --- /dev/null +++ b/powerdevil/daemon/backends/upower/udevqt_p.h @@ -0,0 +1,82 @@ +/* + Copyright 2009 Benjamin K. Stuhl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef UDEVQT_P_H +#define UDEVQT_P_H + +extern "C" +{ +#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE +#include +} + +class QByteArray; +class QSocketNotifier; + +namespace UdevQt +{ + +class DevicePrivate +{ + public: + DevicePrivate(struct udev_device *udev_, bool ref = true); + ~DevicePrivate(); + DevicePrivate &operator=(const DevicePrivate& other); + + QString decodePropertyValue(const QByteArray &encoded) const; + + struct udev_device *udev; +}; + + +class ClientPrivate +{ + public: + enum ListenToWhat { ListenToList, ListenToNone }; + + ClientPrivate(Client *q_); + ~ClientPrivate(); + + void init(const QStringList &subsystemList, ListenToWhat what); + void setWatchedSubsystems(const QStringList &subsystemList); + void _uq_monitorReadyRead(int fd); + DeviceList deviceListFromEnumerate(struct udev_enumerate *en); + + struct udev *udev; + struct udev_monitor *monitor; + Client *q; + QSocketNotifier *monitorNotifier; + QStringList watchedSubsystems; +}; + +inline QStringList listFromListEntry(struct udev_list_entry *list) +{ + QStringList ret; + struct udev_list_entry *entry; + + udev_list_entry_foreach(entry, list) { + ret << QString::fromLatin1(udev_list_entry_get_name(entry)); + } + return ret; +} + +} + +#endif diff --git a/powerdevil/daemon/backends/upower/udevqtclient.cpp b/powerdevil/daemon/backends/upower/udevqtclient.cpp new file mode 100644 index 00000000..c1157c3e --- /dev/null +++ b/powerdevil/daemon/backends/upower/udevqtclient.cpp @@ -0,0 +1,256 @@ +/* + Copyright 2009 Benjamin K. Stuhl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "udevqt.h" +#include "udevqt_p.h" + +#include +#include + +namespace UdevQt { + +ClientPrivate::ClientPrivate(Client *q_) + : udev(0), monitor(0), q(q_), monitorNotifier(0) +{ +} + +ClientPrivate::~ClientPrivate() +{ + udev_unref(udev); + delete monitorNotifier; + + if (monitor) + udev_monitor_unref(monitor); +} + +void ClientPrivate::init(const QStringList &subsystemList, ListenToWhat what) +{ + udev = udev_new(); + + if (what != ListenToNone) { + setWatchedSubsystems(subsystemList); + } +} + +void ClientPrivate::setWatchedSubsystems(const QStringList &subsystemList) +{ + // create a listener + struct udev_monitor *newM = udev_monitor_new_from_netlink(udev, "udev"); + + if (!newM) { + qWarning("UdevQt: unable to create udev monitor connection"); + return; + } + + // apply our filters; an empty list means listen to everything + foreach (const QString& subsysDevtype, subsystemList) { + int ix = subsysDevtype.indexOf("/"); + + if (ix > 0) { + QByteArray subsystem = subsysDevtype.left(ix).toLatin1(); + QByteArray devType = subsysDevtype.mid(ix + 1).toLatin1(); + udev_monitor_filter_add_match_subsystem_devtype(newM, subsystem.constData(), devType.constData()); + } else { + udev_monitor_filter_add_match_subsystem_devtype(newM, subsysDevtype.toLatin1().constData(), NULL); + } + } + + // start the new monitor receiving + udev_monitor_enable_receiving(newM); + QSocketNotifier *sn = new QSocketNotifier(udev_monitor_get_fd(newM), QSocketNotifier::Read); + QObject::connect(sn, SIGNAL(activated(int)), q, SLOT(_uq_monitorReadyRead(int))); + + // kill any previous monitor + delete monitorNotifier; + if (monitor) + udev_monitor_unref(monitor); + + // and save our new one + monitor = newM; + monitorNotifier = sn; + watchedSubsystems = subsystemList; +} + +void ClientPrivate::_uq_monitorReadyRead(int fd) +{ + Q_UNUSED(fd); + monitorNotifier->setEnabled(false); + struct udev_device *dev = udev_monitor_receive_device(monitor); + monitorNotifier->setEnabled(true); + + if (!dev) + return; + + Device device(new DevicePrivate(dev, false)); + + QByteArray action(udev_device_get_action(dev)); + if (action == "add") { + emit q->deviceAdded(device); + } else if (action == "remove") { + emit q->deviceRemoved(device); + } else if (action == "change") { + emit q->deviceChanged(device); + } else if (action == "online") { + emit q->deviceOnlined(device); + } else if (action == "offline") { + emit q->deviceOfflined(device); + } else { + qWarning("UdevQt: unhandled device action \"%s\"", action.constData()); + } +} + +DeviceList ClientPrivate::deviceListFromEnumerate(struct udev_enumerate *en) +{ + DeviceList ret; + struct udev_list_entry *list, *entry; + + udev_enumerate_scan_devices(en); + list = udev_enumerate_get_list_entry(en); + udev_list_entry_foreach(entry, list) { + struct udev_device *ud = udev_device_new_from_syspath(udev_enumerate_get_udev(en), + udev_list_entry_get_name(entry)); + + if (!ud) + continue; + + ret << Device(new DevicePrivate(ud, false)); + } + + udev_enumerate_unref(en); + + return ret; +} + + +Client::Client(QObject *parent) + : QObject(parent) + , d(new ClientPrivate(this)) +{ + d->init(QStringList(), ClientPrivate::ListenToNone); +} + +Client::Client(const QStringList& subsystemList, QObject *parent) + : QObject(parent) + , d(new ClientPrivate(this)) +{ + d->init(subsystemList, ClientPrivate::ListenToList); +} + +Client::~Client() +{ + delete d; +} + +QStringList Client::watchedSubsystems() const +{ + // we're watching a specific list + if (!d->watchedSubsystems.isEmpty()) + return d->watchedSubsystems; + + // we're not watching anything + if (!d->monitor) + return QStringList(); + + // we're watching everything: figure out what "everything" currently is + // we don't cache it, since it may be subject to change, depending on hotplug + struct udev_enumerate *en = udev_enumerate_new(d->udev); + udev_enumerate_scan_subsystems(en); + QStringList s = listFromListEntry(udev_enumerate_get_list_entry(en)); + udev_enumerate_unref(en); + return s; +} + +void Client::setWatchedSubsystems(const QStringList &subsystemList) +{ + d->setWatchedSubsystems(subsystemList); +} + +DeviceList Client::devicesByProperty(const QString &property, const QVariant &value) +{ + struct udev_enumerate *en = udev_enumerate_new(d->udev); + + if (value.isValid()) { + udev_enumerate_add_match_property(en, property.toLatin1().constData(), value.toString().toLatin1().constData()); + } else { + udev_enumerate_add_match_property(en, property.toLatin1().constData(), NULL); + } + + return d->deviceListFromEnumerate(en); +} + +DeviceList Client::allDevices() +{ + struct udev_enumerate *en = udev_enumerate_new(d->udev); + return d->deviceListFromEnumerate(en); +} + +DeviceList Client::devicesBySubsystem(const QString &subsystem) +{ + struct udev_enumerate *en = udev_enumerate_new(d->udev); + + udev_enumerate_add_match_subsystem(en, subsystem.toLatin1().constData()); + return d->deviceListFromEnumerate(en); +} + +Device Client::deviceByDeviceFile(const QString &deviceFile) +{ + struct stat sb; + + if (stat(deviceFile.toLatin1().constData(), &sb) != 0) + return Device(); + + struct udev_device *ud = 0; + + if (S_ISBLK(sb.st_mode)) + ud = udev_device_new_from_devnum(d->udev, 'b', sb.st_rdev); + else if (S_ISCHR(sb.st_mode)) + ud = udev_device_new_from_devnum(d->udev, 'c', sb.st_rdev); + + if (!ud) + return Device(); + + return Device(new DevicePrivate(ud, false)); +} + +Device Client::deviceBySysfsPath(const QString &sysfsPath) +{ + struct udev_device *ud = udev_device_new_from_syspath(d->udev, sysfsPath.toLatin1().constData()); + + if (!ud) + return Device(); + + return Device(new DevicePrivate(ud, false)); +} + +Device Client::deviceBySubsystemAndName(const QString &subsystem, const QString &name) +{ + struct udev_device *ud = udev_device_new_from_subsystem_sysname(d->udev, + subsystem.toLatin1().constData(), + name.toLatin1().constData()); + + if (!ud) + return Device(); + + return Device(new DevicePrivate(ud, false)); +} + +} + +#include "udevqt.moc" diff --git a/powerdevil/daemon/backends/upower/udevqtdevice.cpp b/powerdevil/daemon/backends/upower/udevqtdevice.cpp new file mode 100644 index 00000000..f1926664 --- /dev/null +++ b/powerdevil/daemon/backends/upower/udevqtdevice.cpp @@ -0,0 +1,270 @@ +/* + Copyright 2009 Benjamin K. Stuhl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "udevqt.h" +#include "udevqt_p.h" + +#include + +namespace UdevQt { + +DevicePrivate::DevicePrivate(struct udev_device *udev_, bool ref) + : udev(udev_) +{ + if (ref) + udev_device_ref(udev); +} + +DevicePrivate::~DevicePrivate() +{ + udev_device_unref(udev); +} + +DevicePrivate &DevicePrivate::operator=(const DevicePrivate &other) +{ + udev_device_unref(udev); + udev = udev_device_ref(other.udev); + return *this; +} + +QString DevicePrivate::decodePropertyValue(const QByteArray &encoded) const +{ + QByteArray decoded; + const int len = encoded.length(); + + for (int i = 0; i < len; i++) { + quint8 ch = encoded.at(i); + + if (ch == '\\') { + if (i + 1 < len && encoded.at(i + 1) == '\\') { + decoded.append('\\'); + i++; + continue; + } else if (i + 3 < len && encoded.at(i + 1) == 'x') { + QByteArray hex = encoded.mid(i + 2, 2); + bool ok; + int code = hex.toInt(&ok, 16); + if (ok) + decoded.append(char(code)); + i += 3; + continue; + } + } else { + decoded.append(ch); + } + } + return QString::fromUtf8(decoded); +} + +Device::Device() + : d(0) +{ +} + +Device::Device(const Device &other) +{ + if (other.d) { + d = new DevicePrivate(other.d->udev); + } else { + d = 0; + } +} + +Device::Device(DevicePrivate *devPrivate) + : d(devPrivate) +{ +} + +Device::~Device() +{ + delete d; +} + +Device &Device::operator=(const Device &other) +{ + if (this == &other) + return *this; + if (!other.d) { + delete d; + d = 0; + return *this; + } + if (!d) { + d = new DevicePrivate(other.d->udev); + } else { + *d = *other.d; + } + + return *this; +} + +bool Device::isValid() const +{ + return (d != 0); +} + +QString Device::subsystem() const +{ + if (!d) + return QString(); + + return QString::fromLatin1(udev_device_get_subsystem(d->udev)); +} + +QString Device::devType() const +{ + if (!d) + return QString(); + + return QString::fromLatin1(udev_device_get_devtype(d->udev)); +} + +QString Device::name() const +{ + if (!d) + return QString(); + + return QString::fromLatin1(udev_device_get_sysname(d->udev)); +} + +QString Device::sysfsPath() const +{ + if (!d) + return QString(); + + return QString::fromLatin1(udev_device_get_syspath(d->udev)); +} + +int Device::sysfsNumber() const +{ + if (!d) + return -1; + + QString value = QString::fromLatin1(udev_device_get_sysnum(d->udev)); + bool success = false; + int number = value.toInt(&success); + if (success) + return number; + return -1; +} + +QString Device::driver() const +{ + if (!d) + return QString(); + + return QString::fromLatin1(udev_device_get_driver(d->udev)); +} + +QString Device::primaryDeviceFile() const +{ + if (!d) + return QString(); + + return QString::fromLatin1(udev_device_get_devnode(d->udev)); +} + +QStringList Device::alternateDeviceSymlinks() const +{ + if (!d) + return QStringList(); + + return listFromListEntry(udev_device_get_devlinks_list_entry(d->udev)); +} + +QStringList Device::deviceProperties() const +{ + if (!d) + return QStringList(); + + return listFromListEntry(udev_device_get_properties_list_entry(d->udev)); +} + +QStringList Device::sysfsProperties() const +{ + if (!d) + return QStringList(); + + return listFromListEntry(udev_device_get_properties_list_entry(d->udev)); +} + +Device Device::parent() const +{ + if (!d) + return Device(); + + struct udev_device *p = udev_device_get_parent(d->udev); + + if (!p) + return Device(); + + return Device(new DevicePrivate(p)); +} + +QVariant Device::deviceProperty(const QString &name) const +{ + if (!d) + return QVariant(); + + QByteArray propName = name.toLatin1(); + QString propValue = QString::fromLatin1(udev_device_get_property_value(d->udev, propName.constData())); + if (!propValue.isEmpty()) { + return QVariant::fromValue(propValue); + } + return QVariant(); +} + +QString Device::decodedDeviceProperty(const QString &name) const +{ + if (!d) + return QString(); + + QByteArray propName = name.toLatin1(); + return d->decodePropertyValue(udev_device_get_property_value(d->udev, propName.constData())); +} + +QVariant Device::sysfsProperty(const QString &name) const +{ + if (!d) + return QVariant(); + + QByteArray propName = name.toLatin1(); + QString propValue = QString::fromLatin1(udev_device_get_sysattr_value(d->udev, propName.constData())); + if (!propValue.isEmpty()) { + return QVariant::fromValue(propValue); + } + return QVariant(); +} + +Device Device::ancestorOfType(const QString &subsys, const QString &devtype) const +{ + if (!d) + return Device(); + + struct udev_device *p = udev_device_get_parent_with_subsystem_devtype(d->udev, + subsys.toLatin1().constData(), devtype.toLatin1().constData()); + + if (!p) + return Device(); + + return Device(new DevicePrivate(p)); +} + +} diff --git a/powerdevil/daemon/backends/upower/upowersuspendjob.cpp b/powerdevil/daemon/backends/upower/upowersuspendjob.cpp new file mode 100644 index 00000000..08a850a4 --- /dev/null +++ b/powerdevil/daemon/backends/upower/upowersuspendjob.cpp @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + Copyright (C) 2010 Alejandro Fiestas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "upowersuspendjob.h" + +#include "upower_interface.h" + +#include +#include +#include +#include +#include + +UPowerSuspendJob::UPowerSuspendJob(OrgFreedesktopUPowerInterface *upowerInterface, + PowerDevil::BackendInterface::SuspendMethod method, + PowerDevil::BackendInterface::SuspendMethods supported) + : KJob(), m_upowerInterface(upowerInterface) +{ + kDebug() << "Starting UPower suspend job"; + m_method = method; + m_supported = supported; + + connect(m_upowerInterface, SIGNAL(Resuming()), this, SLOT(resumeDone())); +} + +UPowerSuspendJob::~UPowerSuspendJob() +{ + +} + +void UPowerSuspendJob::start() +{ + QTimer::singleShot(0, this, SLOT(doStart())); +} + +void UPowerSuspendJob::kill(bool /*quietly */) +{ + +} + +void UPowerSuspendJob::doStart() +{ + if (m_supported & m_method) + { + switch(m_method) + { + case PowerDevil::BackendInterface::ToRam: + m_upowerInterface->AboutToSleep("suspend"); + m_upowerInterface->Suspend(); + break; + case PowerDevil::BackendInterface::ToDisk: + m_upowerInterface->AboutToSleep("hibernate"); + m_upowerInterface->Hibernate(); + break; + default: + kDebug() << "This backend doesn't support hybrid mode"; + setError(1); + setErrorText(i18n("Unsupported suspend method")); + break; + } + emitResult(); + } +} + + +void UPowerSuspendJob::resumeDone() +{ + emitResult(); +} + +#include "upowersuspendjob.moc" diff --git a/powerdevil/daemon/backends/upower/upowersuspendjob.h b/powerdevil/daemon/backends/upower/upowersuspendjob.h new file mode 100644 index 00000000..aac4b12b --- /dev/null +++ b/powerdevil/daemon/backends/upower/upowersuspendjob.h @@ -0,0 +1,54 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Kevin Ottens + Copyright (C) 2010 Alejandro Fiestas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef UPOWERSUSPENDJOB_H +#define UPOWERSUSPENDJOB_H + +#include +#include +#include + +#include "powerdevilbackendinterface.h" + +class OrgFreedesktopUPowerInterface; + +class UPowerSuspendJob : public KJob +{ + Q_OBJECT +public: + UPowerSuspendJob(OrgFreedesktopUPowerInterface *upowerInterface, + PowerDevil::BackendInterface::SuspendMethod method, + PowerDevil::BackendInterface::SuspendMethods supported); + virtual ~UPowerSuspendJob(); + + void start(); + void kill(bool quietly); + +private Q_SLOTS: + void doStart(); + void resumeDone(); + +private: + OrgFreedesktopUPowerInterface *m_upowerInterface; + PowerDevil::BackendInterface::SuspendMethod m_method; + PowerDevil::BackendInterface::SuspendMethods m_supported; +}; + +#endif //UPOWERSUSPENDJOB_H diff --git a/powerdevil/daemon/backends/upower/xlibandxrandr.h b/powerdevil/daemon/backends/upower/xlibandxrandr.h new file mode 100644 index 00000000..0dab3672 --- /dev/null +++ b/powerdevil/daemon/backends/upower/xlibandxrandr.h @@ -0,0 +1,36 @@ +/************************************************************************************* + * Copyright (C) 2012 by Alejandro Fiestas Olivares * + * * + * 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 XLIBANDXRANDR_H +#define XLIBANDXRANDR_H + +extern "C" +{ +#include +#include +#define INT8 _X11INT8 +#define INT32 _X11INT32 +#include +#undef INT8 +#undef INT32 +#include +} + +#include + +#endif // XLIBANDXRANDR diff --git a/powerdevil/daemon/backends/upower/xrandrbrightness.cpp b/powerdevil/daemon/backends/upower/xrandrbrightness.cpp new file mode 100644 index 00000000..f18092e7 --- /dev/null +++ b/powerdevil/daemon/backends/upower/xrandrbrightness.cpp @@ -0,0 +1,182 @@ +/* This file is part of the KDE project + * Copyright (C) 2010 Lukas Tinkl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "xrandrbrightness.h" + +#include + +#include +#include + +#include +#include +#include + +XRandrBrightness::XRandrBrightness() + : m_backlight(None), m_resources(0) +{ + // init + int major, minor; + if (!XRRQueryVersion (QX11Info::display(), &major, &minor)) + { + qWarning("RandR extension missing"); + return; + } + + if (major < 1 || (major == 1 && minor < 2)) + { + qWarning("RandR version %d.%d too old", major, minor); + return; + } + + m_backlight = XInternAtom(QX11Info::display(), "Backlight", True); + if (m_backlight == None) + m_backlight = XInternAtom(QX11Info::display(), "BACKLIGHT", True); // try with legacy atom + + if (m_backlight == None) + { + qWarning("No outputs have backlight property"); + return; + } + + m_resources = XRRGetScreenResources(QX11Info::display(), QX11Info::appRootWindow()); + + if (!m_resources) + { + qWarning("No available Randr resources"); + return; + } +} + +XRandrBrightness::~XRandrBrightness() +{ + if (m_resources) { + XRRFreeScreenResources(m_resources); + } +} + +bool XRandrBrightness::isSupported() const +{ + if (!m_resources) + return false; + + // Verify that there are outputs that actually support backlight control... + for (int o = 0; o < m_resources->noutput; o++) + { + if (backlight_get(m_resources->outputs[o]) != -1) { + return true; + } + } + + return false; +} + +float XRandrBrightness::brightness() const +{ + float result = 0; + + if (!m_resources) + return result; + + for (int o = 0; o < m_resources->noutput; o++) + { + RROutput output = m_resources->outputs[o]; + double cur = backlight_get(output); + if (cur != -1) + { + XRRPropertyInfo * info = XRRQueryOutputProperty(QX11Info::display(), output, m_backlight); + if (info) + { + if (info->range && info->num_values == 2) + { + double min = info->values[0]; + double max = info->values[1]; + XFree(info); + + // FIXME for now just return the first output's value + result = (cur - min) * 100 / (max - min); + break; + } + XFree(info); + } + } + } + + return result; +} + +void XRandrBrightness::setBrightness(float brightness) +{ + if (!m_resources) + return; + + for (int o = 0; o < m_resources->noutput; o++) + { + RROutput output = m_resources->outputs[o]; + double cur = backlight_get(output); + if (cur != -1) + { + XRRPropertyInfo * info = XRRQueryOutputProperty(QX11Info::display(), output, m_backlight); + if (info) + { + if (info->range && info->num_values == 2) + { + double min = info->values[0]; + double max = info->values[1]; + + // FIXME for now just set the first output's value + double value = min + (brightness * (max - min) / 100); + backlight_set(output, (long) (value + 0.5)); + } + XFree(info); + } + } + } + + XSync(QX11Info::display(), False); +} + +long XRandrBrightness::backlight_get(RROutput output) const +{ + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop; + Atom actual_type; + int actual_format; + long value; + + if (!m_backlight || XRRGetOutputProperty (QX11Info::display(), output, m_backlight, + 0, 4, False, False, None, + &actual_type, &actual_format, + &nitems, &bytes_after, &prop) != Success) + return -1; + + if (actual_type != XA_INTEGER || nitems != 1 || actual_format != 32) + value = -1; + else + value = *((long *) prop); + XFree (prop); + return value; +} + +void XRandrBrightness::backlight_set(RROutput output, long value) +{ + XRRChangeOutputProperty (QX11Info::display(), output, m_backlight, XA_INTEGER, 32, + PropModeReplace, (unsigned char *) &value, 1); +} diff --git a/powerdevil/daemon/backends/upower/xrandrbrightness.h b/powerdevil/daemon/backends/upower/xrandrbrightness.h new file mode 100644 index 00000000..875c6672 --- /dev/null +++ b/powerdevil/daemon/backends/upower/xrandrbrightness.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + * Copyright (C) 2010 Lukas Tinkl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef XRANDRBRIGHTNESS_H +#define XRANDRBRIGHTNESS_H + +#include + +#include +#include +#include + +class XRandrBrightness +{ +public: + XRandrBrightness(); + ~XRandrBrightness(); + bool isSupported() const; + float brightness() const; + void setBrightness(float brightness); + +private: + long backlight_get(RROutput output) const; + void backlight_set(RROutput output, long value); + + Atom m_backlight; + XRRScreenResources *m_resources; +}; + +#endif // XRANDRBRIGHTNESS_H diff --git a/powerdevil/daemon/backends/upower/xrandrx11helper.cpp b/powerdevil/daemon/backends/upower/xrandrx11helper.cpp new file mode 100644 index 00000000..28bad37f --- /dev/null +++ b/powerdevil/daemon/backends/upower/xrandrx11helper.cpp @@ -0,0 +1,70 @@ +/************************************************************************************* + * Copyright (C) 2013 by Dan Vrátil * + * Copyright (C) 2013 by Dario Freddi * + * * + * 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 "xrandrx11helper.h" + +#include + +#include +#include + +XRandRX11Helper::XRandRX11Helper(): + QWidget() +{ + XRRQueryVersion (QX11Info::display(), &m_versionMajor, &m_versionMinor); + + XRRQueryExtension(QX11Info::display(), &m_randrBase, &m_randrError); + + m_window = XCreateSimpleWindow(QX11Info::display(), + XRootWindow(QX11Info::display(), DefaultScreen(QX11Info::display())) + , 0, 0, 1, 1, 0, 0, 0 ); + + XRRSelectInput(QX11Info::display(), m_window, RROutputPropertyNotifyMask); + + KSystemEventFilter::installEventFilter(this); +} + +XRandRX11Helper::~XRandRX11Helper() +{ + KSystemEventFilter::removeEventFilter(this); + XDestroyWindow(QX11Info::display(), m_window); +} + +bool XRandRX11Helper::x11Event(XEvent *event) +{ + XRRNotifyEvent* e2 = reinterpret_cast< XRRNotifyEvent* >(event); + + if (event->xany.type != m_randrBase + RRNotify) { + return false; + } + + if (e2->subtype == RRNotify_OutputProperty) { + XRROutputPropertyNotifyEvent* e2 = reinterpret_cast< XRROutputPropertyNotifyEvent* >(event); + char *atomName = XGetAtomName(QX11Info::display(), e2->property); + if (QString(atomName) == RR_PROPERTY_BACKLIGHT) { + Q_EMIT brightnessChanged(); + } + + XFree(atomName); + } + + return false; +} + +#include "xrandrx11helper.moc" diff --git a/powerdevil/daemon/backends/upower/xrandrx11helper.h b/powerdevil/daemon/backends/upower/xrandrx11helper.h new file mode 100644 index 00000000..184f582a --- /dev/null +++ b/powerdevil/daemon/backends/upower/xrandrx11helper.h @@ -0,0 +1,49 @@ +/************************************************************************************* + * Copyright (C) 2013 by Dan Vrátil * + * Copyright (C) 2013 by Dario Freddi * + * * + * 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 XRANDRX11HELPER_H +#define XRANDRX11HELPER_H + +#include +#include "xlibandxrandr.h" + +class XRandRX11Helper : public QWidget +{ + Q_OBJECT + + public: + XRandRX11Helper(); + virtual ~XRandRX11Helper(); + + Q_SIGNALS: + void brightnessChanged(); + + protected: + virtual bool x11Event(XEvent *); + + int m_randrBase; + int m_randrError; + int m_versionMajor; + int m_versionMinor; + + bool m_debugMode; + Window m_window; +}; + +#endif // XRANDRX11HELPER_H diff --git a/powerdevil/daemon/brightnessosdwidget.cpp b/powerdevil/daemon/brightnessosdwidget.cpp new file mode 100644 index 00000000..1474018d --- /dev/null +++ b/powerdevil/daemon/brightnessosdwidget.cpp @@ -0,0 +1,135 @@ +/******************************************************************* +* brightnessosdwidget.cpp +* adapted from kdemultimedia/kmix/osdwidget.cpp +* Copyright 2009 Aurélien Gâteau +* Copyright 2009 Dario Andres Rodriguez +* Copyright 2009 Christian Esken +* Copyright 2010 Felix Geyer +* +* 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, see . +* +******************************************************************/ + +#include "brightnessosdwidget.h" + +// Qt +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include + +BrightnessOSDWidget::BrightnessOSDWidget(PowerDevil::BackendInterface::BrightnessControlType type, QWidget * parent) + : Plasma::Dialog(parent, Qt::ToolTip), + m_type(type), + m_scene(new QGraphicsScene(this)), + m_container(new QGraphicsWidget), + m_iconLabel(new Plasma::Label), + m_volumeLabel(new Plasma::Label), + m_meter(new Plasma::Meter), + m_hideTimer(new QTimer(this)) +{ + KWindowSystem::setState(winId(), NET::KeepAbove); + KWindowSystem::setType(winId(), NET::Tooltip); + setAttribute(Qt::WA_X11NetWmWindowTypeToolTip, true); + m_meter->setMeterType(Plasma::Meter::BarMeterHorizontal); + m_meter->setMaximum(100); + + m_volumeLabel->setAlignment(Qt::AlignCenter); + + //Setup the auto-hide timer + m_hideTimer->setInterval(2000); + m_hideTimer->setSingleShot(true); + connect(m_hideTimer, SIGNAL(timeout()), this, SLOT(hide())); + + //Setup the OSD layout + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(m_container); + layout->setContentsMargins(0, 0, 0, 0); + layout->addItem(m_iconLabel); + layout->addItem(m_meter); + layout->addItem(m_volumeLabel); + + m_scene->addItem(m_container); + setGraphicsWidget(m_container); + + themeUpdated(); + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeUpdated())); // e.g. for updating font +} + +void BrightnessOSDWidget::activateOSD() +{ + m_hideTimer->start(); +} + +void BrightnessOSDWidget::setCurrentBrightness(int brightnessLevel) +{ + m_meter->setValue(brightnessLevel); + m_volumeLabel->setText(QString::number(brightnessLevel) + " %"); +} + +void BrightnessOSDWidget::themeUpdated() +{ + //Set a font which makes the text appear as big (height-wise) as the meter. + //QFont font = QFont(m_volumeLabel->nativeWidget()->font()); + Plasma::Theme* theme = Plasma::Theme::defaultTheme(); + + + QPalette palette = m_volumeLabel->palette(); + palette.setColor(QPalette::WindowText, theme->color(Plasma::Theme::TextColor)); + m_volumeLabel->setPalette(palette); + + QFont font = theme->font(Plasma::Theme::DefaultFont); + font.setPointSize(15); + m_volumeLabel->setFont(font); + QFontMetrics qfm(font); + QRect textSize = qfm.boundingRect("100 % "); + + int widthHint = textSize.width(); + int heightHint = textSize.height(); + //setCurrentVolume(100,false); + m_volumeLabel->setMaximumHeight(heightHint); + m_volumeLabel->setMinimumWidth(widthHint); + m_volumeLabel->nativeWidget()->setFixedWidth(widthHint); + + //Cache the icon pixmaps + QFontMetrics fm(m_volumeLabel->font()); + QSize iconSize = QSize(fm.height(), fm.height()); + + if (m_type == PowerDevil::BackendInterface::Screen) { + m_brightnessPixmap = KIcon("video-display").pixmap(iconSize); + } else { + m_brightnessPixmap = KIcon("input-keyboard").pixmap(iconSize); + } + + m_iconLabel->nativeWidget()->setPixmap(m_brightnessPixmap); + m_iconLabel->nativeWidget()->setFixedSize(iconSize); + m_iconLabel->setMinimumSize(iconSize); + m_iconLabel->setMaximumSize(iconSize); + + m_meter->setMaximumHeight(iconSize.height()); + m_container->setMinimumSize(iconSize.width() * 13 + m_volumeLabel->nativeWidget()->width(), iconSize.height()); + m_container->setMaximumSize(iconSize.width() * 13 + m_volumeLabel->nativeWidget()->width(), iconSize.height()); + + syncToGraphicsWidget(); +} + + +#include "brightnessosdwidget.moc" diff --git a/powerdevil/daemon/brightnessosdwidget.h b/powerdevil/daemon/brightnessosdwidget.h new file mode 100644 index 00000000..40166d4a --- /dev/null +++ b/powerdevil/daemon/brightnessosdwidget.h @@ -0,0 +1,65 @@ +/******************************************************************* +* brightnessosdwidget.h +* adapted from kdemultimedia/kmix/osdwidget.h +* Copyright 2009 Aurélien Gâteau +* Copyright 2009 Dario Andres Rodriguez +* Copyright 2009 Christian Esken +* Copyright 2010 Felix Geyer +* +* 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, see . +* +******************************************************************/ + +#ifndef BRIGHTNESSOSDWIDGET__H +#define BRIGHTNESSOSDWIDGET__H + +#include "powerdevilbackendinterface.h" + +#include + +#include + +class QTimer; + +namespace Plasma +{ +class Label; +class Meter; +} + +class BrightnessOSDWidget : public Plasma::Dialog +{ +Q_OBJECT +public: + BrightnessOSDWidget(PowerDevil::BackendInterface::BrightnessControlType type, QWidget * parent = 0); + + void setCurrentBrightness(int brightnessLevel); + void activateOSD(); + +protected slots: + void themeUpdated(); + +private: + PowerDevil::BackendInterface::BrightnessControlType m_type; + QGraphicsScene *m_scene; + QGraphicsWidget *m_container; + Plasma::Label *m_iconLabel; + Plasma::Label *m_volumeLabel; + Plasma::Meter *m_meter; + QTimer *m_hideTimer; + + QPixmap m_brightnessPixmap; +}; + +#endif diff --git a/powerdevil/daemon/config-powerdevil.h.cmake b/powerdevil/daemon/config-powerdevil.h.cmake new file mode 100644 index 00000000..b730cd9f --- /dev/null +++ b/powerdevil/daemon/config-powerdevil.h.cmake @@ -0,0 +1,2 @@ +/* Defines if you have UDev */ +#cmakedefine HAVE_UDEV 1 diff --git a/powerdevil/daemon/kdedpowerdevil.cpp b/powerdevil/daemon/kdedpowerdevil.cpp new file mode 100644 index 00000000..4b363a78 --- /dev/null +++ b/powerdevil/daemon/kdedpowerdevil.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "kdedpowerdevil.h" + +#include "powerdevilfdoconnector.h" +#include "powermanagementadaptor.h" +#include "powermanagementpolicyagentadaptor.h" + +#include "powerdevilbackendloader.h" +#include "powerdevilcore.h" + +#include + +#include +#include + +#include +#include +#include + +K_PLUGIN_FACTORY( PowerDevilFactory, + registerPlugin(); ) +K_EXPORT_PLUGIN( PowerDevilFactory( "powerdevildaemon" ) ) + +#define POWERDEVIL_VERSION "1.99" + +KDEDPowerDevil::KDEDPowerDevil(QObject* parent, const QVariantList &) + : KDEDModule(parent) +{ + QTimer::singleShot(0, this, SLOT(init())); +} + +KDEDPowerDevil::~KDEDPowerDevil() +{ +} + +void KDEDPowerDevil::init() +{ + KGlobal::insertCatalog("powerdevil"); + + KAboutData aboutData("powerdevil", "powerdevil", ki18n("KDE Power Management System"), + POWERDEVIL_VERSION, ki18n("KDE Power Management System is PowerDevil, an " + "advanced, modular and lightweight Power Management " + "daemon"), + KAboutData::License_GPL, ki18n("(c) 2010 MetalWorkers Co."), + KLocalizedString(), "http://www.kde.org"); + + aboutData.addAuthor(ki18n( "Dario Freddi" ), ki18n("Maintainer"), "drf@kde.org", + "http://drfav.wordpress.com"); + + if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.PowerManagement") || + QDBusConnection::systemBus().interface()->isServiceRegistered("com.novell.powersave") || + QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.Policy.Power")) { + kError() << "KDE Power Management system not initialized, another power manager has been detected"; + return; + } + + m_core = new PowerDevil::Core(this, KComponentData(aboutData)); + + connect(m_core, SIGNAL(coreReady()), this, SLOT(onCoreReady())); + + // Before doing anything, let's set up our backend + PowerDevil::BackendInterface *interface = PowerDevil::BackendLoader::loadBackend(m_core); + + if (!interface) { + // Ouch + kError() << "KDE Power Management System init failed!"; + m_core->loadCore(0); + } else { + // Let's go! + kDebug() << "Backend loaded, loading core"; + m_core->loadCore(interface); + } +} + +void KDEDPowerDevil::onCoreReady() +{ + kDebug() << "Core is ready, registering various services on the bus..."; + //DBus logic for the core + new PowerManagementAdaptor(m_core); + new PowerDevil::FdoConnector(m_core); + + QDBusConnection::sessionBus().registerService("org.kde.Solid.PowerManagement"); + QDBusConnection::sessionBus().registerObject("/org/kde/Solid/PowerManagement", m_core); + + QDBusConnection::systemBus().interface()->registerService("org.freedesktop.Policy.Power"); + + // Start the Policy Agent service + new PowerManagementPolicyAgentAdaptor(PowerDevil::PolicyAgent::instance()); + + QDBusConnection::sessionBus().registerService("org.kde.Solid.PowerManagement.PolicyAgent"); + QDBusConnection::sessionBus().registerObject("/org/kde/Solid/PowerManagement/PolicyAgent", PowerDevil::PolicyAgent::instance()); +} + +#include "kdedpowerdevil.moc" diff --git a/powerdevil/daemon/kdedpowerdevil.h b/powerdevil/daemon/kdedpowerdevil.h new file mode 100644 index 00000000..137e6ca5 --- /dev/null +++ b/powerdevil/daemon/kdedpowerdevil.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 KDEDPOWERDEVIL_H +#define KDEDPOWERDEVIL_H + +#include +#include + +namespace PowerDevil { + class Core; +} + +class KDEDPowerDevil : public KDEDModule +{ + Q_OBJECT + Q_DISABLE_COPY(KDEDPowerDevil) + +public: + explicit KDEDPowerDevil(QObject* parent, const QVariantList &); + virtual ~KDEDPowerDevil(); + +private Q_SLOTS: + void init(); + void onCoreReady(); + +private: + PowerDevil::Core *m_core; +}; + +#endif // KDEDPOWERDEVIL_H diff --git a/powerdevil/daemon/org.kde.Solid.PowerManagement.xml b/powerdevil/daemon/org.kde.Solid.PowerManagement.xml new file mode 100644 index 00000000..e097dfce --- /dev/null +++ b/powerdevil/daemon/org.kde.Solid.PowerManagement.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/powerdevil/daemon/powerdevil.desktop b/powerdevil/daemon/powerdevil.desktop new file mode 100644 index 00000000..e1fa3e0b --- /dev/null +++ b/powerdevil/daemon/powerdevil.desktop @@ -0,0 +1,145 @@ +[Desktop Entry] +Type=Service +Icon=preferences-system-power-management +X-KDE-ServiceTypes=KDEDModule +X-KDE-Library=powerdevil +X-KDE-DBus-ModuleName=powerdevil +X-KDE-Kded-autoload=true +X-KDE-Kded-load-on-demand=false +X-KDE-Kded-phase=1 + +Name=Power Management +Name[ar]=إدارة الطاقة +Name[ast]=Xestión d'enerxía +Name[be@latin]=Kiravańnie enerhijaj +Name[bg]=Управление на захранването +Name[bn]=পাওয়ার ব্যবস্থাপনা +Name[bn_IN]=বিদ্যুৎ সরবরাহ পরিচালনা +Name[bs]=Upravljanje napajanjem +Name[ca]=Gestió d'energia +Name[ca@valencia]=Gestió d'energia +Name[cs]=Správa napájení +Name[csb]=Sprôwianié mòcą +Name[da]=Strømstyring +Name[de]=Energieverwaltung +Name[el]=Διαχείριση ενέργειας +Name[en_GB]=Power Management +Name[eo]=Energiadministrado +Name[es]=Gestión de energía +Name[et]=Toitehaldus +Name[eu]=Energia-kudeaketa +Name[fi]=Virranhallinta +Name[fr]=Gestion de l'énergie +Name[fy]=Enerzjybehear +Name[ga]=Bainisteoireacht Cumhachta +Name[gl]=Xestión da enerxía +Name[gu]=પાવર વ્યવસ્થાપક +Name[he]=ניהול צריכת חשמל +Name[hi]=बिज़ली प्रबंधन +Name[hne]=पावर प्रबंधन +Name[hr]=Upravljanje potrošnjom energije +Name[hu]=Energiakezelő +Name[ia]=Gestion de energia +Name[id]=Manajemen Daya +Name[is]=Orkustjórnun +Name[it]=Gestione energetica +Name[ja]=電源管理 +Name[kk]=Қуаттандыруды басқару +Name[km]=ការ​គ្រប់គ្រង​ថាមពល +Name[kn]=ವಿದ್ಯುಚ್ಛಕ್ತಿ ವ್ಯವಸ್ಥಾಪನೆ +Name[ko]=전원 관리 +Name[ku]=Gerînendeyê hêzê +Name[lt]=Energijos valdymas +Name[lv]=Energokontrole +Name[mai]=पावर मैनेजमेंट +Name[mk]=Менаџмент на енергија +Name[ml]=വൈദ്യുതി നടത്തിപ്പു് +Name[mr]=वीज व्यवस्थापन +Name[nb]=Strømstyring +Name[nds]=Stroomkuntrull +Name[nl]=Energiebeheer +Name[nn]=Straumstyring +Name[or]=ଶକ୍ତି ପରିଚାଳନା +Name[pa]=ਪਾਵਰ ਮੈਨਿਜਮੈਂਟ +Name[pl]=Zarządzanie energią +Name[pt]=Gestão de Energia +Name[pt_BR]=Gerenciamento de energia +Name[ro]=Gestiune energie +Name[ru]=Управление питанием +Name[si]=බල පරිපාලනය +Name[sk]=Správa napájania +Name[sl]=Upravljanje z energijo +Name[sr]=Управљање напајањем +Name[sr@ijekavian]=Управљање напајањем +Name[sr@ijekavianlatin]=Upravljanje napajanjem +Name[sr@latin]=Upravljanje napajanjem +Name[sv]=Strömsparhantering +Name[ta]=Power Management +Name[tg]=Идоракунии барқ +Name[th]=การจัดการพลังงาน +Name[tr]=Güç Yönetimi +Name[ug]=توك مەنبەسىنى باشقۇرۇش +Name[uk]=Керування живленням +Name[wa]=Manaedjmint di l' enerdjeye +Name[x-test]=xxPower Managementxx +Name[zh_CN]=电源管理 +Name[zh_TW]=電源管理 + +Comment=Battery, Display and CPU power management and notification +Comment[ar]=إدارة طاقة وإشعارات البطارية والشاشة والمعالج +Comment[ast]=Xestión y notificaciones d'enerxía de la batería, pantalla y CPU +Comment[bg]=Управление и уведомяване относно захранването на батерията, екрана и процесора +Comment[bs]=Obavještavanje i upravljanje baterijom i napajanjem ekrana i procesora +Comment[ca]=Gestió d'energia i notificació de la bateria, pantalla i CPU +Comment[ca@valencia]=Gestió d'energia i notificació de la bateria, pantalla i CPU +Comment[cs]=Správa a oznamování baterie, zobrazení a výkonu CPU +Comment[da]=Bekendtgørelser om strømstyring for batteri, skærm og CPU +Comment[de]=Akku-, Anzeige- und Prozessorleistungsverwaltung und -benachrichtigung +Comment[el]=Μπαταρία, Εμφάνιση και διαχείριση ενέργειας και ειδοποιήσεων ΚΜΕ +Comment[en_GB]=Battery, Display and CPU power management and notification +Comment[es]=Gestión y notificaciones de energía de la batería, pantalla y CPU +Comment[et]=Aku, monitori ja protsessori toitehaldus ja märguanded +Comment[eu]=Bateriaren, bistaratzearen eta PUZaren ahalmenaren kudeaketa eta jakinarazpenak +Comment[fi]=Akun, näytön ja suorittimen virranhallinta sekä ilmoitukset +Comment[fr]=Gestion et notifications de l'énergie pour les batteries, l'affichage et la consommation du processeur +Comment[gl]=Xestión e notificacións da xestión enerxética da batería, da pantalla e da CPU +Comment[he]=ניהול והודעות של צריכת החשמל של הסוללה, התצוגה והמעבד +Comment[hr]=Upravljanje potrošnjom energije baterije, ekrana i CPU-a i pripadajućim obavijestima. +Comment[hu]=Akkumulátor-, kijelző- és processzorkezelés és értesítés +Comment[ia]=Batteria, monstrator, gestion de energia de CPU e notification +Comment[id]=Baterai, Tampilan dan manajemen daya CPU dan notifikasi +Comment[is]=Stjórnun og tilkynningar vegna rafhlaðna, skjáa og örgjörva +Comment[ja]=バッテリ、ディスプレイ、CPU の電源管理と通知 +Comment[kk]=Батарея, дисплей, процесорын қуаттаныруын басқару және олs туралы құлақтандыру +Comment[km]=ថ្ម បង្ហាញ​ការ​ជូនដំណឹង និង​គ្រប់គ្រង​ថាមពល​ស៊ីភីយូ +Comment[ko]=배터리, 디스플레이, CPU 전원 관리 및 알림 +Comment[lt]=Baterijos, Monitoriaus ir CPU energijos valdymas ir pranešimai +Comment[lv]=Baterijas, ekrāna un procesora enerģijas pārvaldība un paziņojumi +Comment[mr]=बॅटरी, डिस्प्ले व CPU वीज व्यवस्थापन व सूचना +Comment[nb]=Håndtering og varsling for strømstyring av batteri, skjerm og prosessor +Comment[nds]=Batterie-, Schirm- un Perzesser-Stroomkuntrull un -Bescheden +Comment[nl]=Energiebeheer voor accu, scherm en CPU en meldingen +Comment[pa]=ਬੈਟਰੀ, ਡਿਸਪਲੇਅ ਤੇ CPU ਪਾਵਰ ਪਰਬੰਧ ਤੇ ਨੋਟੀਫਿਕੇਸ਼ਨ +Comment[pl]=Zarządzanie i powiadomienia o stanie baterii, wyświetlacza i zasilania procesora +Comment[pt]=Gestão e notificação da energia, do ecrã e do CPU +Comment[pt_BR]=Gerenciamento e notificação de energia, da tela e do CPU +Comment[ro]=Gestiune și notificări pentru acumulator, afișaj și putere procesor +Comment[ru]=Настройка яркости экрана, режима ожидания и питания +Comment[si]=බැටරි, ප්‍රදර්ශන සහ CPU බලශක්ති කළමනාකරනය සහ දැනුම්දීම +Comment[sk]=Správa napájania a upozornenia batérie, obrazovky a CPU +Comment[sl]=Upravljanje in obveščanje o porabi energije baterije, zaslona in procesorja +Comment[sr]=Обавештавање и управљање батеријом и напајањем екрана и процесора +Comment[sr@ijekavian]=Обавјештавање и управљање батеријом и напајањем екрана и процесора +Comment[sr@ijekavianlatin]=Obavještavanje i upravljanje baterijom i napajanjem ekrana i procesora +Comment[sr@latin]=Obaveštavanje i upravljanje baterijom i napajanjem ekrana i procesora +Comment[sv]=Hantering och underrättelser om batteri, skärm och processorkraft +Comment[tg]=Батарея, Экран ва идоракунии манбаъи CPU ва огоҳӣ +Comment[th]=การจัดการพลังงานของ แบตเตอรี่, ส่วนแสดงผล และซีพียู รวมถึงการแจ้งให้ทราบ +Comment[tr]=Pil, Ekran ve CPU güç yönetimi ve bildirimler +Comment[ug]=توكدان، ئېكران ۋە CPU توك مەنبە باشقۇرۇش ۋە ئۇقتۇرۇش +Comment[uk]=Керування та сповіщення про стан акумуляторів та живлення дисплея і процесора +Comment[vi]=Quản lý năng lượng và thông báo cho pin, màn hình và CPU +Comment[wa]=Manaedjmint eyet notifiaedje di l' enerdjeye del batreye, do håynaedje et do CPU +Comment[x-test]=xxBattery, Display and CPU power management and notificationxx +Comment[zh_CN]=电池、显示器和 CPU 电源管理及通知 +Comment[zh_TW]=電池、顯示與 CPU 電力管理與通知 diff --git a/powerdevil/daemon/powerdevilaction.cpp b/powerdevil/daemon/powerdevilaction.cpp new file mode 100644 index 00000000..f16394cc --- /dev/null +++ b/powerdevil/daemon/powerdevilaction.cpp @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevilaction.h" + +#include "powerdevilcore.h" + +#include + +namespace PowerDevil +{ + +class Action::Private +{ +public: + Private() {} + ~Private() {} + + PowerDevil::Core *core; + + QList< int > registeredIdleTimeouts; + PowerDevil::PolicyAgent::RequiredPolicies requiredPolicies; +}; + +Action::Action(QObject* parent) + : QObject(parent) + , d(new Private) +{ + d->core = qobject_cast(parent); +} + +Action::~Action() +{ + delete d; +} + +void Action::registerIdleTimeout(int msec) +{ + d->registeredIdleTimeouts.append(msec); + d->core->registerActionTimeout(this, msec); +} + +bool Action::unloadAction() +{ + // Remove all registered idle timeouts, if any + d->core->unregisterActionTimeouts(this); + d->registeredIdleTimeouts.clear(); + + // Ok, let's see if the action has to do something for being unloaded + return onUnloadAction(); +} + +bool Action::onUnloadAction() +{ + // Usually nothing has to be done, so let's just happily return true + return true; +} + +bool Action::isSupported() +{ + return true; +} + +BackendInterface* Action::backend() const +{ + return d->core->backend(); +} + +Core* Action::core() +{ + return d->core; +} + +void Action::trigger(const QVariantMap& args) +{ + if (args.contains("Explicit") && args["Explicit"].toBool()) { + // The action was explicitly triggered by the user, hence any policy check is bypassed. + triggerImpl(args); + } else { + // The action was taken automatically: let's check if we have the rights to do that + PolicyAgent::RequiredPolicies unsatisfiablePolicies = PolicyAgent::instance()->requirePolicyCheck(d->requiredPolicies); + if (unsatisfiablePolicies == PolicyAgent::None) { + // Ok, let's trigger the action + triggerImpl(args); + } else { + // TODO: Notify somehow? + kWarning() << "Unsatisfied policies, the action has been aborted"; + } + } +} + +void Action::setRequiredPolicies(PolicyAgent::RequiredPolicies requiredPolicies) +{ + d->requiredPolicies = requiredPolicies; +} + +} + +#include "powerdevilaction.moc" diff --git a/powerdevil/daemon/powerdevilaction.h b/powerdevil/daemon/powerdevilaction.h new file mode 100644 index 00000000..81249d47 --- /dev/null +++ b/powerdevil/daemon/powerdevilaction.h @@ -0,0 +1,234 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_POWERDEVILACTION_H +#define POWERDEVIL_POWERDEVILACTION_H + +#include "powerdevilpolicyagent.h" + +#include +#include + +#include + +class KConfigGroup; + +namespace PowerDevil +{ +class BackendInterface; +class Core; + +/** + * @brief The base class for Power Management Actions + * + * The Action class is the very base class for writing a new Power Management action. + * Developers wishing to implement their own action are supposed to subclass Action. + * + * @par Creating a brand new Action + * + * If you are already familiar with KDE's plugin system, you have to know that actions are + * nothing but a KService plugin which will be loaded on demand. Each action has an ID associated to it + * which represents it in the config file and uniquely identifies it in the loading phase. + * + * In addition to standard parameters, the .desktop file representing your action should contain the following + * entries: + * + * @code + * X-KDE-ServiceTypes=PowerDevil/Action + * X-KDE-PowerDevil-Action-ID=YourActionID + * X-KDE-PowerDevil-Action-IsBundled=false + * X-KDE-PowerDevil-Action-UIComponentLibrary=myactionplugin_config + * X-KDE-PowerDevil-Action-ConfigPriority=98 + * @endcode + * + * The @c UIComponentLibrary field refers to the library which contains the configuration UI + * for your action. Please see ActionConfig documentation for more details. + * + * The @c ConfigPriority is relevant to the configuration UI as well, and determines where your config UI will appear. + * The higher the number, the higher your config UI will be in the list of actions. Choose this value wisely: usually + * only very basic power management functions should have a value > 50. + * + * The most important functions you need to reimplement are loadAction and triggerImpl. The first is called + * whenever an action is loaded, carrying the action's configuration. The other is called whenever + * the action is triggered. You usually want to process the action here as triggerImpl is guaranteed + * to be called just when policies are satisfied. + * + * @par Runtime requirements + * + * Some actions might be available only when the system satisfies certain hardware or software runtime requirements. + * In this case, powerdevil provides a way for the action to advertise to the outside whether it is supported or + * not. This can be done by reimplementing @c isSupported and adding to the .desktop file the field + * + * @code + * X-KDE-PowerDevil-Action-HasRuntimeRequirement=true + * @endcode + * + * Done that, powerdevil will take care of exposing your action only if support for it is advertised. In addition, + * the UI will expose the configuration of your action only if its support is advertised. Of course, this means the + * action will be temporarily loaded by the config UI to verify its support. If your action is performing some tasks in + * the constructor besides setting policies, first of all revise your design since you probably don't need or want to + * do that. If you really cannot avoid that, you MUST check for an OPTIONAL parameter in the QVariantList coming + * from the plugin's constructor. If it exists, it's a boolean and it is true, the action is being loaded just for + * a support check, and you should refrain from doing any actions which would affect the system. This parameter is also + * used in tests. + * + * @par Handling policies from within the action + * + * As you might know, the KDE Power Management system features a very efficient policy handler, which + * prevents Power Management actions when certain condition occurs. The integration with Actions is very easy: + * in your Action's constructor, you want to call setRequiredPolicies, stating which policies have to be + * satisfied to perform the action. For example, if your action should not be performed whenever the session + * cannot be interrupted, you would pass @c InterruptSession. + * + * Done that, your action is already obeying to the policy. trigger, in fact, calls triggerImpl just when + * the policies are allowing your action to be performed. + * + * @since 4.6 + */ +class KDE_EXPORT Action : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(Action) + +public: + /** + * Default constructor + */ + explicit Action(QObject *parent); + /** + * Default destructor + */ + virtual ~Action(); + + /** + * Reimplement this function when creating a new Action. This function is called whenever the action is loaded or + * its configuration changes. It carries the KConfigGroup associated with your action and generated from your + * config interface. + * + * @param config The action's configuration which should be loaded. + * @returns Whether the action has been successfully loaded. + * + * @see ActionConfig + */ + virtual bool loadAction(const KConfigGroup &config) = 0; + /** + * Unloads the action. You usually shouldn't reimplement this function: reimplement onUnloadAction instead. + * + * @returns Whether the action has been successfully unloaded + */ + virtual bool unloadAction(); + + /** + * This function is meant to find out if this action is available on this system. Actions + * CAN reimplement this function if they are dependent on specific hardware/software requirements. + * By default, this function will always return true. + * + * Should this function return false, the core will delete and ignore the action right after creation. + * + * @returns Whether this action is supported or not by the current system + */ + virtual bool isSupported(); + + /** + * Triggers the action with the given argument. This function is meant to be used by the caller only - + * if you are implementing your own action, reimplement triggerImpl instead. + * + * @param args The arguments for triggering the action + */ + void trigger(const QVariantMap &args); + +protected: + /** + * Registers an idle timeout for this action. Call this function and not KIdleTime directly to take advantage + * of Action's automated handling of idle timeouts. Also, please reimplement onIdleTimeout instead of listening + * to KIdleTime's signals to catch idle timeout events. + * + * @param msec The idle timeout to be registered in milliseconds. + */ + void registerIdleTimeout(int msec); + /** + * Sets the required policies needed for this Action to run. Usually, you want to call this function in your + * Action's constructor. + * + * @param requiredPolicies A set of policies which are required to run this action. It can be empty if your + * Action does not rely on policies. + */ + void setRequiredPolicies(PowerDevil::PolicyAgent::RequiredPolicies requiredPolicies); + + /** + * This function's body should undertake the Action's execution. It has to be reimplemented in a new Action. + * + * @param args The arguments for triggering the action + */ + virtual void triggerImpl(const QVariantMap &args) = 0; + + /** + * @returns The BackendInterface + */ + PowerDevil::BackendInterface *backend() const; + /** + * @returns The PowerDevil Core + */ + PowerDevil::Core *core(); + +protected Q_SLOTS: + /** + * This function is called whenever a profile is loaded. Please note that this is slightly different from + * loadAction: in fact a profile can be reloaded without having the action change its configuration. + * If your action should do something as soon as a profile switches, it should be done inside this function. + */ + virtual void onProfileLoad() = 0; + /** + * This slot is triggered whenever an idle timeout registered with registerIdleTimeout is reached. + * + * @param msec The idle timeout reached in milliseconds + */ + virtual void onIdleTimeout(int msec) = 0; + /** + * This slot is triggered whenever the PC wakes up from an Idle state. It is @b always called after a registered + * idle timeout has been reached. + */ + virtual void onWakeupFromIdle() = 0; + /** + * This function is called when the profile is unloaded. + */ + virtual void onProfileUnload() = 0; + /** + * This function is called when the action is unloaded. You usually want to put what would have gone in your + * destructor here. + * + * @returns Whether the action was unloaded successfully. + */ + virtual bool onUnloadAction(); + +Q_SIGNALS: + void actionTriggered(bool result, const QString &error = QString()); + +private: + class Private; + Private * const d; + + friend class Core; + friend class ActionPool; +}; + +} + +#endif // POWERDEVIL_POWERDEVILACTION_H diff --git a/powerdevil/daemon/powerdevilactionconfig.cpp b/powerdevil/daemon/powerdevilactionconfig.cpp new file mode 100644 index 00000000..51b1d946 --- /dev/null +++ b/powerdevil/daemon/powerdevilactionconfig.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevilactionconfig.h" + +namespace PowerDevil +{ + +class ActionConfig::Private +{ +public: + KConfigGroup config; +}; + +ActionConfig::ActionConfig(QObject *parent) + : QObject(parent) + , d(new Private) +{ + +} + +ActionConfig::~ActionConfig() +{ + delete d; +} + +KConfigGroup ActionConfig::configGroup() const +{ + return d->config; +} + +void ActionConfig::setConfigGroup(const KConfigGroup& group) +{ + d->config = group; +} + +void ActionConfig::setChanged() +{ + emit changed(); +} + +} + +#include "powerdevilactionconfig.moc" diff --git a/powerdevil/daemon/powerdevilactionconfig.h b/powerdevil/daemon/powerdevilactionconfig.h new file mode 100644 index 00000000..a114b65a --- /dev/null +++ b/powerdevil/daemon/powerdevilactionconfig.h @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_POWERDEVILACTIONCONFIG_H +#define POWERDEVIL_POWERDEVILACTIONCONFIG_H + +#include + +#include + +#include + +namespace PowerDevil { + +/** + * @brief The base class for Action's config interfaces + * + * This class should be reimplemented when creating a new Action. It is used to generate + * a configuration UI for your action and integrate it into KDE Power Management System's + * config module seamlessly. + * + * @par Creating an ActionConfig + * + * If you already have been through creating an Action, you have seen that Action's desktop + * file contains already all the needed information for loading its respective ActionConfig. For this + * reason, despite ActionConfig being a plugin, you do not need to create a desktop file for it - + * you just have to write the correct info into the Action's one. + * + * @par The key/value pair rationale + * + * The config UI works in a key/value fashion, where value is a generic QWidget. This is done + * to keep the UI consistent without hurting the flexibility of the implementation. + * Please remember to keep the configuration as easy and essential as possible: if you have gone + * beyond 2 rows, you might be doing something wrong. + * + * @par Loading and saving configuration + * + * Of course, you should also be providing the logic for saving and loading your action's configuration. + * This is done through KConfigGroup: your action has a KConfigGroup assigned by KDE Power Management System + * which can be accessed through configGroup or overwritten through setConfigGroup. The very same group + * you are loading/saving here will be the one passed to Action::loadAction. + * + * @see Action + * + * @since 4.6 + */ +class KDE_EXPORT ActionConfig : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(ActionConfig) + +public: + /** + * Default constructor + */ + ActionConfig(QObject *parent); + /** + * Default destructor + */ + virtual ~ActionConfig(); + + /** + * @returns The KConfigGroup associated to this action, where data should be saved (and loaded) + * + * @note You should not track this KConfigGroup, as it might change from profile to profile. + * Always use this function to access it. + */ + KConfigGroup configGroup() const; + /** + * Overwrites the config group associated with this Action with @c group. + * + * @param group A KConfigGroup carrying the settings for this Action. + */ + void setConfigGroup(const KConfigGroup &group); + + /** + * This function should return the key/value pairs containing your Action's configuration UI. + * + * @returns A list of QString, QWidget pairs representing your Action's configuration UI + */ + virtual QList< QPair< QString, QWidget* > > buildUi() = 0; + + /** + * This function gets called whenever the parent module requires to load a specific configuration. This + * usually occurs when @c configGroup is updated, for example due to the fact that the user wants to modify + * a different profile. In this function, you should update the info contained in the widgets generated + * by @c buildUi accordingly. + */ + virtual void load() = 0; + /** + * This function gets called whenever the parent module requires to save the configuration. Usually, you + * want to read values from the widgets generated with @c buildUi and call @c setConfigGroup to update the + * Action's configuration. + */ + virtual void save() = 0; + +protected Q_SLOTS: + /** + * Call this slot whenever the user makes some changes to the widgets. + */ + void setChanged(); + +Q_SIGNALS: + /** + * This signal gets emitted every time the user changes the (unsaved) configuration. Do not emit this signal + * directly: call setChanged instead. + * + * @see setChanged + */ + void changed(); + +private: + class Private; + Private * const d; +}; + +} + +#endif // POWERDEVIL_POWERDEVILACTIONCONFIG_H diff --git a/powerdevil/daemon/powerdevilactionpool.cpp b/powerdevil/daemon/powerdevilactionpool.cpp new file mode 100644 index 00000000..970aa18a --- /dev/null +++ b/powerdevil/daemon/powerdevilactionpool.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevilactionpool.h" + +#include "powerdevilaction.h" +#include "powerdevilcore.h" + +#include +#include +#include +#include +#include + +#include + +// Bundled actions: +#include "actions/bundled/suspendsession.h" +#include "actions/bundled/brightnesscontrol.h" +#include "actions/bundled/keyboardbrightnesscontrol.h" +#include "actions/bundled/dimdisplay.h" +#include "actions/bundled/runscript.h" +#include "actions/bundled/handlebuttonevents.h" + +namespace PowerDevil +{ + +class ActionPoolHelper +{ +public: + ActionPoolHelper() : q(0) {} + ~ActionPoolHelper() { + delete q; + } + ActionPool *q; +}; + +K_GLOBAL_STATIC(ActionPoolHelper, s_globalActionPool) + +ActionPool *ActionPool::instance() +{ + if (!s_globalActionPool->q) { + new ActionPool; + } + + return s_globalActionPool->q; +} + +ActionPool::ActionPool() +{ + Q_ASSERT(!s_globalActionPool->q); + s_globalActionPool->q = this; +} + +ActionPool::~ActionPool() +{ + clearCache(); +} + +void ActionPool::clearCache() +{ + QHash< QString, Action* >::iterator i = m_actionPool.begin(); + while (i != m_actionPool.end()) { + // Delete the associated action and erase + i.value()->deleteLater(); + i = m_actionPool.erase(i); + } +} + +void ActionPool::init(PowerDevil::Core *parent) +{ + // Load all the actions + KService::List offers = KServiceTypeTrader::self()->query("PowerDevil/Action", + "[X-KDE-PowerDevil-Action-IsBundled] == FALSE"); + foreach (KService::Ptr offer, offers) { + QString actionId = offer->property("X-KDE-PowerDevil-Action-ID", QVariant::String).toString(); + + kDebug() << "Got a valid offer for " << actionId; + //try to load the specified library + PowerDevil::Action *retaction = offer->createInstance< PowerDevil::Action >(parent); + + if (!retaction) { + // Troubles... + kWarning() << "failed to load" << offer->desktopEntryName(); + continue; + } + + // Is the action available and supported? + if (!retaction->isSupported()) { + // Skip that + retaction->deleteLater(); + continue; + } + + // Insert + m_actionPool.insert(actionId, retaction); + } + + // Load bundled actions now + m_actionPool.insert("SuspendSession", new BundledActions::SuspendSession(parent)); + m_actionPool.insert("BrightnessControl", new BundledActions::BrightnessControl(parent)); + m_actionPool.insert("KeyboardBrightnessControl", new BundledActions::KeyboardBrightnessControl(parent)); + m_actionPool.insert("DimDisplay", new BundledActions::DimDisplay(parent)); + m_actionPool.insert("RunScript", new BundledActions::RunScript(parent)); + m_actionPool.insert("HandleButtonEvents", new BundledActions::HandleButtonEvents(parent)); + + // Verify support + QHash::iterator i = m_actionPool.begin(); + while (i != m_actionPool.end()) { + Action *action = i.value(); + if (!action->isSupported()) { + i = m_actionPool.erase(i); + action->deleteLater(); + } else { + ++i; + } + } + + // Register DBus objects + { + KService::List offers = KServiceTypeTrader::self()->query("PowerDevil/Action", + "[X-KDE-PowerDevil-Action-RegistersDBusInterface] == TRUE"); + foreach (KService::Ptr offer, offers) { + QString actionId = offer->property("X-KDE-PowerDevil-Action-ID", QVariant::String).toString(); + + if (m_actionPool.contains(actionId)) { + QDBusConnection::sessionBus().registerObject("/org/kde/Solid/PowerManagement/Actions/" + actionId, m_actionPool[actionId]); + } + } + } +} + +Action* ActionPool::loadAction(const QString& actionId, const KConfigGroup& group, PowerDevil::Core *parent) +{ + Q_UNUSED(parent); + // Let's retrieve the action + if (m_actionPool.contains(actionId)) { + Action *retaction = m_actionPool[actionId]; + + if (group.isValid()) { + + if (m_activeActions.contains(actionId)) { + // We are reloading the action: let's unload it first then. + retaction->onProfileUnload(); + retaction->unloadAction(); + m_activeActions.removeOne(actionId); + } + + retaction->loadAction(group); + m_activeActions.append(actionId); + } + + return retaction; + } else { + // Hmm... troubles in configuration. Np, let's just return 0 and let the core handle this + return 0; + } +} + +void ActionPool::unloadAllActiveActions() +{ + foreach (const QString &action, m_activeActions) { + m_actionPool[action]->onProfileUnload(); + m_actionPool[action]->unloadAction(); + } + m_activeActions.clear(); +} + +} diff --git a/powerdevil/daemon/powerdevilactionpool.h b/powerdevil/daemon/powerdevilactionpool.h new file mode 100644 index 00000000..ca436ffc --- /dev/null +++ b/powerdevil/daemon/powerdevilactionpool.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_POWERDEVILACTIONPOOL_H +#define POWERDEVIL_POWERDEVILACTIONPOOL_H + +#include +#include + +#include + +class KConfigGroup; +namespace PowerDevil +{ + +class Core; +class Action; + +class KDE_EXPORT ActionPool +{ +public: + static ActionPool *instance(); + + virtual ~ActionPool(); + + void init(PowerDevil::Core *parent); + + Action *loadAction(const QString &actionId, const KConfigGroup &group, PowerDevil::Core *parent); + + void unloadAllActiveActions(); + + void clearCache(); + +private: + ActionPool(); + + QHash< QString, Action* > m_actionPool; + QStringList m_activeActions; +}; + +} + +#endif // POWERDEVIL_POWERDEVILACTIONPOOL_H diff --git a/powerdevil/daemon/powerdevilbackendinterface.cpp b/powerdevil/daemon/powerdevilbackendinterface.cpp new file mode 100644 index 00000000..0634499e --- /dev/null +++ b/powerdevil/daemon/powerdevilbackendinterface.cpp @@ -0,0 +1,180 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevilbackendinterface.h" + +namespace PowerDevil +{ + +class BackendInterface::Private +{ +public: + Private() : batteryRemainingTime(0), isReady(false), isError(false), isLidClosed(false) {} + ~Private() {} + + AcAdapterState acAdapterState; + qulonglong batteryRemainingTime; + BatteryState batteryState; + QHash< BrightnessControlType, float > brightness; + BrightnessControlsList brightnessControlsAvailable; + Capabilities capabilities; + SuspendMethods suspendMethods; + QString errorString; + bool isReady; + bool isError; + bool isLidClosed; + QHash< QString, uint > capacities; + QList< RecallNotice > recallNotices; +}; + +BackendInterface::BackendInterface(QObject* parent) + : QObject(parent) + , d(new Private) +{ +} + +BackendInterface::~BackendInterface() +{ + delete d; +} + +BackendInterface::AcAdapterState BackendInterface::acAdapterState() const +{ + return d->acAdapterState; +} + +qulonglong BackendInterface::batteryRemainingTime() const +{ + return d->batteryRemainingTime; +} + +BackendInterface::BatteryState BackendInterface::batteryState() const +{ + return d->batteryState; +} + +float BackendInterface::brightness(BackendInterface::BrightnessControlType type) const +{ + return d->brightness[type]; +} + +BackendInterface::BrightnessControlsList BackendInterface::brightnessControlsAvailable() const +{ + return d->brightnessControlsAvailable; +} + +QHash< QString, uint > BackendInterface::capacities() const +{ + return d->capacities; +} + +QList< BackendInterface::RecallNotice > BackendInterface::recallNotices() const +{ + return d->recallNotices; +} + +BackendInterface::SuspendMethods BackendInterface::supportedSuspendMethods() const +{ + return d->suspendMethods; +} + +bool BackendInterface::isLidClosed() const +{ + return d->isLidClosed; +} + +void BackendInterface::setAcAdapterState(PowerDevil::BackendInterface::AcAdapterState state) +{ + d->acAdapterState = state; + emit acAdapterStateChanged(state); +} + +void BackendInterface::setBackendHasError(const QString& errorDetails) +{ + Q_UNUSED(errorDetails) +} + +void BackendInterface::setBackendIsReady(BrightnessControlsList availableBrightnessControls, + BackendInterface::SuspendMethods supportedSuspendMethods) +{ + d->brightnessControlsAvailable = availableBrightnessControls; + d->suspendMethods = supportedSuspendMethods; + d->isReady = true; + + emit backendReady(); +} + +void BackendInterface::setBatteryRemainingTime(qulonglong time) +{ + if (d->batteryRemainingTime != time) { + d->batteryRemainingTime = time; + emit batteryRemainingTimeChanged(time); + } +} + +void BackendInterface::setBatteryState(PowerDevil::BackendInterface::BatteryState state) +{ + d->batteryState = state; + emit batteryStateChanged(state); +} + +void BackendInterface::setButtonPressed(PowerDevil::BackendInterface::ButtonType type) +{ + if (type == LidClose) { + d->isLidClosed = true; + } else if (type == LidOpen) { + d->isLidClosed = false; + } + emit buttonPressed(type); +} + +void BackendInterface::setCapacityForBattery(const QString& batteryId, uint percent) +{ + d->capacities.insert(batteryId, percent); +} + +void BackendInterface::setRecallNotices(const QList< BackendInterface::RecallNotice >& notices) +{ + d->recallNotices = notices; +} + +void BackendInterface::onBrightnessChanged(BackendInterface::BrightnessControlType device, float brightness) +{ + d->brightness[device] = brightness; + emit brightnessChanged(brightness, device); +} + +void BackendInterface::setResumeFromSuspend() +{ + emit resumeFromSuspend(); +} + +BackendInterface::Capabilities BackendInterface::capabilities() const +{ + return d->capabilities; +} + +void BackendInterface::setCapabilities(BackendInterface::Capabilities capabilities) +{ + d->capabilities = capabilities; +} + +} + +#include "powerdevilbackendinterface.moc" diff --git a/powerdevil/daemon/powerdevilbackendinterface.h b/powerdevil/daemon/powerdevilbackendinterface.h new file mode 100644 index 00000000..911c25a4 --- /dev/null +++ b/powerdevil/daemon/powerdevilbackendinterface.h @@ -0,0 +1,327 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BACKENDINTERFACE_H +#define POWERDEVIL_BACKENDINTERFACE_H + +#include +#include + +#include + +class KJob; + +namespace PowerDevil { + +class KDE_EXPORT BackendInterface : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(BackendInterface) + +public: + explicit BackendInterface(QObject* parent = 0); + virtual ~BackendInterface(); + + /** + * This enum type defines the different states of the system battery. + * + * - NoBatteryState: No battery available + * - Normal: The battery is at its normal charge level + * - Warning: The battery is at its warning charge level + * - Low: The battery is at its low charge level + * - Critical: The battery is at its critical charge level + */ + enum BatteryState{ NoBatteryState, Normal, Warning, Low, Critical }; + + /** + * This enum type defines the different states of the AC adapter. + * + * - UnknownAcAdapterState: The AC adapter has an unknown state + * - Plugged: The AC adapter is plugged + * - Unplugged: The AC adapter is unplugged + */ + enum AcAdapterState{ UnknownAcAdapterState, Plugged, Unplugged }; + + /** + * This enum type defines the types of system button events. + * + * - UnknownButtonType: An unknown button + * - PowerButton: A power button pressed event, generally used to turn on or off the system + * - SleepButton: A sleep button pressed event, generally used to make the system asleep + * - LidOpen: A laptop lid open event + * - LidClose: A laptop lid close event + */ + enum ButtonType{ UnknownButtonType, PowerButton, SleepButton, LidOpen, LidClose, HibernateButton }; + + /** + * This enum type defines the different suspend methods. + * + * - UnknownSuspendMethod: The name says it all + * - Standby: Processes are stopped, some hardware is deactivated (ACPI S1) + * - ToRam: Most devices are deactivated, only RAM is powered (ACPI S3) + * - ToDisk: State of the machine is saved to disk, and it's powered down (ACPI S4) + */ + enum SuspendMethod{ UnknownSuspendMethod = 0, Standby = 1, ToRam = 2, ToDisk = 4, HybridSuspend = 8 }; + + /** + * This type stores an OR combination of SuspendMethod values. + */ + Q_DECLARE_FLAGS(SuspendMethods, SuspendMethod) + + /** + * This enum defines the different types of brightness controls. + * + * - UnknownBrightnessControl: Unknown + * - Screen: Brightness control for a monitor or laptop panel + * - Keyboard: Brightness control for a keyboard backlight + */ + enum BrightnessControlType{ UnknownBrightnessControl = 0, Screen = 1, Keyboard = 2 }; + + typedef QHash BrightnessControlsList; + + /** + * This enum defines the different types brightness keys. + * + * - Increase: Key to increase brightness (Qt::Key_MonBrightnessUp or Qt::Key_KeyboardBrightnessUp) + * - Decrease: Key to decrease brightness (Qt::Key_MonBrightnessDown or Qt::Key_KeyboardBrightnessDown) + * - Toggle: Key to toggle backlight (Qt::Key_KeyboardBacklightOnOff) + */ + enum BrightnessKeyType{ Increase, Decrease, Toggle }; + + /** + * This enum defines capabilities of the backend + * + * - SignalResumeFromSuspend: The backend is able to stream the @c resumeFromSuspend signal accurately + */ + enum Capability { NoCapabilities = 0, SignalResumeFromSuspend = 1 }; + + Q_DECLARE_FLAGS(Capabilities, Capability) + + /** + * This struct contains information for a recall notice from the vendor + */ + struct RecallNotice { + /** The battery uuid */ + QString batteryId; + /** The vendor's name */ + QString vendor; + /** The vendor's website */ + QString url; + }; + + /** + * Initializes the backend. This function @b MUST be called before the backend is usable. Using + * any method in BackendInterface without initializing it might lead to undefined behavior. The signal + * @c backendReady or @c backendError will be streamed upon completion. + * + * @note Backend implementations @b MUST reimplement this function + */ + virtual void init() = 0; + + /** + * @returns the capabilities of the backend + * @see PowerDevil::BackendInterface::Capability + */ + Capabilities capabilities() const; + + /** + * Retrieves the current state of the system battery. + * + * @return the current battery state + * @see PowerDevil::BackendInterface::BatteryState + */ + BatteryState batteryState() const; + + /** + * Retrieves the current estimated remaining time of the system batteries + * + * @return the current global estimated remaining time in milliseconds + */ + qulonglong batteryRemainingTime() const; + + /** + * Retrieves the current state of the system AC adapter. + * + * @return the current AC adapter state + * @see PowerDevil::BackendInterface::AcAdapterState + */ + AcAdapterState acAdapterState() const; + + + /** + * Retrieves the set of suspend methods supported by the system. + * + * @return the suspend methods supported by this system + * @see PowerDevil::BackendInterface::SuspendMethod + * @see PowerDevil::BackendInterface::SuspendMethods + */ + SuspendMethods supportedSuspendMethods() const; + + /** + * Requests a suspend of the system. + * + * @param method the suspend method to use + * @return the job handling the operation + */ + virtual KJob *suspend(SuspendMethod method) = 0; + + /** + * Checks if brightness controls are enabled on this system. + * + * @return a list of the devices available to control + */ + BrightnessControlsList brightnessControlsAvailable() const; + + /** + * Gets the screen brightness. + * + * @param device the name of the device that you would like to control + * @return the brightness of the device, as a percentage + */ + virtual float brightness(BrightnessControlType type = Screen) const; + + /** + * @returns whether the lid is closed or not. + */ + bool isLidClosed() const; + + /** + * Sets the screen brightness. + * + * @param brightness the desired screen brightness, as a percentage + * @param device the name of the device that you would like to control + * @return true if the brightness change succeeded, false otherwise + */ + virtual bool setBrightness(float brightness, BrightnessControlType type = Screen) = 0; + + /** + * Should be called when the user presses a brightness key. + * + * @param type the type of the brightness key press + * @see PowerDevil::BackendInterface::BrightnessKeyType + */ + virtual void brightnessKeyPressed(BrightnessKeyType type, BrightnessControlType controlType = Screen) = 0; + + /** + * Retrieves the capacities of the installed batteries in percentage. + * + * @returns A dictionary with the battery's capacity percentage mapped to the battery uuid. + */ + QHash< QString, uint > capacities() const; + + /** + * Returns a list of recall notices, if available + * + * @return a list of recall notices + * @see PowerDevil::BackendInterface::RecallNotice + */ + QList< RecallNotice > recallNotices() const; + +Q_SIGNALS: + /** + * This signal is emitted when the AC adapter is plugged or unplugged. + * + * @param newState the new state of the AC adapter, it's one of the + * type @see PowerDevil::BackendInterface::AcAdapterState + */ + void acAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState newState); + + /** + * This signal is emitted when the system battery state changed. + * + * @param newState the new state of the system battery, it's one of the + * type @see PowerDevil::BackendInterface::BatteryState + */ + void batteryStateChanged(PowerDevil::BackendInterface::BatteryState newState); + + /** + * This signal is emitted when a button has been pressed. + * + * @param buttonType the pressed button type, it's one of the + * type @see PowerDevil::BackendInterface::ButtonType + */ + void buttonPressed(PowerDevil::BackendInterface::ButtonType buttonType); + + /** + * This signal is emitted when the brightness changes. + * + * @param brightness the new brightness level + */ + void brightnessChanged(float brightness, PowerDevil::BackendInterface::BrightnessControlType type); + + /** + * This signal is emitted when the estimated battery remaining time changes. + * + * @param time the new remaining time + */ + void batteryRemainingTimeChanged(qulonglong time); + + /** + * This signal is emitted when the backend is ready to be used + * + * @see init + */ + void backendReady(); + + /** + * This signal is emitted if the backend could not be initialized + * + * @param error Details about the error occurred + * @see init + */ + void backendError(const QString &error); + + /** + * This signal is emitted when the PC is resuming from suspension + */ + void resumeFromSuspend(); + +protected: + void setCapabilities(Capabilities capabilities); + + void onBrightnessChanged(BrightnessControlType device, float brightness); + void setBatteryRemainingTime(qulonglong time); + void setButtonPressed(PowerDevil::BackendInterface::ButtonType type); + void setBatteryState(PowerDevil::BackendInterface::BatteryState state); + void setAcAdapterState(PowerDevil::BackendInterface::AcAdapterState state); + + void setCapacityForBattery(const QString &batteryId, uint percent); + void setRecallNotices(const QList< RecallNotice > ¬ices); + + void setBackendIsReady(BrightnessControlsList availableBrightnessControls, SuspendMethods supportedSuspendMethods); + void setBackendHasError(const QString &errorDetails); + +protected slots: + // This function is actually here due to HAL + void setResumeFromSuspend(); + +private: + class Private; + Private * const d; + + friend class Core; +}; + +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(PowerDevil::BackendInterface::Capabilities) +Q_DECLARE_OPERATORS_FOR_FLAGS(PowerDevil::BackendInterface::SuspendMethods) + +#endif // POWERDEVIL_BACKENDINTERFACE_H diff --git a/powerdevil/daemon/powerdevilbackendloader.cpp b/powerdevil/daemon/powerdevilbackendloader.cpp new file mode 100644 index 00000000..8259a136 --- /dev/null +++ b/powerdevil/daemon/powerdevilbackendloader.cpp @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevilbackendloader.h" + +#ifdef HAVE_UDEV +#include "backends/upower/powerdevilupowerbackend.h" +#endif +#include "backends/hal/powerdevilhalbackend.h" + +#include + +namespace PowerDevil { +namespace BackendLoader { + +BackendInterface* loadBackend(QObject *parent) +{ +#ifdef HAVE_UDEV + // Check UPower first + kDebug() << "Loading UPower backend..."; + if (PowerDevilUPowerBackend::isAvailable()) { + kDebug() << "Success!"; + return new PowerDevilUPowerBackend(parent); + } + + kDebug() << "Failed!"; +#endif + + // If we are here, try HAL + kDebug() << "Loading HAL backend..."; + if (PowerDevilHALBackend::isAvailable()) { + kDebug() << "Success!"; + return new PowerDevilHALBackend(parent); + } + + // Fail... + kDebug() << "Failed!"; + return 0; +} + +} +} + diff --git a/powerdevil/daemon/powerdevilbackendloader.h b/powerdevil/daemon/powerdevilbackendloader.h new file mode 100644 index 00000000..5cd60be5 --- /dev/null +++ b/powerdevil/daemon/powerdevilbackendloader.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_BACKENDLOADER_H +#define POWERDEVIL_BACKENDLOADER_H + +class QObject; +namespace PowerDevil { + +class BackendInterface; + + +namespace BackendLoader +{ + BackendInterface *loadBackend(QObject *parent); +} + +} + +#endif // POWERDEVIL_POWERDEVILBACKENDLOADER_H diff --git a/powerdevil/daemon/powerdevilcore.cpp b/powerdevil/daemon/powerdevilcore.cpp new file mode 100644 index 00000000..d096d748 --- /dev/null +++ b/powerdevil/daemon/powerdevilcore.cpp @@ -0,0 +1,730 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevilcore.h" + +#include "PowerDevilSettings.h" +#include "screensaver_interface.h" + +#include "powerdevilaction.h" +#include "powerdevilactionpool.h" +#include "powerdevilbackendinterface.h" +#include "powerdevilpolicyagent.h" +#include "powerdevilprofilegenerator.h" + +#include "daemon/actions/bundled/suspendsession.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace PowerDevil +{ + +Core::Core(QObject* parent, const KComponentData &componentData) + : QObject(parent) + , m_backend(0) + , m_applicationData(componentData) + , m_criticalBatteryTimer(new QTimer(this)) + , m_activityConsumer(new KActivities::Consumer(this)) + , m_pendingWakeupEvent(true) +{ +} + +Core::~Core() +{ + // Unload all actions before exiting, and clear the cache + ActionPool::instance()->unloadAllActiveActions(); + ActionPool::instance()->clearCache(); +} + +void Core::loadCore(BackendInterface* backend) +{ + if (!backend) { + onBackendError(i18n("No valid Power Management backend plugins are available. " + "A new installation might solve this problem.")); + return; + } + + m_backend = backend; + + // Async backend init - so that KDED gets a bit of a speed up + kDebug() << "Core loaded, initializing backend"; + connect(m_backend, SIGNAL(backendReady()), this, SLOT(onBackendReady())); + connect(m_backend, SIGNAL(backendError(QString)), this, SLOT(onBackendError(QString))); + m_backend->init(); + + // Register DBus Metatypes + qDBusRegisterMetaType< StringStringMap >(); +} + +void Core::onBackendReady() +{ + kDebug() << "Backend is ready, KDE Power Management system initialized"; + + m_profilesConfig = KSharedConfig::openConfig("powermanagementprofilesrc", KConfig::CascadeConfig); + + // Is it brand new? + if (m_profilesConfig->groupList().isEmpty()) { + // Generate defaults + bool toRam = m_backend->supportedSuspendMethods() & PowerDevil::BackendInterface::ToRam; + bool toDisk = m_backend->supportedSuspendMethods() & PowerDevil::BackendInterface::ToDisk; + if (ProfileGenerator::generateProfiles(toRam, toDisk, true) == ProfileGenerator::ResultUpgraded) { + // Notify the user + emitNotification("warningnot", i18n("Your Power Profiles have been updated to be used with the new KDE Power " + "Management System. You can tweak them or generate a new set of defaults from " + "System Settings."), "system-software-update"); + } + m_profilesConfig->reparseConfiguration(); + } + + // Get the battery devices ready + { + using namespace Solid; + connect(DeviceNotifier::instance(), SIGNAL(deviceAdded(QString)), + this, SLOT(onDeviceAdded(QString))); + connect(DeviceNotifier::instance(), SIGNAL(deviceRemoved(QString)), + this, SLOT(onDeviceRemoved(QString))); + + // Force the addition of already existent batteries + foreach (const Device &device, Device::listFromType(DeviceInterface::Battery, QString())) { + onDeviceAdded(device.udi()); + } + } + + connect(m_backend, SIGNAL(acAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState)), + this, SLOT(onAcAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState))); + connect(m_backend, SIGNAL(batteryRemainingTimeChanged(qulonglong)), + this, SLOT(onBatteryRemainingTimeChanged(qulonglong))); + connect(KIdleTime::instance(), SIGNAL(timeoutReached(int,int)), + this, SLOT(onKIdleTimeoutReached(int,int))); + connect(KIdleTime::instance(), SIGNAL(resumingFromIdle()), + this, SLOT(onResumingFromIdle())); + connect(m_activityConsumer, SIGNAL(currentActivityChanged(QString)), + this, SLOT(loadProfile())); + + // Set up the policy agent + PowerDevil::PolicyAgent::instance()->init(); + + // Initialize the action pool, which will also load the needed startup actions. + PowerDevil::ActionPool::instance()->init(this); + + // Set up the critical battery timer + m_criticalBatteryTimer->setSingleShot(true); + m_criticalBatteryTimer->setInterval(30000); + connect(m_criticalBatteryTimer, SIGNAL(timeout()), this, SLOT(onCriticalBatteryTimerExpired())); + + // In 30 seconds (so we are sure the user sees eventual notifications), check the battery state + QTimer::singleShot(30000, this, SLOT(checkBatteryStatus())); + + // All systems up Houston, let's go! + emit coreReady(); + refreshStatus(); +} + +bool Core::isActionSupported(const QString& actionName) +{ + Action *action = ActionPool::instance()->loadAction(actionName, KConfigGroup(), this); + if (!action) { + return false; + } else { + return action->isSupported(); + } +} + +QString Core::checkBatteryStatus(bool notify) +{ + QString lastMessage; + // Any batteries below 50% of capacity? + for (QHash< QString, uint >::const_iterator i = m_backend->capacities().constBegin(); + i != m_backend->capacities().constEnd(); ++i) { + if (i.value() < 50) { + // Notify, we have a broken battery. + if (m_loadedBatteriesUdi.size() == 1) { + lastMessage = i18n("Your battery capacity is %1%. This means your battery is broken and " + "needs a replacement. Please contact your hardware vendor for more details.", + i.value()); + } else { + lastMessage = i18n("One of your batteries (ID %2) has a capacity of %1%. This means it is broken " + "and needs a replacement. Please contact your hardware vendor for more details.", + i.value(), i.key()); + } + if (notify) { + emitRichNotification("brokenbattery", i18n("Broken Battery"), lastMessage); + } + } + } + + // Any recalled batteries? + foreach (const BackendInterface::RecallNotice ¬ice, m_backend->recallNotices()) { + // Notify, a battery has been recalled + if (m_loadedBatteriesUdi.size() == 1) { + lastMessage = i18n("Your battery might have been recalled by %1. Usually, when vendors recall the " + "hardware, it is because of factory defects which are usually eligible for a " + "free repair or substitution. Please check %1's website to " + "verify if your battery is faulted.", notice.vendor, notice.url); + } else { + lastMessage = i18n("One of your batteries (ID %3) might have been recalled by %1. " + "Usually, when vendors recall the hardware, it is because of factory defects " + "which are usually eligible for a free repair or substitution. " + "Please check %1's website to " + "verify if your battery is faulted.", notice.vendor, notice.url, notice.batteryId); + } + if (notify) { + emitRichNotification("brokenbattery", i18n("Check Your Battery"), lastMessage); + } + } + + return lastMessage; +} + +void Core::refreshStatus() +{ + /* The configuration could have changed if this function was called, so + * let's resync it. + */ + reparseConfiguration(); + + loadProfile(true); +} + +void Core::reparseConfiguration() +{ + PowerDevilSettings::self()->readConfig(); + m_profilesConfig->reparseConfiguration(); + + // Config reloaded + emit configurationReloaded(); +} + +void Core::loadProfile(bool force) +{ + QString profileId; + + // Policy check + if (PolicyAgent::instance()->requirePolicyCheck(PolicyAgent::ChangeProfile) != PolicyAgent::None) { + kDebug() << "Policy Agent prevention: on"; + return; + } + + KConfigGroup config; + + // Check the activity in which we are in + QString activity = m_activityConsumer->currentActivity(); + if (activity.isEmpty()) { + activity = "default"; + } + kDebug() << "We are now into activity " << activity; + KConfigGroup activitiesConfig(m_profilesConfig, "Activities"); + kDebug() << activitiesConfig.groupList() << activitiesConfig.keyList(); + + // Are we mirroring an activity? + if (activitiesConfig.group(activity).readEntry("mode", "None") == "ActLike" && + activitiesConfig.group(activity).readEntry("actLike", QString()) != "AC" && + activitiesConfig.group(activity).readEntry("actLike", QString()) != "Battery" && + activitiesConfig.group(activity).readEntry("actLike", QString()) != "LowBattery") { + // Yes, let's use that then + activity = activitiesConfig.group(activity).readEntry("actLike", QString()); + kDebug() << "Activity is a mirror"; + } + + KConfigGroup activityConfig = activitiesConfig.group(activity); + kDebug() << activityConfig.groupList() << activityConfig.keyList(); + + // See if this activity has priority + if (activityConfig.readEntry("mode", "None") == "SeparateSettings") { + // Prioritize this profile over anything + config = activityConfig.group("SeparateSettings"); + kDebug() << "Activity is enforcing a different profile"; + profileId = activity; + } else if (activityConfig.readEntry("mode", "None") == "ActLike") { + if (activityConfig.readEntry("actLike", QString()) == "AC" || + activityConfig.readEntry("actLike", QString()) == "Battery" || + activityConfig.readEntry("actLike", QString()) == "LowBattery") { + // Same as above, but with an existing profile + config = m_profilesConfig.data()->group(activityConfig.readEntry("actLike", QString())); + profileId = activityConfig.readEntry("actLike", QString()); + kDebug() << "Activity is mirroring a different profile"; + } + } else { + // It doesn't, let's load the current state's profile + if (m_loadedBatteriesUdi.isEmpty()) { + kDebug() << "No batteries found, loading AC"; + profileId = "AC"; + } else { + // Compute the previous and current global percentage + int percent = 0; + for (QHash::const_iterator i = m_batteriesPercent.constBegin(); + i != m_batteriesPercent.constEnd(); ++i) { + percent += i.value(); + } + + if (backend()->acAdapterState() == BackendInterface::Plugged) { + profileId = "AC"; + kDebug() << "Loading profile for plugged AC"; + } else if (percent <= PowerDevilSettings::batteryLowLevel()) { + profileId = "LowBattery"; + kDebug() << "Loading profile for low battery"; + } else { + profileId = "Battery"; + kDebug() << "Loading profile for unplugged AC"; + } + } + + config = m_profilesConfig.data()->group(profileId); + kDebug() << "Activity is not forcing a profile"; + } + + // Release any special inhibitions + { + QHash::iterator i = m_sessionActivityInhibit.begin(); + while (i != m_sessionActivityInhibit.end()) { + PolicyAgent::instance()->ReleaseInhibition(i.value()); + i = m_sessionActivityInhibit.erase(i); + } + + i = m_screenActivityInhibit.begin(); + while (i != m_screenActivityInhibit.end()) { + PolicyAgent::instance()->ReleaseInhibition(i.value()); + i = m_screenActivityInhibit.erase(i); + } + } + + if (!config.isValid()) { + emitNotification("powerdevilerror", i18n("The profile \"%1\" has been selected, " + "but it does not exist.\nPlease check your PowerDevil configuration.", + profileId)); + return; + } + + // Check: do we need to change profile at all? + if (m_currentProfile == profileId && !force) { + // No, let's leave things as they are + kDebug() << "Skipping action reload routine as profile has not changed"; + + // Do we need to force a wakeup? + if (m_pendingWakeupEvent) { + // Fake activity at this stage, when no timeouts are registered + onResumingFromIdle(); + KIdleTime::instance()->simulateUserActivity(); + m_pendingWakeupEvent = false; + } + } else { + // First of all, let's clean the old actions. This will also call the onProfileUnload callback + ActionPool::instance()->unloadAllActiveActions(); + + // Do we need to force a wakeup? + if (m_pendingWakeupEvent) { + // Fake activity at this stage, when no timeouts are registered + onResumingFromIdle(); + KIdleTime::instance()->simulateUserActivity(); + m_pendingWakeupEvent = false; + } + + // Cool, now let's load the needed actions + foreach (const QString &actionName, config.groupList()) { + Action *action = ActionPool::instance()->loadAction(actionName, config.group(actionName), this); + if (action) { + action->onProfileLoad(); + } else { + // Ouch, error. But let's just warn and move on anyway + //TODO Maybe Remove from the configuration if unsupported + kWarning() << "The profile " << profileId << "tried to activate" + << actionName << "a non existent action. This is usually due to an installation problem" + " or to a configuration problem. or simlpy the action is not supported"; + } + } + + // We are now on a different profile + m_currentProfile = profileId; + emit profileChanged(m_currentProfile); + } + + // Now... any special behaviors we'd like to consider? + if (activityConfig.readEntry("mode", "None") == "SpecialBehavior") { + kDebug() << "Activity has special behaviors"; + KConfigGroup behaviorGroup = activityConfig.group("SpecialBehavior"); + if (behaviorGroup.readEntry("performAction", false)) { + // Let's override the configuration for this action at all times + ActionPool::instance()->loadAction("SuspendSession", behaviorGroup.group("ActionConfig"), this); + kDebug() << "Activity overrides suspend session action"; + } + + if (behaviorGroup.readEntry("noSuspend", false)) { + kDebug() << "Activity triggers a suspend inhibition"; + // Trigger a special inhibition - if we don't have one yet + if (!m_sessionActivityInhibit.contains(activity)) { + int cookie = + PolicyAgent::instance()->AddInhibition(PolicyAgent::InterruptSession, i18n("Activity Manager"), + i18n("This activity's policies prevent the system from suspending")); + + m_sessionActivityInhibit.insert(activity, cookie); + } + } + + if (behaviorGroup.readEntry("noScreenManagement", false)) { + kDebug() << "Activity triggers a screen management inhibition"; + // Trigger a special inhibition - if we don't have one yet + if (!m_screenActivityInhibit.contains(activity)) { + int cookie = + PolicyAgent::instance()->AddInhibition(PolicyAgent::ChangeScreenSettings, i18n("Activity Manager"), + i18n("This activity's policies prevent screen power management")); + + m_screenActivityInhibit.insert(activity, cookie); + } + } + } + + // If the lid is closed, retrigger the lid close signal + if (m_backend->isLidClosed()) { + emit m_backend->buttonPressed(PowerDevil::BackendInterface::LidClose); + } +} + +void Core::onDeviceAdded(const QString& udi) +{ + if (m_loadedBatteriesUdi.contains(udi)) { + // We already know about this device + return; + } + + using namespace Solid; + Device device(udi); + Battery *b = qobject_cast(device.asDeviceInterface(DeviceInterface::Battery)); + + if (!b) { + // Not interesting to us + return; + } + + if (b->type() != Solid::Battery::PrimaryBattery && b->type() != Solid::Battery::UpsBattery) { + // Not interesting to us + return; + } + + if (!b->isPowerSupply()) { + // TODO: At some later point it would be really nice to handle those batteries too + // eg, show "your mouse is running low", but in the mean time, we don't care about those + return; + } + + if (!connect(b, SIGNAL(chargePercentChanged(int,QString)), + this, SLOT(onBatteryChargePercentChanged(int,QString))) || + !connect(b, SIGNAL(chargeStateChanged(int,QString)), + this, SLOT(onBatteryChargeStateChanged(int,QString)))) { + emitNotification("powerdevilerror", i18n("Could not connect to battery interface.\n" + "Please check your system configuration")); + } + + kDebug() << "A new battery was detected"; + + m_batteriesPercent[udi] = b->chargePercent(); + if (b->chargeState() == Solid::Battery::NoCharge) { + m_batteriesCharged[udi] = true; + } else { + m_batteriesCharged[udi] = false; + } + m_loadedBatteriesUdi.append(udi); + + // Compute the current global percentage + int globalChargePercent = 0; + for (QHash::const_iterator i = m_batteriesPercent.constBegin(); i != m_batteriesPercent.constEnd(); ++i) { + globalChargePercent += i.value(); + } + + // If a new battery has been added, let's clear some pending suspend actions if the new global batteries percentage is + // higher than the battery low level. (See bug 329537) + if (m_criticalBatteryTimer->isActive() && globalChargePercent > PowerDevilSettings::batteryCriticalLevel()) { + m_criticalBatteryTimer->stop(); + } + + // So we get a "Battery is low" notification directly on system startup if applicable + emitBatteryChargePercentNotification(globalChargePercent, 100); +} + +void Core::onDeviceRemoved(const QString& udi) +{ + if (!m_loadedBatteriesUdi.contains(udi)) { + // We don't know about this device + return; + } + + using namespace Solid; + Device device(udi); + Battery *b = qobject_cast(device.asDeviceInterface(DeviceInterface::Battery)); + + disconnect(b, SIGNAL(chargePercentChanged(int,QString)), + this, SLOT(onBatteryChargePercentChanged(int,QString))); + disconnect(b, SIGNAL(chargeStateChanged(int,QString)), + this, SLOT(onBatteryChargeStateChanged(int,QString))); + + kDebug() << "An existing battery has been removed"; + + m_batteriesPercent.remove(udi); + m_batteriesCharged.remove(udi); + m_loadedBatteriesUdi.removeOne(udi); +} + +void Core::emitNotification(const QString &evid, const QString &message, const QString &iconname) +{ + if (!iconname.isEmpty()) { + KNotification::event(evid, message, KIcon(iconname).pixmap(48,48), + 0, KNotification::CloseOnTimeout, m_applicationData); + } else { + KNotification::event(evid, message, QPixmap(), + 0, KNotification::CloseOnTimeout, m_applicationData); + } +} + +void Core::emitRichNotification(const QString &evid, const QString &title, const QString &message) +{ + KNotification::event(evid, title, message, QPixmap(), + 0, KNotification::CloseOnTimeout, m_applicationData); +} + +bool Core::emitBatteryChargePercentNotification(int currentPercent, int previousPercent) +{ + if (m_backend->acAdapterState() == BackendInterface::Plugged) { + return false; + } + + if (currentPercent <= PowerDevilSettings::batteryCriticalLevel() && + previousPercent > PowerDevilSettings::batteryCriticalLevel()) { + switch (PowerDevilSettings::batteryCriticalAction()) { + case PowerDevil::BundledActions::SuspendSession::ShutdownMode: + emitRichNotification("criticalbattery", i18n("Battery Critical (%1% Remaining)", currentPercent), + i18n("Your battery level is critical, the computer will be halted in 30 seconds.")); + m_criticalBatteryTimer->start(); + break; + case PowerDevil::BundledActions::SuspendSession::ToDiskMode: + emitRichNotification("criticalbattery", i18n("Battery Critical (%1% Remaining)", currentPercent), + i18n("Your battery level is critical, the computer will be hibernated in 30 seconds.")); + m_criticalBatteryTimer->start(); + break; + case PowerDevil::BundledActions::SuspendSession::ToRamMode: + emitRichNotification("criticalbattery", i18n("Battery Critical (%1% Remaining)", currentPercent), + i18n("Your battery level is critical, the computer will be suspended in 30 seconds.")); + m_criticalBatteryTimer->start(); + break; + default: + emitRichNotification("criticalbattery", i18n("Battery Critical (%1% Remaining)", currentPercent), + i18n("Your battery level is critical, save your work as soon as possible.")); + break; + } + return true; + } else if (currentPercent <= PowerDevilSettings::batteryLowLevel() && + previousPercent > PowerDevilSettings::batteryLowLevel()) { + emitRichNotification("lowbattery", i18n("Battery Low (%1% Remaining)", currentPercent), + i18n("Your battery is low. If you need to continue using your computer, either plug in your computer, or shut it down and then change the battery.")); + return true; + } + return false; +} + + +void Core::onAcAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState state) +{ + kDebug(); + // Post request for faking an activity event - usually adapters don't plug themselves out :) + m_pendingWakeupEvent = true; + loadProfile(); + + if (state == BackendInterface::Plugged) { + // If the AC Adaptor has been plugged in, let's clear some pending suspend actions + if (m_criticalBatteryTimer->isActive()) { + m_criticalBatteryTimer->stop(); + emitRichNotification("criticalbattery", + i18n("AC Adapter Plugged In"), + i18n("All pending suspend actions have been canceled.")); + } else { + emitRichNotification("pluggedin", i18n("Running on AC power"), i18n("The power adaptor has been plugged in.")); + } + } else if (state == BackendInterface::Unplugged) { + emitRichNotification("unplugged", i18n("Running on Battery Power"), i18n("The power adaptor has been unplugged.")); + } +} + +void Core::onBackendError(const QString& error) +{ + emitNotification("powerdevilerror", i18n("KDE Power Management System could not be initialized. " + "The backend reported the following error: %1\n" + "Please check your system configuration", error)); +} + +void Core::onBatteryChargePercentChanged(int percent, const QString &udi) +{ + // Compute the previous and current global percentage + int previousPercent = 0; + for (QHash::const_iterator i = m_batteriesPercent.constBegin(); i != m_batteriesPercent.constEnd(); ++i) { + previousPercent += i.value(); + } + int currentPercent = previousPercent - (m_batteriesPercent[udi] - percent); + + // Update the battery percentage + m_batteriesPercent[udi] = percent; + + if (currentPercent < previousPercent) { + if (emitBatteryChargePercentNotification(currentPercent, previousPercent)) { + // Only refresh status if a notification has actually been emitted + refreshStatus(); + } + } +} + +void Core::onBatteryChargeStateChanged(int state, const QString &udi) +{ + bool previousCharged = true; + for (QHash::const_iterator i = m_batteriesCharged.constBegin(); i != m_batteriesCharged.constEnd(); ++i) { + if (!i.value()) { + previousCharged = false; + break; + } + } + + m_batteriesCharged[udi] = (state == Solid::Battery::NoCharge); + + if (m_backend->acAdapterState() != BackendInterface::Plugged) { + return; + } + + bool currentCharged = true; + for (QHash::const_iterator i = m_batteriesCharged.constBegin(); i != m_batteriesCharged.constEnd(); ++i) { + if (!i.value()) { + currentCharged = false; + break; + } + } + + if (!previousCharged && currentCharged) { + emitRichNotification("fullbattery", i18n("Charge Complete"), i18n("Your battery is now fully charged.")); + refreshStatus(); + } +} + +void Core::onCriticalBatteryTimerExpired() +{ + // Do that only if we're not on AC + if (m_backend->acAdapterState() == BackendInterface::Unplugged) { + // We consider this as a very special button + PowerDevil::Action *helperAction = ActionPool::instance()->loadAction("HandleButtonEvents", KConfigGroup(), this); + if (helperAction) { + QVariantMap args; + args["Button"] = 32; + args["Type"] = QVariant::fromValue(PowerDevilSettings::batteryCriticalAction()); + helperAction->trigger(args); + } + } +} + +void Core::onBatteryRemainingTimeChanged(qulonglong time) +{ + emit batteryRemainingTimeChanged(time); +} + +void Core::onKIdleTimeoutReached(int identifier, int msec) +{ + // Find which action(s) requested this idle timeout + for (QHash< Action*, QList< int > >::const_iterator i = m_registeredActionTimeouts.constBegin(); + i != m_registeredActionTimeouts.constEnd(); ++i) { + if (i.value().contains(identifier)) { + i.key()->onIdleTimeout(msec); + // And it will need to be awaken + if (!m_pendingResumeFromIdleActions.contains(i.key())) { + m_pendingResumeFromIdleActions.append(i.key()); + } + break; + } + } + + // Catch the next resume event if some actions require it + if (!m_pendingResumeFromIdleActions.isEmpty()) { + KIdleTime::instance()->catchNextResumeEvent(); + } +} + +void Core::registerActionTimeout(Action* action, int timeout) +{ + // Register the timeout with KIdleTime + int identifier = KIdleTime::instance()->addIdleTimeout(timeout); + + // Add the identifier to the action hash + QList< int > timeouts = m_registeredActionTimeouts[action]; + timeouts.append(identifier); + m_registeredActionTimeouts[action] = timeouts; +} + +void Core::unregisterActionTimeouts(Action* action) +{ + // Clear all timeouts from the action + QList< int > timeoutsToClean = m_registeredActionTimeouts[action]; + + foreach (int id, timeoutsToClean) { + KIdleTime::instance()->removeIdleTimeout(id); + } + + m_registeredActionTimeouts.remove(action); +} + +void Core::onResumingFromIdle() +{ + // Wake up the actions in which an idle action was triggered + QList< Action* >::iterator i = m_pendingResumeFromIdleActions.begin(); + while (i != m_pendingResumeFromIdleActions.end()) { + (*i)->onWakeupFromIdle(); + i = m_pendingResumeFromIdleActions.erase(i); + } +} + +BackendInterface* Core::backend() +{ + return m_backend; +} + +bool Core::isLidClosed() +{ + return m_backend->isLidClosed(); +} + +qulonglong Core::batteryRemainingTime() const +{ + return m_backend->batteryRemainingTime(); +} + +uint Core::backendCapabilities() +{ + return m_backend->capabilities(); +} + +} + +#include "powerdevilcore.moc" diff --git a/powerdevil/daemon/powerdevilcore.h b/powerdevil/daemon/powerdevilcore.h new file mode 100644 index 00000000..7312053e --- /dev/null +++ b/powerdevil/daemon/powerdevilcore.h @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVILCORE_H +#define POWERDEVILCORE_H + +#include "powerdevilbackendinterface.h" + +#include +#include + +#include + +namespace KActivities +{ + class Consumer; +} // namespace KActivities +typedef QMap< QString, QString > StringStringMap; + +class KDirWatch; +class QTimer; +class KNotification; +namespace Solid { +class Battery; +} + +namespace PowerDevil +{ + +class BackendInterface; +class Action; + +class KDE_EXPORT Core : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(Core) + Q_CLASSINFO("D-Bus Interface", "org.kde.Solid.PowerManagement") + +public: + explicit Core(QObject* parent, const KComponentData &componentData); + virtual ~Core(); + + void reloadProfile(int state); + + void emitNotification(const QString &evid, const QString &message = QString(), + const QString &iconname = QString()); + void emitRichNotification(const QString &evid, const QString &title, const QString &message = QString()); + bool emitBatteryChargePercentNotification(int currentPercent, int previousPercent); + + BackendInterface *backend(); + + // More... + +public Q_SLOTS: + void loadCore(PowerDevil::BackendInterface *backend); + // Set of common action - useful for the DBus interface + uint backendCapabilities(); + void refreshStatus(); + void reparseConfiguration(); + + QString checkBatteryStatus(bool notify = true); + + void loadProfile(bool force = false); + + qulonglong batteryRemainingTime() const; + + bool isLidClosed(); + bool isActionSupported(const QString &actionName); + +Q_SIGNALS: + void coreReady(); + void profileChanged(const QString &newProfile); + void configurationReloaded(); + void batteryRemainingTimeChanged(qulonglong time); + +private: + void registerActionTimeout(Action *action, int timeout); + void unregisterActionTimeouts(Action *action); + + friend class Action; + + BackendInterface *m_backend; + QStringList m_loadedBatteriesUdi; + + QWeakPointer< KNotification > notification; + KComponentData m_applicationData; + KSharedConfigPtr m_profilesConfig; + + QString m_currentProfile; + + QHash< QString, int > m_batteriesPercent; + QHash< QString, bool > m_batteriesCharged; + + QTimer *m_criticalBatteryTimer; + + KActivities::Consumer *m_activityConsumer; + + // Idle time management + QHash< Action*, QList< int > > m_registeredActionTimeouts; + QList< Action* > m_pendingResumeFromIdleActions; + bool m_pendingWakeupEvent; + + // Activity inhibition management + QHash< QString, int > m_sessionActivityInhibit; + QHash< QString, int > m_screenActivityInhibit; + +private Q_SLOTS: + void onBackendReady(); + void onBackendError(const QString &error); + void onAcAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState); + void onBatteryChargePercentChanged(int,const QString&); + void onBatteryChargeStateChanged(int,const QString&); + void onBatteryRemainingTimeChanged(qulonglong); + void onKIdleTimeoutReached(int,int); + void onResumingFromIdle(); + void onDeviceAdded(const QString &udi); + void onDeviceRemoved(const QString &udi); + void onCriticalBatteryTimerExpired(); +}; + +} + +Q_DECLARE_METATYPE(StringStringMap) + +#endif // POWERDEVILCORE_H diff --git a/powerdevil/daemon/powerdevilfdoconnector.cpp b/powerdevil/daemon/powerdevilfdoconnector.cpp new file mode 100644 index 00000000..3e5b3eec --- /dev/null +++ b/powerdevil/daemon/powerdevilfdoconnector.cpp @@ -0,0 +1,141 @@ +/*************************************************************************** + * Copyright (C) 2008 by Kevin Ottens * + * Copyright (C) 2008-2010 by Dario Freddi * + * * + * 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 "powerdevilfdoconnector.h" + +#include "powerdevilaction.h" +#include "powerdevilactionpool.h" +#include "powerdevilcore.h" + +#include "powermanagementfdoadaptor.h" +#include "powermanagementinhibitadaptor.h" + +#include "daemon/actions/bundled/suspendsession.h" + +#include + +namespace PowerDevil { + +FdoConnector::FdoConnector(PowerDevil::Core *parent) + : QObject(parent), m_core(parent) +{ + new PowerManagementFdoAdaptor(this); + new PowerManagementInhibitAdaptor(this); + + QDBusConnection c = QDBusConnection::sessionBus(); + + c.registerService("org.freedesktop.PowerManagement"); + c.registerObject("/org/freedesktop/PowerManagement", this); + + c.registerService("org.freedesktop.PowerManagement.Inhibit"); + c.registerObject("/org/freedesktop/PowerManagement/Inhibit", this); + + connect(m_core->backend(), SIGNAL(acAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState)), + this, SLOT(onAcAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState))); + connect(PolicyAgent::instance(), SIGNAL(unavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies)), + this, SLOT(onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies))); +} + +bool FdoConnector::CanHibernate() +{ + return m_core->backend()->supportedSuspendMethods() & PowerDevil::BackendInterface::ToDisk; +} + +bool FdoConnector::CanSuspend() +{ + return m_core->backend()->supportedSuspendMethods() & PowerDevil::BackendInterface::ToRam; +} + +bool FdoConnector::CanHybridSuspend() +{ + return m_core->backend()->supportedSuspendMethods() & PowerDevil::BackendInterface::HybridSuspend; +} + +bool FdoConnector::GetPowerSaveStatus() +{ + return m_core->backend()->acAdapterState() == PowerDevil::BackendInterface::Unplugged; +} + +void FdoConnector::Suspend() +{ + triggerSuspendSession(BundledActions::SuspendSession::ToRamMode); +} + +void FdoConnector::Hibernate() +{ + triggerSuspendSession(BundledActions::SuspendSession::ToDiskMode); +} + +void FdoConnector::HybridSuspend() +{ + triggerSuspendSession(BundledActions::SuspendSession::SuspendHybridMode); +} + +bool FdoConnector::HasInhibit() +{ + return PolicyAgent::instance()->requirePolicyCheck(PolicyAgent::InterruptSession) != PolicyAgent::None; +} + +int FdoConnector::Inhibit(const QString &application, const QString &reason) +{ + // Inhibit here means we cannot interrupt the session. + // If we've been called from DBus, use PolicyAgent's service watching system + if (calledFromDBus()) { + return PolicyAgent::instance()->addInhibitionWithExplicitDBusService((uint)PolicyAgent::InterruptSession, + application, reason, message().service()); + } else { + return PolicyAgent::instance()->AddInhibition((uint)PolicyAgent::InterruptSession, application, reason); + } +} + +void FdoConnector::UnInhibit(int cookie) +{ + PolicyAgent::instance()->ReleaseInhibition(cookie); +} + +void FdoConnector::ForceUnInhibitAll() +{ + PolicyAgent::instance()->releaseAllInhibitions(); +} + +void FdoConnector::onAcAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState newstate) +{ + emit PowerSaveStatusChanged(newstate == PowerDevil::BackendInterface::Unplugged); +} + +void FdoConnector::onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies newpolicies) +{ + emit HasInhibitChanged(newpolicies & PowerDevil::PolicyAgent::InterruptSession); +} + +void FdoConnector::triggerSuspendSession(uint action) +{ + PowerDevil::Action *helperAction = ActionPool::instance()->loadAction("SuspendSession", KConfigGroup(), m_core); + if (helperAction) { + QVariantMap args; + args["Type"] = action; + args["Explicit"] = true; + helperAction->trigger(args); + } +} + +} + +#include "powerdevilfdoconnector.moc" diff --git a/powerdevil/daemon/powerdevilfdoconnector.h b/powerdevil/daemon/powerdevilfdoconnector.h new file mode 100644 index 00000000..5d981f14 --- /dev/null +++ b/powerdevil/daemon/powerdevilfdoconnector.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2008 by Kevin Ottens * + * Copyright (C) 2008-2010 by Dario Freddi * + * * + * 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 POWERDEVILFDOCONNECTOR_H +#define POWERDEVILFDOCONNECTOR_H + +#include + +#include "powerdevilbackendinterface.h" +#include "powerdevilpolicyagent.h" + +namespace PowerDevil { +class Core; + +class FdoConnector : public QObject, protected QDBusContext +{ + Q_OBJECT + Q_DISABLE_COPY(FdoConnector) + + Q_CLASSINFO("D-Bus Interface", "org.freedesktop.PowerManagement") + Q_CLASSINFO("D-Bus Interface", "org.freedesktop.PowerManagement.Inhibit") + +public: + FdoConnector(PowerDevil::Core *parent); + + bool CanHibernate(); + bool CanSuspend(); + bool CanHybridSuspend(); + + bool GetPowerSaveStatus(); + + void Suspend(); + void Hibernate(); + void HybridSuspend(); + + bool HasInhibit(); + + int Inhibit(const QString &application, const QString &reason); + void UnInhibit(int cookie); + void ForceUnInhibitAll(); + +Q_SIGNALS: + void CanSuspendChanged(bool canSuspend); + void CanHibernateChanged(bool canHibernate); + void CanHybridSuspendChanged(bool canHybridSuspend); + void PowerSaveStatusChanged(bool savePower); + + void HasInhibitChanged(bool hasInhibit); + +private Q_SLOTS: + void onAcAdapterStateChanged(PowerDevil::BackendInterface::AcAdapterState); + void onUnavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies); + void triggerSuspendSession(uint action); + +private: + PowerDevil::Core *m_core; +}; + +} + +#endif /*POWERDEVILFDOCONNECTOR_H*/ diff --git a/powerdevil/daemon/powerdevilpolicyagent.cpp b/powerdevil/daemon/powerdevilpolicyagent.cpp new file mode 100644 index 00000000..d217e924 --- /dev/null +++ b/powerdevil/daemon/powerdevilpolicyagent.cpp @@ -0,0 +1,579 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * Copyright (C) 2012 Lukáš Tinkl * + * * + * 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 +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "powerdevilpolicyagent.h" +#include "screensaver_interface.h" + +struct NamedDBusObjectPath +{ + QString name; + QDBusObjectPath path; +}; + +// Marshall the NamedDBusObjectPath data into a D-Bus argument +QDBusArgument &operator<<(QDBusArgument &argument, const NamedDBusObjectPath &namedPath) +{ + argument.beginStructure(); + argument << namedPath.name << namedPath.path; + argument.endStructure(); + return argument; +} + +// Retrieve the NamedDBusObjectPath data from the D-Bus argument +const QDBusArgument &operator>>(const QDBusArgument &argument, NamedDBusObjectPath &namedPath) +{ + argument.beginStructure(); + argument >> namedPath.name >> namedPath.path; + argument.endStructure(); + return argument; +} + +Q_DECLARE_METATYPE(NamedDBusObjectPath) + +namespace PowerDevil +{ + +class PolicyAgentHelper +{ +public: + PolicyAgentHelper() : q(0) { } + ~PolicyAgentHelper() { + delete q; + } + PolicyAgent *q; +}; + +K_GLOBAL_STATIC(PolicyAgentHelper, s_globalPolicyAgent) + +PolicyAgent *PolicyAgent::instance() +{ + if (!s_globalPolicyAgent->q) { + new PolicyAgent; + } + + return s_globalPolicyAgent->q; +} + +PolicyAgent::PolicyAgent(QObject* parent) + : QObject(parent) + , m_sdAvailable(false) + , m_systemdInhibitFd(-1) + , m_ckAvailable(false) + , m_sessionIsBeingInterrupted(false) + , m_lastCookie(0) + , m_busWatcher(new QDBusServiceWatcher(this)) + , m_sdWatcher(new QDBusServiceWatcher(this)) + , m_ckWatcher(new QDBusServiceWatcher(this)) +{ + Q_ASSERT(!s_globalPolicyAgent->q); + s_globalPolicyAgent->q = this; +} + +PolicyAgent::~PolicyAgent() +{ +} + +void PolicyAgent::init() +{ + // Watch over the systemd service + m_sdWatcher.data()->setConnection(QDBusConnection::systemBus()); + m_sdWatcher.data()->setWatchMode(QDBusServiceWatcher::WatchForUnregistration | + QDBusServiceWatcher::WatchForRegistration); + m_sdWatcher.data()->addWatchedService(SYSTEMD_LOGIN1_SERVICE); + + connect(m_sdWatcher.data(), SIGNAL(serviceRegistered(QString)), + this, SLOT(onSessionHandlerRegistered(QString))); + connect(m_sdWatcher.data(), SIGNAL(serviceUnregistered(QString)), + this, SLOT(onSessionHandlerUnregistered(QString))); + // If it's up and running already, let's cache it + if (QDBusConnection::systemBus().interface()->isServiceRegistered(SYSTEMD_LOGIN1_SERVICE)) { + onSessionHandlerRegistered(SYSTEMD_LOGIN1_SERVICE); + } + + // Watch over the ConsoleKit service + m_ckWatcher.data()->setConnection(QDBusConnection::sessionBus()); + m_ckWatcher.data()->setWatchMode(QDBusServiceWatcher::WatchForUnregistration | + QDBusServiceWatcher::WatchForRegistration); + m_ckWatcher.data()->addWatchedService(CONSOLEKIT_SERVICE); + + connect(m_ckWatcher.data(), SIGNAL(serviceRegistered(QString)), + this, SLOT(onSessionHandlerRegistered(QString))); + connect(m_ckWatcher.data(), SIGNAL(serviceUnregistered(QString)), + this, SLOT(onSessionHandlerUnregistered(QString))); + // If it's up and running already, let's cache it + if (QDBusConnection::systemBus().interface()->isServiceRegistered(CONSOLEKIT_SERVICE)) { + onSessionHandlerRegistered(CONSOLEKIT_SERVICE); + } + + // Now set up our service watcher + m_busWatcher.data()->setConnection(QDBusConnection::sessionBus()); + m_busWatcher.data()->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); + + connect(m_busWatcher.data(), SIGNAL(serviceUnregistered(QString)), + this, SLOT(onServiceUnregistered(QString))); +} + +QString PolicyAgent::getNamedPathProperty(const QString &path, const QString &iface, const QString &prop) const +{ + QDBusMessage message = QDBusMessage::createMethodCall(SYSTEMD_LOGIN1_SERVICE, path, + QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get")); + message << iface << prop; + QDBusMessage reply = QDBusConnection::systemBus().call(message); + + QVariantList args = reply.arguments(); + if (!args.isEmpty()) { + NamedDBusObjectPath namedPath; + args.at(0).value().variant().value() >> namedPath; + return namedPath.path.path(); + } + + return QString(); +} + +void PolicyAgent::forceLockAndWait() +{ + OrgFreedesktopScreenSaverInterface screenSaveriface("org.freedesktop.ScreenSaver", + "/ScreenSaver", + QDBusConnection::sessionBus()); + QDBusPendingReply< void > reply = screenSaveriface.Lock(); + reply.waitForFinished(); +} + +void PolicyAgent::onSessionHandlerRegistered(const QString & serviceName) +{ + if (serviceName == SYSTEMD_LOGIN1_SERVICE) { + m_sdAvailable = true; + + qRegisterMetaType(); + qDBusRegisterMetaType(); + + // get the current session + QDBusInterface managerIface(SYSTEMD_LOGIN1_SERVICE, SYSTEMD_LOGIN1_PATH, SYSTEMD_LOGIN1_MANAGER_IFACE, QDBusConnection::systemBus()); + QDBusPendingReply session = managerIface.asyncCall(QLatin1String("GetSessionByPID"), (quint32) QCoreApplication::applicationPid()); + session.waitForFinished(); + + if (!session.isValid()) { + kDebug() << "The session is not registered with systemd"; + m_sdAvailable = false; + return; + } + + QString sessionPath = session.value().path(); + kDebug() << "Session path:" << sessionPath; + + m_sdSessionInterface = new QDBusInterface(SYSTEMD_LOGIN1_SERVICE, sessionPath, + SYSTEMD_LOGIN1_SESSION_IFACE, QDBusConnection::systemBus(), this); + if (!m_sdSessionInterface.data()->isValid()) { + // As above + kDebug() << "Can't contact session iface"; + m_sdAvailable = false; + delete m_sdSessionInterface.data(); + return; + } + + // listen to the systemd-login1 session's Lock signal + connect(m_sdSessionInterface.data(), SIGNAL(Lock()), this, SLOT(forceLockAndWait())); + + // now let's obtain the seat + QString seatPath = getNamedPathProperty(sessionPath, SYSTEMD_LOGIN1_SESSION_IFACE, "Seat"); + + if (seatPath.isEmpty() || seatPath == "/") { + kDebug() << "Unable to associate systemd session with a seat" << seatPath; + m_sdAvailable = false; + return; + } + + // get the current seat + m_sdSeatInterface = new QDBusInterface(SYSTEMD_LOGIN1_SERVICE, seatPath, + SYSTEMD_LOGIN1_SEAT_IFACE, QDBusConnection::systemBus(), this); + + if (!m_sdSeatInterface.data()->isValid()) { + // As above + kDebug() << "Can't contact seat iface"; + m_sdAvailable = false; + delete m_sdSeatInterface.data(); + return; + } + + // finally get the active session path and watch for its changes + m_activeSessionPath = getNamedPathProperty(seatPath, SYSTEMD_LOGIN1_SEAT_IFACE, "ActiveSession"); + + kDebug() << "ACTIVE SESSION PATH:" << m_activeSessionPath; + QDBusConnection::systemBus().connect(SYSTEMD_LOGIN1_SERVICE, seatPath, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, + SLOT(onActiveSessionChanged(QString,QVariantMap,QStringList))); + + onActiveSessionChanged(m_activeSessionPath); + + setupSystemdInhibition(); + + kDebug() << "systemd support initialized"; + } else if (serviceName == CONSOLEKIT_SERVICE) { + m_ckAvailable = true; + + // Otherwise, let's ask ConsoleKit + QDBusInterface ckiface(CONSOLEKIT_SERVICE, "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", QDBusConnection::systemBus()); + + QDBusPendingReply sessionPath = ckiface.asyncCall("GetCurrentSession"); + + sessionPath.waitForFinished(); + + if (!sessionPath.isValid() || sessionPath.value().path().isEmpty()) { + kDebug() << "The session is not registered with ck"; + m_ckAvailable = false; + return; + } + + m_ckSessionInterface = new QDBusInterface(CONSOLEKIT_SERVICE, sessionPath.value().path(), + "org.freedesktop.ConsoleKit.Session", QDBusConnection::systemBus()); + + if (!m_ckSessionInterface.data()->isValid()) { + // As above + kDebug() << "Can't contact iface"; + m_ckAvailable = false; + return; + } + + // Now let's obtain the seat + QDBusPendingReply< QDBusObjectPath > seatPath = m_ckSessionInterface.data()->asyncCall("GetSeatId"); + seatPath.waitForFinished(); + + if (!seatPath.isValid() || seatPath.value().path().isEmpty()) { + kDebug() << "Unable to associate ck session with a seat"; + m_ckAvailable = false; + return; + } + + if (!QDBusConnection::systemBus().connect(CONSOLEKIT_SERVICE, seatPath.value().path(), + "org.freedesktop.ConsoleKit.Seat", "ActiveSessionChanged", + this, SLOT(onActiveSessionChanged(QString)))) { + kDebug() << "Unable to connect to ActiveSessionChanged"; + m_ckAvailable = false; + return; + } + + // Force triggering of active session changed + QDBusMessage call = QDBusMessage::createMethodCall(CONSOLEKIT_SERVICE, seatPath.value().path(), + "org.freedesktop.ConsoleKit.Seat", "GetActiveSession"); + QDBusPendingReply< QDBusObjectPath > activeSession = QDBusConnection::systemBus().asyncCall(call); + activeSession.waitForFinished(); + + onActiveSessionChanged(activeSession.value().path()); + + kDebug() << "ConsoleKit support initialized"; + } + else + kWarning() << "Unhandled service registered:" << serviceName; +} + +void PolicyAgent::onSessionHandlerUnregistered(const QString & serviceName) +{ + if (serviceName == SYSTEMD_LOGIN1_SERVICE) { + m_sdAvailable = false; + delete m_sdSessionInterface.data(); + } + else if (serviceName == CONSOLEKIT_SERVICE) { + m_ckAvailable = false; + delete m_ckSessionInterface.data(); + } +} + +void PolicyAgent::onActiveSessionChanged(const QString & ifaceName, const QVariantMap & changedProps, const QStringList & invalidatedProps) +{ + const QString key = QLatin1String("ActiveSession"); + + if (ifaceName == SYSTEMD_LOGIN1_SEAT_IFACE && (changedProps.keys().contains(key) || invalidatedProps.contains(key))) { + m_activeSessionPath = getNamedPathProperty(m_sdSeatInterface.data()->path(), SYSTEMD_LOGIN1_SEAT_IFACE, key); + kDebug() << "ACTIVE SESSION PATH CHANGED:" << m_activeSessionPath; + onActiveSessionChanged(m_activeSessionPath); + } +} + +void PolicyAgent::onActiveSessionChanged(const QString& activeSession) +{ + if (activeSession.isEmpty() || activeSession == "/") { + kDebug() << "Switched to inactive session - leaving unchanged"; + return; + } else if ((!m_sdSessionInterface.isNull() && activeSession == m_sdSessionInterface.data()->path()) || + (!m_ckSessionInterface.isNull() && activeSession == m_ckSessionInterface.data()->path())) { + kDebug() << "Current session is now active"; + m_wasLastActiveSession = true; + } else { + kDebug() << "Current session is now inactive"; + m_wasLastActiveSession = false; + } +} + +void PolicyAgent::onServiceUnregistered(const QString& serviceName) +{ + if (m_cookieToBusService.values().contains(serviceName)) { + // Ouch - the application quit or crashed without releasing its inhibitions. Let's fix that. + foreach (uint key, m_cookieToBusService.keys(serviceName)) { + ReleaseInhibition(key); + } + } +} + +PolicyAgent::RequiredPolicies PolicyAgent::unavailablePolicies() +{ + RequiredPolicies retpolicies = None; + + if (!m_typesToCookie[ChangeProfile].isEmpty()) { + retpolicies |= ChangeProfile; + } + if (!m_typesToCookie[ChangeScreenSettings].isEmpty()) { + retpolicies |= ChangeScreenSettings; + } + if (!m_typesToCookie[InterruptSession].isEmpty()) { + retpolicies |= InterruptSession; + } + + return retpolicies; +} + +PolicyAgent::RequiredPolicies PolicyAgent::requirePolicyCheck(PolicyAgent::RequiredPolicies policies) +{ + if (!m_sdAvailable) { + // No way to determine if we are on the current session, simply suppose we are + kDebug() << "Can't contact systemd"; + } else if (!m_sdSessionInterface.isNull()) { + bool isActive = m_sdSessionInterface.data()->property("Active").toBool(); + + if (!isActive && !m_wasLastActiveSession) { + return policies; + } + } + + if (!m_ckAvailable) { + // No way to determine if we are on the current session, simply suppose we are + kDebug() << "Can't contact ck"; + } else if (!m_ckSessionInterface.isNull()) { + QDBusPendingReply< bool > rp = m_ckSessionInterface.data()->asyncCall("IsActive"); + rp.waitForFinished(); + + if (!(rp.isValid() && rp.value()) && !m_wasLastActiveSession) { + return policies; + } + } + + // Ok, let's go then + RequiredPolicies retpolicies = None; + + if (policies & ChangeProfile) { + if (!m_typesToCookie[ChangeProfile].isEmpty()) { + retpolicies |= ChangeProfile; + } + } + if (policies & ChangeScreenSettings) { + if (!m_typesToCookie[ChangeScreenSettings].isEmpty()) { + retpolicies |= ChangeScreenSettings; + } + } + if (policies & InterruptSession) { + if (m_sessionIsBeingInterrupted || !m_typesToCookie[InterruptSession].isEmpty()) { + retpolicies |= InterruptSession; + } + } + + return retpolicies; +} + +void PolicyAgent::startSessionInterruption() +{ + m_sessionIsBeingInterrupted = true; +} + +void PolicyAgent::finishSessionInterruption() +{ + m_sessionIsBeingInterrupted = false; +} + +uint PolicyAgent::addInhibitionWithExplicitDBusService(uint types, const QString& appName, + const QString& reason, const QString& service) +{ + ++m_lastCookie; + + m_cookieToAppName.insert(m_lastCookie, qMakePair(appName, reason)); + + if (!m_busWatcher.isNull() && !service.isEmpty()) { + m_cookieToBusService.insert(m_lastCookie, service); + m_busWatcher.data()->addWatchedService(service); + } + + kDebug() << "Added inhibition from an explicit DBus service, " << service << ", with cookie " << + m_lastCookie << " from " << appName << " with " << reason; + + addInhibitionTypeHelper(m_lastCookie, static_cast< PolicyAgent::RequiredPolicies >(types)); + + return m_lastCookie; +} + +uint PolicyAgent::AddInhibition(uint types, + const QString& appName, + const QString& reason) +{ + ++m_lastCookie; + + m_cookieToAppName.insert(m_lastCookie, qMakePair(appName, reason)); + + // Retrieve the service, if we've been called from DBus + if (calledFromDBus() && !m_busWatcher.isNull()) { + if (!message().service().isEmpty()) { + kDebug() << "DBus service " << message().service() << " is requesting inhibition"; + m_cookieToBusService.insert(m_lastCookie, message().service()); + m_busWatcher.data()->addWatchedService(message().service()); + } + } + + kDebug() << "Added inhibition with cookie " << m_lastCookie << " from " << + appName << " with " << reason; + + addInhibitionTypeHelper(m_lastCookie, static_cast< PolicyAgent::RequiredPolicies >(types)); + + return m_lastCookie; +} + +void PolicyAgent::addInhibitionTypeHelper(uint cookie, PolicyAgent::RequiredPolicies types) +{ + // Look through all of the inhibition types + bool notify = false; + if (types & ChangeProfile) { + // Check if we have to notify + if (m_typesToCookie[ChangeProfile].isEmpty()) { + kDebug() << "Added change profile"; + notify = true; + } + m_typesToCookie[ChangeProfile].append(cookie); + } + if (types & ChangeScreenSettings) { + // Check if we have to notify + kDebug() << "Added change screen settings"; + if (m_typesToCookie[ChangeScreenSettings].isEmpty()) { + notify = true; + } + m_typesToCookie[ChangeScreenSettings].append(cookie); + types |= InterruptSession; // implied by ChangeScreenSettings + } + if (types & InterruptSession) { + // Check if we have to notify + kDebug() << "Added interrupt session"; + if (m_typesToCookie[InterruptSession].isEmpty()) { + notify = true; + } + m_typesToCookie[InterruptSession].append(cookie); + } + + if (notify) { + // Emit the signal - inhibition has changed + emit unavailablePoliciesChanged(unavailablePolicies()); + } +} + +void PolicyAgent::ReleaseInhibition(uint cookie) +{ + kDebug() << "Released inhibition with cookie " << cookie; + m_cookieToAppName.remove(cookie); + QString service = m_cookieToBusService.take(cookie); + if (!m_busWatcher.isNull() && !service.isEmpty() && !m_cookieToBusService.key(service)) { + // no cookies from service left + m_busWatcher.data()->removeWatchedService(service); + } + + // Look through all of the inhibition types + bool notify = false; + if (m_typesToCookie[ChangeProfile].contains(cookie)) { + m_typesToCookie[ChangeProfile].removeOne(cookie); + // Check if we have to notify + if (m_typesToCookie[ChangeProfile].isEmpty()) { + notify = true; + } + } + if (m_typesToCookie[ChangeScreenSettings].contains(cookie)) { + m_typesToCookie[ChangeScreenSettings].removeOne(cookie); + // Check if we have to notify + if (m_typesToCookie[ChangeScreenSettings].isEmpty()) { + notify = true; + } + } + if (m_typesToCookie[InterruptSession].contains(cookie)) { + m_typesToCookie[InterruptSession].removeOne(cookie); + // Check if we have to notify + if (m_typesToCookie[InterruptSession].isEmpty()) { + notify = true; + } + } + + if (notify) { + // Emit the signal - inhibition has changed + emit unavailablePoliciesChanged(unavailablePolicies()); + } +} + +void PolicyAgent::releaseAllInhibitions() +{ + QList< uint > allCookies = m_cookieToAppName.keys(); + foreach (uint cookie, allCookies) { + ReleaseInhibition(cookie); + } +} + +void PolicyAgent::setupSystemdInhibition() +{ + if (m_systemdInhibitFd.fileDescriptor() != -1) + return; + + // inhibit systemd handling of power/sleep/lid buttons + // http://www.freedesktop.org/wiki/Software/systemd/inhibit + QDBusInterface managerIface(SYSTEMD_LOGIN1_SERVICE, SYSTEMD_LOGIN1_PATH, SYSTEMD_LOGIN1_MANAGER_IFACE, QDBusConnection::systemBus()); + kDebug() << "fd passing available:" << bool(managerIface.connection().connectionCapabilities() & QDBusConnection::UnixFileDescriptorPassing); + + QVariantList args; + args << "handle-power-key:handle-suspend-key:handle-hibernate-key:handle-lid-switch"; // what + args << "PowerDevil"; // who + args << "KDE handles power events"; // why + args << "block"; // mode + QDBusPendingReply desc = managerIface.asyncCallWithArgumentList("Inhibit", args); + desc.waitForFinished(); + if (desc.isValid()) { + m_systemdInhibitFd = desc.value(); + kDebug() << "systemd powersave events handling inhibited, descriptor:" << m_systemdInhibitFd.fileDescriptor(); + } + else + kWarning() << "failed to inhibit systemd powersave handling"; +} + +} + +#include "powerdevilpolicyagent.moc" diff --git a/powerdevil/daemon/powerdevilpolicyagent.h b/powerdevil/daemon/powerdevilpolicyagent.h new file mode 100644 index 00000000..aa3d0cd4 --- /dev/null +++ b/powerdevil/daemon/powerdevilpolicyagent.h @@ -0,0 +1,141 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * Copyright (C) 2012 Lukáš Tinkl * + * * + * 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 POWERDEVIL_POWERDEVILPOLICYAGENT_H +#define POWERDEVIL_POWERDEVILPOLICYAGENT_H + +#include +#include +#include + +#include +#include + +#include + +class QDBusServiceWatcher; +class QDBusInterface; + +#define SYSTEMD_LOGIN1_SERVICE "org.freedesktop.login1" +#define SYSTEMD_LOGIN1_PATH "/org/freedesktop/login1" +#define SYSTEMD_LOGIN1_MANAGER_IFACE "org.freedesktop.login1.Manager" +#define SYSTEMD_LOGIN1_SESSION_IFACE "org.freedesktop.login1.Session" +#define SYSTEMD_LOGIN1_SEAT_IFACE "org.freedesktop.login1.Seat" + +#define CONSOLEKIT_SERVICE "org.freedesktop.ConsoleKit" + + +namespace PowerDevil +{ + +class KDE_EXPORT PolicyAgent : public QObject, protected QDBusContext +{ + Q_OBJECT + Q_DISABLE_COPY(PolicyAgent) + + Q_CLASSINFO("D-Bus Interface", "org.kde.Solid.PowerManagement.PolicyAgent") + +public: + enum RequiredPolicy { + None = 0, + InterruptSession = 1, + ChangeProfile = 2, + ChangeScreenSettings = 4 + }; + Q_DECLARE_FLAGS(RequiredPolicies, RequiredPolicy) + + static PolicyAgent *instance(); + + virtual ~PolicyAgent(); + + /** + * This function performs a policy check on given policies, and returns a set of unsatisfiable policies, + * or \c None if all the policies are satisfiable and the action can be carried on. + */ + RequiredPolicies requirePolicyCheck(RequiredPolicies policies); + + RequiredPolicies unavailablePolicies(); + + void setupSystemdInhibition(); + +public Q_SLOTS: + // Exported slots + uint AddInhibition(uint types, const QString &appName, const QString &reason); + void ReleaseInhibition(uint cookie); + + void releaseAllInhibitions(); +Q_SIGNALS: + void unavailablePoliciesChanged(PowerDevil::PolicyAgent::RequiredPolicies newpolicies); + +private Q_SLOTS: + void onServiceUnregistered(const QString & serviceName); + void onSessionHandlerRegistered(const QString & serviceName); + void onSessionHandlerUnregistered(const QString & serviceName); + void onActiveSessionChanged(const QString & ifaceName, const QVariantMap & changedProps, const QStringList & invalidatedProps); + void onActiveSessionChanged(const QString &activeSession); + void forceLockAndWait(); + +private: + explicit PolicyAgent(QObject* parent = 0); + + void init(); + void startSessionInterruption(); + void finishSessionInterruption(); + + void addInhibitionTypeHelper(uint cookie, RequiredPolicies types); + + // This function serves solely for fd.o connector + uint addInhibitionWithExplicitDBusService(uint types, const QString &appName, + const QString &reason, const QString &service); + + // systemd support + QString getNamedPathProperty(const QString & path, const QString & iface, const QString & prop) const; + bool m_sdAvailable; + QString m_activeSessionPath; + QWeakPointer< QDBusInterface > m_sdSessionInterface; + QWeakPointer< QDBusInterface > m_sdSeatInterface; + QDBusUnixFileDescriptor m_systemdInhibitFd; + + // ConsoleKit support + bool m_ckAvailable; + QWeakPointer< QDBusInterface > m_ckSessionInterface; + QWeakPointer< QDBusInterface > m_ckSeatInterface; + bool m_sessionIsBeingInterrupted; + + QHash< uint, QPair< QString, QString > > m_cookieToAppName; + QHash< uint, QString > m_cookieToBusService; + QHash< RequiredPolicy, QList< uint > > m_typesToCookie; + + uint m_lastCookie; + + QWeakPointer< QDBusServiceWatcher > m_busWatcher; + QWeakPointer< QDBusServiceWatcher > m_sdWatcher; + QWeakPointer< QDBusServiceWatcher > m_ckWatcher; + + bool m_wasLastActiveSession; + + friend class Core; + friend class FdoConnector; +}; + +} + +#endif // POWERDEVIL_POWERDEVILPOLICYAGENT_H diff --git a/powerdevil/daemon/powerdevilprofilegenerator.cpp b/powerdevil/daemon/powerdevilprofilegenerator.cpp new file mode 100644 index 00000000..32d1ede8 --- /dev/null +++ b/powerdevil/daemon/powerdevilprofilegenerator.cpp @@ -0,0 +1,359 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 "powerdevilprofilegenerator.h" + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace PowerDevil { + +ProfileGenerator::GeneratorResult ProfileGenerator::generateProfiles(bool toRam, bool toDisk, bool tryUpgrade) +{ + if (tryUpgrade) { + bool isUpgraded = false; + KSharedConfigPtr oldProfilesConfigv1 = KSharedConfig::openConfig("powerdevilprofilesrc", KConfig::SimpleConfig); + if (!oldProfilesConfigv1->groupList().isEmpty()) { + // We can upgrade from v1, let's do that. + upgradeProfilesv1(toRam, toDisk); + isUpgraded = true; + } + KSharedConfigPtr oldProfilesConfigv2 = KSharedConfig::openConfig("powerdevil2profilesrc", KConfig::SimpleConfig); + if (!oldProfilesConfigv2->groupList().isEmpty()) { + // We can upgrade from v2, let's do that. + upgradeProfilesv2(); + isUpgraded = true; + } + + if (isUpgraded) { + return ResultUpgraded; + } + } + + // Let's change some defaults + if (!toRam) { + if (!toDisk) { + PowerDevilSettings::setBatteryCriticalAction(0); + } else { + PowerDevilSettings::setBatteryCriticalAction(2); + } + } + + // Ok, let's get our config file. + KSharedConfigPtr profilesConfig = KSharedConfig::openConfig("powermanagementprofilesrc", KConfig::SimpleConfig); + + // And clear it + foreach (const QString &group, profilesConfig->groupList()) { + // Don't delete activity-specific settings + if (group != "Activities") { + profilesConfig->deleteGroup(group); + } + } + + // Let's start: AC profile before anything else + KConfigGroup acProfile(profilesConfig, "AC"); + acProfile.writeEntry("icon", "battery-charging"); + + // We want to dim the screen after a while, definitely + { + KConfigGroup dimDisplay(&acProfile, "DimDisplay"); + dimDisplay.writeEntry< int >("idleTime", 300000); + } + // Show the dialog when power button is pressed and suspend on suspend button pressed and lid closed (if supported) + { + KConfigGroup handleButtonEvents(&acProfile, "HandleButtonEvents"); + handleButtonEvents.writeEntry< uint >("powerButtonAction", LogoutDialogMode); + if (toRam) { + handleButtonEvents.writeEntry< uint >("lidAction", ToRamMode); + } else { + handleButtonEvents.writeEntry< uint >("lidAction", TurnOffScreenMode); + } + } + + // And we also want to turn off the screen after another while + { + KConfigGroup dpmsControl(&acProfile, "DPMSControl"); + dpmsControl.writeEntry< uint >("idleTime", 600); + } + + // Easy part done. Now, any batteries? + bool hasBattery = false; + + foreach(const Solid::Device &device, Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString())) { + const Solid::Battery *b = qobject_cast (device.asDeviceInterface(Solid::DeviceInterface::Battery)); + if (b->isPowerSupply() && (b->type() == Solid::Battery::PrimaryBattery || b->type() == Solid::Battery::UpsBattery)) { + hasBattery = true; + break; + } + } + + if (hasBattery) { + // Then we want to handle brightness in performance. + { + KConfigGroup brightnessControl(&acProfile, "BrightnessControl"); + brightnessControl.writeEntry< int >("value", 100); + } + } + + // Powersave + KConfigGroup batteryProfile(profilesConfig, "Battery"); + batteryProfile.writeEntry("icon", "battery-060"); + // Less brightness. + { + KConfigGroup brightnessControl(&batteryProfile, "BrightnessControl"); + brightnessControl.writeEntry< int >("value", 60); + } + // We want to dim the screen after a while, definitely + { + KConfigGroup dimDisplay(&batteryProfile, "DimDisplay"); + dimDisplay.writeEntry< int >("idleTime", 120000); + } + // Show the dialog when power button is pressed and suspend on suspend button pressed and lid closed (if supported) + { + KConfigGroup handleButtonEvents(&batteryProfile, "HandleButtonEvents"); + handleButtonEvents.writeEntry< uint >("powerButtonAction", LogoutDialogMode); + if (toRam) { + handleButtonEvents.writeEntry< uint >("lidAction", ToRamMode); + } else { + handleButtonEvents.writeEntry< uint >("lidAction", TurnOffScreenMode); + } + } + // We want to turn off the screen after another while + { + KConfigGroup dpmsControl(&batteryProfile, "DPMSControl"); + dpmsControl.writeEntry< uint >("idleTime", 300); + } + // Last but not least, we want to suspend after a rather long period of inactivity + if (toRam) { + KConfigGroup suspendSession(&batteryProfile, "SuspendSession"); + suspendSession.writeEntry< uint >("idleTime", 600000); + suspendSession.writeEntry< uint >("suspendType", ToRamMode); + } + + + // Ok, now for aggressive powersave + KConfigGroup lowBatteryProfile(profilesConfig, "LowBattery"); + lowBatteryProfile.writeEntry("icon", "battery-low"); + // Less brightness. + { + KConfigGroup brightnessControl(&lowBatteryProfile, "BrightnessControl"); + brightnessControl.writeEntry< int >("value", 30); + } + // We want to dim the screen after a while, definitely + { + KConfigGroup dimDisplay(&lowBatteryProfile, "DimDisplay"); + dimDisplay.writeEntry< int >("idleTime", 60000); + } + // Show the dialog when power button is pressed and suspend on suspend button pressed and lid closed (if supported) + { + KConfigGroup handleButtonEvents(&lowBatteryProfile, "HandleButtonEvents"); + handleButtonEvents.writeEntry< uint >("powerButtonAction", LogoutDialogMode); + if (toRam) { + handleButtonEvents.writeEntry< uint >("lidAction", ToRamMode); + } else { + handleButtonEvents.writeEntry< uint >("lidAction", TurnOffScreenMode); + } + } + // We want to turn off the screen after another while + { + KConfigGroup dpmsControl(&lowBatteryProfile, "DPMSControl"); + dpmsControl.writeEntry< uint >("idleTime", 120); + } + // Last but not least, we want to suspend after a rather long period of inactivity + if (toRam) { + KConfigGroup suspendSession(&lowBatteryProfile, "SuspendSession"); + suspendSession.writeEntry< uint >("idleTime", 300000); + suspendSession.writeEntry< uint >("suspendType", ToRamMode); + } + + // Save and be happy + profilesConfig->sync(); + + return ResultGenerated; +} + +void ProfileGenerator::upgradeProfilesv1(bool toRam, bool toDisk) +{ + // Let's change some defaults + if (!toRam) { + if (!toDisk) { + PowerDevilSettings::setBatteryCriticalAction(None); + } else { + PowerDevilSettings::setBatteryCriticalAction(ToDiskMode); + } + } else { + PowerDevilSettings::setBatteryCriticalAction(ToRamMode); + } + + // Ok, let's get our config file. + KSharedConfigPtr profilesConfig = KSharedConfig::openConfig("powerdevil2profilesrc", KConfig::SimpleConfig); + KSharedConfigPtr oldProfilesConfig = KSharedConfig::openConfig("powerdevilprofilesrc", KConfig::SimpleConfig); + + // And clear it + foreach (const QString &group, profilesConfig->groupList()) { + profilesConfig->deleteGroup(group); + } + + foreach (const QString &group, oldProfilesConfig->groupList()) { + KConfigGroup oldGroup = oldProfilesConfig->group(group); + KConfigGroup newGroup(profilesConfig, oldGroup.readEntry< QString >("name", QString())); + + // Read stuff + // Brightness. + { + KConfigGroup brightnessControl(&newGroup, "BrightnessControl"); + brightnessControl.writeEntry< int >("value", oldGroup.readEntry< int >("brightness", 100)); + } + // Dim screen + if (oldGroup.readEntry< bool >("dimOnIdle", false)) { + KConfigGroup dimDisplay(&newGroup, "DimDisplay"); + dimDisplay.writeEntry< int >("idleTime", oldGroup.readEntry< int >("dimOnIdleTime", 30) * 60 * 1000); + } + // DPMS + if (oldGroup.readEntry< bool >("DPMSEnabled", false) && oldGroup.readEntry< int >("DPMSPowerOff", 0) > 0) { + KConfigGroup dpmsControl(&newGroup, "DPMSControl"); + dpmsControl.writeEntry< uint >("idleTime", oldGroup.readEntry< int >("DPMSPowerOff", 30) * 60); + } + // Script + if (!oldGroup.readEntry< QString >("scriptpath", QString()).isEmpty()) { + KConfigGroup runScript(&newGroup, "RunScript"); + runScript.writeEntry< QString >("scriptCommand", oldGroup.readEntry< QString >("scriptpath", QString())); + runScript.writeEntry< uint >("scriptPhase", 0); + } + // SuspendSession + if (oldGroup.readEntry< uint >("idleAction", 0) > 0) { + KConfigGroup suspendSession(&newGroup, "SuspendSession"); + suspendSession.writeEntry< uint >("idleTime", oldGroup.readEntry< int >("idleTime", 30) * 60 * 1000); + suspendSession.writeEntry< uint >("suspendType", upgradeOldAction(oldGroup.readEntry< uint >("idleAction", 0))); + } + // Buttons + if (oldGroup.readEntry< uint >("powerButtonAction", 0) > 0 || oldGroup.readEntry< uint >("lidAction", 0) > 0) { + KConfigGroup handleButtons(&newGroup, "HandleButtonEvents"); + handleButtons.writeEntry< uint >("powerButtonAction", upgradeOldAction(oldGroup.readEntry< uint >("powerButtonAction", 0))); + handleButtons.writeEntry< uint >("lidAction", upgradeOldAction(oldGroup.readEntry< uint >("lidAction", 0))); + } + } + + // Save and be happy + profilesConfig->sync(); + + // We also want to backup and erase the old profiles. + QString oldProfilesFile = KGlobal::dirs()->findResource("config", "powerdevilprofilesrc"); + if (!oldProfilesFile.isEmpty()) { + // Backup + QString bkProfilesFile = oldProfilesFile; + bkProfilesFile.append(".old"); + KConfig *bkConfig = oldProfilesConfig->copyTo(bkProfilesFile); + if (bkConfig != 0) { + bkConfig->sync(); + delete bkConfig; + + // Delete the old profiles now. + QFile::remove(oldProfilesFile); + } + } +} + +void ProfileGenerator::upgradeProfilesv2() +{ + // Ok, let's get our config file. + KSharedConfigPtr profilesConfig = KSharedConfig::openConfig("powermanagementprofilesrc", KConfig::SimpleConfig); + KSharedConfigPtr oldProfilesConfig = KSharedConfig::openConfig("powerdevil2profilesrc", KConfig::SimpleConfig); + + // And clear it + foreach (const QString &group, profilesConfig->groupList()) { + // Don't delete activity-specific settings + if (group != "Activities") { + profilesConfig->deleteGroup(group); + } + } + + // Ok: back in the days, which profile we used for which task? + { + KConfigGroup oldAC = oldProfilesConfig.data()->group(PowerDevilSettings::aCProfile()); + KConfigGroup newGroup(profilesConfig, "AC"); + + oldAC.copyTo(&newGroup); + } + { + KConfigGroup oldBattery = oldProfilesConfig.data()->group(PowerDevilSettings::batteryProfile()); + KConfigGroup newGroup(profilesConfig, "Battery"); + + oldBattery.copyTo(&newGroup); + } + { + KConfigGroup oldLowBattery = oldProfilesConfig.data()->group(PowerDevilSettings::lowProfile()); + KConfigGroup newGroup(profilesConfig, "LowBattery"); + + oldLowBattery.copyTo(&newGroup); + } + + // Save and be happy + profilesConfig->sync(); + + // We also want to backup and erase the old profiles. + QString oldProfilesFile = KGlobal::dirs()->findResource("config", "powerdevil2profilesrc"); + if (!oldProfilesFile.isEmpty()) { + // Backup + QString bkProfilesFile = oldProfilesFile; + bkProfilesFile.append(".old"); + KConfig *bkConfig = oldProfilesConfig->copyTo(bkProfilesFile); + if (bkConfig != 0) { + bkConfig->sync(); + delete bkConfig; + + // Delete the old profiles now. + QFile::remove(oldProfilesFile); + } + } +} + +uint ProfileGenerator::upgradeOldAction(uint oldAction) +{ + switch ((OldIdleAction)oldAction) { + case Standby: + case S2Ram: + return ToRamMode; + case S2Disk: + return ToDiskMode; + case Shutdown: + return ShutdownMode; + case Lock: + return LockScreenMode; + case ShutdownDialog: + return LogoutDialogMode; + case TurnOffScreen: + return TurnOffScreenMode; + default: + return 0; + } +} + +} diff --git a/powerdevil/daemon/powerdevilprofilegenerator.h b/powerdevil/daemon/powerdevilprofilegenerator.h new file mode 100644 index 00000000..1882e025 --- /dev/null +++ b/powerdevil/daemon/powerdevilprofilegenerator.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2010 by Dario Freddi * + * * + * 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 POWERDEVIL_PROFILEGENERATOR_H +#define POWERDEVIL_PROFILEGENERATOR_H + +class KComponentData; +namespace PowerDevil { + +namespace ProfileGenerator +{ + enum GeneratorResult { + ResultFailed = 0, + ResultGenerated = 1, + ResultUpgraded = 2 + }; + + enum OldIdleAction { + None = 0, + Standby = 1, + S2Ram = 2, + S2Disk = 4, + Shutdown = 8, + Lock = 16, + ShutdownDialog = 32, + TurnOffScreen = 64 + }; + + enum NewMode { + NoneMode = 0, + ToRamMode = 1, + ToDiskMode = 2, + SuspendHybridMode = 4, + ShutdownMode = 8, + LogoutDialogMode = 16, + LockScreenMode = 32, + TurnOffScreenMode = 64 + }; + + GeneratorResult generateProfiles(bool toRam, bool toDisk, bool tryUpgrade = false); + void upgradeProfilesv1(bool toRam, bool toDisk); + void upgradeProfilesv2(); + unsigned int upgradeOldAction(unsigned int actionId); +} + +} + +#endif // POWERDEVIL_PROFILEGENERATOR_H diff --git a/powerdevil/kcmodule/CMakeLists.txt b/powerdevil/kcmodule/CMakeLists.txt new file mode 100644 index 00000000..bb3c13e9 --- /dev/null +++ b/powerdevil/kcmodule/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR}/common + ${CMAKE_CURRENT_BINARY_DIR}/common +) + +add_subdirectory(common) + +add_subdirectory(activities) +add_subdirectory(global) +add_subdirectory(profiles) diff --git a/powerdevil/kcmodule/activities/CMakeLists.txt b/powerdevil/kcmodule/activities/CMakeLists.txt new file mode 100644 index 00000000..a360f302 --- /dev/null +++ b/powerdevil/kcmodule/activities/CMakeLists.txt @@ -0,0 +1,24 @@ + +set( kcm_powerdevil_activities_SRCS + activitypage.cpp + activitywidget.cpp + ../common/ErrorOverlay.cpp +) + +kde4_add_ui_files(kcm_powerdevil_activities_SRCS + activityWidget.ui) + +kde4_add_kcfg_files(kcm_powerdevil_activities_SRCS ../../PowerDevilSettings.kcfgc) + +kde4_add_plugin(kcm_powerdevilactivitiesconfig ${kcm_powerdevil_activities_SRCS}) + +target_link_libraries(kcm_powerdevilactivitiesconfig + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBRARY} + ${KDE4_SOLID_LIBS} + ${KACTIVITIES_LIBRARY} + powerdevilconfigcommonprivate +) + +install(TARGETS kcm_powerdevilactivitiesconfig DESTINATION ${PLUGIN_INSTALL_DIR} ) +install( FILES powerdevilactivitiesconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/powerdevil/kcmodule/activities/Messages.sh b/powerdevil/kcmodule/activities/Messages.sh new file mode 100644 index 00000000..c65284a8 --- /dev/null +++ b/powerdevil/kcmodule/activities/Messages.sh @@ -0,0 +1,5 @@ +#! /bin/sh +$EXTRACTRC `find -name \*.ui -o -name \*.rc -o -name \*.kcfg` >> rc.cpp || exit 11 +$XGETTEXT `find -name \*.cpp -o -name \*.h` -o $podir/powerdevilactivitiesconfig.pot +rm -f rc.cpp + diff --git a/powerdevil/kcmodule/activities/activityWidget.ui b/powerdevil/kcmodule/activities/activityWidget.ui new file mode 100644 index 00000000..ec22df23 --- /dev/null +++ b/powerdevil/kcmodule/activities/activityWidget.ui @@ -0,0 +1,192 @@ + + + ActivityWidget + + + + 0 + 0 + 676 + 474 + + + + + + + + + Don't use special settings + + + true + + + + + + + + + Act like + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Define a special behavior + + + + + + + 30 + + + + + Never shutdown the screen + + + + + + + Never suspend or shutdown the computer + + + + + + + 10 + + + + + Always + + + + + + + + + + after + + + + + + + min + + + 1 + + + 360 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Use separate settings (advanced users only) + + + + + + + 30 + + + + + + + + + Qt::Vertical + + + + 20 + 268 + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+
+ + + + actLikeRadio + toggled(bool) + actLikeComboBox + setEnabled(bool) + + + 44 + 66 + + + 133 + 66 + + + + +
diff --git a/powerdevil/kcmodule/activities/activitypage.cpp b/powerdevil/kcmodule/activities/activitypage.cpp new file mode 100644 index 00000000..d8f11693 --- /dev/null +++ b/powerdevil/kcmodule/activities/activitypage.cpp @@ -0,0 +1,219 @@ +/*************************************************************************** + * Copyright (C) 2011 by Dario Freddi * + * * + * 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 "activitypage.h" + +#include "activitywidget.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +K_PLUGIN_FACTORY(PowerDevilActivitiesKCMFactory, + registerPlugin(); + ) +K_EXPORT_PLUGIN(PowerDevilActivitiesKCMFactory("powerdevilactivitiesconfig","powerdevil")) + +ActivityPage::ActivityPage(QWidget *parent, const QVariantList &args) + : KCModule(PowerDevilActivitiesKCMFactory::componentData(), parent, args) + , m_activityConsumer(new KActivities::Consumer(this)) +{ + setButtons(Apply | Help); + + KAboutData *about = + new KAboutData("powerdevilactivitiesconfig", "powerdevilactivitiesconfig", ki18n("Activities Power Management Configuration"), + "", ki18n("A per-activity configurator of KDE Power Management System"), + KAboutData::License_GPL, ki18n("(c), 2010 Dario Freddi"), + ki18n("From this module, you can fine tune power management settings for each of your activities.")); + + about->addAuthor(ki18n("Dario Freddi"), ki18n("Maintainer") , "drf@kde.org", + "http://drfav.wordpress.com"); + + setAboutData(about); + + // Build the UI + KTabWidget *tabWidget = new KTabWidget(); + QVBoxLayout *lay = new QVBoxLayout(); + + foreach (const QString &activity, m_activityConsumer->listActivities()) { + KActivities::Info *info = new KActivities::Info(activity, this); + QString icon = info->icon(); + QString name = info->name(); + kDebug() << activity << info->isValid() << info->availability(); + + QScrollArea *scrollArea = new QScrollArea(); + scrollArea->setFrameShape(QFrame::NoFrame); + scrollArea->setFrameShadow(QFrame::Plain); + scrollArea->setLineWidth(0); + scrollArea->setWidgetResizable(true); + + ActivityWidget *activityWidget = new ActivityWidget(activity); + scrollArea->setWidget(activityWidget); + + activityWidget->load(); + m_activityWidgets.append(activityWidget); + + connect(activityWidget, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); + + tabWidget->addTab(scrollArea, KIcon(icon), name); + } + + // Message widget + m_messageWidget = new KMessageWidget(i18n("The activity service is running with bare functionalities.\n" + "Names and icons of the activities might not be available.")); + m_messageWidget.data()->setMessageType(KMessageWidget::Warning); + m_messageWidget.data()->hide(); + + lay->addWidget(m_messageWidget.data()); + lay->addWidget(tabWidget); + setLayout(lay); + + connect(m_activityConsumer, SIGNAL(serviceStatusChanged(KActivities::Consumer::ServiceStatus)), + this, SLOT(onActivityServiceStatusChanged(KActivities::Consumer::ServiceStatus))); + onActivityServiceStatusChanged(m_activityConsumer->serviceStatus()); + + QDBusServiceWatcher *watcher = new QDBusServiceWatcher("org.kde.Solid.PowerManagement", + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForRegistration | + QDBusServiceWatcher::WatchForUnregistration, + this); + + connect(watcher, SIGNAL(serviceRegistered(QString)), this, SLOT(onServiceRegistered(QString))); + connect(watcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(onServiceUnregistered(QString))); + + if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.Solid.PowerManagement")) { + onServiceRegistered("org.kde.Solid.PowerManagement"); + } else { + onServiceUnregistered("org.kde.Solid.PowerManagement"); + } +} + +ActivityPage::~ActivityPage() +{ + +} + +void ActivityPage::load() +{ + foreach (ActivityWidget *widget, m_activityWidgets) { + widget->load(); + } + + emit changed(false); +} + +void ActivityPage::save() +{ + foreach (ActivityWidget *widget, m_activityWidgets) { + widget->save(); + } + + emit changed(false); + + // Ask to refresh status + QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", "refreshStatus"); + + // Perform call + QDBusConnection::sessionBus().asyncCall(call); +} + +void ActivityPage::fillUi() +{ + +} + +void ActivityPage::onActivityServiceStatusChanged(KActivities::Consumer::ServiceStatus status) +{ + switch (status) { + case KActivities::Consumer::NotRunning: + // Create error overlay, if not present + if (m_errorOverlay.isNull()) { + m_errorOverlay = new ErrorOverlay(this, i18n("The activity service is not running.\n" + "It is necessary to have the activity manager running " + "to configure activity-specific power management behavior."), + this); + } + break; + case KActivities::Consumer::BareFunctionality: + // Show message widget + m_messageWidget.data()->show(); + break; + case KActivities::Consumer::FullFunctionality: + if (m_previousServiceStatus != KActivities::Consumer::FullFunctionality && + !m_errorOverlay.isNull()) { + m_errorOverlay.data()->deleteLater(); + if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.Solid.PowerManagement")) { + onServiceRegistered("org.kde.Solid.PowerManagement"); + } else { + onServiceUnregistered("org.kde.Solid.PowerManagement"); + } + } + if (m_messageWidget.data()->isVisible()) { + m_messageWidget.data()->hide(); + } + break; + } +} + +void ActivityPage::defaults() +{ + KCModule::defaults(); +} + +void ActivityPage::onServiceRegistered(const QString& service) +{ + Q_UNUSED(service); + + if (!m_errorOverlay.isNull()) { + m_errorOverlay.data()->deleteLater(); + } + + onActivityServiceStatusChanged(m_activityConsumer->serviceStatus()); +} + +void ActivityPage::onServiceUnregistered(const QString& service) +{ + Q_UNUSED(service); + + if (!m_errorOverlay.isNull()) { + return; + } + + m_errorOverlay = new ErrorOverlay(this, i18n("The Power Management Service appears not to be running.\n" + "This can be solved by starting or scheduling it inside \"Startup and Shutdown\""), + this); +} + +#include "activitypage.moc" diff --git a/powerdevil/kcmodule/activities/activitypage.h b/powerdevil/kcmodule/activities/activitypage.h new file mode 100644 index 00000000..230f8354 --- /dev/null +++ b/powerdevil/kcmodule/activities/activitypage.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2011 by Dario Freddi * + * * + * 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 ACTIVITYPAGE_H +#define ACTIVITYPAGE_H + +#include + +#include + +class ErrorOverlay; +class ActivityWidget; +class KMessageWidget; +class ActivityPage : public KCModule +{ + Q_OBJECT + +public: + ActivityPage(QWidget *parent, const QVariantList &args); + virtual ~ActivityPage(); + void fillUi(); + + void load(); + void save(); + virtual void defaults(); + +private Q_SLOTS: + void onActivityServiceStatusChanged(KActivities::Consumer::ServiceStatus status); + void onServiceRegistered(const QString &service); + void onServiceUnregistered(const QString &service); + +private: + KActivities::Consumer *m_activityConsumer; + QList< ActivityWidget* > m_activityWidgets; + QWeakPointer< ErrorOverlay > m_errorOverlay; + QWeakPointer< KMessageWidget > m_messageWidget; + KActivities::Consumer::ServiceStatus m_previousServiceStatus; +}; + +#endif // ACTIVITYPAGE_H diff --git a/powerdevil/kcmodule/activities/activitywidget.cpp b/powerdevil/kcmodule/activities/activitywidget.cpp new file mode 100644 index 00000000..8d9517a7 --- /dev/null +++ b/powerdevil/kcmodule/activities/activitywidget.cpp @@ -0,0 +1,189 @@ +/*************************************************************************** + * Copyright (C) 2011 by Dario Freddi * + * * + * 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 "activitywidget.h" + +#include "ui_activityWidget.h" + +#include "daemon/actions/bundled/suspendsession.h" + +#include +#include +#include +#include + +ActivityWidget::ActivityWidget(const QString& activity, QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::ActivityWidget) + , m_profilesConfig(KSharedConfig::openConfig("powermanagementprofilesrc", KConfig::SimpleConfig | KConfig::CascadeConfig)) + , m_activity(activity) + , m_activityConsumer(new KActivities::Consumer(this)) + , m_actionEditWidget(new ActionEditWidget(QString("Activities/%1/SeparateSettings").arg(activity))) +{ + m_ui->setupUi(this); + + m_ui->separateSettingsLayout->addWidget(m_actionEditWidget); + + for (int i = 0; i < m_ui->specialBehaviorLayout->count(); ++i) { + QWidget *widget = m_ui->specialBehaviorLayout->itemAt(i)->widget(); + if (widget) { + widget->setVisible(false); + connect(m_ui->specialBehaviorRadio, SIGNAL(toggled(bool)), widget, SLOT(setVisible(bool))); + } else { + QLayout *layout = m_ui->specialBehaviorLayout->itemAt(i)->layout(); + if (layout) { + for (int j = 0; j < layout->count(); ++j) { + QWidget *widget = layout->itemAt(j)->widget(); + if (widget) { + widget->setVisible(false); + connect(m_ui->specialBehaviorRadio, SIGNAL(toggled(bool)), widget, SLOT(setVisible(bool))); + } + } + } + } + } + + m_actionEditWidget->setVisible(false); + m_actionEditWidget->load(); + + connect(m_ui->separateSettingsRadio, SIGNAL(toggled(bool)), m_actionEditWidget, SLOT(setVisible(bool))); + + connect(m_ui->actLikeRadio, SIGNAL(toggled(bool)), this, SLOT(setChanged())); + connect(m_ui->noSettingsRadio, SIGNAL(toggled(bool)), this, SLOT(setChanged())); + connect(m_ui->separateSettingsRadio, SIGNAL(toggled(bool)), this, SLOT(setChanged())); + connect(m_ui->specialBehaviorRadio, SIGNAL(toggled(bool)), this, SLOT(setChanged())); + connect(m_ui->actLikeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setChanged())); + connect(m_ui->alwaysActionBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setChanged())); + connect(m_ui->alwaysAfterSpin, SIGNAL(valueChanged(int)), this, SLOT(setChanged())); + + connect(m_actionEditWidget, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); +} + +ActivityWidget::~ActivityWidget() +{ + +} + +void ActivityWidget::load() +{ + KConfigGroup activitiesGroup(m_profilesConfig, "Activities"); + KConfigGroup config = activitiesGroup.group(m_activity); + + using namespace PowerDevil::BundledActions; + + QSet< Solid::PowerManagement::SleepState > methods = Solid::PowerManagement::supportedSleepStates(); + + if (methods.contains(Solid::PowerManagement::SuspendState)) { + m_ui->alwaysActionBox->addItem(KIcon("system-suspend"), + i18n("Sleep"), (uint)SuspendSession::ToRamMode); + } + if (methods.contains(Solid::PowerManagement::HibernateState)) { + m_ui->alwaysActionBox->addItem(KIcon("system-suspend-hibernate"), + i18n("Hibernate"), (uint)SuspendSession::ToDiskMode); + } + m_ui->alwaysActionBox->addItem(KIcon("system-shutdown"), i18n("Shutdown"), (uint)SuspendSession::ShutdownMode); + + m_ui->actLikeComboBox->clear(); + + m_ui->actLikeComboBox->addItem(KIcon("battery-charging"), i18n("PC running on AC power"), "AC"); + m_ui->actLikeComboBox->addItem(KIcon("battery-060"), i18n("PC running on battery power"), "Battery"); + m_ui->actLikeComboBox->addItem(KIcon("battery-low"), i18n("PC running on low battery"), "LowBattery"); + + foreach (const QString &activity, m_activityConsumer->listActivities()) { + if (activity == m_activity) { + continue; + } + + if (activitiesGroup.group(activity).readEntry("mode", "None") == "None" || + activitiesGroup.group(activity).readEntry("mode", "None") == "ActLike") { + continue; + } + + KActivities::Info *info = new KActivities::Info(activity, this); + QString icon = info->icon(); + QString name = i18nc("This is meant to be: Act like activity %1", + "Activity \"%1\"", info->name()); + + m_ui->actLikeComboBox->addItem(KIcon(icon), name, activity); + } + + // Proper loading routine + + if (config.readEntry("mode", QString()) == "ActLike") { + m_ui->actLikeRadio->setChecked(true); + m_ui->actLikeComboBox->setCurrentIndex(m_ui->actLikeComboBox->findData(config.readEntry("actLike", QString()))); + } else if (config.readEntry("mode", QString()) == "SpecialBehavior") { + m_ui->specialBehaviorRadio->setChecked(true); + KConfigGroup behaviorGroup = config.group("SpecialBehavior"); + + m_ui->noShutdownPCBox->setChecked(behaviorGroup.readEntry("noSuspend", false)); + m_ui->noShutdownScreenBox->setChecked(behaviorGroup.readEntry("noScreenManagement", false)); + m_ui->alwaysBox->setChecked(behaviorGroup.readEntry("performAction", false)); + + KConfigGroup actionConfig = behaviorGroup.group("ActionConfig"); + m_ui->alwaysActionBox->setCurrentIndex(m_ui->alwaysActionBox->findData(actionConfig.readEntry("suspendType", 0))); + m_ui->alwaysAfterSpin->setValue(actionConfig.readEntry("idleTime", 600000) / 60 / 1000); + } else if (config.readEntry("mode", QString()) == "SeparateSettings") { + m_ui->separateSettingsRadio->setChecked(true); + + m_actionEditWidget->load(); + } +} + +void ActivityWidget::save() +{ + KConfigGroup activitiesGroup(m_profilesConfig, "Activities"); + KConfigGroup config = activitiesGroup.group(m_activity); + + if (m_ui->actLikeRadio->isChecked()) { + config.writeEntry("mode", "ActLike"); + config.writeEntry("actLike", m_ui->actLikeComboBox->itemData(m_ui->actLikeComboBox->currentIndex()).toString()); + } else if (m_ui->specialBehaviorRadio->isChecked()) { + config.writeEntry("mode", "SpecialBehavior"); + + KConfigGroup behaviorGroup = config.group("SpecialBehavior"); + + behaviorGroup.writeEntry("noSuspend", m_ui->noShutdownPCBox->isChecked()); + behaviorGroup.writeEntry("noScreenManagement", m_ui->noShutdownScreenBox->isChecked()); + behaviorGroup.writeEntry("performAction", m_ui->alwaysBox->isChecked()); + + KConfigGroup actionConfig = behaviorGroup.group("ActionConfig"); + actionConfig.writeEntry("suspendType", m_ui->alwaysActionBox->itemData(m_ui->alwaysActionBox->currentIndex())); + actionConfig.writeEntry("idleTime", m_ui->alwaysAfterSpin->value() * 60 * 1000); + + actionConfig.sync(); + behaviorGroup.sync(); + } else if (m_ui->separateSettingsRadio->isChecked()) { + config.writeEntry("mode", "SeparateSettings"); + m_actionEditWidget->save(); + } else { + config.writeEntry("mode", "None"); + } + + config.sync(); +} + +void ActivityWidget::setChanged() +{ + emit changed(true); +} + + +#include "activitywidget.moc" diff --git a/powerdevil/kcmodule/activities/activitywidget.h b/powerdevil/kcmodule/activities/activitywidget.h new file mode 100644 index 00000000..992029d6 --- /dev/null +++ b/powerdevil/kcmodule/activities/activitywidget.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2011 by Dario Freddi * + * * + * 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 ACTIVITYWIDGET_H +#define ACTIVITYWIDGET_H + +#include +#include + +class ActionEditWidget; +namespace KActivities +{ +class Consumer; +} // namespace KActivities + +namespace Ui { +class ActivityWidget; +} + +class ActivityWidget : public QWidget +{ + Q_OBJECT +public: + explicit ActivityWidget(const QString &activity, QWidget *parent = 0); + virtual ~ActivityWidget(); + +public Q_SLOTS: + void load(); + void save(); + + void setChanged(); + +Q_SIGNALS: + void changed(bool changed); + +private: + Ui::ActivityWidget *m_ui; + KSharedConfig::Ptr m_profilesConfig; + QString m_activity; + KActivities::Consumer *m_activityConsumer; + ActionEditWidget* m_actionEditWidget; +}; + +#endif // ACTIVITYWIDGET_H diff --git a/powerdevil/kcmodule/activities/powerdevilactivitiesconfig.desktop b/powerdevil/kcmodule/activities/powerdevilactivitiesconfig.desktop new file mode 100644 index 00000000..b0980312 --- /dev/null +++ b/powerdevil/kcmodule/activities/powerdevilactivitiesconfig.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +Exec=kcmshell4 powerdevilactivitiesconfig +Icon=preferences-activities +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/powerdevil/index.html#activity-setting + +X-KDE-Library=kcm_powerdevilactivitiesconfig +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=power-management +X-KDE-Weight=50 + +Name=Activity Settings +Name[bs]=Postavke aktivnosti +Name[ca]=Arranjament d'activitat +Name[ca@valencia]=Arranjament d'activitat +Name[cs]=Nastavení aktivit +Name[da]=Aktivitetsindstillinger +Name[de]=Aktivitäten-Einstellungen +Name[el]=Ρυθμίσεις δραστηριοτήτων +Name[en_GB]=Activity Settings +Name[es]=Preferencias de la actividad +Name[et]=Tegevuse seadistused +Name[eu]=Jarduera-ezarpenak +Name[fi]=Aktiviteettiasetukset +Name[fr]=Configuration des activités +Name[ga]=Socruithe Gníomhaíochta +Name[gl]=Configuración da actividade +Name[he]=הגדרות של פעילות +Name[hu]=Aktivitásjellemzők +Name[ia]=Preferentias de activitate +Name[is]=Virknistillingar +Name[kk]=Істің параметрлері +Name[km]=ការ​កំណត់​សកម្មភាព +Name[ko]=활동 설정 +Name[lt]=Veiklos nustatymai +Name[mr]=कार्यपध्दती संयोजना +Name[nb]=Aktivitetsinnstillinger +Name[nds]=Aktiviteteninstellen +Name[nl]=Instellingen voor activiteiten +Name[pa]=ਐਕਟਵਿਟੀ ਸੈਟਿੰਗ +Name[pl]=Ustawienia działań +Name[pt]=Configuração da Actividade +Name[pt_BR]=Configurações da atividade +Name[ro]=Configurare activități +Name[ru]=Настройка для комнат +Name[sk]=Nastavenie aktivity +Name[sl]=Nastavitve dejavnosti +Name[sr]=Поставке активности +Name[sr@ijekavian]=Поставке активности +Name[sr@ijekavianlatin]=Postavke aktivnosti +Name[sr@latin]=Postavke aktivnosti +Name[sv]=Inställningar av aktiviteter +Name[tr]=Etkinlik Ayarları +Name[uk]=Параметри простору дій +Name[vi]=Thiết lập Hoạt động +Name[x-test]=xxActivity Settingsxx +Name[zh_CN]=活动设置 +Name[zh_TW]=活動設定 + +Comment=Configure per-activity Power Management +Comment[bs]=Konfiguracija po aktivnosti upravljanja napajanjem +Comment[ca]=Configura l'arranjament per activitat de gestió d'energia +Comment[ca@valencia]=Configura l'arranjament per activitat de gestió d'energia +Comment[cs]=Konfigurace správy napájení na činnost +Comment[da]=Indstil strømstyring pr. aktivitet +Comment[de]=Energieprofile pro Aktivität einzeln einrichten +Comment[el]=Διαμόρφωση ανά δραστηριότητα επιλογών διαχείρισης ενέργειας +Comment[en_GB]=Configure per-activity Power Management +Comment[es]=Configurar de las preferencias de la gestión de energía por actividad +Comment[et]=Toitehalduse seadistused tegevuste kaupa +Comment[eu]=Konfiguratu energia-kudeaketa jardueraka +Comment[fi]=Virranhallinnan aktiviteettikohtaiset asetukset +Comment[fr]=Configuration de la gestion d'énergie par activité +Comment[gl]=Configura a xestión da enerxía para cada actividade +Comment[he]=הגדרות צריכת חשמל לפי פעילות +Comment[hu]=Aktivitásonkénti energiakezelési beállítások módosítása +Comment[ia]=Configura gestion de energia per activitate +Comment[is]=Stilla orkustýringu á hverja virkni +Comment[kk]=Әрбір істің қуаттандыру параметрлерін баптау +Comment[km]=កំណត់​រចនាសម្ព័ន្ធក​នៃ​ការ​គ្រប់គ្រង​ថាមពល​ក្នុង​មួយ​សកម្មភាព +Comment[ko]=활동별 전원 관리 설정 +Comment[lt]=Konfigūruoti atskiros veiklos energijos valdymo nustatymus +Comment[mr]=प्रत्येक कार्यपध्दती साठी वीज व्यवस्थापन संयोजीत करा +Comment[nb]=Sett opp strømstyring per aktivitet +Comment[nds]=Stroompleeg för enkelte Aktiviteten instellen +Comment[nl]=Energiebeheer per activiteit instellen +Comment[pa]=ਪ੍ਰਤੀ-ਸਰਗਰਮੀ ਪਾਵਰ ਪਰਬੰਧ ਸੈਟਿੰਗ ਸੰਰਚਨਾ +Comment[pl]=Ustawienia zarządzania energią w zależności od działania +Comment[pt]=Configurar a Gestão de Energia por Actividade +Comment[pt_BR]=Configura o gerenciamento de energia por atividade +Comment[ro]=Configurează gestiunea alimentării per activitate +Comment[ru]=Настройка параметров энергосбережения для комнат +Comment[sk]=Nastaviť nastavenia správy napájania podľa aktivity +Comment[sl]=Nastavi upravljanje z energijo glede na dejavnost +Comment[sr]=Подешавање управљања напајањем према активности +Comment[sr@ijekavian]=Подешавање управљања напајањем према активности +Comment[sr@ijekavianlatin]=Podešavanje upravljanja napajanjem prema aktivnosti +Comment[sr@latin]=Podešavanje upravljanja napajanjem prema aktivnosti +Comment[sv]=Anpassa inställningar av strömhantering per aktivitet +Comment[tr]=Her Etkinlik için Genel Güç Yönetimi Ayarlarını Yapılandır +Comment[uk]=Налаштування окремих параметрів керування живленням простору дій +Comment[vi]=Cấu hình Quản lý năng lượng cho từng Hoạt động +Comment[x-test]=xxConfigure per-activity Power Managementxx +Comment[zh_CN]=配置基于活动的电源管理 +Comment[zh_TW]=設定個別活動的電源管理 + +X-KDE-Keywords=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities +X-KDE-Keywords[bs]=Sistem, Napajanje, Upravljanje napajanjem, energija, laptop, baterija, suspenzija, AC, suspendiraj, hiberniranje, osvljetljenje, perfomanse, kapak, aktivnost, aktivnosti +X-KDE-Keywords[ca]=sistema,energia,gestió d'energia,corrent,portàtil,bateria,suspensió,AC,suspendre,hibernació,lluminositat,rendiment,tapa,activitat,activitats +X-KDE-Keywords[ca@valencia]=sistema,energia,gestió d'energia,corrent,portàtil,bateria,suspensió,AC,suspendre,hibernació,lluminositat,rendiment,tapa,activitat,activitats +X-KDE-Keywords[da]=system,strøm,strømstyring,energi,laptop,bærbar,batteri,suspension,AC,strømforsyning,suspender,slumre,dvale,lysstyrke,ydelse,låg,aktivitet,aktiviteter +X-KDE-Keywords[de]=system,energie,energieverwaltung,laptop,notebook,akku,batterie,ruhezustand,tiefschlaf,helligkeit,leistung,deckel,aktivität +X-KDE-Keywords[el]=σύστημα,ενέργεια,διαχείριση ενέργειας,ενέργεια,φορητός,μπαταρία,αναστολή,AC,κοίμηση,νάρκη,λαμπρότητα,επιδόσεις,καπάκι,δραστηριότητα,δραστηριότητες +X-KDE-Keywords[en_GB]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities +X-KDE-Keywords[es]=sistema,energía,gestión de energía,energía,portátil,batería,suspensión,AC,suspender,hibernar,brillo,rendimiento,tapa,actividad,actividades +X-KDE-Keywords[et]=süsteem,energia,toide,toitehaldus,sülearvuti,aku,uneseisund,uni,talveuni, heledus,jõudlus,kaas,tegevus,tegevused +X-KDE-Keywords[eu]=sistema,energia,energia-kudeaketa,energia,eramangarria,bateria,egonean,korronte alternoa,egonean uztea,hibernatu,distira,errendimendua,tapa,jarduera,jarduerak +X-KDE-Keywords[fi]=järjestelmä,virta,virranhallinta,energia,kannettava,tietokone,läppäri,akku,lepotila,valmiustila,keskeytä,AC,virtalähde,kirkkaus,suorituskyky,kansi,aktiviteetti,aktiviteetit +X-KDE-Keywords[fr]=système, alimentation, gestion énergétique, énergie, portable, batterie, suspension, AC, suspendre, hiberner, luminosité, performance, capot, activité, activités +X-KDE-Keywords[gl]=sistema,enerxía,xestión da enerxía, xestión enerxética,carga,portátil,batería, suspender,corrente,hibernar,durmir,brillo,rendemento,tapa,actividade +X-KDE-Keywords[hu]=rendszer,energia,energiakezelés,energia,laptop,akkumulátor,AC,felfüggesztés,hibernálás,fényerő,teljesítmény,fedél,aktivitás,aktivitások +X-KDE-Keywords[ia]=systema,potentia,gestion de potentia,energia,laptop,batteria,suspension,CA,suspende,hiberna,brillantia,prestation,coperculo,activitate,activitates +X-KDE-Keywords[kk]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities +X-KDE-Keywords[km]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities +X-KDE-Keywords[ko]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities,시스템,전원,전원 관리,에너지,노트북,배터리,어댑터,절전,대기 모드,대기,최대 절전,최대 절전 모드,밝기,성능,덮개,상판,활동 +X-KDE-Keywords[mr]=प्रणाली, वीज, वीज व्यवस्थापन, ऊर्जा, लैपटॉप, बॅटरी, अकार्यक्षम, AC, अकार्यक्षम, हायबरनेट, प्रखरता, लिड, कार्य +X-KDE-Keywords[nb]=system,strøm,strømstyring,energi,bærbar,batteri,hvilemodus,AC,hvile,dvale,lysstyrke,ytelse,lokk,aktivitet,aktiviteter +X-KDE-Keywords[nds]=Systeem,Stroom,Stroompleeg,Energie,Klappreekner,Batterie,utsetten,AC,Wesselstroom,infreren,Helligkeit,Leisten,Aktiviteet,Aktiviteten +X-KDE-Keywords[nl]=systeem,energie,energiebeheer,laptop,batterij,accu,suspension,AC,onderbreken,slapen,helderheid,prestaties,deksel,activiteit,activiteiten +X-KDE-Keywords[pl]=system,moc,zarządzanie energią,energia,laptop,bateria,wstrzymanie,AC,wstrzymaj,hibernuj,jasność,wydajność,pokrywka,działanie,działania +X-KDE-Keywords[pt]=sistema,energia,gestão de energia,portátil,bateria,suspensão,AC,suspender,hibernar,brilho,performance,tampo,actividade,actividades +X-KDE-Keywords[pt_BR]=sistema,energia,gerenciamento de energia,energia,portátil,laptop,notebook,bateria,suspensão,AC,suspender,hibernar,brilho,desempenho,tampa,atividade,atividades +X-KDE-Keywords[ru]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities,системное,питание,управление питанием,энергопотребление,ноутбук,батарея,спящий режим,гибернация,ждущий режим,яркость,производительность,крышка,комната,комнаты +X-KDE-Keywords[sk]=systém,napájanie,správa napájanie,energia,laptop,batéria,uspanie,AC,uspať,hibernovať,jas,výkon,kryt,aktivita,aktivity +X-KDE-Keywords[sl]=sistem,energija,upravljanje z energijo,prenosnik,prenosni računalnik,baterija,akumulator,pripravljenost,mirovanje,električno omrežje,svetlost,zmogljivost,pokrov,dejavnost,dejavnosti,napajanje +X-KDE-Keywords[sr]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities,систем,напајање,струја,управљање напајањем,лаптоп,батерија,суспендовање,АЦ,хибернација,светлина,осветљај,перформансе,поклопац,активност +X-KDE-Keywords[sr@ijekavian]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities,систем,напајање,струја,управљање напајањем,лаптоп,батерија,суспендовање,АЦ,хибернација,светлина,осветљај,перформансе,поклопац,активност +X-KDE-Keywords[sr@ijekavianlatin]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities,sistem,napajanje,struja,upravljanje napajanjem,laptop,baterija,suspendovanje,AC,hibernacija,svetlina,osvetljaj,performanse,poklopac,aktivnost +X-KDE-Keywords[sr@latin]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities,sistem,napajanje,struja,upravljanje napajanjem,laptop,baterija,suspendovanje,AC,hibernacija,svetlina,osvetljaj,performanse,poklopac,aktivnost +X-KDE-Keywords[sv]=system,kraft,krafthantering,energi,bärbar dator,batteri,viloläge,AC,gå till viloläge,dvala,ljusstyrka,prestanda,lock,aktivitet,aktiviteter +X-KDE-Keywords[tr]=sistem,güç,güç yönetimi,enerji,dizüstü,pil,askıya alma,Adaptör,uyku kipi,hazırda bekletme,parlaklık,performans,başarım,dizüstü kapağı,ekran parlaklığı,etkinlik,etkinlikler +X-KDE-Keywords[uk]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities,система,живлення,мережа,струм,керування,енергія,ноутбук,акумулятор,батарея,батареї,присипляння,призупинення,призупинка,яскравість,швидкодія,кришка,кришки,простір,дій,простори,активність +X-KDE-Keywords[x-test]=xxsystem,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activitiesxx +X-KDE-Keywords[zh_CN]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities,系统,电源,电源管理,能源,笔记本,电池,休眠,睡眠,交流,亮度,性能,活动 +X-KDE-Keywords[zh_TW]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,activity,activities diff --git a/powerdevil/kcmodule/common/CMakeLists.txt b/powerdevil/kcmodule/common/CMakeLists.txt new file mode 100644 index 00000000..be16362b --- /dev/null +++ b/powerdevil/kcmodule/common/CMakeLists.txt @@ -0,0 +1,19 @@ + +set( powerdevil_config_common_private_SRCS + actionconfigwidget.cpp + actioneditwidget.cpp + ErrorOverlay.cpp +) + +kde4_add_library(powerdevilconfigcommonprivate SHARED ${powerdevil_config_common_private_SRCS}) + +target_link_libraries(powerdevilconfigcommonprivate + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBRARY} + powerdevilcore + powerdevilui +) + +set_target_properties(powerdevilconfigcommonprivate PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) + +install( TARGETS powerdevilconfigcommonprivate ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/powerdevil/kcmodule/common/ErrorOverlay.cpp b/powerdevil/kcmodule/common/ErrorOverlay.cpp new file mode 100644 index 00000000..732e9962 --- /dev/null +++ b/powerdevil/kcmodule/common/ErrorOverlay.cpp @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 2011 by Dario Freddi * + * * + * 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 "ErrorOverlay.h" + +#include +#include +#include + +#include +#include +#include + +static const KCatalogLoader loader("libpowerdevilcommonconfig"); + +ErrorOverlay::ErrorOverlay(QWidget *baseWidget, const QString &details, QWidget *parent) : + QWidget(parent ? parent : baseWidget->window()), + m_BaseWidget(baseWidget) +{ + // Build the UI + QVBoxLayout *layout = new QVBoxLayout; + layout->setSpacing(10); + + QLabel *pixmap = new QLabel(); + pixmap->setPixmap(KIcon("dialog-error").pixmap(64)); + + QLabel *message = new QLabel(i18n("Power Management configuration module could not be loaded.\n%1", details)); + + pixmap->setAlignment(Qt::AlignHCenter); + message->setAlignment(Qt::AlignHCenter); + + layout->addStretch(); + layout->addWidget(pixmap); + layout->addWidget(message); + layout->addStretch(); + + setLayout(layout); + + // Draw the transparent overlay background + QPalette p = palette(); + p.setColor(backgroundRole(), QColor(0, 0, 0, 128)); + p.setColor(foregroundRole(), Qt::white); + setPalette(p); + setAutoFillBackground(true); + + m_BaseWidget->installEventFilter(this); + + reposition(); +} + +ErrorOverlay::~ErrorOverlay() +{ +} + +void ErrorOverlay::reposition() +{ + if (!m_BaseWidget) { + return; + } + + // reparent to the current top level widget of the base widget if needed + // needed eg. in dock widgets + if (parentWidget() != m_BaseWidget->window()) { + setParent(m_BaseWidget->window()); + } + + // follow base widget visibility + // needed eg. in tab widgets + if (!m_BaseWidget->isVisible()) { + hide(); + return; + } + + show(); + + // follow position changes + const QPoint topLevelPos = m_BaseWidget->mapTo(window(), QPoint(0, 0)); + const QPoint parentPos = parentWidget()->mapFrom(window(), topLevelPos); + move(parentPos); + + // follow size changes + // TODO: hide/scale icon if we don't have enough space + resize(m_BaseWidget->size()); +} + +bool ErrorOverlay::eventFilter(QObject * object, QEvent * event) +{ + if (object == m_BaseWidget && + (event->type() == QEvent::Move || event->type() == QEvent::Resize || + event->type() == QEvent::Show || event->type() == QEvent::Hide || + event->type() == QEvent::ParentChange)) { + reposition(); + } + return QWidget::eventFilter(object, event); +} + +#include "ErrorOverlay.moc" diff --git a/powerdevil/kcmodule/common/ErrorOverlay.h b/powerdevil/kcmodule/common/ErrorOverlay.h new file mode 100644 index 00000000..8081e758 --- /dev/null +++ b/powerdevil/kcmodule/common/ErrorOverlay.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2011 by Dario Freddi * + * * + * 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 ERROROVERLAY_H +#define ERROROVERLAY_H + +#include + +#include + +class KDE_EXPORT ErrorOverlay : public QWidget +{ + Q_OBJECT +public: + explicit ErrorOverlay(QWidget *baseWidget, const QString &details, QWidget *parent = 0); + virtual ~ErrorOverlay(); + +protected: + bool eventFilter(QObject *object, QEvent *event); + +private: + void reposition(); + +private: + QWidget *m_BaseWidget; +}; + +#endif // ERROROVERLAY_H diff --git a/powerdevil/kcmodule/common/Messages.sh b/powerdevil/kcmodule/common/Messages.sh new file mode 100644 index 00000000..e982c361 --- /dev/null +++ b/powerdevil/kcmodule/common/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT `find -name \*.cpp -o -name \*.h` -o $podir/libpowerdevilcommonconfig.pot diff --git a/powerdevil/kcmodule/common/actionconfigwidget.cpp b/powerdevil/kcmodule/common/actionconfigwidget.cpp new file mode 100644 index 00000000..1f291b62 --- /dev/null +++ b/powerdevil/kcmodule/common/actionconfigwidget.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (C) 2010 by Sebastian Kugler * + * * + * 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 "actionconfigwidget.h" + +#include +#include +#include +#include +#include +#include + +ActionConfigWidget::ActionConfigWidget(QWidget* parent) : QWidget(parent) +{ + m_gridLayout = new QGridLayout(this); + /* + QLabel* l = new QLabel( this ); + l->setText( "Hello World!" ); + + m_gridLayout->addWidget(l, 0, 0); + */ +} + +ActionConfigWidget::~ActionConfigWidget() +{} + + +void ActionConfigWidget::addWidgets(QList > configMap) +{ + int row = m_gridLayout->rowCount(); + row++; + + QCheckBox* currentSectionCheckbox = 0; + /* + //Clean the values + QList::const_iterator it; + for (it = list.constBegin(); it != list.constEnd(); ++it) { + QString tempString = *it; + tempString = tempString.trimmed(); + tempString = tempString.mid(1, tempString.length()-2); + versionList.append(tempString); + } + */ + QList >::const_iterator it; + for (it = configMap.constBegin(); it != configMap.constEnd(); ++it) { + //foreach (QPair line, configMap) { + QPair line = *it; + if (line.first.isEmpty()) { + // A title checkbox + currentSectionCheckbox = qobject_cast(line.second); + currentSectionCheckbox->setChecked(true); + currentSectionCheckbox->setStyleSheet("font-weight: bold;"); + m_gridLayout->addWidget(line.second, row, 0, 1, 3); + } else { + // connect enabled / disabled + QLabel* label = new QLabel(this); + label->setText(line.first); + + m_gridLayout->addItem(new QSpacerItem(50 ,3), row, 0); + m_gridLayout->addWidget(label, row, 1, Qt::AlignRight); + m_gridLayout->addWidget(line.second, row, 2); + + connect(currentSectionCheckbox, SIGNAL(toggled(bool)), + label, SLOT(setEnabled(bool))); + connect(currentSectionCheckbox, SIGNAL(toggled(bool)), + line.second, SLOT(setEnabled(bool))); + } + row++; + } +} + +#include "actionconfigwidget.moc" diff --git a/powerdevil/kcmodule/common/actionconfigwidget.h b/powerdevil/kcmodule/common/actionconfigwidget.h new file mode 100644 index 00000000..a8c72a10 --- /dev/null +++ b/powerdevil/kcmodule/common/actionconfigwidget.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2010 by Sebastian Kugler * + * * + * 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 ACTIONCONFIG_H +#define ACTIONCONFIG_H + +#include +#include + +#include +#include +#include + +#include + +class KDE_EXPORT ActionConfigWidget : public QWidget +{ +Q_OBJECT +public: + ActionConfigWidget(QWidget* parent); + ~ActionConfigWidget(); + + void addWidgets(QList > configMap); + +private: + QGridLayout* m_gridLayout; +}; + +#endif // ActionConfigWidget_H diff --git a/powerdevil/kcmodule/common/actioneditwidget.cpp b/powerdevil/kcmodule/common/actioneditwidget.cpp new file mode 100644 index 00000000..116564fc --- /dev/null +++ b/powerdevil/kcmodule/common/actioneditwidget.cpp @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright (C) 2008-2011 by Dario Freddi * + * * + * 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 "actioneditwidget.h" + +#include "actionconfigwidget.h" + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +ActionEditWidget::ActionEditWidget(const QString &configName, QWidget *parent) + : QWidget(parent) + , m_configName(configName) +{ + m_profilesConfig = KSharedConfig::openConfig("powermanagementprofilesrc", KConfig::SimpleConfig | KConfig::CascadeConfig); + + ActionConfigWidget *actionConfigWidget = new ActionConfigWidget(0); + QMap< int, QList > > widgets; + + // Load all the services + KService::List offers = KServiceTypeTrader::self()->query("PowerDevil/Action", "(Type == 'Service')"); + + foreach (const KService::Ptr &offer, offers) { + // Does it have a runtime requirement? + if (offer->property("X-KDE-PowerDevil-Action-HasRuntimeRequirement", QVariant::Bool).toBool()) { + kDebug() << offer->name() << " has a runtime requirement"; + + QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", "isActionSupported"); + call.setArguments(QVariantList() << offer->property("X-KDE-PowerDevil-Action-ID", QVariant::String)); + QDBusPendingReply< bool > reply = QDBusConnection::sessionBus().asyncCall(call); + reply.waitForFinished(); + + if (reply.isValid()) { + if (!reply.value()) { + kDebug() << "The action " << offer->property("X-KDE-PowerDevil-Action-ID", QVariant::String) << " appears not to be supported by the core."; + continue; + } + } else { + kDebug() << "There was a problem in contacting DBus!! Assuming the action is ok."; + } + } + + //try to load the specified library + KPluginFactory *factory = KPluginLoader(offer->property("X-KDE-PowerDevil-Action-UIComponentLibrary", + QVariant::String).toString()).factory(); + + if (!factory) { + kError() << "KPluginFactory could not load the plugin:" << offer->property("X-KDE-PowerDevil-Action-UIComponentLibrary", + QVariant::String).toString(); + continue; + } + + PowerDevil::ActionConfig *actionConfig = factory->create(); + if (!actionConfig) { + kError() << "KPluginFactory could not load the plugin:" << offer->property("X-KDE-PowerDevil-Action-UIComponentLibrary", + QVariant::String).toString(); + continue; + } + + connect(actionConfig, SIGNAL(changed()), this, SLOT(onChanged())); + + QCheckBox *checkbox = new QCheckBox(offer->name()); + if (!offer->icon().isEmpty()) { + checkbox->setIcon(KIcon(offer->icon())); + } + connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(onChanged())); + m_actionsHash.insert(offer->property("X-KDE-PowerDevil-Action-ID", QVariant::String).toString(), checkbox); + m_actionsConfigHash.insert(offer->property("X-KDE-PowerDevil-Action-ID", QVariant::String).toString(), actionConfig); + + QList > offerWidgets = actionConfig->buildUi(); + offerWidgets.prepend(qMakePair(QString(), checkbox)); + widgets.insertMulti(100 - offer->property("X-KDE-PowerDevil-Action-ConfigPriority", QVariant::Int).toInt(), + offerWidgets); + } + + for (QMap< int, QList > >::const_iterator i = widgets.constBegin(); i != widgets.constEnd(); ++i) { + actionConfigWidget->addWidgets(i.value()); + } + + QVBoxLayout *lay = new QVBoxLayout; + lay->addWidget(actionConfigWidget); + lay->addStretch(); + setLayout(lay); +} + +ActionEditWidget::~ActionEditWidget() +{ + +} + +void ActionEditWidget::load() +{ + KConfigGroup group = configGroup(); + + kDebug() << m_profilesConfig.data()->entryMap().keys(); + + if (!group.isValid()) { + return; + } + kDebug() << "Ok, KConfigGroup ready" << group.entryMap().keys(); + + // Iterate over the possible actions + for (QHash< QString, QCheckBox* >::const_iterator i = m_actionsHash.constBegin(); i != m_actionsHash.constEnd(); ++i) { + i.value()->setChecked(group.groupList().contains(i.key())); + + KConfigGroup actionGroup = group.group(i.key()); + m_actionsConfigHash[i.key()]->setConfigGroup(actionGroup); + m_actionsConfigHash[i.key()]->load(); + } + + emit changed(false); +} + +void ActionEditWidget::save() +{ + KConfigGroup group = configGroup(); + + if (!group.isValid()) { + kDebug() << "Could not perform a save operation, group is not valid!"; + return; + } + + // Iterate over the possible actions + for (QHash< QString, QCheckBox* >::const_iterator i = m_actionsHash.constBegin(); i != m_actionsHash.constEnd(); ++i) { + if (i.value()->isChecked()) { + // Perform the actual save + m_actionsConfigHash[i.key()]->save(); + } else { + // Erase the group + group.deleteGroup(i.key()); + } + } + + group.sync(); + + // After saving, reload the config to make sure we'll pick up changes. + m_profilesConfig.data()->reparseConfiguration(); + + emit changed(false); +} + +void ActionEditWidget::onChanged() +{ + emit changed(true); +} + +QString ActionEditWidget::configName() const +{ + return m_configName; +} + +KConfigGroup ActionEditWidget::configGroup() +{ + if (!m_configName.contains('/')) { + return KConfigGroup(m_profilesConfig, m_configName); + } else { + QStringList names = m_configName.split('/'); + KConfigGroup retgroup(m_profilesConfig, names.first()); + + QStringList::const_iterator i = names.constBegin(); + ++i; + + while (i != names.constEnd()) { + retgroup = retgroup.group(*i); + ++i; + } + + return retgroup; + } +} + +#include "actioneditwidget.moc" diff --git a/powerdevil/kcmodule/common/actioneditwidget.h b/powerdevil/kcmodule/common/actioneditwidget.h new file mode 100644 index 00000000..7fcde8fc --- /dev/null +++ b/powerdevil/kcmodule/common/actioneditwidget.h @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2008-2011 by Dario Freddi * + * * + * 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 ACTIONEDITWIDGET_H +#define ACTIONEDITWIDGET_H + +#include + +#include + +#include + +namespace PowerDevil +{ +class ActionConfig; +} + +class QCheckBox; +class KConfigGroup; + +class KDE_EXPORT ActionEditWidget : public QWidget +{ + Q_OBJECT +public: + explicit ActionEditWidget(const QString &configName, QWidget *parent = 0); + virtual ~ActionEditWidget(); + + QString configName() const; + +public Q_SLOTS: + void load(); + void save(); + +private Q_SLOTS: + void onChanged(); + +Q_SIGNALS: + void changed(bool changed); + +private: + KConfigGroup configGroup(); + +private: + QString m_configName; + KSharedConfig::Ptr m_profilesConfig; + QHash< QString, QCheckBox* > m_actionsHash; + QHash< QString, PowerDevil::ActionConfig* > m_actionsConfigHash; +}; + +#endif // ACTIONEDITWIDGET_H diff --git a/powerdevil/kcmodule/global/CMakeLists.txt b/powerdevil/kcmodule/global/CMakeLists.txt new file mode 100644 index 00000000..0c72dc65 --- /dev/null +++ b/powerdevil/kcmodule/global/CMakeLists.txt @@ -0,0 +1,23 @@ + +set( kcm_powerdevil_global_SRCS + GeneralPage.cpp +) + +kde4_add_ui_files(kcm_powerdevil_global_SRCS + generalPage.ui) + +kde4_add_kcfg_files(kcm_powerdevil_global_SRCS ../../PowerDevilSettings.kcfgc) + +kde4_add_plugin(kcm_powerdevilglobalconfig ${kcm_powerdevil_global_SRCS}) + +target_link_libraries(kcm_powerdevilglobalconfig + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBRARY} + ${KDE4_KIO_LIBS} + ${KDE4_SOLID_LIBS} + ${KDE4_KNOTIFYCONFIG_LIBRARY} + powerdevilconfigcommonprivate +) + +install(TARGETS kcm_powerdevilglobalconfig DESTINATION ${PLUGIN_INSTALL_DIR} ) +install( FILES powerdevilglobalconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/powerdevil/kcmodule/global/GeneralPage.cpp b/powerdevil/kcmodule/global/GeneralPage.cpp new file mode 100644 index 00000000..fabeae5f --- /dev/null +++ b/powerdevil/kcmodule/global/GeneralPage.cpp @@ -0,0 +1,214 @@ +/*************************************************************************** + * Copyright (C) 2008 by Dario Freddi * + * * + * 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 "GeneralPage.h" + +#include "ErrorOverlay.h" +#include "PowerDevilSettings.h" + +#include "daemon/actions/bundled/suspendsession.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +K_PLUGIN_FACTORY(PowerDevilGeneralKCMFactory, + registerPlugin(); + ) +K_EXPORT_PLUGIN(PowerDevilGeneralKCMFactory("powerdevilglobalconfig","powerdevil")) + +typedef QMap< QString, QString > StringStringMap; +Q_DECLARE_METATYPE(StringStringMap) + +GeneralPage::GeneralPage(QWidget *parent, const QVariantList &args) + : KCModule(PowerDevilGeneralKCMFactory::componentData(), parent, args) +{ + qDBusRegisterMetaType< StringStringMap >(); + + setButtons(Apply | Help); + + KAboutData *about = + new KAboutData("powerdevilglobalconfig", "powerdevilglobalconfig", ki18n("Global Power Management Configuration"), + "", ki18n("A global power management configurator for KDE Power Management System"), + KAboutData::License_GPL, ki18n("(c), 2010 Dario Freddi"), + ki18n("From this module, you can configure the main Power Management daemon, assign profiles to " + "states, and do some advanced fine tuning on battery handling")); + + about->addAuthor(ki18n("Dario Freddi"), ki18n("Maintainer") , "drf@kde.org", + "http://drfav.wordpress.com"); + + setAboutData(about); + + setupUi(this); + + fillUi(); + + QDBusServiceWatcher *watcher = new QDBusServiceWatcher("org.kde.Solid.PowerManagement", + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForRegistration | + QDBusServiceWatcher::WatchForUnregistration, + this); + + connect(watcher, SIGNAL(serviceRegistered(QString)), this, SLOT(onServiceRegistered(QString))); + connect(watcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(onServiceUnregistered(QString))); + + if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.Solid.PowerManagement")) { + onServiceRegistered("org.kde.Solid.PowerManagement"); + } else { + onServiceUnregistered("org.kde.Solid.PowerManagement"); + } +} + +GeneralPage::~GeneralPage() +{ +} + +void GeneralPage::fillUi() +{ + bool hasBattery = false; + + foreach(const Solid::Device &device, Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString())) { + const Solid::Battery *b = qobject_cast (device.asDeviceInterface(Solid::DeviceInterface::Battery)); + if(b->type() == Solid::Battery::PrimaryBattery || b->type() == Solid::Battery::UpsBattery) { + hasBattery = true; + break; + } + } + + eventsIconLabel->setPixmap(KIcon("preferences-desktop-notification").pixmap(24)); + batteryLevelsIconLabel->setPixmap(KIcon("battery").pixmap(24)); + + QSet< Solid::PowerManagement::SleepState > methods = Solid::PowerManagement::supportedSleepStates(); + + BatteryCriticalCombo->addItem(KIcon("dialog-cancel"), i18n("Do nothing"), PowerDevil::BundledActions::SuspendSession::None); + if (methods.contains(Solid::PowerManagement::SuspendState)) { + BatteryCriticalCombo->addItem(KIcon("system-suspend"), i18n("Sleep"), PowerDevil::BundledActions::SuspendSession::ToRamMode); + } + if (methods.contains(Solid::PowerManagement::HibernateState)) { + BatteryCriticalCombo->addItem(KIcon("system-suspend-hibernate"), i18n("Hibernate"), PowerDevil::BundledActions::SuspendSession::ToDiskMode); + } + BatteryCriticalCombo->addItem(KIcon("system-shutdown"), i18n("Shutdown"), PowerDevil::BundledActions::SuspendSession::ShutdownMode); + + notificationsButton->setIcon(KIcon("preferences-desktop-notification")); + + // modified fields... + + connect(lockScreenOnResume, SIGNAL(stateChanged(int)), SLOT(changed())); + connect(doNotInhibitLid, SIGNAL(stateChanged(int)), SLOT(changed())); + + connect(notificationsButton, SIGNAL(clicked()), SLOT(configureNotifications())); + + connect(lowSpin, SIGNAL(valueChanged(int)), SLOT(changed())); + connect(criticalSpin, SIGNAL(valueChanged(int)), SLOT(changed())); + + connect(BatteryCriticalCombo, SIGNAL(currentIndexChanged(int)), SLOT(changed())); + + // Disable stuff, eventually + if (!hasBattery) { + batteryLevelsIconLabel->hide(); + batteryLevelsLabel->hide(); + + BatteryCriticalLabel->hide(); + BatteryCriticalCombo->hide(); + lowLabel->hide(); + lowSpin->hide(); + criticalLabel->hide(); + criticalSpin->hide(); + } +} + +void GeneralPage::load() +{ + lockScreenOnResume->setChecked(PowerDevilSettings::configLockScreen()); + doNotInhibitLid->setChecked(PowerDevilSettings::doNotInhibitOnLidClose()); + + lowSpin->setValue(PowerDevilSettings::batteryLowLevel()); + criticalSpin->setValue(PowerDevilSettings::batteryCriticalLevel()); + + BatteryCriticalCombo->setCurrentIndex(BatteryCriticalCombo->findData(PowerDevilSettings::batteryCriticalAction())); +} + +void GeneralPage::configureNotifications() +{ + KNotifyConfigWidget::configure(this, "powerdevil"); +} + +void GeneralPage::save() +{ + PowerDevilSettings::setConfigLockScreen(lockScreenOnResume->isChecked()); + PowerDevilSettings::setDoNotInhibitOnLidClose(doNotInhibitLid->isChecked()); + + PowerDevilSettings::setBatteryLowLevel(lowSpin->value()); + PowerDevilSettings::setBatteryCriticalLevel(criticalSpin->value()); + + PowerDevilSettings::setBatteryCriticalAction(BatteryCriticalCombo->itemData(BatteryCriticalCombo->currentIndex()).toInt()); + + PowerDevilSettings::self()->writeConfig(); + + // Notify Daemon + QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", "refreshStatus"); + + // Perform call + QDBusConnection::sessionBus().asyncCall(call); + + // And now we are set with no change + emit changed(false); +} + +void GeneralPage::defaults() +{ + KCModule::defaults(); +} + +void GeneralPage::onServiceRegistered(const QString& service) +{ + Q_UNUSED(service); + + if (!m_errorOverlay.isNull()) { + m_errorOverlay.data()->deleteLater(); + } +} + +void GeneralPage::onServiceUnregistered(const QString& service) +{ + Q_UNUSED(service); + + if (!m_errorOverlay.isNull()) { + m_errorOverlay.data()->deleteLater(); + } + + m_errorOverlay = new ErrorOverlay(this, i18n("The Power Management Service appears not to be running.\n" + "This can be solved by starting or scheduling it inside \"Startup and Shutdown\""), + this); +} + +#include "GeneralPage.moc" diff --git a/powerdevil/kcmodule/global/GeneralPage.h b/powerdevil/kcmodule/global/GeneralPage.h new file mode 100644 index 00000000..a34d54f1 --- /dev/null +++ b/powerdevil/kcmodule/global/GeneralPage.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2008 by Dario Freddi * + * * + * 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 GENERALPAGE_H +#define GENERALPAGE_H + +#include + +#include "ui_generalPage.h" + +class ErrorOverlay; +class GeneralPage : public KCModule, private Ui_generalPage +{ + Q_OBJECT + +public: + GeneralPage(QWidget *parent, const QVariantList &args); + virtual ~GeneralPage(); + void fillUi(); + + void load(); + void save(); + virtual void defaults(); + +private slots: + void configureNotifications(); + void onServiceRegistered(const QString &service); + void onServiceUnregistered(const QString &service); + +private: + QWeakPointer< ErrorOverlay > m_errorOverlay; +}; + +#endif /* GENERALPAGE_H */ diff --git a/powerdevil/kcmodule/global/Messages.sh b/powerdevil/kcmodule/global/Messages.sh new file mode 100755 index 00000000..e67d1b5e --- /dev/null +++ b/powerdevil/kcmodule/global/Messages.sh @@ -0,0 +1,5 @@ +#! /bin/sh +$EXTRACTRC `find -name \*.ui -o -name \*.rc -o -name \*.kcfg` >> rc.cpp || exit 11 +$XGETTEXT `find -name \*.cpp -o -name \*.h` -o $podir/powerdevilglobalconfig.pot +rm -f rc.cpp + diff --git a/powerdevil/kcmodule/global/generalPage.ui b/powerdevil/kcmodule/global/generalPage.ui new file mode 100644 index 00000000..798b1ee6 --- /dev/null +++ b/powerdevil/kcmodule/global/generalPage.ui @@ -0,0 +1,301 @@ + + + generalPage + + + + 0 + 0 + 761 + 436 + + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + + + + <b>Battery levels</b> + + + + + + + + + QFormLayout::ExpandingFieldsGrow + + + + + Battery is at low level at + + + lowSpin + + + + + + + + 100 + 16777215 + + + + Low battery level + + + Battery will be considered low when it reaches this level + + + % + + + 100 + + + + + + + Battery is at critical level at + + + criticalSpin + + + + + + + + 100 + 16777215 + + + + Critical battery level + + + Battery will be considered critical when it reaches this level + + + % + + + 100 + + + + + + + When battery is at critical level + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + BatteryCriticalCombo + + + + + + + + 300 + 16777215 + + + + + + + + + + 4 + + + + + + 24 + 24 + + + + + 16 + 16777215 + + + + + + + + + + + <b>Events</b> + + + + + + + + + 30 + + + + + Lock screen on resume + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lockScreenOnResume + + + + + + + Locks screen when waking up from suspension + + + + + + You will be asked for a password when resuming from sleep state + + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Configure Notifications... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + When this option is selected, applications will not be allowed to inhibit sleep when the lid is closed + + + When this option is selected, applications will not be allowed to inhibit sleep when the lid is closed + + + Never prevent an action on lid close + + + + + + + When this option is selected, applications will not be allowed to inhibit sleep when the lid is closed + + + When this option is selected, applications will not be allowed to inhibit sleep when the lid is closed + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KIntSpinBox + QSpinBox +
knuminput.h
+
+
+ + +
diff --git a/powerdevil/kcmodule/global/powerdevilglobalconfig.desktop b/powerdevil/kcmodule/global/powerdevilglobalconfig.desktop new file mode 100644 index 00000000..011dbcac --- /dev/null +++ b/powerdevil/kcmodule/global/powerdevilglobalconfig.desktop @@ -0,0 +1,148 @@ +[Desktop Entry] +Exec=kcmshell4 powerdevilglobalconfig +Icon=preferences-other +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/powerdevil/index.html#advanced-settings + +X-KDE-Library=kcm_powerdevilglobalconfig +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=power-management +X-KDE-Weight=99 + +Name=Advanced Settings +Name[bs]=Napredne postavke +Name[ca]=Arranjament avançat +Name[ca@valencia]=Arranjament avançat +Name[cs]=Pokročilá nastavení +Name[da]=Avancerede indstillinger +Name[de]=Erweiterte Einstellungen +Name[el]=Προχωρημένες ρυθμίσεις +Name[en_GB]=Advanced Settings +Name[es]=Preferencias avanzadas +Name[et]=Muud seadistused +Name[eu]=Ezarpen aurreratuak +Name[fi]=Lisäasetukset +Name[fr]=Configuration avancée +Name[ga]=Ardsocruithe +Name[gl]=Configuración avanzada +Name[he]=הגדרות מתקדמות +Name[hu]=Speciális beállítások +Name[ia]=Preferentias Avantiate +Name[is]=Ítarlegar stillingar +Name[kk]=Жетелеп баптау +Name[km]=ការ​កំណត់​​កម្រិត​ខ្ពស់ +Name[ko]=고급 설정 +Name[lt]=Išsamesni nustatymai +Name[mr]=प्रगत संयोजना +Name[nb]=Avanserte innstillinger +Name[nds]=Verwiedert Instellen +Name[nl]=Geavanceerde instellingen +Name[pa]=ਤਕਨੀਕੀ ਸੈਟਿੰਗ +Name[pl]=Ustawienia zaawansowane +Name[pt]=Configuração Avançada +Name[pt_BR]=Configurações avançadas +Name[ro]=Configurări avansate +Name[ru]=Дополнительные параметры +Name[sk]=Pokročilé nastavenia +Name[sl]=Napredne nastavitve +Name[sr]=Напредне поставке +Name[sr@ijekavian]=Напредне поставке +Name[sr@ijekavianlatin]=Napredne postavke +Name[sr@latin]=Napredne postavke +Name[sv]=Avancerade inställningar +Name[tr]=Gelişmiş ayarlar +Name[uk]=Додаткові параметри +Name[vi]=Thiết lập nâng cao +Name[x-test]=xxAdvanced Settingsxx +Name[zh_CN]=高级设置 +Name[zh_TW]=進階設定 + +Comment=Configure Advanced Power Management Settings +Comment[bs]=Napredno podešavanje i upravljanje napajanjem +Comment[ca]=Configura l'arranjament avançat de gestió d'energia +Comment[ca@valencia]=Configura l'arranjament avançat de gestió d'energia +Comment[cs]=Nastavení pokročilého nastavení správy napájení +Comment[da]=Indstil avanceret strømstyring +Comment[de]=Erweiterte Energieprofile einrichten +Comment[el]=Διαμόρφωση προχωρημένων επιλογών διαχείρισης ενέργειας +Comment[en_GB]=Configure Advanced Power Management Settings +Comment[es]=Configurar las preferencias avanzadas de la gestión de energía +Comment[et]=Toitehalduse muud seadistused +Comment[eu]=Konfiguratu energia kudeatzeko ezarpen aurreratuak +Comment[fi]=Virranhallinnan lisäasetukset +Comment[fr]=Configuration avancée de la gestion d'énergie +Comment[ga]=Cumraigh Ardsocruithe Bhainisteoireacht Cumhachta +Comment[gl]=Configura a xestión avanzada da enerxía +Comment[he]=הגדרות מתקדמות של חיסכון בצריכת חשמל +Comment[hu]=Speciális energiakezelési beállítások módosítása +Comment[ia]=Configura preferentias avantiate de gestion de energia +Comment[is]=Stilla ítarlegar orkustillingar +Comment[kk]=Қуаттандыруның жетелеген параметрлерін баптау +Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​នៃ​ការ​កំណត់​ការ​គ្រប់គ្រង​ថាមពល +Comment[ko]=고급 전원 관리 설정 +Comment[lt]=Konfigūruoti išsamesnius energijos valdymo nustatymus +Comment[mr]=प्रगत वीज व्यवस्थापन संयोजीत करा +Comment[nb]=Sett avanserte strømstyringsinnstillinger +Comment[nds]=Verwiedert Stroompleeginstellen +Comment[nl]=Instellingen voor geavanceerd energiebeheer configureren +Comment[pa]=ਤਕਨੀਕੀ ਪਾਵਰ ਪਰਬੰਧ ਸੈਟਿੰਗ ਸੰਰਚਨਾ +Comment[pl]=Ustawienia zaawansowane zarządzania energią +Comment[pt]=Configurar a Gestão de Energia Avançada +Comment[pt_BR]=Configura as opções avançadas de gerenciamento de energia +Comment[ro]=Configurează opțiunile avansate de gestiune a alimentării +Comment[ru]=Настройка дополнительных параметров энергосбережения +Comment[sk]=Nastaviť nastavenia pokročilej správy napájania +Comment[sl]=Nastavi napredno upravljanje z energijo +Comment[sr]=Подешавање напредних поставки за управљање напајањем +Comment[sr@ijekavian]=Подешавање напредних поставки за управљање напајањем +Comment[sr@ijekavianlatin]=Podešavanje naprednih postavki za upravljanje napajanjem +Comment[sr@latin]=Podešavanje naprednih postavki za upravljanje napajanjem +Comment[sv]=Anpassa avancerade inställningar av strömhantering +Comment[tr]=Gelişmiş Güç Yönetimi Ayarlarını Yapılandır +Comment[uk]=Налаштування додаткових параметрів керування живленням +Comment[vi]=Cấu hình các thiết lập cho Quản lý năng lượng nâng cao +Comment[x-test]=xxConfigure Advanced Power Management Settingsxx +Comment[zh_CN]=配置高级电源管理设置 +Comment[zh_TW]=設定進階電源管理 + +X-KDE-Keywords=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid +X-KDE-Keywords[bs]=Sistem, Napajanje, Upravljanje napajanjem, energija, laptop, baterija, suspenzija, AC, suspendiraj, hiberniranje, osvljetljenje, kapak, +X-KDE-Keywords[ca]=sistema,energia,gestió d'energia,corrent,portàtil,bateria,suspensió,AC,suspèn,hiberna,lluminositat,rendiment,tapa +X-KDE-Keywords[ca@valencia]=sistema,energia,gestió d'energia,corrent,portàtil,bateria,suspensió,AC,suspèn,hiberna,lluminositat,rendiment,tapa +X-KDE-Keywords[da]=system,strøm,strømstyring,energi,laptop,bærbar,batteri,suspension,AC,strømforsyning,suspender,slumre,dvale,lysstyrke,ydelse,låg +X-KDE-Keywords[de]=system,energie,energieverwaltung,laptop,notebook,akku,batterie,ruhezustand,tiefschlaf,helligkeit,leistung,deckel +X-KDE-Keywords[el]=σύστημα,ενέργεια,διαχείριση ενέργειας,ενέργεια,φορητός,μπαταρία,αναστολή,AC,κοίμηση,νάρκη,λαμπρότητα,επιδόσεις,καπάκι +X-KDE-Keywords[en_GB]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid +X-KDE-Keywords[es]=sistema,energía,gestión de energía,energía,portátil,batería,suspensión,AC,suspender,hibernar,brillo,rendimiento,tapa +X-KDE-Keywords[et]=süsteem,energia,toide,toitehaldus,sülearvuti,aku,uneseisund,uni,talveuni, heledus,jõudlus,kaas +X-KDE-Keywords[eu]=sistema,energia,energia-kudeaketa,energia,eramangarria,bateria,egonean,korronte alternoa,egonean uztea,hibernatu,distira,errendimendua,tapa +X-KDE-Keywords[fi]=järjestelmä,virta,virranhallinta,energia,kannettava,tietokone,läppäri,akku,lepotila,valmiustila,AC,virtalähde,keskeytä,kirkkaus,suorituskyky,kansi +X-KDE-Keywords[fr]=système, alimentation, gestion énergétique, énergie, portable, batterie, suspension, AC, suspendre, hiberner, luminosité, performance, capot +X-KDE-Keywords[gl]=sistema,enerxía,xestión da enerxía, xestión enerxética,carga,portátil,batería, suspender,corrente,hibernar,durmir,brillo,rendemento,tapa +X-KDE-Keywords[hu]=rendszer,energia,energiakezelés,energia,laptop,akkumulátor,AC,felfüggesztés,hibernálás,fényerő,teljesítmény,fedél +X-KDE-Keywords[ia]=systema,potentia,gestion de potentia,energia,laptop,batteria,suspension,CA,suspende,hiberna,brillantia,prestation,coperculo +X-KDE-Keywords[kk]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid +X-KDE-Keywords[km]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid +X-KDE-Keywords[ko]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,시스템,전원,전원 관리,에너지,노트북,배터리,어댑터,절전,대기 모드,대기,최대 절전,최대 절전 모드,밝기,성능,덮개,상판 +X-KDE-Keywords[mr]=प्रणाली, वीज, वीज व्यवस्थापन, ऊर्जा, लैपटॉप, बॅटरी, अकार्यक्षम, AC, अकार्यक्षम, हायबरनेट, प्रखरता, लिड +X-KDE-Keywords[nb]=system,strøm,strømstyring,energi,bærbar,batteri,hvilemodus,AC,hvile,dvale,lysstyrke,ytelse,lokk +X-KDE-Keywords[nds]=Systeem,Stroom,Stroompleeg,Energie,Klappreekner,Batterie,utsetten,AC,Wesselstroom,infreren,Helligkeit,Leisten +X-KDE-Keywords[nl]=systeem,energie,energiebeheer,laptop,batterij,accu,suspension,AC,onderbreken,slapen,helderheid,prestaties,deksel +X-KDE-Keywords[pl]=system,moc,zarządzanie energią,energia,laptop,bateria,wstrzymanie,AC,wstrzymaj,hibernuj,jasność,wydajność,pokrywka +X-KDE-Keywords[pt]=sistema,energia,gestão de energia,portátil,bateria,suspensão,AC,suspender,hibernar,brilho,performance,tampo +X-KDE-Keywords[pt_BR]=sistema,energia,gerenciamento de energia,energia,notebook,laptop,portátil,bateria,suspensão,AC,suspender,hibernar,brilho,desempenho,tampa +X-KDE-Keywords[ru]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,системное,питание,управление питанием,энергопотребление,ноутбук,батарея,спящий режим,гибернация,ждущий режим,яркость,производительность,крышка +X-KDE-Keywords[sk]=systém,napájanie,správa napájanie,energia,laptop,batéria,uspanie,AC,uspať,hibernovať,jas,výkon,kryt +X-KDE-Keywords[sl]=sistem,energija,upravljanje z energijo,prenosnik,prenosni računalnik,baterija,akumulator,pripravljenost,mirovanje,električno omrežje,svetlost,zmogljivost,pokrov,napajanje +X-KDE-Keywords[sr]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,систем,напајање,струја,управљање напајањем,лаптоп,батерија,суспендовање,АЦ,хибернација,светлина,осветљај,перформансе,поклопац +X-KDE-Keywords[sr@ijekavian]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,систем,напајање,струја,управљање напајањем,лаптоп,батерија,суспендовање,АЦ,хибернација,светлина,осветљај,перформансе,поклопац +X-KDE-Keywords[sr@ijekavianlatin]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,sistem,napajanje,struja,upravljanje napajanjem,laptop,baterija,suspendovanje,AC,hibernacija,svetlina,osvetljaj,performanse,poklopac +X-KDE-Keywords[sr@latin]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,sistem,napajanje,struja,upravljanje napajanjem,laptop,baterija,suspendovanje,AC,hibernacija,svetlina,osvetljaj,performanse,poklopac +X-KDE-Keywords[sv]=system,kraft,krafthantering,energi,bärbar dator,batteri,viloläge,AC,gå till viloläge,dvala,ljusstyrka,prestanda,lock +X-KDE-Keywords[tr]=sistem,güç,güç yönetimi,enerji,dizüstü,pil,askıya alma,Adaptör,uyku kipi,hazırda bekletme,parlaklık,performans,başarım,dizüstü kapağı,ekran parlaklığı +X-KDE-Keywords[uk]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,система,живлення,мережа,струм,керування,енергія,ноутбук,акумулятор,батарея,батареї,присипляння,призупинення,призупинка,яскравість,швидкодія,кришка,кришки +X-KDE-Keywords[x-test]=xxsystem,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lidxx +X-KDE-Keywords[zh_CN]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,系统,电源,电源管理,能源,笔记本,电池,休眠,睡眠,交流,亮度,性能 +X-KDE-Keywords[zh_TW]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid diff --git a/powerdevil/kcmodule/profiles/CMakeLists.txt b/powerdevil/kcmodule/profiles/CMakeLists.txt new file mode 100644 index 00000000..f09c2ec1 --- /dev/null +++ b/powerdevil/kcmodule/profiles/CMakeLists.txt @@ -0,0 +1,24 @@ + +set( kcm_powerdevil_profiles_SRCS + EditPage.cpp + ../../daemon/powerdevilprofilegenerator.cpp +) + +kde4_add_ui_files(kcm_powerdevil_profiles_SRCS + profileEditPage.ui) + +kde4_add_kcfg_files(kcm_powerdevil_profiles_SRCS ../../PowerDevilSettings.kcfgc) + +kde4_add_plugin(kcm_powerdevilprofilesconfig ${kcm_powerdevil_profiles_SRCS}) + +target_link_libraries(kcm_powerdevilprofilesconfig + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBRARY} + ${KDE4_KIO_LIBS} + ${KDE4_SOLID_LIBS} + powerdevilui + powerdevilconfigcommonprivate +) + +install(TARGETS kcm_powerdevilprofilesconfig DESTINATION ${PLUGIN_INSTALL_DIR} ) +install( FILES powerdevilprofilesconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/powerdevil/kcmodule/profiles/EditPage.cpp b/powerdevil/kcmodule/profiles/EditPage.cpp new file mode 100644 index 00000000..0865b90e --- /dev/null +++ b/powerdevil/kcmodule/profiles/EditPage.cpp @@ -0,0 +1,300 @@ +/*************************************************************************** + * Copyright (C) 2008-2010 by Dario Freddi * + * * + * 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 "EditPage.h" + +#include "actioneditwidget.h" +#include "ErrorOverlay.h" + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +K_PLUGIN_FACTORY(PowerDevilProfilesKCMFactory, + registerPlugin(); + ) +K_EXPORT_PLUGIN(PowerDevilProfilesKCMFactory("powerdevilprofilesconfig","powerdevil")) + +typedef QMap< QString, QString > StringStringMap; +Q_DECLARE_METATYPE(StringStringMap) + +EditPage::EditPage(QWidget *parent, const QVariantList &args) + : KCModule(PowerDevilProfilesKCMFactory::componentData(), parent, args) +{ + qDBusRegisterMetaType< StringStringMap >(); + + setButtons(Apply | Help | Default); + + KAboutData *about = + new KAboutData("powerdevilprofilesconfig", "powerdevilprofilesconfig", ki18n("Power Profiles Configuration"), + "", ki18n("A profile configurator for KDE Power Management System"), + KAboutData::License_GPL, ki18n("(c), 2010 Dario Freddi"), + ki18n("From this module, you can manage KDE Power Management System's power profiles, by tweaking " + "existing ones or creating new ones.")); + + about->addAuthor(ki18n("Dario Freddi"), ki18n("Maintainer") , "drf@kde.org", + "http://drfav.wordpress.com"); + + setAboutData(about); + + setupUi(this); + + m_profilesConfig = KSharedConfig::openConfig("powermanagementprofilesrc", KConfig::SimpleConfig | KConfig::CascadeConfig); + + if (m_profilesConfig->groupList().isEmpty()) { + // Use the generator + QSet methods = Solid::PowerManagement::supportedSleepStates(); + PowerDevil::ProfileGenerator::generateProfiles( + methods.contains(Solid::PowerManagement::SuspendState), + methods.contains(Solid::PowerManagement::HibernateState) + ); + m_profilesConfig->reparseConfiguration(); + } + + kDebug() << m_profilesConfig.data()->groupList() << m_profilesConfig.data()->entryMap().keys(); + + // Create widgets for each profile + ActionEditWidget *editWidget = new ActionEditWidget("AC"); + m_editWidgets.insert("AC", editWidget); + acWidgetLayout->addWidget(editWidget); + connect(editWidget, SIGNAL(changed(bool)), this, SLOT(onChanged(bool))); + tabWidget->setTabIcon(0, KIcon("battery-charging")); + + editWidget = new ActionEditWidget("Battery"); + m_editWidgets.insert("Battery", editWidget); + batteryWidgetLayout->addWidget(editWidget); + connect(editWidget, SIGNAL(changed(bool)), this, SLOT(onChanged(bool))); + tabWidget->setTabIcon(1, KIcon("battery-060")); + + editWidget = new ActionEditWidget("LowBattery"); + m_editWidgets.insert("LowBattery", editWidget); + lowBatteryWidgetLayout->addWidget(editWidget); + connect(editWidget, SIGNAL(changed(bool)), this, SLOT(onChanged(bool))); + tabWidget->setTabIcon(2, KIcon("battery-low")); + + QDBusServiceWatcher *watcher = new QDBusServiceWatcher("org.kde.Solid.PowerManagement", + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForRegistration | + QDBusServiceWatcher::WatchForUnregistration, + this); + + connect(watcher, SIGNAL(serviceRegistered(QString)), this, SLOT(onServiceRegistered(QString))); + connect(watcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(onServiceUnregistered(QString))); + + bool hasBattery = false; + foreach(const Solid::Device &device, Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString())) { + const Solid::Battery *b = qobject_cast (device.asDeviceInterface(Solid::DeviceInterface::Battery)); + if (b->isPowerSupply() && (b->type() == Solid::Battery::PrimaryBattery || b->type() == Solid::Battery::UpsBattery)) { + hasBattery = true; + break; + } + } + + if (!hasBattery) { + tabWidget->setTabEnabled(1, false); + tabWidget->setTabEnabled(2, false); + tabWidget->setTabBarHidden(true); + } + + if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.Solid.PowerManagement")) { + onServiceRegistered("org.kde.Solid.PowerManagement"); + } else { + onServiceUnregistered("org.kde.Solid.PowerManagement"); + } +} + +EditPage::~EditPage() +{ +} + +void EditPage::onChanged(bool value) +{ + ActionEditWidget *editWidget = qobject_cast< ActionEditWidget* >(sender()); + if (!editWidget) { + return; + } + + m_profileEdited[editWidget->configName()] = value; + + if (value) { + emit changed(true); + } + + checkAndEmitChanged(); +} + +void EditPage::load() +{ + kDebug() << "Loading routine called"; + for (QHash< QString, ActionEditWidget* >::const_iterator i = m_editWidgets.constBegin(); + i != m_editWidgets.constEnd(); ++i) { + i.value()->load(); + + m_profileEdited[i.value()->configName()] = false; + } +} + +void EditPage::save() +{ + QStringList profiles; + + for (QHash< QString, ActionEditWidget* >::const_iterator i = m_editWidgets.constBegin(); + i != m_editWidgets.constEnd(); ++i) { + i.value()->save(); + if (m_profileEdited[i.value()->configName()]) { + profiles.append(i.value()->configName()); + } + + m_profileEdited[i.value()->configName()] = false; + } + // Notify the daemon + notifyDaemon(profiles); + + emit changed(false); +} + +void EditPage::notifyDaemon(const QStringList &editedProfiles) +{ + QDBusMessage call; + if (!editedProfiles.isEmpty()) { + call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", "currentProfile"); + QDBusPendingReply< QString > reply = QDBusConnection::sessionBus().asyncCall(call); + reply.waitForFinished(); + + if (reply.isValid()) { + if (!editedProfiles.contains(reply.value())) { + // Ask to reparse config + kDebug() << "Inactive profile edited, reparsing configuration"; + call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", "reparseConfiguration"); + + // Perform call + QDBusConnection::sessionBus().asyncCall(call); + return; + } + } + } + + // Refresh status + call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement", + "org.kde.Solid.PowerManagement", "refreshStatus"); + + // Perform call + QDBusConnection::sessionBus().asyncCall(call); +} + +void EditPage::restoreDefaultProfiles() +{ + // Confirm + int ret = KMessageBox::warningContinueCancel(this, i18n("The KDE Power Management System will now generate a set of defaults " + "based on your computer's capabilities. This will also erase " + "all existing modifications you made. " + "Are you sure you want to continue?"), i18n("Restore Default Profiles")); + if (ret == KMessageBox::Continue) { + kDebug() << "Restoring defaults."; + QSet methods = Solid::PowerManagement::supportedSleepStates(); + PowerDevil::ProfileGenerator::generateProfiles( + methods.contains(Solid::PowerManagement::SuspendState), + methods.contains(Solid::PowerManagement::HibernateState) + ); + + load(); + + // Notify the daemon + notifyDaemon(); + } +} + +void EditPage::openUrl(const QString &url) +{ + new KRun(KUrl(url), this); +} + +void EditPage::defaults() +{ + restoreDefaultProfiles(); +} + +void EditPage::checkAndEmitChanged() +{ + bool value = false; + for (QHash< QString, bool >::const_iterator i = m_profileEdited.constBegin(); + i != m_profileEdited.constEnd(); ++i) { + if (i.value()) { + value = i.value(); + } + } + + emit changed(value); +} + +void EditPage::onServiceRegistered(const QString& service) +{ + Q_UNUSED(service); + + if (!m_errorOverlay.isNull()) { + m_errorOverlay.data()->deleteLater(); + } +} + +void EditPage::onServiceUnregistered(const QString& service) +{ + Q_UNUSED(service); + + if (!m_errorOverlay.isNull()) { + m_errorOverlay.data()->deleteLater(); + } + + m_errorOverlay = new ErrorOverlay(this, i18n("The Power Management Service appears not to be running.\n" + "This can be solved by starting or scheduling it inside \"Startup and Shutdown\""), + this); +} + +#include "EditPage.moc" diff --git a/powerdevil/kcmodule/profiles/EditPage.h b/powerdevil/kcmodule/profiles/EditPage.h new file mode 100644 index 00000000..27ccbed9 --- /dev/null +++ b/powerdevil/kcmodule/profiles/EditPage.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2008 by Dario Freddi * + * * + * 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 EDITPAGE_H +#define EDITPAGE_H + +#include + +#include "ui_profileEditPage.h" + +class ActionEditWidget; +namespace PowerDevil { +class ActionConfig; +} + +class ErrorOverlay; +class QCheckBox; +class KToolBar; + +class EditPage : public KCModule, private Ui_profileEditPage +{ + Q_OBJECT + +public: + explicit EditPage(QWidget *parent, const QVariantList &args); + ~EditPage(); + + void load(); + void save(); + virtual void defaults(); + +private slots: + void onChanged(bool changed); + + void restoreDefaultProfiles(); + + void notifyDaemon(const QStringList &editedProfiles = QStringList()); + + void openUrl(const QString &url); + + void onServiceRegistered(const QString &service); + void onServiceUnregistered(const QString &service); + + void checkAndEmitChanged(); + +private: + KSharedConfig::Ptr m_profilesConfig; + QHash< QString, bool > m_profileEdited; + QWeakPointer< ErrorOverlay > m_errorOverlay; + QHash< QString, ActionEditWidget* > m_editWidgets; +}; + +#endif /* EDITPAGE_H */ diff --git a/powerdevil/kcmodule/profiles/Messages.sh b/powerdevil/kcmodule/profiles/Messages.sh new file mode 100755 index 00000000..02ddd3e1 --- /dev/null +++ b/powerdevil/kcmodule/profiles/Messages.sh @@ -0,0 +1,5 @@ +#! /bin/sh +$EXTRACTRC `find -name \*.ui -o -name \*.rc -o -name \*.kcfg` >> rc.cpp || exit 11 +$XGETTEXT `find -name \*.cpp -o -name \*.h` -o $podir/powerdevilprofilesconfig.pot +rm -f rc.cpp + diff --git a/powerdevil/kcmodule/profiles/powerdevilprofilesconfig.desktop b/powerdevil/kcmodule/profiles/powerdevilprofilesconfig.desktop new file mode 100644 index 00000000..105719db --- /dev/null +++ b/powerdevil/kcmodule/profiles/powerdevilprofilesconfig.desktop @@ -0,0 +1,148 @@ +[Desktop Entry] +Exec=kcmshell4 powerdevilprofilesconfig +Icon=preferences-system-power-management +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/powerdevil/index.html + +X-KDE-Library=kcm_powerdevilprofilesconfig +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=power-management +X-KDE-Weight=1 + +Name=Energy Saving +Name[bs]=Štednja energije +Name[ca]=Estalvi d'energia +Name[ca@valencia]=Estalvi d'energia +Name[cs]=Úsporný režim +Name[da]=Strømbesparelse +Name[de]=Energiesparen +Name[el]=Εξοικονόμηση ενέργειας +Name[en_GB]=Energy Saving +Name[es]=Ahorro de energía +Name[et]=Energia säästmine +Name[eu]=Energia-aurreztea +Name[fi]=Virransäästö +Name[fr]=Économie d'énergie +Name[ga]=Spáráil Fuinnimh +Name[gl]=Aforro enerxético +Name[he]=חיסכון בחשמל +Name[hu]=Energiatakarékosság +Name[ia]=Sparnio de energia +Name[is]=Orkusparnaður +Name[kk]=Қуатты үнемдеу +Name[km]=សន្សំ​ថាមពល​ +Name[ko]=에너지 절약 +Name[lt]=Energijos taupymas +Name[mr]=ऊर्जा बचत +Name[nb]=Energisparing +Name[nds]=Stroomsporen +Name[nl]=Energiebesparing +Name[pa]=ਊਰਜਾ ਬੱਚਤ +Name[pl]=Oszczędzanie energii +Name[pt]=Poupança de Energia +Name[pt_BR]=Economia de energia +Name[ro]=Economisire energie +Name[ru]=Энергосбережение +Name[sk]=Šetrenie energie +Name[sl]=Varčevanje z energijo +Name[sr]=Штедња енергије +Name[sr@ijekavian]=Штедња енергије +Name[sr@ijekavianlatin]=Štednja energije +Name[sr@latin]=Štednja energije +Name[sv]=Strömsparhantering +Name[tr]=Enerji Tasarrufu +Name[uk]=Заощадження енергії +Name[vi]=Tiết kiệm năng lượng +Name[x-test]=xxEnergy Savingxx +Name[zh_CN]=节能 +Name[zh_TW]=省電模式 + +Comment=Configure Energy Saving +Comment[bs]=Podesi štednju energije +Comment[ca]=Configura l'estalvi d'energia +Comment[ca@valencia]=Configura l'estalvi d'energia +Comment[cs]=Upravte šetření energie +Comment[da]=Indstillinger for strømbesparelse +Comment[de]=Energiespar-Einstellungen einrichten +Comment[el]=Διαμόρφωση της εξοικονόμησης ενέργειας +Comment[en_GB]=Configure Energy Saving +Comment[es]=Configurar el ahorro de energía +Comment[et]=Energia säästmise seadistused +Comment[eu]=Konfiguratu energia-aurreztea +Comment[fi]=Virransäästön asetukset +Comment[fr]=Configurer les économies d'énergie +Comment[ga]=Cumraigh Spáráil Fuinnimh +Comment[gl]=Configurar o aforro enerxético +Comment[he]=הגדרות חיסכון באנרגייה +Comment[hu]=Energiatakarékossági beállítások +Comment[ia]=Configura sparnio de energia +Comment[is]=Stilla orkusparnað +Comment[kk]=Қуат үнемдеуді баптау +Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​នៃ​​ការសន្សំ​ថាមពល +Comment[ko]=절전 설정 +Comment[lt]=Konfigūruoti energijos taupymą +Comment[mr]=ऊर्जा बचत संयोजीत करा +Comment[nb]=Sett opp strømsparing +Comment[nds]=Instellen för't Stroomsporen fastleggen +Comment[nl]=Energiebesparing instellen +Comment[pa]=ਊਰਜਾ ਬੱਚਤ ਸੰਰਚਨਾ +Comment[pl]=Ustawienia oszczędzania energii +Comment[pt]=Configurar a Poupança de Energia +Comment[pt_BR]=Configura a economia de energia +Comment[ro]=Configurează economisirea energiei +Comment[ru]=Параметры энергосбережения +Comment[sk]=Nastaviť šetrenie energie +Comment[sl]=Nastavi varčevanje z energijo +Comment[sr]=Подешавање штедње енергије +Comment[sr@ijekavian]=Подешавање штедње енергије +Comment[sr@ijekavianlatin]=Podešavanje štednje energije +Comment[sr@latin]=Podešavanje štednje energije +Comment[sv]=Anpassa strömsparhantering +Comment[tr]=Enerji Tasarrufunu Yapılandır +Comment[uk]=Налаштувати заощадження енергії +Comment[vi]=Cấu hình cho Tiết kiệm năng lượng +Comment[x-test]=xxConfigure Energy Savingxx +Comment[zh_CN]=保存能源设置 +Comment[zh_TW]=設定省電模式 + +X-KDE-Keywords=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid +X-KDE-Keywords[bs]=Sistem, Napajanje, Upravljanje napajanjem, energija, laptop, baterija, suspenzija, AC, suspendiraj, hiberniranje, osvljetljenje, kapak, +X-KDE-Keywords[ca]=sistema,energia,gestió d'energia,corrent,portàtil,bateria,suspensió,AC,suspèn,hiberna,lluminositat,rendiment,tapa +X-KDE-Keywords[ca@valencia]=sistema,energia,gestió d'energia,corrent,portàtil,bateria,suspensió,AC,suspèn,hiberna,lluminositat,rendiment,tapa +X-KDE-Keywords[da]=system,strøm,strømstyring,energi,laptop,bærbar,batteri,suspension,AC,strømforsyning,suspender,slumre,dvale,lysstyrke,ydelse,låg +X-KDE-Keywords[de]=system,energie,energieverwaltung,laptop,notebook,akku,batterie,ruhezustand,tiefschlaf,helligkeit,leistung,deckel +X-KDE-Keywords[el]=σύστημα,ενέργεια,διαχείριση ενέργειας,ενέργεια,φορητός,μπαταρία,αναστολή,AC,κοίμηση,νάρκη,λαμπρότητα,επιδόσεις,καπάκι +X-KDE-Keywords[en_GB]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid +X-KDE-Keywords[es]=sistema,energía,gestión de energía,energía,portátil,batería,suspensión,AC,suspender,hibernar,brillo,rendimiento,tapa +X-KDE-Keywords[et]=süsteem,energia,toide,toitehaldus,sülearvuti,aku,uneseisund,uni,talveuni, heledus,jõudlus,kaas +X-KDE-Keywords[eu]=sistema,energia,energia-kudeaketa,energia,eramangarria,bateria,egonean,korronte alternoa,egonean uztea,hibernatu,distira,errendimendua,tapa +X-KDE-Keywords[fi]=järjestelmä,virta,virranhallinta,energia,kannettava,tietokone,läppäri,akku,lepotila,valmiustila,AC,virtalähde,keskeytä,kirkkaus,suorituskyky,kansi +X-KDE-Keywords[fr]=système, alimentation, gestion énergétique, énergie, portable, batterie, suspension, AC, suspendre, hiberner, luminosité, performance, capot +X-KDE-Keywords[gl]=sistema,enerxía,xestión da enerxía, xestión enerxética,carga,portátil,batería, suspender,corrente,hibernar,durmir,brillo,rendemento,tapa +X-KDE-Keywords[hu]=rendszer,energia,energiakezelés,energia,laptop,akkumulátor,AC,felfüggesztés,hibernálás,fényerő,teljesítmény,fedél +X-KDE-Keywords[ia]=systema,potentia,gestion de potentia,energia,laptop,batteria,suspension,CA,suspende,hiberna,brillantia,prestation,coperculo +X-KDE-Keywords[kk]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid +X-KDE-Keywords[km]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid +X-KDE-Keywords[ko]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,시스템,전원,전원 관리,에너지,노트북,배터리,어댑터,절전,대기 모드,대기,최대 절전,최대 절전 모드,밝기,성능,덮개,상판 +X-KDE-Keywords[mr]=प्रणाली, वीज, वीज व्यवस्थापन, ऊर्जा, लैपटॉप, बॅटरी, अकार्यक्षम, AC, अकार्यक्षम, हायबरनेट, प्रखरता, लिड +X-KDE-Keywords[nb]=system,strøm,strømstyring,energi,bærbar,batteri,hvilemodus,AC,hvile,dvale,lysstyrke,ytelse,lokk +X-KDE-Keywords[nds]=Systeem,Stroom,Stroompleeg,Energie,Klappreekner,Batterie,utsetten,AC,Wesselstroom,infreren,Helligkeit,Leisten +X-KDE-Keywords[nl]=systeem,energie,energiebeheer,laptop,batterij,accu,suspension,AC,onderbreken,slapen,helderheid,prestaties,deksel +X-KDE-Keywords[pl]=system,moc,zarządzanie energią,energia,laptop,bateria,wstrzymanie,AC,wstrzymaj,hibernuj,jasność,wydajność,pokrywka +X-KDE-Keywords[pt]=sistema,energia,gestão de energia,portátil,bateria,suspensão,AC,suspender,hibernar,brilho,performance,tampo +X-KDE-Keywords[pt_BR]=sistema,energia,gerenciamento de energia,energia,notebook,laptop,portátil,bateria,suspensão,AC,suspender,hibernar,brilho,desempenho,tampa +X-KDE-Keywords[ru]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,системное,питание,управление питанием,энергопотребление,ноутбук,батарея,спящий режим,гибернация,ждущий режим,яркость,производительность,крышка +X-KDE-Keywords[sk]=systém,napájanie,správa napájanie,energia,laptop,batéria,uspanie,AC,uspať,hibernovať,jas,výkon,kryt +X-KDE-Keywords[sl]=sistem,energija,upravljanje z energijo,prenosnik,prenosni računalnik,baterija,akumulator,pripravljenost,mirovanje,električno omrežje,svetlost,zmogljivost,pokrov,napajanje +X-KDE-Keywords[sr]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,систем,напајање,струја,управљање напајањем,лаптоп,батерија,суспендовање,АЦ,хибернација,светлина,осветљај,перформансе,поклопац +X-KDE-Keywords[sr@ijekavian]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,систем,напајање,струја,управљање напајањем,лаптоп,батерија,суспендовање,АЦ,хибернација,светлина,осветљај,перформансе,поклопац +X-KDE-Keywords[sr@ijekavianlatin]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,sistem,napajanje,struja,upravljanje napajanjem,laptop,baterija,suspendovanje,AC,hibernacija,svetlina,osvetljaj,performanse,poklopac +X-KDE-Keywords[sr@latin]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,sistem,napajanje,struja,upravljanje napajanjem,laptop,baterija,suspendovanje,AC,hibernacija,svetlina,osvetljaj,performanse,poklopac +X-KDE-Keywords[sv]=system,kraft,krafthantering,energi,bärbar dator,batteri,viloläge,AC,gå till viloläge,dvala,ljusstyrka,prestanda,lock +X-KDE-Keywords[tr]=sistem,güç,güç yönetimi,enerji,dizüstü,pil,askıya alma,Adaptör,uyku kipi,hazırda bekletme,parlaklık,performans,başarım,dizüstü kapağı,ekran parlaklığı +X-KDE-Keywords[uk]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,система,живлення,мережа,струм,керування,енергія,ноутбук,акумулятор,батарея,батареї,присипляння,призупинення,призупинка,яскравість,швидкодія,кришка,кришки +X-KDE-Keywords[x-test]=xxsystem,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lidxx +X-KDE-Keywords[zh_CN]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid,系统,电源,电源管理,能源,笔记本,电池,休眠,睡眠,交流,亮度,性能 +X-KDE-Keywords[zh_TW]=system,power,power management,energy,laptop,battery,suspension,AC,suspend,hibernate,brightness,performance,lid diff --git a/powerdevil/kcmodule/profiles/profileEditPage.ui b/powerdevil/kcmodule/profiles/profileEditPage.ui new file mode 100644 index 00000000..dc265794 --- /dev/null +++ b/powerdevil/kcmodule/profiles/profileEditPage.ui @@ -0,0 +1,63 @@ + + + profileEditPage + + + + 0 + 0 + 683 + 293 + + + + + + + 0 + + + + On AC Power + + + + + + + + + + On Battery + + + + + + + + + + On Low Battery + + + + + + + + + + + + + + KTabWidget + QTabWidget +
ktabwidget.h
+ 1 +
+
+ + +
diff --git a/powerdevil/powerdevil.notifyrc b/powerdevil/powerdevil.notifyrc new file mode 100644 index 00000000..52ec8be4 --- /dev/null +++ b/powerdevil/powerdevil.notifyrc @@ -0,0 +1,1575 @@ +[Global] +Name=KDE Power Management System +Name[bg]=Система за управление захранването на KDE +Name[bs]=KDE‑ov sistem za upravljanje napajanjem +Name[ca]=Sistema de gestió d'energia del KDE +Name[ca@valencia]=Sistema de gestió d'energia del KDE +Name[cs]=Systém správy napájení KDE +Name[da]=KDE's strømstyringssystem +Name[de]=KDE-Energieverwaltungssystem +Name[el]=Σύστημα διαχείρισης ενέργειας KDE +Name[en_GB]=KDE Power Management System +Name[es]=Sistema de gestión de energía de KDE +Name[et]=KDE toitehalduse süsteem +Name[eu]=KDEren energia kudeatzeko sistema +Name[fi]=KDE:n virranhallintajärjestelmä +Name[fr]=Système KDE de gestion de l'énergie +Name[ga]=Córas Bainisteoireachta Cumhachta KDE +Name[gl]=Sistema de xestión da enerxía de KDE +Name[he]=מערכת ניהול צריכת חשמל של KDE +Name[hi]=केडीई बिज़ली प्रबंधन तंत्र +Name[hr]=KDE-ov sustav upravljanja potrošnjom energije +Name[hu]=KDE energiakezelő rendszer +Name[ia]=Systema de gestion de energia de KDE +Name[is]=KDE orkustjórnunarkerfið +Name[ja]=KDE 電源管理 +Name[kk]=KDE-нің қуаттандыруды басқару жүйесі +Name[km]=ប្រព័ន្ធ​គ្រប់គ្រង​ថាមពល​របស់ KDE +Name[kn]=KDE ವಿದ್ಯುಚ್ಛಕ್ತಿ ನಿರ್ವಹಣಾ ವ್ಯವಸ್ಥೆ +Name[ko]=KDE 전원 관리 시스템 +Name[lt]=KDE energijos valdymo sistema +Name[lv]=KDE energokontroles sistēma +Name[mr]=केडीई वीज व्यवस्थापन प्रणाली +Name[nb]=Et strømstyringsverktøy for KDE +Name[nds]=Stroomkuntrullsysteem för KDE +Name[nl]=KDE-energiebeheersysteem +Name[pa]=KDE ਪਾਵਰ ਪਰਬੰਧਕ ਸਿਸਟਮ +Name[pl]=System zarządzania energią w KDE +Name[pt]=Sistema de Gestão de Energia do KDE +Name[pt_BR]=Sistema de Gerenciamento de Energia do KDE +Name[ro]=Sistemul KDE de gestiune a alimentării +Name[ru]=Система управления питанием KDE +Name[sk]=Systém správy napájania KDE +Name[sl]=KDE-jev sistem za upravljanje z energijo +Name[sr]=КДЕ‑ов систем за управљање напајањем +Name[sr@ijekavian]=КДЕ‑ов систем за управљање напајањем +Name[sr@ijekavianlatin]=KDE‑ov sistem za upravljanje napajanjem +Name[sr@latin]=KDE‑ov sistem za upravljanje napajanjem +Name[sv]=KDE:s strömsparhanteringssystem +Name[th]=ระบบจัดการพลังงานของ KDE +Name[tr]=KDE Güç Yönetim Sistemi +Name[ug]=ك د ئې(KDE) توك مەنبە باشقۇرۇش سىستېمىسى +Name[uk]=Система керування живленням KDE +Name[vi]=Hệ thống quản lý năng lượng KDE +Name[wa]=Sistinme di manaedjmint di l' enerdjeye di KDE +Name[x-test]=xxKDE Power Management Systemxx +Name[zh_CN]=KDE 电源管理系统 +Name[zh_TW]=KDE 電源管理系統 +IconName=preferences-system-power-management +Comment=Power Management System +Comment[bs]=Sistem za upravljanje napajanjem +Comment[ca]=Sistema de gestió d'energia +Comment[ca@valencia]=Sistema de gestió d'energia +Comment[cs]=Systém správy napájení +Comment[da]=Strømstyringssystem +Comment[de]=Energieverwaltungssystem +Comment[el]=Σύστημα διαχείρισης ενέργειας +Comment[en_GB]=Power Management System +Comment[es]=Sistema de gestión de energía +Comment[et]=Toitehalduse süsteem +Comment[eu]=Energia kudeatzeko sistema +Comment[fi]=Virranhallintajärjestelmä +Comment[fr]=Système de gestion de l'énergie +Comment[ga]=Córas Bainisteoireachta Cumhachta +Comment[gl]=Sistema de xestión da enerxía +Comment[he]=מערכת ניהול צריכת חשמל +Comment[hu]=Energiakezelő rendszer +Comment[ia]=Systema de gestion de energia +Comment[is]=Orkustjórnunarkerfi +Comment[kk]=Қуаттандыруды басқару жүйесі +Comment[ko]=전원 관리 시스템 +Comment[lt]=Energijos valdymo sistema +Comment[mr]=वीज व्यवस्थापन प्रणाली +Comment[nb]=Et strømstyringsverktøy +Comment[nds]=Stroompleegsysteem +Comment[nl]=Energiebeheersysteem +Comment[pa]=ਪਾਵਰ ਪਰਬੰਧ ਸਿਸਟਮ +Comment[pl]=System zarządzania energią +Comment[pt]=Sistema de Gestão de Energia +Comment[pt_BR]=Sistema de Gerenciamento de Energia +Comment[ro]=Sistemul de gestiune a alimentării +Comment[ru]=Система управления питанием +Comment[sk]=Systém správy napájania +Comment[sl]=Sistem za upravljanje z energijo +Comment[sr]=Систем за управљање напајањем +Comment[sr@ijekavian]=Систем за управљање напајањем +Comment[sr@ijekavianlatin]=Sistem za upravljanje napajanjem +Comment[sr@latin]=Sistem za upravljanje napajanjem +Comment[sv]=Strömsparhanteringssystem +Comment[tr]=Güç Yönetim Sistemi +Comment[uk]=Система керування живленням +Comment[x-test]=xxPower Management Systemxx +Comment[zh_CN]=电源管理系统 +Comment[zh_TW]=電源管理系統 +Version=2 + +[Context/warningnot] +Name=Warning +Name[af]=Waarskuwing +Name[ar]=إنذار +Name[as]=সতৰ্কবাণী +Name[ast]=Avisu +Name[be]=Папярэджанне +Name[be@latin]=Uvaha +Name[bg]=Предупреждение +Name[bn]=সতর্কবার্তা +Name[bn_IN]=সতর্কবার্তা +Name[bs]=Upozorenje +Name[ca]=Avís +Name[ca@valencia]=Avís +Name[cs]=Varování +Name[csb]=Bôczënk +Name[da]=Advarsel +Name[de]=Warnung +Name[el]=Προειδοποίηση +Name[en_GB]=Warning +Name[eo]=Averto +Name[es]=Aviso +Name[et]=Hoiatus +Name[eu]=Abisua +Name[fi]=Varoitus +Name[fr]=Avertissement +Name[fy]=Warskôging +Name[ga]=Rabhadh +Name[gl]=Aviso +Name[gu]=ચેતવણી +Name[he]=אזהרה +Name[hi]=चेतावनी +Name[hne]=चेतावनी +Name[hr]=Upozorenje +Name[hsb]=Kedźbu +Name[hu]=Figyelmeztetés +Name[ia]=Aviso +Name[id]=Peringatan +Name[is]=Aðvörun +Name[it]=Avviso +Name[ja]=警告 +Name[kk]=Ескерту +Name[km]=ការ​ព្រមាន +Name[kn]=ಎಚ್ಚರಿಕೆ +Name[ko]=경고 +Name[ku]=Hişyarî +Name[lt]=Dėmesio +Name[lv]=Brīdinājums +Name[mai]=चेतावनी +Name[mk]=Предупредување +Name[ml]=മുന്നറിയിപ്പു് +Name[mr]=इशारा +Name[nb]=Advarsel +Name[nds]=Wohrschoen +Name[ne]=चेतावनी +Name[nl]=Waarschuwing +Name[nn]=Åtvaring +Name[oc]=Alèrta +Name[or]=ଚେତାବନୀ +Name[pa]=ਚੇਤਾਵਨੀ +Name[pl]=Ostrzeżenie +Name[pt]=Aviso +Name[pt_BR]=Aviso +Name[ro]=Atenționare +Name[ru]=Предупреждение +Name[se]=Várrehus +Name[si]=අවවාදය +Name[sk]=Varovanie +Name[sl]=Opozorilo +Name[sr]=Упозорење +Name[sr@ijekavian]=Упозорење +Name[sr@ijekavianlatin]=Upozorenje +Name[sr@latin]=Upozorenje +Name[sv]=Varning +Name[ta]=எச்சரிக்கை +Name[te]=హెచ్చరిక +Name[tg]=Огоҳинома +Name[th]=คำเตือน +Name[tr]=Uyarı +Name[ug]=ئاگاھلاندۇرۇش +Name[uk]=Попередження +Name[uz]=Ogohnoma +Name[uz@cyrillic]=Огоҳнома +Name[vi]=Cảnh báo +Name[wa]=Adviertixhmint +Name[x-test]=xxWarningxx +Name[zh_CN]=警告 +Name[zh_TW]=警告 +Comment=Used for warning notifications +Comment[ar]=يُستخدم للتنبيهات التحذيرية +Comment[ast]=Usáu pa notificaciones d'avisu +Comment[be@latin]=Dla aścierahalnych paviedamleńniaŭ +Comment[bg]=Използва се за предупреждения +Comment[bn]=সতর্কীকরণ বিজ্ঞপ্তির জন্য ব্যবহৃত হয় +Comment[bs]=Koristi se za obavještenja o upozorenjima +Comment[ca]=S'usa per a les notificacions d'avís +Comment[ca@valencia]=S'usa per a les notificacions d'avís +Comment[cs]=Použito pro varování a upozornění +Comment[da]=Bruges til advarselsbekendtgørelser +Comment[de]=Verwendet für Warnmeldungen +Comment[el]=Χρησιμοποιείται για τις προειδοποιήσεις +Comment[en_GB]=Used for warning notifications +Comment[eo]=Uzita por avertmesaĝoj +Comment[es]=Usado para notificaciones de advertencia +Comment[et]=Hoiatuste jaoks +Comment[eu]=Abisu-jakinarazpenetarako erabiltzen da +Comment[fi]=Käytetään varoitusilmoituksiin +Comment[fr]=Utilisé pour les notifications d'avertissements +Comment[fy]=Brûkt faor warskôging notifikaasjes +Comment[ga]=Úsáidte do rabhaidh +Comment[gl]=Emprégase para as notificacións de aviso +Comment[gu]=ચેતવણી નોંધણીઓ આપવા માટે વપરાય છે +Comment[he]=משמש להתרעות אזהרה +Comment[hi]=चेतावनियाँ देने के लिए उपयोग में लिया जाता है +Comment[hne]=चेतावनी सूचना बर उपयोग होथे +Comment[hr]=Korišten za upozoravajuće obavijesti +Comment[hu]=Kezelőprogram figyelmeztető üzenetekhez +Comment[ia]=Usate pro notificationes de avisos +Comment[id]=Digunakan untuk notifikasi peringatan +Comment[is]=Notað fyrir aðvaranir +Comment[it]=Usato per notifiche di avviso +Comment[ja]=警告の通知に使用 +Comment[kk]=Ескерту хабарларға қолданылады +Comment[km]=បានប្រើ​សម្រាប់​ការ​ជូន​ព្រមាន +Comment[kn]=ಎಚ್ಚರಿಕೆ ಸೂಚನೆಗಳಿಗೆ ಬಳಸಲಾಗುತ್ತದೆ +Comment[ko]=경고 알림에 사용됨 +Comment[lt]=Naudojama perspėjimams +Comment[lv]=Izmanto brīdinājumu paziņojumiem +Comment[ml]=താക്കീത് അറിയിപ്പുകള്‍ക്കായി ഉപയോഗിക്കുന്നു +Comment[mr]=इशारा सूचना करिता वापरले जाते +Comment[nb]=Brukt til varselsmeldinger +Comment[nds]=Bi Wohrschoen bruukt +Comment[nl]=Wordt gebruikt voor waarschuwingsmeldingen +Comment[nn]=Er brukt til åtvaringsvarsel +Comment[or]=ଚେତାବନୀ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପାଇଁ ବ୍ୟବହୃତ ହୋଇଥାଏ +Comment[pa]=ਚੇਤਾਵਨੀ ਨੋਟੀਫਿਕੇਸ਼ਨ ਲਈ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ +Comment[pl]=Używane do ostrzeżeń +Comment[pt]=Usado para as notificações de aviso +Comment[pt_BR]=Usado para as notificações de aviso +Comment[ro]=Utilizat pentru notificări de avertizare +Comment[ru]=Используется для системных уведомлений +Comment[si]=අවවාද පණිවුඩ සඳහා යොදාගනී +Comment[sk]=Používa sa pre varovné upozornenia +Comment[sl]=Uporabljeno za obvestila z opozorili +Comment[sr]=Користи се за позорна обавештења +Comment[sr@ijekavian]=Користи се за позорна обавјештења +Comment[sr@ijekavianlatin]=Koristi se za pozorna obavještenja +Comment[sr@latin]=Koristi se za pozorna obaveštenja +Comment[sv]=Används för varningsmeddelanden +Comment[ta]=Used for warning notifications +Comment[te]=హెచ్చరిక నోటీసుల కొరకు వుపయోగించబడింది +Comment[tg]=Используется для надписей под значками на рабочем столе. +Comment[th]=ใช้สำหรับการแจ้งเตือนให้ทราบ +Comment[tr]=Uyarı bildirimleri için kullanılır +Comment[ug]=ئاگاھلاندۇرۇش ئۇقتۇرۇشلىرى ئۈچۈن ئىشلىتىلىدۇ. +Comment[uk]=Використовується для попереджень +Comment[vi]=Sử dụng cho thông tin cảnh báo +Comment[wa]=Eployî po des notifiaedjes d' adviertixhmint +Comment[x-test]=xxUsed for warning notificationsxx +Comment[zh_CN]=用于发出警告通知 +Comment[zh_TW]=用於警告通知 + +[Context/stdnot] +Name=Notification +Name[af]=Stelselboodskap +Name[ar]=إشعار +Name[ast]=Notificación +Name[be]=Абвяшчэнні +Name[be@latin]=Infarmavańnie +Name[bg]=Уведомяване +Name[bn]=বিজ্ঞপ্তি +Name[bn_IN]=সূচনা +Name[bs]=Obavještenje +Name[ca]=Notificació +Name[ca@valencia]=Notificació +Name[cs]=Hlášení +Name[csb]=Dôwanié wiédzë +Name[da]=Bekendtgørelse +Name[de]=Benachrichtigung +Name[el]=Ειδοποίηση +Name[en_GB]=Notification +Name[eo]=Atentigo +Name[es]=Notificación +Name[et]=Märguanne +Name[eu]=Jakinarazpena +Name[fi]=Ilmoitus +Name[fr]=Notification +Name[fy]=Notifikaasje +Name[ga]=Fógairt +Name[gl]=Notificación +Name[gu]=નોંધણી +Name[he]=הודעות +Name[hi]=अधिसूचना +Name[hne]=अधिसूचना +Name[hr]=Obavijest +Name[hsb]=Zdźělenka +Name[hu]=Rendszerüzenet +Name[ia]=Notification +Name[id]=Notifikasi +Name[is]=Kerfistilkynning +Name[kk]=Құлақтандыру +Name[km]=សេចក្តី​ជូន​ដំណឹង​ +Name[kn]=ಸೂಚನೆಗಳು +Name[ko]=알림 +Name[ku]=Agahdarî +Name[lt]=Pranešimas +Name[lv]=Paziņojums +Name[mai]=अधिसूचना +Name[mk]=Известување +Name[ml]=അറിയിപ്പു് +Name[mr]=सूचना +Name[nb]=Varsling +Name[nds]=Bescheed +Name[ne]=सूचना +Name[nl]=Melding +Name[nn]=Varsling +Name[oc]=Notificacion +Name[or]=ବିଜ୍ଞପ୍ତି +Name[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ +Name[pl]=Powiadomienie +Name[pt]=Notificação +Name[pt_BR]=Notificação +Name[ro]=Notificare +Name[ru]=Уведомление +Name[se]=Dieđiheapmi +Name[si]=දැනුම්දීම +Name[sk]=Upozornenie +Name[sl]=Obvestilo +Name[sr]=Обавештење +Name[sr@ijekavian]=Обавештење +Name[sr@ijekavianlatin]=Obaveštenje +Name[sr@latin]=Obaveštenje +Name[sv]=Underrättelse +Name[ta]=அறிவிப்பு +Name[te]=నో‍టీసు +Name[tg]=Огоҳинома +Name[th]=การแจ้งให้ทราบ +Name[tr]=Bildirim +Name[ug]=ئۇقتۇرۇش +Name[uk]=Сповіщення +Name[uz]=Xabarnoma +Name[uz@cyrillic]=Хабарнома +Name[wa]=Notifiaedje +Name[x-test]=xxNotificationxx +Name[zh_CN]=通知 +Name[zh_TW]=通知 +Comment=Used for standard notifications +Comment[ar]=يستخدم للتنبيهات العادية +Comment[ast]=Usáu pa notificaciones standard +Comment[be@latin]=Dla zvyčajnych infarmavańniaŭ +Comment[bg]=Използва се за стандартни уведомления +Comment[bn]=সাধারণ বিজ্ঞপ্তির জন্য ব্যবহৃত +Comment[bs]=Koristi se za standardna obavještenja +Comment[ca]=S'usa per a les notificacions estàndard +Comment[ca@valencia]=S'usa per a les notificacions estàndard +Comment[cs]=Použito pro běžná oznámení +Comment[csb]=Brëkòwóné dlô sztandardowi notifikacëji +Comment[da]=Bruges til almindelige bekendtgørelser +Comment[de]=Verwendet für Standard-Benachrichtigungen +Comment[el]=Χρησιμοποιείται για τυπικές ειδοποιήσεις +Comment[en_GB]=Used for standard notifications +Comment[es]=Usado para notificaciones estándar +Comment[et]=Tavaliste märguannete jaoks +Comment[eu]=Jakinarazpen estandarretarako erabilia +Comment[fi]=Käytetään normaaleihin ilmoituksiin +Comment[fr]=Utilisé pour les notifications standards +Comment[fy]=Brûkt foar standert notifikaasjes +Comment[ga]=Úsáidte d'fhógraí caighdeánacha +Comment[gl]=Emprégase para as notificacións estándar +Comment[gu]=પ્રમાણભૂત નોંધ કરવા માટે ઉપયોગ થાય છે +Comment[he]=משמש להודעות רגילות +Comment[hi]=मानक सूचनाओं के लिए उपयोग में लिया जाता है +Comment[hne]=स्टेन्डर्ड सूचना बर उपयोग मं आथे +Comment[hr]=Korišten za standardne obavijesti +Comment[hu]=Kezelő értesítő üzenetekhez +Comment[ia]=Usate pro notificationes standard +Comment[id]=Digunakan untuk notifikasi standar +Comment[is]=Notað fyrir venjulegar tilkynningar +Comment[ja]=通常の通知に使用 +Comment[kk]=Стандартты құлақтандырулар үшін қолданылады +Comment[km]=បាន​ប្រើ​សម្រាប់​ការ​ជូនដំណឹង​ស្តង់ដារ +Comment[kn]=ಪ್ರಮಾಣಿತ ಸೂಚನೆಗಳಿಗೆ ಬಳಸಲಾಗುತ್ತದೆ +Comment[ko]=표준 알림에 사용됨 +Comment[ku]=Ji bo hişyariyên standard tê karandin +Comment[lt]=Naudojamas standartiniams pranešimams +Comment[lv]=Izmanto standarta paziņojumiem +Comment[mk]=Се користи за стандардни известувања +Comment[ml]=സ്റ്റാന്‍ഡര്‍ഡ് അറിയിപ്പുകള്‍ക്കായി ഉപയോഗിക്കുന്നത് +Comment[mr]=प्रमाणित सूचना करिता वापरले जाते +Comment[nb]=Brukt til standardmeldinger +Comment[nds]=Bi Standardbescheden bruukt +Comment[nl]=Wordt gebruikt voor standaardmeldingen +Comment[nn]=Er brukt til standardvarsel +Comment[or]=ମାନକ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପାଇଁ ବ୍ୟବହୃତ ହୋଇଥାଏ +Comment[pa]=ਸਟੈਂਡਰਡ ਨੋਟੀਫਿਕੇਸ਼ਨ ਲਈ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ +Comment[pl]=Używane do zwykłych powiadomień +Comment[pt]=Usado para as notificações normais +Comment[pt_BR]=Usado para as notificações padrão +Comment[ro]=Utilizat pentru notificări obișnuite +Comment[ru]=Используется для уведомлений +Comment[si]=සම්මත දැන්වීම් සඳහා යොදාගනී +Comment[sk]=Používa sa pre bežné upozornenia +Comment[sl]=Za običajna obvestila +Comment[sr]=Користи се за стандардна обавештења +Comment[sr@ijekavian]=Користи се за стандардна обавјештења +Comment[sr@ijekavianlatin]=Koristi se za standardna obavještenja +Comment[sr@latin]=Koristi se za standardna obaveštenja +Comment[sv]=Används för standardmeddelanden +Comment[ta]=Used for standard notifications +Comment[tg]=Используется для надписей под значками на рабочем столе. +Comment[th]=ใช้สำหรับการแจ้งให้ทราบมาตรฐาน +Comment[tr]=Standart bildirimler için kullanılır +Comment[ug]=ئۆلچەملىك ئۇقتۇرۇشلار ئۈچۈن ئىشلىتىلىدۇ. +Comment[uk]=Використовується для звичайних сповіщень +Comment[wa]=Eployî po des standårds notifiaedjes +Comment[x-test]=xxUsed for standard notificationsxx +Comment[zh_CN]=用于标准通知 +Comment[zh_TW]=用於標準通知 + +[Context/criticalnot] +Name=Critical notification +Name[ar]=تنبيه حرج +Name[ast]=Notificación crítica +Name[be@latin]=Važnaje infarmavańnie +Name[bg]=Критични уведомления +Name[bn]=গুরুত্বপূর্ণ বিজ্ঞপ্তি +Name[bn_IN]=গুরুত্বপূর্ণ সূচনাবার্তা +Name[bs]=Kritično obavještenje +Name[ca]=Notificacions crítiques +Name[ca@valencia]=Notificacions crítiques +Name[cs]=Kritické hlášení +Name[csb]=Dôwanié kriticzny wiédzë +Name[da]=Kritisk bekendtgørelse +Name[de]=Kritische Benachrichtigung +Name[el]=Κρίσιμη ειδοποίηση +Name[en_GB]=Critical notification +Name[eo]=Grava Atentigo +Name[es]=Notificación crítica +Name[et]=Kriitiliste märguannete jaoks +Name[eu]=Jakinarazpen kritikoa +Name[fi]=Kriittinen ilmoitus +Name[fr]=Notification critique +Name[fy]=Kritike notifikaasje +Name[ga]=Fógairt ríthábhachtach +Name[gl]=Notificación crítica +Name[gu]=નિર્ણાયક નોંધણી +Name[he]=הודעות חשובות +Name[hi]=गंभीर सूचना +Name[hne]=गंभीर सूचना +Name[hr]=Kritična obavijest +Name[hu]=Kritikus fontosságú üzenet +Name[ia]=Notification critic +Name[id]=Notifikasi kritis +Name[is]=Hættutilkynning +Name[ja]=重大な通知 +Name[kk]=Маңызды құлақтандыру +Name[km]=ការ​ជូន​ដំណឹង​សំខាន់ +Name[kn]=ವಿಷಮ ಸೂಚನೆ +Name[ko]=치명적 알림 +Name[ku]=Hişyarî dana rexne +Name[lt]=Kritinis pranešimas +Name[lv]=Kritisks paziņojums +Name[mk]=Критично известување +Name[ml]=ഗുരുതര അറിയിപ്പു് +Name[mr]=महत्वाची सूचना +Name[nb]=Kritisk varsling +Name[nds]=Kritisch Bescheed +Name[nl]=Kritieke melding +Name[nn]=Viktig varsel +Name[or]=ଗମ୍ଭୀର ବିଜ୍ଞପ୍ତି +Name[pa]=ਨਾਜ਼ੁਕ ਨੋਟੀਫਿਕੇਸ਼ਨ +Name[pl]=Powiadomienie krytyczne +Name[pt]=Notificação crítica +Name[pt_BR]=Notificação crítica +Name[ro]=Notificare critică +Name[ru]=Критичное уведомление +Name[si]=දරුණු පණිවුඩය +Name[sk]=Kritické upozornenie +Name[sl]=Kritična obvestila +Name[sr]=Критично обавештење +Name[sr@ijekavian]=Критично обавјештење +Name[sr@ijekavianlatin]=Kritično obavještenje +Name[sr@latin]=Kritično obaveštenje +Name[sv]=Kritisk underrättelse +Name[ta]=Critical notification +Name[tg]=Уведомление &на панели задач +Name[th]=การแจ้งให้ทราบขั้นวิกฤติ +Name[tr]=Kritik bildirim +Name[ug]=جىددىي ئۇقتۇرۇش +Name[uk]=Сповіщення про критичні події +Name[vi]=Thông báo quan trọng +Name[wa]=Notifiaedje critike +Name[x-test]=xxCritical notificationxx +Name[zh_CN]=危急通知 +Name[zh_TW]=緊急通知 +Comment=Notifies a critical event +Comment[ar]=ينبه على حدث حرج +Comment[ast]=Notifica un eventu críticu +Comment[be@latin]=Paviedamlaje pra važnuju padzieju +Comment[bg]=Уведомяване за критична ситуация +Comment[bn]=গুরুত্বপূর্ণ ঘটনার কথা জানায় +Comment[bs]=Obaveštava o kritičnom događaju +Comment[ca]=Notifiquen esdeveniments crítics +Comment[ca@valencia]=Notifiquen esdeveniments crítics +Comment[cs]=Upozorňuje na kritickou událost +Comment[csb]=Dôwô kriticzną wiedzã +Comment[da]=Bekendtgør en kritisk begivenhed +Comment[de]=Benachrichtigt über einen kritischen Zustand +Comment[el]=Ειδοποίηση ενός κρίσιμου γεγονότος +Comment[en_GB]=Notifies a critical event +Comment[eo]=Sciigi kritikan eventon +Comment[es]=Notifica un evento crítico +Comment[et]=Märguandmine kriitilisest sündmusest +Comment[eu]=Gertaera kritiko baten berri ematen du +Comment[fi]=Ilmoittaa kriittisestä tapahtumasta +Comment[fr]=Notifie un évènement critique +Comment[fy]=Meld krityk barren +Comment[ga]=Cuireann sé seo teagmhas criticiúil in iúl +Comment[gl]=Notifica un suceso crítico +Comment[gu]=ખતરાની ઘટનાની નોંધ આપે છે +Comment[he]=משמש להודיע על אירועים חשובים +Comment[hi]=गंभीर घटना की सूचना देता है +Comment[hne]=एक गंभीर घटना ल बताथे +Comment[hr]=Obavještava o kritičnom događaju +Comment[hu]=Kritikus fontosságú üzenetet jelez +Comment[ia]=Il notifica un evento critic +Comment[id]=Beritahukan sebuah acara kritis +Comment[is]=Gefur tilkynningu um krítíska atburði +Comment[ja]=重大なイベントを通知します +Comment[kk]=Дағдарысты оқиға туралы құлақтандыру +Comment[km]=ជូនដំណឹង​ព្រត្តិការណ៍​សំខាន់ +Comment[kn]=ವಿಷಮ ಘಟನೆಯೊಂದನ್ನು ಸೂಚಿಸುತ್ತದೆ +Comment[ko]=치명적인 사건을 알림 +Comment[lt]=Perspėja apie kritinį įvykį +Comment[lv]=Paziņo kritisku notikumu +Comment[mk]=Известува за критичен настан +Comment[ml]=ഒരു അത്യാവശ്യമായ സംഭവം അറിയിക്കുന്നു +Comment[mr]=महत्वाच्या घटना करिता सूचीत करतो +Comment[nb]=Varsler om en kritisk hendelse +Comment[nds]=Gifft över en kritisch Begeefnis bescheed +Comment[nl]=Meldt een kritieke gebeurtenis +Comment[nn]=Varslar om noko viktig +Comment[or]=ଗୋଟିଏ ଗମ୍ଭୀର ସ୍ଥିତିକୁ ଜଣାଇଥାଏ +Comment[pa]=ਇੱਕ ਨਾਜ਼ੁਕ ਈਵੈਂਟ ਲਈ ਸੂਚਨਾ +Comment[pl]=Powiadomienie o zdarzeniu krytycznym +Comment[pt]=Notifica um evento crítico +Comment[pt_BR]=Notifica um evento crítico +Comment[ro]=Notifică un eveniment critic +Comment[ru]=Уведомление о критическом событии +Comment[si]=දරුණු අවස්ථාවක් අඟවයි +Comment[sk]=Upozorňuje na kritickú udalosť +Comment[sl]=Obvestilo o kritičnem dogodku +Comment[sr]=Обавештава о критичном догађају +Comment[sr@ijekavian]=Обавјештава о критичном догађају +Comment[sr@ijekavianlatin]=Obavještava o kritičnom događaju +Comment[sr@latin]=Obaveštava o kritičnom događaju +Comment[sv]=Underrättar om en kritisk händelse +Comment[ta]=Notifies a critical event +Comment[te]=సంక్లిష్ట ఘటనను తెలుపుతుంది +Comment[tg]=Событие колеса в заголовке: +Comment[th]=แจ้งให้ทราบถึงเหตุการณ์ขั้นวิกฤติ +Comment[tr]=Bir kritik olayı bildirir +Comment[ug]=جىددىي ھادىسە ئۇقتۇرۇشى +Comment[uk]=Сповіщає про критичну подію +Comment[wa]=Notifieye èn evenmint critike +Comment[x-test]=xxNotifies a critical eventxx +Comment[zh_CN]=危急事件通知 +Comment[zh_TW]=通知緊急事件 + +[Event/lowbattery] +Name=Battery Low +Name[bs]=Nizak nivo baterije +Name[ca]=Bateria baixa +Name[ca@valencia]=Bateria baixa +Name[cs]=Baterie je téměř vybitá +Name[da]=Lavt batteri +Name[de]=Akku-Ladestand niedrig +Name[el]=Μπαταρία χαμηλή +Name[en_GB]=Battery Low +Name[es]=Batería baja +Name[et]=Aku laetus on madal +Name[eu]=Bateria baxua +Name[fi]=Akku vähissä +Name[fr]=Batterie faible +Name[ga]=Cadhnra Íseal +Name[gl]=Batería baixa +Name[he]=הסוללה במצב נמוכה +Name[hu]=Az akkumulátor gyenge +Name[ia]=Batteria basse +Name[is]=Lítið eftir á rafhlöðu +Name[kk]=Батареясы сарқылды +Name[ko]=배터리 부족 +Name[lt]=Akumuliatorius ištuštėjęs +Name[mr]=बॅटरी कमी +Name[nb]=Lavt batteri +Name[nds]=Batterie siet +Name[nl]=Accu op laag niveau +Name[pa]=ਘੱਟ ਬੈਟਰੀ +Name[pl]=Bateria na niskim poziomie +Name[pt]=Bateria Fraca +Name[pt_BR]=Bateria fraca +Name[ro]=Acumulator scăzut +Name[ru]=Низкий уровень заряда батареи +Name[sk]=Batéria je slabá +Name[sl]=Nizka raven baterije +Name[sr]=Батерија при крају +Name[sr@ijekavian]=Батерија при крају +Name[sr@ijekavianlatin]=Baterija pri kraju +Name[sr@latin]=Baterija pri kraju +Name[sv]=Dåligt batteri +Name[tr]=Pil Düşük +Name[uk]=Низький рівень заряду +Name[x-test]=xxBattery Lowxx +Name[zh_CN]=电池电量低 +Name[zh_TW]=電池電力偏低 +Comment=Your battery has reached low level +Comment[ar]=وصلت بطاريتك إلى مستوى منخفض +Comment[ast]=La batería llegó al nivel baxu +Comment[be@latin]=Tvaja batareja maje nizki zarad. +Comment[bg]=Батерията е достигнала ниско ниво +Comment[bn]=আপনার ব্যাটারি নিম্ন মাত্রায় পৌঁছেছে +Comment[bs]=Popunjenost baterije pala je nizak nivo +Comment[ca]=La bateria ha arribat al nivell baix +Comment[ca@valencia]=La bateria ha arribat al nivell baix +Comment[cs]=Baterie dosáhla nízké úrovně +Comment[csb]=Twòjô baterëjô mô nisczi stón naładowaniô +Comment[da]=Dit batteri har nået lavt niveau +Comment[de]=Der Ladestand Ihres Akkus hat einen niedrigen Wert erreicht. +Comment[el]=Η μπαταρία σας έχει βρεθεί σε χαμηλή στάθμη ενέργειας +Comment[en_GB]=Your battery has reached low level +Comment[eo]=Via baterio atingis malaltan nivelon +Comment[es]=Su batería ha llegado al nivel bajo +Comment[et]=Aku täituvus on madal +Comment[eu]=Bateria behe-mailara iritsi da +Comment[fi]=Akku on vähissä +Comment[fr]=Votre batterie a atteint un niveau bas +Comment[fy]=Jo batterij hat in leech nivo berikt +Comment[ga]=Shroich do chadhnra leibhéal íseal +Comment[gl]=A batería acadou o nivel de carga baixa +Comment[gu]=તમારી બેટ્રી નીચા સ્તર પર પહોંચી ગઇ છે +Comment[he]=הסוללה הגיע לרמה נמוכה +Comment[hi]=आपकी बैटरी का स्तर कम हो गया है +Comment[hne]=आपमन के बैटरी के पावर कम हो गे हे +Comment[hr]=Vaša baterija je oslabila +Comment[hsb]=Aku je nětko skoro prózdny. +Comment[hu]=A telepek feltöltöttsége alacsony szintű +Comment[ia]=Tu batteria ha attingite nivello basse +Comment[id]=Baterai anda telah mencapai level yang rendah +Comment[is]=Rafhlaðan er við lægstu mörk +Comment[ja]=バッテリ残量が低レベルに達しました +Comment[kk]=Батареяңыздың қуаты аз +Comment[km]=ថ្ម​របស់​​​អ្នក​បាន​ឈាន​ដល់​កម្រិត​ទាប +Comment[kn]=ನಿನ್ನ ವಿದ್ಯುತ್ಕೋಶವು ಕ್ಷೀಣ ಸ್ಥಿತಿಗೆ ತಲುಪಿದೆ +Comment[ko]=배터리에 남은 용량이 적습니다 +Comment[lt]=Jūsų akumuliatorius pasiekė žemą lygmenį +Comment[lv]=Jūsu baterija ir sasniegusi zemu līmeni +Comment[mai]=अहाँक बैटरीक स्तर कम भ' गेल अछि +Comment[mk]=Вашата батерија достигна ниско ниво +Comment[ml]=നിങ്ങളുടെ ബാറ്ററി കുറവായ നില എത്തിയിരിക്കുന്നു +Comment[mr]=बॅटरी किमान पातळी पर्यंत पोहचली आहे +Comment[nb]=Batteriet har nådd lavt nivå +Comment[nds]=Dien Batteriestoop is nu "Siet" +Comment[nl]=Uw accu heeft het lage niveau bereikt +Comment[nn]=Batterinivået er lågt +Comment[or]=ଆପଣଙ୍କର ବ୍ୟାଟେରୀ ନିମ୍ନ ସ୍ତରରେ ପହଞ୍ଚିଯାଇଛି +Comment[pa]=ਤੁਹਾਡੀ ਬੈਟਰੀ ਘੱਟ ਲੈਵਲ ਤੱਕ ਅੱਪੜ ਗਈ ਹੈ +Comment[pl]=Bateria osiągnęła niski poziom naładowania +Comment[pt]=A sua bateria atingiu um nível baixo +Comment[pt_BR]=Sua bateria atingiu um nível baixo +Comment[ro]=Acumulatorul a atins un nivel scăzut +Comment[ru]=Низкий уровень заряда батареи +Comment[si]=ඔබේ බැටරිය අවම ප්‍රමාණයට පැමිණ ඇත. +Comment[sk]=Batéria dosiahla nízku úroveň +Comment[sl]=Baterija je dosegla nizko raven napolnjenosti +Comment[sr]=Попуњеност батерије пала је низак ниво +Comment[sr@ijekavian]=Попуњеност батерије пала је низак ниво +Comment[sr@ijekavianlatin]=Popunjenost baterije pala je nizak nivo +Comment[sr@latin]=Popunjenost baterije pala je nizak nivo +Comment[sv]=Batteriet har nått en låg nivå +Comment[ta]=Your battery has reached low level +Comment[te]=మీ బ్యాటరీ కనిష్ట స్థాయికి చేరినది +Comment[tg]=Барқи батарея ба итмом мерасад +Comment[th]=ประจุแบตเตอรี่ของคุณอยู่ในระดับต่ำ +Comment[tr]=Pil seviyesi düşük düzeye ulaştı +Comment[ug]=توكدان توكى تۆۋەن سەۋىيىگە يەتتى +Comment[uk]=У вашому акумуляторі закінчується заряд +Comment[wa]=Vosse batreye a-st arivé å bas livea +Comment[x-test]=xxYour battery has reached low levelxx +Comment[zh_CN]=电池电量过低 +Comment[zh_TW]=您的電池電力已達不足的程度 +Contexts=warningnot +Sound=KDE-Sys-Warning.ogg +Action=Sound|Popup +IconName=battery-caution + +[Event/criticalbattery] +Name=Battery Critical +Name[bs]=Baterija kritična +Name[ca]=Bateria crítica +Name[ca@valencia]=Bateria crítica +Name[cs]=Baterie na kritické úrovni +Name[da]=Kritisk batteri +Name[de]=Akku-Ladestand kritisch +Name[el]=Μπαταρία κρίσιμη +Name[en_GB]=Battery Critical +Name[es]=Batería en nivel crítico +Name[et]=Aku kriitiline tase +Name[eu]=Bateria oso gutxi +Name[fi]=Akku kriittisellä tasolla +Name[fr]=Batterie critique +Name[ga]=Cadhnra Criticiúil +Name[gl]=Batería no nivel crítico +Name[he]=סוללה במצב קריטי +Name[hu]=Kritikus lemerültség +Name[ia]=Batteria critic +Name[is]=Rafhlaða að tæmast +Name[kk]=Батарея дағдарысты деңгейде +Name[ko]=배터리 바닥남 +Name[lt]=Akumuliatoriaus kritinis lygmuo +Name[mr]=बॅटरी संकटात +Name[nb]=Batteri på kritisk nivå +Name[nds]=Batterie kritisch +Name[nl]=Accu op kritiek niveau +Name[pa]=ਬੈਟਰੀ ਨਾਜ਼ੁਕ ਲੈਵਲ +Name[pl]=Bateria na poziomie krytycznym +Name[pt]=Bateria Crítica +Name[pt_BR]=Bateria em nível crítico +Name[ro]=Acumulator critic +Name[ru]=Критический уровень заряда батареи +Name[sk]=Kritická úroveň batérie +Name[sl]=Kritična raven baterije +Name[sr]=Батерија критична +Name[sr@ijekavian]=Батерија критична +Name[sr@ijekavianlatin]=Baterija kritična +Name[sr@latin]=Baterija kritična +Name[sv]=Kritiskt batteri +Name[tr]=Pil Seviyesi Kritik +Name[uk]=Заряд на критичному рівні +Name[x-test]=xxBattery Criticalxx +Name[zh_CN]=电池电量危急 +Name[zh_TW]=電池電力嚴重不足 +Comment=Your battery has reached critical level. This notification triggers a countdown before doing the configured action, hence it is strongly advised to leave that on. +Comment[ar]=وصلت بطاريتك إلى مستوى حرج. هذا التنبيه يطلق عداً تنازلياً قبل أن ينفذ الإجراء المضبوط مسبقا؛ لذا ينصح بشده تركه مفعلاً. +Comment[ast]=La batería llegó al nivel críticu. Esta notificación entama un cuntador enantes d'executar l'aición configurada, encamiéntase dexar esta configuración activada. +Comment[be@latin]=Tvaja batareja maje vielmi nizki zarad. Hetaje paviedamleńnie ŭklučaje ličylnik da času vykanańnia aznačanych dziejańniaŭ. My raim pakinuć jaho ŭklučanym. +Comment[bg]=Батерията се изтощи до критично ниво. Започва обратно броене и се препоръчва да го оставите. +Comment[bs]=Popunjenost baterija je spala na kritičan nivo. Ovo obavještenje okida odbrojavanje prije izvođenja podešene radnje, stoga vam ozbiljno savetujemo da ga ostavite uključenim. +Comment[ca]=La bateria ha arribat al nivell crític. Aquesta notificació activa un compte enrere abans d'efectuar l'acció configurada, per tant, es recomana deixar-ho actiu. +Comment[ca@valencia]=La bateria ha arribat al nivell crític. Esta notificació activa un compte arrere abans d'efectuar l'acció configurada, per tant, es recomana deixar-ho actiu. +Comment[cs]=Baterie dosáhla kritické úrovně. Tímto upozorněním se spustí odpočet a následně se provede nastavená činnost, proto je doporučeno nezasahovat. +Comment[da]=Dit batteri har nået kritisk niveau. Denne bekendtgørelse udløser en nedtælling før den konfigurerede handling udføres, derfor anbefales det kraftigt at lade den være slået til. +Comment[de]=Der Ladestand Ihres Akkus hat einen kritischen Wert erreicht. Diese Benachrichtigung löst einen Rückwärtszähler aus, bevor die eingestellte Aktion ausgeführt wird. Es wird dringend empfohlen, diese Einstellung aktiviert zu lassen. +Comment[el]=Η μπαταρία σας βρίσκεται σε κρίσιμη στάθμη ενέργειας. Η ειδοποίηση αυτή ενεργοποιεί μια αντίστροφη μέτρηση πριν την εκτέλεση της διαμορφωμένης ενέργειας. Συστήνεται έντονα η ενεργοποίηση αυτής της λειτουργίας. +Comment[en_GB]=Your battery has reached critical level. This notification triggers a countdown before doing the configured action, hence it is strongly advised to leave that on. +Comment[eo]=Via baterio atingis danĝeran nivelon. Tiu sciigo lanĉis nombradon ĝis nulo antaŭ lanĉi agordon, tiucele ni substrekas la neceson lasi tiun funkcion aktiva. +Comment[es]=Su batería ha llegado al nivel crítico. Esta notificación inicia un contador antes de ejecutar la acción configurada, se recomienda dejar esta configuración habilitada. +Comment[et]=Aku täituvus on jõudnud kriitilisele tasemele. See märguanne toob teatava aja pärast kaasa seadistatud toimingu, mistõttu see on väga soovitatav jätta sisselülitatuks. +Comment[eu]=Bateria maila kritikora iritsi da. Jakinarazpen honek atzekoz aurrerako zenbaketa bat abiarazten du konfiguratutako ekintza egin aurretik; beraz, oso gomendagarria da hori gaituta uztea. +Comment[fi]=Akkusi varaus on kriittisen vähissä. Tämä ilmoitus käynnistää lähtölaskennan ennen asetetun toiminnon tekemistä, joten on hyvin suositeltavaa jättää tämä päälle. +Comment[fr]=Votre batterie a atteint un niveau critique. Cette notification déclenche un compte à rebours avant de lancer l'action configurée. Il est par conséquent fortement recommandé de laisser cette fonction active. +Comment[fy]=Jo batterij hat in krityknivo berikt. Dizze notifikaasje aktivearet in ôftelling foardat de ynstelde aksje begjinne sil. It wurdt oanrêt dit ynskeakele te litten. +Comment[ga]=Shroich do chadhnra leibhéal criticiúil. Tosaíonn an fógra seo comhaireamh síos sula ndéanfar an gníomh cumraithe, agus mar sin moltar go láidir duit é a fhágáil ar siúl. +Comment[gl]=A batería acadou o nivel crítico. Esta notificación inicia unha conta-atrás previa a realizar a acción configurada, polo que se recomenda que a deixe seguir. +Comment[he]=הסוללה הגיע לרמה קריטית. הודעה זו מתחילה ספירה לאחור לפני ביצוע הפעולה המוגדרת, לפיכך מומלץ בחום להשאיר אותה פתוחה. +Comment[hne]=आपमन के बैटरी हर एकदम सिराय गे हे. ये सूचना एक उलटी गिनती चालू करही अउ पहिली से बताय काम करही. ते पाय एला अइसने रहिन देव. +Comment[hr]=Baterija je kritično oslabila. Ova obavijest uključuje odbrojavanje prije obavljanja podešene akcije, pa je zbog toga jako preporučeno da ostavite ovo upaljeno. +Comment[hsb]=Aku je kritisce prózdny. Tute skedźbnjenje startuje countdown před konfigurowanej akciju, tuž so doporuči jón nic přetorhnyć. +Comment[hu]=A telepek kritikus szintre merültek, visszaszámlálás után a rendszer végrehajtja a beállított műveletet (kérjük ne zárja be a számlálót). +Comment[ia]=Tu batteria ha attingite nivello critic. Iste notification pone in marcha un computo reverso ante que facer le action configurate, dunque tu es fortemente avisate de lassar lo connectite. +Comment[id]=Baterai anda telah mencapai level kritis. Notifikasi ini memicu penghitungan mundur sebelum melakukan aksi yang diatur, sehingga sangat disarankan untuk membiarkan aksi tersebut tetap hidup. +Comment[is]=Rafhlaðan hefur náð hættumörkum. Þessi aðvörun setur í gang niðurtalningu, sem síðan setur í gang ákveðna aðgerð sem stillt hefur verið. Þar með er ráðlegt að leyfa því ferli að hafa sinn gang. +Comment[ja]=バッテリ残量が危険レベルに達しました。この通知によって、このレベルに設定されているアクションのカウントダウンが開始されるので、有効にしておくことを強くお勧めします。 +Comment[kk]=Батареяңыз әбден сарқытылды. Бұл құлақтандырумен бұл жағдайға бағышталған амалға қалған уакыт санауы басталады, бұған кедергі қылмауы абзал. +Comment[km]=ថ្ម​របស់​អ្នក​បានដល់កម្រិត​សំខាន់ ។ ការ​ជូនដំណឹង​នេះ​កេះ​ឲ្យ​រាប់​ថយ​ក្រោយ​មុនធ្វើ​​សកម្មភាព​ដែល​បានកំណត់​រចនាសម្ព័ន្ធ ដូច្នេះ​វា​ត្រូវ​បានផ្ដល់​អនុសាសន៍​ឲ្យ​ទុក​វា​សិន ។ +Comment[ko]=배터리가 부족합니다. 설정된 동작을 실행할 때까지 잠깐 동안의 여유가 있으며, 그 시간 동안 작업을 정리하십시오. +Comment[lt]=Jūsų akumuliatoriaus įkrova pasiekė kritinį lygmenį. Šis perspėjimas sužadina atvirkštinį skaičiavimą, kuriam pasibaigus bus atliekamas konfigūruotas veiksmas, tad primygtinai siūlome palikti šį nustatymą įjungtą +Comment[lv]=Jūsu baterija ir sasniegisi kritisku līmeni. Šis paziņojums sāk laika atskaiti līdz konfigurētajai darbībai, tāpēc ir ļoti vēlams atstāt to redzamu. +Comment[mk]=Вашата батерија достигна критично ниво. Ова известување предизвикува одбројување пред да се изврши конфигурираното дејство и е многу препорачливо тоа да остане вклучено. +Comment[ml]=നിങ്ങളുടെ ബാറ്ററി ഗുരുതരമായ നിലയില്‍ എത്തിയിരിയ്ക്കുന്നു. ഈ അറിയിപ്പ് ഒരു കഴിഞ്ഞാല്‍ ക്രമീകരിച്ച പ്രവര്‍ത്തനം തുടങ്ങുന്നതിനു് മുമ്പു് ഒരു കൌണ്ട്ഡൌണ്‍ ആരംഭിയ്ക്കും, അതിനാല്‍ ഇതു് സജീവമായി വയ്ക്കാന്‍ ശക്തിയായി ഉപദേശിക്കുന്നു. +Comment[mr]=बॅटरी संकटाच्या पातळी पर्यंत पोहचली आहे. ही सूचना संयोजीत क्रिया करण्यापूर्वी काऊन्टडाउन सक्रिय करते, ज्यामुळे त्यांस वगळण्यास सूचविले जाते. +Comment[nb]=Batteriet har nådd kritisk nivå. Denne varslingen utløser en nedtelling før den innstilte handlinga utføres, så det tilrådes sterkt å la den stå på. +Comment[nds]=Dien Batterie is bi de kritische Stoop ankamen. Disse Bescheed tellt en Tiet daal, ehr he de instellte Akschoon utföhrt, laat em also beter an. +Comment[nl]=Uw accu heeft het kritieke niveau bereikt. Deze melding activeert een aftelling voordat de ingestelde actie zal worden uitgevoerd. Het wordt ten zeerste aanbevolen dit ingeschakeld te laten. +Comment[nn]=Batterinivået er kritisk lågt +Comment[pa]=ਤੁਹਾਡੀ ਬੈਟਰੀ ਨਾਜ਼ੁਕ ਲੈਵਲ ਤੱਕ ਘੱਟ ਗਈ ਹੈ। ਇਹ ਨੋਟੀਫਿਕੇਸ਼ਨ ਸੰਰਚਿਤ ਕੀਤੇ ਐਕਸ਼ਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਉਲਟੀ-ਗਿਣਟੀ ਸ਼ੁਰੂ ਕਰਦਾ ਹੈ, ਇਸਕਰਕੇ ਇਸ ਨੂੰ ਚੱਲਣ ਦੀ ਸਲਾਹ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ। +Comment[pl]=Bateria osiągnęła krytyczny poziom. To powiadomienie rozpoczyna także odliczanie przed wykonaniem skonfigurowanego działania, więc dobrze jest je zostawić. +Comment[pt]=A sua bateria atingiu um nível crítico. Esta notificação despoleta uma contagem antes de efectuar a acção configurada; por isso, recomenda-se que deixe a opção ligada. +Comment[pt_BR]=Sua bateria atingiu um nível crítico. Esta notificação aciona uma contagem antes de realizar a ação configurada. Por isso, recomenda-se deixar a opção ativada. +Comment[ro]=Acumulatorul a atins nivelul critic. Această notificare declanșează o numărătoare inversă pînă la executarea acțiunii implicite, deci se recomandă să îl lăsați activat. +Comment[ru]=Заряд батареи достиг критического уровня. Это уведомление добавляет задержку перед выполнением выбранного действия, потому желательно его оставить включённым. +Comment[si]=ඔබේ බැටරිය දරුණු ලෙස පහළයි. මෙම දැන්වීම සැකසූ ක්‍රියාව ක්‍රියාත්මක කිරීමට පෙර අවරෝහණ ගණනයක් සිදු කරයි. එය සක්‍රීය කර තැබීම නිර්දේශිතයි. +Comment[sk]=Vaša batéria dosiahla kritickú úroveň nabitia. Toto upozornenie spustí odpočítavanie pred vykonaním prednastavenej akcie, preto je vysoko doporučené nechať ho zapnuté. +Comment[sl]=Baterija je dosegla kritično raven izpraznjenosti. To obvestilo sproži odštevanje do izvedbe nastavljenega dejanja, zato močno priporočamo, da to pustite omogočeno. +Comment[sr]=Попуњеност батерија је спала на критичан ниво. Ово обавештење окида одбројавање пре извођења подешене радње, стога вам озбиљно саветујемо да га оставите укљученим. +Comment[sr@ijekavian]=Попуњеност батерија је спала на критичан ниво. Ово обавјештење окида одбројавање прије извођења подешене радње, стога вам озбиљно савјетујемо да га оставите укљученим. +Comment[sr@ijekavianlatin]=Popunjenost baterija je spala na kritičan nivo. Ovo obavještenje okida odbrojavanje prije izvođenja podešene radnje, stoga vam ozbiljno savjetujemo da ga ostavite uključenim. +Comment[sr@latin]=Popunjenost baterija je spala na kritičan nivo. Ovo obaveštenje okida odbrojavanje pre izvođenja podešene radnje, stoga vam ozbiljno savetujemo da ga ostavite uključenim. +Comment[sv]=Batteriet har nått kritisk nivå. Den här underrättelsen utlöser en nerräkning innan den inställda åtgärden utförs, därmed råds du att lämna den på. +Comment[ta]=Your battery has reached critical level. This notification triggers a countdown before doing the configured action, hence it is strongly advised to leave that on. +Comment[te]=మీ బ్యాటరీ సంక్లిష్ట స్థాయిని చేరుకుంది. ఈ నోటీసు ఆకృతీకరించిన చర్యను జరుపుటకు ముందుగా కౌంట్‌డౌన్‌ (దిగువలెక్కింపు)ను జురుపుతుంది, అందుకని దానిని అలా వదిలి వేయమని గట్టిగా సిఫార్సు చేయడమైంది. +Comment[th]=แบตเตอรี่ของคุณเหลือประจุไฟอยู่ในระดับวิกฤติ การแจ้งให้ทราบนี้จะเริ่มการนับถอยหลัง ก่อนจะทำการกระทำตามที่ได้ปรับแต่งค่าเอาไว้ ซึ่งขอแนะนำให้คงการกระทำดังกล่าวเอาไว้ +Comment[tr]=Pil seviyeniz kritik duruma ulaştı. Bu bildirim yapılandırılmış eylemi gerçekleştirmeden önce bir geri sayım işlemini tetikler. Bu seçeneği açık bırakmanız şiddetle önerilir. +Comment[ug]=توكدان توكى جىددىي سەۋىيىگە يەتتى. سىستېما ئۇقتۇرۇشى بىر قېتىم ئاگاھلاندۇرغاندىن كېيىن سىز سەپلىگەن مەشغۇلاتنى ئىجرا قىلىدۇ. بۇ تەڭشەكنى ئوچۇق قويۇشىڭىزنى كۈچلۈك تەۋسىيە قىلىمىز. +Comment[uk]=Заряд акумулятора вашого комп’ютера досяг критичного рівня. За цим сповіщенням буде почато відлік часу до виконання відповідної налаштованої дії, отже, ми наполегливо рекомендуємо вам не вимикати цей пункт. +Comment[wa]=Vosse batreye a-st arivé a on livea critike. Ci notifiaedje enonde ene munutreye divant d' fé l' faitindje d' apontieye, dabôrd il est mo rcomandé di låtchî ça. +Comment[x-test]=xxYour battery has reached critical level. This notification triggers a countdown before doing the configured action, hence it is strongly advised to leave that on.xx +Comment[zh_CN]=电池电量达到危急等级。系统通知将会在一次倒计时后执行您配置的动作,强烈建议您保留此设定为开启。 +Comment[zh_TW]=您的電池電力已到嚴重警告區。這個通知發出後將會開始倒數計時,時間到後就會進行設定好的動作。建議您保持此項開啟。 +Contexts=warningnot +Sound=KDE-Sys-App-Error-Critical.ogg +Action=Sound|Popup +IconName=dialog-warning + +[Event/fullbattery] +Name=Charge Complete +Name[bs]=Gotovo punjenje +Name[ca]=Càrrega completada +Name[ca@valencia]=Càrrega completada +Name[cs]=Nabití bylo dokončeno +Name[da]=Opladning fuldført +Name[de]=Vollständig geladen +Name[el]=Φόρτιση πλήρης +Name[en_GB]=Charge Complete +Name[es]=Carga completa +Name[et]=Laadimine on tehtud +Name[eu]=Karga beteta +Name[fi]=Lataus valmis +Name[fr]=Charge terminée +Name[ga]=Luchtaithe +Name[gl]=Carga completa +Name[he]=טעינה הושלמה +Name[hu]=Töltés befejezve +Name[ia]=Cargamento completate +Name[is]=Full hleðsla +Name[kk]=Толтыруы бітті +Name[ko]=충전 완료됨 +Name[lt]=Įkrovimas baigtas +Name[mr]=चार्ज पूर्ण +Name[nb]=Fullført lading +Name[nds]=Opladen afslaten +Name[nl]=Laden voltooid +Name[pa]=ਚਾਰਜ ਪੂਰਾ +Name[pl]=Ukończono ładowanie +Name[pt]=Carga Completa +Name[pt_BR]=Carga completa +Name[ro]=Încărcare finalizată +Name[ru]=Зарядка завершена +Name[sk]=Nabíjanie ukončené +Name[sl]=Polnjenje zaključeno +Name[sr]=Пуњење довршено +Name[sr@ijekavian]=Пуњење довршено +Name[sr@ijekavianlatin]=Punjenje dovršeno +Name[sr@latin]=Punjenje dovršeno +Name[sv]=Laddning klar +Name[tr]=Şarj Tamamlandı +Name[uk]=Заряджання завершено +Name[x-test]=xxCharge Completexx +Name[zh_CN]=充电完成 +Name[zh_TW]=充電完成 +Comment=The battery is fully charged +Comment[bs]=Baterija je potpuno puna +Comment[ca]=La bateria està totalment carregada +Comment[ca@valencia]=La bateria està totalment carregada +Comment[cs]=Baterie je plně nabitá +Comment[da]=Batteriet er fuldt opladet +Comment[de]=Der Akku ist nun vollständig geladen +Comment[el]=Η μπαταρία έχει φορτιστεί πλήρως +Comment[en_GB]=The battery is fully charged +Comment[es]=La batería está completamente cargada +Comment[et]=Aku on täielikult laetud +Comment[eu]=Bateria erabat kargatuta dago +Comment[fi]=Akku on ladattu täyteen +Comment[fr]=La batterie est totalement chargée +Comment[gl]=A batería ten a carga completa +Comment[he]=הסוללה טעונה במלואה +Comment[hu]=Az akkumulátor teljesen feltöltve +Comment[ia]=Le batteria es cargate completemente +Comment[is]=Rafhlaðan er nú fullhlaðin +Comment[kk]=Батареясы әбден толды +Comment[ko]=배터리가 완전히 충전됨 +Comment[lt]=Akumuliatorius pilnai įkrautas +Comment[mr]=बॅटरी पूर्णतया चार्ज झालेली आहे +Comment[nb]=Batteriet er fullt ladet +Comment[nds]=De Batterie is heel laadt +Comment[nl]=De accu is volledig geladen +Comment[pa]=ਬੈਟਰੀ ਪੂਰੀ ਚਾਰਜ ਹੈ +Comment[pl]=Bateria jest w pełni naładowana +Comment[pt]=A bateria está completamente carregada +Comment[pt_BR]=A bateria está completamente carregada +Comment[ro]=Acumulatorul este încărcat complet +Comment[ru]=Батарея полностью заряжена +Comment[sk]=Batéria je plne nabitá +Comment[sl]=Baterija je povsem napolnjena +Comment[sr]=Батерија је потпуно напуњена +Comment[sr@ijekavian]=Батерија је потпуно напуњена +Comment[sr@ijekavianlatin]=Baterija je potpuno napunjena +Comment[sr@latin]=Baterija je potpuno napunjena +Comment[sv]=Batteriet är fulladdat +Comment[tr]=Pil tam şarjlı +Comment[uk]=Акумулятор повністю заряджено +Comment[x-test]=xxThe battery is fully chargedxx +Comment[zh_CN]=电池已充满 +Comment[zh_TW]=電池已充飽 +Contexts=stdnot +Sound=KDE-Sys-App-Positive.ogg +Action= +IconName=battery-100 + +[Event/pluggedin] +Name=AC adaptor plugged in +Name[ar]=وصل قابس الطاقة +Name[ast]=Adautador de corriente coneutáu +Name[be@latin]=Padłučany blok siłkavańnia +Name[bg]=Адапторът е включен +Name[bn]=এ-সি অ্যাডাপ্টর লাগানো +Name[bs]=AC adapter utaknut +Name[ca]=Adaptador de CA endollat +Name[ca@valencia]=Adaptador de CA endollat +Name[cs]=AC adaptér zapojen +Name[csb]=Wëtkniãti zasëlôcz +Name[da]=Strømforsyning tilsluttet +Name[de]=Netzkabel angeschlossen +Name[el]=Σύνδεση με μετασχηματιστή AC +Name[en_GB]=AC adaptor plugged in +Name[es]=Adaptador de corriente conectado +Name[et]=Ühendati elektrivõrku +Name[eu]=Korronte alternoko egokigailua konektatuta +Name[fi]=Kytkettiin verkkovirtaan +Name[fr]=Adaptateur secteur branché +Name[fy]=AC adapter ynstútsen +Name[ga]=Tá an cuibheoir SA plugáilte isteach +Name[gl]=Enchufouse a alimentación externa +Name[gu]=AC એડપ્ટર લગાવવામાં આવ્યું +Name[he]=מתאם החשמל חובר +Name[hi]=एसी एडॉप्टर प्लग में लगा है +Name[hne]=एसी पिन प्लग मं लगे हे +Name[hr]=Priključen je AC adapter +Name[hsb]=Milinowy adapter přizamknjeny +Name[hu]=Tápcsatlakozó bedugva +Name[ia]=Adaptator AC connectite +Name[id]=Adaptor AC ditancapkan +Name[is]=AC spennubreytir tengdur +Name[ja]=AC アダプタが接続されました +Name[kk]=Айнымалы тоқ адаптері қосылған +Name[km]=បាន​ដោត​អាដាប់ទ័រ AC +Name[kn]=AC ವಿದ್ಯಚ್ಛಕ್ತಿ ಅನುಕಾರಕವನ್ನು (ಅಡಾಪ್ಟರ್) ಅಳವಡಿಸಲಾಗಿದೆ +Name[ko]=AC 어댑터 연결됨 +Name[ku]=Adaptora AC girêdayî ye +Name[lt]=Prijungtas AC adapteris +Name[lv]=Iesprausts barošanas vads +Name[mk]=AC-адаптерот е вклучен +Name[ml]=എസി അഡാപ്റ്റര്‍ കുത്തിയിരിക്കുന്നു +Name[mr]=AC अडॅप्टर प्लग केले +Name[nb]=Strømadapteret er koblet til +Name[nds]=Stroomkavel tokoppelt +Name[nl]=Netstroomadapter aangesloten +Name[nn]=Straumkontakten er kopla i +Name[or]=AC ଏଡ଼ପଟର ପ୍ଲଗ ହୋଇଛି +Name[pa]=AC ਐਡਪਟਰ ਪਲੱਗ ਲੱਗਾ ਹੈ +Name[pl]=Podłączenie zasilania zewnętrznego +Name[pt]=Ligado à corrente +Name[pt_BR]=Adaptador de energia conectado +Name[ro]=Adaptor de curent alternativ atașat +Name[ru]=Подключён к электрической сети +Name[si]=AC ඇඩැප්ටරය සවිකර ඇත +Name[sk]=Napájanie zo siete pripojené +Name[sl]=Napajanje iz električnega omrežja +Name[sr]=АЦ адаптер утакнут +Name[sr@ijekavian]=АЦ адаптер утакнут +Name[sr@ijekavianlatin]=AC adapter utaknut +Name[sr@latin]=AC adapter utaknut +Name[sv]=Nätadapter inkopplad +Name[ta]=AC adaptor plugged in +Name[te]=AC ఎడాప్టర్ ప్లగ్ చేయబడింది +Name[tg]=Сетевой адаптер: подключен +Name[th]=มีการเสียบสายตัวแปลงไฟเข้ามา +Name[tr]=AC adaptörünün fişi takıldı +Name[ug]=ئۆزگىرىشچان توك ماسلاشتۇرغۇچنى چاتقاندا +Name[uk]=Увімкнено живлення від мережі +Name[vi]=Đã gắn bộ sạc AC +Name[wa]=Adaptateu AC tchôkî +Name[x-test]=xxAC adaptor plugged inxx +Name[zh_CN]=已插入交流适配器 +Name[zh_TW]=AC 電源已插入 +Comment=The power adaptor has been plugged in +Comment[ar]=تم توصيل قابس الطاقة +Comment[ast]=Coneutóse l'adautador de corriente +Comment[be@latin]=Padłučany blok siłkavańnia. +Comment[bg]=Адапторът е включен +Comment[bn]=পাওয়ার অ্যাডাপ্টর লাগানো হয়েছে +Comment[bs]=Utaknut je adapter spoljašnjeg napajanja +Comment[ca]=L'adaptador de corrent s'ha endollat +Comment[ca@valencia]=L'adaptador de corrent s'ha endollat +Comment[cs]=Zdroj napájení byl připojen +Comment[csb]=Zasëlôcz òstôł wetkniãti +Comment[da]=Strømforsyningen er blevet tilsluttet +Comment[de]=Das Netzkabel ist angeschlossen worden. +Comment[el]=Ο μετασχηματιστής ρεύματος συνδέθηκε +Comment[en_GB]=The power adaptor has been plugged in +Comment[eo]=la energia ŝnuro konektiĝis +Comment[es]=Se ha conectado el adaptador de corriente +Comment[et]=Arvuti ühendati elektrivõrku +Comment[eu]=Elikagailua konektatu da +Comment[fi]=Tietokone kytkettiin verkkovirtaan +Comment[fr]=L'adaptateur secteur a été branché +Comment[fy]=In stroomadapter is ynstutsen +Comment[ga]=Tá an cuibheoir cumhachta plugáilte isteach +Comment[gl]=Enchufouse o transformador de corrente +Comment[gu]=પાવર એડપ્ટર લગાવવામાં આવેલ છે +Comment[he]=מתאם החשמל חובר +Comment[hi]=पावर एडॉप्टर को प्लग में लगाया गया +Comment[hne]=पावर के प्लग लगिस +Comment[hr]=Priključen je priključak utičnice +Comment[hsb]=Milinowy adapter je so přizamknył +Comment[hu]=Az áramellátást biztosító tápcsatlakozó bedugva +Comment[ia]=Le adaptator de energia ha essite connectite +Comment[id]=Adaptop daya telah ditancapkan +Comment[is]=Spennubreytirinn hefur verið tengdur +Comment[ja]=電源アダプタが接続されました +Comment[kk]=Қуаттандыру адаптері қосылып тұр +Comment[km]=អាដាប់ទ័រ​ថាមពល​ត្រូវ​បាន​ដោត +Comment[kn]=ವಿದ್ಯುಚ್ಛಕ್ತಿ ಅನುಕಾರಕವನ್ನು (ಅಡಾಪ್ಟರ್) ಅಳವಡಿಸಲಾಗಿದೆ +Comment[ko]=AC 어댑터가 연결되었습니다 +Comment[ku]=Adaptorê hêzê hate girêdan +Comment[lt]=Kintamosios srovės adapteris buvo prijungtas +Comment[lv]=Tika iesprausts strāvas vads +Comment[mai]=पावर एडाप्टर केँ प्लग मे लगाएल गेल अछि +Comment[mk]=Вклучен е адаптерот за ел. енергија +Comment[ml]=പവര്‍ അഡാപ്റ്റര്‍ പ്ലഗ്ഗിലേക്ക് കുത്തിയിരിക്കുന്നു +Comment[mr]=पॉवर अडॅप्टरला प्लग केले गेले आहे +Comment[nb]=Strømadapteret er koblet til +Comment[nds]=Dat Stroomkavel wöör tokoppelt +Comment[nl]=De netstroomadapter is aangesloten +Comment[nn]=Straumkontakten er vorten kopla i +Comment[or]=ଶକ୍ତି ଏଡ଼ପଟରକୁ ପ୍ଲଗରେ ଲଗାହୋଇଛି +Comment[pa]=ਪਾਵਰ ਐਡਪਟਰ ਦਾ ਪਲੱਗ ਲਗਾਇਆ ਗਿਆ +Comment[pl]=Podłączono zasilanie zewnętrzne +Comment[pt]=O computador foi ligado à corrente +Comment[pt_BR]=O adaptador de energia foi conectado +Comment[ro]=Adaptorul de alimentare a fost atașat +Comment[ru]=Ноутбук подключён к электрической сети +Comment[si]=විදුලි ඇඩැප්ටරය සවිකර ඇත +Comment[sk]=Napájanie zo siete bolo pripojené +Comment[sl]=Priključeno je bilo napajanje iz električnega omrežja +Comment[sr]=Утакнут је адаптер спољашњег напајања +Comment[sr@ijekavian]=Утакнут је адаптер спољашњег напајања +Comment[sr@ijekavianlatin]=Utaknut je adapter spoljašnjeg napajanja +Comment[sr@latin]=Utaknut je adapter spoljašnjeg napajanja +Comment[sv]=Nätadaptern har kopplats in +Comment[ta]=The power adaptor has been plugged in +Comment[tg]=Подключен блок питания +Comment[th]=มีการเสียบปลั๊กตัวแปลงไฟเข้ามาเพื่อทำการชาร์จไฟ +Comment[tr]=Güç adaptörünün fişi takıldı +Comment[ug]=توك مەنبە ماسلاشتۇرغۇچنى چاتقاندا +Comment[uk]=Було увімкнено живлення від мережі +Comment[wa]=L' adaptateu d' corant a stî tchôkî +Comment[x-test]=xxThe power adaptor has been plugged inxx +Comment[zh_CN]=已插入电源适配器 +Comment[zh_TW]=市電電源已插上 +Contexts=stdnot +Sound=KDE-Sys-App-Positive.ogg +Action=None +IconName=battery-charging-low + +[Event/unplugged] +Name=AC adaptor unplugged +Name[ar]=نزع قابس الطاقة +Name[ast]=Adautador de corriente desconeutáu +Name[be@latin]=Adłučany blok siłkavańnia +Name[bg]=Адапторът е изключен. +Name[bn]=এ-সি অ্যাডাপ্টর খোলা +Name[bs]=AC adapter izvučen +Name[ca]=Adaptador de CA desendollat +Name[ca@valencia]=Adaptador de CA desendollat +Name[cs]=AC adaptér odpojen +Name[csb]=Zasëlôcz òstôł wëjãti +Name[da]=Strømforsyning frakoblet +Name[de]=Netzkabel entfernt +Name[el]=Ο μετασχηματιστής ρεύματος AC αποσυνδέθηκε +Name[en_GB]=AC adaptor unplugged +Name[es]=Adaptador de corriente desconectado +Name[et]=Lahutati elektrivõrgust +Name[eu]=Korronte alternoko egokigailua deskonektatuta +Name[fi]=Poistuttiin verkkovirrasta +Name[fr]=Adaptateur secteur débranché +Name[fy]=AC adapter der út helle +Name[ga]=Cuibheoir SA díphlugáilte +Name[gl]=Desenchufouse a alimentación externa +Name[gu]=AC એડપ્ટર નીકાળી લેવામાં આવ્યું +Name[he]=מתאם החשמל נותק +Name[hi]=एसी एडॉप्टर का प्लग निकाला गया है +Name[hne]=पावर के प्लग निकलिस +Name[hr]=Isključen je AC adapter +Name[hsb]=Milinowy adapter wućehnjeny +Name[hu]=Tápcsatlakozó kihúzva +Name[ia]=Adaptator de AC disconnectite +Name[id]=Adaptop AC dicabut +Name[is]=AC spennubreytir aftengdur +Name[ja]=AC アダプタが取り外されました +Name[kk]=Айнымалы тоқ адаптері ажыратылған +Name[km]=បានដក​អាដាប់ទ័រ AC ចេញ +Name[kn]=AC ವಿದ್ಯುಚ್ಛಕ್ತಿ ಅನುಕಾರಕವನ್ನು (ಅಡಾಪ್ಟರ್) ತೆಗೆಯಲಾಗಿದೆ +Name[ko]=AC 어댑터 연결 끊김 +Name[ku]=Adaptora AC negirêdayî ye +Name[lt]=Atjungtas AC adapteris +Name[lv]=Izrauts barošanas vads +Name[mk]=AC-адаптерот е исклучен +Name[ml]=എസി അഡാപ്റ്റര്‍ പുറത്തെടുത്തിരിക്കുന്നു +Name[mr]=AC अडॅप्टर काढून टाकले +Name[nb]=Strømadapteret er dratt ut +Name[nds]=Stroomkavel ruttrocken +Name[nl]=Netstroomadapter niet aangesloten +Name[nn]=Straumkontakten er kopla ut +Name[or]=AC ଏଡ଼ପଟର ପ୍ଲଗ ହୋଇନାହିଁ +Name[pa]=AC ਐਡਪਟਰ ਦਾ ਪਲੱਗ ਕੱਢਿਆ +Name[pl]=Odłączenie zasilania zewnętrznego +Name[pt]=Desligado da corrente +Name[pt_BR]=Adaptador de energia desconectado +Name[ro]=Adaptor de curent alternativ detașat +Name[ru]=Отключение от электрической сети +Name[si]=AC ඇඩැප්ටරය ගලවා ඇත +Name[sk]=Napájanie zo siete odpojené +Name[sl]=Konec napajanja iz električnega omrežja +Name[sr]=АЦ адаптер извучен +Name[sr@ijekavian]=АЦ адаптер извучен +Name[sr@ijekavianlatin]=AC adapter izvučen +Name[sr@latin]=AC adapter izvučen +Name[sv]=Nätadapter frånkopplad +Name[ta]=AC adaptor unplugged +Name[te]=AC ఎడాప్టర్ అన్‌ప్లగ్ చేయబడింది +Name[tg]=Блок питания отключен +Name[th]=ตัวแปลงไฟถูกถอดออก +Name[tr]=AC adaptörünün fişi çekildi +Name[ug]=ئۆزگىرىشچان توك مەنبە ماسلاشتۇرغۇچ ئۈزۈلگەندە +Name[uk]=Вимкнено живлення від мережі +Name[vi]=Đã tháo bộ sạc AC +Name[wa]=Adaptateu AC distchôkî +Name[x-test]=xxAC adaptor unpluggedxx +Name[zh_CN]=已拔出交流适配器 +Name[zh_TW]=AC 電源已拔除 +Comment=The power adaptor has been unplugged +Comment[ar]=تم نزع قابس الطاقة +Comment[ast]=Desconeutáu l'adautador de corriente +Comment[be@latin]=Adłučany blok siłkavańnia. +Comment[bg]=Адапторът е изключен +Comment[bn]=পাওয়ার অ্যাডাপ্টর খুলে ফেলা হয়েছে +Comment[bs]=Izvučen je adapter spoljašnjeg napajanja +Comment[ca]=L'adaptador de corrent s'ha desendollat +Comment[ca@valencia]=L'adaptador de corrent s'ha desendollat +Comment[cs]=Zdroj napájení byl odpojen +Comment[csb]=Zasëlôcz òstôł wëjãti +Comment[da]=Strømforsyningen er blevet frakoblet +Comment[de]=Das Netzkabel ist vom Rechner getrennt worden. +Comment[el]=Ο μετασχηματιστής ρεύματος αποσυνδέθηκε +Comment[en_GB]=The power adaptor has been unplugged +Comment[eo]=la energia ŝnuro malkonektiĝis +Comment[es]=Se ha desconectado el adaptador de corriente +Comment[et]=Arvuti lahutati elektrivõrgust +Comment[eu]=Elikagailua deskonektatu da +Comment[fi]=Tietokone otettiin pois verkkovirrasta +Comment[fr]=L'adaptateur secteur a été débranché +Comment[fy]=In stroomadapter is der út lutsen +Comment[ga]=Bhí an cuibheoir cumhachta díphlugáilte +Comment[gl]=Desenchufouse a fonte de alimentación +Comment[gu]=પાવર એડપ્ટર કાઢી નાખવામાં આવેલ છે +Comment[he]=מתאם החשמל נותק +Comment[hi]=पावर एडॉप्टर को प्लग से निकाला गया है +Comment[hne]=पावर के प्लग हर निकल गिस +Comment[hr]=Odštekan je priključak utičnice +Comment[hsb]=Milinowy adapter bu wućehnjeny +Comment[hu]=Az áramellátást biztosító tápcsatlakozó kihúzva +Comment[ia]=Le adaptator de energia ha essite disconnectite +Comment[id]=Adaptor daya telah dicabut +Comment[is]=Spennubreytirinn hefur verið aftengdur +Comment[ja]=電源アダプタが取り外されました +Comment[kk]=Қуаттандыру адаптері ажыратылып тұр +Comment[km]=អាប់ដាប់ទ័រ​ថាមពល​ត្រូវ​បាន​ដកចេញ +Comment[kn]=ವಿದ್ಯುಚ್ಛಕ್ತಿ ಅನುಕಾರಕವನ್ನು (ಅಡಾಪ್ಟರ್) ತೆಗೆಯಲಾಗಿದೆ +Comment[ko]=AC 어댑터의 연결이 해제되었습니다 +Comment[ku]=Adaptorê hêzê hate qut kirin +Comment[lt]=Kintamosios srovės adapteris buvo atjungtas +Comment[lv]=Tika izrauts strāvas vads +Comment[mai]=पावर एडाप्टर केँ प्लग सँ निकालल गेल अछि +Comment[mk]=Исклучен е адаптерот за ел. енергија +Comment[ml]=പവര്‍ അഡാപ്റ്റര്‍ പ്ലഗ്ഗില്‍ നിന്നും ഊരിയിരിക്കുന്നു +Comment[mr]=पॉवर अडॅप्टरला काढून टाकण्यात आले आहे +Comment[nb]=Strømadapteret er koblet fra +Comment[nds]=Dat Stroomkavel wöör ruttrocken +Comment[nl]=De netstroomadapter is losgekoppeld +Comment[nn]=Straumkontakten er vorten kopla ut +Comment[or]=ଶକ୍ତି ଏଡ଼ପଟରଟି ପ୍ଲଗ ହୋଇନାହିଁ +Comment[pa]=ਪਾਵਰ ਐਡਪਟਰ ਦਾ ਪਲੱਗ ਕੱਢਿਆ +Comment[pl]=Odłączono zasilanie zewnętrzne +Comment[pt]=O computador foi desligado da corrente +Comment[pt_BR]=O adaptador de energia foi desconectado +Comment[ro]=Adaptorul de alimentare a fost detașat +Comment[ru]=Ноутбук отключён от электрической сети +Comment[si]=විදුලි ඇඩැප්ටරය ගලවා ඇත +Comment[sk]=Napájanie zo siete bolo odpojené +Comment[sl]=Napajanje iz električnega omrežja je bilo prekinjeno +Comment[sr]=Извучен је адаптер спољашњег напајања +Comment[sr@ijekavian]=Извучен је адаптер спољашњег напајања +Comment[sr@ijekavianlatin]=Izvučen je adapter spoljašnjeg napajanja +Comment[sr@latin]=Izvučen je adapter spoljašnjeg napajanja +Comment[sv]=Nätadaptern har kopplats från +Comment[ta]=The power adaptor has been unplugged +Comment[tg]=Отключен блок питания +Comment[th]=มีการถอดสายชาร์จของตัวแปลงไฟออก +Comment[tr]=Güç adaptörünün fişi çekildi +Comment[ug]=توك مەنبە ماسلاشتۇرغۇچ ئۈزۈلگەندە +Comment[uk]=Було вимкнено живлення від мережі +Comment[wa]=L' adaptateu d' corant a stî distchôkî +Comment[x-test]=xxThe power adaptor has been unpluggedxx +Comment[zh_CN]=已拔出电源适配器 +Comment[zh_TW]=市電電源已拔除 +Contexts=stdnot +Sound=KDE-Sys-App-Negative.ogg +Action=Sound +IconName=battery-low + +[Event/powerdevilerror] +Name=Internal Error +Name[bs]=Interna greška +Name[ca]=Error intern +Name[ca@valencia]=Error intern +Name[cs]=Vnitřní chyba +Name[da]=Intern fejl +Name[de]=Interner Fehler +Name[el]=Εσωτερικό σφάλμα +Name[en_GB]=Internal Error +Name[es]=Error interno +Name[et]=Sisemine tõrge +Name[eu]=Barne-errorea +Name[fi]=Sisäinen virhe +Name[fr]=Erreur interne +Name[ga]=Earráid Inmheánach +Name[gl]=Erro interno +Name[he]=שגיאה פנימית +Name[hu]=Belső hiba +Name[ia]=Error Interne +Name[is]=Innri villa +Name[kk]=Ішкі қате +Name[ko]=내부 오류 +Name[lt]=Vidinė klaida +Name[mr]=अंतर्गत त्रुटी +Name[nb]=Intern feil +Name[nds]=Intern Fehler +Name[nl]=Interne fout +Name[pa]=ਅੰਦਰੂਨੀ ਗਲਤੀ +Name[pl]=Błąd wewnętrzny +Name[pt]=Erro Interno +Name[pt_BR]=Erro interno +Name[ro]=Eroare internă +Name[ru]=Внутренняя ошибка +Name[sk]=Interná chyba +Name[sl]=Notranja napaka +Name[sr]=Унутрашња грешка +Name[sr@ijekavian]=Унутрашња грешка +Name[sr@ijekavianlatin]=Unutrašnja greška +Name[sr@latin]=Unutrašnja greška +Name[sv]=Internt fel +Name[tr]=Dahili Hata +Name[uk]=Внутрішня помилка +Name[x-test]=xxInternal Errorxx +Name[zh_CN]=内部错误 +Name[zh_TW]=內部錯誤 +Comment=The KDE Power Management System has triggered an internal error +Comment[ar]=أطلق مراقب الطاقة خطأً داخلياً +Comment[bg]=Системата за управление на захранването предизвика вътрешна грешка +Comment[bs]=Unutrašnja greška u KDE‑ovom sistemu za upravljanje napajanjem +Comment[ca]=El sistema de gestió d'energia del KDE ha activat un error intern +Comment[ca@valencia]=El sistema de gestió d'energia del KDE ha activat un error intern +Comment[cs]=Systém správy napájení KDE vyvolal interní chybu +Comment[da]=KDE's strømstyringssystem har udløst en intern fejl +Comment[de]=Das KDE-Energieverwaltungssystem hat einen internen Fehler ausgelöst. +Comment[el]=Ο διαχειριστής ενέργειας συστήματος KDE προκάλεσε ένα εσωτερικό σφάλμα +Comment[en_GB]=The KDE Power Management System has triggered an internal error +Comment[es]=El sistema de gestión de energía de KDE ha sufrido un error interno +Comment[et]=KDE toitehalduse süsteemi tabas sisemine tõrge +Comment[eu]=KDEren energia kudeatzeko sistemak barne-errore bat eragin du +Comment[fi]=KDE:n virranhallintajärjestelmä on kohdannut sisäisen virheen +Comment[fr]=Le système de gestion de l'énergie de KDE a déclenché une erreur interne +Comment[gl]=O sistema de xestión da enerxía de KDE disparou un erro interno +Comment[he]=מערכת ניהול צריכת החשמל של KDE דיווחה על שגיאה פנימית +Comment[hr]=KDE-ov sustav upravljanja potrošnjom energije je naišao na internu pogrešku +Comment[hu]=A KDE Energiakezelő rendszere belső hibát okozott +Comment[ia]=Le systema de gestion de energia de KDE ha generate un error interne +Comment[is]=KDE orkustjórnunarkerfið kom af stað innri villu +Comment[ja]=KDE 電源管理に内部エラーが発生しました +Comment[kk]=KDE қуаттандыру басқару жүйесінде ішкі бір қатесі орын алды +Comment[km]=ប្រព័ន្ធ​គ្រប់គ្រង​ថាមពល KDE មាន​កំហុស​ខាង​ក្នុង +Comment[ko]=KDE 전원 관리 시스템에서 내부 오류가 발생하였습니다 +Comment[lt]=KDE energijos valdymo sistema sužadino vidinę klaidą +Comment[lv]=KDE energokontroles sistēmā radās iekšēja kļūda +Comment[mr]=केडीई वीज व्यवस्थापन प्रणालीने अंतर्गत त्रुटी सक्रिय केली आहे +Comment[nb]=KDE strømstyringssystem har utløst en intern feil +Comment[nds]=Dat KDE-Stroomkuntrullsysteem hett en intern Fehler hatt. +Comment[nl]=Het KDE-energiebeheersysteem activeerde een interne fout +Comment[pa]=KDE ਪਾਵਰ ਮੈਨਜੇਮੈਂਟ ਸਿਸਟਮ ਨੇ ਅੰਦਰੂਨੀ ਗਲਤੀ +Comment[pl]=Wystąpił wewnętrzny błąd systemu zarządzania energią KDE +Comment[pt]=O Sistema de Gestão de Energia do KDE originou um erro interno +Comment[pt_BR]=Ocorreu um erro interno no Sistema de Gerenciamento de Energia do KDE +Comment[ro]=Sistemul KDE de gestiune a alimentării a declanșat o eroare internă +Comment[ru]=Произошла внутренняя ошибка системы управления питанием KDE +Comment[sk]=Systém správy napájania KDE vyvolal internú chybu +Comment[sl]=V KDE-jevem sistemu za upravljanje z energijo je prišlo do notranje napake +Comment[sr]=Унутрашња грешка у КДЕ‑овом систему за управљање напајањем +Comment[sr@ijekavian]=Унутрашња грешка у КДЕ‑овом систему за управљање напајањем +Comment[sr@ijekavianlatin]=Unutrašnja greška u KDE‑ovom sistemu za upravljanje napajanjem +Comment[sr@latin]=Unutrašnja greška u KDE‑ovom sistemu za upravljanje napajanjem +Comment[sv]=KDE:s strömsparhanteringssystem har orsakat ett internt fel +Comment[th]=ระบบจัดการพลังงานของ KDE ส่งสัญญาณให้ทราบว่าเกิดข้อผิดพลาดภายในขึ้น +Comment[tr]=KDE Güç Yönetim Sistemi bir iç hata tetikledi +Comment[ug]=ئىچكى ك د ئې(KDE) توك مەنبە باشقۇرۇش سىستېما خاتالىقى كۆرۈلدى +Comment[uk]=У системі керування живленням KDE сталася внутрішня помилка +Comment[wa]=Li sistinme di manaedjmint di l' enerdjeye di KDE a eclitchî ene divantrinne aroke +Comment[x-test]=xxThe KDE Power Management System has triggered an internal errorxx +Comment[zh_CN]=KDE 电源管理系统触发了内部错误 +Comment[zh_TW]=KDE 電源管理系統觸發了一個內部錯誤 +Contexts=criticalnot +Sound=KDE-Sys-App-Error-Critical.ogg +Action=Sound|Popup +IconName=dialog-error + +[Event/inhibition] +Name=Suspension inhibited +Name[ar]=ثُبِّط التعليق +Name[ast]=Suspensión inhibida +Name[be@latin]=Son zabaronieny +Name[bg]=Спирането е задържано +Name[bn]=স্থগিতাবস্থায় যাওয়া বিরত +Name[bs]=Suspendovanje sprečeno +Name[ca]=La suspensió s'ha inhibit +Name[ca@valencia]=La suspensió s'ha inhibit +Name[cs]=Uspávání potlačeno +Name[da]=Suspendering undertrykt +Name[de]=Bereitschaftsmodus unterbunden +Name[el]=Αποτροπή αναστολής +Name[en_GB]=Suspension inhibited +Name[es]=Suspensión inhibida +Name[et]=Passiivseisundisse minekut takistati +Name[eu]=Egonean uztea galarazita +Name[fi]=Keskeytystila estetty +Name[fr]=Suspension désactivée +Name[fy]=Sliepstân tsjinhâlden +Name[ga]=Cuireadh cosc ar fhionraíocht +Name[gl]=Evitouse a suspensión +Name[gu]=સસ્પેન્શન રોકી દેવાયું +Name[he]=הפסקה בוטלה +Name[hi]=निलंबन निषेधित +Name[hne]=सस्पेंसन रोके गिस +Name[hr]=Odlazak na spavanje prekinut +Name[hu]=A felfüggesztés letiltva +Name[ia]=Suspension inhibite +Name[id]=Suspensi dicegah +Name[is]=Biðstaða hindruð +Name[ja]=サスペンドが阻止されました +Name[kk]=Аялдауы кідірілді +Name[km]=បានហាមឃាត់​ការ​ផ្អាក +Name[kn]=ತಡೆಹಿಡಿಯುವಿಕೆಯನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ +Name[ko]=대기 모드로 들어가지 않았음 +Name[lt]=Sustabdymas sutrukdytas +Name[lv]=Iemigšana aizkavēta +Name[ml]=മയങ്ങല്‍ തടഞ്ഞിരിയ്ക്കുന്നു +Name[mr]=अकार्यक्षम करणे थांबविले +Name[nb]=Suspensjon hindret +Name[nds]=Utsetten blockeert +Name[nl]=Slaapstand verhinderd +Name[nn]=Kvilemodus vart stoppa +Name[pa]=ਸਸਪੈਂਡ ਵਿੱਚ ਵਿਘਨ +Name[pl]=Wstrzymanie usypiania +Name[pt]=Suspensão inibida +Name[pt_BR]=Suspensão inibida +Name[ro]=Suspendare inhibată +Name[ru]=Отмена перехода в ждущий режим +Name[si]=අත්හිටුවීම නිෂේධිතයි +Name[sk]=Uspanie potlačené +Name[sl]=Začasna zaustavitev prekinjena +Name[sr]=Суспендовање спречено +Name[sr@ijekavian]=Суспендовање спријечено +Name[sr@ijekavianlatin]=Suspendovanje spriječeno +Name[sr@latin]=Suspendovanje sprečeno +Name[sv]=Viloläge förhindrat +Name[ta]=Suspension inhibited +Name[te]=సస్పెన్షన్ ఇన్హిబిటెడ్ +Name[tg]=0.5x2 дюйм, 12x50 мм (Решагии ҷудошудаи папкаи миёна ) +Name[th]=การหยุดพักชั่วคราวถูกยับยั้ง +Name[tr]=Askıya alma işlemi geciktirildi +Name[ug]=توڭلىتىش چەكلەندى +Name[uk]=Присипляння заблоковано +Name[wa]=Metaedje doirmi espaitchî +Name[x-test]=xxSuspension inhibitedxx +Name[zh_CN]=已禁止挂起 +Name[zh_TW]=禁止暫停 +Comment=The suspension has been inhibited because an application requested it +Comment[ar]=ثُبِّط التعليق لأن تطبيقاً طلب ذلك +Comment[ast]=La suspensión inhibióse porque lo solicitó una aplicación +Comment[be@latin]=Son zabaronieny niejkaj aplikacyjaj. +Comment[bg]=Спирането беше задържано заради програма +Comment[bn]=একটি অ্যাপলিকেশন-এর অনুরোধে কম্পিউটারকে স্থগিতাবস্থায় যাওয়া থেকে বিরত রাখা হয়েছে +Comment[bs]=Suspendovanje je sprečeno jer je neki program to zatražio +Comment[ca]=La suspensió s'ha inhibit perquè una aplicació ho ha sol·licitat +Comment[ca@valencia]=La suspensió s'ha inhibit perquè una aplicació ho ha sol·licitat +Comment[cs]=Uspávání bylo potlačeno na základě požadavku aplikace +Comment[da]=Suspendering er blevet undertrykt fordi et program anmodede om det +Comment[de]=Der Bereitschaftsmodus ist unterbunden worden, weil eine Anwendung dies angefordert hat. +Comment[el]=Η αναστολή αποτράπηκε επειδή μια εφαρμογή το απαίτησε +Comment[en_GB]=The suspension has been inhibited because an application requested it +Comment[es]=La suspensión se ha inhibido porque lo ha solicitado una aplicación +Comment[et]=Passiivseisundisse minekut takistas mingi rakendus +Comment[eu]=Egonean uztea galarazi da aplikazio batek hala eskatu duelako +Comment[fi]=Keskeytystila estetty koska sovellus vaati sitä +Comment[fr]=La suspension a été désactivée car une application en a fait la demande +Comment[fy]=De sliepstân is tsjinhâlden omdat in applikaasje der om frege hat +Comment[ga]=Cuireadh cosc ar fhionraíocht toisc go raibh feidhmchlár á iarraidh +Comment[gl]=Evitouse a suspensión porque así o pediu un programa +Comment[gu]=સસ્પેન્શન રોકી દેવામાં આવ્યું કારણકે કાર્યક્રમે તેની વિનંતી કરી હતી +Comment[he]=ההפסקה בוטלה עקב בקשת יישום +Comment[hne]=सस्पेंसन ल रोक दे गे काबर कि एक ठिन अनुपरयोग ह निवेदन करिस +Comment[hr]=Odlazak na spavanje je prekinut jer je aplikacija dala zahtjev za tim. +Comment[hu]=Egy alkalmazás a felfüggesztés letiltását kérte +Comment[ia]=Le suspension ha essite inhibite proque un application exigeva lo +Comment[id]=Suspensi telah dicegah karena sebuah aplikasi memintanya +Comment[is]=Biðstaðan var hindruð að kröfu forrits +Comment[ja]=アプリケーションの要求によりサスペンドが阻止されました +Comment[kk]=Аялдау режіміне өту бір бағдарламаның талабымен кідірілді +Comment[km]=ការ​ផ្អាក​ត្រូវ​បានហាមឃាត់​ ពីព្រោះ​កម្មវិធី​បាន​ស្នើ​វា +Comment[kn]=ತಡೆಹಿಡಿಯುವಿಕೆಯನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ ಏಕೆಂದರೆ ಅನ್ವಯವು ಹಾಗೆ ಮಾಡಲು ಮನವಿ ಸಲ್ಲಿಸಿತ್ತು +Comment[ko]=프로그램의 요청으로 대기 모드에 들어가지 않았습니다 +Comment[lt]=Sustabdymas sutrukdytas, nes to prašė programa +Comment[lv]=Iemigšana tika aizkavēta, jo to pieprasīja kāda programma +Comment[ml]=ഒരു പ്രയോഗം ആവശ്യപ്പെട്ട പ്രകാരം മയങ്ങള്‍ തടഞ്ഞിരിയ്ക്കുന്നു +Comment[mr]=एका अनुप्रयोगाने विनंती केल्यामुळे अकार्यक्षम करणे थांबविले आहे +Comment[nb]=Suspensjonen er blitt hindret fordi et program ba om det +Comment[nds]=Dat Utsetten wöör blockeert, en Programm hett dat anfraagt. +Comment[nl]=Het activeren van de slaapstand is verhinderd omdat een programma hierom verzocht +Comment[nn]=Kvilemodus vart stoppa fordi eit program ønskte det +Comment[pa]=ਸਸਪੈਂਡ ਕਰਨ ਨੂੰ ਰੋਕਿਆ ਗਿਆ, ਕਿਉਂਕਿ ਇੱਕ ਐਪਲੀਕੇਸ਼ਨ ਨੇ ਇਸ ਲਈ ਮੰਗ ਕੀਤੀ ਸੀ। +Comment[pl]=Usypianie zostało wstrzymane na żądanie programu +Comment[pt]=A suspensão foi inibida porque uma aplicação o pediu +Comment[pt_BR]=A suspensão foi inibida por solicitação de um aplicativo +Comment[ro]=Suspendarea a fost inhibată pentru că o aplicație a cerut astfel +Comment[ru]=Переход в ждущий режим прерван по запросу приложения +Comment[si]=යෙදුමක් මගින් ඉල්ලා සිටින බැවින් අත්හිටුවීම නිෂේධිතයි. +Comment[sk]=Uspanie bolo potlačené, pretože aplikácia si to vyžiadala +Comment[sl]=Začasna zaustavitev je bila prekinjena, ker je to zahteval nek program +Comment[sr]=Суспендовање је спречено јер је неки програм то затражио +Comment[sr@ijekavian]=Суспендовање је спријечено јер је неки програм то затражио +Comment[sr@ijekavianlatin]=Suspendovanje je spriječeno jer je neki program to zatražio +Comment[sr@latin]=Suspendovanje je sprečeno jer je neki program to zatražio +Comment[sv]=Viloläget har förhindrats eftersom ett program begärde det +Comment[ta]=The suspension has been inhibited because an application requested it +Comment[te]=ఒక అనువర్తనము దానిని అభ్యర్దించుట వలన సస్పెన్షన్ ఇన్హిబిటెడ్ చేయబడింది +Comment[th]=หยุดชั่วคราวเพราะโปรแกรมร้องขอ +Comment[tr]=Bir uygulama istediği için askıya alma işlemi geciktirildi +Comment[ug]=بۇ توڭلىتىش چەكلەندى چۈنكى پروگرامما ئىلتىماس قىلدى +Comment[uk]=Присипляння було заблоковано на вимогу програми +Comment[wa]=Li metaedje doirmi a stî espaitchî paske on programe l' a dmandé +Comment[x-test]=xxThe suspension has been inhibited because an application requested itxx +Comment[zh_CN]=由于应用程序的要求,挂起已被禁止 +Comment[zh_TW]=暫停功能已被禁止,因為有應用程式如此要求 +Contexts=criticalnot +Sound=KDE-Sys-App-Error-Critical.ogg +Action=Sound|Popup +IconName=dialog-information + +[Event/brokenbattery] +Name=Broken battery notification +Name[ar]=تبليغ البطارية التالفة +Name[bg]=Повредена батерия +Name[bs]=Obavještenje o pokvarenoj bateriji +Name[ca]=Notificació de bateria trencada +Name[ca@valencia]=Notificació de bateria trencada +Name[cs]=Oznámení vadné baterie +Name[da]=Bekendtgørelse af defekt batteri +Name[de]=Benachrichtigung über defekten Akku +Name[el]=Ειδοποίηση χαλασμένης μπαταρίας +Name[en_GB]=Broken battery notification +Name[es]=Notificación de batería estropeada +Name[et]=Katkise aku märguanne +Name[eu]=Bateria hondatuaren jakinarazpena +Name[fi]=Ilmoitus rikkinäisestä akusta +Name[fr]=Notification de batterie endommagée +Name[gl]=Notificación de batería estragada +Name[he]=הודעת סוללה תקולה +Name[hr]=Obavijest o neispravnoj bateriji +Name[hu]=Hibás akkumulátor értesítés +Name[ia]=Notification de batteria rupte +Name[is]=Tilkynning um að rafhlaðan er ekki í lagi +Name[ja]=バッテリーの故障通知 +Name[kk]=Батареяның істен шыққаны туралы хабарлауы +Name[km]=ការ​ជូន​ដំណឹង​ថ្ម​ខូច +Name[kn]=ಬ್ಯಾಟರಿ ಹಾಳಾದ ಸೂಚನೆ +Name[ko]=배터리 문제 알림 +Name[lt]=Pranešimas apie sugedusią bateriją +Name[lv]=Bojātas baterijas paziņojums +Name[mr]=तुटलेली बॅटरी सूचना +Name[nb]=Varsling om ødelagt batteri +Name[nds]=Bescheed över Batteriefehlers +Name[nl]=Gebroken melding over accu +Name[pa]=ਖਰਾਬ ਨੈਟਰੀ ਨੋਟੀਫਿਕੇਸ਼ਨ +Name[pl]=Powiadomienie o zepsutej baterii +Name[pt]=Notificação de baterias com problemas +Name[pt_BR]=Notificação de bateria com problema +Name[ro]=Notificare de acumulator defect +Name[ru]=Уведомления о неполадках батарей +Name[sk]=Upozornenie na poškodenú batériu +Name[sl]=Obvestilo o poškodovani bateriji +Name[sr]=Обавештење о поквареној батерији +Name[sr@ijekavian]=Обавјештење о поквареној батерији +Name[sr@ijekavianlatin]=Obavještenje o pokvarenoj bateriji +Name[sr@latin]=Obaveštenje o pokvarenoj bateriji +Name[sv]=Underrättelse om felaktigt batteri +Name[th]=การแจ้งให้ทราบถึงแบตเตอรี่เสียหาย +Name[tr]=Kırık pil bildirimi +Name[ug]=بۇزۇلغان توكدان ئۇقتۇرۇشى +Name[uk]=Сповіщення про пошкоджений акумулятор +Name[vi]=Thông tin pin hỏng +Name[wa]=Notifiaedje d' ene batreye di schetêye +Name[x-test]=xxBroken battery notificationxx +Name[zh_CN]=电池损坏通知 +Name[zh_TW]=電池損壞通知 +Comment=KDE Power Management System has detected some troubles with one of your batteries +Comment[bs]=KDE sistem za upravljanje napajanjem otkrio je problem sa nekom od baterija. +Comment[ca]=El sistema de gestió d'energia del KDE ha detectat algun problema amb alguna de les bateries +Comment[ca@valencia]=El sistema de gestió d'energia del KDE ha detectat algun problema amb alguna de les bateries +Comment[cs]=Správce napájení KDE zjistil problémy s jednou z vašich baterií +Comment[da]=KDE's strømstyringssystem har fundet nogle problemer med et af dine batterier +Comment[de]=Das KDE-Energieverwaltungssystem hat Probleme mit einer Ihrer Akkus entdeckt +Comment[el]=Το σύστημα διαχείρισης ενέργειας του KDE έχει εντοπίσει κάποια προβλήματα με κάποια από τις μπαταρίες σας +Comment[en_GB]=KDE Power Management System has detected some troubles with one of your batteries +Comment[es]=El sistema de gestión de energía de KDE ha detectado algún problema en una de sus baterías +Comment[et]=KDE toitehalduse süsteem tuvastas mingeid probleeme mõne su akuga +Comment[eu]=KDEren energia kudeatzeko sistemak baterietako batekin arazoak daudela detektatu du +Comment[fi]=KDE:n virranhallintajärjestelmä on havainnut ongelmia akuissasi +Comment[fr]=Le système de gestion de l'énergie de KDE a détecté des problèmes avec l'une de vos batteries +Comment[gl]=O sistema de xestión da enerxía de KDE detectou algúns problemas cunha das baterías +Comment[he]=מערכת ניהול צריכת חשמל של KDE זיהתה בעיות עם אחת הסוללות +Comment[hu]=A KDE energiakezelő rendszere hibát észlelt az egyik akkumulátorában +Comment[ia]=Le systema de gestion de energia de KDE releva alcun problemas con un de tu batterias +Comment[is]=Þessi tilkynning kemur upp ef KDE orkustjórnunarkerfið finnur einhver vandamál með rafhlöður +Comment[kk]=KDE қуаттандыруды басқару жүйесі батареяңыздың бір мәселелерін байқады +Comment[ko]=KDE 전원 관리 시스템에서 배터리에 문제를 발견하였습니다 +Comment[lt]=KDE energijos valdymo sistema aptiko bėdų su vienu iš Jūsų akumuliatorių +Comment[mr]=केडीई वीज व्यवस्थापन प्रणालीला तुमच्या बैटरीमध्ये काही समस्या वाटत आहे +Comment[nb]=KDE Strømstyringssystem har oppdaget vanskeligheter med et av batteriene dine +Comment[nds]=Dat KDE-Stroompleegsysteem hett Problemen mit een vun Dien Batterien opdeckt. +Comment[nl]=Deze melding verschijnt als het KDE energiebeheersysteem een probleem detecteert met één van uw accu's +Comment[pa]=ਕੇਡੀਈ ਊਰਜਾ ਪਰਬੰਧ ਸਿਸਟਮ ਨੂੰ ਤੁਹਾਡੀਆਂ ਬੈਟਰੀਆਂ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਮਿਲੀ ਹੈ +Comment[pl]=System zarządzania energią w KDE wykrył jakieś problemy z jedną z twoich baterii +Comment[pt]=O Sistema de Gestão de Energia do KDE detectou algum problema com alguma das suas baterias +Comment[pt_BR]=O Sistema de Gerenciamento de Energia do KDE detectou um problema com uma das suas baterias +Comment[ro]=Sistemul KDE de gestiune a alimentării a identificat probleme cu unul dintre acumulatoare +Comment[ru]=Система управления питанием KDE обнаружила, что одна из ваших батарей имеет проблемы. +Comment[sk]=Systém správy napájania KDE zistil problémy s jednou z vašich batérií +Comment[sl]=Sistem za upravljanje z energijo je zaznal težavo z eno izmed baterij +Comment[sr]=КДЕ‑ов систем за управљање напајањем открио је проблем са неком од батерија. +Comment[sr@ijekavian]=КДЕ‑ов систем за управљање напајањем открио је проблем са неком од батерија. +Comment[sr@ijekavianlatin]=KDE‑ov sistem za upravljanje napajanjem otkrio je problem sa nekom od baterija. +Comment[sr@latin]=KDE‑ov sistem za upravljanje napajanjem otkrio je problem sa nekom od baterija. +Comment[sv]=KDE:s strömsparhantering har detekterar vissa problem med något av batterierna +Comment[tr]=KDE Güç Yönetim Sistemi pillerinizden birinde bazı sorunlar algıladı. +Comment[uk]=Системою керування живленням KDE виявлено проблеми з одним з акумуляторів +Comment[x-test]=xxKDE Power Management System has detected some troubles with one of your batteriesxx +Comment[zh_CN]=KDE 电源管理系统检测到电池问题 +Comment[zh_TW]=KDE 電源管理系統發現您的電池有些問題 +Contexts=criticalnot +Sound=KDE-Sys-App-Error-Critical.ogg +Action=Sound|Popup +IconName=battery-missing diff --git a/qguiplatformplugin_kde/CMakeLists.txt b/qguiplatformplugin_kde/CMakeLists.txt new file mode 100644 index 00000000..18dd808f --- /dev/null +++ b/qguiplatformplugin_kde/CMakeLists.txt @@ -0,0 +1,15 @@ +project(qguiplatformplugin_kde) + +set(kde_SOURCES qguiplatformplugin_kde.cpp) +qt4_generate_moc(qguiplatformplugin_kde.cpp ${CMAKE_CURRENT_BINARY_DIR}/qguiplatformplugin_kde.moc) + + +add_library (kde SHARED ${kde_SOURCES}) + +target_link_libraries(kde ${KDE4_KIO_LIBS} ${QT_QTGUI_LIBRARY}) + +install (TARGETS kde LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/gui_platform) + + + + diff --git a/qguiplatformplugin_kde/qguiplatformplugin_kde.cpp b/qguiplatformplugin_kde/qguiplatformplugin_kde.cpp new file mode 100644 index 00000000..4f67cc55 --- /dev/null +++ b/qguiplatformplugin_kde/qguiplatformplugin_kde.cpp @@ -0,0 +1,387 @@ +/* This file is part of the KDE project + + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qguiplatformplugin_p.h" + +#include + +/* + * Map a Qt filter string into a KDE one. + * (from kfiledialog.cpp) +*/ +static QString qt2KdeFilter(const QString &f) +{ + QString filter; + QTextStream str(&filter, QIODevice::WriteOnly); + const QStringList list(f.split(";;").replaceInStrings("/", "\\/")); + QStringList::const_iterator it(list.begin()), + end(list.end()); + bool first=true; + + for(; it!=end; ++it) + { + int ob=(*it).lastIndexOf('('), + cb=(*it).lastIndexOf(')'); + + if(-1!=cb && ob0 && + ('('==(*it)[pos-1] || ' '==(*it)[pos-1]) && + (*it).length()>=kde.length()+pos && + (')'==(*it)[pos+kde.length()] || ' '==(*it)[pos+kde.length()])) + { + *sel=*it; + return; + } + } +} + + +class KFileDialogBridge : public KFileDialog +{ +public: + KFileDialogBridge (const KUrl &startDir, const QString &filter, QFileDialog *original_) + : KFileDialog (startDir, filter, original_), original(original_) + { + connect(this, SIGNAL(fileSelected(QString)), original, SIGNAL(currentChanged(QString))); + } + + virtual void accept() + { + kDebug(); + KFileDialog::accept(); + QMetaObject::invokeMethod(original, "accept"); //workaround protected + } + + virtual void reject() + { + kDebug(); + KFileDialog::reject(); + QMetaObject::invokeMethod(original, "reject"); //workaround protected + } + + QFileDialog *original; +}; + +class KColorDialogBridge : public KColorDialog +{ +public: + KColorDialogBridge(QColorDialog* original_ = 0L) : KColorDialog(original_, true) , original(original_) + { + connect(this, SIGNAL(colorSelected(QColor)), original, SIGNAL(currentColorChanged(QColor))); + } + + QColorDialog *original; + + virtual void accept() + { + KColorDialog::accept(); + original->setCurrentColor(color()); + QMetaObject::invokeMethod(original, "accept"); //workaround protected + } + + virtual void reject() + { + KColorDialog::reject(); + QMetaObject::invokeMethod(original, "reject"); //workaround protected + } +}; + +Q_DECLARE_METATYPE(KFileDialogBridge *) +Q_DECLARE_METATYPE(KColorDialogBridge *) + +class KQGuiPlatformPlugin : public QGuiPlatformPlugin +{ + Q_OBJECT +public: + KQGuiPlatformPlugin() + { + QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection); + } + + virtual QStringList keys() const { return QStringList() << QLatin1String("kde"); } + virtual QString styleName() + { + const QString defaultStyle = KStyle::defaultStyle(); + const KConfigGroup pConfig(KGlobal::config(), "General"); + return pConfig.readEntry("widgetStyle", defaultStyle); + } + virtual QPalette palette() + { + return KGlobalSettings::createApplicationPalette(); + } + virtual QString systemIconThemeName() + { + return KIconTheme::current(); + } + virtual QStringList iconThemeSearchPaths() + { + return KGlobal::dirs()->resourceDirs("icon"); + } + virtual QIcon fileSystemIcon(const QFileInfo &file) + { + return KIcon(KMimeType::findByPath(file.filePath(), 0, true)->iconName()); + } + virtual int platformHint(PlatformHint hint) + { + switch(hint) + { + case PH_ToolButtonStyle: { + KConfigGroup group(KGlobal::config(), "Toolbar style"); + QString style = group.readEntry("ToolButtonStyle", "TextUnderIcon").toLower(); + if (style == "textbesideicon" || style == "icontextright") + return Qt::ToolButtonTextBesideIcon; + else if (style == "textundericon" || style == "icontextbottom") + return Qt::ToolButtonTextUnderIcon; + else if (style == "textonly") + return Qt::ToolButtonTextOnly; + else + return Qt::ToolButtonIconOnly; + } + case PH_ToolBarIconSize: + return KIconLoader::global()->currentSize(KIconLoader::MainToolbar); + case PH_ItemView_ActivateItemOnSingleClick: + return KGlobalSettings::singleClick(); + default: + break; + } + return QGuiPlatformPlugin::platformHint(hint); + } + +public: // File Dialog integration +#define K_FD(QFD) KFileDialogBridge *kdefd = qvariant_cast(QFD->property("_k_bridge")) + virtual void fileDialogDelete(QFileDialog *qfd) + { + K_FD(qfd); + delete kdefd; + } + virtual bool fileDialogSetVisible(QFileDialog *qfd, bool visible) + { + K_FD(qfd); + if (!kdefd && visible) { + if(qfd->options() & QFileDialog::DontUseNativeDialog) + return false; + + kdefd = new KFileDialogBridge(KUrl::fromPath(qfd->directory().canonicalPath()), + qt2KdeFilter(qfd->nameFilters().join(";;")), qfd); + + qfd->setProperty("_k_bridge", QVariant::fromValue(kdefd)); + } + + if (visible) { + switch (qfd->fileMode()) { + case QFileDialog::AnyFile: + kdefd->setMode(KFile::LocalOnly | KFile::File); + break; + case QFileDialog::ExistingFile: + kdefd->setMode(KFile::LocalOnly | KFile::File | KFile::ExistingOnly); + break; + case QFileDialog::ExistingFiles: + kdefd->setMode(KFile::LocalOnly | KFile::Files | KFile::ExistingOnly); + break; + case QFileDialog::Directory: + case QFileDialog::DirectoryOnly: + kdefd->setMode(KFile::LocalOnly | KFile::Directory); + break; + } + + + kdefd->setOperationMode((qfd->acceptMode() == QFileDialog::AcceptSave) ? KFileDialog::Saving : KFileDialog::Opening); + kdefd->setCaption(qfd->windowTitle()); + kdefd->setConfirmOverwrite(qfd->confirmOverwrite()); + kdefd->setSelection(qfd->selectedFiles().value(0)); + } + kdefd->setVisible(visible); + return true; + } + virtual QDialog::DialogCode fileDialogResultCode(QFileDialog *qfd) + { + K_FD(qfd); + Q_ASSERT(kdefd); + return QDialog::DialogCode(kdefd->result()); + } + virtual void fileDialogSetDirectory(QFileDialog *qfd, const QString &directory) + { + K_FD(qfd); + kdefd->setUrl(KUrl::fromPath(directory)); + } + virtual QString fileDialogDirectory(const QFileDialog *qfd) const + { + K_FD(qfd); + Q_ASSERT(kdefd); + return kdefd->baseUrl().pathOrUrl(); + } + virtual void fileDialogSelectFile(QFileDialog *qfd, const QString &filename) + { + K_FD(qfd); + Q_ASSERT(kdefd); + kdefd->setSelection(filename); + } + virtual QStringList fileDialogSelectedFiles(const QFileDialog *qfd) const + { + K_FD(qfd); + Q_ASSERT(kdefd); + return kdefd->selectedFiles(); + } + /*virtual void fileDialogSetFilter(QFileDialog *qfd) + { + K_FD(qfd); + }*/ + virtual void fileDialogSetNameFilters(QFileDialog *qfd, const QStringList &filters) + { + K_FD(qfd); + Q_ASSERT(kdefd); + kdefd->setFilter(qt2KdeFilter(filters.join(";;"))); + } + /*virtual void fileDialogSelectNameFilter(QFileDialog *qfd, const QString &filter) + { + K_FD(qfd); + }*/ + virtual QString fileDialogSelectedNameFilter(const QFileDialog *qfd) const + { + K_FD(qfd); + Q_ASSERT(kdefd); + QString ret; + kde2QtFilter(qfd->nameFilters().join(";;"), kdefd->currentFilter(), &ret); + return ret; + } +public: // ColorDialog +#define K_CD(QCD) KColorDialogBridge *kdecd = qvariant_cast(QCD->property("_k_bridge")) + virtual void colorDialogDelete(QColorDialog *qcd) + { + K_CD(qcd); + delete kdecd; + + } + virtual bool colorDialogSetVisible(QColorDialog *qcd, bool visible) + { + K_CD(qcd); + if (!kdecd) { + kdecd = new KColorDialogBridge(qcd); + kdecd->setColor(qcd->currentColor()); + if (qcd->options() & QColorDialog::NoButtons) { + kdecd->setButtons(KDialog::None); + } + kdecd->setModal(qcd->isModal()); + qcd->setProperty("_k_bridge", QVariant::fromValue(kdecd)); + } + if (visible) { + kdecd->setCaption(qcd->windowTitle()); + kdecd->setAlphaChannelEnabled(qcd->options() & QColorDialog::ShowAlphaChannel); + } + kdecd->setVisible(visible); + return true; + } + virtual void colorDialogSetCurrentColor(QColorDialog *qcd, const QColor &color) + { + K_CD(qcd); + if (kdecd) { + kdecd->setColor(color); + } + } + +private slots: + void init() + { + connect(KIconLoader::global(), SIGNAL(iconLoaderSettingsChanged()), this, SLOT(updateToolbarIcons())); + connect(KGlobalSettings::self(), SIGNAL(toolbarAppearanceChanged(int)), this, SLOT(updateToolbarStyle())); + connect(KGlobalSettings::self(), SIGNAL(kdisplayStyleChanged()), this, SLOT(updateWidgetStyle())); + } + + void updateToolbarStyle() + { + //from gtksymbol.cpp + QWidgetList widgets = QApplication::allWidgets(); + for (int i = 0; i < widgets.size(); ++i) { + QWidget *widget = widgets.at(i); + if (qobject_cast(widget)) { + QEvent event(QEvent::StyleChange); + QApplication::sendEvent(widget, &event); + } + } + } + + void updateToolbarIcons() + { + QWidgetList widgets = QApplication::allWidgets(); + for (int i = 0; i < widgets.size(); ++i) { + QWidget *widget = widgets.at(i); + if (qobject_cast(widget) || qobject_cast(widget)) { + QEvent event(QEvent::StyleChange); + QApplication::sendEvent(widget, &event); + } + } + } + + void updateWidgetStyle() + { + if (qApp) { + if (qApp->style()->objectName() != styleName()) { + qApp->setStyle(styleName()); + } + } + } +}; + +Q_EXPORT_PLUGIN2(KQGuiPlatformPlugin, KQGuiPlatformPlugin) + +#include "qguiplatformplugin_kde.moc" + diff --git a/qguiplatformplugin_kde/qguiplatformplugin_p.h b/qguiplatformplugin_kde/qguiplatformplugin_p.h new file mode 100644 index 00000000..9a44acfa --- /dev/null +++ b/qguiplatformplugin_kde/qguiplatformplugin_p.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIPLATFORM_P_H +#define QGUIPLATFORM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QPalette; +class QIcon; +class QFileDialog; +class QColorDialog; +class QFileInfo; + +struct Q_GUI_EXPORT QGuiPlatformPluginInterface : public QFactoryInterface +{ +}; + +#define QGuiPlatformPluginInterface_iid "com.nokia.qt.QGuiPlatformPluginInterface" + +Q_DECLARE_INTERFACE(QGuiPlatformPluginInterface, QGuiPlatformPluginInterface_iid) + +class Q_GUI_EXPORT QGuiPlatformPlugin : public QObject, public QGuiPlatformPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QGuiPlatformPluginInterface:QFactoryInterface) + public: + explicit QGuiPlatformPlugin(QObject *parent = 0); + ~QGuiPlatformPlugin(); + + virtual QStringList keys() const { return QStringList() << QLatin1String("default"); }; + + virtual QString styleName(); + virtual QPalette palette(); + virtual QString systemIconThemeName(); + virtual QStringList iconThemeSearchPaths(); + virtual QIcon fileSystemIcon(const QFileInfo &); + + enum PlatformHint { PH_ToolButtonStyle, PH_ToolBarIconSize, PH_ItemView_ActivateItemOnSingleClick }; + virtual int platformHint(PlatformHint hint); + + + virtual void fileDialogDelete(QFileDialog *) {} + virtual bool fileDialogSetVisible(QFileDialog *, bool) { return false; } + virtual QDialog::DialogCode fileDialogResultCode(QFileDialog *) { return QDialog::Rejected; } + virtual void fileDialogSetDirectory(QFileDialog *, const QString &) {} + virtual QString fileDialogDirectory(const QFileDialog *) const { return QString(); } + virtual void fileDialogSelectFile(QFileDialog *, const QString &) {} + virtual QStringList fileDialogSelectedFiles(const QFileDialog *) const { return QStringList(); } + virtual void fileDialogSetFilter(QFileDialog *) {} + virtual void fileDialogSetNameFilters(QFileDialog *, const QStringList &) {} + virtual void fileDialogSelectNameFilter(QFileDialog *, const QString &) {} + virtual QString fileDialogSelectedNameFilter(const QFileDialog *) const { return QString(); } + + virtual void colorDialogDelete(QColorDialog *) {} + virtual bool colorDialogSetVisible(QColorDialog *, bool) { return false; } + virtual void colorDialogSetCurrentColor(QColorDialog *, const QColor &) {} +}; + +//internal +QGuiPlatformPlugin *qt_guiPlatformPlugin(); + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QGUIPLATFORMPLUGIN_H diff --git a/solid-actions-kcm/ActionEditor.cpp b/solid-actions-kcm/ActionEditor.cpp new file mode 100644 index 00000000..8cda2bbe --- /dev/null +++ b/solid-actions-kcm/ActionEditor.cpp @@ -0,0 +1,190 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 "ActionEditor.h" + +#include + +#include + +ActionEditor::ActionEditor(QWidget *parent) : KDialog(parent) +{ + topItem = new PredicateItem( Solid::Predicate(), 0 ); + rootItem = 0; + rootModel = new PredicateModel( topItem, this ); + // Prepare the dialog + setInitialSize( QSize(600, 600) ); // Set a decent initial size + // setModal( true ); + // Set up the interface + ui.setupUi( mainWidget() ); + ui.TvPredicateTree->setHeaderHidden( true ); + ui.TvPredicateTree->setModel( rootModel ); + ui.IbActionIcon->setIconSize( KIconLoader::SizeLarge ); + + ui.CbDeviceType->addItems( actionData()->interfaceList() ); + + // Connect up with everything needed -> slot names explain + connect( ui.TvPredicateTree, SIGNAL(activated(QModelIndex)), this, SLOT(updateParameter()) ); + connect( ui.PbParameterSave, SIGNAL(clicked()), this, SLOT(saveParameter()) ); + connect( ui.PbParameterReset, SIGNAL(clicked()), this, SLOT(updateParameter()) ); + connect( ui.CbDeviceType, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePropertyList()) ); + connect( ui.CbParameterType, SIGNAL(currentIndexChanged(int)), this, SLOT(manageControlStatus()) ); + + if( !KGlobalSettings::singleClick() ) { + connect( ui.TvPredicateTree, SIGNAL(clicked(QModelIndex)), this, SLOT(updateParameter()) ); + } +} + +ActionEditor::~ActionEditor() +{ + delete topItem; +} + +void ActionEditor::setActionToEdit( ActionItem * item ) +{ + activeItem = item; + + // Set all the text appropriately + ui.IbActionIcon->setIcon( item->icon() ); + ui.LeActionFriendlyName->setText( item->name() ); + ui.LeActionCommand->setUrl( KUrl(item->exec()) ); + + setPredicate( item->predicate() ); + setCaption( i18n("Editing Action %1", item->name()) ); // Set a friendly i18n caption +} + +void ActionEditor::setPredicate( Solid::Predicate predicate ) +{ + delete topItem; + topItem = new PredicateItem( Solid::Predicate(), 0 ); + rootItem = new PredicateItem( predicate, topItem ); + rootModel->setRootPredicate( rootItem->parent() ); + + // Select the top item, not the hidden root + QModelIndex topItem = rootModel->index( 0, 0, QModelIndex() ); + ui.TvPredicateTree->setCurrentIndex( topItem ); + ui.TvPredicateTree->expandToDepth( 2 ); + updateParameter(); +} + +void ActionEditor::updateParameter() +{ + QModelIndex current = ui.TvPredicateTree->currentIndex(); + PredicateItem * currentItem = static_cast( current.internalPointer() ); + + ui.CbParameterType->setCurrentIndex( currentItem->itemType ); + updatePropertyList(); + ui.CbDeviceType->setCurrentIndex( actionData()->interfacePosition( currentItem->ifaceType ) ); + int valuePos = actionData()->propertyPosition( currentItem->ifaceType, currentItem->property ); + ui.CbValueName->setCurrentIndex( valuePos ); + ui.LeValueMatch->setText( currentItem->value.toString() ); + ui.CbValueMatch->setCurrentIndex( currentItem->compOperator ); +} + +void ActionEditor::saveParameter() +{ + QModelIndex current = ui.TvPredicateTree->currentIndex(); + PredicateItem * currentItem = static_cast( current.internalPointer() ); + + // Hold onto this so we can determine if the number of children has changed... + Solid::Predicate::Type oldType = currentItem->itemType; + + currentItem->setTypeByInt( ui.CbParameterType->currentIndex() ); + currentItem->ifaceType = actionData()->interfaceFromName( ui.CbDeviceType->currentText() ); + currentItem->property = actionData()->propertyInternal( currentItem->ifaceType, ui.CbValueName->currentText() ); + currentItem->value = QVariant( ui.LeValueMatch->text() ); + currentItem->setComparisonByInt( ui.CbValueMatch->currentIndex() ); + + rootModel->itemUpdated( current ); + rootModel->childrenChanging( current, oldType ); +} + +QString ActionEditor::predicateString() +{ + return rootItem->predicate().toString(); +} + +void ActionEditor::updatePropertyList() +{ + Solid::DeviceInterface::Type currentType; + currentType = actionData()->interfaceFromName( ui.CbDeviceType->currentText() ); + + ui.CbValueName->clear(); + ui.CbValueName->addItems( actionData()->propertyList( currentType ) ); +} + +void ActionEditor::manageControlStatus() +{ + bool atomEnable = false; + bool isEnable = false; + + switch( ui.CbParameterType->currentIndex() ) { + case Solid::Predicate::PropertyCheck: + atomEnable = true; + case Solid::Predicate::InterfaceCheck: + isEnable = true; + break; + default: + break; + } + ui.CbDeviceType->setEnabled( isEnable ); + ui.CbValueName->setEnabled( atomEnable ); + ui.CbValueMatch->setEnabled( atomEnable ); + ui.LeValueMatch->setEnabled( atomEnable ); +} + +SolidActionData * ActionEditor::actionData() +{ + return SolidActionData::instance(); +} + +void ActionEditor::accept() +{ + // Save any open parameter changes first... + saveParameter(); + + // Read the data and prepare to save + QString iconName = ui.IbActionIcon->icon(); + QString actionName = ui.LeActionFriendlyName->text(); + QString command = ui.LeActionCommand->text(); + QString predicate = predicateString(); + + // We need to ensure that they are all valid before applying + if (iconName.isEmpty() || actionName.isEmpty() || command.isEmpty() || !Solid::Predicate::fromString(predicate).isValid()) { + KMessageBox::error(this, i18n("It appears that the action name, command, icon or condition are not valid.\nTherefore, changes will not be applied."), i18n("Invalid action")); + return; + } + // apply the changes + if (iconName != activeItem->icon()) { // Has the icon changed? + activeItem->setIcon( ui.IbActionIcon->icon() ); // Write the change + } + if (actionName != activeItem->name()) { // Has the friendly name changed? + activeItem->setName( ui.LeActionFriendlyName->text() ); // Write the change + } + if (command != activeItem->exec()) { // Has the command changed? + activeItem->setExec( ui.LeActionCommand->text() ); // Write the change + } + if (predicate != activeItem->predicate().toString() ) { // Has it changed? + activeItem->setPredicate( predicate ); // Write the change + } + + KDialog::accept(); +} + +#include "ActionEditor.moc" diff --git a/solid-actions-kcm/ActionEditor.h b/solid-actions-kcm/ActionEditor.h new file mode 100644 index 00000000..6f8675e5 --- /dev/null +++ b/solid-actions-kcm/ActionEditor.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 ACTIONEDITOR_H +#define ACTIONEDITOR_H + +#include + +#include "ActionItem.h" +#include "PredicateItem.h" +#include "PredicateModel.h" +#include "SolidActionData.h" +#include "ui_ActionEditor.h" + +class ActionEditor : public KDialog +{ + Q_OBJECT +public: + ActionEditor(QWidget *parent = 0); + ~ActionEditor(); + + void setActionToEdit( ActionItem * item ); + +public slots: + virtual void accept(); + +private: + SolidActionData * actionData(); + QString predicateString(); + + Ui::ActionEditor ui; + ActionItem * activeItem; + PredicateItem * topItem; + PredicateItem * rootItem; + PredicateModel * rootModel; + +private slots: + void updatePropertyList(); + void manageControlStatus(); + void updateParameter(); + void saveParameter(); + void setPredicate( Solid::Predicate predicate ); + +}; + +#endif diff --git a/solid-actions-kcm/ActionEditor.ui b/solid-actions-kcm/ActionEditor.ui new file mode 100644 index 00000000..486149f9 --- /dev/null +++ b/solid-actions-kcm/ActionEditor.ui @@ -0,0 +1,335 @@ + + + ActionEditor + + + + 0 + 0 + 602 + 522 + + + + + + + + + + 0 + 0 + + + + + 80 + 80 + + + + + 75 + 75 + + + + Action icon, click to change it + + + + + + + Action name + + + + + + + + + + + + 80 + 0 + + + + Command: + + + + + + + Command that will trigger the action +This can include any or all of the following case insensitive expands: + +%f: The mountpoint for the device - Storage Access devices only +%d: Path to the device node - Block devices only +%i: The identifier of the device + + + + + + + + + + + + 80 + 0 + + + + Devices must match the following parameters for this action: + + + + + + + + + + + + Edit Parameter + + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + + 150 + 16777215 + + + + Parameter type: + + + + + + + + Property Match + + + + + Content Conjunction + + + + + Content Disjunction + + + + + Device Interface Match + + + + + + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + + 150 + 16777215 + + + + Device type: + + + + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + + 150 + 16777215 + + + + Value name: + + + + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + + 150 + 16777215 + + + + + Equals + + + + + Contains + + + + + + + + + + + + + + + Qt::Horizontal + + + + 227 + 25 + + + + + + + + Reset Parameter + + + + + + + Save Parameter Changes + + + + + + + + + + + + + KIconButton + QPushButton +
kicondialog.h
+
+ + KUrlRequester + QFrame +
kurlrequester.h
+
+ + KLineEdit + QLineEdit +
klineedit.h
+
+ + KComboBox + QComboBox +
kcombobox.h
+
+
+ + +
diff --git a/solid-actions-kcm/ActionItem.cpp b/solid-actions-kcm/ActionItem.cpp new file mode 100644 index 00000000..c5fc69a3 --- /dev/null +++ b/solid-actions-kcm/ActionItem.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 "ActionItem.h" +#include "SolidActionData.h" + +#include + +#include +#include +#include + +#include + +ActionItem::ActionItem(const QString& pathToDesktop, const QString& action, QObject *parent) +{ + Q_UNUSED(parent); + + desktopMasterPath = pathToDesktop; + actionName = action; + // Create the desktop file + desktopFileMaster = new KDesktopFile(desktopMasterPath); + desktopWritePath = desktopFileMaster->locateLocal(desktopMasterPath); + desktopFileWrite = new KDesktopFile(desktopWritePath); + // Now we can fill the action groups list + configGroups.append(desktopFileMaster->desktopGroup()); + actionGroups.insertMulti(ActionItem::GroupDesktop, &configGroups.last()); + configGroups.append(desktopFileMaster->actionGroup(actionName)); + actionGroups.insertMulti(ActionItem::GroupAction, &configGroups.last()); + configGroups.append(desktopFileWrite->desktopGroup()); + actionGroups.insertMulti(ActionItem::GroupDesktop, &configGroups.last()); + configGroups.append(desktopFileWrite->actionGroup(actionName)); + actionGroups.insertMulti(ActionItem::GroupAction, &configGroups.last()); + + QString predicateString = readKey(ActionItem::GroupDesktop, "X-KDE-Solid-Predicate", ""); + predicateItem = Solid::Predicate::fromString( predicateString ); +} + +ActionItem::~ActionItem() +{ + delete desktopFileWrite; + delete desktopFileMaster; +} + +/// Public functions below + +bool ActionItem::isUserSupplied() +{ + return hasKey(ActionItem::GroupDesktop, "X-KDE-Action-Custom"); +} + +QString ActionItem::icon() +{ + return readKey(ActionItem::GroupAction, "Icon", ""); +} + +QString ActionItem::exec() +{ + return readKey(ActionItem::GroupAction, "Exec", ""); +} + +QString ActionItem::name() +{ + return readKey(ActionItem::GroupAction, "Name", ""); +} + +Solid::Predicate ActionItem::predicate() const +{ + return predicateItem; +} + +QString ActionItem::involvedTypes() const +{ + SolidActionData * actData = SolidActionData::instance(); + QSet devTypeList = predicateItem.usedTypes(); + QStringList deviceTypes; + foreach( Solid::DeviceInterface::Type devType, devTypeList ) { + deviceTypes << actData->nameFromInterface( devType ); + } + + return deviceTypes.join(", "); +} + +void ActionItem::setIcon(const QString& nameOfIcon) +{ + setKey(ActionItem::GroupAction, "Icon", nameOfIcon); +} + +void ActionItem::setName(const QString& nameOfAction) +{ + setKey(ActionItem::GroupAction, "Name", nameOfAction); +} + +void ActionItem::setExec(const QString& execUrl) +{ + setKey(ActionItem::GroupAction, "Exec", execUrl); +} + +void ActionItem::setPredicate( const QString& newPredicate ) +{ + setKey(ActionItem::GroupDesktop, "X-KDE-Solid-Predicate", newPredicate); + predicateItem = Solid::Predicate::fromString( newPredicate ); +} + +/// Private functions below + +QString ActionItem::readKey(GroupType keyGroup, const QString& keyName, const QString& defaultValue) +{ + return configItem(ActionItem::DesktopRead, keyGroup, keyName)->readEntry(keyName, defaultValue); +} + +void ActionItem::setKey(GroupType keyGroup, const QString& keyName, const QString& keyContents) +{ + configItem(ActionItem::DesktopWrite, keyGroup)->writeEntry(keyName, keyContents); +} + +bool ActionItem::hasKey(GroupType keyGroup, const QString& keyName) +{ + return configItem(ActionItem::DesktopRead, keyGroup, keyName)->hasKey(keyName); +} + +KConfigGroup * ActionItem::configItem(DesktopAction actionType, GroupType keyGroup, const QString& keyName) +{ + int countAccess = 0; + + if (actionType == ActionItem::DesktopRead) { + foreach(KConfigGroup * possibleGroup, actionGroups.values(keyGroup)) { + if (possibleGroup->hasKey(keyName)) { + return possibleGroup; + break; + } + } + } else if (actionType == ActionItem::DesktopWrite) { + if (isUserSupplied()) { + countAccess = 1; + } + return actionGroups.values(keyGroup)[countAccess]; + } + return actionGroups.values(keyGroup)[0]; // Implement a backstop so a valid value is always returned +} + +#include "ActionItem.moc" diff --git a/solid-actions-kcm/ActionItem.h b/solid-actions-kcm/ActionItem.h new file mode 100644 index 00000000..509efb31 --- /dev/null +++ b/solid-actions-kcm/ActionItem.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 ACTION_ITEM_H +#define ACTION_ITEM_H + +#include +#include + +#include + +class QString; + +class KDesktopFile; +class KConfigGroup; + +class ActionItem: public QObject +{ + Q_OBJECT + +public: + ActionItem(const QString& pathToDesktop, const QString& action, QObject *parent = 0); + ~ActionItem(); + + bool isUserSupplied(); + + QString icon(); + QString exec(); + QString name(); + Solid::Predicate predicate() const; + QString involvedTypes() const; + void setIcon( const QString& nameOfIcon ); + void setName( const QString& nameOfAction ); + void setExec( const QString& execUrl ); + void setPredicate( const QString& newPredicate ); + + QString desktopMasterPath; + QString desktopWritePath; + QString actionName; + +private: + enum DesktopAction { DesktopRead = 0, DesktopWrite = 1 }; + enum GroupType { GroupDesktop = 0, GroupAction = 1 }; + + QString readKey(GroupType keyGroup, const QString& keyName, const QString& defaultValue); + void setKey(GroupType keyGroup, const QString& keyName, const QString& keyContents); + bool hasKey(GroupType keyGroup, const QString& keyName); + KConfigGroup * configItem(DesktopAction actionType, GroupType keyGroup, const QString& keyName = QString()); + + KDesktopFile * desktopFileMaster; + KDesktopFile * desktopFileWrite; + QMultiMap actionGroups; + QList configGroups; + Solid::Predicate predicateItem; + +}; + +Q_DECLARE_METATYPE( ActionItem * ) + +#endif diff --git a/solid-actions-kcm/ActionModel.cpp b/solid-actions-kcm/ActionModel.cpp new file mode 100644 index 00000000..de2d4f33 --- /dev/null +++ b/solid-actions-kcm/ActionModel.cpp @@ -0,0 +1,121 @@ +/************************************************************************** + * Copyright (C) 2009 Ben Cooksley * + * Copyright (C) 2007 Will Stephenson * + * * + * 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 "ActionModel.h" +#include "ActionItem.h" + +#include +#include +#include + +class ActionModel::Private { +public: + Private() {} + + QList actions; +}; + +static bool sortAction( ActionItem * left, ActionItem * right ) +{ + return left->name() > right->name(); +} + +ActionModel::ActionModel( QObject *parent ) + : QAbstractTableModel( parent ) + , d( new Private() ) +{ +} + +ActionModel::~ActionModel() +{ + qDeleteAll( d->actions ); + d->actions.clear(); + delete d; +} + +int ActionModel::columnCount( const QModelIndex &parent ) const +{ + Q_UNUSED( parent ); + return 2; +} + +int ActionModel::rowCount( const QModelIndex &parent ) const +{ + if( !parent.isValid() ) { + return d->actions.count(); + } + return 0; +} + +QVariant ActionModel::data( const QModelIndex &index, int role ) const +{ + QVariant theData; + if ( !index.isValid() ) { + return QVariant(); + } + + ActionItem * mi = d->actions.at( index.row() ); + switch ( role ) { + case Qt::DisplayRole: + if( index.column() == 0 ) { + theData.setValue( mi->name() ); + } else if( index.column() == 1 ) { + theData.setValue( mi->involvedTypes() ); + } + break; + case Qt::DecorationRole: + if( index.column() == 0 ) { + theData = QVariant( KIcon(mi->icon()) ); + } + break; + case Qt::UserRole: + theData.setValue( mi ); + break; + default: + break; + } + return theData; +} + +void ActionModel::buildActionList() +{ + qDeleteAll( d->actions ); + d->actions.clear(); + // Prepare to search for possible actions -> we only want solid types + QStringList allPossibleActions = KGlobal::dirs()->findAllResources("data", "solid/actions/"); + // Get service objects for those actions and add them to the display + foreach(const QString &desktop, allPossibleActions) { + // Get contained services list + QList services = KDesktopFileActions::userDefinedServices(desktop, true); + foreach( const KServiceAction &deviceAction, services ) { + ActionItem * actionItem = new ActionItem( desktop, deviceAction.name(), this ); // Create an action + d->actions.append( actionItem ); + } + } + qSort( d->actions.begin(), d->actions.end(), sortAction ); + reset(); +} + +QList ActionModel::actionList() const +{ + return d->actions; +} + +#include "ActionModel.moc" diff --git a/solid-actions-kcm/ActionModel.h b/solid-actions-kcm/ActionModel.h new file mode 100644 index 00000000..209fcbff --- /dev/null +++ b/solid-actions-kcm/ActionModel.h @@ -0,0 +1,48 @@ +/************************************************************************** + * Copyright (C) 2009 Ben Cooksley * + * * + * 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 ACTIONMODEL_H +#define ACTIONMODEL_H + +#include + +class ActionItem; + +class ActionModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit ActionModel( QObject *parent = 0 ); + ~ActionModel(); + + QVariant data( const QModelIndex &index, int role ) const; + int rowCount( const QModelIndex &parent = QModelIndex() ) const; + int columnCount( const QModelIndex &parent = QModelIndex() ) const; + + void buildActionList(); + QList actionList() const; + +private: + + class Private; + Private * const d; +}; + +#endif diff --git a/solid-actions-kcm/AddAction.ui b/solid-actions-kcm/AddAction.ui new file mode 100644 index 00000000..745597e6 --- /dev/null +++ b/solid-actions-kcm/AddAction.ui @@ -0,0 +1,43 @@ + + + AddAction + + + + 0 + 0 + 289 + 40 + + + + + + + + + Action name: + + + + + + + Enter the name for your new action + + + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+
+ + +
diff --git a/solid-actions-kcm/CMakeLists.txt b/solid-actions-kcm/CMakeLists.txt new file mode 100644 index 00000000..bb7c289f --- /dev/null +++ b/solid-actions-kcm/CMakeLists.txt @@ -0,0 +1,49 @@ +PROJECT (solid-actions) + +# We allow this to be built seperately for convienence purposes +IF(CMAKE_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + + FIND_PACKAGE(KDE4 REQUIRED) + INCLUDE(KDE4Defaults) + ADD_DEFINITIONS(${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) + +ENDIF(CMAKE_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + +INCLUDE_DIRECTORIES (${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) + +ADD_SUBDIRECTORY(device-actions) + +########### next target ############### + +SET(kcm_solid_actions_srcs + PredicateItem.cpp + PredicateModel.cpp + ActionItem.cpp + ActionModel.cpp + ActionEditor.cpp + SolidActionData.cpp + SolidActions.cpp ) + +SET(solid_action_desktop_gen_srcs + DesktopFileGenerator.cpp + SolidActionData.cpp ) + +KDE4_ADD_UI_FILES(kcm_solid_actions_srcs + SolidActions.ui + AddAction.ui + ActionEditor.ui ) + +KDE4_ADD_PLUGIN(kcm_solid_actions ${kcm_solid_actions_srcs}) +KDE4_ADD_EXECUTABLE(solid-action-desktop-gen ${solid_action_desktop_gen_srcs}) + +TARGET_LINK_LIBRARIES(kcm_solid_actions ${KDE4_KIO_LIBS} ${KDE4_SOLID_LIBS} ) +TARGET_LINK_LIBRARIES(solid-action-desktop-gen ${KDE4_SOLID_LIBS} ${KDE4_KIO_LIBS} ) + +########### install files ############### + +INSTALL( TARGETS kcm_solid_actions DESTINATION ${PLUGIN_INSTALL_DIR} ) +INSTALL( TARGETS solid-action-desktop-gen ${INSTALL_TARGETS_DEFAULT_ARGS} ) +INSTALL( FILES solid-actions.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +INSTALL( FILES solid-action-template.desktop DESTINATION ${DATA_INSTALL_DIR}/kcmsolidactions ) +INSTALL( FILES solid-device-type.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} ) + diff --git a/solid-actions-kcm/DesktopFileGenerator.cpp b/solid-actions-kcm/DesktopFileGenerator.cpp new file mode 100644 index 00000000..a9f82c47 --- /dev/null +++ b/solid-actions-kcm/DesktopFileGenerator.cpp @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 +#include +#include +#include + +#include "SolidActionData.h" + +#include + +int main( int argc, char *argv[] ) +{ + KLocale::setMainCatalog("solid-action-desktop-gen"); + // About data + KAboutData aboutData("solid-action-desktop-gen", 0, ki18n("Solid Action Desktop File Generator"), "0.4", ki18n("Tool to automatically generate Desktop Files from Solid DeviceInterface classes for translation"), + KAboutData::License_GPL, ki18n("(c) 2009, Ben Cooksley")); + aboutData.addAuthor(ki18n("Ben Cooksley"), ki18n("Maintainer"), "ben@eclipse.endoftheinternet.org"); + KCmdLineArgs::init(argc, argv, &aboutData); + + KApplication application(false); + SolidActionData * availActions = SolidActionData::instance(); + foreach( Solid::DeviceInterface::Type internalType, availActions->interfaceTypeList() ) { + QString typeName = Solid::DeviceInterface::typeToString( internalType ); + KDesktopFile typeFile( "services", "solid-device-" + typeName + ".desktop" ); + KConfigGroup tConfig = typeFile.desktopGroup(); + + tConfig.writeEntry( "Name", "Solid Device" ); + tConfig.writeEntry( "X-KDE-ServiceTypes", "SolidDevice" ); + tConfig.writeEntry( "Type", "Service" ); + + if( !tConfig.hasKey("X-KDE-Solid-Actions-Type") ) { + tConfig.writeEntry( "X-KDE-Solid-Actions-Type", typeName ); + } + + QStringList typeValues = availActions->propertyInternalList( internalType ); + QString actionText = typeValues.join(";").append(";"); + tConfig.writeEntry( "Actions", actionText ); + + kWarning() << "Desktop file created: " + typeFile.fileName(); + foreach( const QString &tValue, typeValues ) { + KConfigGroup vConfig = typeFile.actionGroup( tValue ); + if( !vConfig.hasKey("Name") ) { + vConfig.writeEntry( "Name", availActions->propertyName( internalType, tValue ) ); + } + vConfig.sync(); + } + tConfig.sync(); + typeFile.sync(); + } + + kWarning() << "Generation now completed"; + return 0; +} diff --git a/solid-actions-kcm/Messages.sh b/solid-actions-kcm/Messages.sh new file mode 100644 index 00000000..c4c99925 --- /dev/null +++ b/solid-actions-kcm/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC *.ui >> rc.cpp +$XGETTEXT *.cpp -o $podir/kcm_solid_actions.pot +rm -f rc.cpp diff --git a/solid-actions-kcm/PredicateItem.cpp b/solid-actions-kcm/PredicateItem.cpp new file mode 100644 index 00000000..600148c3 --- /dev/null +++ b/solid-actions-kcm/PredicateItem.cpp @@ -0,0 +1,208 @@ +/*************************************************************************** +* Copyright 2009 Ben Cooksley * +* * +* 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 "PredicateItem.h" + +#include "ActionEditor.h" + +#include +#include + +#include +#include + +class PredicateItem::Private { + +public: + Private() {} + + PredicateItem * parent; + QList children; + +}; + +PredicateItem::PredicateItem( Solid::Predicate item, PredicateItem * itsParent ) + : d( new Private() ) +{ + d->parent = itsParent; + + if ( d->parent ) { + d->parent->children().append( this ); + } + + // Read data from Solid::Predicate + itemType = item.type(); + ifaceType = item.interfaceType(); + property = item.propertyName(); + value = item.matchingValue(); + compOperator = item.comparisonOperator(); + + if( itemType == Solid::Predicate::Disjunction || itemType == Solid::Predicate::Conjunction ) { + PredicateItem * child = new PredicateItem( item.firstOperand(), this ); + PredicateItem * child2 = new PredicateItem( item.secondOperand(), this ); + Q_UNUSED( child ) + Q_UNUSED( child2 ) + } + // We're now ready, no need to keep the Solid::Predicate for now +} + +PredicateItem::~PredicateItem() +{ + qDeleteAll( d->children ); + d->children.clear(); + delete d; +} + +PredicateItem * PredicateItem::child( int index ) const +{ + return d->children.at(index); +} + +PredicateItem * PredicateItem::parent() const +{ + return d->parent; +} + +QList& PredicateItem::children() const +{ + return d->children; +} + +Solid::Predicate PredicateItem::predicate() const +{ + Solid::Predicate item; + + switch( itemType ) { + case Solid::Predicate::InterfaceCheck: + item = Solid::Predicate( ifaceType ); + break; + case Solid::Predicate::Conjunction: + item = children().at(0)->predicate() & children().at(1)->predicate(); + break; + case Solid::Predicate::Disjunction: + item = children().at(0)->predicate() | children().at(1)->predicate(); + break; + default: + break; + } + + if( itemType != Solid::Predicate::PropertyCheck ) { + return item; + } + + switch( compOperator ) { + case Solid::Predicate::Equals: + item = Solid::Predicate( ifaceType, property, value ); + break; + case Solid::Predicate::Mask: + item = Solid::Predicate( ifaceType, property, value, Solid::Predicate::Mask ); + break; + default: + break; + } + + return item; +} + +QString PredicateItem::prettyName() const +{ + QString typeName; + QString compName; + + QString deviceName; + switch( itemType ) { + case Solid::Predicate::InterfaceCheck: + deviceName = SolidActionData::instance()->nameFromInterface(ifaceType); + typeName = i18n("The device must be of the type %1", deviceName); + break; + case Solid::Predicate::Disjunction: + typeName = i18n("Any of the contained properties must match"); + break; + case Solid::Predicate::Conjunction: + typeName = i18n("All of the contained properties must match"); + break; + default: + break; + } + + QString prettyProperty = SolidActionData::instance()->propertyName( ifaceType, property ); + switch( compOperator ) { + case Solid::Predicate::Equals: + compName = i18n("The device property %1 must equal %2", prettyProperty, value.toString()); + break; + case Solid::Predicate::Mask: + compName = i18n("The device property %1 must contain %2", prettyProperty, value.toString()); + break; + default: + break; + } + + if( itemType == Solid::Predicate::PropertyCheck ) { + return compName; + } + return typeName; +} + +void PredicateItem::setTypeByInt( int item ) +{ + Solid::Predicate::Type iType = Solid::Predicate::InterfaceCheck; + switch( item ) { + case Solid::Predicate::PropertyCheck: + iType = Solid::Predicate::PropertyCheck; + break; + case Solid::Predicate::Conjunction: + iType = Solid::Predicate::Conjunction; + break; + case Solid::Predicate::Disjunction: + iType = Solid::Predicate::Disjunction; + break; + case Solid::Predicate::InterfaceCheck: + iType = Solid::Predicate::InterfaceCheck; + break; + default: + break; + } + itemType = iType; +} + +void PredicateItem::setComparisonByInt( int item ) +{ + switch( item ) { + case Solid::Predicate::Equals: + compOperator = Solid::Predicate::Equals; + break; + case Solid::Predicate::Mask: + compOperator = Solid::Predicate::Mask; + break; + default: + break; + } +} + +void PredicateItem::updateChildrenStatus() +{ + if( itemType != Solid::Predicate::Disjunction && itemType != Solid::Predicate::Conjunction ) { + qDeleteAll( d->children ); + d->children.clear(); + } else if( d->children.count() == 0 ) { + Solid::Predicate templItem = Solid::Predicate::fromString("IS StorageVolume"); + new PredicateItem( templItem, this ); + new PredicateItem( templItem, this ); + } +} diff --git a/solid-actions-kcm/PredicateItem.h b/solid-actions-kcm/PredicateItem.h new file mode 100644 index 00000000..b1123a44 --- /dev/null +++ b/solid-actions-kcm/PredicateItem.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright 2009 Ben Cooksley * + * * + * 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 PREDICATEITEM_H +#define PREDICATEITEM_H + +#include + +class QString; +template class QList; + +class PredicateItem +{ +public: + PredicateItem( Solid::Predicate item, PredicateItem * itsParent ); + ~PredicateItem(); + + PredicateItem * child( int index ) const; + PredicateItem * parent() const; + QList& children() const; + Solid::Predicate predicate() const; + QString prettyName() const; + void setTypeByInt( int item ); + void setComparisonByInt( int item ); + void updateChildrenStatus(); + + Solid::Predicate::Type itemType; + Solid::DeviceInterface::Type ifaceType; + QString property; + QVariant value; + Solid::Predicate::ComparisonOperator compOperator; + +private: + class Private; + Private *const d; +}; + +Q_DECLARE_METATYPE( PredicateItem * ) + +#endif diff --git a/solid-actions-kcm/PredicateModel.cpp b/solid-actions-kcm/PredicateModel.cpp new file mode 100644 index 00000000..4031276d --- /dev/null +++ b/solid-actions-kcm/PredicateModel.cpp @@ -0,0 +1,176 @@ +/************************************************************************** + * Copyright (C) 2009 Ben Cooksley * + * Copyright (C) 2007 Will Stephenson * + * * + * 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 "PredicateModel.h" + +#include "PredicateItem.h" + +class PredicateModel::Private { +public: + Private() {} + + PredicateItem * rootItem; +}; + +PredicateModel::PredicateModel( PredicateItem * menuRoot, QObject *parent ) + : QAbstractItemModel( parent ) + , d( new Private() ) +{ + d->rootItem = menuRoot; +} + +PredicateModel::~PredicateModel() +{ + delete d; +} + +int PredicateModel::columnCount( const QModelIndex &parent ) const +{ + Q_UNUSED( parent ); + return 1; +} + +int PredicateModel::rowCount( const QModelIndex &parent ) const +{ + PredicateItem * mi; + if ( parent.isValid() ) { + mi = static_cast( parent.internalPointer() ); + } else { + mi = d->rootItem; + } + + return mi->children().count(); +} + +QVariant PredicateModel::data( const QModelIndex &index, int role ) const +{ + PredicateItem * mi = 0; + QVariant theData; + if ( !index.isValid() ) { + return QVariant(); + } + + mi = static_cast( index.internalPointer() ); + switch ( role ) { + case Qt::DisplayRole: + theData.setValue( mi->prettyName() ); + break; + case Qt::UserRole: + theData.setValue( mi ); + break; + default: + break; + } + return theData; +} + +Qt::ItemFlags PredicateModel::flags( const QModelIndex &index ) const +{ + if ( !index.isValid() ) { + return 0; + } + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +QModelIndex PredicateModel::index( int row, int column, const QModelIndex &parent ) const +{ + if ( !hasIndex(row, column, parent) ) { + return QModelIndex(); + } + + PredicateItem *parentItem; + if ( !parent.isValid() ) { + parentItem = d->rootItem; + } else { + parentItem = static_cast( parent.internalPointer() ); + } + + PredicateItem *childItem = parentItem->children().value(row); + if ( childItem ) { + return createIndex( row, column, childItem ); + } else { + return QModelIndex(); + } +} + +QModelIndex PredicateModel::parent( const QModelIndex &index ) const +{ + PredicateItem *childItem = static_cast( index.internalPointer() ); + if( !childItem ) { + return QModelIndex(); + } + + PredicateItem * parent = childItem->parent(); + PredicateItem * grandParent = parent->parent(); + + int childRow = 0; + if( grandParent ) { + childRow = grandParent->children().indexOf( parent ); + } + + if ( parent == d->rootItem ) { + return QModelIndex(); + } + return createIndex( childRow, 0, parent ); +} + +PredicateItem * PredicateModel::rootItem() const +{ + return d->rootItem; +} + +void PredicateModel::setRootPredicate( PredicateItem * item ) +{ + d->rootItem = item; + reset(); +} + +void PredicateModel::itemUpdated( const QModelIndex& item ) +{ + emit dataChanged( item, item ); +} + +void PredicateModel::childrenChanging( const QModelIndex& item, Solid::Predicate::Type oldType ) +{ + PredicateItem * currentItem = static_cast( item.internalPointer() ); + Solid::Predicate::Type newType = currentItem->itemType; + + if( oldType == newType ) { + return; + } + + if( rowCount(item) != 0 && newType != Solid::Predicate::Conjunction && newType != Solid::Predicate::Disjunction ) { + emit beginRemoveRows( item, 0, 1 ); + currentItem->updateChildrenStatus(); + emit endRemoveRows(); + return; + } + + bool hasChildren = (newType == Solid::Predicate::Conjunction || newType == Solid::Predicate::Disjunction); + + if( rowCount(item) == 0 && hasChildren ) { + emit beginInsertRows( item, 0, 1 ); + currentItem->updateChildrenStatus(); + emit endInsertRows(); + } +} + +#include "PredicateModel.moc" diff --git a/solid-actions-kcm/PredicateModel.h b/solid-actions-kcm/PredicateModel.h new file mode 100644 index 00000000..3c6f182c --- /dev/null +++ b/solid-actions-kcm/PredicateModel.h @@ -0,0 +1,56 @@ +/************************************************************************** + * Copyright (C) 2009 Ben Cooksley * + * * + * 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 PREDICATEMODEL_H +#define PREDICATEMODEL_H + +#include + +#include + +class PredicateItem; + +class PredicateModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit PredicateModel( PredicateItem * menuRoot, QObject *parent = 0 ); + ~PredicateModel(); + + QVariant data( const QModelIndex &index, int role ) const; + Qt::ItemFlags flags( const QModelIndex &index ) 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; + + void setRootPredicate( PredicateItem * item ); + void itemUpdated( const QModelIndex& item ); + void childrenChanging( const QModelIndex& item, Solid::Predicate::Type oldType ); + +protected: + PredicateItem * rootItem() const; + +private: + class Private; + Private *const d; +}; + +#endif diff --git a/solid-actions-kcm/SolidActionData.cpp b/solid-actions-kcm/SolidActionData.cpp new file mode 100644 index 00000000..fd1fde4a --- /dev/null +++ b/solid-actions-kcm/SolidActionData.cpp @@ -0,0 +1,192 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 "SolidActionData.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static SolidActionData * actData = 0; + +SolidActionData::SolidActionData(bool includeFiles) +{ + QStringList allPossibleDevices; + int propertyOffset = Solid::DeviceInterface::staticMetaObject.propertyOffset(); + + QList interfaceList = fillInterfaceList(); + foreach( const QMetaObject &interface, interfaceList ) { + QString ifaceName = interface.className(); + ifaceName.remove(0, ifaceName.lastIndexOf(':') + 1); + Solid::DeviceInterface::Type ifaceDev = Solid::DeviceInterface::stringToType( ifaceName ); + QString cleanName = Solid::DeviceInterface::typeDescription( ifaceDev ); + types.insert( ifaceDev, cleanName ); + + QMap deviceValues; + for( int doneProps = propertyOffset; interface.propertyCount() > doneProps; doneProps = doneProps + 1 ) { + QMetaProperty ifaceProp = interface.property(doneProps); + deviceValues.insert( ifaceProp.name(), generateUserString(ifaceProp.name()) ); + } + values.insert( ifaceDev, deviceValues ); + } + + if( includeFiles ) { + // Fill the lists of possible device types / device values + allPossibleDevices = KGlobal::dirs()->findAllResources("data", "solid/devices/"); + // List all the known device actions, then add their name and all values to the appropriate lists + foreach( const QString &desktop, allPossibleDevices ) { + KDesktopFile deviceFile(desktop); + KConfigGroup deviceType = deviceFile.desktopGroup(); // Retrieve the configuration group where the user friendly name is + + QString ifaceName = deviceType.readEntry("X-KDE-Solid-Actions-Type"); + Solid::DeviceInterface::Type ifaceDev = Solid::DeviceInterface::stringToType( ifaceName ); + QString cleanName = Solid::DeviceInterface::typeDescription( ifaceDev ); + + types.insert( ifaceDev, cleanName ); // Read the user friendly name + + QMap deviceValues = values.value( ifaceDev ); + foreach( const QString &text, deviceFile.readActions() ) { // We want every single action + KConfigGroup actionType = deviceFile.actionGroup( text ); + deviceValues.insert( text, actionType.readEntry("Name") ); // Add to the type - actions map + } + values.insert( ifaceDev, deviceValues ); + } + } +} + +QList SolidActionData::propertyList( Solid::DeviceInterface::Type devInterface ) +{ + return values.value( devInterface ).values(); +} + +QList SolidActionData::propertyInternalList( Solid::DeviceInterface::Type devInterface ) +{ + return values.value( devInterface ).keys(); +} + +QString SolidActionData::propertyInternal( Solid::DeviceInterface::Type devInterface, QString property ) +{ + return values.value( devInterface ).key( property ); +} + +QString SolidActionData::propertyName( Solid::DeviceInterface::Type devInterface, QString property ) +{ + return values.value( devInterface ).value( property ); +} + +int SolidActionData::propertyPosition( Solid::DeviceInterface::Type devInterface, QString property ) +{ + return values.value( devInterface ).keys().indexOf( property ); +} + +QList SolidActionData::interfaceList() +{ + return types.values(); +} + +QList SolidActionData::interfaceTypeList() +{ + return types.keys(); +} + +Solid::DeviceInterface::Type SolidActionData::interfaceFromName( const QString& name ) +{ + return types.key( name ); +} + +QString SolidActionData::nameFromInterface( Solid::DeviceInterface::Type devInterface ) +{ + return types.value( devInterface ); +} + +int SolidActionData::interfacePosition( Solid::DeviceInterface::Type devInterface ) +{ + return types.keys().indexOf( devInterface ); +} + +QString SolidActionData::generateUserString( QString className ) +{ + QString finalString; + QRegExp camelCase("([A-Z])"); // Create the split regexp + + finalString = className.remove(0, className.lastIndexOf(':') + 1); // Remove any Class information + finalString = finalString.replace( camelCase, " \\1" ); // Use Camel Casing to add spaces + finalString = KStringHandler::capwords( finalString ); // Captialise everything + return finalString.trimmed(); +} + +SolidActionData * SolidActionData::instance() +{ + if( actData == 0 ) { + actData = new SolidActionData( true ); + } + return actData; +} + +QList SolidActionData::fillInterfaceList() +{ + QList interfaces; + interfaces.append( Solid::AcAdapter::staticMetaObject ); + interfaces.append( Solid::AudioInterface::staticMetaObject ); + interfaces.append( Solid::Battery::staticMetaObject ); + interfaces.append( Solid::Block::staticMetaObject ); + interfaces.append( Solid::Button::staticMetaObject ); + interfaces.append( Solid::Camera::staticMetaObject ); + interfaces.append( Solid::DvbInterface::staticMetaObject ); + interfaces.append( Solid::NetworkInterface::staticMetaObject ); + interfaces.append( Solid::PortableMediaPlayer::staticMetaObject ); + interfaces.append( Solid::Processor::staticMetaObject ); + interfaces.append( Solid::SerialInterface::staticMetaObject ); + interfaces.append( Solid::StorageAccess::staticMetaObject ); + interfaces.append( Solid::StorageDrive::staticMetaObject ); + interfaces.append( Solid::OpticalDrive::staticMetaObject ); + interfaces.append( Solid::StorageVolume::staticMetaObject ); + interfaces.append( Solid::OpticalDisc::staticMetaObject ); + interfaces.append( Solid::Video::staticMetaObject ); + interfaces.append( Solid::SmartCardReader::staticMetaObject ); + return interfaces; +} + +#include "SolidActionData.moc" diff --git a/solid-actions-kcm/SolidActionData.h b/solid-actions-kcm/SolidActionData.h new file mode 100644 index 00000000..27337c62 --- /dev/null +++ b/solid-actions-kcm/SolidActionData.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 SOLIDACTIONDATA_H +#define SOLIDACTIONDATA_H + +#include +#include +#include + +#include + +class SolidActionData : public QObject +{ + Q_OBJECT + +public: + QList propertyList( Solid::DeviceInterface::Type devInterface ); + QList propertyInternalList( Solid::DeviceInterface::Type devInterface ); + QString propertyInternal( Solid::DeviceInterface::Type devInterface, QString property ); + QString propertyName( Solid::DeviceInterface::Type devInterface, QString property ); + int propertyPosition( Solid::DeviceInterface::Type devInterface, QString property ); + + QList interfaceList(); + QList interfaceTypeList(); + Solid::DeviceInterface::Type interfaceFromName( const QString& name ); + QString nameFromInterface( Solid::DeviceInterface::Type devInterface ); + int interfacePosition( Solid::DeviceInterface::Type devInterface ); + + static SolidActionData * instance(); + +private: + SolidActionData(bool includeFiles); + QString generateUserString(QString className); + QList fillInterfaceList(); + + QMap > values; + QMap types; +}; + +#endif diff --git a/solid-actions-kcm/SolidActions.cpp b/solid-actions-kcm/SolidActions.cpp new file mode 100644 index 00000000..e9575a63 --- /dev/null +++ b/solid-actions-kcm/SolidActions.cpp @@ -0,0 +1,231 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 "SolidActions.h" +#include "ActionItem.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +K_PLUGIN_FACTORY( SolidActionsFactory, registerPlugin(); ) +K_EXPORT_PLUGIN( SolidActionsFactory("kcmsolidactions", "kcm_solid_actions") ) + +SolidActions::SolidActions(QWidget* parent, const QVariantList&) + : KCModule(SolidActionsFactory::componentData(), parent) +{ + KAboutData * about = new KAboutData("Device Actions", 0, ki18n("Solid Device Actions Editor"), "1.1", + ki18n("Solid Device Actions Control Panel Module"), + KAboutData::License_GPL, + ki18n("(c) 2009 Solid Device Actions team")); + about->addAuthor(ki18n("Ben Cooksley"), ki18n("Maintainer"), "ben@eclipse.endoftheinternet.org"); + setAboutData(about); + setButtons(KCModule::Help); + + // Prepare main display dialog + actionModel = new ActionModel( this ); + mainUi.setupUi( this ); + mainUi.TvActions->setModel( actionModel ); + mainUi.TvActions->setHeaderHidden( true ); + mainUi.TvActions->setRootIsDecorated( false ); + mainUi.TvActions->setSelectionMode( QAbstractItemView::SingleSelection ); + mainUi.PbAddAction->setGuiItem( KStandardGuiItem::add() ); + mainUi.PbEditAction->setIcon( KIcon("document-edit") ); + + connect( mainUi.PbAddAction, SIGNAL(clicked()), this, SLOT(slotShowAddDialog()) ); + connect( mainUi.PbEditAction, SIGNAL(clicked()), this, SLOT(editAction()) ); + connect( mainUi.PbDeleteAction, SIGNAL(clicked()), this, SLOT(deleteAction()) ); + connect( mainUi.TvActions->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(toggleEditDelete()) ); + connect( mainUi.TvActions, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(editAction()) ); + + // Prepare + connect up with Edit dialog + editUi = new ActionEditor(this); + connect( editUi, SIGNAL(accepted()), this, SLOT(acceptActionChanges()) ); + + // Prepare + connect up add action dialog + addDialog = new KDialog(this); + addUi.setupUi( addDialog->mainWidget() ); + addDialog->setInitialSize( QSize(300, 100) ); // Set a sensible default size + + slotTextChanged( addUi.LeActionName->text() ); + connect( addUi.LeActionName, SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged(QString)) ); + connect( addDialog, SIGNAL(okClicked()), this, SLOT(addAction()) ); +} + +SolidActions::~SolidActions() +{ + delete editUi; + delete actionModel; +} + +void SolidActions::slotShowAddDialog() +{ + addDialog->show(); + addUi.LeActionName->setFocus(); + addUi.LeActionName->clear(); +} + +void SolidActions::slotTextChanged( const QString & text ) +{ + addDialog->enableButtonOk( !text.isEmpty() ); +} + +void SolidActions::load() +{ + fillActionsList(); +} + +void SolidActions::defaults() +{ +} + +void SolidActions::save() +{ +} + +void SolidActions::addAction() +{ + QString enteredName = addUi.LeActionName->text(); + KDesktopFile templateDesktop(KStandardDirs::locate("data", "kcmsolidactions/solid-action-template.desktop")); // Lets get the template + + // Lets get a desktop file + QString internalName = enteredName; // copy the name the user entered -> we will be making mods + internalName.replace(QChar(' '), QChar('-'), Qt::CaseSensitive); // replace spaces with dashes + QString filePath = KStandardDirs::locateLocal("data", 0); // Get the location on disk for "data" + filePath = filePath + "solid/actions/" + internalName + ".desktop"; // Create a file path for new action + + // Fill in an initial template + KDesktopFile * newDesktop = templateDesktop.copyTo(filePath); + newDesktop->actionGroup("open").writeEntry("Name", enteredName); // ditto + delete newDesktop; // Force file to be written + + // Prepare to open the editDialog + fillActionsList(); + QList actionList = actionModel->actionList(); + QModelIndex newAction; + foreach( ActionItem * newItem, actionList ) { // Lets find our new action + if( newItem->desktopMasterPath == filePath ) { + int position = actionList.indexOf( newItem ); + newAction = actionModel->index( position, 0, QModelIndex() ); // Grab it + break; + } + } + + mainUi.TvActions->setCurrentIndex( newAction ); // Set it as currently active + editAction(); // Open the edit dialog +} + +void SolidActions::editAction() +{ + ActionItem * selectedItem = selectedAction(); + if( !selectedItem ) { + return; + } + + // We should error out here if we have to + if( !selectedItem->predicate().isValid() ) { + KMessageBox::error(this, i18n("It appears that the predicate for this action is not valid."), i18n("Error Parsing Device Conditions")); + return; + } + + // Display us! + editUi->setActionToEdit( selectedItem ); + editUi->setWindowIcon( windowIcon() ); + editUi->show(); +} + +void SolidActions::deleteAction() +{ + ActionItem * action = selectedAction(); + if( action->isUserSupplied() ) { // Is the action user supplied? + KIO::NetAccess::del( KUrl(action->desktopMasterPath), this); // Remove the main desktop file then + } + KIO::NetAccess::del( KUrl(action->desktopWritePath), this); // Remove the modified desktop file now + fillActionsList(); // Update the list of actions +} + +ActionItem * SolidActions::selectedAction() +{ + QModelIndex action = mainUi.TvActions->currentIndex(); + ActionItem * actionItem = actionModel->data( action, Qt::UserRole ).value(); + return actionItem; +} + +void SolidActions::fillActionsList() +{ + mainUi.TvActions->selectionModel()->clearSelection(); + actionModel->buildActionList(); + mainUi.TvActions->header()->setResizeMode( 0, QHeaderView::Stretch ); + mainUi.TvActions->header()->setResizeMode( 1, QHeaderView::ResizeToContents ); + toggleEditDelete(); +} + +void SolidActions::acceptActionChanges() +{ + // Re-read the actions list to ensure changes are reflected + KBuildSycocaProgressDialog::rebuildKSycoca(this); + fillActionsList(); +} + +void SolidActions::toggleEditDelete() +{ + bool toggle = true; + + if( !mainUi.TvActions->currentIndex().isValid() ) { // Is an action selected? + mainUi.PbDeleteAction->setText( i18n("No Action Selected") ); // Set a friendly disabled text + mainUi.PbDeleteAction->setIcon( KIcon() ); + toggle = false; + } + + mainUi.PbEditAction->setEnabled(toggle); // Change them to the new state + mainUi.PbDeleteAction->setEnabled(toggle); // Ditto + + if( !toggle ) { + return; + } + + KUrl writeDesktopFile( selectedAction()->desktopWritePath ); // Get the write desktop file + // What functionality do we need to change? + if( selectedAction()->isUserSupplied() ) { + // We are able to directly delete it, enable full delete functionality + mainUi.PbDeleteAction->setGuiItem( KStandardGuiItem::remove() ); + } else if( KIO::NetAccess::exists(writeDesktopFile, KIO::NetAccess::SourceSide, this) ) { // Does the write file exist? + // We are able to revert, lets show it + mainUi.PbDeleteAction->setGuiItem( KStandardGuiItem::discard() ); + } else { + // We cannot do anything then, disable delete functionality + mainUi.PbDeleteAction->setText( i18n("Cannot be deleted") ); + mainUi.PbDeleteAction->setIcon( KIcon() ); + mainUi.PbDeleteAction->setEnabled( false ); + } +} + +#include "SolidActions.moc" diff --git a/solid-actions-kcm/SolidActions.h b/solid-actions-kcm/SolidActions.h new file mode 100644 index 00000000..1eb31cac --- /dev/null +++ b/solid-actions-kcm/SolidActions.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 SOLIDACTIONS_H +#define SOLIDACTIONS_H + +#include + +#include "SolidActions.h" +#include "ActionModel.h" +#include "ActionEditor.h" +#include "ui_AddAction.h" +#include "ui_SolidActions.h" + +class ActionItem; + +class SolidActions: public KCModule +{ + Q_OBJECT + +public: + SolidActions(QWidget* parent, const QVariantList&); + ~SolidActions(); + void load(); + void save(); + void defaults(); + +private slots: + void addAction(); + void editAction(); + void deleteAction(); + ActionItem * selectedAction(); + void fillActionsList(); + void acceptActionChanges(); + void toggleEditDelete(); + void slotTextChanged( const QString& ); + void slotShowAddDialog(); + +private: + Ui::SolidActions mainUi; + ActionModel * actionModel; + ActionEditor * editUi; + Ui::AddAction addUi; + KDialog * addDialog; + void clearActions(); + +}; + +#endif diff --git a/solid-actions-kcm/SolidActions.ui b/solid-actions-kcm/SolidActions.ui new file mode 100644 index 00000000..fd5e4ab9 --- /dev/null +++ b/solid-actions-kcm/SolidActions.ui @@ -0,0 +1,53 @@ + + + SolidActions + + + + 0 + 0 + 553 + 384 + + + + + + + + + + + + Add... + + + + + + + Edit... + + + + + + + Remove + + + + + + + + + + KPushButton + QPushButton +
kpushbutton.h
+
+
+ + +
diff --git a/solid-actions-kcm/device-actions/CMakeLists.txt b/solid-actions-kcm/device-actions/CMakeLists.txt new file mode 100644 index 00000000..a542b120 --- /dev/null +++ b/solid-actions-kcm/device-actions/CMakeLists.txt @@ -0,0 +1,3 @@ +FILE(GLOB desktopfile *.desktop) + +INSTALL( FILES ${desktopfile} DESTINATION ${DATA_INSTALL_DIR}/solid/devices ) diff --git a/solid-actions-kcm/device-actions/solid-device-AcAdapter.desktop b/solid-actions-kcm/device-actions/solid-device-AcAdapter.desktop new file mode 100644 index 00000000..d3a239c3 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-AcAdapter.desktop @@ -0,0 +1,120 @@ +[Desktop Action plugged] +# ctxt: AC adapter plugged in +Name=Plugged +Name[bs]=Utaknut +Name[ca]=Endollat +Name[ca@valencia]=Endollat +Name[cs]=Připojeno +Name[da]=I stikkontakten +Name[de]=Angeschlossen +Name[el]=Σε σύνδεση +Name[en_GB]=Plugged +Name[es]=Enchufado +Name[et]=Ühendatud +Name[eu]=Konektatuta +Name[fi]=Kytketty +Name[fr]=Branché +Name[ga]=Plugáilte +Name[gl]=Enchufado +Name[he]=מחובר +Name[hu]=Bedugva +Name[ia]=Connectite +Name[is]=Í sambandi +Name[kk]=Қосылған +Name[ko]=연결됨 +Name[lt]=Prijungtas +Name[mr]=प्लग केलेले +Name[nb]=Tilkoblet +Name[nds]=Tokoppelt +Name[nl]=Ingeplugd +Name[pa]=ਪਲੱਗ ਲੱਗਾ +Name[pl]=Podłączony +Name[pt]=Ligado +Name[pt_BR]=Conectado +Name[ro]=Atașat +Name[ru]=Подключён +Name[sk]=Pripojené +Name[sl]=Priključeno +Name[sr]=утакнут +Name[sr@ijekavian]=утакнут +Name[sr@ijekavianlatin]=utaknut +Name[sr@latin]=utaknut +Name[sv]=Ansluten +Name[tr]=Fişe takılı +Name[uk]=З’єднано +Name[x-test]=xxPluggedxx +Name[zh_CN]=已插入 +Name[zh_TW]=已插入 + +[Desktop Entry] +Actions=plugged; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=AcAdapter diff --git a/solid-actions-kcm/device-actions/solid-device-AudioInterface.desktop b/solid-actions-kcm/device-actions/solid-device-AudioInterface.desktop new file mode 100644 index 00000000..676ee3ee --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-AudioInterface.desktop @@ -0,0 +1,430 @@ +[Desktop Action deviceType] +Name=Device Type +Name[ar]=نوع الجهاز +Name[ast]=Triba de preséu +Name[bg]=Вид устройство +Name[bn]=ডিভাইস ধরন +Name[bs]=tip uređaja +Name[ca]=Tipus de dispositiu +Name[ca@valencia]=Tipus de dispositiu +Name[cs]=Typ zařízení +Name[csb]=Ôrt ùrządzenia +Name[da]=Enhedstype +Name[de]=Gerätetyp +Name[el]=Τύπος συσκευής +Name[en_GB]=Device Type +Name[eo]=Aparata Tipo +Name[es]=Tipo de dispositivo +Name[et]=Seadme tüüp +Name[eu]=Gailu mota +Name[fa]=نوع دستگاه +Name[fi]=Laitetyyppi +Name[fr]=Type de périphérique +Name[fy]=Apparaat type +Name[ga]=Cineál Gléis +Name[gl]=Tipo do dispositivo +Name[gu]=ઉપકરણ પ્રકાર +Name[he]=סוג ההתקן +Name[hi]=औज़ार प्रकार +Name[hr]=Tip uređaja +Name[hu]=Eszköztípus +Name[ia]=Typo de dispositivo +Name[id]=Tipe Divais +Name[is]=Tegund tækis +Name[ja]=デバイスのタイプ +Name[kk]=Құрылғының түрі +Name[km]=ប្រភេទ​ឧបករណ៍ +Name[kn]=ಸಾಧನದ ಬಗೆ +Name[ko]=장치 종류 +Name[lt]=Įrenginio tipas +Name[lv]=Ierīces tips +Name[mk]=Тип на уред +Name[ml]=ഉപകരണതരം +Name[mr]=साधन प्रकार +Name[nb]=Enhetstype +Name[nds]=Reedschaptyp +Name[nl]=Apparaattype +Name[nn]=Einingstype +Name[pa]=ਜੰਤਰ ਕਿਸਮ +Name[pl]=Typ urządzenia +Name[pt]=Tipo de Dispositivo +Name[pt_BR]=Tipo de dispositivo +Name[ro]=Tip dispozitiv +Name[ru]=Тип устройства +Name[si]=මෙවලම් වර්‍ගය +Name[sk]=Typ zariadenia +Name[sl]=Vrsta naprave +Name[sr]=тип уређаја +Name[sr@ijekavian]=тип уређаја +Name[sr@ijekavianlatin]=tip uređaja +Name[sr@latin]=tip uređaja +Name[sv]=Enhetstyp +Name[tg]=Дастгоҳҳо +Name[th]=ประเภทของอุปกรณ์ +Name[tr]=Aygıt Tipi +Name[ug]=ئۈسكۈنە تىپى +Name[uk]=Тип пристрою +Name[vi]=Kiểu thiết bị +Name[wa]=Sôre d' éndjin +Name[x-test]=xxDevice Typexx +Name[zh_CN]=设备类型 +Name[zh_TW]=裝置類型 + +[Desktop Action driver] +Name=Driver +Name[ar]=المشغل +Name[ast]=Controlador +Name[bg]=Драйвер +Name[bn]=ড্রাইভার +Name[bs]=drajver +Name[ca]=Controlador +Name[ca@valencia]=Controlador +Name[cs]=Ovladač +Name[csb]=Czérownik +Name[da]=Driver +Name[de]=Treiber +Name[el]=Οδηγός +Name[en_GB]=Driver +Name[eo]=Pelilo +Name[es]=Controlador +Name[et]=Draiver +Name[eu]=Gidaria +Name[fa]=گرداننده +Name[fi]=Ajuri +Name[fr]=Pilote +Name[fy]=Stjoerprogramma +Name[ga]=Tiománaí +Name[gl]=Controlador +Name[gu]=ડ્રાઇવર +Name[he]=מנהל התקן +Name[hi]=ड्राईवर +Name[hr]=Pogonski program +Name[hu]=Meghajtó +Name[ia]=Driver +Name[id]=Penggerak +Name[is]=Rekill +Name[ja]=ドライバ +Name[ka]=დრაივერი +Name[kk]=Драйвері +Name[km]=កម្មវិធី​បញ្ជា +Name[kn]=ಚಾಲಕ +Name[ko]=드라이버 +Name[lt]=Tvarkyklė +Name[lv]=Draiveris +Name[mai]=ड्राइवर +Name[mk]=Управувач +Name[ml]=സാരഥി +Name[mr]=ड्राइव्हर +Name[nb]=Driver +Name[nds]=Driever +Name[nl]=Stuurprogramma +Name[nn]=Drivar +Name[pa]=ਡਰਾਇਵਰ +Name[pl]=Sterownik +Name[pt]=Controlador +Name[pt_BR]=Driver +Name[ro]=Driver +Name[ru]=Драйвер +Name[si]=ධාවකය +Name[sk]=Ovládač +Name[sl]=Gonilnik +Name[sr]=драјвер +Name[sr@ijekavian]=драјвер +Name[sr@ijekavianlatin]=drajver +Name[sr@latin]=drajver +Name[sv]=Drivrutin +Name[tg]=Драйвер +Name[th]=ไดรเวอร์ +Name[tr]=Sürücü +Name[ug]=قوزغاتقۇ +Name[uk]=Драйвер +Name[vi]=Trình điều khiển +Name[wa]=Mineu +Name[x-test]=xxDriverxx +Name[zh_CN]=驱动 +Name[zh_TW]=驅動程式 + +[Desktop Action driverHandle] +Name=Driver Handle +Name[ar]=مقبض المشغل +Name[ast]=Controlador de preséu +Name[bg]=Управление на драйвера +Name[bn]=ড্রাইভার হ্যাণ্ডল +Name[bs]=ručka drajvera +Name[ca]=Gestor de controlador +Name[ca@valencia]=Gestor de controlador +Name[cs]=ID ovladače +Name[csb]=Czérownik Handle +Name[da]=Driver-handle +Name[de]=Treiber-Alias +Name[el]=Χειριστήριο οδηγού +Name[en_GB]=Driver Handle +Name[eo]=Pelila tenilo +Name[es]=Controlador de dispositivo +Name[et]=Draiveri pide +Name[eu]=Gidariaren heldulekua +Name[fi]=Ajuritunniste +Name[fr]=Gestionnaire du pilote +Name[fy]=Stjoerprograma regelaar +Name[ga]=Hanla an Tiománaí +Name[gl]=Xestión do controlador +Name[gu]=ડ્રાઇવ સંભાળનાર +Name[he]=ממשק מנהל ההתקן +Name[hi]=औजार हेंडल +Name[hr]=Pogonski program +Name[hu]=Meghajtóazonosító +Name[ia]=Maneator de driver +Name[id]=Penanganan Penggerak +Name[is]=Hald rekils +Name[ja]=ドライバハンドル +Name[kk]=Драйвер өңдеуі +Name[km]=កា​រគ្រប់គ្រង​កម្មវិធី​បញ្ជា +Name[ko]=드라이버 핸들 +Name[lt]=Tvarkyklės rankena +Name[lv]=Draivera rokturis +Name[ml]=ഉപരണത്തിന്റെ പിടി +Name[mr]=ड्राइव्हर हेंडल +Name[nb]=Drivernavn +Name[nds]=Drievergreep +Name[nl]=Stuurprogrammapook +Name[nn]=Drivarnamn +Name[pa]=ਡਰਾਇਵਰ ਹੈਂਡਲ +Name[pl]=Uchwyt sterownika +Name[pt]=Descritor do Controlador +Name[pt_BR]=Manipulador do driver +Name[ro]=Manipulare driver +Name[ru]=Драйверная ссылка на устройство +Name[si]=ධාවක අල්ලුව +Name[sk]=Rukoväť ovládača +Name[sl]=Ročica gonilnika +Name[sr]=ручка драјвера +Name[sr@ijekavian]=ручка драјвера +Name[sr@ijekavianlatin]=ručka drajvera +Name[sr@latin]=ručka drajvera +Name[sv]=Drivrutinreferens +Name[tg]=Плеери DJ-Mixer +Name[th]=การจัดการไดรเวอร์ +Name[tr]=Sürücü Tanıtıcı +Name[ug]=قوزغاتقۇ تۇتقۇسى +Name[uk]=Обробка драйвером +Name[vi]=Xử lý trình điều khiển +Name[wa]=Apougnî mineu +Name[x-test]=xxDriver Handlexx +Name[zh_CN]=驱动处理接口 +Name[zh_TW]=驅動程式處理 + +[Desktop Action name] +Name=Name +Name[ar]=الاسم +Name[ast]=Nome +Name[bg]=Име +Name[bn]=নাম +Name[bs]=ime +Name[ca]=Nom +Name[ca@valencia]=Nom +Name[cs]=Jméno +Name[csb]=Miono +Name[da]=Navn +Name[de]=Name +Name[el]=Όνομα +Name[en_GB]=Name +Name[eo]=Nomo +Name[es]=Nombre +Name[et]=Nimi +Name[eu]=Izena +Name[fa]=نام +Name[fi]=Nimi +Name[fr]=Nom +Name[fy]=Namme +Name[ga]=Ainm +Name[gl]=Nome +Name[gu]=નામ +Name[he]=שם +Name[hi]=नाम +Name[hr]=Ime +Name[hu]=Név +Name[ia]=Nomine +Name[id]=Nama +Name[is]=Heiti +Name[ja]=名前 +Name[ka]=სახელი +Name[kk]=Атауы +Name[km]=ឈ្មោះ +Name[kn]=ಹೆಸರು +Name[ko]=이름 +Name[lt]=Pavadinimas +Name[lv]=Nosaukums +Name[mk]=Име +Name[ml]=പേരു് +Name[mr]=नाव +Name[nb]=Navn +Name[nds]=Naam +Name[nl]=Naam +Name[nn]=Namn +Name[pa]=ਨਾਂ +Name[pl]=Nazwa +Name[pt]=Nome +Name[pt_BR]=Nome +Name[ro]=Denumire +Name[ru]=Имя +Name[si]=නම +Name[sk]=Názov +Name[sl]=Ime +Name[sr]=име +Name[sr@ijekavian]=име +Name[sr@ijekavianlatin]=ime +Name[sr@latin]=ime +Name[sv]=Namn +Name[tg]=Ном +Name[th]=ชื่อ +Name[tr]=İsim +Name[ug]=ئاتى +Name[uk]=Назва +Name[wa]=No +Name[x-test]=xxNamexx +Name[zh_CN]=名称 +Name[zh_TW]=名稱 + +[Desktop Action soundcardType] +Name=Soundcard Type +Name[ar]=نوع بطاقة الصوت +Name[ast]=Triba de tarxeta de soníu +Name[bg]=Вид звукова карта +Name[bn]=সাউণ্ডকার্ড ধরন +Name[bs]=tip zvučne kartice +Name[ca]=Tipus de targeta de so +Name[ca@valencia]=Tipus de targeta de so +Name[cs]=Typ zvukové karty +Name[csb]=Ôrt zwãkòwi kôrtë +Name[da]=Type af lydkort +Name[de]=Soundkartentyp +Name[el]=Τύπος κάρτας ήχου +Name[en_GB]=Soundcard Type +Name[eo]=Tipo de Sonkarto +Name[es]=Tipo de tarjeta de sonido +Name[et]=Helikaardi tüüp +Name[eu]=Soinu-txartel mota +Name[fi]=Äänikortin tyyppi +Name[fr]=Type de carte son +Name[fy]=Lûdskaart type +Name[ga]=Cineál an Chárta Fuaime +Name[gl]=Tipo de tarxeta de son +Name[gu]=સાઉન્ડકાર્ડ પ્રકાર +Name[he]=סוג כרטיס קול +Name[hi]=ध्वनिकार्ड प्रकार +Name[hr]=Tip zvučne kartice +Name[hu]=Hangkártyatípus +Name[ia]=Typo de carta de sono +Name[id]=Tipe Kartu Suara +Name[is]=Tegund hljóðkorts +Name[ja]=サウンドカードのタイプ +Name[kk]=Дыбыс картасының түрі +Name[km]=ប្រភេទ​កាត​សំឡេង +Name[kn]=ಧ್ವನಿಕಾರ್ಡಿನ ಬಗೆ +Name[ko]=사운드카드 종류 +Name[lt]=Garso plokštės tipas +Name[lv]=Skaņas kartes tips +Name[mai]=साउंडकार्ड प्रकार +Name[mk]=Тип на аудиокартичка +Name[ml]=സൌണ്ട് കാര്‍ഡിന്റെ തരം +Name[mr]=साउंडकार्ड प्रकार +Name[nb]=Lydkort-type +Name[nds]=Klangkoort-Typ +Name[nl]=Type geluidskaart +Name[nn]=Lydkorttype +Name[pa]=ਸਾਊਂਡ ਕਾਰਡ ਕਿਸਮ +Name[pl]=Typ karty dźwiękowej +Name[pt]=Tipo de Placa de Som +Name[pt_BR]=Tipo de placa de som +Name[ro]=Tipul plăcii de sunet +Name[ru]=Тип звуковой карты +Name[si]=ශබ්ද කාඩ්පත් වර්ගය +Name[sk]=Typ zvukovej karty +Name[sl]=Vrsta zvočne kartice +Name[sr]=тип звучне картице +Name[sr@ijekavian]=тип звучне картице +Name[sr@ijekavianlatin]=tip zvučne kartice +Name[sr@latin]=tip zvučne kartice +Name[sv]=Typ av ljudkort +Name[tg]=Намуди корти овозӣ +Name[th]=ประเภทของแผงวงจรเสียง +Name[tr]=Ses Kartı Tipi +Name[ug]=ئۈن كارتا تىپى +Name[uk]=Тип звукової картки +Name[wa]=Sôre di cwåte son +Name[x-test]=xxSoundcard Typexx +Name[zh_CN]=声卡类型 +Name[zh_TW]=音效卡類型 + +[Desktop Entry] +Actions=deviceType;driver;driverHandle;name;soundcardType; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=AudioInterface diff --git a/solid-actions-kcm/device-actions/solid-device-Battery.desktop b/solid-actions-kcm/device-actions/solid-device-Battery.desktop new file mode 100644 index 00000000..1ad9c880 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-Battery.desktop @@ -0,0 +1,407 @@ +[Desktop Action chargePercent] +Name=Charge Percent +Name[ar]=نسبة الشحن +Name[ast]=Porcentaxe de carga +Name[bg]=Зареждане (%) +Name[bn]=শতকরা চার্জ +Name[bs]=popunjenost +Name[ca]=Percentatge de càrrega +Name[ca@valencia]=Percentatge de càrrega +Name[cs]=Procento nabití +Name[da]=Ladningsprocent +Name[de]=Ladestand +Name[el]=Ποσοστό φόρτισης +Name[en_GB]=Charge Percent +Name[eo]=Procento de Ŝargo +Name[es]=Porcentaje de carga +Name[et]=Täituvuse protsent +Name[eu]=Kargaren ehunekoa +Name[fi]=Latauksen tila prosenteissa +Name[fr]=Pourcentage de charge +Name[fy]=Batterijlading prosint +Name[ga]=Céatadán Luchtaithe +Name[gl]=Mudar a porcentaxe +Name[gu]=ચાર્જ ટકા +Name[he]=אחוז טעינה +Name[hi]=चार्ज प्रतिशत +Name[hr]=Postotak preostalog kapaciteta +Name[hu]=Feltöltöttségi százalék +Name[ia]=Percentage de cargamento +Name[id]=Persentase Pengisian +Name[is]=Prósentuhlutfall hleðslu +Name[it]=Percentuale di carica +Name[ja]=充電率 +Name[kk]=Толу пайызы +Name[km]=ភាគរយបញ្ចូលថ្ម +Name[kn]=ಚಾರ್ಜಿನ ಪ್ರತಿಶತ +Name[ko]=충전률 +Name[lt]=Įkrovimas procentais +Name[lv]=Uzlādes procenti +Name[mai]=चार्ज प्रतिशत +Name[mk]=Процент на полнеж +Name[ml]=ചാര്‍ജ്ജ് ശതമാനം +Name[mr]=चार्ज टक्केवारी +Name[nb]=Prosent lading +Name[nds]=Oplaadperzent +Name[nl]=Ladingspercentage +Name[nn]=Oppladingsprosent +Name[pa]=ਚਾਰਜ ਫੀਸਦੀ +Name[pl]=Poziom naładowania +Name[pt]=Percentagem de Carga +Name[pt_BR]=Porcentagem de carga +Name[ro]=Procentaj încărcare +Name[ru]=Уровень заряда +Name[si]=ආරෝපිත ප්‍රමාණය +Name[sk]=Percento nabitia +Name[sl]=Odstotek napolnjenosti +Name[sr]=попуњеност +Name[sr@ijekavian]=попуњеност +Name[sr@ijekavianlatin]=popunjenost +Name[sr@latin]=popunjenost +Name[sv]=Laddningsprocent +Name[tg]=Фоизи барқгирӣ +Name[th]=ร้อยละของประจุไฟ +Name[tr]=Şarj Yüzdesi +Name[ug]=پىرسەنتىنى ئۆزگەرت +Name[uk]=Рівень заряду +Name[vi]=Phần trăm sạc +Name[wa]=Åcintaedje di tcherdjaedje +Name[x-test]=xxCharge Percentxx +Name[zh_CN]=充电百分比 +Name[zh_TW]=充電百分比 + +[Desktop Action chargeState] +Name=Charge State +Name[ar]=حالة الشحن +Name[ast]=Estáu de carga +Name[bg]=Състояние на зареждането +Name[bn]=চার্জের অবস্থা +Name[bs]=stanje punjenja +Name[ca]=Estat de la càrrega +Name[ca@valencia]=Estat de la càrrega +Name[cs]=Stav nabití +Name[da]=Ladningstilstand +Name[de]=Ladestatus +Name[el]=Κατάσταση φόρτισης +Name[en_GB]=Charge State +Name[eo]=Stato de ŝarĝo +Name[es]=Estado de carga +Name[et]=Täituvuse olek +Name[eu]=Kargaren egoera +Name[fi]=Latauksen tila +Name[fr]=État de charge +Name[fy]=Batterijlading tastân +Name[ga]=Staid Luchtaithe +Name[gl]=Mudar o estado +Name[gu]=ચાર્જ સ્થિતિ +Name[he]=מצב טעינה +Name[hi]=चार्ज स्तिथि +Name[hr]=Stanje preostalog kapaciteta +Name[hu]=Feltöltöttségi állapot +Name[ia]=Stato de cargamento +Name[id]=Tingkat Pengisian +Name[is]=Staða hleðslu +Name[it]=Stato di carica +Name[ja]=充電の状態 +Name[kk]=Толтыру күй-жайы +Name[km]=ស្ថានភាព​បញ្ចូល​ថ្ម +Name[kn]=ಚಾರ್ಜಿನ ಸ್ಥಿತಿ +Name[ko]=충전 상태 +Name[lt]=Įkrovimo būklė +Name[lv]=Uzlādes stāvoklis +Name[mai]=चार्ज स्थिति +Name[mk]=Состојба на полнеж +Name[ml]=ചാര്‍ജ്ജ് സ്ഥിതി +Name[mr]=चार्ज स्थिती +Name[nb]=Ladingstilstand +Name[nds]=Oplaadtostand +Name[nl]=Ladingsstatus +Name[nn]=Oppladingsstatus +Name[pa]=ਚਾਰਜ ਹਾਲਤ +Name[pl]=Stan ładowania +Name[pt]=Estado da Carga +Name[pt_BR]=Estado da carga +Name[ro]=Starea încărcării +Name[ru]=Состояние заряда +Name[si]=ආරෝපණ තත්වය +Name[sk]=Stav nabitia +Name[sl]=Stanje napolnjenosti +Name[sr]=стање пуњења +Name[sr@ijekavian]=стање пуњења +Name[sr@ijekavianlatin]=stanje punjenja +Name[sr@latin]=stanje punjenja +Name[sv]=Laddningstillstånd +Name[tg]=Ҳолати қувва +Name[th]=สถานะการประจุไฟ +Name[tr]=Şarj Durumu +Name[ug]=ھالىتىنى ئۆزگەرت +Name[uk]=Стан зарядженості +Name[vi]=Trạng thái sạc +Name[wa]=Estat do tcherdjaedje +Name[x-test]=xxCharge Statexx +Name[zh_CN]=充电状态 +Name[zh_TW]=充電狀態 + +[Desktop Action plugged] +# ctxt: battery plugged in +Name=Plugged +Name[bs]=Utaknut +Name[ca]=Endollada +Name[ca@valencia]=Endollada +Name[cs]=Připojeno +Name[da]=I stikkontakten +Name[de]=Angeschlossen +Name[el]=Σε σύνδεση +Name[en_GB]=Plugged +Name[es]=Enchufado +Name[et]=Ühendatud +Name[eu]=Konektatuta +Name[fi]=Kytketty +Name[fr]=Branchée +Name[ga]=Plugáilte +Name[gl]=Enchufada +Name[he]=מחובר +Name[hu]=Bedugva +Name[ia]=Connectite +Name[is]=Í sambandi +Name[it]=Connessa +Name[kk]=Қосылған +Name[ko]=연결됨 +Name[lt]=Prijungtas +Name[mr]=प्लग केलेले +Name[nb]=Tilkoblet +Name[nds]=Tokoppelt +Name[nl]=Ingeplugd +Name[pa]=ਪਲੱਗ ਲੱਗਾ +Name[pl]=Podłączona +Name[pt]=Ligada +Name[pt_BR]=Conectada +Name[ro]=Atașat +Name[ru]=Подключён +Name[sk]=Pripojené +Name[sl]=Priključena +Name[sr]=утакнута +Name[sr@ijekavian]=утакнута +Name[sr@ijekavianlatin]=utaknuta +Name[sr@latin]=utaknuta +Name[sv]=Anslutet +Name[tr]=Fişe takılı +Name[uk]=З’єднано +Name[x-test]=xxPluggedxx +Name[zh_CN]=已插入 +Name[zh_TW]=已插入 + +[Desktop Action rechargeable] +Name=Rechargeable +Name[ar]=قابلة للشحن +Name[ast]=Recargable +Name[bg]=Презаредима +Name[bn]=রিচার্জযোগ্য +Name[bs]=punjiva +Name[ca]=Recarregable +Name[ca@valencia]=Recarregable +Name[cs]=Nabíjecí +Name[da]=Genopladeligt +Name[de]=Wiederaufladbar +Name[el]=Επαναφορτιζόμενη +Name[en_GB]=Rechargeable +Name[eo]=Reŝarĝebla +Name[es]=Recargable +Name[et]=Laetav +Name[eu]=Kargatzekoa +Name[fi]=Uudelleenladattavissa +Name[fr]=Rechargeable +Name[fy]=Oplaadbaar +Name[ga]=In-Athluchtaithe +Name[gl]=Recargábel +Name[he]=ניתן לטעינה חוזרת +Name[hi]=चार्जयोग्य +Name[hr]=Punjiva +Name[hu]=Újratölthető +Name[ia]=Recargabile +Name[id]=Dapat Diisi Ulang +Name[is]=Endurhlaðanlegt +Name[it]=Ricaricabile +Name[ja]=再充電可能 +Name[kk]=Қайта толтырылатын +Name[km]=អាច​បញ្ចូល​ថ្ម​បាន +Name[kn]=ಮರು ಚಾರ್ಜ್ ಮಾಡಬಹುದಾದ +Name[ko]=충전 가능 +Name[lt]=Iš naujo pakraunamas +Name[lv]=Lādējams +Name[mai]=फेर चार्ज करैयोग्य +Name[ml]=വീണ്ടും ചാര്‍ജ്ജ് ചെയ്യാവുന്നത് +Name[mr]=परत चार्ज करता येण्याजोगे +Name[nb]=Oppladbar +Name[nds]=Wedderlaadbor +Name[nl]=Oplaadbaar +Name[nn]=Oppladbart +Name[pa]=ਮੁੜ-ਚਾਰਜ ਯੋਗ +Name[pl]=Do wielokrotnego ładowania +Name[pt]=Recarregável +Name[pt_BR]=Recarregável +Name[ro]=Reîncărcabil +Name[ru]=Перезаряжаемая +Name[si]=නැවත ආරෝපනය කල හැකි +Name[sk]=Dobíjateľná +Name[sl]=Znova napolnljiva +Name[sr]=пуњива +Name[sr@ijekavian]=пуњива +Name[sr@ijekavianlatin]=punjiva +Name[sr@latin]=punjiva +Name[sv]=Uppladdningsbart +Name[th]=สามารถประจุไฟใหม่ได้ +Name[tr]=Yeniden şarj edilebilir +Name[ug]=توكلاشچان +Name[uk]=Перезарядка +Name[wa]=Ritcherdjåve +Name[x-test]=xxRechargeablexx +Name[zh_CN]=可充电 +Name[zh_TW]=可重新充電 + +[Desktop Action type] +Name=Type +Name[ar]=النوع +Name[ast]=Triba +Name[bg]=Вид +Name[bn]=ধরন +Name[bs]=tip +Name[ca]=Tipus +Name[ca@valencia]=Tipus +Name[cs]=Typ +Name[csb]=Ôrt +Name[da]=Type +Name[de]=Typ +Name[el]=Τύπος +Name[en_GB]=Type +Name[eo]=Tipo +Name[es]=Tipo +Name[et]=Tüüp +Name[eu]=Mota +Name[fa]=نوع +Name[fi]=Tyyppi +Name[fr]=Type +Name[fy]=Type +Name[ga]=Cineál +Name[gl]=Tipo +Name[gu]=પ્રકાર +Name[he]=סוג +Name[hi]=प्रकार +Name[hr]=Tip +Name[hu]=Típus +Name[ia]=Typo +Name[id]=Tipe +Name[is]=Tegund +Name[it]=Tipo +Name[ja]=タイプ +Name[ka]=ტიპი +Name[kk]=Түрі +Name[km]=ប្រភេទ +Name[kn]=ಬಗೆ +Name[ko]=종류 +Name[lt]=Tipas +Name[lv]=Tips +Name[mai]=प्रकार +Name[mk]=Тип +Name[ml]=തരം +Name[mr]=प्रकार +Name[nb]=Type +Name[nds]=Typ +Name[nl]=Type +Name[nn]=Type +Name[pa]=ਕਿਸਮ +Name[pl]=Typ +Name[pt]=Tipo +Name[pt_BR]=Tipo +Name[ro]=Tip +Name[ru]=Тип +Name[si]=වර්‍ගය +Name[sk]=Typ +Name[sl]=Vrsta +Name[sr]=тип +Name[sr@ijekavian]=тип +Name[sr@ijekavianlatin]=tip +Name[sr@latin]=tip +Name[sv]=Typ +Name[tg]=Намуд +Name[th]=ประเภท +Name[tr]=Tip +Name[ug]=تىپى +Name[uk]=Тип +Name[wa]=Sôre +Name[x-test]=xxTypexx +Name[zh_CN]=类型 +Name[zh_TW]=類型 + +[Desktop Entry] +Actions=chargePercent;chargeState;plugged;rechargeable;type; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=Battery diff --git a/solid-actions-kcm/device-actions/solid-device-Block.desktop b/solid-actions-kcm/device-actions/solid-device-Block.desktop new file mode 100644 index 00000000..bbaff8d5 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-Block.desktop @@ -0,0 +1,286 @@ +[Desktop Action device] +Name=Device +Name[ar]=الجهاز +Name[ast]=Preseos +Name[bg]=Устройство +Name[bn]=ডিভাইস +Name[bs]=uređaj +Name[ca]=Dispositiu +Name[ca@valencia]=Dispositiu +Name[cs]=Zařízení +Name[csb]=Ùrządzenié +Name[da]=Enhed +Name[de]=Gerät +Name[el]=Συσκευή +Name[en_GB]=Device +Name[eo]=Aparato +Name[es]=Dispositivo +Name[et]=Seade +Name[eu]=Gailua +Name[fa]=دستگاه +Name[fi]=Laite +Name[fr]=Périphérique +Name[fy]=Apparaat +Name[ga]=Gléas +Name[gl]=Dispositivo +Name[gu]=ઉપકરણ +Name[he]=התקן +Name[hi]=औज़ार +Name[hr]=Uređaj +Name[hu]=Eszköz +Name[ia]=Dispositivo +Name[id]=Divais +Name[is]=Tæki +Name[it]=Dispositivo +Name[ja]=デバイス +Name[ka]=მოწყობილობა +Name[kk]=Құрылғысы +Name[km]=ឧបករណ៍ +Name[kn]=ಸಾಧನ +Name[ko]=장치 +Name[lt]=Įrenginys +Name[lv]=Ierīce +Name[mk]=Уред +Name[ml]=ഉപകരണം +Name[mr]=साधन +Name[nb]=Enhet +Name[nds]=Reedschap +Name[nl]=Apparaat +Name[nn]=Eining +Name[pa]=ਜੰਤਰ +Name[pl]=Urządzenie +Name[pt]=Dispositivo +Name[pt_BR]=Dispositivo +Name[ro]=Dispozitiv +Name[ru]=Устройство +Name[si]=මෙවලම +Name[sk]=Zariadenie +Name[sl]=Naprava +Name[sr]=уређај +Name[sr@ijekavian]=уређај +Name[sr@ijekavianlatin]=uređaj +Name[sr@latin]=uređaj +Name[sv]=Enhet +Name[tg]=Дастгоҳ +Name[th]=อุปกรณ์ +Name[tr]=Aygıt +Name[ug]=ئۈسكۈنە +Name[uk]=Пристрій +Name[vi]=Thiết bị +Name[wa]=Éndjin +Name[x-test]=xxDevicexx +Name[zh_CN]=设备 +Name[zh_TW]=裝置 + +[Desktop Action major] +Name=Major +Name[ar]=عام +Name[ast]=Mayor +Name[bn]=মেজর +Name[bs]=Glavnii +Name[ca]=Major +Name[ca@valencia]=Major +Name[cs]=Velké +Name[csb]=Wësok +Name[da]=Stor +Name[de]=Hohe Kennzahl +Name[el]=Κύριο +Name[en_GB]=Major +Name[eo]=ĉefa +Name[es]=Mayor +Name[et]=Põhiversioon +Name[eu]=Handiagoa +Name[fi]=Ensisijainen +Name[fr]=Majeur +Name[fy]=Grut +Name[ga]=Príomh +Name[gl]=Maior +Name[gu]=મુખ્ય +Name[he]=ראשי +Name[hi]=प्रमुख +Name[hr]=Glavni +Name[hu]=Főszám +Name[ia]=Major +Name[id]=Mayor +Name[is]=Mest +Name[it]=Maggiore +Name[ja]=メジャー +Name[kk]=Негізгі +Name[km]=ធំ +Name[kn]=ಪ್ರಮುಖ +Name[ko]=주 +Name[lt]=Pagrindinis +Name[lv]=Galvenais +Name[mk]=Главен +Name[ml]=മുഖ്യം +Name[mr]=मोठा +Name[nb]=Hoved +Name[nds]=Hooch +Name[nl]=Hoofd +Name[nn]=Hovud +Name[pa]=ਮੇਜ਼ਰ +Name[pl]=Główny numer urządzenia +Name[pt]=Nº Maior +Name[pt_BR]=Maior +Name[ro]=Major +Name[ru]=Старший номер (major) +Name[si]=ප්‍රධාන +Name[sk]=Major +Name[sl]=Velika +Name[sr]=велики +Name[sr@ijekavian]=велики +Name[sr@ijekavianlatin]=veliki +Name[sr@latin]=veliki +Name[sv]=Huvudnummer +Name[tg]=Moria +Name[th]=หมายเลขหลัก +Name[tr]=Büyük +Name[ug]=ئاساسىي +Name[uk]=Головний +Name[wa]=Grand +Name[x-test]=xxMajorxx +Name[zh_CN]=主号 +Name[zh_TW]=主要 + +[Desktop Action minor] +Name=Minor +Name[ar]=فرعي +Name[ast]=Menor +Name[bn]=মাইনর +Name[bs]=Sporedni +Name[ca]=Menor +Name[ca@valencia]=Menor +Name[cs]=Malé +Name[csb]=Niskò +Name[da]=Mindre +Name[de]=Niedrige Kennzahl +Name[el]=Δευτερεύον +Name[en_GB]=Minor +Name[eo]=Malĉefa +Name[es]=Menor +Name[et]=Alamversioon +Name[eu]=Txikiagoa +Name[fi]=Toissijainen +Name[fr]=Mineur +Name[fy]=Lyts +Name[ga]=Mion +Name[gl]=Menor +Name[gu]=ગૌણ +Name[he]=משני +Name[hi]=अमुख्य +Name[hr]=Sporedni +Name[hu]=Alszám +Name[ia]=Minor +Name[id]=Minor +Name[is]=Minnst +Name[it]=Minore +Name[ja]=マイナー +Name[kk]=Қосалқы +Name[km]=តូច +Name[kn]=ಅಪ್ರಮುಖ +Name[ko]=부 +Name[lt]=Mažesnis +Name[lv]=Mazais +Name[mk]=Спореден +Name[ml]=നിസാരം +Name[mr]=लहान +Name[nb]=Under +Name[nds]=Siet +Name[nl]=Onder +Name[nn]=Del +Name[pa]=ਮਾਈਨਰ +Name[pl]=Podrzędny numer urządzenia +Name[pt]=Nº Menor +Name[pt_BR]=Menor +Name[ro]=Minor +Name[ru]=Младший номер (minor) +Name[si]=සුළු +Name[sk]=Minor +Name[sl]=Mala +Name[sr]=мали +Name[sr@ijekavian]=мали +Name[sr@ijekavianlatin]=mali +Name[sr@latin]=mali +Name[sv]=Delnummer +Name[tg]=Moria +Name[th]=หมายเลขรอง +Name[tr]=Küçük +Name[ug]=قوشۇمچە +Name[uk]=Додатковий +Name[wa]=Pitit +Name[x-test]=xxMinorxx +Name[zh_CN]=从号 +Name[zh_TW]=次要 + +[Desktop Entry] +Actions=device;major;minor; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=Block diff --git a/solid-actions-kcm/device-actions/solid-device-Button.desktop b/solid-actions-kcm/device-actions/solid-device-Button.desktop new file mode 100644 index 00000000..9cfef04f --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-Button.desktop @@ -0,0 +1,281 @@ +[Desktop Action hasState] +Name=Has State +Name[ar]=يملك حالة +Name[ast]=Tien estáu +Name[bs]=sa stanjem +Name[ca]=Té estat +Name[ca@valencia]=Té estat +Name[cs]=Má stav +Name[csb]=Mô stón +Name[da]=Har tilstanden +Name[de]=Hat den Status +Name[el]=Έχει κατάσταση +Name[en_GB]=Has State +Name[eo]=Havas Staton +Name[es]=Tiene estado +Name[et]=Olekuga +Name[eu]=Egoera dauka +Name[fi]=On tilassa +Name[fy]=Hat tastân +Name[ga]=Staid Aige +Name[gl]=Ten o estado +Name[gu]=આમાં સ્થિતિ છે +Name[he]=בעל מצב +Name[hi]=स्तिथि है +Name[hr]=Ima li stanje +Name[hu]=Van állapota +Name[ia]=Stato Has +Name[id]=Memiliki Tingkat +Name[is]=Er með stöðu +Name[ja]=状態あり +Name[kk]=Күй-жайы +Name[km]=មាន​ស្ថានភាព +Name[kn]=ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿದೆ +Name[ko]=상태 여부 +Name[lt]=Būklė +Name[lv]=Piemīt stāvoklis +Name[mai]=स्थिति राखैत अछि +Name[mk]=Има состојба +Name[ml]=സ്ഥിതിയുണ്ട് +Name[mr]=स्थिती आहे +Name[nb]=Har tilstand +Name[nds]=Hett en Status +Name[nl]=Heeft status +Name[nn]=Har status +Name[pa]=ਹਾਲਤ ਹੈ +Name[pl]=Ma stan +Name[pt]=Tem o Estado +Name[pt_BR]=Possui estado +Name[ro]=Are stare +Name[ru]=Переключатель +Name[si]=තත්වයක් ඇත +Name[sk]=Má stav +Name[sl]=Ima stanje +Name[sr]=има стање +Name[sr@ijekavian]=има стање +Name[sr@ijekavianlatin]=ima stanje +Name[sr@latin]=ima stanje +Name[sv]=Har tillstånd +Name[tg]=Дорои ҳолат +Name[th]=มีค่าสถานะ +Name[tr]=Duruma Sahip +Name[ug]=ھالەتلىك +Name[uk]=Має стан +Name[vi]=Có trạng thái +Name[wa]=A l' estat +Name[x-test]=xxHas Statexx +Name[zh_CN]=有状态 +Name[zh_TW]=有狀態 + +[Desktop Action stateValue] +Name=State Value +Name[ar]=قيمة الحالة +Name[ast]=Valor del estáu +Name[bs]=vrijednost stanja +Name[ca]=Valor de l'estat +Name[ca@valencia]=Valor de l'estat +Name[cs]=Hodnota stavu +Name[da]=Tilstandsværdi +Name[de]=Status-Wert +Name[el]=Τιμή κατάστασης +Name[en_GB]=State Value +Name[eo]=Valuo de Stato +Name[es]=Valor del estado +Name[et]=Oleku väärtus +Name[eu]=Egoeraren balioa +Name[fi]=Tilan arvo +Name[fy]=Tastân wearde +Name[ga]=Luach na Staide +Name[gl]=Valor do estado +Name[gu]=સ્થિતિ કિંમત +Name[he]=ערך מצב +Name[hi]=स्थिति मान +Name[hr]=Vrijednost stanja +Name[hu]=Állapotérték +Name[ia]=Valor de stato +Name[id]=Nilai Tingkat +Name[is]=Stöðugildi +Name[ja]=状態の値 +Name[kk]=Мөлшері +Name[km]=តម្លៃ​ស្ថានភាព +Name[kn]=ಸ್ಥಿತಿ ಮೌಲ್ಯ +Name[ko]=상태 값 +Name[lt]=Būklės vertė +Name[lv]=Stāvokļa vērtība +Name[mk]=Вредност на состојба +Name[ml]=അവസ്ഥാവില +Name[mr]=स्थिती मूल्य +Name[nb]=Tilstandsverdi +Name[nds]=Statusweert +Name[nl]=Statuswaarde +Name[nn]=Statusverdi +Name[pa]=ਹਾਲਤ ਮੁੱਲ +Name[pl]=Wartość stanu +Name[pt]=Valor do Estado +Name[pt_BR]=Valor do estado +Name[ro]=Valoarea stării +Name[ru]=Значение состояния +Name[si]=තත්ව අගය +Name[sk]=Hodnota stavu +Name[sl]=Vrednost stanja +Name[sr]=вредност стања +Name[sr@ijekavian]=вредност стања +Name[sr@ijekavianlatin]=vrednost stanja +Name[sr@latin]=vrednost stanja +Name[sv]=Tillståndsvärde +Name[tg]=Бозиҳои стратегӣ +Name[th]=ค่าของสถานะ +Name[tr]=Durum Değeri +Name[ug]=ھالەت قىممىتى +Name[uk]=Значення стану +Name[wa]=Valixhance d' estat +Name[x-test]=xxState Valuexx +Name[zh_CN]=状态值 +Name[zh_TW]=狀態值 + +[Desktop Action type] +Name=Type +Name[ar]=النوع +Name[ast]=Triba +Name[bg]=Вид +Name[bn]=ধরন +Name[bs]=tip +Name[ca]=Tipus +Name[ca@valencia]=Tipus +Name[cs]=Typ +Name[csb]=Ôrt +Name[da]=Type +Name[de]=Typ +Name[el]=Τύπος +Name[en_GB]=Type +Name[eo]=Tipo +Name[es]=Tipo +Name[et]=Tüüp +Name[eu]=Mota +Name[fa]=نوع +Name[fi]=Tyyppi +Name[fr]=Type +Name[fy]=Type +Name[ga]=Cineál +Name[gl]=Tipo +Name[gu]=પ્રકાર +Name[he]=סוג +Name[hi]=प्रकार +Name[hr]=Tip +Name[hu]=Típus +Name[ia]=Typo +Name[id]=Tipe +Name[is]=Tegund +Name[it]=Tipo +Name[ja]=タイプ +Name[ka]=ტიპი +Name[kk]=Түрі +Name[km]=ប្រភេទ +Name[kn]=ಬಗೆ +Name[ko]=종류 +Name[lt]=Tipas +Name[lv]=Tips +Name[mai]=प्रकार +Name[mk]=Тип +Name[ml]=തരം +Name[mr]=प्रकार +Name[nb]=Type +Name[nds]=Typ +Name[nl]=Type +Name[nn]=Type +Name[pa]=ਕਿਸਮ +Name[pl]=Typ +Name[pt]=Tipo +Name[pt_BR]=Tipo +Name[ro]=Tip +Name[ru]=Тип +Name[si]=වර්‍ගය +Name[sk]=Typ +Name[sl]=Vrsta +Name[sr]=тип +Name[sr@ijekavian]=тип +Name[sr@ijekavianlatin]=tip +Name[sr@latin]=tip +Name[sv]=Typ +Name[tg]=Намуд +Name[th]=ประเภท +Name[tr]=Tip +Name[ug]=تىپى +Name[uk]=Тип +Name[wa]=Sôre +Name[x-test]=xxTypexx +Name[zh_CN]=类型 +Name[zh_TW]=類型 + +[Desktop Entry] +Actions=hasState;stateValue;type; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=Button diff --git a/solid-actions-kcm/device-actions/solid-device-Camera.desktop b/solid-actions-kcm/device-actions/solid-device-Camera.desktop new file mode 100644 index 00000000..021aa940 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-Camera.desktop @@ -0,0 +1,215 @@ +[Desktop Action supportedDrivers] +Name=Supported Drivers +Name[ar]=المشغلات المدعومة +Name[ast]=Controladores sofitaos +Name[bg]=Поддържани драйвери +Name[bn]=সমর্থিত ড্রাইভার +Name[bs]=podržani drajveri +Name[ca]=Controladors acceptats +Name[ca@valencia]=Controladors acceptats +Name[cs]=Podporované ovladače +Name[csb]=Wspiéróné czérowniczi +Name[da]=Understøttede drivere +Name[de]=Unterstützte Treiber +Name[el]=Υποστηριζόμενοι οδηγοί +Name[en_GB]=Supported Drivers +Name[eo]=subtenataj Peliloj +Name[es]=Dispositivos soportados +Name[et]=Toetatud draiverid +Name[eu]=Onartutzen diren gidariak +Name[fi]=Tuetut ajurit +Name[fr]=Pilotes pris en charge +Name[fy]=Stipe stjoerprogramma's +Name[ga]=Tiománaithe a dTacaítear Leo +Name[gl]=Controladores soportados +Name[gu]=આધારિત ડ્રાઇવરો +Name[he]=מנהלי התקנים נתמכים +Name[hi]=समर्थित ड्राईवर +Name[hr]=Podržani pisači +Name[hu]=Támogatott meghajtók +Name[ia]=Drivers supportate +Name[id]=Penggerak Didukung +Name[is]=Studdir reklar +Name[it]=Driver supportati +Name[ja]=サポートされているドライバ +Name[kk]=Қолдайтын драйверлері +Name[km]=កម្មវិធី​បញ្ជា​ដែលបានគាំទ្រ +Name[kn]=ಬೆಂಬಲಿತ ಚಾಲಕಗಳು +Name[ko]=지원하는 드라이버 +Name[lt]=Palaikomos tvarkyklės +Name[lv]=Atbalstītie draiveri +Name[mai]=समर्थित ड्राइवर +Name[mk]=Поддржани управувачи +Name[ml]=പിന്തുണയുള്ള സാരഥികള്‍ +Name[mr]=समर्थीत ड्राइव्हर्स +Name[nb]=Støttede drivere +Name[nds]=Ünnerstütt Drievers +Name[nl]=Ondersteunde stuurprogramma's +Name[nn]=Støtta drivarar +Name[pa]=ਸਹਾਇਕ ਡਰਾਇਵਰ +Name[pl]=Obsługiwane sterowniki +Name[pt]=Controladores Suportados +Name[pt_BR]=Drivers suportados +Name[ro]=Drivere susținute +Name[ru]=Поддерживаемые драйверы +Name[si]=සහාය දක්වන ධාවක +Name[sk]=Podporované ovládače +Name[sl]=Podprti gonilniki +Name[sr]=подржани драјвери +Name[sr@ijekavian]=подржани драјвери +Name[sr@ijekavianlatin]=podržani drajveri +Name[sr@latin]=podržani drajveri +Name[sv]=Drivrutiner som stöds +Name[tg]=Дастгоҳҳои мувофиқ +Name[th]=ไดรเวอร์ที่รองรับ +Name[tr]=Desteklenen Sürücüler +Name[ug]=قوللايدىغان قوزغاتقۇلار +Name[uk]=Підтримувані драйвери +Name[wa]=Mineus sopoirtés +Name[x-test]=xxSupported Driversxx +Name[zh_CN]=支持的驱动 +Name[zh_TW]=支援的驅動程式 + +[Desktop Action supportedProtocols] +Name=Supported Protocols +Name[ar]=البروتوكولات المدعومة +Name[ast]=Protocolos sofitaos +Name[bg]=Поддържани протоколи +Name[bn]=সমর্থিত প্রোটোকল +Name[bs]=podržani protokoli +Name[ca]=Protocols acceptats +Name[ca@valencia]=Protocols acceptats +Name[cs]=Podporované protokoly +Name[csb]=Wspiéróné protokòłë +Name[da]=Understøttede protokoller +Name[de]=Unterstützte Protokolle +Name[el]=Υποστηριζόμενα πρωτόκολλα +Name[en_GB]=Supported Protocols +Name[eo]=Subtenitaj Protokoloj +Name[es]=Protocolos soportados +Name[et]=Toetatud protokollid +Name[eu]=Onartzen diren protokoloak +Name[fi]=Tuetut yhteyskäytännöt +Name[fr]=Protocoles pris en charge +Name[fy]=Stipe protokollen +Name[ga]=Prótacail a dTacaítear Leo +Name[gl]=Protocolos soportados +Name[gu]=આધારિત પ્રોટોકોલ્સ +Name[he]=פרוטוקולים נתמכים +Name[hi]=समर्थित प्रोटोकॉल +Name[hr]=Podržani Protokoli +Name[hu]=Támogatott protokollok +Name[ia]=Protocollos supportate +Name[id]=Protokol Didukung +Name[is]=Studdar samskiptareglur +Name[it]=Protocolli supportati +Name[ja]=サポートされているプロトコル +Name[kk]=Қолдайтын протоколдары +Name[km]=ពិពីការ​ដែលបានគាំទ្រ +Name[kn]=ಬೆಂಬಲಿತ ಪ್ರಕ್ರಮಗಳು (ಪ್ರೋಟೋಕಾಲ್) +Name[ko]=지원하는 프로토콜 +Name[lt]=Palaikomi protokolai +Name[lv]=Atbalstītie protokoli +Name[mk]=Поддржани протоколи +Name[ml]=പിന്തുണയ്ക്കുന്ന സമ്പ്രദായങ്ങള്‍ +Name[mr]=समर्थीत शिष्टाचार +Name[nb]=Støttede protokoller +Name[nds]=Ünnerstütt Protokollen +Name[nl]=Ondersteunde protocollen +Name[nn]=Støtta protokollar +Name[pa]=ਸਹਾਇਕ ਪਰੋਟੋਕਾਲ +Name[pl]=Obsługiwane protokoły +Name[pt]=Protocolos Suportados +Name[pt_BR]=Protocolos suportados +Name[ro]=Protocoale susținute +Name[ru]=Поддерживаемые протоколы +Name[si]=සහාය දක්වන ක්‍රියා පටිපාටි +Name[sk]=Podporované protokoly +Name[sl]=Podprti protokoli +Name[sr]=подржани протоколи +Name[sr@ijekavian]=подржани протоколи +Name[sr@ijekavianlatin]=podržani protokoli +Name[sr@latin]=podržani protokoli +Name[sv]=Protokoll som stöds +Name[tg]=Протоколҳо +Name[th]=โพรโทคอลที่รองรับ +Name[tr]=Desteklenen Protokoller +Name[ug]=قوللايدىغان كېلىشىملەر +Name[uk]=Підтримувані протоколи +Name[wa]=Protocoles sopoirtés +Name[x-test]=xxSupported Protocolsxx +Name[zh_CN]=支持的协议 +Name[zh_TW]=支援的協定 + +[Desktop Entry] +Actions=supportedDrivers;supportedProtocols; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=Camera diff --git a/solid-actions-kcm/device-actions/solid-device-DvbInterface.desktop b/solid-actions-kcm/device-actions/solid-device-DvbInterface.desktop new file mode 100644 index 00000000..70d6e3f1 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-DvbInterface.desktop @@ -0,0 +1,360 @@ +[Desktop Action device] +Name=Device +Name[ar]=الجهاز +Name[ast]=Preseos +Name[bg]=Устройство +Name[bn]=ডিভাইস +Name[bs]=uređaj +Name[ca]=Dispositiu +Name[ca@valencia]=Dispositiu +Name[cs]=Zařízení +Name[csb]=Ùrządzenié +Name[da]=Enhed +Name[de]=Gerät +Name[el]=Συσκευή +Name[en_GB]=Device +Name[eo]=Aparato +Name[es]=Dispositivo +Name[et]=Seade +Name[eu]=Gailua +Name[fa]=دستگاه +Name[fi]=Laite +Name[fr]=Périphérique +Name[fy]=Apparaat +Name[ga]=Gléas +Name[gl]=Dispositivo +Name[gu]=ઉપકરણ +Name[he]=התקן +Name[hi]=औज़ार +Name[hr]=Uređaj +Name[hu]=Eszköz +Name[ia]=Dispositivo +Name[id]=Divais +Name[is]=Tæki +Name[it]=Dispositivo +Name[ja]=デバイス +Name[ka]=მოწყობილობა +Name[kk]=Құрылғысы +Name[km]=ឧបករណ៍ +Name[kn]=ಸಾಧನ +Name[ko]=장치 +Name[lt]=Įrenginys +Name[lv]=Ierīce +Name[mk]=Уред +Name[ml]=ഉപകരണം +Name[mr]=साधन +Name[nb]=Enhet +Name[nds]=Reedschap +Name[nl]=Apparaat +Name[nn]=Eining +Name[pa]=ਜੰਤਰ +Name[pl]=Urządzenie +Name[pt]=Dispositivo +Name[pt_BR]=Dispositivo +Name[ro]=Dispozitiv +Name[ru]=Устройство +Name[si]=මෙවලම +Name[sk]=Zariadenie +Name[sl]=Naprava +Name[sr]=уређај +Name[sr@ijekavian]=уређај +Name[sr@ijekavianlatin]=uređaj +Name[sr@latin]=uređaj +Name[sv]=Enhet +Name[tg]=Дастгоҳ +Name[th]=อุปกรณ์ +Name[tr]=Aygıt +Name[ug]=ئۈسكۈنە +Name[uk]=Пристрій +Name[vi]=Thiết bị +Name[wa]=Éndjin +Name[x-test]=xxDevicexx +Name[zh_CN]=设备 +Name[zh_TW]=裝置 + +[Desktop Action deviceAdapter] +Name=Device Adapter +Name[ar]=محول الجهاز +Name[ast]=Adautador de preséu +Name[bg]=Адаптор на устройството +Name[bn]=ডিভাইস অ্যাডাপ্টার +Name[bs]=adapter uređaja +Name[ca]=Adaptador de dispositius +Name[ca@valencia]=Adaptador de dispositius +Name[cs]=Adaptér zařízení +Name[csb]=Adapter ùrządzenia +Name[da]=Enhedsadapter +Name[de]=Geräteadapter +Name[el]=Προσαρμογέας συσκευής +Name[en_GB]=Device Adapter +Name[eo]=Aparata adaptilo +Name[es]=Adaptador de dispositivo +Name[et]=Seadme adapter +Name[eu]=Gailu-egokigailua +Name[fi]=Laitesovitin +Name[fr]=Adaptateur de périphériques +Name[fy]=Apparaat adapter +Name[ga]=Cuibheoir Gléis +Name[gl]=Adaptador de dispositivos +Name[gu]=ઉપકરણ એડપ્ટર +Name[he]=מתאם התקן +Name[hi]=उपकरण एडेपटर +Name[hr]=Prilagodnik uređaja +Name[hu]=Eszközadapter +Name[ia]=Adaptator del dispositivo +Name[id]=Adaptor Divais +Name[is]=Tengi tækis +Name[ja]=デバイスのアダプタ +Name[kk]=Құрылғы адаптері +Name[km]=អាដាប់ទ័រ​ឧបករណ៍​ +Name[kn]=ಸಾಧನದ ಅಡಾಪ್ಟರ್ +Name[ko]=장치 어댑터 +Name[lt]=Įrenginio adapteris +Name[lv]=Ierīces adapteris +Name[mk]=Адаптер за уред +Name[ml]=ഉപകരണത്തിന്റെ അഡാപ്റ്റര്‍ +Name[mr]=साधन अडॅप्टर +Name[nb]=Enhetsadapter +Name[nds]=Reedschap +Name[nl]=Apparaat-adapter +Name[nn]=Straumtilkopling for eining +Name[pa]=ਜੰਤਰ ਅਡਪੈਟਰ +Name[pl]=Adapter urządzenia +Name[pt]=Adaptador de Dispositivo +Name[pt_BR]=Adaptador de dispositivo +Name[ro]=Adaptor dispozitiv +Name[ru]=Адаптер устройства +Name[si]=මෙවලම් අනුහුරුව +Name[sk]=Adaptér zariadenia +Name[sl]=Vmesnik naprave +Name[sr]=адаптер уређаја +Name[sr@ijekavian]=адаптер уређаја +Name[sr@ijekavianlatin]=adapter uređaja +Name[sr@latin]=adapter uređaja +Name[sv]=Enhetsadapter +Name[tg]=Извещение о новых устройствах +Name[th]=อะแดปเตอร์อุปกรณ์ +Name[tr]=Aygıt Bağdaştırıcısı +Name[ug]=ئۈسكۈنە ماسلاشتۇرغۇچ +Name[uk]=Адаптер пристрою +Name[vi]=Bộ tiếp hợp cho thiết bị +Name[wa]=Adaptateu d' éndjin +Name[x-test]=xxDevice Adapterxx +Name[zh_CN]=设备适配器 +Name[zh_TW]=裝置接合器 + +[Desktop Action deviceIndex] +Name=Device Index +Name[ar]=فهرس الجهاز +Name[ast]=Índiz de preséu +Name[bg]=Индекс на устройство +Name[bn]=ডিভাইস ইন্ডেক্স +Name[bs]=indeks uređaja +Name[ca]=Índex de dispositius +Name[ca@valencia]=Índex de dispositius +Name[cs]=Index zařízení +Name[csb]=Indeks ùrządzeniów +Name[da]=Enhedsindeks +Name[de]=Geräteindex +Name[el]=Δείκτης συσκευής +Name[en_GB]=Device Index +Name[eo]=Indekso de Aparatoj +Name[es]=Índice de dispositivo +Name[et]=Seadme indeks +Name[eu]=Gailu-indizea +Name[fi]=Laiteindeksi +Name[fr]=Index du périphérique +Name[fy]=Apparat yndeks +Name[ga]=Innéacs Gléis +Name[gl]=Índice de dispositivos +Name[gu]=ઉપકરણ અનુક્રમ +Name[he]=אינדקס התקן +Name[hi]=उपकरण क्रमांक +Name[hr]=Indeks uređaja +Name[hu]=Eszközindex +Name[ia]=Indice del dispositivo +Name[id]=Indeks Divais +Name[is]=Yfirlit tækis +Name[ja]=デバイスのインデックス +Name[kk]=Құрылғы индексі +Name[km]=លិបិក្រម​ឧបករណ៍ +Name[kn]=ಸಾಧನದ ಸೂಚಿ (ಇಂಡೆಕ್ಸ್) +Name[ko]=장치 인덱스 +Name[lt]=Įrenginio indeksas +Name[lv]=Ierīces indekss +Name[mk]=Индекс на уреди +Name[ml]=ഉപകരണത്തിന്റെ സൂചിക +Name[mr]=साधन अनुक्रमणिका +Name[nb]=Enhetsindeks +Name[nds]=Reedschap-Index +Name[nl]=Apparaatindex +Name[nn]=Indeks for eining +Name[pa]=ਜੰਤਰ ਇੰਡੈਕਸ +Name[pl]=Indeks urządzenia +Name[pt]=Índice do Dispositivo +Name[pt_BR]=Índice do dispositivo +Name[ro]=Index dispozitiv +Name[ru]=Номер устройства +Name[si]=මෙවලම් සූචිය +Name[sk]=Index zariadenia +Name[sl]=Indeks naprave +Name[sr]=индекс уређаја +Name[sr@ijekavian]=индекс уређаја +Name[sr@ijekavianlatin]=indeks uređaja +Name[sr@latin]=indeks uređaja +Name[sv]=Enhetsindex +Name[tg]=Индекси роҳнамо +Name[th]=ดัชนีอุปกรณ์ +Name[tr]=Aygıt Dizini +Name[ug]=ئۈسكۈنە ئىندىكىسى +Name[uk]=Індекс пристрою +Name[vi]=Chỉ mục thiết bị +Name[wa]=Indecse di l' éndjin +Name[x-test]=xxDevice Indexxx +Name[zh_CN]=设备索引 +Name[zh_TW]=裝置索引 + +[Desktop Action deviceType] +Name=Device Type +Name[ar]=نوع الجهاز +Name[ast]=Triba de preséu +Name[bg]=Вид устройство +Name[bn]=ডিভাইস ধরন +Name[bs]=tip uređaja +Name[ca]=Tipus de dispositiu +Name[ca@valencia]=Tipus de dispositiu +Name[cs]=Typ zařízení +Name[csb]=Ôrt ùrządzenia +Name[da]=Enhedstype +Name[de]=Gerätetyp +Name[el]=Τύπος συσκευής +Name[en_GB]=Device Type +Name[eo]=Aparata Tipo +Name[es]=Tipo de dispositivo +Name[et]=Seadme tüüp +Name[eu]=Gailu mota +Name[fa]=نوع دستگاه +Name[fi]=Laitetyyppi +Name[fr]=Type de périphérique +Name[fy]=Apparaat type +Name[ga]=Cineál Gléis +Name[gl]=Tipo do dispositivo +Name[gu]=ઉપકરણ પ્રકાર +Name[he]=סוג ההתקן +Name[hi]=औज़ार प्रकार +Name[hr]=Tip uređaja +Name[hu]=Eszköztípus +Name[ia]=Typo de dispositivo +Name[id]=Tipe Divais +Name[is]=Tegund tækis +Name[ja]=デバイスのタイプ +Name[kk]=Құрылғының түрі +Name[km]=ប្រភេទ​ឧបករណ៍ +Name[kn]=ಸಾಧನದ ಬಗೆ +Name[ko]=장치 종류 +Name[lt]=Įrenginio tipas +Name[lv]=Ierīces tips +Name[mk]=Тип на уред +Name[ml]=ഉപകരണതരം +Name[mr]=साधन प्रकार +Name[nb]=Enhetstype +Name[nds]=Reedschaptyp +Name[nl]=Apparaattype +Name[nn]=Einingstype +Name[pa]=ਜੰਤਰ ਕਿਸਮ +Name[pl]=Typ urządzenia +Name[pt]=Tipo de Dispositivo +Name[pt_BR]=Tipo de dispositivo +Name[ro]=Tip dispozitiv +Name[ru]=Тип устройства +Name[si]=මෙවලම් වර්‍ගය +Name[sk]=Typ zariadenia +Name[sl]=Vrsta naprave +Name[sr]=тип уређаја +Name[sr@ijekavian]=тип уређаја +Name[sr@ijekavianlatin]=tip uređaja +Name[sr@latin]=tip uređaja +Name[sv]=Enhetstyp +Name[tg]=Дастгоҳҳо +Name[th]=ประเภทของอุปกรณ์ +Name[tr]=Aygıt Tipi +Name[ug]=ئۈسكۈنە تىپى +Name[uk]=Тип пристрою +Name[vi]=Kiểu thiết bị +Name[wa]=Sôre d' éndjin +Name[x-test]=xxDevice Typexx +Name[zh_CN]=设备类型 +Name[zh_TW]=裝置類型 + +[Desktop Entry] +Actions=device;deviceAdapter;deviceIndex;deviceType; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=DvbInterface diff --git a/solid-actions-kcm/device-actions/solid-device-NetworkInterface.desktop b/solid-actions-kcm/device-actions/solid-device-NetworkInterface.desktop new file mode 100644 index 00000000..7cdf9fd8 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-NetworkInterface.desktop @@ -0,0 +1,360 @@ +[Desktop Action hwAddress] +Name=Hw Address +Name[ar]=عنوان العتاد +Name[ast]=Direición HW +Name[bg]=Хардуерен адрес +Name[bn]=Hw অ্যাড্রেস +Name[bs]=hv. adresa +Name[ca]=Adreça maquinari +Name[ca@valencia]=Adreça maquinari +Name[cs]=Hw adresa +Name[csb]=Adresa Hw +Name[da]=HW-adresse +Name[de]=HW-Adresse +Name[el]=Διεύθυνση Hw +Name[en_GB]=Hw Address +Name[eo]=Hw Adreso +Name[es]=Dirección HW +Name[et]=Riistvara-aadress +Name[eu]=HW helbidea +Name[fi]=Rautaosoite +Name[fr]=Adresse matérielle +Name[fy]=Hw adres +Name[ga]=Seoladh Crua-Earraí +Name[gl]=Enderezo hardware +Name[gu]=હાર્ડવેર સરનામું +Name[he]=כתובת חומרה +Name[hi]=हार्डवेयर पता +Name[hr]=Hardverska adresa +Name[hu]=Hardveres cím +Name[ia]=Adresse Hw +Name[id]=Alamat Peranti Keras +Name[is]=HW vistfang +Name[ja]=HW アドレス +Name[kk]=Жабд. адресі +Name[km]=អាសយដ្ឋាន Hw +Name[kn]=Hw ವಿಳಾಸ +Name[ko]=하드웨어 주소 +Name[lt]=Aparatinis adresas +Name[lv]=Hw adrese +Name[mai]=Hw पता +Name[mk]=Адреса на хардвер +Name[ml]=എച്ച്ഡബ്ല്യൂ വിലാസം +Name[mr]=Hw पत्ता +Name[nb]=Hw-adresse +Name[nds]=Hardware-Adress +Name[nl]=HW-adres +Name[nn]=Maskinvareadresse +Name[pa]=Hw ਐਡਰੈੱਸ +Name[pl]=Adres sprzętowy +Name[pt]=Endereço de H/W +Name[pt_BR]=Endereço de hardware +Name[ro]=Adresă fizică +Name[ru]=Аппаратный адрес +Name[si]=Hw ලිපිනය +Name[sk]=Hw adresa +Name[sl]=Strojni naslov +Name[sr]=хв. адреса +Name[sr@ijekavian]=хв. адреса +Name[sr@ijekavianlatin]=hv. adresa +Name[sr@latin]=hv. adresa +Name[sv]=Hårdvaruadress +Name[tg]=Суроғаи Hw +Name[th]=ที่อยู่ฮาร์ดแวร์ +Name[tr]=Donanım Adresi +Name[ug]=قاتتىق دېتال ئادرېسى +Name[uk]=Апар. адреса +Name[vi]=Địa chỉ phần cứng +Name[wa]=Adresse Hw +Name[x-test]=xxHw Addressxx +Name[zh_CN]=硬件地址 +Name[zh_TW]=硬體位址 + +[Desktop Action ifaceName] +Name=Iface Name +Name[ar]=اسم الواجهة +Name[ast]=Nome d'interface +Name[bg]=Име на интерфейс +Name[bn]=Iface-এর নাম +Name[bs]=ime sučelja +Name[ca]=Nom d'interfície +Name[ca@valencia]=Nom d'interfície +Name[cs]=Název rozhraní +Name[csb]=Miono Iface +Name[da]=Navn på grænseflade +Name[de]=Schnittstellen-Name +Name[el]=Όνομα Iface +Name[en_GB]=Iface Name +Name[eo]=Iface Nomo +Name[es]=Nombre de interfaz +Name[et]=Liidese nimi +Name[eu]=Interfaze-izena +Name[fi]=Verkkoliitynnän nimi +Name[fr]=Nom « Iface » +Name[fy]=Iface namme +Name[ga]=Ainm an Chomhéadain +Name[gl]=Nome da interface +Name[gu]=ઇન્ટરફેસ નામ +Name[he]=שם Iface +Name[hi]=Iface नाम +Name[hr]=Ime sučelja +Name[hu]=Felületnév +Name[ia]=Nomine Iface +Name[id]=Nama Antarmuka +Name[is]=IFACE nafn +Name[ja]=インターフェース名 +Name[kk]=И-фейс атауы +Name[km]=ឈ្មោះ Iface +Name[kn]=Iface ಹೆಸರು +Name[ko]=인터페이스 이름 +Name[lt]=Sąsajos pavadinimas +Name[lv]=Sask. nosaukums +Name[mk]=Име на интерфејс +Name[ml]=ഐഫേസിന്റെ പേരു് +Name[mr]=Iface नाव +Name[nb]=G.snitt-navn +Name[nds]=Koppelsteed-Naam +Name[nl]=Iface-naam +Name[nn]=Grensesnittnamn +Name[pa]=Iface ਨਾਂ +Name[pl]=Nazwa interfejsu +Name[pt]=Nome da Interface +Name[pt_BR]=Nome da interface +Name[ro]=Denumire interfață +Name[ru]=Название интерфейса +Name[si]=Iface නාමය +Name[sk]=Názov rozhrania +Name[sl]=Ime vmesnika +Name[sr]=име сучеља +Name[sr@ijekavian]=име сучеља +Name[sr@ijekavianlatin]=ime sučelja +Name[sr@latin]=ime sučelja +Name[sv]=Gränssnittsnamn +Name[tg]=Бозиҳои Dice +Name[th]=ชื่อส่วนติดต่อ +Name[tr]=Iface Adı +Name[ug]=ئارايۈز ئاتى +Name[uk]=Назва Iface +Name[vi]=Tên Iface +Name[wa]=No Iface +Name[x-test]=xxIface Namexx +Name[zh_CN]=接口名称 +Name[zh_TW]=介面名稱 + +[Desktop Action macAddress] +Name=Mac Address +Name[ar]=عنوان Mac +Name[ast]=Direición MAC +Name[bg]=МАС-адрес +Name[bn]=ম্যাক অ্যাড্রেস +Name[bs]=MAC adresa +Name[ca]=Adreça MAC +Name[ca@valencia]=Adreça MAC +Name[cs]=Mac adresa +Name[csb]=Adresa Mac +Name[da]=MAC-adresse +Name[de]=MAC-Adresse +Name[el]=Διεύθυνση MAC +Name[en_GB]=Mac Address +Name[eo]=Maŝinadreso +Name[es]=Dirección MAC +Name[et]=MAC-aadress +Name[eu]=MAC helbidea +Name[fi]=Mac-osoite +Name[fr]=Adresse « Mac » +Name[fy]=Mac adres +Name[ga]=Seoladh MAC +Name[gl]=Enderezo MAC +Name[gu]=મેક સરનામું +Name[he]=כתובת MAC +Name[hi]=मेक पता +Name[hr]=MAC adresa +Name[hu]=MAC cím +Name[ia]=Adresse Mac +Name[id]=Alamat Mac +Name[is]=MAC vistfang +Name[ja]=Mac アドレス +Name[ka]=MAC მისამართი +Name[kk]=Mac адресі +Name[km]=អាសយដ្ឋាន Mac +Name[kn]=ಮ್ಯಾಕ್ ವಿಳಾಸ +Name[ko]=MAC 주소 +Name[lt]=Mac adresas +Name[lv]=Mac adrese +Name[mai]=Mac पता +Name[mk]=Mac-адреса +Name[ml]=മാക് വിലാസം +Name[mr]=Mac पत्ता +Name[nb]=MAC-adresse +Name[nds]=Mac-Adress +Name[nl]=MAC-adres +Name[nn]=MAC-adresse +Name[pa]=ਮੈਕ ਐਡਰੈੱਸ +Name[pl]=Adres Mac +Name[pt]=Endereço MAC +Name[pt_BR]=Endereço MAC +Name[ro]=Adresă MAC +Name[ru]=MAC-адрес +Name[si]=මැක් ලිපිනය +Name[sk]=Mac adresa +Name[sl]=Naslov MAC +Name[sr]=МАЦ адреса +Name[sr@ijekavian]=МАЦ адреса +Name[sr@ijekavianlatin]=MAC adresa +Name[sr@latin]=MAC adresa +Name[sv]=MAC-adress +Name[tg]=Суроғаи Mac +Name[th]=ค่าที่อยู่ Mac +Name[tr]=Mac Adresi +Name[ug]=MAC ئادرېس +Name[uk]=Mac-адреса +Name[vi]=Địa chỉ Mac +Name[wa]=Adresse Mac +Name[x-test]=xxMac Addressxx +Name[zh_CN]=Mac 地址 +Name[zh_TW]=Mac 位址 + +[Desktop Action wireless] +Name=Wireless +Name[ar]=لاسلكي +Name[ast]=Inalámbricu +Name[bg]=Безжична мрежа +Name[bn]=ওয়্যারলেস +Name[bs]=bežična +Name[ca]=Xarxa sense fils +Name[ca@valencia]=Xarxa sense fils +Name[cs]=Bezdrátové +Name[csb]=Bezkablowé +Name[da]=Trådløst +Name[de]=Drahtlos +Name[el]=Ασύρματο +Name[en_GB]=Wireless +Name[eo]=Sendrata reto +Name[es]=Inalámbrico +Name[et]=Juhtmeta +Name[eu]=Haririk gabea +Name[fa]=بی‌سیم +Name[fi]=Langaton +Name[fr]=Sans fil +Name[fy]=Triedleas +Name[ga]=Gan Sreang +Name[gl]=Sen fíos +Name[gu]=વાયરલેસ +Name[he]=אלחוטי +Name[hi]=बेतार +Name[hr]=Bežićna +Name[hu]=Vezeték nélküli +Name[ia]=Wireless (Sin Cablos) +Name[id]=Nirkabel +Name[is]=Þráðlaust +Name[ja]=ワイヤレス +Name[ka]=უმავთულო კავშირი +Name[kk]=Сымсыз +Name[km]=ឥតខ្សែ +Name[kn]=ವೈರ್ಲೆಸ್ +Name[ko]=무선 +Name[lt]=Bevielis +Name[lv]=Bezvadu +Name[mk]=Бежичен +Name[ml]=വയര്‍ലസ്സ് +Name[mr]=वायरलेस +Name[nb]=Trådløs +Name[nds]=Funk +Name[nl]=Draadloos +Name[nn]=Trådlaust +Name[pa]=ਬੇਤਾਰ +Name[pl]=Bezprzewodowy +Name[pt]=Sem-Fios +Name[pt_BR]=Sem fio +Name[ro]=Fără fir +Name[ru]=Беспроводная сеть +Name[si]=රැහැන් රහිත +Name[sk]=Bezdrôtové +Name[sl]=Brezžično +Name[sr]=бежична +Name[sr@ijekavian]=бежична +Name[sr@ijekavianlatin]=bežična +Name[sr@latin]=bežična +Name[sv]=Trådlöst +Name[tg]=Бесимӣ +Name[th]=อุปกรณ์ไร้สาย +Name[tr]=Kablosuz +Name[ug]=سىمسىز +Name[uk]=Бездротове +Name[wa]=Sins fyi +Name[x-test]=xxWirelessxx +Name[zh_CN]=无线 +Name[zh_TW]=無線 + +[Desktop Entry] +Actions=hwAddress;ifaceName;macAddress;wireless; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=NetworkInterface diff --git a/solid-actions-kcm/device-actions/solid-device-OpticalDisc.desktop b/solid-actions-kcm/device-actions/solid-device-OpticalDisc.desktop new file mode 100644 index 00000000..11f3b059 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-OpticalDisc.desktop @@ -0,0 +1,941 @@ +[Desktop Action appendable] +Name=Appendable +Name[ar]=قابل للإضافة +Name[ast]=Pue amestase +Name[bg]=Незавършен диск +Name[bn]=যোগ করা যাবে +Name[bs]=dopisiv +Name[ca]=Afegible +Name[ca@valencia]=Afegible +Name[cs]=Připojitelný +Name[csb]=Dodôwny +Name[da]=Data kan tilføjes +Name[de]=Anhängbar +Name[el]=Προσαρτήσιμο +Name[en_GB]=Appendable +Name[eo]=Aldonebla +Name[es]=Se puede añadir +Name[et]=Lisatav +Name[eu]=Gehi dakiokeena +Name[fi]=Liitettävä +Name[fr]=Opposable +Name[fy]=Kin taheakje +Name[ga]=In-iarcheangailte +Name[gl]=Poden engadírselle datos +Name[gu]=ઉમેરી શકાય તેવું +Name[he]=ניתן להוסיף עליו +Name[hi]=संल्गनक +Name[hr]=Može se dodavati +Name[hu]=Hozzáfűzhető +Name[ia]=On pote adjunger +Name[id]=Dapat Ditambahkan +Name[is]=Hægt að bæta við +Name[it]=Aggiungibile +Name[ja]=追記可能 +Name[kk]=Жалғасулы +Name[km]=អាច​បន្ថែមខាង​ចុង​បាន +Name[kn]=ಸೇರಿಸಬಹುದಾದ +Name[ko]=추가 가능 +Name[lt]=Pridedamas +Name[lv]=Papildināms +Name[ml]=വീണ്ടും എഴുതാവുന്നതു് +Name[mr]=जोडता येण्याजोगे +Name[nb]=Har plass igjen +Name[nds]=Nich afslaten +Name[nl]=Uitbreidbaar +Name[nn]=Tilleggbar +Name[pa]=ਜੋੜਨਯੋਗ +Name[pl]=Z możliwością dopisywania +Name[pt]=Adicionável +Name[pt_BR]=Anexável +Name[ro]=Completabil +Name[ru]=Дозаписываемый +Name[si]=ඇමිණිය හැකි +Name[sk]=Doplniteľné +Name[sl]=Dodajanje je mogoče +Name[sr]=дописив +Name[sr@ijekavian]=дописив +Name[sr@ijekavianlatin]=dopisiv +Name[sr@latin]=dopisiv +Name[sv]=Tilläggbar +Name[tg]=Намуди зоҳирӣ +Name[th]=สามารถเขียนเพิ่มเติมได้ +Name[tr]=Eklenebilir +Name[ug]=قوشۇشقا بولىدۇ +Name[uk]=Додавання +Name[vi]=Có thể ghi thêm +Name[wa]=Adjoutåve +Name[x-test]=xxAppendablexx +Name[zh_CN]=可追加 +Name[zh_TW]=可附加 + +[Desktop Action availableContent] +Name=Available Content +Name[ar]=المحتويات المتوفرة +Name[ast]=Conteníu disponible +Name[bg]=Налично съдържание +Name[bn]=পাওয়া যাচ্ছে +Name[bs]=dostupan sadržaj +Name[ca]=Contingut disponible +Name[ca@valencia]=Contingut disponible +Name[cs]=Dostupný obsah +Name[csb]=Przëstãpnô zamkłosc +Name[da]=Tilgængeligt indhold +Name[de]=Verfügbarer Inhalt +Name[el]=Διαθέσιμο περιεχόμενο +Name[en_GB]=Available Content +Name[eo]=Havebla Enhavo +Name[es]=Contenido disponible +Name[et]=Sisuga +Name[eu]=Eduki eskuragarria +Name[fi]=Käytettävissä oleva sisältö +Name[fr]=Contenu disponible +Name[fy]=Beskikbere ynhâld +Name[ga]=Ábhar Le Fáil +Name[gl]=Contido dispoñíbel +Name[gu]=પ્રાપ્ત વિગત +Name[he]=תוכן זמין +Name[hi]=उपलब्ध विषयवस्तु +Name[hr]=Dostupni sadržaj +Name[hu]=Elérhető tartalom +Name[ia]=Contento disponibile +Name[id]=Isi Tersedia +Name[is]=Aðgengilegt innihald +Name[it]=Contenuto disponibile +Name[ja]=利用可能なコンテンツ +Name[kk]=Бар мазмұны +Name[km]=មាតិកា​ដែល​អាច​ប្រើបាន +Name[kn]=ಲಭ್ಯವಿರುವ ವಿಷಯ +Name[ko]=사용 가능한 내용 +Name[lt]=Turimas turinys +Name[lv]=Pieejams saturs +Name[mai]=उपलब्ध सामग्री +Name[mk]=Достапна содржина +Name[ml]=ലഭ്യമായ ള്ളടക്കങ്ങള്‍ +Name[mr]=उपलब्ध मजकूर +Name[nb]=Tilgjengelig innhold +Name[nds]=Verföögbor Inholt +Name[nl]=Beschikbare inhoud +Name[nn]=Tilgjengeleg innhald +Name[pa]=ਉਪਲੱਬਧ ਸਮੱਗਰੀ +Name[pl]=Dostępna treść +Name[pt]=Conteúdo Disponível +Name[pt_BR]=Conteúdo disponível +Name[ro]=Conținut disponibil +Name[ru]=Содержимое +Name[si]=පවතින අන්තර්ගතය +Name[sk]=Dostupný obsah +Name[sl]=Razpoložljiva vsebina +Name[sr]=доступан садржај +Name[sr@ijekavian]=доступан садржај +Name[sr@ijekavianlatin]=dostupan sadržaj +Name[sr@latin]=dostupan sadržaj +Name[sv]=Tillgängligt innehåll +Name[tg]=Мазмуни дастрас +Name[th]=เนื้อหาที่มีอยู่ +Name[tr]=Kullanılabilir İçerik +Name[ug]=ئىشلەتكىلى بولىدىغان مەزمۇن +Name[uk]=Доступний вміст +Name[vi]=Nội dung hiện hữu +Name[wa]=Ådvins disponibe +Name[x-test]=xxAvailable Contentxx +Name[zh_CN]=可用内容 +Name[zh_TW]=可用的內容 + +[Desktop Action blank] +Name=Blank +Name[ar]=فارغ +Name[ast]=Baleru +Name[bg]=Празен диск +Name[bn]=ফাঁকা +Name[bs]=prazan +Name[ca]=En blanc +Name[ca@valencia]=En blanc +Name[cs]=Prázdné +Name[csb]=Czësti +Name[da]=Tom +Name[de]=Leer +Name[el]=Κενό +Name[en_GB]=Blank +Name[eo]=Malplena +Name[es]=En blanco +Name[et]=Tühi +Name[eu]=Hutsik +Name[fi]=Tyhjä +Name[fr]=Vide +Name[fy]=Leech +Name[ga]=Folamh +Name[gl]=Sen gravar +Name[gu]=ખાલી +Name[he]=ריק +Name[hi]=खाली +Name[hr]=Prazan +Name[hu]=Üres +Name[ia]=Vacue +Name[id]=Kosong +Name[is]=Tómur +Name[it]=Vuoto +Name[ja]=空 +Name[kk]=Бос +Name[km]=ទទេ +Name[kn]=ಖಾಲಿ +Name[ko]=비어 있음 +Name[lt]=Tuščias +Name[lv]=Tukšs +Name[mk]=Празен +Name[ml]=ശൂന്യം +Name[mr]=रिकामे +Name[nb]=Tom +Name[nds]=Leddig +Name[nl]=Blanco +Name[nn]=Tom +Name[pa]=ਖਾਲੀ +Name[pl]=Pusty +Name[pt]=Vazio +Name[pt_BR]=Vazio +Name[ro]=Gol +Name[ru]=Пустой +Name[si]=හිස් +Name[sk]=Prázdne +Name[sl]=Prazen +Name[sr]=празан +Name[sr@ijekavian]=празан +Name[sr@ijekavianlatin]=prazan +Name[sr@latin]=prazan +Name[sv]=Tom +Name[tg]=Холӣ +Name[th]=แผ่นเปล่า +Name[tr]=Boş +Name[ug]=بوش +Name[uk]=Порожньо +Name[vi]=Trống +Name[wa]=Vude +Name[x-test]=xxBlankxx +Name[zh_CN]=空 +Name[zh_TW]=空白 + +[Desktop Action capacity] +Name=Capacity +Name[ar]=السعة +Name[ast]=Capacidá +Name[bg]=Капацитет +Name[bn]=পরিমাপ +Name[bs]=kapacitet +Name[ca]=Capacitat +Name[ca@valencia]=Capacitat +Name[cs]=Kapacita +Name[csb]=Plac na diskù +Name[da]=Kapacitet +Name[de]=Kapazität +Name[el]=Χωρητικότητα +Name[en_GB]=Capacity +Name[eo]=Kapacito +Name[es]=Capacidad +Name[et]=Mahtuvus +Name[eu]=Edukiera +Name[fi]=Tilavuus +Name[fr]=Capacité +Name[fy]=kapisiteit +Name[ga]=Toilleadh +Name[gl]=Capacidade +Name[gu]=ક્ષમતા +Name[he]=קיבולת +Name[hi]=क्षमता +Name[hr]=Kapacitet +Name[hu]=Kapacitás +Name[ia]=Capacitate +Name[id]=Kapasitas +Name[is]=Rýmd +Name[it]=Capacità +Name[ja]=容量 +Name[ka]=მოცულობა +Name[kk]=Сыйымдылығы +Name[km]=សមត្ថភាព +Name[kn]=ಸಾಮರ್ಥ್ಯ +Name[ko]=용량 +Name[lt]=Galimybės +Name[lv]=Ietilpība +Name[mk]=Капацитет +Name[ml]=വലിപ്പം +Name[mr]=क्षमता +Name[nb]=Kapasitet +Name[nds]=Grött +Name[nl]=Capaciteit +Name[nn]=Kapasitet +Name[pa]=ਸਮਰੱਥਾ +Name[pl]=Pojemność +Name[pt]=Capacidade +Name[pt_BR]=Capacidade +Name[ro]=Capacitate +Name[ru]=Ёмкость +Name[si]=පරිමාව +Name[sk]=Kapacita +Name[sl]=Zmogljivost +Name[sr]=капацитет +Name[sr@ijekavian]=капацитет +Name[sr@ijekavianlatin]=kapacitet +Name[sr@latin]=kapacitet +Name[sv]=Kapacitet +Name[tg]=Audacity +Name[th]=ความจุ +Name[tr]=Kapasite +Name[ug]=سىغىمى +Name[uk]=Місткість +Name[vi]=Dung lượng +Name[wa]=Capacité +Name[x-test]=xxCapacityxx +Name[zh_CN]=容量 +Name[zh_TW]=空間 + +[Desktop Action discType] +Name=Disc Type +Name[ar]=نوع القرص +Name[ast]=Triba de discu +Name[bg]=Вид диск +Name[bn]=ডিস্ক ধরন +Name[bs]=tip diska +Name[ca]=Tipus de disc +Name[ca@valencia]=Tipus de disc +Name[cs]=Typ disku +Name[csb]=Ôrt diskù +Name[da]=Disktype +Name[de]=Disc-Typ +Name[el]=Τύπος δίσκου +Name[en_GB]=Disc Type +Name[eo]=Tipo de Disko +Name[es]=Tipo de disco +Name[et]=Plaadi tüüp +Name[eu]=Disko mota +Name[fi]=Levyn tyyppi +Name[fr]=Type de disque +Name[fy]=Skiif type +Name[ga]=Cineál an Diosca +Name[gl]=Tipo de disco +Name[gu]=ડિસ્ક પ્રકાર +Name[he]=סוג דיסק +Name[hi]=डिस्क प्रकार +Name[hr]=Tip diska +Name[hu]=Lemeztípus +Name[ia]=Typo disco +Name[id]=Tipe Cakram +Name[is]=Gerð disks +Name[it]=Tipo di disco +Name[ja]=ディスクのタイプ +Name[ka]=დისკის ტიპი +Name[kk]=Диск түрі +Name[km]=ប្រភេទ​ថាស +Name[kn]=ಡಿಸ್ಕಿನ ಬಗೆ +Name[ko]=디스크 종류 +Name[lt]=Disko tipas +Name[lv]=Tiska veids +Name[mai]=डिस्क प्रकार +Name[mk]=Тип на диск +Name[ml]=ഡിസ്കിന്റെ തരം +Name[mr]=डिस्क प्रकार +Name[nb]=Platetype +Name[nds]=Schiev-Typ +Name[nl]=Schijftype +Name[nn]=Disktype +Name[pa]=ਡਿਸਕ ਕਿਸਮ +Name[pl]=Typ dysku +Name[pt]=Tipo de Disco +Name[pt_BR]=Tipo de disco +Name[ro]=Tipul discului +Name[ru]=Тип диска +Name[si]=තැටි වර්ගය +Name[sk]=Typ disku +Name[sl]=Vrsta diska +Name[sr]=тип диска +Name[sr@ijekavian]=тип диска +Name[sr@ijekavianlatin]=tip diska +Name[sr@latin]=tip diska +Name[sv]=Skivtyp +Name[tg]=Намуди диск +Name[th]=ประเภทของแผ่นดิสก์ +Name[tr]=Disk Tipi +Name[ug]=دىسكا تىپى +Name[uk]=Тип диска +Name[vi]=Kiểu đĩa +Name[wa]=Sôre di plake +Name[x-test]=xxDisc Typexx +Name[zh_CN]=盘片类型 +Name[zh_TW]=磁碟型態 + +[Desktop Action fsType] +Name=Fs Type +Name[ar]=نوع نظام الملفات +Name[ast]=Triba de Fs +Name[bg]=Вид файлова система +Name[bn]=Fs ধরন +Name[bs]=tip fsis. +Name[ca]=Tipus de sistema de fitxers +Name[ca@valencia]=Tipus de sistema de fitxers +Name[cs]=Typ FS +Name[csb]=Ôrt Fs +Name[da]=FS-type +Name[de]=Dateisystemtyp +Name[el]=Τύπος συστήματος αρχείων +Name[en_GB]=Fs Type +Name[eo]=Dosiersistema Tipo +Name[es]=Tipo de s. a. +Name[et]=Failisüsteemi tüüp +Name[eu]=Fitxategi-sistema mota +Name[fi]=Tiedostojärjestelmän tyyppi +Name[fr]=Type de système de fichiers +Name[fy]=Fs type +Name[ga]=Cineál an Chórais Comhad +Name[gl]=Sistema de ficheiros +Name[gu]=Fs પ્રકાર +Name[he]=סוג מערכת קבצים +Name[hi]=Fs प्रकार +Name[hr]=Tip datotečnog sustava +Name[hu]=Fájlrendszer +Name[ia]=Typo Fs +Name[id]=Tipe Sistem Berkas +Name[is]=Tegund skráakerfis +Name[it]=Tipo di filesystem +Name[ja]=Fs タイプ +Name[kk]=ФЖ түрі +Name[km]=ប្រភេទ Fs +Name[kn]=Fs ಬಗೆ +Name[ko]=파일 시스템 종류 +Name[lt]=FS tipas +Name[lv]=FS tips +Name[mai]=Fs प्रकार +Name[mk]=Тип на дат. систем +Name[ml]=ഫയല്‍ വ്യവസ്ഥയുടെ തരം +Name[mr]=Fs प्रकार +Name[nb]=Filsystemtype +Name[nds]=Dateisysteem-Typ +Name[nl]=FS-type +Name[nn]=Filsystemtype +Name[pa]=Fs ਕਿਸਮ +Name[pl]=Typ systemu plików +Name[pt]=Tipo de SF +Name[pt_BR]=Tipo de sistema de arquivos +Name[ro]=Tipul SF +Name[ru]=Файловая система +Name[si]=Fs වර්ගය +Name[sk]=Typ FS +Name[sl]=Vrsta dat. sist. +Name[sr]=тип фсис. +Name[sr@ijekavian]=тип фсис. +Name[sr@ijekavianlatin]=tip fsis. +Name[sr@latin]=tip fsis. +Name[sv]=Filsystemtyp +Name[tg]=Намуди Fs +Name[th]=ประเภทของระบบแฟ้ม +Name[tr]=Dosya Sistemi Tipi +Name[ug]=ھۆججەت سىستېما تىپى +Name[uk]=Тип ФС +Name[vi]=Kiểu hệ thống tập tin +Name[wa]=Sôre di Fs +Name[x-test]=xxFs Typexx +Name[zh_CN]=文件系统类型 +Name[zh_TW]=檔案系統型態 + +[Desktop Action ignored] +Name=Ignored +Name[ar]=متجاهَل +Name[ast]=Inoráu +Name[bg]=Пренебрегнат +Name[bn]=উপেক্ষিত +Name[bs]=ignorisan +Name[ca]=Ignorat +Name[ca@valencia]=Ignorat +Name[cs]=Ignorováno +Name[csb]=Ignorowóné +Name[da]=Ignoreret +Name[de]=Ignoriert +Name[el]=Παράβλεψη +Name[en_GB]=Ignored +Name[eo]=Ignorita +Name[es]=Ignorado +Name[et]=Eiratav +Name[eu]=Ez ikusi eginda +Name[fi]=Ei otettu huomioon +Name[fr]=Ignoré +Name[fy]=Negearre +Name[ga]=Neamhaird Déanta De +Name[gl]=Ignorado +Name[gu]=અવગણેલ +Name[he]=התעלם +Name[hi]=उपेक्षित +Name[hr]=Zanemareno +Name[hu]=Nem kezelt +Name[ia]=Ignorate +Name[id]=Diabaikan +Name[is]=Hunsað +Name[it]=Ignorato +Name[ja]=無視 +Name[kk]=Еленбеген +Name[km]=បានមិនអើពើ +Name[kn]=ಆಲಕ್ಷಿತ +Name[ko]=무시됨 +Name[lt]=Ignoruota +Name[lv]=Ignorēts +Name[mk]=Игнорирано +Name[ml]=അവഗണിച്ചു +Name[mr]=उपेक्षित +Name[nb]=Ignorert +Name[nds]=Övergahn +Name[nl]=Genegeerd +Name[nn]=Oversett +Name[pa]=ਅਣਡਿੱਠ ਕੀਤਾ +Name[pl]=Ignorowany +Name[pt]=Ignorado +Name[pt_BR]=Ignorado +Name[ro]=Ignorat +Name[ru]=Игнорируется +Name[si]=නොතැකූ +Name[sk]=Ignorované +Name[sl]=Prezrto +Name[sr]=игнорисан +Name[sr@ijekavian]=игнорисан +Name[sr@ijekavianlatin]=ignorisan +Name[sr@latin]=ignorisan +Name[sv]=Ignorerad +Name[tg]=Радшуда +Name[th]=ไม่สนใจ +Name[tr]=Yoksayılmış +Name[ug]=پەرۋا قىلمىدى +Name[uk]=Ігнорується +Name[vi]=Bỏ qua +Name[wa]=Passé houte +Name[x-test]=xxIgnoredxx +Name[zh_CN]=已忽略 +Name[zh_TW]=忽略 + +[Desktop Action label] +Name=Label +Name[ar]=التسمية +Name[ast]=Etiqueta +Name[bg]=Етикет +Name[bn]=লেবেল +Name[bs]=etiketa +Name[ca]=Etiqueta +Name[ca@valencia]=Etiqueta +Name[cs]=Popisek +Name[csb]=Znakòwnik +Name[da]=Etiket +Name[de]=Beschriftung +Name[el]=Ετικέτα +Name[en_GB]=Label +Name[eo]=Labelo +Name[es]=Etiqueta +Name[et]=Pealdis +Name[eu]=Etiketa +Name[fa]=برچسب +Name[fi]=Nimike +Name[fr]=Étiquette +Name[fy]=Lebel +Name[ga]=Lipéad +Name[gl]=Etiqueta +Name[gu]=લેબલ +Name[he]=תוויות +Name[hi]=लेबल +Name[hr]=Natpis +Name[hu]=Címke +Name[ia]=Etiquetta +Name[id]=Label +Name[is]=Merking +Name[it]=Etichetta +Name[ja]=ラベル +Name[kk]=Тамғасы +Name[km]=ស្លាក +Name[kn]=ಗುರುತುಪಟ್ಟಿ +Name[ko]=레이블 +Name[lt]=Etiketė +Name[lv]=Etiķete +Name[mk]=Натпис +Name[ml]=ലേബല്‍ +Name[mr]=लेबल +Name[nb]=Etikett +Name[nds]=Beteker +Name[nl]=Label +Name[nn]=Merkelapp +Name[pa]=ਲੇਬਲ +Name[pl]=Etykieta +Name[pt]=Legenda +Name[pt_BR]=Rótulo +Name[ro]=Etichetă +Name[ru]=Метка +Name[si]=ලේබලය +Name[sk]=Štítok +Name[sl]=Oznaka +Name[sr]=етикета +Name[sr@ijekavian]=етикета +Name[sr@ijekavianlatin]=etiketa +Name[sr@latin]=etiketa +Name[sv]=Etikett +Name[tg]=Тамға +Name[th]=แถบป้าย +Name[tr]=Etiket +Name[ug]=ئەن +Name[uk]=Мітка +Name[vi]=Nhãn +Name[wa]=Etikete +Name[x-test]=xxLabelxx +Name[zh_CN]=标签 +Name[zh_TW]=標籤 + +[Desktop Action rewritable] +Name=Rewritable +Name[ar]=قابل للكتابة +Name[ast]=Regrabable +Name[bg]=Презаписваем диск +Name[bn]=আবার লেখা যাবে +Name[bs]=prebrisiv +Name[ca]=Regravable +Name[ca@valencia]=Regravable +Name[cs]=Přepisovatelný +Name[csb]=Wielorazowò zapisëwanlné +Name[da]=Genbrændbar +Name[de]=Wiederbeschreibbar +Name[el]=Επανεγγράψιμο +Name[en_GB]=Rewritable +Name[eo]=Re-skribitebla +Name[es]=Regrabable +Name[et]=Korduvkirjutatav +Name[eu]=Birgrabagarria +Name[fi]=Uudelleenkirjoitettavissa +Name[fr]=Réinscriptible +Name[fy]=Wer te beskriuwen +Name[ga]=In-Athscríofa +Name[gl]=Regravábel +Name[gu]=ફરી લખી શકાય તેવું +Name[he]=ניתן לכתיבה חוזרת +Name[hi]=फिर लिखनेयोग्य +Name[hr]=Prebrisiv +Name[hu]=Újraírható +Name[ia]=Que on pote scriber de nove +Name[id]=Dapat Ditulis Ulang +Name[is]=Endurskrifanlegt +Name[it]=Riscrivibile +Name[ja]=リライタブル +Name[kk]=Қайта жазылмалы +Name[km]=អាច​សរសេរ​បាន +Name[kn]=ಪುನಃ ಬರೆಯಬಹುದಾದ +Name[ko]=다시 쓸 수 있음 +Name[lt]=Perrašomas +Name[lv]=Pārrakstāms +Name[mai]=फेर लिखबा योग्य +Name[ml]=വീണ്ടും എഴുതാവുന്ന +Name[mr]=परत लिहिता येण्याजोगे +Name[nb]=Overskrivbar +Name[nds]=Wedderschriefbor +Name[nl]=Herschrijfbaar +Name[nn]=Omskrivbar +Name[pa]=ਮੁੜ-ਲਿਖਣਯੋਗ +Name[pl]=Z możliwością ponownego zapisu +Name[pt]=Regravável +Name[pt_BR]=Regravável +Name[ro]=Reinscriptibil +Name[ru]=Перезаписываемый +Name[si]=නැවත ලිවිය හැකි +Name[sk]=Prepisovateľné +Name[sl]=Prepisljiv +Name[sr]=пребрисив +Name[sr@ijekavian]=пребрисив +Name[sr@ijekavianlatin]=prebrisiv +Name[sr@latin]=prebrisiv +Name[sv]=Skrivbar +Name[tg]=Навишташаванда +Name[th]=สามารถเขียนใหม่ได้ +Name[tr]=Yeniden yazılabilir +Name[ug]=يېزىشقا بولىدىغان +Name[uk]=Перезапис +Name[wa]=Riscrijhåve +Name[x-test]=xxRewritablexx +Name[zh_CN]=可覆写 +Name[zh_TW]=可覆寫 + +[Desktop Action size] +Name=Size +Name[ar]=الحجم +Name[ast]=Tamañu +Name[bg]=Големина +Name[bn]=মাপ +Name[bs]=veličina +Name[ca]=Mida +Name[ca@valencia]=Mida +Name[cs]=Velikost +Name[csb]=Miara +Name[da]=Størrelse +Name[de]=Größe +Name[el]=Μέγεθος +Name[en_GB]=Size +Name[eo]=Grandeco +Name[es]=Tamaño +Name[et]=Suurus +Name[eu]=Neurria +Name[fa]=اندازه +Name[fi]=Koko +Name[fr]=Taille +Name[fy]=Grutte +Name[ga]=Méid +Name[gl]=Tamaño +Name[gu]=માપ +Name[he]=גודל +Name[hi]=आकार +Name[hr]=Veličina +Name[hu]=Méret +Name[ia]=Dimension +Name[id]=Ukuran +Name[is]=Stærð +Name[it]=Dimensione +Name[ja]=サイズ +Name[ka]=ზომა +Name[kk]=Көлемі +Name[km]=ទំហំ +Name[kn]=ಗಾತ್ರ +Name[ko]=크기 +Name[lt]=Dydis +Name[lv]=Izmērs +Name[mk]=Големина +Name[ml]=വലിപ്പം +Name[mr]=आकार +Name[nb]=Størrelse +Name[nds]=Grött +Name[nl]=Grootte +Name[nn]=Storleik +Name[pa]=ਸਾਈਜ਼ +Name[pl]=Rozmiar +Name[pt]=Tamanho +Name[pt_BR]=Tamanho +Name[ro]=Dimensiune +Name[ru]=Размер +Name[si]=ප්‍රමාණය +Name[sk]=Veľkosť +Name[sl]=Velikost +Name[sr]=величина +Name[sr@ijekavian]=величина +Name[sr@ijekavianlatin]=veličina +Name[sr@latin]=veličina +Name[sv]=Storlek +Name[tg]=Андоза +Name[th]=ขนาด +Name[tr]=Boyut +Name[ug]=چوڭلۇقى +Name[uk]=Розмір +Name[wa]=Grandeu +Name[x-test]=xxSizexx +Name[zh_CN]=大小 +Name[zh_TW]=大小 + +[Desktop Action usage] +Name=Usage +Name[ar]=الاستعمال +Name[ast]=Usu +Name[bg]=Използване +Name[bn]=ব্যবহার +Name[bs]=upotreba +Name[ca]=Ús +Name[ca@valencia]=Ús +Name[cs]=Použití +Name[csb]=Brëkòwóné +Name[da]=Brug +Name[de]=Verwendung +Name[el]=Χρήση +Name[en_GB]=Usage +Name[eo]=Uzado +Name[es]=Uso +Name[et]=Kasutus +Name[eu]=Erabilera +Name[fi]=Käyttötaso +Name[fr]=Usage +Name[fy]=Brûkens +Name[ga]=Úsáid +Name[gl]=Uso +Name[gu]=વપરાશ +Name[he]=שימוש +Name[hi]=उपयोग +Name[hr]=Iskorištenost +Name[hu]=Kihasználtság +Name[ia]=Usage +Name[id]=Penggunaan +Name[is]=Notkun +Name[it]=Uso +Name[ja]=使用率 +Name[ka]=გამოყენება +Name[kk]=Толуы +Name[km]=កា​រប្រើប្រាស់ +Name[kn]=ಬಳಕೆ +Name[ko]=사용량 +Name[lt]=Naudojimas +Name[lv]=Izlietojums +Name[mk]=Користење +Name[ml]=ഉപയോഗരീതി +Name[mr]=वापर +Name[nb]=Bruk +Name[nds]=Bruuk +Name[nl]=Gebruik +Name[nn]=Bruk +Name[pa]=ਵਰਤੋਂ +Name[pl]=Wykorzystanie +Name[pt]=Utilização +Name[pt_BR]=Uso +Name[ro]=Utilizare +Name[ru]=Использование +Name[si]=භාවිතය +Name[sk]=Použitie +Name[sl]=Poraba +Name[sr]=употреба +Name[sr@ijekavian]=употреба +Name[sr@ijekavianlatin]=upotreba +Name[sr@latin]=upotreba +Name[sv]=Användning +Name[tg]=Истифодабарӣ +Name[th]=วิธีใช้ +Name[tr]=Kullanım +Name[ug]=ئىشلىتىلىشى +Name[uk]=Використання +Name[wa]=Eployaedje +Name[x-test]=xxUsagexx +Name[zh_CN]=已用量 +Name[zh_TW]=使用量 + +[Desktop Action uuid] +Name=Uuid +Name[ar]=المعرف الفريد عالمياً (Uuid) +Name[ast]=Uuid +Name[bg]=Uuid +Name[bn]=Uuid +Name[bs]=UUID +Name[ca]=UUID +Name[ca@valencia]=UUID +Name[cs]=Uuid +Name[csb]=Uuid +Name[da]=Uuid +Name[de]=UUID +Name[el]=Uuid +Name[en_GB]=Uuid +Name[eo]=Uuid +Name[es]=Uuid +Name[et]=Uuid +Name[eu]=UUIDa +Name[fi]=Uuid +Name[fr]=Uuid +Name[fy]=Uuid +Name[ga]=Uuid +Name[gl]=Uuid +Name[gu]=Uuid +Name[he]=Uuid +Name[hi]=Uuid +Name[hr]=UUID +Name[hu]=UUID +Name[ia]=Uuid +Name[id]=Uuid +Name[is]=UUID +Name[it]=Uuid +Name[ja]=UUID +Name[ka]=Uuid +Name[kk]=Uuid +Name[km]=Uuid +Name[kn]=Uuid +Name[ko]=UUID +Name[lt]=Uuid +Name[lv]=Uuid +Name[mk]=Uuid +Name[ml]=യുയുഐഡി +Name[mr]=Uuid +Name[nb]=Uuid +Name[nds]=UUID +Name[nl]=Uuid +Name[nn]=UUID +Name[pa]=Uuid +Name[pl]=Uuid +Name[pt]=UUID +Name[pt_BR]=UUID +Name[ro]=Uuid +Name[ru]=UUID +Name[si]=Uuid +Name[sk]=Uuid +Name[sl]=UUID +Name[sr]=УУИД +Name[sr@ijekavian]=УУИД +Name[sr@ijekavianlatin]=UUID +Name[sr@latin]=UUID +Name[sv]=Uuid +Name[tg]=Phluid +Name[th]=ค่า Uuid +Name[tr]=Uuid +Name[ug]=Uuid +Name[uk]=Uuid +Name[wa]=Uuid +Name[x-test]=xxUuidxx +Name[zh_CN]=UUID +Name[zh_TW]=UUID + +[Desktop Entry] +Actions=appendable;availableContent;blank;capacity;discType;fsType;ignored;label;rewritable;size;usage;uuid; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=OpticalDisc diff --git a/solid-actions-kcm/device-actions/solid-device-OpticalDrive.desktop b/solid-actions-kcm/device-actions/solid-device-OpticalDrive.desktop new file mode 100644 index 00000000..edb85a19 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-OpticalDrive.desktop @@ -0,0 +1,723 @@ +[Desktop Action bus] +Name=Bus +Name[ar]=الناقل +Name[ast]=Bus +Name[bg]=Шина +Name[bn]=বাস +Name[bs]=magistrala +Name[ca]=Bus +Name[ca@valencia]=Bus +Name[cs]=Sběrnice +Name[csb]=Bus +Name[da]=Bus +Name[de]=Bus +Name[el]=Δίαυλος +Name[en_GB]=Bus +Name[eo]=Buso +Name[es]=Bus +Name[et]=Siin +Name[eu]=Busa +Name[fa]=گذرگاه +Name[fi]=Väylä +Name[fr]=Bus +Name[fy]=Bus +Name[ga]=Bus +Name[gl]=Bus +Name[gu]=બસ +Name[he]=אפיק +Name[hi]=बस +Name[hr]=Sabirnica +Name[hu]=Busz +Name[ia]=Bus +Name[id]=Bus +Name[is]=Rás (bus) +Name[it]=Bus +Name[ja]=バス +Name[ka]=სალტე +Name[kk]=Шинасы +Name[km]=ខ្សែបញ្ជូន +Name[kn]=ಬಸ್ +Name[ko]=버스 +Name[lt]=Magistralė +Name[lv]=Kopne +Name[mk]=Магистрала +Name[ml]=ബസ് +Name[mr]=बस +Name[nb]=Buss +Name[nds]=Bus +Name[nl]=Bus +Name[nn]=Buss +Name[pa]=ਬਸ +Name[pl]=Szyna +Name[pt]=Barramento +Name[pt_BR]=Barramento +Name[ro]=Magistrală +Name[ru]=Шина +Name[si]=Bus +Name[sk]=Zbernica +Name[sl]=Vodilo +Name[sr]=магистрала +Name[sr@ijekavian]=магистрала +Name[sr@ijekavianlatin]=magistrala +Name[sr@latin]=magistrala +Name[sv]=Buss +Name[tg]=Белоруссия +Name[th]=ระบบบัส +Name[tr]=Yol +Name[ug]=باش لىنىيە +Name[uk]=Шина +Name[wa]=Bus +Name[x-test]=xxBusxx +Name[zh_CN]=总线 +Name[zh_TW]=匯流排 + +[Desktop Action driveType] +Name=Drive Type +Name[ar]=نوع المشغل +Name[ast]=Triba de discu +Name[bg]=Вид устройство +Name[bn]=ড্রাইভ-এর ধরন +Name[bs]=tip jedinice +Name[ca]=Tipus d'unitat +Name[ca@valencia]=Tipus d'unitat +Name[cs]=Typ mechaniky +Name[csb]=Ôrt nëka +Name[da]=Drevtype +Name[de]=Laufwerkstyp +Name[el]=Τύπος οδηγού +Name[en_GB]=Drive Type +Name[eo]=Tipo de Diskingo +Name[es]=Tipo de disco +Name[et]=Seadme tüüp +Name[eu]=Unitate mota +Name[fi]=Asematyyppi +Name[fr]=Type de lecteur +Name[fy]=Stasjons type +Name[ga]=Cineál an Tiomántáin +Name[gl]=Tipo de dispositivo +Name[gu]=ડ્રાઇવ પ્રકાર +Name[he]=סוג כונן +Name[hi]=ड्राईव प्रकार +Name[hr]=Tip uređaja +Name[hu]=Meghajtótípus +Name[ia]=Typo de drive +Name[id]=Tipe Penggerak +Name[is]=Gerð drifs +Name[it]=Tipo di unità +Name[ja]=ドライブのタイプ +Name[ka]=ამძრავის ტიპი +Name[kk]=Жетек түрі +Name[km]=ប្រភេទ​ដ្រាយ +Name[kn]=ಡ್ರೈವಿನ ಬಗೆ +Name[ko]=드라이브 종류 +Name[lt]=Diskasukio tipas +Name[lv]=Dziņa tips +Name[mai]=ड्राइव प्रकार +Name[mk]=Тип на уред +Name[ml]=ഡ്രൈവിന്റെ തരം +Name[mr]=ड्राइव्ह प्रकार +Name[nb]=Drev-type +Name[nds]=Loopwark-Typ +Name[nl]=Apparaattype +Name[nn]=Einingstype +Name[pa]=ਡਰਾਇਵਰ ਕਿਸਮ +Name[pl]=Typ napędu +Name[pt]=Tipo de Unidade +Name[pt_BR]=Tipo de unidade +Name[ro]=Tip unitate +Name[ru]=Тип устройства +Name[si]=ධාවක වර්ගය +Name[sk]=Typ mechaniky +Name[sl]=Vrsta pogona +Name[sr]=тип јединице +Name[sr@ijekavian]=тип јединице +Name[sr@ijekavianlatin]=tip jedinice +Name[sr@latin]=tip jedinice +Name[sv]=Enhetstyp +Name[tg]=Намуди дастгоҳ +Name[th]=ประเภทของไดรฟ์ +Name[tr]=Sürücü Tipi +Name[ug]=قوزغاتقۇ تىپى +Name[uk]=Тип пристрою +Name[vi]=Kiểu trình điều khiển +Name[wa]=Sôre di lijheu +Name[x-test]=xxDrive Typexx +Name[zh_CN]=驱动类型 +Name[zh_TW]=磁碟型態 + +[Desktop Action hotpluggable] +Name=Hotpluggable +Name[ar]=قابل للتوصيل +Name[ast]=Conexón en caliente +Name[bn]=হট-প্লাগ-যোগ্য +Name[bs]=vruće uključiva +Name[ca]=Connectable en calent +Name[ca@valencia]=Connectable en calent +Name[cs]=Hotplug +Name[da]=Flytbar +Name[de]=Hotplug-fähig +Name[el]=Δυνατότητα Hotplug +Name[en_GB]=Hotpluggable +Name[eo]=Dumkure permutebla +Name[es]=Conexión en caliente +Name[et]=Töö ajal ühendatav +Name[eu]=Hotplug-erako gaitua +Name[fi]=Lennossakytkettävä +Name[fr]=Connectable à chaud +Name[fy]=Hotplug barren +Name[ga]=Inphlugáilte +Name[gl]=Conectábel en quente +Name[gu]=હોટપ્લગેબલ +Name[he]=החלפה חמה +Name[hi]=हाटप्लग योग्य +Name[hr]=Podržava brzo uštekavanje +Name[hu]=Menet közben csatlakoztatható +Name[ia]=Hotpluggable (On pote connecter lo con machina active) +Name[id]=Dapat di-Hotplug +Name[is]=Hraðtengjanlegt (hotplug) +Name[it]=Collegabile in marcia +Name[ja]=Hotplug 可能 +Name[kk]=Істеп турғанда қосылмалы +Name[km]=ដោតដើរ +Name[kn]=ಹಾಟ್‌ಪ್ಲಗ್‌ ಮಾಡಬಹುದಾದ +Name[ko]=핫플러그 가능 +Name[lt]=Greitai prijungiamas +Name[lv]=Karsti nomaināms +Name[ml]=ഹോട്ട്പ്ലഗ് ചെയ്യാവുന്ന +Name[mr]=हॉटप्लग करता येणारे +Name[nb]=Kan kobles til påslått +Name[nds]=Jümmers tokoppelbor +Name[nl]=Hotplugbaar +Name[nn]=Hotplug-kompatibel +Name[pa]=ਹਾਟਪਲੱਗਯੋਗ +Name[pl]=Podłączany "na gorąco" +Name[pt]=Conectável em Funcionamento +Name[pt_BR]=Conectável em funcionamento +Name[ro]=Detașabil +Name[ru]=Подключается в любое время +Name[si]=Hotpluggable +Name[sk]=Hotplug +Name[sl]=Priključljivo med delovanjem +Name[sr]=вруће укључива +Name[sr@ijekavian]=вруће укључива +Name[sr@ijekavianlatin]=vruće uključiva +Name[sr@latin]=vruće uključiva +Name[sv]=Inkopplingsbar +Name[tg]=Дастгоҳҳои пайвастшаванда +Name[th]=สามารถถอดเสียบได้ +Name[tr]=Çıkarılıp takılabilir +Name[ug]=ئىسسىق چېتىلىشچان +Name[uk]=«Гаряче» з’єднання +Name[vi]=Tháo lắp nóng +Name[wa]=Hotplugåve +Name[x-test]=xxHotpluggablexx +Name[zh_CN]=可热插拔 +Name[zh_TW]=可熱插拔 + +[Desktop Action readSpeed] +Name=Read Speed +Name[ar]=سرعة القراءة +Name[ast]=Velocidá de llectura +Name[bg]=Скорост на четене +Name[bn]=পড়ার গতি +Name[bs]=brzina čitanja +Name[ca]=Velocitat de lectura +Name[ca@valencia]=Velocitat de lectura +Name[cs]=Rychlost čtení +Name[csb]=Chùtkòsc czëtaniô +Name[da]=Læsehastighed +Name[de]=Lesegeschwindigkeit +Name[el]=Ταχύτητα ανάγνωσης +Name[en_GB]=Read Speed +Name[eo]=Leg-rapideco +Name[es]=Velocidad de lectura +Name[et]=Lugemiskiirus +Name[eu]=Irakurketa-abiadura +Name[fi]=Lukunopeus +Name[fr]=Vitesse de lecture +Name[fy]=Lês fluggens +Name[ga]=Luas Léite +Name[gl]=Velocidade de lectura +Name[gu]=લખવાની ઝડપ +Name[he]=מהירות קריאה +Name[hi]=पढ़ने की गति +Name[hr]=Brzina čitanja +Name[hu]=Olvasási sebesség +Name[ia]=Velocitate de lectura +Name[id]=Kecepatan Baca +Name[is]=Leshraði +Name[it]=Velocità in lettura +Name[ja]=読み取り速度 +Name[kk]=Оқу жылдамдығы +Name[km]=ល្បឿន​អាន +Name[kn]=ಓದುವ ವೇಗ +Name[ko]=읽기 속도 +Name[lt]=Skaitymo sparta +Name[lv]=Lasīšanas ātrums +Name[mk]=Брзина на читање +Name[ml]=വായനാ വേഗം +Name[mr]=वाचन वेग +Name[nb]=Lesehastighet +Name[nds]=Leesgauigkeit +Name[nl]=Leessnelheid +Name[nn]=Lesefart +Name[pa]=ਪੜ੍ਹਨ ਸਪੀਡ +Name[pl]=Szybkość odczytu +Name[pt]=Velocidade de Leitura +Name[pt_BR]=Velocidade de leitura +Name[ro]=Viteză de citire +Name[ru]=Скорость чтения +Name[si]=කියවුම් වේගය +Name[sk]=Rýchlosť čítania +Name[sl]=Hitrost branja +Name[sr]=брзина читања +Name[sr@ijekavian]=брзина читања +Name[sr@ijekavianlatin]=brzina čitanja +Name[sr@latin]=brzina čitanja +Name[sv]=Läshastighet +Name[tg]=Суръати хондан +Name[th]=ความเร็วในการอ่านข้อมูล +Name[tr]=Okuma hızı +Name[ug]=ئوقۇش تېزلىكى +Name[uk]=Швидкість читання +Name[wa]=Radisté d' lijhaedje +Name[x-test]=xxRead Speedxx +Name[zh_CN]=读取速度 +Name[zh_TW]=讀取速度 + +[Desktop Action removable] +Name=Removable +Name[ar]=قابل للإزالة +Name[ast]=Estrayible +Name[bg]=Преносим +Name[bn]=অপসারণযোগ্য +Name[bs]=uklonjiva +Name[ca]=Extraïble +Name[ca@valencia]=Extraïble +Name[cs]=Odpojitelný +Name[csb]=Przenosné +Name[da]=Flytbar +Name[de]=Wechselbar +Name[el]=Αφαιρούμενο μέσο +Name[en_GB]=Removable +Name[eo]=Demetebla +Name[es]=Extraíble +Name[et]=Eemaldatav +Name[eu]=Aldagarria +Name[fa]=جدا شدنی +Name[fi]=Poistettavissa +Name[fr]=Amovible +Name[fy]=Te ferwiderjen +Name[ga]=Inbhainte +Name[gl]=Eliminábel +Name[gu]=દૂર કરી શકાય તેવું +Name[he]=ניתן להסרה +Name[hi]=हटाने योग्य +Name[hr]=Moguće ga je izvaditi +Name[hu]=Cserélhető +Name[ia]=Removibile +Name[id]=Dapat Dilepaskan +Name[is]=Fjarlægjanlegt +Name[it]=Rimovibile +Name[ja]=リムーバブル +Name[kk]=Ауыстырмалы +Name[km]=អាច​យក​ចេញ​បាន +Name[kn]=ತೆಗೆಯಬಹುದಾದ +Name[ko]=제거 가능 +Name[lt]=Keičiamas +Name[lv]=Noņemams +Name[mai]=हटबैयोग्य +Name[mk]=Подвижен +Name[ml]=നീക്കം ചെയ്യാവുന്ന +Name[mr]=काढता येणारे +Name[nb]=Flyttbar +Name[nds]=Tuuschbor +Name[nl]=Verwijderbaar +Name[nn]=Flyttbar +Name[pa]=ਹਟਾਉਣਯੋਗ +Name[pl]=Wymienny +Name[pt]=Removível +Name[pt_BR]=Removível +Name[ro]=Amovibil +Name[ru]=Сменный носитель +Name[si]=ඉවත්කල හැකි +Name[sk]=Vymeniteľné +Name[sl]=Odstranljivo +Name[sr]=уклоњива +Name[sr@ijekavian]=уклоњива +Name[sr@ijekavianlatin]=uklonjiva +Name[sr@latin]=uklonjiva +Name[sv]=Flyttbar +Name[tg]=Дастгоҳи ҷудошаванда +Name[th]=ถอดเสียบได้ +Name[tr]=Çıkarılabilir +Name[ug]=كۆچمە +Name[uk]=Змінний пристрій +Name[wa]=Bodjåve +Name[x-test]=xxRemovablexx +Name[zh_CN]=移动 +Name[zh_TW]=可移除 + +[Desktop Action size] +Name=Size +Name[ar]=الحجم +Name[ast]=Tamañu +Name[bg]=Големина +Name[bn]=মাপ +Name[bs]=veličina +Name[ca]=Mida +Name[ca@valencia]=Mida +Name[cs]=Velikost +Name[csb]=Miara +Name[da]=Størrelse +Name[de]=Größe +Name[el]=Μέγεθος +Name[en_GB]=Size +Name[eo]=Grandeco +Name[es]=Tamaño +Name[et]=Suurus +Name[eu]=Neurria +Name[fa]=اندازه +Name[fi]=Koko +Name[fr]=Taille +Name[fy]=Grutte +Name[ga]=Méid +Name[gl]=Tamaño +Name[gu]=માપ +Name[he]=גודל +Name[hi]=आकार +Name[hr]=Veličina +Name[hu]=Méret +Name[ia]=Dimension +Name[id]=Ukuran +Name[is]=Stærð +Name[it]=Dimensione +Name[ja]=サイズ +Name[ka]=ზომა +Name[kk]=Көлемі +Name[km]=ទំហំ +Name[kn]=ಗಾತ್ರ +Name[ko]=크기 +Name[lt]=Dydis +Name[lv]=Izmērs +Name[mk]=Големина +Name[ml]=വലിപ്പം +Name[mr]=आकार +Name[nb]=Størrelse +Name[nds]=Grött +Name[nl]=Grootte +Name[nn]=Storleik +Name[pa]=ਸਾਈਜ਼ +Name[pl]=Rozmiar +Name[pt]=Tamanho +Name[pt_BR]=Tamanho +Name[ro]=Dimensiune +Name[ru]=Размер +Name[si]=ප්‍රමාණය +Name[sk]=Veľkosť +Name[sl]=Velikost +Name[sr]=величина +Name[sr@ijekavian]=величина +Name[sr@ijekavianlatin]=veličina +Name[sr@latin]=veličina +Name[sv]=Storlek +Name[tg]=Андоза +Name[th]=ขนาด +Name[tr]=Boyut +Name[ug]=چوڭلۇقى +Name[uk]=Розмір +Name[wa]=Grandeu +Name[x-test]=xxSizexx +Name[zh_CN]=大小 +Name[zh_TW]=大小 + +[Desktop Action supportedMedia] +Name=Supported Media +Name[ar]=الوسائط المدعومة +Name[ast]=Medios sofitaos +Name[bg]=Поддържана медия +Name[bn]=সমর্থিত মিডিয়া +Name[bs]=podržani medijumi +Name[ca]=Suports acceptats +Name[ca@valencia]=Suports acceptats +Name[cs]=Podporovaná média +Name[csb]=Wspiéróné media +Name[da]=Understøttede medier +Name[de]=Unterstützte Medien +Name[el]=Υποστηριζόμενα μέσα +Name[en_GB]=Supported Media +Name[eo]=subtenataj Aŭdvidaĵoj +Name[es]=Medios soportados +Name[et]=Toetatud meedia +Name[eu]=Onartzen diren euskarriak +Name[fi]=Tuetut mediat +Name[fr]=Média pris en charge +Name[fy]=Stipe media +Name[ga]=Meáin a dTacaítear Leo +Name[gl]=Medios soportados +Name[gu]=આધારિત મિડીઆ +Name[he]=מדיה נתמכת +Name[hi]=समर्थित मीडिया +Name[hr]=Podržani mediji +Name[hu]=Támogatott média +Name[ia]=Media supportate +Name[id]=Media Didukung +Name[is]=Studdir miðlar +Name[it]=Dispositivi supportati +Name[ja]=サポートされているメディア +Name[kk]=Тасушысы +Name[km]=មេឌៀ​ដែលបានគាំទ្រ +Name[kn]=ಬೆಂಬಲಿತ ಮಾಧ್ಯಮ +Name[ko]=지원하는 미디어 +Name[lt]=Palaikomi media tipai +Name[lv]=Atbalstītie datu nesēji +Name[mai]=समर्थित मीडिआ +Name[mk]=Поддржани медиуми +Name[ml]=പിന്തുണയുള്ള മാദ്ധ്യമം +Name[mr]=समर्थीत मीडिया +Name[nb]=Støttede medier +Name[nds]=Ünnerstütt Schieven +Name[nl]=Ondersteunde media +Name[nn]=Støtta medium +Name[pa]=ਸਹਾਇਕ ਮੀਡਿਆ +Name[pl]=Obsługiwane nośniki +Name[pt]=Discos Suportados +Name[pt_BR]=Mídia suportada +Name[ro]=Mediu susținut +Name[ru]=Поддерживаемые носители +Name[si]=සහාය දක්වන මාධ්‍යය +Name[sk]=Podporované médiá +Name[sl]=Podprti nosilci +Name[sr]=подржани медијуми +Name[sr@ijekavian]=подржани медијуми +Name[sr@ijekavianlatin]=podržani medijumi +Name[sr@latin]=podržani medijumi +Name[sv]=Media som stöds +Name[tg]=Медиаи мувофиқ +Name[th]=สื่อที่รองรับ +Name[tr]=Desteklenen Ortam +Name[ug]=قوللايدىغان ۋاسىتىلەر +Name[uk]=Підтримувані носії +Name[wa]=Media sopoirté +Name[x-test]=xxSupported Mediaxx +Name[zh_CN]=支持的媒体 +Name[zh_TW]=支援的媒體 + +[Desktop Action writeSpeed] +Name=Write Speed +Name[ar]=سرعة الكتابة +Name[ast]=Velocidá d'escritura +Name[bg]=Скорост на запис +Name[bn]=লেখার গতি +Name[bs]=brzina pisanja +Name[ca]=Velocitat d'escriptura +Name[ca@valencia]=Velocitat d'escriptura +Name[cs]=Rychlost zápisu +Name[csb]=Chùtkòsc pisaniô +Name[da]=Brændehastighed +Name[de]=Schreibgeschwindigkeit +Name[el]=Ταχύτητα εγγραφής +Name[en_GB]=Write Speed +Name[eo]=Skribrapideco +Name[es]=Velocidad de escritura +Name[et]=Kirjutamiskiirus +Name[eu]=Idazketa-abiadura +Name[fi]=Kirjoitusnopeus +Name[fr]=Vitesse d'écriture +Name[fy]=Skriuw fluggens +Name[ga]=Luas Scríofa +Name[gl]=Velocidade de gravación +Name[gu]=લખવાની ઝડપ +Name[he]=מהירות כתיבה +Name[hi]=लेखन गति +Name[hr]=Brzina pisanja +Name[hu]=Írási sebesség +Name[ia]=Velocitate de scriptura +Name[id]=Kecepatan Tulis +Name[is]=Skrifhraði +Name[it]=Velocità in scrittura +Name[ja]=書き込み速度 +Name[ka]=ჩაწერის სიჩქარე +Name[kk]=Жазу жылдамдығы +Name[km]=ល្បឿនសរសេរ +Name[kn]=ಬರೆಯುವ ವೇಗ +Name[ko]=쓰기 속도 +Name[lt]=Rašymo greitis +Name[lv]=Rakstīšanas ātrums +Name[mai]=लेखन गति +Name[mk]=Брзина на запишување +Name[ml]=എഴുത്തിന്റെ വേഗത +Name[mr]=लिखाण वेग +Name[nb]=Skrivehastighet +Name[nds]=Schriev-Gauigkeit +Name[nl]=Schrijfsnelheid +Name[nn]=Skrivefart +Name[pa]=ਲਿਖਣ ਸਪੀਡ +Name[pl]=Szybkość zapisu +Name[pt]=Velocidade de Gravação +Name[pt_BR]=Velocidade de gravação +Name[ro]=Viteză de scriere +Name[ru]=Скорость записи +Name[si]=ලිවීම් වේගය +Name[sk]=Rýchlosť zápisu +Name[sl]=Hitrost zapisovanja +Name[sr]=брзина писања +Name[sr@ijekavian]=брзина писања +Name[sr@ijekavianlatin]=brzina pisanja +Name[sr@latin]=brzina pisanja +Name[sv]=Skrivhastighet +Name[tg]=Суръати навиштан +Name[th]=ความเร็วในการเขียนข้อมูล +Name[tr]=Yazma Hızı +Name[ug]=يېزىش تېزلىكى +Name[uk]=Швидкість запису +Name[wa]=Radisté d' sicrijhaedje +Name[x-test]=xxWrite Speedxx +Name[zh_CN]=写入速度 +Name[zh_TW]=寫入速度 + +[Desktop Action writeSpeeds] +Name=Write Speeds +Name[ar]=سرعات الكتابة +Name[ast]=Velocidaes d'escritura +Name[bg]=Скорости на запис +Name[bn]=লেখার গতি +Name[bs]=brzine pisanja +Name[ca]=Velocitats d'escriptura +Name[ca@valencia]=Velocitats d'escriptura +Name[cs]=Rychlosti zápisu +Name[csb]=Chùtkòscë pisaniô +Name[da]=Brændehastigheder +Name[de]=Schreibgeschwindigkeiten +Name[el]=Ταχύτητες εγγραφής +Name[en_GB]=Write Speeds +Name[eo]=Skribrapidecoj +Name[es]=Velocidades de escritura +Name[et]=Kirjutamiskiirus +Name[eu]=Idazketa-abiadurak +Name[fi]=Kirjoitusnopeudet +Name[fr]=Vitesses d'écriture +Name[fy]=Skriuw fluggens +Name[ga]=Luasanna Scríofa +Name[gl]=Velocidades de gravación +Name[gu]=લખવાની ઝડપો +Name[he]=מהירויות כתיבה +Name[hi]=लेखन गतियाँ +Name[hr]=Brzine pisanja +Name[hu]=Írási sebességek +Name[ia]=Velocitates de scriptura +Name[id]=Kecepatan Tulis +Name[is]=Skrifhraðar +Name[it]=Velocità in scrittura +Name[ja]=書き込み速度 +Name[ka]=ჩაწერის სიჩქარეები +Name[kk]=Жазу жылдамдықтары +Name[km]=ល្បឿន​សរសេរ +Name[kn]=ಬರೆಯುವ ವೇಗಗಳು +Name[ko]=지원하는 쓰기 속도 +Name[lt]=Rašymo greičiai +Name[lv]=Rakstīšanas ātrumi +Name[mai]=लेखन गति +Name[mk]=Брзини на запишување +Name[ml]=എഴുത്തിന്റെ വേഗതകള്‍ +Name[mr]=लिखाण वेग +Name[nb]=Skrivehastigheter +Name[nds]=Schriev-Gauigkeiten +Name[nl]=Schrijfsnelheden +Name[nn]=Skrivefartar +Name[pa]=ਲਿਖਣ ਸਪੀਡ +Name[pl]=Szybkości zapisu +Name[pt]=Velocidades de Gravação +Name[pt_BR]=Velocidades de gravação +Name[ro]=Viteze de scriere +Name[ru]=Скорости записи +Name[si]=ලිවීම් වේග +Name[sk]=Rýchlosti zápisu +Name[sl]=Hitrosti zapisovanja +Name[sr]=брзине писања +Name[sr@ijekavian]=брзине писања +Name[sr@ijekavianlatin]=brzine pisanja +Name[sr@latin]=brzine pisanja +Name[sv]=Skrivhastigheter +Name[tg]=Суръатҳои навиштан +Name[th]=ความเร็วในการเขียนข้อมูล +Name[tr]=yazma Hızları +Name[ug]=يېزىش تېزلىكى +Name[uk]=Швидкості запису +Name[wa]=Radistés d' sicrijhaedje +Name[x-test]=xxWrite Speedsxx +Name[zh_CN]=写入速度 +Name[zh_TW]=寫入速度 + +[Desktop Entry] +Actions=bus;driveType;hotpluggable;readSpeed;removable;size;supportedMedia;writeSpeed;writeSpeeds; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=OpticalDrive diff --git a/solid-actions-kcm/device-actions/solid-device-PortableMediaPlayer.desktop b/solid-actions-kcm/device-actions/solid-device-PortableMediaPlayer.desktop new file mode 100644 index 00000000..16702027 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-PortableMediaPlayer.desktop @@ -0,0 +1,215 @@ +[Desktop Action supportedDrivers] +Name=Supported Drivers +Name[ar]=المشغلات المدعومة +Name[ast]=Controladores sofitaos +Name[bg]=Поддържани драйвери +Name[bn]=সমর্থিত ড্রাইভার +Name[bs]=podržani drajveri +Name[ca]=Controladors acceptats +Name[ca@valencia]=Controladors acceptats +Name[cs]=Podporované ovladače +Name[csb]=Wspiéróné czérowniczi +Name[da]=Understøttede drivere +Name[de]=Unterstützte Treiber +Name[el]=Υποστηριζόμενοι οδηγοί +Name[en_GB]=Supported Drivers +Name[eo]=subtenataj Peliloj +Name[es]=Dispositivos soportados +Name[et]=Toetatud draiverid +Name[eu]=Onartutzen diren gidariak +Name[fi]=Tuetut ajurit +Name[fr]=Pilotes pris en charge +Name[fy]=Stipe stjoerprogramma's +Name[ga]=Tiománaithe a dTacaítear Leo +Name[gl]=Controladores soportados +Name[gu]=આધારિત ડ્રાઇવરો +Name[he]=מנהלי התקנים נתמכים +Name[hi]=समर्थित ड्राईवर +Name[hr]=Podržani pisači +Name[hu]=Támogatott meghajtók +Name[ia]=Drivers supportate +Name[id]=Penggerak Didukung +Name[is]=Studdir reklar +Name[it]=Driver supportati +Name[ja]=サポートされているドライバ +Name[kk]=Қолдайтын драйверлері +Name[km]=កម្មវិធី​បញ្ជា​ដែលបានគាំទ្រ +Name[kn]=ಬೆಂಬಲಿತ ಚಾಲಕಗಳು +Name[ko]=지원하는 드라이버 +Name[lt]=Palaikomos tvarkyklės +Name[lv]=Atbalstītie draiveri +Name[mai]=समर्थित ड्राइवर +Name[mk]=Поддржани управувачи +Name[ml]=പിന്തുണയുള്ള സാരഥികള്‍ +Name[mr]=समर्थीत ड्राइव्हर्स +Name[nb]=Støttede drivere +Name[nds]=Ünnerstütt Drievers +Name[nl]=Ondersteunde stuurprogramma's +Name[nn]=Støtta drivarar +Name[pa]=ਸਹਾਇਕ ਡਰਾਇਵਰ +Name[pl]=Obsługiwane sterowniki +Name[pt]=Controladores Suportados +Name[pt_BR]=Drivers suportados +Name[ro]=Drivere susținute +Name[ru]=Поддерживаемые драйверы +Name[si]=සහාය දක්වන ධාවක +Name[sk]=Podporované ovládače +Name[sl]=Podprti gonilniki +Name[sr]=подржани драјвери +Name[sr@ijekavian]=подржани драјвери +Name[sr@ijekavianlatin]=podržani drajveri +Name[sr@latin]=podržani drajveri +Name[sv]=Drivrutiner som stöds +Name[tg]=Дастгоҳҳои мувофиқ +Name[th]=ไดรเวอร์ที่รองรับ +Name[tr]=Desteklenen Sürücüler +Name[ug]=قوللايدىغان قوزغاتقۇلار +Name[uk]=Підтримувані драйвери +Name[wa]=Mineus sopoirtés +Name[x-test]=xxSupported Driversxx +Name[zh_CN]=支持的驱动 +Name[zh_TW]=支援的驅動程式 + +[Desktop Action supportedProtocols] +Name=Supported Protocols +Name[ar]=البروتوكولات المدعومة +Name[ast]=Protocolos sofitaos +Name[bg]=Поддържани протоколи +Name[bn]=সমর্থিত প্রোটোকল +Name[bs]=podržani protokoli +Name[ca]=Protocols acceptats +Name[ca@valencia]=Protocols acceptats +Name[cs]=Podporované protokoly +Name[csb]=Wspiéróné protokòłë +Name[da]=Understøttede protokoller +Name[de]=Unterstützte Protokolle +Name[el]=Υποστηριζόμενα πρωτόκολλα +Name[en_GB]=Supported Protocols +Name[eo]=Subtenitaj Protokoloj +Name[es]=Protocolos soportados +Name[et]=Toetatud protokollid +Name[eu]=Onartzen diren protokoloak +Name[fi]=Tuetut yhteyskäytännöt +Name[fr]=Protocoles pris en charge +Name[fy]=Stipe protokollen +Name[ga]=Prótacail a dTacaítear Leo +Name[gl]=Protocolos soportados +Name[gu]=આધારિત પ્રોટોકોલ્સ +Name[he]=פרוטוקולים נתמכים +Name[hi]=समर्थित प्रोटोकॉल +Name[hr]=Podržani Protokoli +Name[hu]=Támogatott protokollok +Name[ia]=Protocollos supportate +Name[id]=Protokol Didukung +Name[is]=Studdar samskiptareglur +Name[it]=Protocolli supportati +Name[ja]=サポートされているプロトコル +Name[kk]=Қолдайтын протоколдары +Name[km]=ពិពីការ​ដែលបានគាំទ្រ +Name[kn]=ಬೆಂಬಲಿತ ಪ್ರಕ್ರಮಗಳು (ಪ್ರೋಟೋಕಾಲ್) +Name[ko]=지원하는 프로토콜 +Name[lt]=Palaikomi protokolai +Name[lv]=Atbalstītie protokoli +Name[mk]=Поддржани протоколи +Name[ml]=പിന്തുണയ്ക്കുന്ന സമ്പ്രദായങ്ങള്‍ +Name[mr]=समर्थीत शिष्टाचार +Name[nb]=Støttede protokoller +Name[nds]=Ünnerstütt Protokollen +Name[nl]=Ondersteunde protocollen +Name[nn]=Støtta protokollar +Name[pa]=ਸਹਾਇਕ ਪਰੋਟੋਕਾਲ +Name[pl]=Obsługiwane protokoły +Name[pt]=Protocolos Suportados +Name[pt_BR]=Protocolos suportados +Name[ro]=Protocoale susținute +Name[ru]=Поддерживаемые протоколы +Name[si]=සහාය දක්වන ක්‍රියා පටිපාටි +Name[sk]=Podporované protokoly +Name[sl]=Podprti protokoli +Name[sr]=подржани протоколи +Name[sr@ijekavian]=подржани протоколи +Name[sr@ijekavianlatin]=podržani protokoli +Name[sr@latin]=podržani protokoli +Name[sv]=Protokoll som stöds +Name[tg]=Протоколҳо +Name[th]=โพรโทคอลที่รองรับ +Name[tr]=Desteklenen Protokoller +Name[ug]=قوللايدىغان كېلىشىملەر +Name[uk]=Підтримувані протоколи +Name[wa]=Protocoles sopoirtés +Name[x-test]=xxSupported Protocolsxx +Name[zh_CN]=支持的协议 +Name[zh_TW]=支援的協定 + +[Desktop Entry] +Actions=supportedDrivers;supportedProtocols; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=PortableMediaPlayer diff --git a/solid-actions-kcm/device-actions/solid-device-Processor.desktop b/solid-actions-kcm/device-actions/solid-device-Processor.desktop new file mode 100644 index 00000000..550b4671 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-Processor.desktop @@ -0,0 +1,355 @@ +[Desktop Action canChangeFrequency] +Name=Can Change Frequency +Name[ar]=يمكنه تغير التردد +Name[ast]=Pues camudar la frecuencia +Name[bg]=Може да променя честотата +Name[bn]=কম্পাঙ্ক বদলাতে পারে +Name[bs]=može da mijenja takt +Name[ca]=Pot canviar la freqüència +Name[ca@valencia]=Pot canviar la freqüència +Name[cs]=Může měnit frekvenci +Name[da]=Kan skifte frekvens +Name[de]=Kann die Frequenz wechseln +Name[el]=Δυνατότητα αλλαγής συχνότητας +Name[en_GB]=Can Change Frequency +Name[es]=Puede cambiar la frecuencia +Name[et]=Muudetava sagedusega +Name[eu]=Maiztasuna alda daiteke +Name[fi]=Osaa vaihtaa taajuutta +Name[fr]=Fréquence modifiable +Name[fy]=Kin frekwinsje feroarje +Name[ga]=Is Féidir Minicíocht a Athrú +Name[gl]=Pode mudar a frecuencia +Name[gu]=આવૃત્તિ બદલી શકે છે +Name[he]=יכול לשנות תדירות +Name[hi]=आवृत्ति बदल सकता है +Name[hr]=Može mijenjati frekvenciju +Name[hu]=Frekvenciaváltás lehetséges +Name[ia]=Il pote cambiar frequentia +Name[id]=Dapat Mengubah Frekuensi +Name[is]=Getur breytt tíðni +Name[it]=Può cambiare frequenza +Name[ja]=周波数の変更が可能 +Name[kk]=Жиілігі өзгермелі +Name[km]=អាច​ផ្លាស់ប្ដូរ​ប្រេកង់​ +Name[kn]=ಕಂಪನ ದರ(frequency) ವನ್ನು ಬದಲಾಯಿಸಬಹುದು +Name[ko]=주파수 변경 가능 +Name[lt]=Gali leisti dažnumą +Name[lv]=Var mainīt frekvenci +Name[mai]=आवृति बदलि सकैत अछि +Name[mk]=Може да смени фреквенција +Name[ml]=ആവര്‍ത്തി മാറ്റാവുന്നത് +Name[mr]=फ्रिक्वेन्सी बदलू शकतो +Name[nb]=Kan endre frekvens +Name[nds]=Kann Frequenz wesseln +Name[nl]=Kan de frequentie wijzigen +Name[nn]=Frekvens som kan endrast +Name[pa]=ਫਰੀਕਿਊਂਸੀ ਬਦਲੀ ਜਾ ਸਕਦੀ ਹੈ +Name[pl]=Z możliwością zmiany częstotliwości +Name[pt]=Pode Variar a Frequência +Name[pt_BR]=Pode alterar a frequência +Name[ro]=Poate schimba frecvența +Name[ru]=Возможность изменения частоты +Name[si]=සංඛ්‍යාතය වෙනස් කල හැක +Name[sk]=Môže meniť frekvenciu +Name[sl]=Lahko spreminja hitrost +Name[sr]=може да мења такт +Name[sr@ijekavian]=може да мијења такт +Name[sr@ijekavianlatin]=može da mijenja takt +Name[sr@latin]=može da menja takt +Name[sv]=Kan ändra frekvens +Name[th]=สามารถเปลี่ยนความถี่ได้ +Name[tr]=Frekansı Değiştirilebilir +Name[ug]=چاستوتىسىنى ئۆزگەرتكىلى بولىدۇ +Name[uk]=Може змінювати частоту +Name[vi]=Có thể thay đổi tần số +Name[wa]=Sait candjî d frecwince +Name[x-test]=xxCan Change Frequencyxx +Name[zh_CN]=可更改频率 +Name[zh_TW]=可變更頻率 + +[Desktop Action instructionSets] +Name=Instruction Sets +Name[ar]=مجموعة الأوامر +Name[ast]=Conxuntu d'instrucciones +Name[bg]=Набор инструкции +Name[bn]=ইনস্ট্রাকশন সেট +Name[bs]=skup instrukcija +Name[ca]=Jocs d'instruccions +Name[ca@valencia]=Jocs d'instruccions +Name[cs]=Instrukční sady +Name[da]=Instruktionssæt +Name[de]=Instruktions-Sätze +Name[el]=Σύνολα εντολών +Name[en_GB]=Instruction Sets +Name[es]=Conjunto de instrucciones +Name[et]=Käsustikud +Name[eu]=Instrukzio sortak +Name[fi]=Käskyjoukko +Name[fr]=Jeux d'instructions +Name[fy]=Ynstruksje set +Name[ga]=Tacair Treoracha +Name[gl]=Xogo de instrucións +Name[gu]=સૂચના સમૂહો +Name[he]=אוסף פקודות +Name[hi]=अनुदेश सेट +Name[hr]=Instrukcijski skup +Name[hu]=Utasításkészletek +Name[ia]=Insimules de instruction +Name[id]=Perangkat Instruksi +Name[is]=Inntaksaðgerðir (instruction sets) +Name[it]=Serie di istruzioni +Name[ja]=命令セット +Name[kk]=Нұсқаулар жиыны +Name[km]=សំណុំ​សេចក្ដី​ណែនាំ +Name[kn]=ಸೂಚನೆಗಳು +Name[ko]=명령어 집합 +Name[lt]=Instrukcijų rinkiniai +Name[lv]=Instrukciju kopas +Name[mk]=Инструкциски множества +Name[ml]=നിര്‍ദ്ദേശ ഗണം +Name[mr]=आज्ञा संच +Name[nb]=Instruksjonssett +Name[nds]=Anwiesen-Setten +Name[nl]=Instructiesets +Name[nn]=Instruksjonssett +Name[pa]=ਹਦਾਇਤ ਸੈੱਟ +Name[pl]=Zestawy instrukcji +Name[pt]=Conjuntos de Instruções +Name[pt_BR]=Conjuntos de instruções +Name[ro]=Seturi de instrucțiuni +Name[ru]=Наборы команд +Name[si]=උපදෙස් මාලා +Name[sk]=Inštrukčné sady +Name[sl]=Nabori ukazov +Name[sr]=скуп инструкција +Name[sr@ijekavian]=скуп инструкција +Name[sr@ijekavianlatin]=skup instrukcija +Name[sr@latin]=skup instrukcija +Name[sv]=Instruktionsuppsättningar +Name[tg]=Тарзи вуруд +Name[th]=ชุดคำสั่งต่าง ๆ +Name[tr]=Yönerge Ayarları +Name[ug]=پەرمان توپلىمى +Name[uk]=Набори команд +Name[vi]=Tập lệnh +Name[wa]=Djeus d' instruccion +Name[x-test]=xxInstruction Setsxx +Name[zh_CN]=指令集 +Name[zh_TW]=指令集 + +[Desktop Action maxSpeed] +Name=Max Speed +Name[ar]=السرعة القصوى +Name[ast]=Velocidá máx. +Name[bg]=Макс. скорост +Name[bn]=সর্বোচ্চ গতি +Name[bs]=najveća brzina +Name[ca]=Velocitat màxima +Name[ca@valencia]=Velocitat màxima +Name[cs]=Maximální rychlost +Name[csb]=Maksymalnô chùtkòsc +Name[da]=Maks. hastighed +Name[de]=Maximalgeschwindigkeit +Name[el]=Μέγιστη ταχύτητα +Name[en_GB]=Max Speed +Name[eo]=Maksimuma Rapideco +Name[es]=Velocidad máx. +Name[et]=Maks. kiirus +Name[eu]=Gehienezko abiadura +Name[fi]=Enimmäisnopeus +Name[fr]=Vitesse maximale +Name[fy]=Maks. fluggens +Name[ga]=Uasluas +Name[gl]=Velocidade máxima +Name[gu]=મહત્તમ ઝડપ +Name[he]=מהירות מירבית +Name[hi]=अधिकतम गति +Name[hr]=Maksimalna brzina +Name[hu]=Max. sebesség +Name[ia]=Velocitate maxime +Name[id]=Kecepatan Maks +Name[is]=Mesti hraði +Name[it]=Velocità massima +Name[ja]=最大速度 +Name[ka]=მაქს. სიჩქარე +Name[kk]=Жылдамдығының шегі +Name[km]=ល្បឿន​អតិបរមា +Name[kn]=ಗರಿಷ್ಟ ವೇಗ +Name[ko]=최대 속도 +Name[lt]=Maksimalus greitis +Name[lv]=Maks ātrums +Name[mk]=Maкc. брзина +Name[ml]=കൂടിയ വേഗം +Name[mr]=कमाल वेग +Name[nb]=Maks. hastighet +Name[nds]=Hööchst Gauigkeit +Name[nl]=Maximale snelheid +Name[nn]=Maksfart +Name[pa]=ਵੱਧੋ-ਵੱਧ ਸਪੀਡ +Name[pl]=Maksymalna szybkość +Name[pt]=Velocidade Máxima +Name[pt_BR]=Velocidade máxima +Name[ro]=Viteză maximă +Name[ru]=Максимальная скорость +Name[si]=උපරිම වේගය +Name[sk]=Maximálna rýchlosť +Name[sl]=Največja hitrost +Name[sr]=највећа брзина +Name[sr@ijekavian]=највећа брзина +Name[sr@ijekavianlatin]=najveća brzina +Name[sr@latin]=najveća brzina +Name[sv]=Maximal hastighet +Name[tg]=Суръати тезтарин +Name[th]=ความเร็วสูงสุด +Name[tr]=En Yüksek Hız +Name[ug]=ئەڭ چوڭ تېزلىك +Name[uk]=Макс. швидкість +Name[wa]=Radisté macsimom +Name[x-test]=xxMax Speedxx +Name[zh_CN]=最大速度 +Name[zh_TW]=最大速率 + +[Desktop Action number] +Name=Number +Name[ar]=الرقم +Name[ast]=Númberu +Name[bg]=Номер +Name[bn]=সংখ্যা +Name[bs]=broj +Name[ca]=Número +Name[ca@valencia]=Número +Name[cs]=Číslo +Name[csb]=Numer +Name[da]=Nummer +Name[de]=Nummer +Name[el]=Αριθμός +Name[en_GB]=Number +Name[eo]=Nombro +Name[es]=Número +Name[et]=Arv +Name[eu]=Zenbakia +Name[fi]=Numero +Name[fr]=Numéro +Name[fy]=Nûmer +Name[ga]=Uimhir +Name[gl]=Número +Name[gu]=ક્રમ +Name[he]=מספר +Name[hi]=संख्या +Name[hr]=Broj +Name[hu]=Szám +Name[ia]=Numero +Name[id]=Nomor +Name[is]=Fjöldi +Name[it]=Numero +Name[ja]=番号 +Name[kk]=Нөмірі +Name[km]=លេខ +Name[kn]=ಸಂಖ್ಯೆ +Name[ko]=숫자 +Name[lt]=Skaičius +Name[lv]=Numurs +Name[mk]=Број +Name[ml]=അക്കം +Name[mr]=क्रमांक +Name[nb]=Tall +Name[nds]=Nummer +Name[nl]=Nummer +Name[nn]=Nummer +Name[pa]=ਗਿਣਤੀ +Name[pl]=Numer +Name[pt]=Número +Name[pt_BR]=Número +Name[ro]=Număr +Name[ru]=Номер +Name[si]=අංකය +Name[sk]=Číslo +Name[sl]=Število +Name[sr]=број +Name[sr@ijekavian]=број +Name[sr@ijekavianlatin]=broj +Name[sr@latin]=broj +Name[sv]=Antal +Name[tg]=Рақам +Name[th]=จำนวน +Name[tr]=Numara +Name[ug]=نومۇرى +Name[uk]=Номер +Name[wa]=Nombe +Name[x-test]=xxNumberxx +Name[zh_CN]=数值 +Name[zh_TW]=數字 + +[Desktop Entry] +Actions=canChangeFrequency;instructionSets;maxSpeed;number; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=Processor diff --git a/solid-actions-kcm/device-actions/solid-device-SerialInterface.desktop b/solid-actions-kcm/device-actions/solid-device-SerialInterface.desktop new file mode 100644 index 00000000..a9c614eb --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-SerialInterface.desktop @@ -0,0 +1,258 @@ +[Desktop Action driverHandle] +Name=Driver Handle +Name[ar]=مقبض المشغل +Name[ast]=Controlador de preséu +Name[bg]=Управление на драйвера +Name[bn]=ড্রাইভার হ্যাণ্ডল +Name[bs]=ručka drajvera +Name[ca]=Gestor de controlador +Name[ca@valencia]=Gestor de controlador +Name[cs]=ID ovladače +Name[csb]=Czérownik Handle +Name[da]=Driver-handle +Name[de]=Treiber-Alias +Name[el]=Χειριστήριο οδηγού +Name[en_GB]=Driver Handle +Name[eo]=Pelila tenilo +Name[es]=Controlador de dispositivo +Name[et]=Draiveri pide +Name[eu]=Gidariaren heldulekua +Name[fi]=Ajuritunniste +Name[fr]=Gestionnaire du pilote +Name[fy]=Stjoerprograma regelaar +Name[ga]=Hanla an Tiománaí +Name[gl]=Xestión do controlador +Name[gu]=ડ્રાઇવ સંભાળનાર +Name[he]=ממשק מנהל ההתקן +Name[hi]=औजार हेंडल +Name[hr]=Pogonski program +Name[hu]=Meghajtóazonosító +Name[ia]=Maneator de driver +Name[id]=Penanganan Penggerak +Name[is]=Hald rekils +Name[ja]=ドライバハンドル +Name[kk]=Драйвер өңдеуі +Name[km]=កា​រគ្រប់គ្រង​កម្មវិធី​បញ្ជា +Name[ko]=드라이버 핸들 +Name[lt]=Tvarkyklės rankena +Name[lv]=Draivera rokturis +Name[ml]=ഉപരണത്തിന്റെ പിടി +Name[mr]=ड्राइव्हर हेंडल +Name[nb]=Drivernavn +Name[nds]=Drievergreep +Name[nl]=Stuurprogrammapook +Name[nn]=Drivarnamn +Name[pa]=ਡਰਾਇਵਰ ਹੈਂਡਲ +Name[pl]=Uchwyt sterownika +Name[pt]=Descritor do Controlador +Name[pt_BR]=Manipulador do driver +Name[ro]=Manipulare driver +Name[ru]=Драйверная ссылка на устройство +Name[si]=ධාවක අල්ලුව +Name[sk]=Rukoväť ovládača +Name[sl]=Ročica gonilnika +Name[sr]=ручка драјвера +Name[sr@ijekavian]=ручка драјвера +Name[sr@ijekavianlatin]=ručka drajvera +Name[sr@latin]=ručka drajvera +Name[sv]=Drivrutinreferens +Name[tg]=Плеери DJ-Mixer +Name[th]=การจัดการไดรเวอร์ +Name[tr]=Sürücü Tanıtıcı +Name[ug]=قوزغاتقۇ تۇتقۇسى +Name[uk]=Обробка драйвером +Name[vi]=Xử lý trình điều khiển +Name[wa]=Apougnî mineu +Name[x-test]=xxDriver Handlexx +Name[zh_CN]=驱动处理接口 +Name[zh_TW]=驅動程式處理 + +[Desktop Action port] +Name=Port +Name[ar]=المنفذ +Name[ast]=Puertu +Name[bg]=Порт +Name[bn]=পোর্ট +Name[bs]=port +Name[ca]=Port +Name[ca@valencia]=Port +Name[cs]=Port +Name[csb]=Pòrt +Name[da]=Port +Name[de]=Port +Name[el]=Θύρα +Name[en_GB]=Port +Name[eo]=Konektejo +Name[es]=Puerto +Name[et]=Port +Name[eu]=Ataka +Name[fa]=درگاه +Name[fi]=Portti +Name[fr]=Port +Name[fy]=Poarte +Name[ga]=Port +Name[gl]=Porto +Name[gu]=પોર્ટ +Name[he]=מפתח +Name[hi]=फोर्ट +Name[hr]=Port +Name[hu]=Csatlakozó +Name[ia]=Porto +Name[id]=Pangkalan +Name[is]=Gátt +Name[ja]=ポート +Name[ka]=პორტი +Name[kk]=Порты +Name[km]=ច្រក +Name[kn]=ಸಂಪರ್ಕಸ್ಥಾನ +Name[ko]=포트 +Name[lt]=Prievadas +Name[lv]=Ports +Name[mk]=Порта +Name[ml]=പോര്‍ട്ട് +Name[mr]=पोर्ट +Name[nb]=Port +Name[nds]=Port +Name[nl]=Poort +Name[nn]=Port +Name[pa]=ਪੋਰਟ +Name[pl]=Port +Name[pt]=Porta +Name[pt_BR]=Porta +Name[ro]=Port +Name[ru]=Порт +Name[si]=පේනුව +Name[sk]=Port +Name[sl]=Vrata +Name[sr]=порт +Name[sr@ijekavian]=порт +Name[sr@ijekavianlatin]=port +Name[sr@latin]=port +Name[sv]=Port +Name[tg]=Порт +Name[th]=พอร์ต +Name[tr]=Port +Name[ug]=ئېغىز +Name[uk]=Порт +Name[wa]=Pôrt +Name[x-test]=xxPortxx +Name[zh_CN]=端口 +Name[zh_TW]=連接埠 + +[Desktop Action serialType] +# ctxt: The physical type of serial port (ie. USB, RS232, etc) +Name=Serial Type +Name[bs]=Tip serijskog porta +Name[ca]=Tipus de sèrie +Name[ca@valencia]=Tipus de sèrie +Name[cs]=Typ sériového portu +Name[da]=Serialtype +Name[de]=Serieller Typ +Name[el]=Τύπος σειραϊκής +Name[en_GB]=Serial Type +Name[es]=Tipo de puerto serie +Name[et]=Jadaliidese tüüp +Name[eu]=Serie mota +Name[fi]=Sarjaportin tyyppi +Name[fr]=Type de port série +Name[gl]=Tipo de serie +Name[hu]=Csatlakozótípus +Name[ia]=Typo serial +Name[is]=Tegund raðtengis +Name[kk]=Тізбекті порт түрі +Name[ko]=시리얼 포트 종류 +Name[lt]=Serijinis tipas +Name[mr]=सिरीअल प्रकार +Name[nb]=Seriell type +Name[nds]=Seriell-Typ +Name[nl]=Type serieel +Name[pa]=ਸੀਰੀਅਲ ਟਾਈਪ +Name[pl]=Typ portu +Name[pt]=Tipo de Série +Name[pt_BR]=Tipo de serial +Name[ru]=Тип последовательного порта +Name[sk]=Sériový typ +Name[sl]=Vrsta zaporedne naprave +Name[sr]=тип серијског +Name[sr@ijekavian]=тип серијског +Name[sr@ijekavianlatin]=tip serijskog +Name[sr@latin]=tip serijskog +Name[sv]=Serietyp +Name[tr]=Seri Türü +Name[uk]=Тип послідовного інтерфейсу +Name[x-test]=xxSerial Typexx +Name[zh_CN]=串口类型 +Name[zh_TW]=序列類型 + +[Desktop Entry] +Actions=driverHandle;port;serialType; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=SerialInterface diff --git a/solid-actions-kcm/device-actions/solid-device-SmartCardReader.desktop b/solid-actions-kcm/device-actions/solid-device-SmartCardReader.desktop new file mode 100644 index 00000000..baafdd38 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-SmartCardReader.desktop @@ -0,0 +1,142 @@ +[Desktop Action readerType] +Name=Reader Type +Name[ar]=نوع القارئ +Name[ast]=Triba de llector +Name[bg]=Вид четец +Name[bn]=রিডার ধরন +Name[bs]=tip čitača +Name[ca]=Tipus de lector +Name[ca@valencia]=Tipus de lector +Name[cs]=Typ čtečky +Name[csb]=Ôrt czëtaniô +Name[da]=Læsertype +Name[de]=Lesertyp +Name[el]=Τύπος αναγνώστη +Name[en_GB]=Reader Type +Name[eo]=Tipo de Legilo +Name[es]=Tipo de lector +Name[et]=Lugeja tüüp +Name[eu]=Irakurgailu mota +Name[fi]=Lukijatyyppi +Name[fr]=Type de lecteur +Name[fy]=Lês type +Name[ga]=Cineál an Léitheora +Name[gl]=Tipo de lector +Name[gu]=વાંચન પ્રકાર +Name[he]=סוג קורא +Name[hi]=रीडर प्रकार +Name[hr]=Vrsta čitača +Name[hu]=Olvasótípus +Name[ia]=Typo de lector +Name[id]=Tipe Pembaca +Name[is]=Gerð lesara +Name[ja]=リーダーのタイプ +Name[kk]=Оқу құралының түрі +Name[km]=ប្រភេទ​កម្មវិធី​អាន +Name[kn]=ಓದುಗನ ಬಗೆ +Name[ko]=리더 종류 +Name[lt]=Skaitymo tipas +Name[lv]=Lasītāja tips +Name[mk]=Тип на читач +Name[ml]=റീഡറിന്റെ തരം +Name[mr]=वाचक प्रकार +Name[nb]=Lesertype +Name[nds]=Lesertyp +Name[nl]=Type reader +Name[nn]=Lesartype +Name[pa]=ਰੀਡਰ ਟਾਈਪ +Name[pl]=Typ czytnika +Name[pt]=Tipo de Leitor +Name[pt_BR]=Tipo de leitor +Name[ro]=Tip cititor +Name[ru]=Тип устройства чтения +Name[si]=කියවන්නාගේ වර්ගය +Name[sk]=Typ čítačky +Name[sl]=Vrsta bralnika +Name[sr]=тип читача +Name[sr@ijekavian]=тип читача +Name[sr@ijekavianlatin]=tip čitača +Name[sr@latin]=tip čitača +Name[sv]=Typ av läsare +Name[tg]=Намуди хондан +Name[th]=ประเภทของตัวอ่าน +Name[tr]=Okuyucu Tipi +Name[ug]=ئوقۇغۇچ تىپى +Name[uk]=Тип засобу зчитування +Name[wa]=Sôre do lijheu +Name[x-test]=xxReader Typexx +Name[zh_CN]=读取器类型 +Name[zh_TW]=讀取器型態 + +[Desktop Entry] +Actions=readerType; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=SmartCardReader diff --git a/solid-actions-kcm/device-actions/solid-device-StorageAccess.desktop b/solid-actions-kcm/device-actions/solid-device-StorageAccess.desktop new file mode 100644 index 00000000..256c6226 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-StorageAccess.desktop @@ -0,0 +1,217 @@ +[Desktop Action accessible] +Name=Accessible +Name[ar]=متاح +Name[ast]=Accesible +Name[bg]=Достъпен +Name[bn]=সহায়ক প্রযুক্তি +Name[bs]=pristupan +Name[ca]=Accessible +Name[ca@valencia]=Accessible +Name[cs]=Přístupné +Name[csb]=Pòmòce przëstãpù +Name[da]=Tilgængelig +Name[de]=Verfügbar +Name[el]=Προσβάσιμο +Name[en_GB]=Accessible +Name[eo]=Atingebla +Name[es]=Accesible +Name[et]=Juurdepääsuga +Name[eu]=Eskuragarri +Name[fi]=Saatavilla +Name[fr]=Accessible +Name[fy]=Tagonklik +Name[ga]=Inrochtana +Name[gl]=Accesíbel +Name[gu]=ઉપયોગી +Name[he]=נגיש +Name[hi]=पहुँच योग्य +Name[hr]=Pristupačan +Name[hu]=Elérhető +Name[ia]=Accessibile +Name[id]=Dapat Diakses +Name[is]=Aðgengilegt +Name[it]=Accessibile +Name[ja]=アクセス可能 +Name[kk]=Қол жетерлік +Name[km]=អាច​ចូលដំណើរការ​បាន +Name[kn]=ನಿಲುಕಬಲ್ಲ +Name[ko]=접근 가능 여부 +Name[lt]=Prieinamas +Name[lv]=Pieejams +Name[mk]=Пристапно +Name[ml]=സാമീപിയ്ക്കാവുന്നതു് +Name[mr]=सुलभ +Name[nb]=Tilgjengelig +Name[nds]=Togriepbor +Name[nl]=Toegankelijk +Name[nn]=Tilgjengeleg +Name[pa]=ਸਹੂਲਤਾਂ +Name[pl]=Dostępny +Name[pt]=Acessível +Name[pt_BR]=Acessível +Name[ro]=Accesibil +Name[ru]=Доступно +Name[si]=ප්‍රවේශවිය හැකි +Name[sk]=Prístupné +Name[sl]=Dostopno +Name[sr]=приступан +Name[sr@ijekavian]=приступан +Name[sr@ijekavianlatin]=pristupan +Name[sr@latin]=pristupan +Name[sv]=Tillgänglig +Name[tg]=Имкониятҳо +Name[th]=เข้าถึงได้ +Name[tr]=Erişilebilir +Name[ug]=زىيارەتچان +Name[uk]=Доступний +Name[vi]=Truy cập được +Name[wa]=Arinnåve +Name[x-test]=xxAccessiblexx +Name[zh_CN]=可访问 +Name[zh_TW]=可存取 + +[Desktop Action filePath] +Name=File Path +Name[ar]=مسار الملف +Name[ast]=Camín a ficheru +Name[bg]=Път до файл +Name[bn]=ফাইল পাথ +Name[bs]=putanja datoteke +Name[ca]=Camí al fitxer +Name[ca@valencia]=Camí al fitxer +Name[cs]=Cesta k souboru +Name[csb]=Stegna lopka +Name[da]=Filsti +Name[de]=Dateipfad +Name[el]=Διαδρομή αρχείου +Name[en_GB]=File Path +Name[eo]=Dosiervojo +Name[es]=Ruta a archivo +Name[et]=Faili asukoht +Name[eu]=Fitxategiaren bide-izena +Name[fa]=مسیر پرونده +Name[fi]=Tiedostopolku +Name[fr]=Emplacement du fichier +Name[fy]=Triem paad +Name[ga]=Conair Chomhaid +Name[gl]=Ruta ao ficheiro +Name[gu]=ફાઇલ પાથ +Name[he]=נתיב קובץ +Name[hi]=फ़ाइल पथ +Name[hr]=Putanja datoteke +Name[hu]=Elérési út +Name[ia]=Percurso de file +Name[id]=Alamat Berkas +Name[is]=Skráarslóð +Name[it]=Percorso di file +Name[ja]=ファイルのパス +Name[kk]=Файл жолы +Name[km]=ផ្លូវ​ឯកសារ +Name[kn]=ಕಡತದ ಮಾರ್ಗ +Name[ko]=파일 경로 +Name[lt]=Failo kelias +Name[lv]=Faila ceļš +Name[mk]=Патека на датотека +Name[ml]=ഫയല്‍ വഴി +Name[mr]=फाईलचा मार्ग +Name[nb]=Filsti +Name[nds]=Dateipadd +Name[nl]=Bestandspad +Name[nn]=Filadresse +Name[pa]=ਫਾਇਲ ਪਾਥ +Name[pl]=Ścieżka do pliku +Name[pt]=Localização do Ficheiro +Name[pt_BR]=Caminho do arquivo +Name[ro]=Calea fișierului +Name[ru]=Путь к файлу +Name[si]=ගොනු පෙත +Name[sk]=Cesta k súboru +Name[sl]=Pot do datoteke +Name[sr]=путања фајла +Name[sr@ijekavian]=путања фајла +Name[sr@ijekavianlatin]=putanja fajla +Name[sr@latin]=putanja fajla +Name[sv]=Filsökväg +Name[tg]=Роҳи файл +Name[th]=พาธของแฟ้ม +Name[tr]=Dosya Yolu +Name[ug]=ھۆججەت يولى +Name[uk]=Шлях до файла +Name[vi]=Đường dẫn tập tin +Name[wa]=Tchimin do fitchî +Name[x-test]=xxFile Pathxx +Name[zh_CN]=文件路径 +Name[zh_TW]=檔案路徑 + +[Desktop Entry] +Actions=accessible;filePath; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=StorageAccess diff --git a/solid-actions-kcm/device-actions/solid-device-StorageDrive.desktop b/solid-actions-kcm/device-actions/solid-device-StorageDrive.desktop new file mode 100644 index 00000000..5627c0b4 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-StorageDrive.desktop @@ -0,0 +1,434 @@ +[Desktop Action bus] +Name=Bus +Name[ar]=الناقل +Name[ast]=Bus +Name[bg]=Шина +Name[bn]=বাস +Name[bs]=magistrala +Name[ca]=Bus +Name[ca@valencia]=Bus +Name[cs]=Sběrnice +Name[csb]=Bus +Name[da]=Bus +Name[de]=Bus +Name[el]=Δίαυλος +Name[en_GB]=Bus +Name[eo]=Buso +Name[es]=Bus +Name[et]=Siin +Name[eu]=Busa +Name[fa]=گذرگاه +Name[fi]=Väylä +Name[fr]=Bus +Name[fy]=Bus +Name[ga]=Bus +Name[gl]=Bus +Name[gu]=બસ +Name[he]=אפיק +Name[hi]=बस +Name[hr]=Sabirnica +Name[hu]=Busz +Name[ia]=Bus +Name[id]=Bus +Name[is]=Rás (bus) +Name[it]=Bus +Name[ja]=バス +Name[ka]=სალტე +Name[kk]=Шинасы +Name[km]=ខ្សែបញ្ជូន +Name[kn]=ಬಸ್ +Name[ko]=버스 +Name[lt]=Magistralė +Name[lv]=Kopne +Name[mk]=Магистрала +Name[ml]=ബസ് +Name[mr]=बस +Name[nb]=Buss +Name[nds]=Bus +Name[nl]=Bus +Name[nn]=Buss +Name[pa]=ਬਸ +Name[pl]=Szyna +Name[pt]=Barramento +Name[pt_BR]=Barramento +Name[ro]=Magistrală +Name[ru]=Шина +Name[si]=Bus +Name[sk]=Zbernica +Name[sl]=Vodilo +Name[sr]=магистрала +Name[sr@ijekavian]=магистрала +Name[sr@ijekavianlatin]=magistrala +Name[sr@latin]=magistrala +Name[sv]=Buss +Name[tg]=Белоруссия +Name[th]=ระบบบัส +Name[tr]=Yol +Name[ug]=باش لىنىيە +Name[uk]=Шина +Name[wa]=Bus +Name[x-test]=xxBusxx +Name[zh_CN]=总线 +Name[zh_TW]=匯流排 + +[Desktop Action driveType] +Name=Drive Type +Name[ar]=نوع المشغل +Name[ast]=Triba de discu +Name[bg]=Вид устройство +Name[bn]=ড্রাইভ-এর ধরন +Name[bs]=tip jedinice +Name[ca]=Tipus d'unitat +Name[ca@valencia]=Tipus d'unitat +Name[cs]=Typ mechaniky +Name[csb]=Ôrt nëka +Name[da]=Drevtype +Name[de]=Laufwerkstyp +Name[el]=Τύπος οδηγού +Name[en_GB]=Drive Type +Name[eo]=Tipo de Diskingo +Name[es]=Tipo de disco +Name[et]=Seadme tüüp +Name[eu]=Unitate mota +Name[fi]=Asematyyppi +Name[fr]=Type de lecteur +Name[fy]=Stasjons type +Name[ga]=Cineál an Tiomántáin +Name[gl]=Tipo de dispositivo +Name[gu]=ડ્રાઇવ પ્રકાર +Name[he]=סוג כונן +Name[hi]=ड्राईव प्रकार +Name[hr]=Tip uređaja +Name[hu]=Meghajtótípus +Name[ia]=Typo de drive +Name[id]=Tipe Penggerak +Name[is]=Gerð drifs +Name[it]=Tipo di unità +Name[ja]=ドライブのタイプ +Name[ka]=ამძრავის ტიპი +Name[kk]=Жетек түрі +Name[km]=ប្រភេទ​ដ្រាយ +Name[kn]=ಡ್ರೈವಿನ ಬಗೆ +Name[ko]=드라이브 종류 +Name[lt]=Diskasukio tipas +Name[lv]=Dziņa tips +Name[mai]=ड्राइव प्रकार +Name[mk]=Тип на уред +Name[ml]=ഡ്രൈവിന്റെ തരം +Name[mr]=ड्राइव्ह प्रकार +Name[nb]=Drev-type +Name[nds]=Loopwark-Typ +Name[nl]=Apparaattype +Name[nn]=Einingstype +Name[pa]=ਡਰਾਇਵਰ ਕਿਸਮ +Name[pl]=Typ napędu +Name[pt]=Tipo de Unidade +Name[pt_BR]=Tipo de unidade +Name[ro]=Tip unitate +Name[ru]=Тип устройства +Name[si]=ධාවක වර්ගය +Name[sk]=Typ mechaniky +Name[sl]=Vrsta pogona +Name[sr]=тип јединице +Name[sr@ijekavian]=тип јединице +Name[sr@ijekavianlatin]=tip jedinice +Name[sr@latin]=tip jedinice +Name[sv]=Enhetstyp +Name[tg]=Намуди дастгоҳ +Name[th]=ประเภทของไดรฟ์ +Name[tr]=Sürücü Tipi +Name[ug]=قوزغاتقۇ تىپى +Name[uk]=Тип пристрою +Name[vi]=Kiểu trình điều khiển +Name[wa]=Sôre di lijheu +Name[x-test]=xxDrive Typexx +Name[zh_CN]=驱动类型 +Name[zh_TW]=磁碟型態 + +[Desktop Action hotpluggable] +Name=Hotpluggable +Name[ar]=قابل للتوصيل +Name[ast]=Conexón en caliente +Name[bn]=হট-প্লাগ-যোগ্য +Name[bs]=vruće uključiva +Name[ca]=Connectable en calent +Name[ca@valencia]=Connectable en calent +Name[cs]=Hotplug +Name[da]=Flytbar +Name[de]=Hotplug-fähig +Name[el]=Δυνατότητα Hotplug +Name[en_GB]=Hotpluggable +Name[eo]=Dumkure permutebla +Name[es]=Conexión en caliente +Name[et]=Töö ajal ühendatav +Name[eu]=Hotplug-erako gaitua +Name[fi]=Lennossakytkettävä +Name[fr]=Connectable à chaud +Name[fy]=Hotplug barren +Name[ga]=Inphlugáilte +Name[gl]=Conectábel en quente +Name[gu]=હોટપ્લગેબલ +Name[he]=החלפה חמה +Name[hi]=हाटप्लग योग्य +Name[hr]=Podržava brzo uštekavanje +Name[hu]=Menet közben csatlakoztatható +Name[ia]=Hotpluggable (On pote connecter lo con machina active) +Name[id]=Dapat di-Hotplug +Name[is]=Hraðtengjanlegt (hotplug) +Name[it]=Collegabile in marcia +Name[ja]=Hotplug 可能 +Name[kk]=Істеп турғанда қосылмалы +Name[km]=ដោតដើរ +Name[kn]=ಹಾಟ್‌ಪ್ಲಗ್‌ ಮಾಡಬಹುದಾದ +Name[ko]=핫플러그 가능 +Name[lt]=Greitai prijungiamas +Name[lv]=Karsti nomaināms +Name[ml]=ഹോട്ട്പ്ലഗ് ചെയ്യാവുന്ന +Name[mr]=हॉटप्लग करता येणारे +Name[nb]=Kan kobles til påslått +Name[nds]=Jümmers tokoppelbor +Name[nl]=Hotplugbaar +Name[nn]=Hotplug-kompatibel +Name[pa]=ਹਾਟਪਲੱਗਯੋਗ +Name[pl]=Podłączany "na gorąco" +Name[pt]=Conectável em Funcionamento +Name[pt_BR]=Conectável em funcionamento +Name[ro]=Detașabil +Name[ru]=Подключается в любое время +Name[si]=Hotpluggable +Name[sk]=Hotplug +Name[sl]=Priključljivo med delovanjem +Name[sr]=вруће укључива +Name[sr@ijekavian]=вруће укључива +Name[sr@ijekavianlatin]=vruće uključiva +Name[sr@latin]=vruće uključiva +Name[sv]=Inkopplingsbar +Name[tg]=Дастгоҳҳои пайвастшаванда +Name[th]=สามารถถอดเสียบได้ +Name[tr]=Çıkarılıp takılabilir +Name[ug]=ئىسسىق چېتىلىشچان +Name[uk]=«Гаряче» з’єднання +Name[vi]=Tháo lắp nóng +Name[wa]=Hotplugåve +Name[x-test]=xxHotpluggablexx +Name[zh_CN]=可热插拔 +Name[zh_TW]=可熱插拔 + +[Desktop Action removable] +Name=Removable +Name[ar]=قابل للإزالة +Name[ast]=Estrayible +Name[bg]=Преносим +Name[bn]=অপসারণযোগ্য +Name[bs]=uklonjiva +Name[ca]=Extraïble +Name[ca@valencia]=Extraïble +Name[cs]=Odpojitelný +Name[csb]=Przenosné +Name[da]=Flytbar +Name[de]=Wechselbar +Name[el]=Αφαιρούμενο μέσο +Name[en_GB]=Removable +Name[eo]=Demetebla +Name[es]=Extraíble +Name[et]=Eemaldatav +Name[eu]=Aldagarria +Name[fa]=جدا شدنی +Name[fi]=Poistettavissa +Name[fr]=Amovible +Name[fy]=Te ferwiderjen +Name[ga]=Inbhainte +Name[gl]=Eliminábel +Name[gu]=દૂર કરી શકાય તેવું +Name[he]=ניתן להסרה +Name[hi]=हटाने योग्य +Name[hr]=Moguće ga je izvaditi +Name[hu]=Cserélhető +Name[ia]=Removibile +Name[id]=Dapat Dilepaskan +Name[is]=Fjarlægjanlegt +Name[it]=Rimovibile +Name[ja]=リムーバブル +Name[kk]=Ауыстырмалы +Name[km]=អាច​យក​ចេញ​បាន +Name[kn]=ತೆಗೆಯಬಹುದಾದ +Name[ko]=제거 가능 +Name[lt]=Keičiamas +Name[lv]=Noņemams +Name[mai]=हटबैयोग्य +Name[mk]=Подвижен +Name[ml]=നീക്കം ചെയ്യാവുന്ന +Name[mr]=काढता येणारे +Name[nb]=Flyttbar +Name[nds]=Tuuschbor +Name[nl]=Verwijderbaar +Name[nn]=Flyttbar +Name[pa]=ਹਟਾਉਣਯੋਗ +Name[pl]=Wymienny +Name[pt]=Removível +Name[pt_BR]=Removível +Name[ro]=Amovibil +Name[ru]=Сменный носитель +Name[si]=ඉවත්කල හැකි +Name[sk]=Vymeniteľné +Name[sl]=Odstranljivo +Name[sr]=уклоњива +Name[sr@ijekavian]=уклоњива +Name[sr@ijekavianlatin]=uklonjiva +Name[sr@latin]=uklonjiva +Name[sv]=Flyttbar +Name[tg]=Дастгоҳи ҷудошаванда +Name[th]=ถอดเสียบได้ +Name[tr]=Çıkarılabilir +Name[ug]=كۆچمە +Name[uk]=Змінний пристрій +Name[wa]=Bodjåve +Name[x-test]=xxRemovablexx +Name[zh_CN]=移动 +Name[zh_TW]=可移除 + +[Desktop Action size] +Name=Size +Name[ar]=الحجم +Name[ast]=Tamañu +Name[bg]=Големина +Name[bn]=মাপ +Name[bs]=veličina +Name[ca]=Mida +Name[ca@valencia]=Mida +Name[cs]=Velikost +Name[csb]=Miara +Name[da]=Størrelse +Name[de]=Größe +Name[el]=Μέγεθος +Name[en_GB]=Size +Name[eo]=Grandeco +Name[es]=Tamaño +Name[et]=Suurus +Name[eu]=Neurria +Name[fa]=اندازه +Name[fi]=Koko +Name[fr]=Taille +Name[fy]=Grutte +Name[ga]=Méid +Name[gl]=Tamaño +Name[gu]=માપ +Name[he]=גודל +Name[hi]=आकार +Name[hr]=Veličina +Name[hu]=Méret +Name[ia]=Dimension +Name[id]=Ukuran +Name[is]=Stærð +Name[it]=Dimensione +Name[ja]=サイズ +Name[ka]=ზომა +Name[kk]=Көлемі +Name[km]=ទំហំ +Name[kn]=ಗಾತ್ರ +Name[ko]=크기 +Name[lt]=Dydis +Name[lv]=Izmērs +Name[mk]=Големина +Name[ml]=വലിപ്പം +Name[mr]=आकार +Name[nb]=Størrelse +Name[nds]=Grött +Name[nl]=Grootte +Name[nn]=Storleik +Name[pa]=ਸਾਈਜ਼ +Name[pl]=Rozmiar +Name[pt]=Tamanho +Name[pt_BR]=Tamanho +Name[ro]=Dimensiune +Name[ru]=Размер +Name[si]=ප්‍රමාණය +Name[sk]=Veľkosť +Name[sl]=Velikost +Name[sr]=величина +Name[sr@ijekavian]=величина +Name[sr@ijekavianlatin]=veličina +Name[sr@latin]=veličina +Name[sv]=Storlek +Name[tg]=Андоза +Name[th]=ขนาด +Name[tr]=Boyut +Name[ug]=چوڭلۇقى +Name[uk]=Розмір +Name[wa]=Grandeu +Name[x-test]=xxSizexx +Name[zh_CN]=大小 +Name[zh_TW]=大小 + +[Desktop Entry] +Actions=bus;driveType;hotpluggable;removable;size; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=StorageDrive diff --git a/solid-actions-kcm/device-actions/solid-device-StorageVolume.desktop b/solid-actions-kcm/device-actions/solid-device-StorageVolume.desktop new file mode 100644 index 00000000..8090b2d5 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-StorageVolume.desktop @@ -0,0 +1,507 @@ +[Desktop Action fsType] +Name=Fs Type +Name[ar]=نوع نظام الملفات +Name[ast]=Triba de Fs +Name[bg]=Вид файлова система +Name[bn]=Fs ধরন +Name[bs]=tip fsis. +Name[ca]=Tipus de sistema de fitxers +Name[ca@valencia]=Tipus de sistema de fitxers +Name[cs]=Typ FS +Name[csb]=Ôrt Fs +Name[da]=FS-type +Name[de]=Dateisystemtyp +Name[el]=Τύπος συστήματος αρχείων +Name[en_GB]=Fs Type +Name[eo]=Dosiersistema Tipo +Name[es]=Tipo de s. a. +Name[et]=Failisüsteemi tüüp +Name[eu]=Fitxategi-sistema mota +Name[fi]=Tiedostojärjestelmän tyyppi +Name[fr]=Type de système de fichiers +Name[fy]=Fs type +Name[ga]=Cineál an Chórais Comhad +Name[gl]=Sistema de ficheiros +Name[gu]=Fs પ્રકાર +Name[he]=סוג מערכת קבצים +Name[hi]=Fs प्रकार +Name[hr]=Tip datotečnog sustava +Name[hu]=Fájlrendszer +Name[ia]=Typo Fs +Name[id]=Tipe Sistem Berkas +Name[is]=Tegund skráakerfis +Name[it]=Tipo di filesystem +Name[ja]=Fs タイプ +Name[kk]=ФЖ түрі +Name[km]=ប្រភេទ Fs +Name[kn]=Fs ಬಗೆ +Name[ko]=파일 시스템 종류 +Name[lt]=FS tipas +Name[lv]=FS tips +Name[mai]=Fs प्रकार +Name[mk]=Тип на дат. систем +Name[ml]=ഫയല്‍ വ്യവസ്ഥയുടെ തരം +Name[mr]=Fs प्रकार +Name[nb]=Filsystemtype +Name[nds]=Dateisysteem-Typ +Name[nl]=FS-type +Name[nn]=Filsystemtype +Name[pa]=Fs ਕਿਸਮ +Name[pl]=Typ systemu plików +Name[pt]=Tipo de SF +Name[pt_BR]=Tipo de sistema de arquivos +Name[ro]=Tipul SF +Name[ru]=Файловая система +Name[si]=Fs වර්ගය +Name[sk]=Typ FS +Name[sl]=Vrsta dat. sist. +Name[sr]=тип фсис. +Name[sr@ijekavian]=тип фсис. +Name[sr@ijekavianlatin]=tip fsis. +Name[sr@latin]=tip fsis. +Name[sv]=Filsystemtyp +Name[tg]=Намуди Fs +Name[th]=ประเภทของระบบแฟ้ม +Name[tr]=Dosya Sistemi Tipi +Name[ug]=ھۆججەت سىستېما تىپى +Name[uk]=Тип ФС +Name[vi]=Kiểu hệ thống tập tin +Name[wa]=Sôre di Fs +Name[x-test]=xxFs Typexx +Name[zh_CN]=文件系统类型 +Name[zh_TW]=檔案系統型態 + +[Desktop Action ignored] +Name=Ignored +Name[ar]=متجاهَل +Name[ast]=Inoráu +Name[bg]=Пренебрегнат +Name[bn]=উপেক্ষিত +Name[bs]=ignorisan +Name[ca]=Ignorat +Name[ca@valencia]=Ignorat +Name[cs]=Ignorováno +Name[csb]=Ignorowóné +Name[da]=Ignoreret +Name[de]=Ignoriert +Name[el]=Παράβλεψη +Name[en_GB]=Ignored +Name[eo]=Ignorita +Name[es]=Ignorado +Name[et]=Eiratav +Name[eu]=Ez ikusi eginda +Name[fi]=Ei otettu huomioon +Name[fr]=Ignoré +Name[fy]=Negearre +Name[ga]=Neamhaird Déanta De +Name[gl]=Ignorado +Name[gu]=અવગણેલ +Name[he]=התעלם +Name[hi]=उपेक्षित +Name[hr]=Zanemareno +Name[hu]=Nem kezelt +Name[ia]=Ignorate +Name[id]=Diabaikan +Name[is]=Hunsað +Name[it]=Ignorato +Name[ja]=無視 +Name[kk]=Еленбеген +Name[km]=បានមិនអើពើ +Name[kn]=ಆಲಕ್ಷಿತ +Name[ko]=무시됨 +Name[lt]=Ignoruota +Name[lv]=Ignorēts +Name[mk]=Игнорирано +Name[ml]=അവഗണിച്ചു +Name[mr]=उपेक्षित +Name[nb]=Ignorert +Name[nds]=Övergahn +Name[nl]=Genegeerd +Name[nn]=Oversett +Name[pa]=ਅਣਡਿੱਠ ਕੀਤਾ +Name[pl]=Ignorowany +Name[pt]=Ignorado +Name[pt_BR]=Ignorado +Name[ro]=Ignorat +Name[ru]=Игнорируется +Name[si]=නොතැකූ +Name[sk]=Ignorované +Name[sl]=Prezrto +Name[sr]=игнорисан +Name[sr@ijekavian]=игнорисан +Name[sr@ijekavianlatin]=ignorisan +Name[sr@latin]=ignorisan +Name[sv]=Ignorerad +Name[tg]=Радшуда +Name[th]=ไม่สนใจ +Name[tr]=Yoksayılmış +Name[ug]=پەرۋا قىلمىدى +Name[uk]=Ігнорується +Name[vi]=Bỏ qua +Name[wa]=Passé houte +Name[x-test]=xxIgnoredxx +Name[zh_CN]=已忽略 +Name[zh_TW]=忽略 + +[Desktop Action label] +Name=Label +Name[ar]=التسمية +Name[ast]=Etiqueta +Name[bg]=Етикет +Name[bn]=লেবেল +Name[bs]=etiketa +Name[ca]=Etiqueta +Name[ca@valencia]=Etiqueta +Name[cs]=Popisek +Name[csb]=Znakòwnik +Name[da]=Etiket +Name[de]=Beschriftung +Name[el]=Ετικέτα +Name[en_GB]=Label +Name[eo]=Labelo +Name[es]=Etiqueta +Name[et]=Pealdis +Name[eu]=Etiketa +Name[fa]=برچسب +Name[fi]=Nimike +Name[fr]=Étiquette +Name[fy]=Lebel +Name[ga]=Lipéad +Name[gl]=Etiqueta +Name[gu]=લેબલ +Name[he]=תוויות +Name[hi]=लेबल +Name[hr]=Natpis +Name[hu]=Címke +Name[ia]=Etiquetta +Name[id]=Label +Name[is]=Merking +Name[it]=Etichetta +Name[ja]=ラベル +Name[kk]=Тамғасы +Name[km]=ស្លាក +Name[kn]=ಗುರುತುಪಟ್ಟಿ +Name[ko]=레이블 +Name[lt]=Etiketė +Name[lv]=Etiķete +Name[mk]=Натпис +Name[ml]=ലേബല്‍ +Name[mr]=लेबल +Name[nb]=Etikett +Name[nds]=Beteker +Name[nl]=Label +Name[nn]=Merkelapp +Name[pa]=ਲੇਬਲ +Name[pl]=Etykieta +Name[pt]=Legenda +Name[pt_BR]=Rótulo +Name[ro]=Etichetă +Name[ru]=Метка +Name[si]=ලේබලය +Name[sk]=Štítok +Name[sl]=Oznaka +Name[sr]=етикета +Name[sr@ijekavian]=етикета +Name[sr@ijekavianlatin]=etiketa +Name[sr@latin]=etiketa +Name[sv]=Etikett +Name[tg]=Тамға +Name[th]=แถบป้าย +Name[tr]=Etiket +Name[ug]=ئەن +Name[uk]=Мітка +Name[vi]=Nhãn +Name[wa]=Etikete +Name[x-test]=xxLabelxx +Name[zh_CN]=标签 +Name[zh_TW]=標籤 + +[Desktop Action size] +Name=Size +Name[ar]=الحجم +Name[ast]=Tamañu +Name[bg]=Големина +Name[bn]=মাপ +Name[bs]=veličina +Name[ca]=Mida +Name[ca@valencia]=Mida +Name[cs]=Velikost +Name[csb]=Miara +Name[da]=Størrelse +Name[de]=Größe +Name[el]=Μέγεθος +Name[en_GB]=Size +Name[eo]=Grandeco +Name[es]=Tamaño +Name[et]=Suurus +Name[eu]=Neurria +Name[fa]=اندازه +Name[fi]=Koko +Name[fr]=Taille +Name[fy]=Grutte +Name[ga]=Méid +Name[gl]=Tamaño +Name[gu]=માપ +Name[he]=גודל +Name[hi]=आकार +Name[hr]=Veličina +Name[hu]=Méret +Name[ia]=Dimension +Name[id]=Ukuran +Name[is]=Stærð +Name[it]=Dimensione +Name[ja]=サイズ +Name[ka]=ზომა +Name[kk]=Көлемі +Name[km]=ទំហំ +Name[kn]=ಗಾತ್ರ +Name[ko]=크기 +Name[lt]=Dydis +Name[lv]=Izmērs +Name[mk]=Големина +Name[ml]=വലിപ്പം +Name[mr]=आकार +Name[nb]=Størrelse +Name[nds]=Grött +Name[nl]=Grootte +Name[nn]=Storleik +Name[pa]=ਸਾਈਜ਼ +Name[pl]=Rozmiar +Name[pt]=Tamanho +Name[pt_BR]=Tamanho +Name[ro]=Dimensiune +Name[ru]=Размер +Name[si]=ප්‍රමාණය +Name[sk]=Veľkosť +Name[sl]=Velikost +Name[sr]=величина +Name[sr@ijekavian]=величина +Name[sr@ijekavianlatin]=veličina +Name[sr@latin]=veličina +Name[sv]=Storlek +Name[tg]=Андоза +Name[th]=ขนาด +Name[tr]=Boyut +Name[ug]=چوڭلۇقى +Name[uk]=Розмір +Name[wa]=Grandeu +Name[x-test]=xxSizexx +Name[zh_CN]=大小 +Name[zh_TW]=大小 + +[Desktop Action usage] +Name=Usage +Name[ar]=الاستعمال +Name[ast]=Usu +Name[bg]=Използване +Name[bn]=ব্যবহার +Name[bs]=upotreba +Name[ca]=Ús +Name[ca@valencia]=Ús +Name[cs]=Použití +Name[csb]=Brëkòwóné +Name[da]=Brug +Name[de]=Verwendung +Name[el]=Χρήση +Name[en_GB]=Usage +Name[eo]=Uzado +Name[es]=Uso +Name[et]=Kasutus +Name[eu]=Erabilera +Name[fi]=Käyttötaso +Name[fr]=Usage +Name[fy]=Brûkens +Name[ga]=Úsáid +Name[gl]=Uso +Name[gu]=વપરાશ +Name[he]=שימוש +Name[hi]=उपयोग +Name[hr]=Iskorištenost +Name[hu]=Kihasználtság +Name[ia]=Usage +Name[id]=Penggunaan +Name[is]=Notkun +Name[it]=Uso +Name[ja]=使用率 +Name[ka]=გამოყენება +Name[kk]=Толуы +Name[km]=កា​រប្រើប្រាស់ +Name[kn]=ಬಳಕೆ +Name[ko]=사용량 +Name[lt]=Naudojimas +Name[lv]=Izlietojums +Name[mk]=Користење +Name[ml]=ഉപയോഗരീതി +Name[mr]=वापर +Name[nb]=Bruk +Name[nds]=Bruuk +Name[nl]=Gebruik +Name[nn]=Bruk +Name[pa]=ਵਰਤੋਂ +Name[pl]=Wykorzystanie +Name[pt]=Utilização +Name[pt_BR]=Uso +Name[ro]=Utilizare +Name[ru]=Использование +Name[si]=භාවිතය +Name[sk]=Použitie +Name[sl]=Poraba +Name[sr]=употреба +Name[sr@ijekavian]=употреба +Name[sr@ijekavianlatin]=upotreba +Name[sr@latin]=upotreba +Name[sv]=Användning +Name[tg]=Истифодабарӣ +Name[th]=วิธีใช้ +Name[tr]=Kullanım +Name[ug]=ئىشلىتىلىشى +Name[uk]=Використання +Name[wa]=Eployaedje +Name[x-test]=xxUsagexx +Name[zh_CN]=已用量 +Name[zh_TW]=使用量 + +[Desktop Action uuid] +Name=Uuid +Name[ar]=المعرف الفريد عالمياً (Uuid) +Name[ast]=Uuid +Name[bg]=Uuid +Name[bn]=Uuid +Name[bs]=UUID +Name[ca]=UUID +Name[ca@valencia]=UUID +Name[cs]=Uuid +Name[csb]=Uuid +Name[da]=Uuid +Name[de]=UUID +Name[el]=Uuid +Name[en_GB]=Uuid +Name[eo]=Uuid +Name[es]=Uuid +Name[et]=Uuid +Name[eu]=UUIDa +Name[fi]=Uuid +Name[fr]=Uuid +Name[fy]=Uuid +Name[ga]=Uuid +Name[gl]=Uuid +Name[gu]=Uuid +Name[he]=Uuid +Name[hi]=Uuid +Name[hr]=UUID +Name[hu]=UUID +Name[ia]=Uuid +Name[id]=Uuid +Name[is]=UUID +Name[it]=Uuid +Name[ja]=UUID +Name[ka]=Uuid +Name[kk]=Uuid +Name[km]=Uuid +Name[kn]=Uuid +Name[ko]=UUID +Name[lt]=Uuid +Name[lv]=Uuid +Name[mk]=Uuid +Name[ml]=യുയുഐഡി +Name[mr]=Uuid +Name[nb]=Uuid +Name[nds]=UUID +Name[nl]=Uuid +Name[nn]=UUID +Name[pa]=Uuid +Name[pl]=Uuid +Name[pt]=UUID +Name[pt_BR]=UUID +Name[ro]=Uuid +Name[ru]=UUID +Name[si]=Uuid +Name[sk]=Uuid +Name[sl]=UUID +Name[sr]=УУИД +Name[sr@ijekavian]=УУИД +Name[sr@ijekavianlatin]=UUID +Name[sr@latin]=UUID +Name[sv]=Uuid +Name[tg]=Phluid +Name[th]=ค่า Uuid +Name[tr]=Uuid +Name[ug]=Uuid +Name[uk]=Uuid +Name[wa]=Uuid +Name[x-test]=xxUuidxx +Name[zh_CN]=UUID +Name[zh_TW]=UUID + +[Desktop Entry] +Actions=fsType;ignored;label;size;usage;uuid; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=StorageVolume diff --git a/solid-actions-kcm/device-actions/solid-device-Video.desktop b/solid-actions-kcm/device-actions/solid-device-Video.desktop new file mode 100644 index 00000000..fd8f79d9 --- /dev/null +++ b/solid-actions-kcm/device-actions/solid-device-Video.desktop @@ -0,0 +1,144 @@ +[Desktop Action supportedDrivers] +Name=Supported Drivers +Name[ar]=المشغلات المدعومة +Name[ast]=Controladores sofitaos +Name[bg]=Поддържани драйвери +Name[bn]=সমর্থিত ড্রাইভার +Name[bs]=podržani drajveri +Name[ca]=Controladors acceptats +Name[ca@valencia]=Controladors acceptats +Name[cs]=Podporované ovladače +Name[csb]=Wspiéróné czérowniczi +Name[da]=Understøttede drivere +Name[de]=Unterstützte Treiber +Name[el]=Υποστηριζόμενοι οδηγοί +Name[en_GB]=Supported Drivers +Name[eo]=subtenataj Peliloj +Name[es]=Dispositivos soportados +Name[et]=Toetatud draiverid +Name[eu]=Onartutzen diren gidariak +Name[fi]=Tuetut ajurit +Name[fr]=Pilotes pris en charge +Name[fy]=Stipe stjoerprogramma's +Name[ga]=Tiománaithe a dTacaítear Leo +Name[gl]=Controladores soportados +Name[gu]=આધારિત ડ્રાઇવરો +Name[he]=מנהלי התקנים נתמכים +Name[hi]=समर्थित ड्राईवर +Name[hr]=Podržani pisači +Name[hu]=Támogatott meghajtók +Name[ia]=Drivers supportate +Name[id]=Penggerak Didukung +Name[is]=Studdir reklar +Name[it]=Driver supportati +Name[ja]=サポートされているドライバ +Name[kk]=Қолдайтын драйверлері +Name[km]=កម្មវិធី​បញ្ជា​ដែលបានគាំទ្រ +Name[kn]=ಬೆಂಬಲಿತ ಚಾಲಕಗಳು +Name[ko]=지원하는 드라이버 +Name[lt]=Palaikomos tvarkyklės +Name[lv]=Atbalstītie draiveri +Name[mai]=समर्थित ड्राइवर +Name[mk]=Поддржани управувачи +Name[ml]=പിന്തുണയുള്ള സാരഥികള്‍ +Name[mr]=समर्थीत ड्राइव्हर्स +Name[nb]=Støttede drivere +Name[nds]=Ünnerstütt Drievers +Name[nl]=Ondersteunde stuurprogramma's +Name[nn]=Støtta drivarar +Name[pa]=ਸਹਾਇਕ ਡਰਾਇਵਰ +Name[pl]=Obsługiwane sterowniki +Name[pt]=Controladores Suportados +Name[pt_BR]=Drivers suportados +Name[ro]=Drivere susținute +Name[ru]=Поддерживаемые драйверы +Name[si]=සහාය දක්වන ධාවක +Name[sk]=Podporované ovládače +Name[sl]=Podprti gonilniki +Name[sr]=подржани драјвери +Name[sr@ijekavian]=подржани драјвери +Name[sr@ijekavianlatin]=podržani drajveri +Name[sr@latin]=podržani drajveri +Name[sv]=Drivrutiner som stöds +Name[tg]=Дастгоҳҳои мувофиқ +Name[th]=ไดรเวอร์ที่รองรับ +Name[tr]=Desteklenen Sürücüler +Name[ug]=قوللايدىغان قوزغاتقۇلار +Name[uk]=Підтримувані драйвери +Name[wa]=Mineus sopoirtés +Name[x-test]=xxSupported Driversxx +Name[zh_CN]=支持的驱动 +Name[zh_TW]=支援的驅動程式 + +[Desktop Entry] +Actions=supportedDrivers; +Name=Solid Device +Name[ar]=جهاز في سوليد +Name[ast]=Preseos de Solid +Name[bn]=সলিড ডিভাইস +Name[bs]=uređaj pod Solidom +Name[ca]=Dispositiu del Solid +Name[ca@valencia]=Dispositiu del Solid +Name[cs]=Solid zařízení +Name[da]=Solid-enhed +Name[de]=Solid-Gerät +Name[el]=Συμπαγής συσκευή +Name[en_GB]=Solid Device +Name[eo]=Solid-aparatoj +Name[es]=Dispositivo de Solid +Name[et]=Solidi seade +Name[eu]=Solid gailua +Name[fi]=Kiinteä laite +Name[fr]=Périphérique Solid +Name[fy]=Solid apparaat +Name[ga]=Gléas Solid +Name[gl]=Dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ +Name[he]=התקן Solid +Name[hi]=सोलिड औज़ार +Name[hr]=Solid uređaj +Name[hu]=Solid eszköz +Name[ia]=Dispositivo Solid +Name[id]=Divais Solid +Name[is]=Solid tæki +Name[it]=Dispositivo di Solid +Name[ja]=Solid デバイス +Name[kk]=Solid құрылғысы +Name[km]=ឧបករណ៍​យូ​តាន់ +Name[kn]=ಘನ ಸಾಧನ +Name[ko]=Solid 장치 +Name[lt]=Solid įrenginys +Name[lv]=Solid ierīce +Name[mk]=Полупроводнички уред +Name[ml]=സോളിഡ് ഉപകരണം +Name[mr]=सॉलिड साधन +Name[nb]=Solid-enhet +Name[nds]=Solid-Reedschap +Name[nl]=Solid-apparaat +Name[nn]=Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ +Name[pl]=Urządzenie Solid +Name[pt]=Dispositivo do Solid +Name[pt_BR]=Dispositivo do Solid +Name[ro]=Dispozitiv Solid +Name[ru]=Устройство Solid +Name[si]=දෘඩ මෙවලම් +Name[sk]=Zariadenie Solid +Name[sl]=Naprava Solid +Name[sr]=уређај под Солидом +Name[sr@ijekavian]=уређај под Солидом +Name[sr@ijekavianlatin]=uređaj pod Solidom +Name[sr@latin]=uređaj pod Solidom +Name[sv]=Solid-enhet +Name[tg]=Дастгоҳҳои ҷудошаванда +Name[th]=อุปกรณ์ผ่าน Solid +Name[tr]=Solid Aygıtı +Name[ug]=Solid ئۈسكۈنە +Name[uk]=Пристрій Solid +Name[wa]=Éndjins Solid +Name[x-test]=xxSolid Devicexx +Name[zh_CN]=Solid 设备 +Name[zh_TW]=實體裝置 +Type=Service +X-KDE-ServiceTypes=SolidDevice +X-KDE-Solid-Actions-Type=Video diff --git a/solid-actions-kcm/solid-action-template.desktop b/solid-actions-kcm/solid-action-template.desktop new file mode 100644 index 00000000..7c322ff8 --- /dev/null +++ b/solid-actions-kcm/solid-action-template.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Actions=open; +Type=Service +X-KDE-Action-Custom=true +X-KDE-Solid-Predicate=[ IS StorageVolume AND StorageVolume.ignored == false ] + +[Desktop Action open] +Icon=unknown +Exec= diff --git a/solid-actions-kcm/solid-actions.desktop b/solid-actions-kcm/solid-actions.desktop new file mode 100644 index 00000000..97744c49 --- /dev/null +++ b/solid-actions-kcm/solid-actions.desktop @@ -0,0 +1,178 @@ +[Desktop Entry] +Exec=kcmshell4 solid-actions +Icon=system-run +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/solid-actions/index.html + +X-KDE-Library=kcm_solid_actions +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=hardware + +Name=Device Actions +Name[ar]=إجراءات الأجهزة +Name[ast]=Aiciones del preséu +Name[bg]=Действия за устройства +Name[bn]=ডিভাইস অ্যাকশন +Name[bs]=Radnje uređaja +Name[ca]=Accions de dispositiu +Name[ca@valencia]=Accions de dispositiu +Name[cs]=Činnosti zařízení +Name[csb]=Dzejanié ùrządzenia +Name[da]=Enhedshandlinger +Name[de]=Geräte-Aktionen +Name[el]=Ενέργειες συσκευής +Name[en_GB]=Device Actions +Name[eo]=Aparataj agoj +Name[es]=Acciones del dispositivo +Name[et]=Seadme toimingud +Name[eu]=Gailuaren ekintzak +Name[fi]=Laitetoiminnot +Name[fr]=Actions du périphérique +Name[fy]=Apparaat aksjes +Name[ga]=Gníomhartha Gléis +Name[gl]=Accións do dispositivo +Name[gu]=ઉપકરણ ક્રિયાઓ +Name[he]=פעולות התקן +Name[hi]=औजार क्रियाएँ +Name[hr]=Akcije uređaja +Name[hu]=Eszközműveletek +Name[ia]=Actiones de dispositivos +Name[id]=Aksi Divais +Name[is]=Aðgerðir tækis +Name[it]=Azioni dei dispositivi +Name[ja]=デバイスに対するアクション +Name[kk]=Құрылғы әрекеттері +Name[km]=សកម្មភាព​ឧបករណ៍ +Name[kn]=ಸಾಧನದ ಕ್ರಿಯೆಗಳು +Name[ko]=장치 동작 +Name[lt]=Įrenginių veiksmai +Name[lv]=Ierīces darbības +Name[mk]=Дејства за уреди +Name[ml]=ഉപകരണത്തിനുള്ള പ്രവൃത്തികള്‍ +Name[mr]=साधन क्रिया +Name[nb]=Enhetshandlinger +Name[nds]=Reedschap-Akschonen +Name[nl]=Apparaatacties +Name[nn]=Einingshandlingar +Name[pa]=ਜੰਤਰ ਐਕਸ਼ਨ +Name[pl]=Działania na urządzeniach +Name[pt]=Acções do Dispositivo +Name[pt_BR]=Ações do dispositivo +Name[ro]=Acțiuni dispozitiv +Name[ru]=Действия для устройств +Name[si]=මෙවලම් ක්‍රියා +Name[sk]=Akcie zariadenia +Name[sl]=Dejanja za napravo +Name[sr]=Радње уређаја +Name[sr@ijekavian]=Радње уређаја +Name[sr@ijekavianlatin]=Radnje uređaja +Name[sr@latin]=Radnje uređaja +Name[sv]=Enhetsåtgärder +Name[tg]=Амалҳои пештанзимшуда +Name[th]=การกระทำต่าง ๆ กับอุปกรณ์ +Name[tr]=Aygıt Eylemleri +Name[ug]=ئۈسكۈنە مەشغۇلاتى +Name[uk]=Дії з пристроями +Name[vi]=Hành động cho thiết bị +Name[wa]=Accions di l' éndjin +Name[x-test]=xxDevice Actionsxx +Name[zh_CN]=设备动作 +Name[zh_TW]=裝置動作 + +Comment=Manage actions available to the user when connecting new devices +Comment[bs]=Upravljanje radnjama dostupnim korisniku pri povezivanju novih uređaja na računar. +Comment[ca]=Gestiona les accions disponibles per a l'usuari en connectar dispositius nous +Comment[ca@valencia]=Gestiona les accions disponibles per a l'usuari en connectar dispositius nous +Comment[cs]=Spravovat činnosti dostupné pro uživatele při připojení nových zařízení +Comment[da]=Håndtér de handlinger som er tilgængelige for brugeren når nye enheder tilsluttes +Comment[de]=Einrichtung der Aktionen, die für den Anwender verfügbar sein sollen, wenn neue Geräte an den Rechner angeschlossen werden. +Comment[el]=Διαχείριση ενεργειών διαθέσιμων στο χρήστη κατά τη σύνδεση νέων συσκευών +Comment[en_GB]=Manage actions available to the user when connecting new devices +Comment[es]=Gestionar las acciones disponibles para el usuario cuando conecta nuevos dispositivos +Comment[et]=Toimingute haldamine, mida kasutaja saab tarvitada uue seadme ühendamisel arvutiga +Comment[eu]=kudeatu gailu berriak konektatzean erabiltzaileak erabilgarri dituen ekintzak +Comment[fi]=Hallitse toimintoja, jotka ovat käyttäjän valittavissa, kun uusia laitteita kytketään +Comment[fr]=Gère les actions disponibles pour l'utilisateur lors de la connexion de nouveaux périphériques +Comment[ga]=Bainistigh na gníomhartha atá ar fáil don úsáideoir agus gléasanna nua á gceangal +Comment[gl]=Xestiona as accións dispoñíbeis para o usuario cando se conecten novos dispositivos +Comment[he]=מנהל פעילויות זמונית למשתמש בעת חיבור של התקנים חדשים +Comment[hu]=Új eszköz csatlakoztatásakor a felhasználónak elérhető műveletek kezelése +Comment[ia]=Gerer actiones disponibile al usator quando il connecte nove dispositivos al computator +Comment[is]=Stillingatól fyrir þær aðgerðir sem verða í boði fyrir notanda þegar ný tæki eru tengd við tölvuna +Comment[it]=Gestisci le azioni disponibili all'utente quando si collegano nuovi dispositivi +Comment[kk]=Жаңа құрылғыларды қосқанда қол жетерлік басқару амалдары +Comment[ko]=새 장치를 연결했을 때 표시할 동작을 관리합니다 +Comment[lt]=Tvarkyti veiksmus pasiekiamus naudotojui kai prijungiami nauji įrenginiai +Comment[mr]=नवीन साधने जोडल्यावर वापरकर्त्यास उपलब्ध असलेल्या क्रियांचे व्यवस्थापन करा +Comment[nb]=Håndter handlingene som er tilgjengelige for brukeren når nye enheter kobles til datamaskinen +Comment[nds]=Akschonen plegen, de för Brukers praatstaht, wenn nieg Reedschappen den Reekner tokoppelt warrt +Comment[nl]=Beheren van acties die beschikbaar zijn voor de gebruiker bij het aankoppelen van nieuwe apparaten +Comment[pa]=ਯੂਜ਼ਰ ਨੂੰ ਮਿਲਣ ਵਾਲੀਆਂ ਕਾਰਵਾਈਆਂ ਦਾ ਪਰਬੰਧ, ਜਦੋਂ ਨਵੇਂ ਜੰਤਰ ਕੁਨੈਕਟ ਕੀਤੇ ਜਾਂਦੇ ਹਨ +Comment[pl]=Zdecyduj o dostępnych dla użytkownika działaniach przy podłączaniu nowego urządzenia +Comment[pt]=Gerir as acções disponíveis para o utilizador, quando são ligados dispositivos novos ao computador +Comment[pt_BR]=Gerencia as ações disponíveis ao conectar novos dispositivos +Comment[ro]=Gestionează acțiunile oferite utilizatorului la conectarea noilor dispozitive +Comment[ru]=Настройка предлагаемых пользователю действий при подключении устройств +Comment[sk]=Spravovať akcie dostupné aktuálnemu používateľovi pri pripájaní nových zariadení +Comment[sl]=Upravljajte dejanja, ki so na voljo uporabniku, ko se priključi nova naprava +Comment[sr]=Одредите радње доступне кориснику при повезивању нових уређаја +Comment[sr@ijekavian]=Одредите радње доступне кориснику при повезивању нових уређаја +Comment[sr@ijekavianlatin]=Odredite radnje dostupne korisniku pri povezivanju novih uređaja +Comment[sr@latin]=Odredite radnje dostupne korisniku pri povezivanju novih uređaja +Comment[sv]=Hantera tillgängliga åtgärder för användare när nya enheter ansluts +Comment[tr]=Bilgisayara yeni bir aygıt takıldığında kullanıcı tarafından kullanılabilecek eylemleri yönet +Comment[uk]=Керування діями, доступними користувачеві після з’єднання пристроїв з комп’ютером +Comment[x-test]=xxManage actions available to the user when connecting new devicesxx +Comment[zh_CN]=管理当新设备连接时的系统动作 +Comment[zh_TW]=管理新增裝置到電腦時要做些什麼動作 + +X-KDE-Keywords=Solid Devices Actions +X-KDE-Keywords[bs]=Akcije čvrstih uređaja +X-KDE-Keywords[ca]=Accions de dispositiu del Solid +X-KDE-Keywords[ca@valencia]=Accions de dispositiu del Solid +X-KDE-Keywords[cs]=Činnosti zařízení Solid +X-KDE-Keywords[da]=Solid enhedshandlinger +X-KDE-Keywords[de]=Solid-Geräte-Aktionen +X-KDE-Keywords[el]=Ενέργειες συσκευής Solid +X-KDE-Keywords[en_GB]=Solid Devices Actions +X-KDE-Keywords[es]=Acciones de dispositivos Solid +X-KDE-Keywords[et]=Solidi seadmete toimingud +X-KDE-Keywords[eu]=Solid gailuen ekintzak +X-KDE-Keywords[fi]=solid, laitetoiminnot +X-KDE-Keywords[fr]=Actions du périphérique Solid +X-KDE-Keywords[ga]=Gníomhartha Gléasanna Solid +X-KDE-Keywords[gl]=Accións do dispositivo Solid +X-KDE-Keywords[he]=פעולות התקן של Solid +X-KDE-Keywords[hu]=Solid eszközműveletek +X-KDE-Keywords[ia]=Actiones de dispositivos solid +X-KDE-Keywords[is]=Aðgerðir Solid-tækja +X-KDE-Keywords[it]=Azioni dei dispositivi Solid +X-KDE-Keywords[kk]=Solid Devices Actions +X-KDE-Keywords[km]=សកម្មភាព​ឧបករណ៍​រឹង +X-KDE-Keywords[ko]=Solid 장치 동작 +X-KDE-Keywords[lt]=Solid įrenginių veiksmai +X-KDE-Keywords[lv]=Solid ierīces darbības +X-KDE-Keywords[mr]=सॉलिड साधन क्रिया +X-KDE-Keywords[nb]=Solid enhetshandlinger +X-KDE-Keywords[nds]=Solid,Reedschappen,Akschonen +X-KDE-Keywords[nl]=Solid-apparaatacties +X-KDE-Keywords[pa]=ਸਾਲਡ ਜੰਤਰ ਐਕਸ਼ਨ +X-KDE-Keywords[pl]=Działania na urządzeniach Solid +X-KDE-Keywords[pt]=Acções do Dispositivo Solid +X-KDE-Keywords[pt_BR]=Ações do dispositivo Solid +X-KDE-Keywords[ro]=Acțiuni dispozitiv Solid +X-KDE-Keywords[ru]=Действия для устройств Solid +X-KDE-Keywords[sk]=Akcie zariadení Solid +X-KDE-Keywords[sl]=solid,naprave,dejanja,strojna oprema +X-KDE-Keywords[sr]=Solid Devices Actions,Солидове радње над уређајима +X-KDE-Keywords[sr@ijekavian]=Solid Devices Actions,Солидове радње над уређајима +X-KDE-Keywords[sr@ijekavianlatin]=Solid Devices Actions,Solidove radnje nad uređajima +X-KDE-Keywords[sr@latin]=Solid Devices Actions,Solidove radnje nad uređajima +X-KDE-Keywords[sv]=Solid enhetsåtgärder +X-KDE-Keywords[tr]=Solid Aygıt Eylemleri +X-KDE-Keywords[uk]=solid,пристрій,пристрої,дія,дії +X-KDE-Keywords[x-test]=xxSolid Devices Actionsxx +X-KDE-Keywords[zh_CN]=Solid Devices Actions,设备动作 +X-KDE-Keywords[zh_TW]=Solid Devices Actions diff --git a/solid-actions-kcm/solid-device-type.desktop b/solid-actions-kcm/solid-device-type.desktop new file mode 100644 index 00000000..9997e1f4 --- /dev/null +++ b/solid-actions-kcm/solid-device-type.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=SolidDevice +Name=Solid Device Type +Name[ar]=نوع الجهاز في سوليد +Name[ast]=Triba de preséu de Solid +Name[bn]=সলিড ডিভাইস টাইপ +Name[bs]=tip uređaja pod Solidom +Name[ca]=Tipus de dispositiu del Solid +Name[ca@valencia]=Tipus de dispositiu del Solid +Name[cs]=Typ zařízení Solid +Name[da]=Solid enhedstype +Name[de]=Solid-Gerätetyp +Name[el]=Τύπος συμπαγής συσκευής +Name[en_GB]=Solid Device Type +Name[eo]=Solid Aparata Tipo +Name[es]=Tipo de dispositivo de Solid +Name[et]=Solidi seadme tüüp +Name[eu]=Solid gailu mota +Name[fi]=Kiintolaitetyyppi +Name[fr]=Type de périphérique Solid +Name[fy]=Solid apparaat type +Name[ga]=Cineál Gléis Solid +Name[gl]=Tipo do dispositivo de Solid +Name[gu]=સોલિડ ઉપકરણ પ્રકાર +Name[he]=סוג התקן Solid +Name[hi]=सोलिड औज़ार प्रकार +Name[hr]=Vrsta Solid uređaja +Name[hu]=Solid eszköztípus +Name[ia]=Typo de dispositivo de Solid +Name[id]=Tipe Divais Solid +Name[is]=Tegund Solid-tækis +Name[it]=Tipo di dispositivo Solid +Name[ja]=Solid デバイスのタイプ +Name[kk]=Solid құрылғысының түрі +Name[km]=ប្រភេទ​ឧបករណ៍​តាន់ +Name[kn]=ಘನ(ಸಾಲಿಡ್) ಸಾಧನ ಬಗೆ +Name[ko]=Solid 장치 종류 +Name[lt]=Solid įrenginio tipas +Name[lv]=Solid ierīces tips +Name[mk]=Полупроводнички тип на уред +Name[ml]=സോളിഡ് ഉപകരണതരം +Name[mr]=सॉलिड साधन प्रकार +Name[nb]=Type solid-enhet +Name[nds]=Solid-Reedschaptyp +Name[nl]=Solid-apparaattype +Name[nn]=Type Solid-eining +Name[pa]=ਸਾਲਡ ਜੰਤਰ ਕਿਸਮ +Name[pl]=Typ urządzenia Solid +Name[pt]=Tipo de Dispositivo do Solid +Name[pt_BR]=Tipo de dispositivo do Solid +Name[ro]=Tip dispozitiv solid +Name[ru]=Тип устройства Solid +Name[si]=දෘඩ මෙවලම් වර්‍ගය +Name[sk]=Typ zariadenia Solid +Name[sl]=Vrsta naprave Solid +Name[sr]=тип уређаја под Солидом +Name[sr@ijekavian]=тип уређаја под Солидом +Name[sr@ijekavianlatin]=tip uređaja pod Solidom +Name[sr@latin]=tip uređaja pod Solidom +Name[sv]=Solid-enhetstyp +Name[tg]=Намуди дастгоҳи ҷудошаванда +Name[th]=ประเภทอุปกรณ์ของ Solid +Name[tr]=Solid Aygıtı Tipi +Name[ug]=Solid ئۈسكۈنە تىپى +Name[uk]=Тип пристрою Solid +Name[wa]=Sôre d' éndjin Solid +Name[x-test]=xxSolid Device Typexx +Name[zh_CN]=Solid 设备类型 +Name[zh_TW]=實體裝置類型 diff --git a/startkde.cmake b/startkde.cmake new file mode 100644 index 00000000..afc2cfb8 --- /dev/null +++ b/startkde.cmake @@ -0,0 +1,405 @@ +#!/bin/sh +# +# DEFAULT KDE STARTUP SCRIPT ( @KDE4WORKSPACE_VERSION@ ) +# + +if test "x$1" = x--failsafe; then + KDE_FAILSAFE=1 # General failsafe flag + KWIN_COMPOSE=N # Disable KWin's compositing + export KWIN_COMPOSE KDE_FAILSAFE +fi + +# When the X server dies we get a HUP signal from xinit. We must ignore it +# because we still need to do some cleanup. +trap 'echo GOT SIGHUP' HUP + +# we have to unset this for Darwin since it will screw up KDE's dynamic-loading +unset DYLD_FORCE_FLAT_NAMESPACE + +# in case we have been started with full pathname spec without being in PATH +bindir=`echo "$0" | sed -n 's,^\(/.*\)/[^/][^/]*$,\1,p'` +if [ -n "$bindir" ]; then + qbindir=`$bindir/kde4-config --qt-binaries` + qdbus=$qbindir/qdbus + case $PATH in + $bindir|$bindir:*|*:$bindir|*:$bindir:*) ;; + *) PATH=$bindir:$PATH; export PATH;; + esac +else + qdbus=qdbus +fi + +# Check if a KDE session already is running and whether it's possible to connect to X +kcheckrunning +kcheckrunning_result=$? +if test $kcheckrunning_result -eq 0 ; then + echo "KDE seems to be already running on this display." + xmessage -geometry 500x100 "KDE seems to be already running on this display." > /dev/null 2>/dev/null + exit 1 +elif test $kcheckrunning_result -eq 2 ; then + echo "\$DISPLAY is not set or cannot connect to the X server." + exit 1 +fi + +# Boot sequence: +# +# kdeinit is used to fork off processes which improves memory usage +# and startup time. +# +# * kdeinit starts klauncher first. +# * Then kded is started. kded is responsible for keeping the sycoca +# database up to date. When an up to date database is present it goes +# into the background and the startup continues. +# * Then kdeinit starts kcminit. kcminit performs initialisation of +# certain devices according to the user's settings +# +# * Then ksmserver is started which takes control of the rest of the startup sequence + +# The user's personal KDE directory is usually ~/.kde, but this setting +# may be overridden by setting KDEHOME. + +kdehome=$HOME/@KDE_DEFAULT_HOME@ +test -n "$KDEHOME" && kdehome=`echo "$KDEHOME"|sed "s,^~/,$HOME/,"` + +# see kstartupconfig source for usage +mkdir -m 700 -p $kdehome +mkdir -m 700 -p $kdehome/share +mkdir -m 700 -p $kdehome/share/config +cat >$kdehome/share/config/startupconfigkeys </env/*.sh and /env/*.sh +# (where is $KDEHOME or ~/.kde, and is where KDE is installed) +# +# This is where you can define environment variables that will be available to +# all KDE programs, so this is where you can run agents using e.g. eval `ssh-agent` +# or eval `gpg-agent --daemon`. +# Note: if you do that, you should also put "ssh-agent -k" as a shutdown script +# +# (see end of this file). +# For anything else (that doesn't set env vars, or that needs a window manager), +# better use the Autostart folder. + +libpath=`kde4-config --path lib | tr : '\n'` + +for prefix in `echo "$libpath" | sed -n -e 's,/lib[^/]*/,/env/,p'`; do + for file in "$prefix"*.sh; do + test -r "$file" && . "$file" + done +done + +# Set the path for Qt plugins provided by KDE +QT_PLUGIN_PATH=${QT_PLUGIN_PATH+$QT_PLUGIN_PATH:}`kde4-config --path qtplugins` +export QT_PLUGIN_PATH + +# Activate the kde font directories. +# +# There are 4 directories that may be used for supplying fonts for KDE. +# +# There are two system directories. These belong to the administrator. +# There are two user directories, where the user may add her own fonts. +# +# The 'override' versions are for fonts that should come first in the list, +# i.e. if you have a font in your 'override' directory, it will be used in +# preference to any other. +# +# The preference order looks like this: +# user override, system override, X, user, system +# +# Where X is the original font database that was set up before this script +# runs. + +usr_odir=$HOME/.fonts/kde-override +usr_fdir=$HOME/.fonts + +if test -n "$KDEDIRS"; then + kdedirs_first=`echo "$KDEDIRS"|sed -e 's/:.*//'` + sys_odir=$kdedirs_first/share/fonts/override + sys_fdir=$kdedirs_first/share/fonts +else + sys_odir=$KDEDIR/share/fonts/override + sys_fdir=$KDEDIR/share/fonts +fi + +# We run mkfontdir on the user's font dirs (if we have permission) to pick +# up any new fonts they may have installed. If mkfontdir fails, we still +# add the user's dirs to the font path, as they might simply have been made +# read-only by the administrator, for whatever reason. + +test -d "$sys_odir" && xset +fp "$sys_odir" +test -d "$usr_odir" && (mkfontdir "$usr_odir" ; xset +fp "$usr_odir") +test -d "$usr_fdir" && (mkfontdir "$usr_fdir" ; xset fp+ "$usr_fdir") +test -d "$sys_fdir" && xset fp+ "$sys_fdir" + +# Ask X11 to rebuild its font list. +xset fp rehash + +# Set a left cursor instead of the standard X11 "X" cursor, since I've heard +# from some users that they're confused and don't know what to do. This is +# especially necessary on slow machines, where starting KDE takes one or two +# minutes until anything appears on the screen. +# +# If the user has overwritten fonts, the cursor font may be different now +# so don't move this up. +# +xsetroot -cursor_name left_ptr + +# Get Ghostscript to look into user's KDE fonts dir for additional Fontmap +if test -n "$GS_LIB" ; then + GS_LIB=$usr_fdir:$GS_LIB + export GS_LIB +else + GS_LIB=$usr_fdir + export GS_LIB +fi + +lnusertemp=`kde4-config --path exe --locate lnusertemp` +if test -z "$lnusertemp"; then + # Startup error + echo 'startkde: ERROR: Could not locate lnusertemp in '`kde4-config --path exe` 1>&2 +fi + +# Link "tmp" "socket" and "cache" resources to directory in /tmp +# Creates: +# - a directory /tmp/kde-$USER and links $KDEHOME/tmp-$HOSTNAME to it. +# - a directory /tmp/ksocket-$USER and links $KDEHOME/socket-$HOSTNAME to it. +# - a directory /var/tmp/kdecache-$USER and links $KDEHOME/cache-$HOSTNAME to it. +# Note: temporary locations can be overriden through the KDETMP and KDEVARTMP +# environment variables +for resource in tmp cache socket; do + if "$lnusertemp" $resource >/dev/null; then + : # ok + else + echo 'startkde: Call to lnusertemp failed (temporary directories full?). Check your installation.' 1>&2 + test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null + xmessage -geometry 600x100 "Call to lnusertemp failed (temporary directories full?). Check your installation." + exit 1 + fi +done + +# In case of dcop sockets left by a previous session, cleanup +#dcopserver_shutdown + +echo 'startkde: Starting up...' 1>&2 + +# Make sure that the KDE prefix is first in XDG_DATA_DIRS and that it's set at all. +# The spec allows XDG_DATA_DIRS to be not set, but X session startup scripts tend +# to set it to a list of paths *not* including the KDE prefix if it's not /usr or +# /usr/local. +if test -z "$XDG_DATA_DIRS"; then + XDG_DATA_DIRS="@SHARE_INSTALL_PREFIX@:/usr/share:/usr/local/share" +else + XDG_DATA_DIRS="@SHARE_INSTALL_PREFIX@:$XDG_DATA_DIRS" +fi +export XDG_DATA_DIRS + +# Make sure that D-Bus is running +# D-Bus autolaunch is broken +if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then + eval `dbus-launch --sh-syntax --exit-with-session` +fi +if $qdbus >/dev/null 2>/dev/null; then + : # ok +else + echo 'startkde: Could not start D-Bus. Can you call qdbus?' 1>&2 + test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null + xmessage -geometry 500x100 "Could not start D-Bus. Can you call qdbus?" + exit 1 +fi + + +# Mark that full KDE session is running (e.g. Konqueror preloading works only +# with full KDE running). The KDE_FULL_SESSION property can be detected by +# any X client connected to the same X session, even if not launched +# directly from the KDE session but e.g. using "ssh -X", kdesu. $KDE_FULL_SESSION +# however guarantees that the application is launched in the same environment +# like the KDE session and that e.g. KDE utilities/libraries are available. +# KDE_FULL_SESSION property is also only available since KDE 3.5.5. +# The matching tests are: +# For $KDE_FULL_SESSION: +# if test -n "$KDE_FULL_SESSION"; then ... whatever +# For KDE_FULL_SESSION property: +# xprop -root | grep "^KDE_FULL_SESSION" >/dev/null 2>/dev/null +# if test $? -eq 0; then ... whatever +# +# Additionally there is (since KDE 3.5.7) $KDE_SESSION_UID with the uid +# of the user running the KDE session. It should be rarely needed (e.g. +# after sudo to prevent desktop-wide functionality in the new user's kded). +# +# Since KDE4 there is also KDE_SESSION_VERSION, containing the major version number. +# Note that this didn't exist in KDE3, which can be detected by its absense and +# the presence of KDE_FULL_SESSION. +# +KDE_FULL_SESSION=true +export KDE_FULL_SESSION +xprop -root -f KDE_FULL_SESSION 8t -set KDE_FULL_SESSION true + +KDE_SESSION_VERSION=4 +export KDE_SESSION_VERSION +xprop -root -f KDE_SESSION_VERSION 32c -set KDE_SESSION_VERSION 4 + +KDE_SESSION_UID=`id -ru` +export KDE_SESSION_UID + +XDG_CURRENT_DESKTOP=KDE +export XDG_CURRENT_DESKTOP + +# At this point all the environment is ready, let's send it to kwalletd if running +if test -n "$PAM_KWALLET_LOGIN" ; then + env | socat STDIN UNIX-CONNECT:$PAM_KWALLET_LOGIN +fi + +# We set LD_BIND_NOW to increase the efficiency of kdeinit. +# kdeinit unsets this variable before loading applications. +LD_BIND_NOW=true @KDE4_LIBEXEC_INSTALL_DIR@/start_kdeinit_wrapper +kcminit_startup +if test $? -ne 0; then + # Startup error + echo 'startkde: Could not start kdeinit4. Check your installation.' 1>&2 + test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null + xmessage -geometry 500x100 "Could not start kdeinit4. Check your installation." + exit 1 +fi + +# finally, give the session control to the session manager +# see kdebase/ksmserver for the description of the rest of the startup sequence +# if the KDEWM environment variable has been set, then it will be used as KDE's +# window manager instead of kwin. +# if KDEWM is not set, ksmserver will ensure kwin is started. +# kwrapper4 is used to reduce startup time and memory usage +# kwrapper4 does not return useful error codes such as the exit code of ksmserver. +# We only check for 255 which means that the ksmserver process could not be +# started, any problems thereafter, e.g. ksmserver failing to initialize, +# will remain undetected. +test -n "$KDEWM" && KDEWM="--windowmanager $KDEWM" +# If the session should be locked from the start (locked autologin), +# lock now and do the rest of the KDE startup underneath the locker. +KSMSERVEROPTIONS="" +test -n "$dl" && KSMSERVEROPTIONS=" --lockscreen" +kwrapper4 ksmserver $KDEWM $KSMSERVEROPTIONS +if test $? -eq 255; then + # Startup error + echo 'startkde: Could not start ksmserver. Check your installation.' 1>&2 + test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null + xmessage -geometry 500x100 "Could not start ksmserver. Check your installation." +fi + +wait_drkonqi=`kreadconfig --file startkderc --group WaitForDrKonqi --key Enabled --default true` + +if test x"$wait_drkonqi"x = x"true"x ; then + # wait for remaining drkonqi instances with timeout (in seconds) + wait_drkonqi_timeout=`kreadconfig --file startkderc --group WaitForDrKonqi --key Timeout --default 900` + wait_drkonqi_counter=0 + while $qdbus | grep "^[^w]*org.kde.drkonqi" > /dev/null ; do + sleep 5 + wait_drkonqi_counter=$((wait_drkonqi_counter+5)) + if test "$wait_drkonqi_counter" -ge "$wait_drkonqi_timeout" ; then + # ask remaining drkonqis to die in a graceful way + $qdbus | grep 'org.kde.drkonqi-' | while read address ; do + $qdbus "$address" "/MainApplication" "quit" + done + break + fi + done +fi + +echo 'startkde: Shutting down...' 1>&2 +# just in case +test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null + +# Clean up +kdeinit4_shutdown +# KDE3 support +kde3 kdeinit_shutdown 2>/dev/null +kde3 dcopserver_shutdown --wait 2>/dev/null + +echo 'startkde: Running shutdown scripts...' 1>&2 + +# Run scripts found in $KDEDIRS/shutdown +for prefix in `echo "$libpath" | sed -n -e 's,/lib[^/]*/,/shutdown/,p'`; do + for file in `ls "$prefix" 2> /dev/null | egrep -v '(~|\.bak)$'`; do + test -x "$prefix$file" && "$prefix$file" + done +done + +unset KDE_FULL_SESSION +xprop -root -remove KDE_FULL_SESSION +unset KDE_SESSION_VERSION +xprop -root -remove KDE_SESSION_VERSION +unset KDE_SESSION_UID + +echo 'startkde: Done.' 1>&2 diff --git a/statusnotifierwatcher/CMakeLists.txt b/statusnotifierwatcher/CMakeLists.txt new file mode 100644 index 00000000..308841e8 --- /dev/null +++ b/statusnotifierwatcher/CMakeLists.txt @@ -0,0 +1,26 @@ +project(StatusNotifierWatcher) + +set(kded_statusnotifierwatcher_SRCS statusnotifierwatcher.cpp ) + +QT4_ADD_DBUS_ADAPTOR(kded_statusnotifierwatcher_SRCS ${KDE4_DBUS_INTERFACES_DIR}/org.kde.StatusNotifierWatcher.xml + statusnotifierwatcher.h StatusNotifierWatcher) + + +set(statusnotifieritem_xml ${KDE4_DBUS_INTERFACES_DIR}/org.kde.StatusNotifierItem.xml) +set_source_files_properties(${statusnotifieritem_xml} PROPERTIES + NO_NAMESPACE false + INCLUDE "systemtraytypedefs.h" + CLASSNAME OrgKdeStatusNotifierItemInterface +) +QT4_ADD_DBUS_INTERFACE(kded_statusnotifierwatcher_SRCS ${statusnotifieritem_xml} statusnotifieritem_interface) + +kde4_add_plugin(kded_statusnotifierwatcher ${kded_statusnotifierwatcher_SRCS}) + + +target_link_libraries(kded_statusnotifierwatcher ${KDE4_KIO_LIBS} ) + +install(TARGETS kded_statusnotifierwatcher DESTINATION ${PLUGIN_INSTALL_DIR}) + + +install( FILES statusnotifierwatcher.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded) + diff --git a/statusnotifierwatcher/statusnotifierwatcher.cpp b/statusnotifierwatcher/statusnotifierwatcher.cpp new file mode 100644 index 00000000..ef3e32b7 --- /dev/null +++ b/statusnotifierwatcher/statusnotifierwatcher.cpp @@ -0,0 +1,148 @@ +/*************************************************************************** + * Copyright 2009 by Marco Martin * + * * + * 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 "statusnotifierwatcher.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include "statusnotifierwatcheradaptor.h" +#include "statusnotifieritem_interface.h" +#include + + +static inline KAboutData aboutData() +{ + return KAboutData("statusnotifierwatcher", 0, ki18n("statusnotifierwatcher"), WORKSPACE_VERSION_STRING); +} + +K_PLUGIN_FACTORY(StatusNotifierWatcherFactory, + registerPlugin(); + ) +K_EXPORT_PLUGIN(StatusNotifierWatcherFactory(aboutData())) + +StatusNotifierWatcher::StatusNotifierWatcher(QObject *parent, const QList&) + : KDEDModule(parent) +{ + setModuleName("StatusNotifierWatcher"); + new StatusNotifierWatcherAdaptor(this); + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerService("org.kde.StatusNotifierWatcher"); + dbus.registerObject("/StatusNotifierWatcher", this); + + m_serviceWatcher = new QDBusServiceWatcher(this); + m_serviceWatcher->setConnection(dbus); + m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); + + connect(m_serviceWatcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(serviceUnregistered(QString))); +} + +StatusNotifierWatcher::~StatusNotifierWatcher() +{ + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.unregisterService("org.kde.StatusNotifierWatcher"); +} + + +void StatusNotifierWatcher::RegisterStatusNotifierItem(const QString &serviceOrPath) +{ + QString service; + QString path; + if (serviceOrPath.startsWith('/')) { + service = message().service(); + path = serviceOrPath; + } else { + service = serviceOrPath; + path = "/StatusNotifierItem"; + } + QString notifierItemId = service + path; + if (QDBusConnection::sessionBus().interface()->isServiceRegistered(service).value() && + !m_registeredServices.contains(notifierItemId)) { + kDebug()<<"Registering" << notifierItemId << "to system tray"; + + //check if the service has registered a SystemTray object + org::kde::StatusNotifierItem trayclient(service, path, + QDBusConnection::sessionBus()); + if (trayclient.isValid()) { + m_registeredServices.append(notifierItemId); + m_serviceWatcher->addWatchedService(service); + emit StatusNotifierItemRegistered(notifierItemId); + } + } +} + +QStringList StatusNotifierWatcher::RegisteredStatusNotifierItems() const +{ + return m_registeredServices; +} + + +void StatusNotifierWatcher::serviceUnregistered(const QString& name) +{ + kDebug()<<"Service "<< name << "unregistered"; + m_serviceWatcher->removeWatchedService(name); + + QString match = name + '/'; + QStringList::Iterator it = m_registeredServices.begin(); + while (it != m_registeredServices.end()) { + if (it->startsWith(match)) { + QString name = *it; + it = m_registeredServices.erase(it); + emit StatusNotifierItemUnregistered(name); + } else { + ++it; + } + } + + if (m_statusNotifierHostServices.contains(name)) { + m_statusNotifierHostServices.remove(name); + emit StatusNotifierHostUnregistered(); + } +} + +void StatusNotifierWatcher::RegisterStatusNotifierHost(const QString &service) +{ + if (service.contains("org.kde.StatusNotifierHost-") && + QDBusConnection::sessionBus().interface()->isServiceRegistered(service).value() && + !m_statusNotifierHostServices.contains(service)) { + kDebug()<<"Registering"<addWatchedService(service); + emit StatusNotifierHostRegistered(); + } +} + +bool StatusNotifierWatcher::IsStatusNotifierHostRegistered() const +{ + return !m_statusNotifierHostServices.isEmpty(); +} + +int StatusNotifierWatcher::ProtocolVersion() const +{ + return 0; +} + +#include "statusnotifierwatcher.moc" diff --git a/statusnotifierwatcher/statusnotifierwatcher.desktop b/statusnotifierwatcher/statusnotifierwatcher.desktop new file mode 100644 index 00000000..bfb66731 --- /dev/null +++ b/statusnotifierwatcher/statusnotifierwatcher.desktop @@ -0,0 +1,128 @@ +[Desktop Entry] +Type=Service +Name=Status Notifier Manager +Name[ar]=مدير تنبيهات الحالة +Name[ast]=Xestor del notificador del estáu +Name[bn]=স্ট্যাটাস বিজ্ঞপ্তি ম্যানেজার +Name[bs]=Menadžer izveštavača o stanju +Name[ca]=Gestor del notificador d'estat +Name[ca@valencia]=Gestor del notificador d'estat +Name[cs]=Správce oznamování stavu +Name[da]=Håndtering af statusbekendtgørelser +Name[de]=Statusbenachrichtigungs-Verwaltung +Name[el]=Διαχειριστής των ειδοποιήσεων κατάστασης +Name[en_GB]=Status Notifier Manager +Name[es]=Gestor del notificador del estado +Name[et]=Oleku märguannete haldur +Name[eu]=Egoera-jakinarazlearen kudeatzailea +Name[fi]=Tilailmoittimen hallinta +Name[fr]=Gestionnaire du notificateur d'état +Name[gl]=Xestor das notificacións de estado +Name[he]=מנהל שירותי הודעות מצב +Name[hi]=स्थिति संकेत प्रबंधक +Name[hr]=Upravitelj glasnika stanja +Name[hu]=Állapotértesítés-kezelő +Name[ia]=Gerente de notificator de stato +Name[id]=Manajer Notifikasi Status +Name[is]=Stöðutilkynningaþjónn +Name[it]=Gestore del notificatore di stato +Name[ja]=ステータス通知マネージャ +Name[kk]=Күй-жайы туралы құлақтандырғыш менеджері +Name[km]=កម្មវិធី​គ្រប់គ្រង​ធាតុជូន​ដំណឹង​អំពី​ស្ថានភាព +Name[kn]= ಸ್ಥಿತಿ ಸೂಚನಾ ವ್ಯವಸ್ಥಾಪಕ +Name[ko]=상태 알림 관리자 +Name[lt]=Būsenos pranešimų valdymas +Name[lv]=Statusa paziņojumu pārvaldītājs +Name[mr]=स्थिती निदर्शक व्यवस्थापक +Name[nb]=Håndtering av statusvarsler +Name[nds]=Statusbescheed-Beluern +Name[nl]=Statusmeldingenbeheerder +Name[pa]=ਹਾਲਤ ਨੋਟੀਫਾਇਰ ਮੈਨੇਜਰ +Name[pl]=Zarządzanie powiadomieniami o stanie +Name[pt]=Gestor das Notificações de Estado +Name[pt_BR]=Gerenciador de notificações de status +Name[ro]=Gestionar notificator de stare +Name[ru]=Диспетчер уведомлений о состоянии +Name[si]=තත්ව දැන්වීමේ කළමනාකරු +Name[sk]=Správca oznámení stavu +Name[sl]=Upravljalnik obvestilnika o stanju +Name[sr]=Менаџер извештавача о стању +Name[sr@ijekavian]=Менаџер извјештавача о стању +Name[sr@ijekavianlatin]=Menadžer izvještavača o stanju +Name[sr@latin]=Menadžer izveštavača o stanju +Name[sv]=Hantering av statusunderrättelser +Name[tg]=Мудири ҳолатҳои система +Name[th]=ตัวจัดการการแจ้งสถานะให้ทราบ +Name[tr]=Durum Bildirim Yöneticisi +Name[ug]=ھالەت بىلدۈرگۈ باشقۇرغۇچ +Name[uk]=Керування сповіщенням про стан +Name[wa]=Manaedjeu do notifiaedje d' estat +Name[x-test]=xxStatus Notifier Managerxx +Name[zh_CN]=状态通知管理器 +Name[zh_TW]=狀態通知管理員 +Comment=Manages services that provide status notifier user interfaces +Comment[ar]=أدر الخدمات التي توفر واجهات المستخدم لمنبّهات الحالة +Comment[ast]=Xestiona servicios qu'ufren interfaces d'usuariu pal notificador d'estáu +Comment[bs]=Upravljanje servisima koji pružaju sučelje izveštavača o stanju +Comment[ca]=Gestiona serveis que proporcionen notificacions d'estat a les interfícies d'usuari +Comment[ca@valencia]=Gestiona serveis que proporcionen notificacions d'estat a les interfícies d'usuari +Comment[cs]=Nastavení služeb poskytujících rozhraní pro oznamování stavu +Comment[da]=Håndterer tjenester der giver brugerflader til statusbekendtgørelser +Comment[de]=Verwaltet Dienste, die eine Schnittstelle für Status-Informationen bereitstellen +Comment[el]=Διαχειρίζεται υπηρεσίες που παρέχουν περιβάλλοντα χρήστη για τις ειδοποιήσεις κατάστασης +Comment[en_GB]=Manages services that provide status notifier user interfaces +Comment[es]=Gestiona servicios que proporcionan interfaces de usuario para el notificador de estado +Comment[et]=Teenuste haldamine, mis pakuvad olekumärguannete kasutajaliidest +Comment[eu]=Egora-jakinarazlerako erabiltzaile-interfazeak hornitzen dituen zerbitzuak kudeatzen ditu +Comment[fi]=Hallitsee palveluja, jotka tarjoavat tilailmoitinkäyttöliittymät +Comment[fr]=Gère les services fournissant des interfaces utilisateurs pour la notification d'état +Comment[gl]=Xestiona servizos que fornecen interfaces de usuario para o notificador de estado +Comment[he]=ניהול שירותים המספקים ממשקי משתמש להודעות מצב +Comment[hr]=Upravlja uslugama koje omogućuju obavještavanje o stanju korisničkog sučelja +Comment[hu]=Kezeli az állapotértesítést nyújtó szolgáltatásokat +Comment[ia]=Il gere servicios que forni interfacies de usator pro notificator de stato +Comment[id]=Atur layanan yang menyediakan notifikasi status antarmuka pengguna +Comment[is]=Stjórnar þjónustum sem sjá um stöðutilkynningar notendaviðmóta +Comment[it]=Gestisce i servizi che forniscono interfacce utente al notificatore di stato +Comment[ja]=ステータス通知ユーザインターフェースを提供するサービスを管理 +Comment[kk]=Күй-жайы туралы құлақтандыру интерфейсін қамтамасыз ететін қызметін басқару +Comment[km]=គ្រប់គ្រង​សារ​ដែល​ផ្ដល់​កម្មវិធី​​ជូនដំណឹង​អំពី​ស្ថានភាព​ចំណុច​ប្រទាក់​អ្នកប្រើ +Comment[kn]=ಸ್ಥಿತಿಯನ್ನು ಸೂಚಿಸುವ ಬಳಕೆದಾರ ಸಂಪರ್ಕಸಾಧನಗಳನ್ನು ಒದಗಿಸುವ ಸೇವೆಗಳನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ +Comment[ko]=상태 알림 인터페이스를 제공하는 서비스를 관리합니다 +Comment[lt]=Valdo tarnybas, teikiančias būsenos pranešimų naudotojo sąsajas +Comment[lv]=Pārvalda servisus, kas sniedz statusa paziņojumu lietotāja saskarni +Comment[mr]=स्थितीबाबत सूचना दैणाऱ्या सेवांचे व्यवस्थापन करतो +Comment[nb]=Håndterer tjenester som tilbyr brukerflater for statusvarsler +Comment[nds]=Deensten plegen, de Statusbescheed-Brukerkoppelsteden praatstellt +Comment[nl]=Beheert services die statusmeldingen leveren aan gebruikersinterfaces +Comment[pa]=ਸਰਵਿਸਾਂ ਦਾ ਪਰਬੰਧ ਕਰਦਾ ਹੈ, ਜੋ ਕਿ ਹਾਲਤ ਨੋਟੀਫਾਇਰ ਯੂਜ਼ਰ ਇੰਟਰਫੇਸ ਦਿੰਦਾ ਹੈ +Comment[pl]=Zarządza usługami, które udostępniają interfejs użytkownika powiadomień o stanie +Comment[pt]=Faz a gestão dos serviços que fornecem interface de notificação do estado +Comment[pt_BR]=Gerencia os serviços que fornecem interfaces de notificação do status +Comment[ro]=Administrează serviciile care furnizează interfețe utilizator pentru notificări de stare +Comment[ru]=Управление службами интерфейсов уведомлений о состоянии +Comment[si]=පරිශීලක අතුරු මුහුණත් වලට තත්ව දැනුම් දීම් සපයන සේවා කළමනාකරනය කරයි +Comment[sk]=Spravuje služby, ktoré poskytujú užívateľské rozhrania pre oznámenie stavu +Comment[sl]=Upravlja s storitvami, ki ponujajo uporabniške vmesnike obvestilnika o stanju +Comment[sr]=Управљање сервисима који пружају сучеље извештавача о стању +Comment[sr@ijekavian]=Управљање сервисима који пружају сучеље извјештавача о стању +Comment[sr@ijekavianlatin]=Upravljanje servisima koji pružaju sučelje izvještavača o stanju +Comment[sr@latin]=Upravljanje servisima koji pružaju sučelje izveštavača o stanju +Comment[sv]=Hanterar tjänster som tillhandahåller användargränssnitt för statusunderrättelser +Comment[th]=จัดการบริการต่าง ๆ ที่แจ้งสถานะมาให้ผู้ใช้รับทราบ +Comment[tr]=Durum bildirimi kullanıcı arayüzünü sunan servisleri yönetir +Comment[ug]=ھالەت بىلدۈرگۈ ئىشلەتكۈچى ئارايۈزىنى تەمىنلەشنى باشقۇرۇش مۇلازىمىتى +Comment[uk]=Керує службами інтерфейсів користувача для сповіщення про стан +Comment[vi]=Quản lý các dịch vụ cung cấp thông báo trạng thái +Comment[wa]=Manaedje les siervices ki dnèt ls eterfaces uzeu d' notifiaedje di l' estat +Comment[x-test]=xxManages services that provide status notifier user interfacesxx +Comment[zh_CN]=状态通知协议的管理服务 +Comment[zh_TW]=管理提供狀態通知使用者介面的服務 + +X-KDE-ServiceTypes=KDEDModule +X-KDE-Library=statusnotifierwatcher +X-KDE-DBus-ModuleName=statusnotifierwatcher +X-KDE-Kded-autoload=true +X-KDE-Kded-load-on-demand=false +X-KDE-Kded-phase=1 + diff --git a/statusnotifierwatcher/statusnotifierwatcher.h b/statusnotifierwatcher/statusnotifierwatcher.h new file mode 100644 index 00000000..290f194f --- /dev/null +++ b/statusnotifierwatcher/statusnotifierwatcher.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright 2009 by Marco Martin * + * * + * 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 STATUSNOTIFIERWATCHER_H +#define STATUSNOTIFIERWATCHER_H + +#include + +#include +#include +#include +#include + +class QDBusServiceWatcher; + +class StatusNotifierWatcher : public KDEDModule, protected QDBusContext +{ + Q_OBJECT + Q_PROPERTY(QStringList RegisteredStatusNotifierItems READ RegisteredStatusNotifierItems) + Q_PROPERTY(bool IsStatusNotifierHostRegistered READ IsStatusNotifierHostRegistered) + Q_PROPERTY(int ProtocolVersion READ ProtocolVersion) + +public: + StatusNotifierWatcher(QObject *parent, const QList&); + ~StatusNotifierWatcher(); + + QStringList RegisteredStatusNotifierItems() const; + + bool IsStatusNotifierHostRegistered() const; + + int ProtocolVersion() const; + +public Q_SLOTS: + void RegisterStatusNotifierItem(const QString &service); + + void RegisterStatusNotifierHost(const QString &service); + +protected Q_SLOTS: + void serviceUnregistered(const QString& name); + +Q_SIGNALS: + void StatusNotifierItemRegistered(const QString &service); + //TODO: decide if this makes sense, the systray itself could notice the vanishing of items, but looks complete putting it here + void StatusNotifierItemUnregistered(const QString &service); + void StatusNotifierHostRegistered(); + void StatusNotifierHostUnregistered(); + +private: + QDBusServiceWatcher *m_serviceWatcher; + QStringList m_registeredServices; + QSet m_statusNotifierHostServices; +}; +#endif diff --git a/statusnotifierwatcher/systemtraytypedefs.h b/statusnotifierwatcher/systemtraytypedefs.h new file mode 100644 index 00000000..20e63044 --- /dev/null +++ b/statusnotifierwatcher/systemtraytypedefs.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * * + * Copyright (C) 2009 Marco Martin * + * * + * 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 SYSTEMTRAYTYPEDEFS_H +#define SYSTEMTRAYTYPEDEFS_H + +#include +#include +#include + +struct KDbusImageStruct { + int width; + int height; + QByteArray data; +}; + +typedef QVector KDbusImageVector; + +struct KDbusToolTipStruct { + QString icon; + KDbusImageVector image; + QString title; + QString subTitle; +}; + +Q_DECLARE_METATYPE(KDbusImageStruct) +Q_DECLARE_METATYPE(KDbusImageVector) +Q_DECLARE_METATYPE(KDbusToolTipStruct) + +#endif + diff --git a/systemsettings/CMakeLists.txt b/systemsettings/CMakeLists.txt new file mode 100644 index 00000000..f448eb63 --- /dev/null +++ b/systemsettings/CMakeLists.txt @@ -0,0 +1,17 @@ +PROJECT(systemsettings) + +IF(CMAKE_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + + FIND_PACKAGE(KDE4 REQUIRED) + INCLUDE(KDE4Defaults) + ADD_DEFINITIONS(${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) + +ENDIF(CMAKE_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + +INCLUDE_DIRECTORIES (${CMAKE_CURRENT_SOURCE_DIR}/core ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) + +ADD_SUBDIRECTORY(core) +ADD_SUBDIRECTORY(app) +ADD_SUBDIRECTORY(categories) +ADD_SUBDIRECTORY(classic) +ADD_SUBDIRECTORY(icons) diff --git a/systemsettings/Mainpage.dox b/systemsettings/Mainpage.dox new file mode 100644 index 00000000..b812113d --- /dev/null +++ b/systemsettings/Mainpage.dox @@ -0,0 +1,7 @@ +/** @mainpage System Settings interface + * This is a collection of standard plugin interfaces to System Settings. + */ + +// DOXYGEN_ENABLE = YES +// DOXYGEN_SET_PROJECT_NAME = System Settings +// DOXYGEN_SET_EXCLUDE_PATTERNS += */app/* */icons/* */classic/* diff --git a/systemsettings/Messages.sh b/systemsettings/Messages.sh new file mode 100644 index 00000000..4ca6099f --- /dev/null +++ b/systemsettings/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC `find . -name \*.ui -o -name \*.rc -o -name \*.kcfg` >> rc.cpp +$XGETTEXT `find . -name \*.cpp` -o $podir/systemsettings.pot +rm -f rc.cpp diff --git a/systemsettings/app/BaseConfig.kcfgc b/systemsettings/app/BaseConfig.kcfgc new file mode 100644 index 00000000..e420cdf9 --- /dev/null +++ b/systemsettings/app/BaseConfig.kcfgc @@ -0,0 +1,5 @@ +File=systemsettings.kcfg +ClassName=BaseConfig +Singleton=true +Mutators=true +SetUserTexts=true diff --git a/systemsettings/app/CMakeLists.txt b/systemsettings/app/CMakeLists.txt new file mode 100644 index 00000000..2a44e49b --- /dev/null +++ b/systemsettings/app/CMakeLists.txt @@ -0,0 +1,22 @@ +include_directories( ToolTips ) + +SET( systemsettings_SRCS + SystemSettingsApp.cpp + SettingsBase.cpp + ToolTips/ktooltip.cpp + ToolTips/ktooltipwindow.cpp + ToolTips/tooltipmanager.cpp + main.cpp ) + +KDE4_ADD_APP_ICON( systemsettings_SRCS "${KDE4_ICON_INSTALL_DIR}/oxygen/*/categories/preferences-system.png" ) +KDE4_ADD_UI_FILES( systemsettings_SRCS configDialog.ui ) +KDE4_ADD_KCFG_FILES( systemsettings_SRCS BaseConfig.kcfgc ) +QT4_ADD_DBUS_ADAPTOR( systemsettings_SRCS org.kde.systemsettings.xml SystemSettingsApp.h SystemSettingsApp ) + +KDE4_ADD_EXECUTABLE( systemsettings ${systemsettings_SRCS}) + +TARGET_LINK_LIBRARIES( systemsettings ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KCMUTILS_LIBS} systemsettingsview ) + +INSTALL( TARGETS systemsettings ${INSTALL_TARGETS_DEFAULT_ARGS} ) +INSTALL( FILES systemsettingsui.rc systemsettings.kcfg DESTINATION ${DATA_INSTALL_DIR}/systemsettings ) +INSTALL( PROGRAMS kdesystemsettings.desktop systemsettings.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) diff --git a/systemsettings/app/SettingsBase.cpp b/systemsettings/app/SettingsBase.cpp new file mode 100644 index 00000000..74ccd4f8 --- /dev/null +++ b/systemsettings/app/SettingsBase.cpp @@ -0,0 +1,401 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 "SettingsBase.h" +#include "BaseConfig.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BaseData.h" +#include "ModuleView.h" + +SettingsBase::SettingsBase( QWidget * parent ) + : KXmlGuiWindow(parent) +{ + // Ensure delayed loading doesn't cause a crash + activeView = 0; + aboutDialog = 0; + configDialog = 0; + lostFound = 0; + // Prepare the view area + stackedWidget = new QStackedWidget( this ); + setCentralWidget(stackedWidget); + setWindowFlags( windowFlags() | Qt::WindowContextHelpButtonHint ); + // Initialise search + searchText = new KLineEdit( this ); + searchText->setClearButtonShown( true ); + searchText->setClickMessage( i18nc( "Search through a list of control modules", "Search" ) ); + searchText->setCompletionMode( KGlobalSettings::CompletionPopup ); + + spacerWidget = new QWidget( this ); + spacerWidget->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Maximum ); + // Initalise the window so we don't flicker + initToolBar(); + // We can now launch the delayed loading safely + QTimer::singleShot(0, this, SLOT(initApplication())); +} + +SettingsBase::~SettingsBase() +{ + delete rootModule; +} + +QSize SettingsBase::sizeHint() const +{ + return QSize(720, 600); +} + +void SettingsBase::initApplication() +{ + // Prepare the menu of all modules + categories = KServiceTypeTrader::self()->query("SystemSettingsCategory"); + modules = KServiceTypeTrader::self()->query("KCModule", "[X-KDE-System-Settings-Parent-Category] != ''"); + modules += KServiceTypeTrader::self()->query("SystemSettingsExternalApp"); + rootModule = new MenuItem( true, 0 ); + initMenuList(rootModule); + // Handle lost+found modules... + if (lostFound) { + for (int i = 0; i < modules.size(); ++i) { + const KService::Ptr entry = modules.at(i); + MenuItem * infoItem = new MenuItem(false, lostFound); + infoItem->setService( entry ); + kDebug() << "Added " << entry->name(); + } + } + + // Prepare the Base Data + BaseData::instance()->setMenuItem( rootModule ); + // Load all possible views + const KService::List pluginObjects = KServiceTypeTrader::self()->query( "SystemSettingsView" ); + const int nbPlugins = pluginObjects.count(); + for( int pluginsDone = 0; pluginsDone < nbPlugins ; ++pluginsDone ) { + KService::Ptr activeService = pluginObjects.at( pluginsDone ); + QString error; + BaseMode * controller = activeService->createInstance(this, QVariantList(), &error); + if( error.isEmpty() ) { + possibleViews.insert( activeService->library(), controller ); + controller->init( activeService ); + connect(controller, SIGNAL(changeToolBarItems(BaseMode::ToolBarItems)), this, SLOT(changeToolBar(BaseMode::ToolBarItems))); + connect(controller, SIGNAL(actionsChanged()), this, SLOT(updateViewActions())); + connect(searchText, SIGNAL(textChanged(QString)), controller, SLOT(searchChanged(QString))); + connect(controller, SIGNAL(viewChanged(bool)), this, SLOT(viewChange(bool))); + } else { + kWarning() << "View load error: " + error; + } + } + searchText->completionObject()->setIgnoreCase( true ); + searchText->completionObject()->setItems( BaseData::instance()->menuItem()->keywords() ); + changePlugin(); +} + +void SettingsBase::initToolBar() +{ + // Fill the toolbar with default actions + // Exit is the very last action + quitAction = actionCollection()->addAction( KStandardAction::Quit, "quit_action", this, SLOT(close()) ); + // Configure goes at the end + configureAction = actionCollection()->addAction( KStandardAction::Preferences, this, SLOT(configShow()) ); + configureAction->setShortcut(KShortcut(QKeySequence(Qt::CTRL + Qt::Key_M))); + configureAction->setText( i18n("Configure") ); + // Help after it + initHelpMenu(); + // Then a spacer so the search line-edit is kept separate + spacerAction = new KAction( this ); + spacerAction->setDefaultWidget(spacerWidget); + actionCollection()->addAction( "spacer", spacerAction ); + // Finally the search line-edit + searchAction = new KAction( this ); + searchAction->setDefaultWidget(searchText); + searchAction->setShortcut(KShortcut(QKeySequence(Qt::CTRL + Qt::Key_F))); + connect( searchAction, SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), + searchText, SLOT(setFocus())); + actionCollection()->addAction( "searchText", searchAction ); + // Initialise the Window + setupGUI(Save|Create,QString()); + menuBar()->hide(); + // Toolbar & Configuration + helpActionMenu->setMenu( dynamic_cast( factory()->container("help", this) ) ); + setMinimumSize(620,430); + toolBar()->setMovable(false); // We don't allow any changes + changeToolBar( BaseMode::Search | BaseMode::Configure | BaseMode::Quit ); +} + +void SettingsBase::initHelpMenu() +{ + helpActionMenu = new KActionMenu( KIcon("system-help"), i18n("Help"), this ); + helpActionMenu->setDelayed( false ); + actionCollection()->addAction( "help_toolbar_menu", helpActionMenu ); + // Add the custom actions + aboutModuleAction = actionCollection()->addAction( KStandardAction::AboutApp, "help_about_module", this, SLOT(about()) ); + changeAboutMenu( 0, aboutModuleAction, i18n("About Active Module") ); + aboutViewAction = actionCollection()->addAction( KStandardAction::AboutApp, "help_about_view", this, SLOT(about()) ); +} + +void SettingsBase::initConfig() +{ + // Prepare dialog first + configDialog = new KConfigDialog( this, "systemsettingsconfig", BaseConfig::self() ); + configDialog->setButtons( KDialog::Ok | KDialog::Cancel ); + + // Add our page + QWidget * configPage = new QWidget( configDialog ); + configWidget.setupUi(configPage); + QString iconName = KGlobal::activeComponent().aboutData()->programIconName(); + configDialog->addPage( configPage, i18nc("General config for System Settings", "General"), iconName ); + QVBoxLayout * configLayout = new QVBoxLayout; + // Get the list of modules + foreach( BaseMode * mode, possibleViews ) { + mode->addConfiguration( configDialog ); + QRadioButton * radioButton = new QRadioButton( mode->service()->name(), configWidget.GbViewStyle ); + radioButton->setIcon( KIcon(mode->service()->icon()) ); + configLayout->addWidget( radioButton ); + viewSelection.addButton( radioButton, possibleViews.values().indexOf(mode) ); + } + configWidget.GbViewStyle->setLayout( configLayout ); + configDialog->restoreDialogSize( KGlobal::config()->group("ConfigDialog") ); + connect(configDialog, SIGNAL(okClicked()), this, SLOT(configUpdated())); +} + + +void SettingsBase::initMenuList(MenuItem * parent) +{ + // look for any categories inside this level, and recurse into them + for (int i = 0; i < categories.size(); ++i) { + const KService::Ptr entry = categories.at(i); + const QString parentCategory = entry->property("X-KDE-System-Settings-Parent-Category").toString(); + const QString parentCategory2 = entry->property("X-KDE-System-Settings-Parent-Category-V2").toString(); + if ( parentCategory == parent->category() || + // V2 entries must not be empty if they want to become a proper category. + ( !parentCategory2.isEmpty() && parentCategory2 == parent->category() ) ) { + MenuItem * menuItem = new MenuItem(true, parent); + menuItem->setService( entry ); + if( menuItem->category() == "lost-and-found" ) { + lostFound = menuItem; + continue; + } + initMenuList( menuItem ); + } + } + + KService::List removeList; + + // scan for any modules at this level and add them + for (int i = 0; i < modules.size(); ++i) { + const KService::Ptr entry = modules.at(i); + const QString category = entry->property("X-KDE-System-Settings-Parent-Category").toString(); + const QString category2 = entry->property("X-KDE-System-Settings-Parent-Category-V2").toString(); + if( !parent->category().isEmpty() && (category == parent->category() || category2 == parent->category()) ) { + // Add the module info to the menu + MenuItem * infoItem = new MenuItem(false, parent); + infoItem->setService( entry ); + removeList.append( modules.at(i) ); + } + } + + for (int i = 0; i < removeList.size(); ++i) { + modules.removeOne( removeList.at(i) ); + } + + parent->sortChildrenByWeight(); +} + +void SettingsBase::configUpdated() +{ + KConfigGroup dialogConfig = KGlobal::config()->group("ConfigDialog"); + configDialog->saveDialogSize( dialogConfig ); + BaseConfig::setActiveView( possibleViews.keys().at(viewSelection.checkedId()) ); + BaseConfig::setShowToolTips( configWidget.ChTooltips->isChecked() ); + activeView->saveConfiguration(); + changePlugin(); +} + +void SettingsBase::configShow() +{ + // Initialise the configuration dialog if it hasn't already + if( !configDialog ) { + initConfig(); + } + if( activeView && activeView->moduleView() && !activeView->moduleView()->resolveChanges() ) { + return; // It shouldn't be triggering anyway, since the action is disabled + } + + activeView->loadConfiguration(); + + const QStringList pluginList = possibleViews.keys(); + const int configIndex = pluginList.indexOf( BaseConfig::activeView() ); + if( configIndex != -1 ) { + viewSelection.button( configIndex )->setChecked(true); + } + configWidget.ChTooltips->setChecked( BaseConfig::showToolTips() ); + if( pluginList.isEmpty() ) { + KMessageBox::error(this, i18n("System Settings was unable to find any views, and hence nothing is available to configure."), i18n("No views found")); + } else { + configDialog->show(); + } +} + +bool SettingsBase::queryClose() +{ + bool changes = true; + if( activeView ) { + activeView->saveState(); + changes = activeView->moduleView()->resolveChanges(); + } + BaseConfig::self()->writeConfig(); + return changes; +} + +void SettingsBase::about() +{ + delete aboutDialog; + aboutDialog = 0; + + const KAboutData * about = 0; + if( sender() == aboutViewAction ) { + about = activeView->aboutData(); + } else if( sender() == aboutModuleAction && activeView->moduleView() ) { + about = activeView->moduleView()->aboutData(); + } + + if( about ) { + aboutDialog = new KAboutApplicationDialog(about, 0); + aboutDialog->show(); + } +} + +void SettingsBase::changePlugin() +{ + if( possibleViews.count() == 0 ) { // We should ensure we have a plugin available to choose + KMessageBox::error(this, i18n("System Settings was unable to find any views, and hence has nothing to display."), i18n("No views found")); + close(); + return; // Halt now! + } + + if( activeView ) { + activeView->saveState(); + activeView->leaveModuleView(); + } + + const QString viewToUse = BaseConfig::activeView(); + if( possibleViews.keys().contains(viewToUse) ) { // First the configuration entry + activeView = possibleViews.value(viewToUse); + } + else { // Otherwise we activate the failsafe + activeView = possibleViews.begin().value(); + } + + if( stackedWidget->indexOf(activeView->mainWidget()) == -1 ) { + stackedWidget->addWidget(activeView->mainWidget()); + } + + // Handle the tooltips + qDeleteAll( tooltipManagers ); + tooltipManagers.clear(); + if ( BaseConfig::showToolTips() ) { + QList theViews = activeView->views(); + foreach ( QAbstractItemView* view, theViews ) { + tooltipManagers << new ToolTipManager( view ); + } + } + + changeAboutMenu( activeView->aboutData(), aboutViewAction, i18n("About Active View") ); + viewChange(false); + + stackedWidget->setCurrentWidget(activeView->mainWidget()); + updateViewActions(); + + activeView->giveFocus(); +} + +void SettingsBase::viewChange(bool state) +{ + KCModuleInfo * moduleInfo = activeView->moduleView()->activeModule(); + configureAction->setDisabled(state); + if( moduleInfo ) { + setCaption( moduleInfo->moduleName(), state ); + } else { + setCaption( QString(), state ); + } + changeAboutMenu( activeView->moduleView()->aboutData(), aboutModuleAction, i18n("About Active Module") ); +} + +void SettingsBase::updateViewActions() +{ + guiFactory()->unplugActionList( this, "viewActions" ); + guiFactory()->plugActionList( this, "viewActions", activeView->actionsList() ); +} + +void SettingsBase::changeToolBar( BaseMode::ToolBarItems toolbar ) +{ + if( sender() != activeView ) { + return; + } + guiFactory()->unplugActionList( this, "configure" ); + guiFactory()->unplugActionList( this, "search" ); + guiFactory()->unplugActionList( this, "quit" ); + if ( BaseMode::Search & toolbar ) { + QList searchBarActions; + searchBarActions << spacerAction << searchAction; + guiFactory()->plugActionList( this, "search", searchBarActions ); + } + if ( BaseMode::Configure & toolbar ) { + QList configureBarActions; + configureBarActions << configureAction; + guiFactory()->plugActionList( this, "configure", configureBarActions ); + } + if ( BaseMode::Quit & toolbar ) { + QList quitBarActions; + quitBarActions << quitAction; + guiFactory()->plugActionList( this, "quit", quitBarActions ); + } +} + +void SettingsBase::changeAboutMenu( const KAboutData * menuAbout, KAction * menuItem, QString fallback ) +{ + if( !menuItem ) { + return; + } + + if( menuAbout ) { + menuItem->setText( i18n( "About %1", menuAbout->programName() ) ); + menuItem->setIcon( KIcon( menuAbout->programIconName() ) ); + menuItem->setEnabled(true); + } else { + menuItem->setText( fallback ); + menuItem->setIcon( KIcon( KGlobal::activeComponent().aboutData()->programIconName() ) ); + menuItem->setEnabled(false); + } +} + +#include "SettingsBase.moc" diff --git a/systemsettings/app/SettingsBase.h b/systemsettings/app/SettingsBase.h new file mode 100644 index 00000000..e1bd27f6 --- /dev/null +++ b/systemsettings/app/SettingsBase.h @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2009 by Ben Cooksley * + * * + * 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 SETTINGS_BASE_H +#define SETTINGS_BASE_H + +#include "MenuItem.h" +#include "BaseMode.h" +#include "tooltipmanager.h" +#include "ui_configDialog.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +class SettingsBase : public KXmlGuiWindow +{ + Q_OBJECT + +public: + explicit SettingsBase(QWidget * parent = 0); + ~SettingsBase(); + bool queryClose(); + +protected: + virtual QSize sizeHint() const; + +private slots: + void initApplication(); + void initToolBar(); + void initHelpMenu(); + void initConfig(); + void initMenuList(MenuItem * parent); + void configUpdated(); + void configShow(); + void about(); + void changePlugin(); + void viewChange(bool state); + void updateViewActions(); + void changeToolBar( BaseMode::ToolBarItems toolbar ); + void changeAboutMenu( const KAboutData * menuAbout, KAction * menuItem, QString fallback ); + +private: + // The plugins + QMap possibleViews; + QList tooltipManagers; + BaseMode * activeView; + // The search bar + KLineEdit * searchText; + QWidget * spacerWidget; + // The toolbar + KAction * searchAction; + KAction * spacerAction; + KAction * configureAction; + KAction * quitAction; + // The help menu + KAction * aboutViewAction; + KAction * aboutModuleAction; + KActionMenu * helpActionMenu; + // The configuration + KConfigDialog * configDialog; + Ui::ConfigDialog configWidget; + QButtonGroup viewSelection; + // The control module + QStackedWidget * stackedWidget; + // The module list + MenuItem * rootModule; + MenuItem * lostFound; + KService::List categories; + KService::List modules; + // The about dialog + KAboutApplicationDialog * aboutDialog; +}; +#endif diff --git a/systemsettings/app/SystemSettingsApp.cpp b/systemsettings/app/SystemSettingsApp.cpp new file mode 100644 index 00000000..2efceba8 --- /dev/null +++ b/systemsettings/app/SystemSettingsApp.cpp @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2009 Ben Cooksley + * + * 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 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 "SystemSettingsApp.h" + +SystemSettingsApp::SystemSettingsApp() + : KUniqueApplication() +{ + window = 0; +} + +SystemSettingsApp::~SystemSettingsApp() +{ +} + +void SystemSettingsApp::setMainWindow(SettingsBase * main) +{ + window = main; +} + +void SystemSettingsApp::quit() +{ + if( window ) { + if( !window->queryClose() ) { + return; + } + } + KUniqueApplication::quit(); +} + +#include "SystemSettingsApp.moc" diff --git a/systemsettings/app/SystemSettingsApp.h b/systemsettings/app/SystemSettingsApp.h new file mode 100644 index 00000000..466d88b6 --- /dev/null +++ b/systemsettings/app/SystemSettingsApp.h @@ -0,0 +1,49 @@ +/** + * Copyright (C) 2009 Ben Cooksley + * + * 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 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. + */ + +/** + * Any changes to this header file need to have the following command executed afterwards to regenerate the dbus interface + * qdbuscpp2xml SystemSettingsApp.h -o org.kde.systemsettings.xml + */ + +#ifndef SYSTEMSETTINGSAPP_H +#define SYSTEMSETTINGSAPP_H + +#include + +#include "SettingsBase.h" + +class SystemSettingsApp : public KUniqueApplication +{ + Q_OBJECT + +public: + SystemSettingsApp(); + ~SystemSettingsApp(); + + void setMainWindow(SettingsBase * main); + +public Q_SLOTS: + Q_SCRIPTABLE void quit(); + +private: + SettingsBase * window; +}; + +#endif diff --git a/systemsettings/app/ToolTips/ktooltip.cpp b/systemsettings/app/ToolTips/ktooltip.cpp new file mode 100644 index 00000000..99114106 --- /dev/null +++ b/systemsettings/app/ToolTips/ktooltip.cpp @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (C) 2008 by Fredrik Höglund * + * * + * 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 "ktooltip.h" +#include "ktooltipwindow_p.h" +#include +#include +#include + +class KToolTipManager +{ +public: + ~KToolTipManager(); + + static KToolTipManager* instance(); + + void showTip(const QPoint& pos, QWidget* content); + void hideTip(); + +private: + KToolTipManager(); + + KToolTipWindow* m_window; + static KToolTipManager *s_instance; +}; + +KToolTipManager *KToolTipManager::s_instance = 0; + +KToolTipManager::KToolTipManager() : + m_window(0) +{ +} + +KToolTipManager::~KToolTipManager() +{ + delete m_window; + m_window = 0; +} + +KToolTipManager* KToolTipManager::instance() +{ + if (s_instance == 0) { + s_instance = new KToolTipManager(); + } + + return s_instance; +} + +void KToolTipManager::showTip(const QPoint& pos, QWidget* content) +{ + hideTip(); + Q_ASSERT(m_window == 0); + m_window = new KToolTipWindow(content); + m_window->move(pos); + m_window->show(); +} + +void KToolTipManager::hideTip() +{ + if (m_window != 0) { + m_window->hide(); + m_window->deleteLater(); + m_window = 0; + } +} + +namespace KToolTip +{ + void showText(const QPoint& pos, const QString& text) + { + QLabel* label = new QLabel(text); + label->setForegroundRole(QPalette::ToolTipText); + showTip(pos, label); + } + + void showTip(const QPoint& pos, QWidget* content) + { + KToolTipManager::instance()->showTip(pos, content); + } + + void hideTip() + { + KToolTipManager::instance()->hideTip(); + } +} + diff --git a/systemsettings/app/ToolTips/ktooltip.h b/systemsettings/app/ToolTips/ktooltip.h new file mode 100644 index 00000000..bd539b83 --- /dev/null +++ b/systemsettings/app/ToolTips/ktooltip.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2008 by Fredrik Höglund * + * * + * 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 KTOOLTIP_H +#define KTOOLTIP_H + +class QPoint; +class QString; +class QWidget; + +/** + * Allows to show tooltips having a widget as content. + */ +namespace KToolTip +{ + void showText(const QPoint& pos, const QString& text); + + /** + * Shows the tip @p content at the global position indicated by @p pos. + * + * Ownership of the content widget is transferred to KToolTip. The widget will be deleted + * automatically when it is hidden. + * + * The tip is shown immediately when this function is called. + */ + void showTip(const QPoint& pos, QWidget* content); + void hideTip(); +} + +#endif diff --git a/systemsettings/app/ToolTips/ktooltipwindow.cpp b/systemsettings/app/ToolTips/ktooltipwindow.cpp new file mode 100644 index 00000000..fdff9862 --- /dev/null +++ b/systemsettings/app/ToolTips/ktooltipwindow.cpp @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (C) 2008 by Fredrik Höglund * + * Copyright (C) 2008 by Konstantin Heil * + * Copyright (C) 2009 by Peter Penz * + * Copyright (C) 2012 by Mark Gaiser * + * * + * 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 "ktooltipwindow_p.h" + +#include +#include +#include +#include + +// For the blurred tooltip background +#include + +KToolTipWindow::KToolTipWindow(QWidget* content) : + QWidget(0) +{ + setAttribute(Qt::WA_TranslucentBackground); + setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint); + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(content); +} + +KToolTipWindow::~KToolTipWindow() +{ +} + +void KToolTipWindow::paintEvent(QPaintEvent* event) +{ + QStylePainter painter(this); + QStyleOptionFrame option; + option.init(this); + painter.drawPrimitive(QStyle::PE_PanelTipLabel, option); + painter.end(); + + QWidget::paintEvent(event); +} + +void KToolTipWindow::showEvent(QShowEvent *) +{ + Plasma::WindowEffects::overrideShadow(winId(), true); + Plasma::WindowEffects::enableBlurBehind(winId(), true, mask()); +} + +#include "ktooltipwindow_p.moc" diff --git a/systemsettings/app/ToolTips/ktooltipwindow_p.h b/systemsettings/app/ToolTips/ktooltipwindow_p.h new file mode 100644 index 00000000..4ffe22ba --- /dev/null +++ b/systemsettings/app/ToolTips/ktooltipwindow_p.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2009 by Peter Penz * + * Copyright (C) 2012 by Mark Gaiser * + * * + * 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 KTOOLTIPWINDOW_H +#define KTOOLTIPWINDOW_H + +#include +class QPaintEvent; + +class KToolTipWindow : public QWidget +{ + Q_OBJECT + +public: + explicit KToolTipWindow(QWidget* content); + virtual ~KToolTipWindow(); + +protected: + virtual void paintEvent(QPaintEvent* event); + virtual void showEvent(QShowEvent *); +}; + +#endif diff --git a/systemsettings/app/ToolTips/tooltipmanager.cpp b/systemsettings/app/ToolTips/tooltipmanager.cpp new file mode 100644 index 00000000..2046b09b --- /dev/null +++ b/systemsettings/app/ToolTips/tooltipmanager.cpp @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (C) 2008 by Konstantin Heil * + * * + * 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 "tooltipmanager.h" + +#include "MenuItem.h" + +#include "ktooltip.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_X11 +#include +#endif + +#include +#include +#include + +class ToolTipManager::Private +{ +public: + Private() : + view(0), + timer(0) + { } + + QAbstractItemView* view; + QTimer* timer; + QModelIndex item; + QRect itemRect; +}; + +ToolTipManager::ToolTipManager(QAbstractItemView* parent) + : QObject(parent) + , d(new ToolTipManager::Private) +{ + d->view = parent; + + connect(parent, SIGNAL(viewportEntered()), this, SLOT(hideToolTip())); + connect(parent, SIGNAL(entered(QModelIndex)), this, SLOT(requestToolTip(QModelIndex))); + + d->timer = new QTimer(this); + d->timer->setSingleShot(true); + connect(d->timer, SIGNAL(timeout()), this, SLOT(prepareToolTip())); + + // When the mousewheel is used, the items don't get a hovered indication + // (Qt-issue #200665). To assure that the tooltip still gets hidden, + // the scrollbars are observed. + connect(parent->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hideToolTip())); + connect(parent->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hideToolTip())); + + d->view->viewport()->installEventFilter(this); +} + +ToolTipManager::~ToolTipManager() +{ + delete d; +} + +bool ToolTipManager::eventFilter(QObject* watched, QEvent* event) +{ + if ( watched == d->view->viewport() ) { + switch ( event->type() ) { + case QEvent::Leave: + case QEvent::MouseButtonPress: + hideToolTip(); + break; + case QEvent::ToolTip: + return true; + default: + break; + } + } + + return QObject::eventFilter(watched, event); +} + +void ToolTipManager::requestToolTip(const QModelIndex& index) +{ + // only request a tooltip for the name column and when no selection or + // drag & drop operation is done (indicated by the left mouse button) + if ( !(QApplication::mouseButtons() & Qt::LeftButton) ) { + KToolTip::hideTip(); + + d->itemRect = d->view->visualRect(index); + const QPoint pos = d->view->viewport()->mapToGlobal(d->itemRect.topLeft()); + d->itemRect.moveTo(pos); + d->item = index; + d->timer->start(300); + } else { + hideToolTip(); + } +} + +void ToolTipManager::hideToolTip() +{ + d->timer->stop(); + KToolTip::hideTip(); +} + +void ToolTipManager::prepareToolTip() +{ + showToolTip( d->item ); +} + +void ToolTipManager::showToolTip( QModelIndex menuItem ) +{ + if (QApplication::mouseButtons() & Qt::LeftButton) { + return; + } + + QWidget * tip = createTipContent( menuItem ); + + // calculate the x- and y-position of the tooltip + const QSize size = tip->sizeHint(); + const QRect desktop = QApplication::desktop()->screenGeometry( d->itemRect.bottomRight() ); + + // d->itemRect defines the area of the item, where the tooltip should be + // shown. Per default the tooltip is shown in the bottom right corner. + // If the tooltip content exceeds the desktop borders, it must be assured that: + // - the content is fully visible + // - the content is not drawn inside d->itemRect + const int margin = 3; + const bool hasRoomToLeft = (d->itemRect.left() - size.width() - margin >= desktop.left()); + const bool hasRoomToRight = (d->itemRect.right() + size.width() + margin <= desktop.right()); + const bool hasRoomAbove = (d->itemRect.top() - size.height() - margin >= desktop.top()); + const bool hasRoomBelow = (d->itemRect.bottom() + size.height() + margin <= desktop.bottom()); + if (!hasRoomAbove && !hasRoomBelow && !hasRoomToLeft && !hasRoomToRight) { + delete tip; + tip = 0; + return; + } + + int x = 0; + int y = 0; + if (hasRoomBelow || hasRoomAbove) { + x = qMax(desktop.left(), d->itemRect.center().x() - size.width() / 2); + if (x + size.width() / 2 >= desktop.right()) { + x = desktop.right() - size.width(); + } + + y = hasRoomBelow ? d->itemRect.bottom() + margin : d->itemRect.top() - size.height() - margin; + } else { + Q_ASSERT(hasRoomToLeft || hasRoomToRight); + x = hasRoomToRight ? d->itemRect.right() + margin : d->itemRect.left() - size.width() - margin; + + // Put the tooltip at the bottom of the screen. The x-coordinate has already + // been adjusted, so that no overlapping with d->itemRect occurs. + y = desktop.bottom() - size.height(); + } + + // the ownership of tip is transferred to KToolTip + KToolTip::showTip(QPoint(x, y), tip); +} + +QWidget * ToolTipManager::createTipContent( QModelIndex item ) +{ + const QSize dialogIconSize = QSize(IconSize(KIconLoader::Dialog), IconSize(KIconLoader::Dialog)); + const QSize toolbarIconSize = QSize(IconSize(KIconLoader::MainToolbar), IconSize(KIconLoader::MainToolbar)); + + QWidget * tipContent = new QWidget(); + QGridLayout* tipLayout = new QGridLayout(); + + QLayout * primaryLine = generateToolTipLine( &item, tipContent, dialogIconSize, true ); + tipLayout->addLayout( primaryLine, 0, 0 ); + + for ( int done = 0; d->view->model()->rowCount( item ) > done; done = 1 + done ) { + QModelIndex childItem = d->view->model()->index( done, 0, item ); + QLayout * subLine = generateToolTipLine( &childItem, tipContent, toolbarIconSize, false ); + tipLayout->addLayout( subLine, done + 2, 0 ); + } + + tipLayout->setVerticalSpacing( 0 ); + tipContent->setLayout( tipLayout ); + + if( d->view->model()->rowCount( item ) > 0 ) { + QFrame * separatorLine = new QFrame( tipContent ); + separatorLine->setFrameStyle( QFrame::HLine ); + tipLayout->addWidget( separatorLine, 1, 0 ); + } + + return tipContent; +} + +QLayout * ToolTipManager::generateToolTipLine( QModelIndex * item, QWidget * toolTip, QSize iconSize, bool comment ) +{ + // Get MenuItem + MenuItem * menuItem = d->view->model()->data( *item, Qt::UserRole ).value(); + + QString text = menuItem->name(); + if ( comment ) { + text = QString( "%1" ).arg( menuItem->name() ); + } + + // Generate text + if ( comment ) { + text += "
"; + if ( !menuItem->service()->comment().isEmpty() ) { + text += menuItem->service()->comment(); + } else { + int childCount = d->view->model()->rowCount( *item ); + text += i18np( "Contains 1 item", "Contains %1 items", childCount ); + } + } + QLabel * textLabel = new QLabel( toolTip ); + textLabel->setForegroundRole(QPalette::ToolTipText); + textLabel->setText( text ); + + // Get icon + KIcon icon( menuItem->service()->icon() ); + QLabel * iconLabel = new QLabel( toolTip ); + iconLabel->setPixmap( icon.pixmap(iconSize) ); + iconLabel->setMaximumSize( iconSize ); + + // Generate layout + QHBoxLayout * layout = new QHBoxLayout(); + layout->addWidget( iconLabel ); + layout->addWidget( textLabel ); + + return layout; +} + +#include "tooltipmanager.moc" diff --git a/systemsettings/app/ToolTips/tooltipmanager.h b/systemsettings/app/ToolTips/tooltipmanager.h new file mode 100644 index 00000000..32966681 --- /dev/null +++ b/systemsettings/app/ToolTips/tooltipmanager.h @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (C) 2008 by Konstantin Heil * + * * + * 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 TOOLTIPMANAGER_H +#define TOOLTIPMANAGER_H + +#include + +#include + +class QLayout; +class MenuItem; +class KToolTipItem; +class QAbstractItemView; + +/** + * @brief Manages the tooltips for an item view. + * + * When hovering an item, a tooltip is shown after + * a short timeout. The tooltip is hidden again when the + * viewport is hovered or the item view has been left. + */ +class ToolTipManager : public QObject +{ + Q_OBJECT + +public: + /** + * Standard constructor. The ToolTipManager will start handling ToolTip events on the provided + * view immediately. + * + * @param parent The view which will have the tooltips displayed for. + */ + explicit ToolTipManager(QAbstractItemView* parent); + virtual ~ToolTipManager(); + +public Q_SLOTS: + /** + * Hides the currently shown tooltip. Invoking this method is + * only needed when the tooltip should be hidden although + * an item is hovered. + */ + void hideToolTip(); + +protected: + /** + * Please see the Qt documentation for more details. + * + * @param watched The object that was being watched. + * @param event The event object. + * @returns true if the event was handled in this filter, or false if it was not. + */ + virtual bool eventFilter( QObject* watched, QEvent* event ); + +private Q_SLOTS: + void prepareToolTip(); + void requestToolTip(const QModelIndex& index); + +private: + void showToolTip( QModelIndex menuItem ); + QWidget * createTipContent( QModelIndex item ); + QLayout * generateToolTipLine( QModelIndex * item, QWidget * toolTip, QSize iconSize, bool comment ); + + class Private; + ToolTipManager::Private* d; +}; + +#endif diff --git a/systemsettings/app/configDialog.ui b/systemsettings/app/configDialog.ui new file mode 100644 index 00000000..ac19823a --- /dev/null +++ b/systemsettings/app/configDialog.ui @@ -0,0 +1,45 @@ + + + ConfigDialog + + + + 0 + 0 + 491 + 141 + + + + + + + View Style + + + + + + + Show detailed tooltips + + + + + + + Qt::Vertical + + + + 20 + 44 + + + + + + + + + diff --git a/systemsettings/app/kdesystemsettings.desktop b/systemsettings/app/kdesystemsettings.desktop new file mode 100755 index 00000000..83cda898 --- /dev/null +++ b/systemsettings/app/kdesystemsettings.desktop @@ -0,0 +1,113 @@ +[Desktop Entry] +Exec=systemsettings -caption %c %i +Icon=preferences-system +Type=Application +X-KDE-StartupNotify=true +NotShowIn=KDE; + +GenericName=KDE System Settings +GenericName[ar]=إعدادات نظام كدي +GenericName[bs]=Sistemske postavke KDE-a +GenericName[ca]=Arranjament del sistema del KDE +GenericName[ca@valencia]=Arranjament del sistema del KDE +GenericName[cs]=Nastavení systému KDE +GenericName[da]=KDE Systemindstillinger +GenericName[de]=KDE-Systemeinstellungen +GenericName[el]=Ρυθμίσεις συστήματος του KDE +GenericName[en_GB]=KDE System Settings +GenericName[es]=Preferencias del sistema de KDE +GenericName[et]=KDE Süsteemi seadistused +GenericName[eu]=KDE sistemaren ezarpenak +GenericName[fi]=KDE:n järjestelmäasetukset +GenericName[fr]=Configuration du système de KDE +GenericName[ga]=Socruithe an Chórais KDE +GenericName[gl]=Configuración do sistema KDE +GenericName[he]=הגדרות מערכת של KDE +GenericName[hu]=KDE Rendszerbeállítások +GenericName[ia]=Preferentias de systema KDE +GenericName[is]=KDE kerfisstillingar +GenericName[it]=Impostazioni di sistema KDE +GenericName[kk]=KDE жүйелік параметрлері +GenericName[km]=ការ​កំណត់​ប្រព័ន្ធ KDE +GenericName[ko]=KDE 시스템 설정 +GenericName[lt]=KDE sistemos nustatymai +GenericName[lv]=KDE sistēmas iestatījumi +GenericName[mr]=केडीई प्रणाली संयोजना +GenericName[nb]=KDE Systeminnstillinger +GenericName[nds]=KDE-Systeeminstellen +GenericName[nl]=KDE-systeeminstellingen +GenericName[pa]=KDE ਸਿਸਟਮ ਸੈਟਿੰਗ +GenericName[pl]=Ustawienia systemowe KDE +GenericName[pt]=Configuração do Sistema KDE +GenericName[pt_BR]=Configurações do sistema KDE +GenericName[ro]=Configurări de sistem +GenericName[ru]=Параметры системы KDE +GenericName[sk]=Nastavenie systému KDE +GenericName[sl]=KDE-jeve sistemske nastavitve +GenericName[sr]=КДЕ Системске поставке +GenericName[sr@ijekavian]=КДЕ Системске поставке +GenericName[sr@ijekavianlatin]=KDE Sistemske postavke +GenericName[sr@latin]=KDE Sistemske postavke +GenericName[sv]=KDE:s systeminställningar +GenericName[tr]=KDE Sistem Ayarları +GenericName[ug]=KDE سىستېما تەڭشىكى +GenericName[uk]=Системні параметри KDE +GenericName[vi]=Thiết lập hệ thống KDE +GenericName[x-test]=xxKDE System Settingsxx +GenericName[zh_CN]=KDE 系统设置 +GenericName[zh_TW]=KDE 系統設定 + +Name=KDE System Settings +Name[ar]=إعدادات نظام كدي +Name[bs]=Sistemske postavke KDE-a +Name[ca]=Arranjament del sistema del KDE +Name[ca@valencia]=Arranjament del sistema del KDE +Name[cs]=Nastavení systému KDE +Name[da]=KDE Systemindstillinger +Name[de]=KDE-Systemeinstellungen +Name[el]=Ρυθμίσεις συστήματος του KDE +Name[en_GB]=KDE System Settings +Name[es]=Preferencias del sistema de KDE +Name[et]=KDE Süsteemi seadistused +Name[eu]=KDE sistemaren ezarpenak +Name[fi]=KDE:n järjestelmäasetukset +Name[fr]=Configuration du système de KDE +Name[ga]=Socruithe an Chórais KDE +Name[gl]=Configuración do sistema KDE +Name[he]=הגדרות מערכת של KDE +Name[hu]=KDE Rendszerbeállítások +Name[ia]=Preferentias de systema KDE +Name[is]=KDE kerfisstillingar +Name[it]=Impostazioni di sistema KDE +Name[kk]=KDE жүйелік параметрлері +Name[km]=ការ​កំណត់​ប្រព័ន្ធ KDE +Name[ko]=KDE 시스템 설정 +Name[lt]=KDE sistemos nustatymai +Name[lv]=KDE sistēmas iestatījumi +Name[mr]=केडीई प्रणाली संयोजना +Name[nb]=KDE Systeminnstillinger +Name[nds]=KDE-Systeeminstellen +Name[nl]=KDE-systeeminstellingen +Name[pa]=KDE ਸਿਸਟਮ ਸੈਟਿੰਗ +Name[pl]=Ustawienia systemowe KDE +Name[pt]=Configuração do Sistema KDE +Name[pt_BR]=Configurações do sistema KDE +Name[ro]=Configurări de sistem KDE +Name[ru]=Параметры системы KDE +Name[sk]=Nastavenie systému KDE +Name[sl]=KDE-jeve sistemske nastavitve +Name[sr]=КДЕ Системске поставке +Name[sr@ijekavian]=КДЕ Системске поставке +Name[sr@ijekavianlatin]=KDE Sistemske postavke +Name[sr@latin]=KDE Sistemske postavke +Name[sv]=KDE:s systeminställningar +Name[tr]=KDE Sistem Ayarları +Name[ug]=KDE سىستېما تەڭشىكى +Name[uk]=Системні параметри KDE +Name[vi]=Thiết lập hệ thống KDE +Name[x-test]=xxKDE System Settingsxx +Name[zh_CN]=KDE 系统设置 +Name[zh_TW]=KDE 系統設定 + +X-DBUS-StartupType=Unique +Categories=Qt;KDE;Settings; diff --git a/systemsettings/app/main.cpp b/systemsettings/app/main.cpp new file mode 100644 index 00000000..340b8d80 --- /dev/null +++ b/systemsettings/app/main.cpp @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2009 Ben Cooksley + * + * This file was sourced from the System Settings package + * Copyright (C) 2005 Benjamin C Meyer + * + * + * 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 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 +#include +#include +#include +#include + +#include "SystemSettingsApp.h" +#include "SettingsBase.h" + +int main( int argc, char *argv[] ) +{ + // About data + KAboutData aboutData("systemsettings", 0, ki18n("System Settings"), WORKSPACE_VERSION_STRING, ki18n("Central configuration center for KDE."), KAboutData::License_GPL, ki18n("(c) 2009, Ben Cooksley")); + aboutData.addAuthor(ki18n("Ben Cooksley"), ki18n("Maintainer"), "bcooksley@kde.org"); + aboutData.addAuthor(ki18n("Mathias Soeken"), ki18n("Developer"), "msoeken@informatik.uni-bremen.de"); + aboutData.addAuthor(ki18n("Will Stephenson"), ki18n("Internal module representation, internal module model"), "wstephenson@kde.org"); + + aboutData.setProgramIconName("preferences-system"); + KCmdLineArgs::init(argc, argv, &aboutData); + + SystemSettingsApp application; + + SettingsBase *mainWindow = new SettingsBase(); + mainWindow->show(); + application.setMainWindow(mainWindow); + return application.exec(); +} diff --git a/systemsettings/app/org.kde.systemsettings.xml b/systemsettings/app/org.kde.systemsettings.xml new file mode 100644 index 00000000..c4afba19 --- /dev/null +++ b/systemsettings/app/org.kde.systemsettings.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/systemsettings/app/systemsettings.desktop b/systemsettings/app/systemsettings.desktop new file mode 100755 index 00000000..ce2fbe88 --- /dev/null +++ b/systemsettings/app/systemsettings.desktop @@ -0,0 +1,178 @@ +[Desktop Entry] +Exec=systemsettings -caption %c %i +Icon=preferences-system +Type=Application +X-DocPath=systemsettings/index.html +X-KDE-StartupNotify=true +OnlyShowIn=KDE; + +GenericName=System Settings +GenericName[ar]=إعدادات النظام +GenericName[ast]=Preferencies del sistema +GenericName[be@latin]=Systemnyja nałady +GenericName[bg]=Системни настройки +GenericName[bn]=সিস্টেম সেটিংস +GenericName[bn_IN]=সিস্টেম সংক্রান্ত বৈশিষ্ট্য +GenericName[bs]=Sistemske postavke +GenericName[ca]=Arranjament del sistema +GenericName[ca@valencia]=Arranjament del sistema +GenericName[cs]=Nastavení systému +GenericName[csb]=Systemòwé ùstôwë +GenericName[da]=Systemindstillinger +GenericName[de]=Systemeinstellungen +GenericName[el]=Ρυθμίσεις συστήματος +GenericName[en_GB]=System Settings +GenericName[eo]=Sistema agordo +GenericName[es]=Preferencias del sistema +GenericName[et]=Süsteemi seadistused +GenericName[eu]=Sistemaren ezarpenak +GenericName[fi]=Järjestelmäasetukset +GenericName[fr]=Configuration du système +GenericName[fy]=Systeemynstellings +GenericName[ga]=Socruithe an Chórais +GenericName[gl]=Configuración do sistema +GenericName[gu]=સિસ્ટમ ગોઠવણીઓ +GenericName[he]=הגדרות מערכת +GenericName[hi]=तंत्र विन्यास +GenericName[hne]=तंत्र सेटिंग +GenericName[hr]=Postavke sustava +GenericName[hu]=Rendszerbeállítások +GenericName[ia]=Preferentias de systema +GenericName[id]=Pengaturan Sistem +GenericName[is]=Kerfisstillingar +GenericName[it]=Impostazioni di sistema +GenericName[ja]=システム設定 +GenericName[kk]=Жүйе параметрлері +GenericName[km]=ការ​កំណត់​ប្រព័ន្ធ​ +GenericName[kn]=ವ್ಯವಸ್ಥೆಯ ಸಂಯೋಜನೆಗಳು +GenericName[ko]=시스템 설정 +GenericName[ku]=Mîhengên Pergalê +GenericName[lt]=Sistemos nustatymai +GenericName[lv]=Sistēmas iestatījumi +GenericName[mai]=तंत्र बिन्यास +GenericName[mk]=Системски поставувања +GenericName[ml]=സിസ്റ്റം സജ്ജീകരണങ്ങള്‍ +GenericName[mr]=प्रणाली संयोजना +GenericName[nb]=Systeminnstillinger +GenericName[nds]=Systeeminstellen +GenericName[nl]=Systeeminstellingen +GenericName[nn]=Systemoppsett +GenericName[oc]=Configuracion del sistèma +GenericName[or]=ତନ୍ତ୍ର ବିନ୍ୟାସ +GenericName[pa]=ਸਿਸਟਮ ਸੈਟਿੰਗ +GenericName[pl]=Ustawienia systemowe +GenericName[pt]=Configuração do Sistema +GenericName[pt_BR]=Configurações do Sistema +GenericName[ro]=Configurări de sistem +GenericName[ru]=Параметры системы +GenericName[se]=Vuogádatheivehusat +GenericName[si]=පද්ධති සැකසුම් +GenericName[sk]=Systémové nastavenia +GenericName[sl]=Sistemske nastavitve +GenericName[sr]=Системске поставке +GenericName[sr@ijekavian]=Системске поставке +GenericName[sr@ijekavianlatin]=Sistemske postavke +GenericName[sr@latin]=Sistemske postavke +GenericName[sv]=Systeminställningar +GenericName[ta]=System Settings +GenericName[te]=సిస్టమ్ అమర్పులు +GenericName[tg]=Танзимотҳои система +GenericName[th]=ตั้งค่าระบบ +GenericName[tr]=Sistem Ayarları +GenericName[ug]=سىستېما تەڭشىكى +GenericName[uk]=Системні параметри +GenericName[uz]=Tizim moslamalari +GenericName[uz@cyrillic]=Тизим мосламалари +GenericName[wa]=Apontiaedjes do sistinme +GenericName[x-test]=xxSystem Settingsxx +GenericName[zh_CN]=系统设置 +GenericName[zh_TW]=系統設定 + +Name=System Settings +Name[ar]=إعدادات النظام +Name[ast]=Preferencies del sistema +Name[be]=Сістэмныя настаўленні +Name[be@latin]=Systemnyja nałady +Name[bg]=Системни настройки +Name[bn]=সিস্টেম সেটিংস +Name[bn_IN]=সিস্টেম সংক্রান্ত বৈশিষ্ট্য +Name[br]=Dibarzhoù ar reizhiad +Name[bs]=Sistemske postavke +Name[ca]=Arranjament del sistema +Name[ca@valencia]=Arranjament del sistema +Name[cs]=Nastavení systému +Name[csb]=Systemòwé ùstôwë +Name[da]=Systemindstillinger +Name[de]=Systemeinstellungen +Name[el]=Ρυθμίσεις συστήματος +Name[en_GB]=System Settings +Name[eo]=Sistema agordo +Name[es]=Preferencias del sistema +Name[et]=Süsteemi seadistused +Name[eu]=Sistemaren ezarpenak +Name[fa]=تنظیمات سیستم +Name[fi]=Järjestelmäasetukset +Name[fr]=Configuration du système +Name[fy]=Systeemynstellings +Name[ga]=Socruithe an Chórais +Name[gl]=Configuración do sistema +Name[gu]=સિસ્ટમ ગોઠવણીઓ +Name[he]=הגדרות מערכת +Name[hi]=तंत्र विन्यास +Name[hne]=तंत्र सेटिंग +Name[hr]=Postavke sustava +Name[hu]=Rendszerbeállítások +Name[ia]=Preferentias de systema +Name[id]=Pengaturan Sistem +Name[is]=Kerfisstillingar +Name[it]=Impostazioni di sistema +Name[ja]=KDE システム設定 +Name[kk]=Жүйе параметрлері +Name[km]=ការ​កំណត់​ប្រព័ន្ធ​ +Name[kn]=ವ್ಯವಸ್ಥೆಯ ಸಂಯೋಜನೆಗಳು +Name[ko]=시스템 설정 +Name[ku]=Mîhengên Pergalê +Name[lt]=Sistemos nustatymai +Name[lv]=Sistēmas iestatījumi +Name[mai]=तंत्र बिन्यास +Name[mk]=Системски поставувања +Name[ml]=സിസ്റ്റം സജ്ജീകരണങ്ങള്‍ +Name[mr]=प्रणाली संयोजना +Name[nb]=Systemoppsett +Name[nds]=Systeeminstellen +Name[ne]=प्रणाली सेटिङ +Name[nl]=Systeeminstellingen +Name[nn]=Systemoppsett +Name[oc]=Configuracion del sistèma +Name[or]=ତନ୍ତ୍ର ବିନ୍ୟାସ +Name[pa]=ਸਿਸਟਮ ਸੈਟਿੰਗ +Name[pl]=Ustawienia systemowe +Name[pt]=Configuração do Sistema +Name[pt_BR]=Configurações do Sistema +Name[ro]=Configurări de sistem +Name[ru]=Параметры системы +Name[se]=Vuogádatheivehusat +Name[si]=පද්ධති සැකසුම් +Name[sk]=Systémové nastavenia +Name[sl]=Sistemske nastavitve +Name[sr]=Системске поставке +Name[sr@ijekavian]=Системске поставке +Name[sr@ijekavianlatin]=Sistemske postavke +Name[sr@latin]=Sistemske postavke +Name[sv]=Systeminställningar +Name[ta]=System Settings +Name[te]=సిస్టమ్ అమర్పులు +Name[tg]=Танзимотҳои система +Name[th]=ตั้งค่าระบบ +Name[tr]=Sistem Ayarları +Name[ug]=سىستېما تەڭشىكى +Name[uk]=Системні параметри +Name[uz]=Tizim moslamalari +Name[uz@cyrillic]=Тизим мосламалари +Name[wa]=Apontiaedjes do sistinme +Name[x-test]=xxSystem Settingsxx +Name[zh_CN]=系统设置 +Name[zh_TW]=系統設定 + +X-DBUS-StartupType=Unique +Categories=Qt;KDE;Settings; diff --git a/systemsettings/app/systemsettings.kcfg b/systemsettings/app/systemsettings.kcfg new file mode 100644 index 00000000..60ec5032 --- /dev/null +++ b/systemsettings/app/systemsettings.kcfg @@ -0,0 +1,17 @@ + + + + + + + true + + + + icon_mode + + + diff --git a/systemsettings/app/systemsettingsui.rc b/systemsettings/app/systemsettingsui.rc new file mode 100644 index 00000000..e5ba899b --- /dev/null +++ b/systemsettings/app/systemsettingsui.rc @@ -0,0 +1,24 @@ + + + + + + + + + + + About System Settings + + + + + + + + diff --git a/systemsettings/categories/CMakeLists.txt b/systemsettings/categories/CMakeLists.txt new file mode 100644 index 00000000..648a915d --- /dev/null +++ b/systemsettings/categories/CMakeLists.txt @@ -0,0 +1,38 @@ + +install( FILES systemsettingscategory.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} ) + +install( FILES + settings-accessibility.desktop + settings-account-details.desktop + settings-application-and-system-notifications.desktop + settings-application-appearance-and-behavior.desktop + settings-application-appearance.desktop + settings-audio-and-video.desktop + settings-desktop-appearance.desktop + settings-display.desktop + settings-hardware.desktop + settings-input-devices.desktop + settings-locale.desktop + settings-lost-and-found.desktop + settings-network-and-connectivity.desktop + settings-network-settings.desktop + settings-permissions.desktop + settings-personal-information.desktop + settings-power-management.desktop + settings-removable-devices.desktop + settings-shortcuts-and-gestures.desktop + settings-startup-and-shutdown.desktop + settings-system-administration.desktop + settings-window-behaviour.desktop + settings-workspace-appearance-and-behavior.desktop + settings-workspace-behavior.desktop + DESTINATION ${SERVICES_INSTALL_DIR} ) + +if (NOT WIN32) + install( FILES + settings-bluetooth.desktop + #settings-desktop.desktop + settings-sharing.desktop + DESTINATION ${SERVICES_INSTALL_DIR} ) +endif (NOT WIN32) + diff --git a/systemsettings/categories/settings-accessibility.desktop b/systemsettings/categories/settings-accessibility.desktop new file mode 100644 index 00000000..7048e411 --- /dev/null +++ b/systemsettings/categories/settings-accessibility.desktop @@ -0,0 +1,100 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=accessibility +X-KDE-System-Settings-Parent-Category=workspace-appearance-and-behavior +Icon=preferences-desktop-accessibility + +Name=Accessibility +Name[af]=Toeganklikheid +Name[ar]=الإتاحة +Name[as]=অভিগম্যতা +Name[ast]=Accesibilidá +Name[be]=Даступнасць +Name[be@latin]=Dastupnaść +Name[bg]=Равностоен достъп +Name[bn]=সহায়ক প্রযুক্তি +Name[bn_IN]=বিশেষ ব্যবহারের সহায়তা +Name[br]=Haezadusted +Name[bs]=Pristupačnost +Name[ca]=Accessibilitat +Name[ca@valencia]=Accessibilitat +Name[cs]=Zpřístupnění +Name[csb]=Pòmòce przëstãpù +Name[cy]=Hygyrchedd +Name[da]=Tilgængelighed +Name[de]=Zugangshilfen +Name[el]=Προσιτότητα +Name[en_GB]=Accessibility +Name[eo]=Alirebleco +Name[es]=Accesibilidad +Name[et]=Hõlbustus +Name[eu]=Erabilerraztasuna +Name[fa]=دستیابی‌پذیری +Name[fi]=Esteettömyys +Name[fr]=Accessibilité +Name[fy]=Tagonklikens +Name[ga]=Inrochtaineacht +Name[gl]=Accesibilidade +Name[gu]=ઉપયોગિતા +Name[he]=נגישות +Name[hi]=पहुँच +Name[hne]=पहुंच +Name[hr]=Pristupačnost +Name[hsb]=Přistupnosć +Name[hu]=Kezelési segítség +Name[ia]=Accessibilitate +Name[id]=Aksesibilitas +Name[is]=Aðgengi +Name[it]=Accessibilità +Name[ja]=アクセシビリティ +Name[ka]=სპეციალური შესაძლბლობები +Name[kk]=Арнайы мүмкіндіктер +Name[km]=មធ្យោបាយ​ងាយស្រួល +Name[kn]=ನಿಲುಕಣೆ (ಆಕ್ಸೆಸಿಬಿಲಿಟಿ) +Name[ko]=내게 필요한 설정 +Name[ku]=Gihîştin +Name[lt]=Pritaikymas neįgaliesiems +Name[lv]=Pieejamība +Name[mai]=अभिगम्यता +Name[mk]=Пристапливост +Name[ml]=സാമീപ്യത +Name[mr]=सुलभता +Name[ms]=Kebolehcapaian +Name[nb]=Tilgjengelighet +Name[nds]=Toganghülp +Name[ne]=पहुँचता +Name[nl]=Toegankelijkheid +Name[nn]=Tilgjenge +Name[oc]=Accessibilitat +Name[or]=ଅଭିଗମ୍ୟତା +Name[pa]=ਸਹੂਲਤਾਂ +Name[pl]=Ułatwienia dostępu +Name[pt]=Acessibilidade +Name[pt_BR]=Acessibilidade +Name[ro]=Accesibilitate +Name[ru]=Специальные возможности +Name[se]=Álkkibut geavaheapmi +Name[si]=ප්‍රවේශණය +Name[sk]=Prístupnosť +Name[sl]=Dostopnost +Name[sr]=Приступачност +Name[sr@ijekavian]=Приступачност +Name[sr@ijekavianlatin]=Pristupačnost +Name[sr@latin]=Pristupačnost +Name[sv]=Handikappstöd +Name[ta]=அணுகல் +Name[te]=అందుబాటు +Name[tg]=Имкониятҳо +Name[th]=ช่วยการใช้งาน +Name[tr]=Erişilebilirlik +Name[ug]=قوشۇمچە ئىقتىدار +Name[uk]=Доступність +Name[uz]=Qulayliklar +Name[uz@cyrillic]=Қулайликлар +Name[vi]=Hỗ trợ truy cập +Name[wa]=Accessibilité +Name[xh]=Unikezelo +Name[x-test]=xxAccessibilityxx +Name[zh_CN]=辅助 +Name[zh_TW]=無障礙輔助 diff --git a/systemsettings/categories/settings-account-details.desktop b/systemsettings/categories/settings-account-details.desktop new file mode 100644 index 00000000..bb622a0f --- /dev/null +++ b/systemsettings/categories/settings-account-details.desktop @@ -0,0 +1,73 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=account-details +X-KDE-System-Settings-Parent-Category=application-appearance-and-behavior +Icon=preferences-desktop-user + +Name=Account Details +Name[ar]=تفاصيل الحساب +Name[ast]=Detalles de cuentes +Name[bg]=Данни на сметката +Name[bn]=অ্যাকাউন্ট বিবরণ +Name[bs]=Detalji naloga +Name[ca]=Detalls del compte +Name[ca@valencia]=Detalls del compte +Name[cs]=Podrobnosti o účtu +Name[da]=Kontodetaljer +Name[de]=Benutzerkontodetails +Name[el]=Λεπτομέρειες λογαριασμού +Name[en_GB]=Account Details +Name[es]=Detalles de cuentas +Name[et]=Konto üksikasjad +Name[eu]=Kontuaren xehetasunak +Name[fi]=Käyttäjätilin tiedot +Name[fr]=Détails du compte +Name[ga]=Mionsonraí an Chuntais +Name[gl]=Detalles da conta +Name[gu]=ખાતા વિગતો +Name[he]=פרטי חשבון +Name[hi]=खाता विवरण +Name[hr]=Detalji korisničkog računa +Name[hu]=Felhasználói fiókadatok +Name[ia]=Detalios de conto +Name[id]=Detail Akun +Name[is]=Nánar um notanda +Name[it]=Dettagli dell'account +Name[ja]=アカウント詳細 +Name[kk]=Тіркелгі егжей-тегжейі +Name[km]=សេចក្ដី​លម្អិត​គណនី +Name[kn]=ಖಾತೆಯ ವಿವರ +Name[ko]=계정 정보 +Name[lt]=Paskyros detalės +Name[lv]=Konta detaļas +Name[mr]=खात्याचे तपशील +Name[nb]=Detaljer om kontoen +Name[nds]=Konto-Enkelheiten +Name[nl]=Accountdetails +Name[nn]=Konto­detaljar +Name[pa]=ਅਕਾਊਂਟ ਵੇਰਵਾ +Name[pl]=Szczegóły konta +Name[pt]=Detalhes da Conta +Name[pt_BR]=Detalhes da conta +Name[ro]=Detalii cont +Name[ru]=Учётная запись +Name[si]=ගිණුම් විස්තර +Name[sk]=Detaily účtu +Name[sl]=Podrobnosti računa +Name[sr]=Детаљи налога +Name[sr@ijekavian]=Детаљи налога +Name[sr@ijekavianlatin]=Detalji naloga +Name[sr@latin]=Detalji naloga +Name[sv]=Kontoinformation +Name[tg]=Тафсилоти ҳисоб +Name[th]=รายละเอียดบัญชีผู้ใช้ +Name[tr]=Hesap Detayları +Name[ug]=ھېسابات تەپسىلاتى +Name[uk]=Параметри облікового запису +Name[vi]=Chi tiết tài khoản +Name[wa]=Detays do conte +Name[x-test]=xxAccount Detailsxx +Name[zh_CN]=账户细节 +Name[zh_TW]=帳號詳細資料 + diff --git a/systemsettings/categories/settings-application-and-system-notifications.desktop b/systemsettings/categories/settings-application-and-system-notifications.desktop new file mode 100644 index 00000000..4a5ae567 --- /dev/null +++ b/systemsettings/categories/settings-application-and-system-notifications.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=application-and-system-notifications +X-KDE-System-Settings-Parent-Category=application-appearance-and-behavior +Icon=preferences-desktop-notification + +Name=Application and System Notifications +Name[ar]=تنبيهات التطبيقات والنظام +Name[ast]=Notificaciones d'aplicaciones y del sistema +Name[bg]=Програмни и системни съобщения +Name[bn]=অ্যাপলিকেশন এবং সিস্টেম বিজ্ঞপ্তি +Name[bs]=Sistemska i programska obavještenja +Name[ca]=Notificacions de les aplicacions i del sistema +Name[ca@valencia]=Notificacions de les aplicacions i del sistema +Name[cs]=Oznamování aplikací a systému +Name[da]=Program- og systembekendtgørelser +Name[de]=Anwendungs- und Systembenachrichtigungen +Name[el]=Ειδοποιήσεις εφαρμογών και συστήματος +Name[en_GB]=Application and System Notifications +Name[es]=Notificaciones de aplicaciones y del sistema +Name[et]=Rakenduste ja süsteemi märguanded +Name[eu]=Aplikazio- eta sistema-jakinarazpenak +Name[fi]=Ohjelma- ja järjestelmäilmoitukset +Name[fr]=Notifications des applications et du système +Name[gl]=Notificacións dos programas e do sistema +Name[he]=הודעות מערכת והודעות יישום +Name[hi]=अनुप्रयोग व तंत्र सूचनाएँ +Name[hr]=Obavijesti sustava i aplikacija +Name[hu]=Alkalmazás- és rendszerértesítések +Name[ia]=Applicationes e notificationes de systema +Name[id]=Notifikasi Sistem dan Aplikasi +Name[is]=Tilkynningar kerfis og forrita +Name[it]=Notifiche delle applicazioni e di sistema +Name[ja]=アプリケーションとシステムの通知 +Name[kk]=Қолданба мен жүйелік құлақтандырулары +Name[km]=កា​រជូនដំណឹង​ប្រព័ន្ធ និង​កម្មវិធី​ +Name[kn]=ಅನ್ವಯ ಹಾಗು ವ್ಯವಸ್ಥೆಯ ಸೂಚನೆಗಳು +Name[ko]=프로그램 및 시스템 알림 +Name[lt]=Programų ir sistemos pranešimai +Name[lv]=Programmu un sistēmas paziņojumi +Name[mr]=अनुप्रयोग व प्रणाली सूचना +Name[nb]=Program- og systemvarsler +Name[nds]=Programm- un Systeembescheden +Name[nl]=Programma- en systeemmeldingen +Name[nn]=Program- og system­varslingar +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਤੇ ਸਿਸਟਮ ਨੋਟੀਫਿਕੇਸ਼ਨ +Name[pl]=Powiadomienia programów i systemu +Name[pt]=Notificações das Aplicações e do Sistema +Name[pt_BR]=Notificações dos aplicativos e do sistema +Name[ro]=Notificare aplicații și sistem +Name[ru]=Уведомления +Name[si]=යෙදුම් සහ පද්ධති දැනුම්දීම් +Name[sk]=Upozornenia aplikácií a systému +Name[sl]=Obvestila programov in sistema +Name[sr]=Системска и програмска обавештења +Name[sr@ijekavian]=Системска и програмска обавјештења +Name[sr@ijekavianlatin]=Sistemska i programska obavještenja +Name[sr@latin]=Sistemska i programska obaveštenja +Name[sv]=Program- och systemunderrättelser +Name[tg]=Барномаҳо ва огоҳномаҳои система +Name[th]=การแจ้งให้ทราบของโปรแกรมและระบบ +Name[tr]=Uygulama ve Sistem Bildirimleri +Name[ug]=پروگرامما ۋە سىستېما ئۇقتۇرۇشى +Name[uk]=Сповіщення програм і системи +Name[vi]=Thông báo hệ thống và ứng dụng +Name[wa]=Notifiaedjes des programes eyet do sistinme +Name[x-test]=xxApplication and System Notificationsxx +Name[zh_CN]=应用程序和系统通知 +Name[zh_TW]=應用程式與系統通知 diff --git a/systemsettings/categories/settings-application-appearance-and-behavior.desktop b/systemsettings/categories/settings-application-appearance-and-behavior.desktop new file mode 100644 index 00000000..767c56cc --- /dev/null +++ b/systemsettings/categories/settings-application-appearance-and-behavior.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=application-appearance-and-behavior +X-KDE-System-Settings-Parent-Category= +X-KDE-Weight=80 +Icon=preferences-desktop-theme + +Name=Common Appearance and Behavior +Name[ar]=المظهر والسلوك المشتركان +Name[ast]=Apariencia y comportamientu comunes +Name[bg]=Общ изглед и поведение +Name[bn]=সাধারণ চেহারা এবং আচরণ +Name[bs]=Opšti izgled i ponašanje +Name[ca]=Aparença i comportament usual +Name[ca@valencia]=Aparença i comportament usual +Name[da]=Fælles udseende og opførsel +Name[de]=Allgemeines Erscheinungsbild und Verhalten +Name[el]=Κοινή εμφάνιση και συμπεριφορά +Name[en_GB]=Common Appearance and Behaviour +Name[es]=Apariencia y comportamiento comunes +Name[et]=Üldine välimus ja käitumine +Name[eu]=Itxura eta portaera arruntak +Name[fi]=Yleinen ulkoasu ja toiminta +Name[gl]=Aparencia e comportamento comúns +Name[he]=התנהגות ומראה אחידים +Name[hi]=सामान्य रूप व स्वभाव +Name[hr]=Zajednički izgled i ponašanje +Name[hu]=Általános megjelenés és működés +Name[ia]=Apparentia e comportamento commun +Name[id]=Perilaku dan Tampilan Umum +Name[is]=Sameiginlegt útlit og hegðun +Name[kk]=Жалпы көрнісі мен тәртібі +Name[km]=រូបរាង និង​ឥរិយាបថ​ធម្មតា​ +Name[kn]=ಸಾಮಾನ್ಯ ಗೋಚರಿಕೆ ಹಾಗು ವರ್ತನೆ +Name[ko]=공통 모양과 행동 +Name[lt]=Bendra išvaizda ir elgsena +Name[lv]=Tipisks izskats un izturēšanās +Name[mr]=सामान्य दर्शनीयता व वर्तन +Name[nb]=Felles utseende og oppførsel +Name[nds]=Allmeen Utsehn un Bedregen +Name[nl]=Gemeenschappelijk uiterlijk en gedrag +Name[nn]=Vanleg utsjånad og oppførsel +Name[pa]=ਆਮ ਦਿੱਖ ਤੇ ਰਵੱਈਆ +Name[pl]=Powszechny wygląd i zachowanie +Name[pt]=Aparência e Comportamento Comuns +Name[pt_BR]=Aparência e comportamento comuns +Name[ro]=Aspect și comportament comun +Name[ru]=Основные параметры внешнего вида и поведения +Name[sk]=Spoločný vzhľad a správanie +Name[sl]=Splošen videz in obnašanje +Name[sr]=Општи изглед и понашање +Name[sr@ijekavian]=Општи изглед и понашање +Name[sr@ijekavianlatin]=Opšti izgled i ponašanje +Name[sr@latin]=Opšti izgled i ponašanje +Name[sv]=Gemensamt utseende och beteende +Name[tg]=Намуди зоҳирӣ ва рафтори умумӣ +Name[th]=รูปลักษณ์และพฤติกรรมทั่วไป +Name[tr]=Genel Görünüm ve Davranış +Name[ug]=ئاممىۋى قىياپەت ۋە مەشغۇلات +Name[uk]=Загальний вигляд і поведінка +Name[vi]=Diện mạo và hành vi chung +Name[wa]=Comone rivnance eyet dujhance +Name[x-test]=xxCommon Appearance and Behaviorxx +Name[zh_CN]=公共外观和行为 +Name[zh_TW]=通用外觀與行為 diff --git a/systemsettings/categories/settings-application-appearance.desktop b/systemsettings/categories/settings-application-appearance.desktop new file mode 100644 index 00000000..9374a32b --- /dev/null +++ b/systemsettings/categories/settings-application-appearance.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=application-appearance +X-KDE-System-Settings-Parent-Category=application-appearance-and-behavior +Icon=preferences-desktop-theme + +Name=Application Appearance +Name[ar]=مظهر التطبيقات +Name[ast]=Apariencia de les aplicaciones +Name[bg]=Изглед на програмите +Name[bn]=অ্যাপলিকেশন-এর চেহারা +Name[bs]=Izgled programa +Name[ca]=Aparença de les aplicacions +Name[ca@valencia]=Aparença de les aplicacions +Name[cs]=Vzhled aplikací +Name[da]=Programmers udseende +Name[de]=Erscheinungsbild von Anwendungen +Name[el]=Εμφάνιση εφαρμογών +Name[en_GB]=Application Appearance +Name[es]=Apariencia de las aplicaciones +Name[et]=Rakenduste välimus +Name[eu]=Aplikazioen itxura +Name[fi]=Sovellusten ulkoasu +Name[fr]=Apparence des applications +Name[gl]=Aparencia dos programas +Name[he]=מראה יישום +Name[hi]=अनुप्रयोग रूप +Name[hr]=Izgled aplikacija +Name[hu]=Az alkalmazások megjelenése +Name[ia]=Apparentia de application +Name[id]=Tampilan Aplikasi +Name[is]=Útlit forrita +Name[it]=Aspetto delle applicazioni +Name[ja]=アプリケーションの外観 +Name[kk]=Қолданба көрінісі +Name[km]=រូបរាង​កម្មវិធី​ +Name[kn]=ಅನ್ವಯ ಗೋಚರಿಕೆ +Name[ko]=프로그램 모양 +Name[lt]=Programų išvaizda +Name[lv]=Programmu izskats +Name[mr]=अनुप्रयोग दर्शनीयता +Name[nb]=Programutseende +Name[nds]=Programmutsehn +Name[nl]=Uiterlijk van programma +Name[nn]=Program­utsjånad +Name[pa]=ਐਪਲੀਕੇਸ਼ਨ ਦਿੱਖ +Name[pl]=Wygląd programów +Name[pt]=Aparência das Aplicações +Name[pt_BR]=Aparência dos aplicativos +Name[ro]=Aspect aplicații +Name[ru]=Оформление приложений +Name[si]=යෙදුම් පෙනුම +Name[sk]=Vzhľad aplikácií +Name[sl]=Videz programov +Name[sr]=Изглед програма +Name[sr@ijekavian]=Изглед програма +Name[sr@ijekavianlatin]=Izgled programa +Name[sr@latin]=Izgled programa +Name[sv]=Programutseende +Name[tg]=Намуди зоҳирии барнома +Name[th]=รูปลักษณ์ของโปรแกรม +Name[tr]=Uygulama Görünümü +Name[ug]=پروگرامما كۆرۈنۈشى +Name[uk]=Вигляд вікон програм +Name[vi]=Diện mạo ứng dụng +Name[wa]=Rivnance des programes +Name[x-test]=xxApplication Appearancexx +Name[zh_CN]=应用程序外观 +Name[zh_TW]=應用程式外觀 diff --git a/systemsettings/categories/settings-audio-and-video.desktop b/systemsettings/categories/settings-audio-and-video.desktop new file mode 100644 index 00000000..40f94db5 --- /dev/null +++ b/systemsettings/categories/settings-audio-and-video.desktop @@ -0,0 +1,100 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=audio-and-video +X-KDE-System-Settings-Parent-Category=hardware +X-KDE-Weight=200 +Icon=applications-multimedia + +Name=Multimedia +Name[af]=Multimedia +Name[ar]=الوسائط المتعددة +Name[as]=মাল্টিমিডিয়া +Name[ast]=Multimedia +Name[be]=Мультымедыя +Name[be@latin]=Multymedyja +Name[bg]=Мултимедия +Name[bn]=মাল্টিমিডিয়া +Name[bn_IN]=মাল্টি-মিডিয়া +Name[br]=Liesvedia +Name[bs]=Multimedija +Name[ca]=Multimèdia +Name[ca@valencia]=Multimèdia +Name[cs]=Multimédia +Name[csb]=Mùltimedia +Name[cy]=Amlgyfryngau +Name[da]=Multimedie +Name[de]=Multimedia +Name[el]=Πολυμέσα +Name[en_GB]=Multimedia +Name[eo]=Aŭdvido +Name[es]=Multimedia +Name[et]=Multimeedia +Name[eu]=Multimedia +Name[fa]=چند رسانه‌ای +Name[fi]=Multimedia +Name[fr]=Multimédia +Name[fy]=Multimedia +Name[ga]=Ilmheáin +Name[gl]=Multimedia +Name[gu]=મલ્ટિમીડિઆ +Name[he]=מולטימדיה +Name[hi]=मल्टीमीडिया +Name[hne]=मल्टीमीडिया +Name[hr]=Multimedija +Name[hsb]=Multimedija +Name[hu]=Multimédia +Name[ia]=Multimedia +Name[id]=Multimedia +Name[is]=Margmiðlun +Name[it]=Multimedia +Name[ka]=მულტიმედია +Name[kk]=Мультимедиа +Name[km]=ពហុព័ត៌មាន +Name[kn]=ಬಹುಮಾಧ್ಯಮ +Name[ko]=멀티미디어 +Name[ku]=Multîmedya +Name[lt]=Multimedia +Name[lv]=Multivide +Name[mai]=मल्टीमीडिया +Name[mk]=Мултимедија +Name[ml]=മള്‍ട്ടീമീഡിയ +Name[mr]=मल्टीमीडिया +Name[ms]=Multimedia +Name[nb]=Multimedia +Name[nds]=Multimedia +Name[ne]=मल्टिमिडिया +Name[nl]=Multimedia +Name[nn]=Multimedia +Name[oc]=Multimedià +Name[or]=ବହୁମାଧ୍ଯମ +Name[pa]=ਮਲਟੀਮੀਡਿਆ +Name[pl]=Multimedia +Name[pt]=Multimédia +Name[pt_BR]=Multimídia +Name[ro]=Multimedia +Name[ru]=Мультимедиа +Name[se]=Multimedia +Name[si]=බහුමාධ්‍යය +Name[sk]=Multimédiá +Name[sl]=Predstavnost +Name[sr]=Мултимедија +Name[sr@ijekavian]=Мултимедија +Name[sr@ijekavianlatin]=Multimedija +Name[sr@latin]=Multimedija +Name[sv]=Multimedia +Name[ta]=பல்லூடகம் +Name[te]=బహుళ మాద్యమం +Name[tg]=Мултимедиа +Name[th]=มัลติมีเดีย +Name[tr]=Çoklu Ortam +Name[ug]=كۆپ ۋاسىتە +Name[uk]=Мультимедіа +Name[uz]=Multimedia +Name[uz@cyrillic]=Мултимедиа +Name[vi]=Nhạc/Ảnh +Name[wa]=Multimedia +Name[xh]=Iindlela ezininzi zokwenza +Name[x-test]=xxMultimediaxx +Name[zh_CN]=多媒体 +Name[zh_TW]=多媒體 diff --git a/systemsettings/categories/settings-bluetooth.desktop b/systemsettings/categories/settings-bluetooth.desktop new file mode 100644 index 00000000..1f050702 --- /dev/null +++ b/systemsettings/categories/settings-bluetooth.desktop @@ -0,0 +1,93 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=bluetooth +X-KDE-System-Settings-Parent-Category=network-and-connectivity +Icon=preferences-system-bluetooth + +Name=Bluetooth +Name[ar]=بلوتوث +Name[ast]=Bluetooth +Name[be]=Bluetooth +Name[be@latin]=Bluetooth +Name[bg]=Bluetooth +Name[bn]=ব্লু-টুথ +Name[bn_IN]=ব্লু-টুথ +Name[bs]=Blutut +Name[ca]=Bluetooth +Name[ca@valencia]=Bluetooth +Name[cs]=Bluetooth +Name[csb]=Bluetooth +Name[da]=Bluetooth +Name[de]=Bluetooth +Name[el]=Bluetooth +Name[en_GB]=Bluetooth +Name[eo]=Bluetooth +Name[es]=Bluetooth +Name[et]=Bluetooth +Name[eu]=Bluetootha +Name[fa]=بلوتوث +Name[fi]=Bluetooth +Name[fr]=Bluetooth +Name[fy]=Bluetooth +Name[ga]=Bluetooth +Name[gl]=Bluetooth +Name[gu]=બ્લ્યુટુથ +Name[he]=Bluetooth +Name[hi]=ब्लूटूथ +Name[hne]=ब्लूटूथ +Name[hr]=Bluetooth +Name[hu]=Bluetooth +Name[ia]=Bluetooth +Name[id]=Bluetooth +Name[is]=Blátönn +Name[it]=Bluetooth +Name[ja]=Bluetooth +Name[ka]=Bluetooth +Name[kk]=Bluetooth +Name[km]=ប៊្លូសធូស +Name[kn]=ಬ್ಲೂಟೂತ್ +Name[ko]=블루투스 +Name[ku]=Bluetooth +Name[lt]=Bluetooth +Name[lv]=Bluetooth +Name[mai]=ब्लूटूथ +Name[mk]=Bluetooth +Name[ml]=ബ്ലൂടൂത്ത് +Name[mr]=ब्लूटूथ +Name[ms]=Bluetooth +Name[nb]=Bluetooth +Name[nds]=Bluetooth +Name[ne]=ब्लुटुथ +Name[nl]=Bluetooth +Name[nn]=Bluetooth +Name[or]=ବ୍ଲୁଟୁଥ +Name[pa]=ਬਲਿਊਟੁੱਥ +Name[pl]=Bluetooth +Name[pt]=Bluetooth +Name[pt_BR]=Bluetooth +Name[ro]=Bluetooth +Name[ru]=Bluetooth +Name[se]=Bluetooth +Name[si]=Bluetooth +Name[sk]=Bluetooth +Name[sl]=Bluetooth +Name[sr]=Блутут +Name[sr@ijekavian]=Блутут +Name[sr@ijekavianlatin]=Bluetooth +Name[sr@latin]=Bluetooth +Name[sv]=Blåtand +Name[ta]=Bluetooth +Name[te]=బ్లూటూత్ +Name[tg]=Bluetooth +Name[th]=บลูทูธ +Name[tr]=Bluetooth +Name[ug]=كۆكچىش +Name[uk]=Bluetooth +Name[uz]=Bluetooth +Name[uz@cyrillic]=Bluetooth +Name[vi]=Bluetooth +Name[wa]=Bluetooth +Name[x-test]=xxBluetoothxx +Name[zh_CN]=蓝牙 +Name[zh_TW]=藍牙 diff --git a/systemsettings/categories/settings-desktop-appearance.desktop b/systemsettings/categories/settings-desktop-appearance.desktop new file mode 100644 index 00000000..57e0a148 --- /dev/null +++ b/systemsettings/categories/settings-desktop-appearance.desktop @@ -0,0 +1,131 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=desktop-appearance +X-KDE-System-Settings-Parent-Category=workspace-appearance-and-behavior +X-KDE-Weight=80 +Icon=preferences-desktop-theme + +Name=Workspace Appearance +Name[ar]=مظهر مساحة العمل +Name[ast]=Apariencia del espaciu de trabayu +Name[bg]=Изглед на работния плот +Name[bn]=ওয়ার্কস্পেস-এর চেহারা +Name[bs]=Izgled radnog prostora +Name[ca]=Aparença de l'espai de treball +Name[ca@valencia]=Aparença de l'espai de treball +Name[cs]=Vzhled pracovní plochy +Name[da]=Arbejdsområdets udseende +Name[de]=Erscheinungsbild der Arbeitsfläche +Name[el]=Εμφάνιση χώρου εργασίας +Name[en_GB]=Workspace Appearance +Name[es]=Apariencia del espacio de trabajo +Name[et]=Töötsooni välimus +Name[eu]=Laneko eremuaren itxura +Name[fi]=Työtilan ulkoasu +Name[fr]=Apparence de l'espace de travail +Name[ga]=Cuma an Spáis Oibre +Name[gl]=Aparencia do espazo de traballo +Name[he]=מראה סביבת העבודה +Name[hi]=कार्यक्षेत्र रूप +Name[hr]=Izgled radnog prostora +Name[hu]=Megjelenés +Name[ia]=Apparentia del spatio de labor (Workspace) +Name[id]=Tampilan Ruang Kerja +Name[is]=Útlit vinnusvæða +Name[it]=Aspetto dello spazio di lavoro +Name[ja]=ワークスペースの外観 +Name[kk]=Жұмыс орның көрінісі +Name[km]=រូបរាង​តំបន់​ធ្វើការ +Name[kn]=ಕಾರ್ಯಕ್ಷೇತ್ರ ಗೋಚರಿಕೆ +Name[ko]=작업 공간 모양 +Name[lt]=Darbo erdvės išvaizda +Name[lv]=Darba telpas izskats +Name[mr]=कार्यस्थान दर्शनीयता +Name[nb]=Utseende for arbeidsflaten +Name[nds]=Arbeitrebeet-Utsehn +Name[nl]=Uiterlijk van werkruimte +Name[nn]=Utsjånad på arbeids­område +Name[pa]=ਵਰਕਸਪੇਸ ਦਿੱਖ +Name[pl]=Wygląd przestrzeni roboczej +Name[pt]=Aparência da Área de Trabalho +Name[pt_BR]=Aparência do espaço de trabalho +Name[ro]=Aspect spațiu de lucru +Name[ru]=Оформление рабочей среды +Name[si]=වැඩබිම් පෙනුම +Name[sk]=Vzhľad pracovnej plochy +Name[sl]=Videz delovnega prostora +Name[sr]=Изглед радног простора +Name[sr@ijekavian]=Изглед радног простора +Name[sr@ijekavianlatin]=Izgled radnog prostora +Name[sr@latin]=Izgled radnog prostora +Name[sv]=Arbetsytans utseende +Name[tg]=Намуди зоҳирии муҳити корӣ +Name[th]=รูปลักษณ์ของพื้นที่ทำงาน +Name[tr]=Çalışma Alanı Görünümü +Name[ug]=خىزمەت بوشلۇقىنىڭ كۆرۈنۈشى +Name[uk]=Вигляд робочого простору +Name[vi]=Diện mạo không gian làm việc +Name[wa]=Rivnance di l' espåce di boutaedje +Name[x-test]=xxWorkspace Appearancexx +Name[zh_CN]=工作空间外观 +Name[zh_TW]=工作空間外觀與行為 +Comment=Customize the appearance of your desktop +Comment[ar]=خصص مظهر سطح المكتب الخاص بك +Comment[ast]=Personalizar l'apariencia del escritoriu +Comment[bg]=Настройки на изгледа на работния плот +Comment[bs]=Prilagodite izgled svoje površi +Comment[ca]=Personalitza l'aparença de l'escriptori +Comment[ca@valencia]=Personalitza l'aparença de l'escriptori +Comment[cs]=Upravit vzhled vaší plochy +Comment[da]=Tilpas skrivebordets udseende +Comment[de]=Arbeitsflächen-Design anpassen +Comment[el]=Προσαρμογή της εμφάνισης της επιφάνειας εργασίας +Comment[en_GB]=Customise the appearance of your desktop +Comment[es]=Personalizar la apariencia del escritorio +Comment[et]=Töölaua välimuse kohandamine +Comment[eu]=Pertsonalizatu mahaigainaren itxura +Comment[fi]=Mukauta työpöytäsi ulkoasua +Comment[fr]=Personnalise l'apparence de votre bureau +Comment[ga]=Cumraigh cuma do dheisce +Comment[gl]=Personaliza a aparencia do escritorio +Comment[he]=התאמה אישית של מראה שולחן העבודה +Comment[hi]=डेस्कटॉप प्रसंग मनपसंद बनाएँ +Comment[hr]=Prilagodite izgled Vaše radne površine +Comment[hu]=Az asztal megjelenésének testreszabása +Comment[ia]=Personalisa le apparentia de tu scriptorio +Comment[is]=Sérsníða útlit skjáborðsins +Comment[it]=Personalizza l'aspetto del desktop +Comment[ja]=デスクトップの外観をカスタマイズ +Comment[kk]=Үстел көрінісін өзінше баптап алу +Comment[km]=ប្ដូរ​រូបរាង​ផ្ទៃតុ​របស់​អ្នក​តាម​បំណង +Comment[kn]=ನಿಮ್ಮ ಗಣಕತೆರೆ ಪರಿಸರವಿನ್ಯಾಸವನ್ನು ಇಚ್ಛೆಗೆ ತಕ್ಕಂತೆ ಹೊಂದಿಸಿ +Comment[ko]=데스크톱 모습 사용자 정의 +Comment[lt]=Derinti jūsų darbastalio išvaizdą +Comment[lv]=Pielāgot jūsu darbvirsmas izskatu +Comment[mr]=डेस्कटॉप कसा दिसावा त्यात ऐच्छिक बदल करा +Comment[nb]=Tilpass utseendet for skrivebordet +Comment[nds]=Dat Schriefdischutsehn topassen +Comment[nl]=Pas het uiterlijk van uw bureaublad aan +Comment[pa]=ਆਪਣੇ ਡੈਸਕਟਾਪ ਲਈ ਦਿੱਖ ਬਦਲੋ +Comment[pl]=Dostosowywanie wyglądu pulpitu +Comment[pt]=Personalizar a aparência do seu ambiente de trabalho +Comment[pt_BR]=Personaliza a aparência da sua área de trabalho +Comment[ro]=Personalizați aspectul biroului +Comment[ru]=Настройка внешнего вида рабочего стола +Comment[sk]=Prispôsobenie vzhľadu vašej pracovnej plochy +Comment[sl]=Prilagodite videz svojega namizja +Comment[sr]=Прилагодите изглед своје површи +Comment[sr@ijekavian]=Прилагодите изглед своје површи +Comment[sr@ijekavianlatin]=Prilagodite izgled svoje površi +Comment[sr@latin]=Prilagodite izgled svoje površi +Comment[sv]=Anpassa skrivbordets utseende +Comment[th]=ปรับแต่งรูปลักษณ์ของพื้นที่ทำงาน +Comment[tr]=Masaüstünüzün görünümünü özelleştirin +Comment[ug]=ئۈستەلئۈستىڭىزنىڭ قىياپىتىنى ئۆزلەشتۈر +Comment[uk]=Налаштування зовнішнього вигляду вашої стільниці +Comment[vi]=Tuỳ chỉnh diện mạo màn hình làm việc của bạn +Comment[wa]=Mete a vosse môde li rivnance di vosse sicribanne +Comment[x-test]=xxCustomize the appearance of your desktopxx +Comment[zh_CN]=定制桌面外观 +Comment[zh_TW]=自訂桌面外觀 diff --git a/systemsettings/categories/settings-display.desktop b/systemsettings/categories/settings-display.desktop new file mode 100644 index 00000000..52ca39ab --- /dev/null +++ b/systemsettings/categories/settings-display.desktop @@ -0,0 +1,160 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=display +X-KDE-System-Settings-Parent-Category=hardware +Icon=preferences-desktop-display + +Name=Display and Monitor +Name[ar]=العرض والشاشة +Name[ast]=Pantalla y monitor +Name[bg]=Екран и монитор +Name[bn]=ডিসপ্লে ও মনিটর +Name[bs]=Prikaz i monitor +Name[ca]=Pantalla i monitor +Name[ca@valencia]=Pantalla i monitor +Name[cs]=Obrazovka a monitor +Name[da]=Skærm +Name[de]=Anzeige und Monitor +Name[el]=Απεικόνιση και οθόνη +Name[en_GB]=Display and Monitor +Name[es]=Pantalla y monitor +Name[et]=Ekraan ja monitor +Name[eu]=Bistaratzea eta monitorea +Name[fi]=Näyttö +Name[fr]=Affichage et surveillance +Name[ga]=Scáileán agus Monatóir +Name[gl]=Pantalla e monitor +Name[he]=תצוגה וצגים +Name[hr]=Zaslon i monitor +Name[hu]=Kijelző és monitor +Name[ia]=Monstrator e Monitor +Name[id]=Tampilan dan Monitor +Name[is]=Skjáir og birting +Name[it]=Schermo e video +Name[ja]=ディスプレイとモニタ +Name[kk]=Дисплей мен монитор +Name[km]=បង្ហាញ និង​ត្រួតពិនិត្យ +Name[kn]=ಪ್ರದರ್ಶಕ ಹಾಗು ವ್ಯವಸ್ಥಾಪಕ +Name[ko]=디스플레이와 모니터 +Name[lt]=Ekranas ir monitorius +Name[lv]=Ekrāns un monitors +Name[mr]=डिस्प्ले व मॉनिटर +Name[nb]=Skjerm og monitor +Name[nds]=Schirm un Monitor +Name[nl]=Scherm en monitor +Name[nn]=Skjerm og skjerm­bilete +Name[pa]=ਡਿਸਪਲੇਅ ਤੇ ਮਾਨੀਟਰ +Name[pl]=Wyświetlanie i monitor +Name[pt]=Ecrã e Monitor +Name[pt_BR]=Tela e monitor +Name[ro]=Afișaj și monitor +Name[ru]=Экран +Name[si]=ප්‍රදර්ශනය සහ මොනිටරය +Name[sk]=Obrazovka a monitor +Name[sl]=Zasloni in prikazovalniki +Name[sr]=Приказ и монитор +Name[sr@ijekavian]=Приказ и монитор +Name[sr@ijekavianlatin]=Prikaz i monitor +Name[sr@latin]=Prikaz i monitor +Name[sv]=Bildskärm +Name[th]=ระบบแสดงผลและจอภาพ +Name[tr]=Görüntü ve Ekran +Name[ug]=كۆرسىتىش ۋە كۆزەتكۈچ +Name[uk]=Показ зображення і монітор +Name[vi]=Màn hình và hiển thị +Name[wa]=Håynaedje eyet waitroûle +Name[x-test]=xxDisplay and Monitorxx +Name[zh_CN]=显示和监控 +Name[zh_TW]=顯示與螢幕 +Comment=Display Settings +Comment[af]=Skerm Instellings +Comment[ar]=إعدادات العرض +Comment[ast]=Preferencies de la pantalla +Comment[be]=Настаўленні экрану +Comment[be@latin]=Nałady ekrana +Comment[bg]=Настройки на екрана +Comment[bn]=ডিসপ্লে সেটিংস +Comment[bn_IN]=প্রদর্শন সংক্রান্ত বৈশিষ্ট্য +Comment[br]=Kefluniañ an diskwel +Comment[bs]=Postavke ekrana +Comment[ca]=Arranjament de la pantalla +Comment[ca@valencia]=Arranjament de la pantalla +Comment[cs]=Nastavení obrazovky +Comment[csb]=Ùstôw ekranu +Comment[cy]=Gosodiadau Arddangos +Comment[da]=Skærmindstillinger +Comment[de]=Anzeige-Einstellungen +Comment[el]=Ρυθμίσεις οθόνης +Comment[en_GB]=Display Settings +Comment[eo]=Vidigila agordo +Comment[es]=Preferencias de la pantalla +Comment[et]=Monitoride seadistused +Comment[eu]=Pantailaren ezarpenak +Comment[fa]=نمایش تنظیمات +Comment[fi]=Näytön asetukset +Comment[fr]=Configuration de l'affichage +Comment[fy]=Byldskerm ynstellings +Comment[ga]=Socruithe an Scáileáin +Comment[gl]=Configuración da pantalla +Comment[gu]=ડિસ્પ્લે ગોઠવણીઓ +Comment[he]=הגדרות תצוגה +Comment[hi]=प्रकटन विन्यास +Comment[hne]=देखइया सेटिंग +Comment[hr]=Postavke zaslona +Comment[hsb]=Nastajenja za wobrazowku +Comment[hu]=Megjelenési beállítások +Comment[ia]=Monstra preferentias +Comment[id]=Pengaturan Tampilan +Comment[is]=Stillingar skjás +Comment[it]=Impostazioni dello schermo +Comment[ja]=ディスプレイの設定 +Comment[ka]=დისპლეის კონფიგურირება +Comment[kk]=Дисплей баптаулары +Comment[km]=កំណត់​ការ​បង្ហាញ +Comment[kn]=ಪ್ರದರ್ಶಕದ ಸಂಯೋಜನೆಗಳು +Comment[ko]=디스플레이 설정 +Comment[ku]=Mîhengên Dîmenderê +Comment[lt]=Ekrano parametrai +Comment[lv]=Ekrāna parametri +Comment[mai]=जमावट देखाबू +Comment[mk]=Поставувања на приказот +Comment[ml]=പ്രദര്‍ശനത്തിന്റെ സജ്ജീകരണങ്ങള്‍ +Comment[mr]=डिस्प्ले संयोजना +Comment[ms]=Seting Paparan +Comment[nb]=Skjerminnstillinger +Comment[nds]=Dorstellen inrichten +Comment[ne]=सेटिङ प्रदर्शन गर्नुहोस् +Comment[nl]=Beeldscherminstellingen +Comment[nn]=Skjerminnstillingar +Comment[or]=ପ୍ରଦର୍ଶକ ସଂରଚନା +Comment[pa]=ਡਿਸਪਲੇਅ ਸੈਟਿੰਗ +Comment[pl]=Ustawienia ekranu +Comment[pt]=Configuração do ecrã +Comment[pt_BR]=Configurações da tela +Comment[ro]=Configurări afișare +Comment[ru]=Настройка экрана +Comment[se]=Šearbmaheivehusat +Comment[si]=සංදර්ශන සැකසුම් +Comment[sk]=Nastavenie obrazovky +Comment[sl]=Nastavitve zaslona +Comment[sr]=Поставке екрана +Comment[sr@ijekavian]=Поставке екрана +Comment[sr@ijekavianlatin]=Postavke ekrana +Comment[sr@latin]=Postavke ekrana +Comment[sv]=Anpassa bildskärm +Comment[ta]=அமைப்புகளை காட்டு +Comment[te]=ప్రదర్శన అమరికలు +Comment[tg]=Танзимоти экран +Comment[th]=ตั้งค่าต่าง ๆ ของการแสดงผล +Comment[tr]=Ekran Ayarları +Comment[ug]=كۆرۈنمە يۈز تەڭشىكى +Comment[uk]=Налаштування дисплея +Comment[uz]=Displeyning moslamalari +Comment[uz@cyrillic]=Дисплейнинг мосламалари +Comment[vi]=Thiết lập hiển thị +Comment[wa]=Apontiaedjes do Håynaedje +Comment[x-test]=xxDisplay Settingsxx +Comment[zh_CN]=显示设置 +Comment[zh_TW]=顯示設定 + diff --git a/systemsettings/categories/settings-hardware.desktop b/systemsettings/categories/settings-hardware.desktop new file mode 100644 index 00000000..68bbc717 --- /dev/null +++ b/systemsettings/categories/settings-hardware.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=hardware +X-KDE-System-Settings-Parent-Category= +X-KDE-Weight=200 +Icon=preferences-desktop-peripherals + +Name=Hardware +Name[ar]=العتاد +Name[ast]=Hardware +Name[be]=Прылады +Name[be@latin]=Aparatura +Name[bg]=Хардуер +Name[bn]=হার্ডওয়্যার +Name[bn_IN]=হার্ডওয়্যার +Name[br]=Periantel +Name[bs]=Hardver +Name[ca]=Maquinari +Name[ca@valencia]=Maquinari +Name[cs]=Hardware +Name[cy]=Caledwedd +Name[da]=Hardware +Name[de]=Hardware +Name[el]=Υλικό +Name[en_GB]=Hardware +Name[eo]=Aparataro +Name[es]=Hardware +Name[et]=Riistvara +Name[eu]=Hardwarea +Name[fa]=سخت‌افزار +Name[fi]=Laitteisto +Name[fr]=Matériel +Name[fy]=Hardware +Name[ga]=Crua-Earraí +Name[gl]=Hardware +Name[gu]=હાર્ડવેર +Name[he]=חומרה +Name[hi]=हार्डवेयर +Name[hne]=हार्डवेयर +Name[hr]=Hardver +Name[hu]=Hardver +Name[ia]=Hardware +Name[id]=Peranti Keras +Name[is]=Vélbúnaður +Name[it]=Hardware +Name[ja]=ハードウェア +Name[ka]=მოწყობილობები +Name[kk]=Жабдық +Name[km]=ផ្នែក​រឹង +Name[kn]=ಯಂತ್ರಾಂಶ +Name[ko]=하드웨어 +Name[ku]=Reqalav +Name[lt]=Aparatinė įranga +Name[lv]=Aparatūra +Name[mai]=हार्डवेयर +Name[mk]=Хардвер +Name[ml]=ഹാര്‍ഡ്‌വെയര്‍ +Name[mr]=हार्डवेअर +Name[nb]=Maskinvare +Name[nds]=Hardware +Name[ne]=हार्डवेयर +Name[nl]=Hardware +Name[nn]=Maskinvare +Name[or]=ହାର୍ଡୱେର +Name[pa]=ਹਾਰਡਵੇਅਰ +Name[pl]=Sprzęt +Name[pt]='Hardware' +Name[pt_BR]=Hardware +Name[ro]=Echipament +Name[ru]=Оборудование +Name[se]=Mašiidnagálvu +Name[si]=දෘඩාංග +Name[sk]=Hardvér +Name[sl]=Strojna oprema +Name[sr]=Хардвер +Name[sr@ijekavian]=Хардвер +Name[sr@ijekavianlatin]=Hardver +Name[sr@latin]=Hardver +Name[sv]=Hårdvara +Name[ta]=Hardware +Name[te]=హార్డువేర్ +Name[tg]=Сахтафзор +Name[th]=ฮาร์ดแวร์ +Name[tr]=Donanım +Name[ug]=قاتتىق دېتال +Name[uk]=Обладнання +Name[uz]=Asbob-uskunalar +Name[uz@cyrillic]=Асбоб-ускуналар +Name[vi]=Phần cứng +Name[wa]=Éndjolreye +Name[x-test]=xxHardwarexx +Name[zh_CN]=硬件 +Name[zh_TW]=硬體 diff --git a/systemsettings/categories/settings-input-devices.desktop b/systemsettings/categories/settings-input-devices.desktop new file mode 100644 index 00000000..8f52ad93 --- /dev/null +++ b/systemsettings/categories/settings-input-devices.desktop @@ -0,0 +1,73 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=input-devices +X-KDE-System-Settings-Parent-Category=hardware +Icon=preferences-desktop-peripherals + +Name=Input Devices +Name[ar]=أجهزة الإدخال +Name[ast]=Preseos d'entrada +Name[bg]=Входни устройства +Name[bn]=ইনপুট ডিভাইস +Name[bs]=Uređaji +Name[ca]=Dispositius d'entrada +Name[ca@valencia]=Dispositius d'entrada +Name[cs]=Vstupní zařízení +Name[da]=Input-enheder +Name[de]=Eingabegeräte +Name[el]=Συσκευές εισόδου +Name[en_GB]=Input Devices +Name[es]=Dispositivos de entrada +Name[et]=Sisendseadmed +Name[eu]=Sarrerako gailuak +Name[fi]=Näppäimistö ja syöttölaitteet +Name[fr]=Périphériques d'entrée +Name[ga]=Gléasanna Ionchurtha +Name[gl]=Dispositivos de entrada +Name[gu]=ઇનપુટ ઉપકરણો +Name[he]=התקני קלט +Name[hi]=इंपुट औज़ार +Name[hr]=Ulazni uređaji +Name[hu]=Beviteli eszközök +Name[ia]=Dispositivos de Ingresso +Name[id]=Divais Masukan +Name[is]=Inntakstæki +Name[it]=Dispositivi di immissione +Name[ja]=入力デバイス +Name[kk]=Енгізу құрылғылар +Name[km]=ឧបករណ៍​បញ្ចូល +Name[kn]=ಇನ್ ಪುಟ್ ಸಾಧನಗಳು +Name[ko]=입력 장치 +Name[lt]=Įvedimo įrenginiai +Name[lv]=Ievades iekārtas +Name[mr]=इनपुट साधने +Name[nb]=Inndataenheter +Name[nds]=Ingaav-Reedschappen +Name[nl]=Invoerapparaten +Name[nn]=Inn­einingar +Name[pa]=ਇੰਪੁੱਟ ਜੰਤਰ +Name[pl]=Urządzenia wejściowe +Name[pt]=Dispositivos de Entrada +Name[pt_BR]=Dispositivos de entrada +Name[ro]=Dispozitive de intrare +Name[ru]=Устройства ввода +Name[si]=ආදාන මෙවලම් +Name[sk]=Vstupné zariadenia +Name[sl]=Vhodne naprave +Name[sr]=Улазни уређаји +Name[sr@ijekavian]=Улазни уређаји +Name[sr@ijekavianlatin]=Ulazni uređaji +Name[sr@latin]=Ulazni uređaji +Name[sv]=Inmatningsenheter +Name[tg]=Дастгоҳҳои воридотӣ +Name[th]=อุปกรณ์ป้อนข้อมูล +Name[tr]=Girdi Aygıtları +Name[ug]=كىرگۈزۈش ئۈسكۈنىسى +Name[uk]=Пристрої введення +Name[vi]=Thiết bị nhập +Name[wa]=Éndjins èn intrêye +Name[x-test]=xxInput Devicesxx +Name[zh_CN]=输入设备 +Name[zh_TW]=輸入裝置 + diff --git a/systemsettings/categories/settings-locale.desktop b/systemsettings/categories/settings-locale.desktop new file mode 100644 index 00000000..02c326ac --- /dev/null +++ b/systemsettings/categories/settings-locale.desktop @@ -0,0 +1,72 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=locale +X-KDE-System-Settings-Parent-Category=application-appearance-and-behavior +Icon=preferences-desktop-locale + +Name=Locale +Name[ar]=المحليّة +Name[ast]=Llocal +Name[bn]=লোকেল +Name[bs]=Lokalitet +Name[ca]=Localització +Name[ca@valencia]=Localització +Name[cs]=Lokalizace +Name[da]=Lokalitet +Name[de]=Regionales +Name[el]=Τοπικότητα +Name[en_GB]=Locale +Name[es]=Local +Name[et]=Keeleseadistused +Name[eu]=Eskualde-ezarpenak +Name[fi]=Alue ja kieli +Name[fr]=Localisation +Name[ga]=Logchaighdeán +Name[gl]=Configuración rexional +Name[gu]=સ્થાનિય +Name[he]=מיקום +Name[hi]=लोकेल +Name[hr]=Lokalne postavke +Name[hu]=Nyelvi beállítások +Name[ia]=Local +Name[id]=Locale +Name[is]=Staðfærsla +Name[it]=Localizzazione +Name[ja]=ロケール +Name[ka]=ენა +Name[kk]=Жергілікті стандарттар +Name[km]=មូលដ្ឋាន +Name[kn]=ಪ್ರಾದೇಶಿಕ +Name[ko]=로캘 +Name[lt]=Lokalė +Name[lv]=Lokāle +Name[mr]=स्थानिक +Name[nb]=Lokale +Name[nds]=Spraakinstellen +Name[nl]=Taalregio +Name[nn]=Land og språk +Name[pa]=ਲੋਕੇਲ +Name[pl]=Ustawienia regionalne +Name[pt]=Localização +Name[pt_BR]=Localização +Name[ro]=Localizare +Name[ru]=Локаль +Name[si]=ස්ථානය +Name[sk]=Lokalizácia +Name[sl]=Krajevne nastavitve +Name[sr]=Локалитет +Name[sr@ijekavian]=Локалитет +Name[sr@ijekavianlatin]=Lokalitet +Name[sr@latin]=Lokalitet +Name[sv]=Plats +Name[tg]=Маҳаллӣ +Name[th]=ภาษาระบบ +Name[tr]=Yerel +Name[ug]=رايون +Name[uk]=Локаль +Name[vi]=Vùng +Name[wa]=Lingaedje/payis +Name[x-test]=xxLocalexx +Name[zh_CN]=语系 +Name[zh_TW]=地域 diff --git a/systemsettings/categories/settings-lost-and-found.desktop b/systemsettings/categories/settings-lost-and-found.desktop new file mode 100644 index 00000000..eb379e2d --- /dev/null +++ b/systemsettings/categories/settings-lost-and-found.desktop @@ -0,0 +1,71 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=lost-and-found +X-KDE-System-Settings-Parent-Category= +X-KDE-Weight=250 +Icon=applications-system + +Name=Lost and Found +Name[ar]=المفقودات +Name[ast]=Oxetos perdíos +Name[bn]=হারানো প্রাপ্তি +Name[bs]=Izgubljeno-nađeno +Name[ca]=Perdut i trobat +Name[ca@valencia]=Perdut i trobat +Name[cs]=Ztráty a nálezy +Name[da]=Hittegods +Name[de]=Nicht zuzuordnen +Name[el]=Χάθηκαν και βρέθηκαν +Name[en_GB]=Lost and Found +Name[es]=Objetos perdidos +Name[et]=Kaotatud ja leitud +Name[eu]=Galdutako gauzak +Name[fi]=Sekalaiset +Name[fr]=Objets perdus et retrouvés +Name[ga]=Earraí Caillte +Name[gl]=Obxectos perdidos +Name[gu]=ખોવાયેલ અને મળેલ +Name[he]=אבידות ומציאות +Name[hi]=खोया व पाया +Name[hr]=Izgubljeno i nađeno +Name[hu]=Elveszett és megtalált +Name[ia]=Trovate e perdite +Name[id]=Hilang dan Ditemukan +Name[is]=Tapað og fundið +Name[it]=Oggetti smarriti +Name[ja]=Lost and Found +Name[kk]=Жоғалған мен табылғандар +Name[km]=បាត់ ហើយ​រកឃើញ +Name[kn]=ಲುಪ್ತ ಮತ್ತು ಲಬ್ಧ +Name[ko]=기타 프로그램 +Name[lt]=Pamesta ir rasta +Name[lv]=Pazudis un atrasts +Name[mr]=हरवले व सापडले +Name[nb]=Tapt og funnet +Name[nds]=Passt narms sünst +Name[nl]=Verloren en gevonden +Name[nn]=Tapt og funne +Name[pa]=ਗੁਆਚੇ ਅਤੇ ਲੱਭੇ +Name[pl]=Zgubione i znalezione +Name[pt]=Perdidos e Achados +Name[pt_BR]=Achados e perdidos +Name[ro]=Pierdute și regăsite +Name[ru]=Прочее +Name[si]=නැතිවී සොයා ගැනුනි +Name[sk]=Straty a nálezy +Name[sl]=Izgubljeno in najdeno +Name[sr]=Изгубљено-нађено +Name[sr@ijekavian]=Изгубљено-нађено +Name[sr@ijekavianlatin]=Izgubljeno-nađeno +Name[sr@latin]=Izgubljeno-nađeno +Name[sv]=Hittegods +Name[th]=หาไม่เจอดูที่นี่ +Name[tr]=Kayıp ve Bulunanlar +Name[ug]=يوقالغان ۋە تېپىلغان +Name[uk]=Втрачено і знайдено +Name[vi]=Mất và tìm +Name[wa]=Pierdous eyet rtrovés +Name[x-test]=xxLost and Foundxx +Name[zh_CN]=未知类别 +Name[zh_TW]=Lost & Found diff --git a/systemsettings/categories/settings-network-and-connectivity.desktop b/systemsettings/categories/settings-network-and-connectivity.desktop new file mode 100644 index 00000000..639674bc --- /dev/null +++ b/systemsettings/categories/settings-network-and-connectivity.desktop @@ -0,0 +1,72 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=network-and-connectivity +X-KDE-System-Settings-Parent-Category= +Icon=preferences-system-network-connection + +Name=Network and Connectivity +Name[ar]=الشبكة والاتصال +Name[ast]=Rede y conectividá +Name[bg]=Мрежова свързаност +Name[bn]=নেটওয়ার্ক এবং সংযোগ +Name[bs]=Mreža i povezivost +Name[ca]=Xarxa i connectivitat +Name[ca@valencia]=Xarxa i connectivitat +Name[cs]=Síť a připojení +Name[da]=Netværk og forbindelse +Name[de]=Netzwerk und Verbindungen +Name[el]=Δίκτυο και συνδεσιμότητα +Name[en_GB]=Network and Connectivity +Name[es]=Red y conectividad +Name[et]=Võrk ja ühendused +Name[eu]=Sarea eta konektagarritasuna +Name[fi]=Verkko ja yhteydet +Name[fr]=Réseau et connectivité +Name[ga]=Líonra agus Comhcheangailteacht +Name[gl]=Rede e conectividade +Name[gu]=નેટવર્ક અને જોડાણ +Name[he]=רשת וחיבוריות +Name[hi]=नेटवर्क व जुडाव +Name[hr]=Mreža i spojivost +Name[hu]=Hálózat és kapcsolat +Name[ia]=Rete e connectivitate +Name[id]=Jaringan dan Konektivitas +Name[is]=Net og tengingar +Name[it]=Rete e connettività +Name[ja]=ネットワークと接続 +Name[kk]=Желі мен Байланыс +Name[km]=បណ្តាញ និង​ការតភ្ជាប់ +Name[kn]=ಜಾಲಬಂಧ ಮತ್ತು ಸಂಪರ್ಕ +Name[ko]=네트워크와 연결 +Name[lt]=Tinklas ir prisijungimai +Name[lv]=Tīkls un savienojumi +Name[mr]=संजाळ व जुळवणी +Name[nb]=Nettverk og tilkoblinger +Name[nds]=Nettwark un Verbinnen +Name[nl]=Netwerk en connectiviteit +Name[nn]=Nettverk og samband +Name[pa]=ਨੈੱਟਵਰਕ ਅਤੇ ਕੁਨੈਕਟਵਿਟੀ +Name[pl]=Sieć i łączność +Name[pt]=Rede e Conectividade +Name[pt_BR]=Rede e conectividade +Name[ro]=Rețea și conectivitate +Name[ru]=Сеть и связь +Name[si]=ජාල සහ සම්බන්ධතාවය +Name[sk]=Sieť a pripojenie +Name[sl]=Omrežje in povezljivost +Name[sr]=Мрежа и повезивост +Name[sr@ijekavian]=Мрежа и повезивост +Name[sr@ijekavianlatin]=Mreža i povezivost +Name[sr@latin]=Mreža i povezivost +Name[sv]=Nätverk och anslutningar +Name[tg]=Шабака ва пайвастшавӣ +Name[th]=เครือข่ายและการเชื่อมต่อ +Name[tr]=Ağ ve Bağlanabilirlik +Name[ug]=تور ۋە باغلىنىش +Name[uk]=Мережа і з'єднання +Name[vi]=Kết nối và mạng +Name[wa]=Rantoele eyet raloyaedje +Name[x-test]=xxNetwork and Connectivityxx +Name[zh_CN]=网络和连接 +Name[zh_TW]=網路與連線 diff --git a/systemsettings/categories/settings-network-settings.desktop b/systemsettings/categories/settings-network-settings.desktop new file mode 100644 index 00000000..a2c74d18 --- /dev/null +++ b/systemsettings/categories/settings-network-settings.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=network-settings +X-KDE-System-Settings-Parent-Category=network-and-connectivity +Icon=preferences-system-network + +Name=Network Settings +Name[ar]=إعدادات الشبكة +Name[ast]=Preferencies de rede +Name[be]=Настаўленні сеткі +Name[be@latin]=Nałady sietki +Name[bg]=Мрежови настройки +Name[bn]=নেটওয়ার্ক সেটিংস +Name[bn_IN]=নেটওয়ার্ক সংক্রান্ত বৈশিষ্ট্য +Name[br]=Kefluniadur ar Rouedad +Name[bs]=Mrežne postavke +Name[ca]=Paràmetres de xarxa +Name[ca@valencia]=Paràmetres de xarxa +Name[cs]=Nastavení sítě +Name[csb]=Sécowi nastôw +Name[da]=Netværksindstillinger +Name[de]=Netzwerkeinstellungen +Name[el]=Ρυθμίσεις δικτύου +Name[en_GB]=Network Settings +Name[eo]=Reta agordo +Name[es]=Preferencias de red +Name[et]=Võrguseadistused +Name[eu]=Sareko ezarpenak +Name[fa]=تنظیمات شبکه +Name[fi]=Verkkoasetukset +Name[fr]=Configuration de réseau +Name[fy]=Netwurk ynstellings +Name[ga]=Socruithe Líonra +Name[gl]=Configuración da rede +Name[gu]=નેટવર્ક ગોઠવણીઓ +Name[he]=הגדרות רשת +Name[hi]=नेटवर्क विन्यास +Name[hne]=नेटवर्क सेटिंग +Name[hr]=Postavke mreže +Name[hu]=Hálózati beállítások +Name[ia]=Preferentias de rete +Name[id]=Pengaturan Jaringan +Name[is]=Netstillingar +Name[it]=Impostazioni di rete +Name[ja]=ネットワークの設定 +Name[ka]=ქსელის პარამეტრები +Name[kk]=Желі параметрлері +Name[km]=ការ​កំណត់​បណ្តាញ​ +Name[kn]=ಜಾಲ ಸಂಯೋಜನೆಗಳು +Name[ko]=네트워크 설정 +Name[ku]=Mîhengên Torê +Name[lt]=Tinklo nustatymai +Name[lv]=Tīkla iestatījumi +Name[mai]=नेटवर्क विन्यास +Name[mk]=Поставувања за мрежа +Name[ml]=ശൃംഖലയുടെ സജ്ജീകരണങ്ങള്‍ +Name[mr]=संजाळ संयोजना +Name[ms]=Tetapan Rangkaian +Name[nb]=Nettverksinnstillinger +Name[nds]=Nettwarkinstellen +Name[ne]=सञ्जाल सेटिङ +Name[nl]=Netwerkinstellingen +Name[nn]=Nettverk +Name[oc]=Paramètres ret +Name[or]=ନେଟୱର୍କ ବିନ୍ୟାସ +Name[pa]=ਨੈੱਟਵਰਕ ਸੈਟਿੰਗ +Name[pl]=Ustawienia sieci +Name[pt]=Configuração da Rede +Name[pt_BR]=Configurações de rede +Name[ro]=Configurări rețea +Name[ru]=Настройка сети +Name[se]=Fierpmádatheivehusat +Name[si]=ජාල සැකසුම් +Name[sk]=Nastavenie siete +Name[sl]=Nastavitve omrežja +Name[sr]=Мрежне поставке +Name[sr@ijekavian]=Мрежне поставке +Name[sr@ijekavianlatin]=Mrežne postavke +Name[sr@latin]=Mrežne postavke +Name[sv]=Nätverksinställningar +Name[ta]=Network Settings +Name[te]=నెట్వర్‍క్ అమర్పులు +Name[tg]=Танзимотҳои Интернетӣ +Name[th]=ตั้งค่าระบบเครือข่าย +Name[tr]=Ağ Ayarları +Name[ug]=تور تەڭشەكلىرى +Name[uk]=Мережні параметри +Name[uz]=Tarmoqning moslamalari +Name[uz@cyrillic]=Тармоқнинг мосламалари +Name[vi]=Thiết lập mạng +Name[wa]=Apontiaedjes rantoele +Name[x-test]=xxNetwork Settingsxx +Name[zh_CN]=网络设置 +Name[zh_TW]=網路設定 diff --git a/systemsettings/categories/settings-permissions.desktop b/systemsettings/categories/settings-permissions.desktop new file mode 100644 index 00000000..6a5b8b49 --- /dev/null +++ b/systemsettings/categories/settings-permissions.desktop @@ -0,0 +1,73 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=permissions +X-KDE-System-Settings-Parent-Category=system-administration +Icon=preferences-other + +Name=Permissions +Name[ar]=الصلاحيات +Name[ast]=Permisos +Name[bg]=Права +Name[bn]=অনুমতি +Name[bs]=Dozvole +Name[ca]=Permisos +Name[ca@valencia]=Permisos +Name[cs]=Oprávnění +Name[da]=Rettigheder +Name[de]=Berechtigungen +Name[el]=Άδειες +Name[en_GB]=Permissions +Name[es]=Permisos +Name[et]=Õigused +Name[eu]=Baimenak +Name[fi]=Oikeudet +Name[fr]=Permissions +Name[ga]=Ceadanna +Name[gl]=Permisos +Name[gu]=પરવાનગીઓ +Name[he]=הרשאות +Name[hi]=अनुमतियाँ +Name[hr]=Dopuštenja +Name[hu]=Jogosultságok +Name[ia]=Permissiones +Name[id]=Hak Akses +Name[is]=Heimildir +Name[it]=Permessi +Name[ja]=許可 +Name[kk]=Рұқсаттар +Name[km]=សិទ្ធិ +Name[kn]=ಅನುಮತಿಗಳು +Name[ko]=권한 +Name[lt]=Leidimai +Name[lv]=Atļaujas +Name[mai]=अऩुमति +Name[mr]=परवानगी +Name[nb]=Rettigheter +Name[nds]=Verlöven +Name[nl]=Toegangsrechten +Name[nn]=Løyve +Name[pa]=ਅਧਿਕਾਰ +Name[pl]=Uprawnienia +Name[pt]=Permissões +Name[pt_BR]=Permissões +Name[ro]=Permisiuni +Name[ru]=Права доступа +Name[si]=අවසර +Name[sk]=Práva +Name[sl]=Dovoljenja +Name[sr]=Дозволе +Name[sr@ijekavian]=Дозволе +Name[sr@ijekavianlatin]=Dozvole +Name[sr@latin]=Dozvole +Name[sv]=Rättigheter +Name[tg]=Дастрасӣ +Name[th]=สิทธิ์ที่อนุญาต +Name[tr]=Yetkiler +Name[ug]=ھوقۇقلار +Name[uk]=Права доступу +Name[vi]=Quyền hạn +Name[wa]=Droets +Name[x-test]=xxPermissionsxx +Name[zh_CN]=权限 +Name[zh_TW]=權限 diff --git a/systemsettings/categories/settings-personal-information.desktop b/systemsettings/categories/settings-personal-information.desktop new file mode 100644 index 00000000..0efe607f --- /dev/null +++ b/systemsettings/categories/settings-personal-information.desktop @@ -0,0 +1,74 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=personal-information +X-KDE-System-Settings-Parent-Category=application-appearance-and-behavior +Icon=preferences-desktop-user + +Name=Personal Information +Name[ar]=معلومات شخصية +Name[ast]=Información personal +Name[bg]=Лични данни +Name[bn]=ব্যক্তিগত তথ্য +Name[bs]=Lični podaci +Name[ca]=Informació personal +Name[ca@valencia]=Informació personal +Name[cs]=Osobní informace +Name[da]=Personlig information +Name[de]=Persönliche Informationen +Name[el]=Προσωπικές πληροφορίες +Name[en_GB]=Personal Information +Name[es]=Información personal +Name[et]=Isiklik teave +Name[eu]=Datu pertsonalak +Name[fa]=اطلاعات شخصی +Name[fi]=Henkilökohtaiset tiedot +Name[fr]=Informations personnelles +Name[ga]=Faisnéis Phearsanta +Name[gl]=Información persoal +Name[gu]=વ્યક્તિગત જાણકારી +Name[he]=פרטים אישיים +Name[hi]=व्यक्तिगत जानकारी +Name[hr]=Osobne informacije +Name[hu]=Személyi adatok +Name[ia]=Information personal +Name[id]=Informasi Personal +Name[is]=Persónulegar upplýsingar +Name[it]=Informazioni personali +Name[ja]=個人情報 +Name[kk]=Дербес мәлімет +Name[km]=ព័ត៌មាន​​ផ្ទាល់ខ្លួន +Name[kn]=ವೈಯಕ್ತಿಕ ಮಾಹಿತಿ +Name[ko]=개인 정보 +Name[lt]=Asmeninė informacija +Name[lv]=Personīgā informācija +Name[mr]=वैयक्तिक माहिती +Name[nb]=Personlige opplysninger +Name[nds]=Persöönliche Informatschonen +Name[nl]=Persoonlijke informatie +Name[nn]=Personleg informasjon +Name[pa]=ਨਿੱਜੀ ਜਾਣਕਾਰੀ +Name[pl]=Informacje osobiste +Name[pt]=Informação Pessoal +Name[pt_BR]=Informações pessoais +Name[ro]=Informații personale +Name[ru]=Личные данные +Name[si]=පුද්ගලික විස්තර +Name[sk]=Osobné informácie +Name[sl]=Osebni podatki +Name[sr]=Лични подаци +Name[sr@ijekavian]=Лични подаци +Name[sr@ijekavianlatin]=Lični podaci +Name[sr@latin]=Lični podaci +Name[sv]=Personlig information +Name[tg]=Иттилооти шахсӣ +Name[th]=ข้อมูลส่วนบุคคล +Name[tr]=Kişisel Bilgi +Name[ug]=شەخسىي ئۇچۇرلار +Name[uk]=Особисті відомості +Name[vi]=Thông tin cá nhân +Name[wa]=Informåcion da sinne +Name[x-test]=xxPersonal Informationxx +Name[zh_CN]=个人信息 +Name[zh_TW]=個人資訊 + diff --git a/systemsettings/categories/settings-power-management.desktop b/systemsettings/categories/settings-power-management.desktop new file mode 100644 index 00000000..8b3bdc05 --- /dev/null +++ b/systemsettings/categories/settings-power-management.desktop @@ -0,0 +1,83 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=power-management +X-KDE-System-Settings-Parent-Category=hardware +Icon=preferences-system-power-management + +Name=Power Management +Name[ar]=إدارة الطاقة +Name[ast]=Xestión d'enerxía +Name[be@latin]=Kiravańnie enerhijaj +Name[bg]=Управление на захранването +Name[bn]=পাওয়ার ব্যবস্থাপনা +Name[bn_IN]=বিদ্যুৎ সরবরাহ পরিচালনা +Name[bs]=Upravljanje napajanjem +Name[ca]=Gestió d'energia +Name[ca@valencia]=Gestió d'energia +Name[cs]=Správa napájení +Name[csb]=Sprôwianié mòcą +Name[da]=Strømstyring +Name[de]=Energieverwaltung +Name[el]=Διαχείριση ενέργειας +Name[en_GB]=Power Management +Name[eo]=Energiadministrado +Name[es]=Gestión de energía +Name[et]=Toitehaldus +Name[eu]=Energia-kudeaketa +Name[fi]=Virranhallinta +Name[fr]=Gestion de l'énergie +Name[fy]=Enerzjybehear +Name[ga]=Bainisteoireacht Cumhachta +Name[gl]=Xestión da enerxía +Name[gu]=પાવર વ્યવસ્થાપક +Name[he]=ניהול צריכת חשמל +Name[hi]=बिज़ली प्रबंधन +Name[hne]=पावर प्रबंधन +Name[hr]=Upravljanje potrošnjom energije +Name[hu]=Energiakezelő +Name[ia]=Gestion de energia +Name[id]=Manajemen Daya +Name[is]=Orkustjórnun +Name[it]=Gestione energetica +Name[ja]=電源管理 +Name[kk]=Қуаттандыруды басқару +Name[km]=ការ​គ្រប់គ្រង​ថាមពល +Name[kn]=ವಿದ್ಯುಚ್ಛಕ್ತಿ ವ್ಯವಸ್ಥಾಪನೆ +Name[ko]=전원 관리 +Name[ku]=Gerînendeyê hêzê +Name[lt]=Energijos valdymas +Name[lv]=Energokontrole +Name[mai]=पावर मैनेजमेंट +Name[mk]=Менаџмент на енергија +Name[ml]=വൈദ്യുതി നടത്തിപ്പു് +Name[mr]=वीज व्यवस्थापन +Name[nb]=Strømstyring +Name[nds]=Stroomkuntrull +Name[nl]=Energiebeheer +Name[nn]=Straumstyring +Name[or]=ଶକ୍ତି ପରିଚାଳନା +Name[pa]=ਪਾਵਰ ਮੈਨਿਜਮੈਂਟ +Name[pl]=Zarządzanie energią +Name[pt]=Gestão de Energia +Name[pt_BR]=Gerenciamento de energia +Name[ro]=Gestiune energie +Name[ru]=Управление питанием +Name[si]=බල පරිපාලනය +Name[sk]=Správa napájania +Name[sl]=Upravljanje z energijo +Name[sr]=Управљање напајањем +Name[sr@ijekavian]=Управљање напајањем +Name[sr@ijekavianlatin]=Upravljanje napajanjem +Name[sr@latin]=Upravljanje napajanjem +Name[sv]=Strömsparhantering +Name[ta]=Power Management +Name[tg]=Идоракунии барқ +Name[th]=การจัดการพลังงาน +Name[tr]=Güç Yönetimi +Name[ug]=توك مەنبەسىنى باشقۇرۇش +Name[uk]=Керування живленням +Name[wa]=Manaedjmint di l' enerdjeye +Name[x-test]=xxPower Managementxx +Name[zh_CN]=电源管理 +Name[zh_TW]=電源管理 diff --git a/systemsettings/categories/settings-removable-devices.desktop b/systemsettings/categories/settings-removable-devices.desktop new file mode 100644 index 00000000..89cb6046 --- /dev/null +++ b/systemsettings/categories/settings-removable-devices.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=removable-devices +X-KDE-System-Settings-Parent-Category=hardware +Icon=drive-removable-media + +Name=Removable Devices +Name[ar]=أجهزة قابلة للإزالة +Name[ast]=Preseos estrayibles +Name[bg]=Преносими устройства +Name[bn]=অপসারণযোগ্য ডিভাইস +Name[bs]=Uklonjivi uređaji +Name[ca]=Dispositius extraïbles +Name[ca@valencia]=Dispositius extraïbles +Name[cs]=Odpojitelná zařízení +Name[csb]=Przenosné ùrządzenia +Name[da]=Flytbare enheder +Name[de]=Wechselmedien +Name[el]=Αφαιρούμενες συσκευές +Name[en_GB]=Removable Devices +Name[eo]=Demeteblaj Aparatoj +Name[es]=Dispositivos extraíbles +Name[et]=Eemaldatavad seadmed +Name[eu]=Gailu aldagarriak +Name[fa]=دستگاههای جداشدنی +Name[fi]=Irrotettavat laitteet +Name[fr]=Périphériques amovibles +Name[fy]=Utnimbere apparaten +Name[ga]=Gléasanna Inbhainte +Name[gl]=Dispositivos extraíbeis +Name[he]=התקנים נשלפים +Name[hi]=हटाने लायक औज़ार +Name[hr]=Uklonjivi uređaji +Name[hu]=Cserélhető eszközök +Name[ia]=Dispositivos removibile +Name[id]=Divais Dapat Dilepaskan +Name[is]=Útskiptanleg tæki +Name[it]=Dispositivi rimovibili +Name[ja]=リムーバブルデバイス +Name[kk]=Ауыстырмалы құрылғылар +Name[km]=ឧបករណ៍ចល័ត +Name[kn]=ತೆಗೆದೆಹಾಕಬಹುದಾದ ಸಾಧನಗಳು +Name[ko]=이동식 장치 +Name[lt]=Keičiamieji įrenginiai +Name[lv]=Noņemamās iekārtas +Name[mk]=Подвижни уреди +Name[ml]=നീക്കം ചെയ്യാവുന്ന ഉപകരണങ്ങള്‍ +Name[mr]=काढता येणारी साधने +Name[nb]=Flyttbar +Name[nds]=Tuuschbor Reedschappen +Name[nl]=Verwijderbare apparaten +Name[nn]=Flyttbare einingar +Name[pa]=ਹਟਾਉਣਯੋਗ ਜੰਤਰ +Name[pl]=Urządzenia wymienne +Name[pt]=Dispositivos Removíveis +Name[pt_BR]=Dispositivos removíveis +Name[ro]=Dispozitive amovibile +Name[ru]=Внешние носители +Name[si]=ඉවත් කල හැකි මෙවලම් +Name[sk]=Vymeniteľné zariadenia +Name[sl]=Odstranljive naprave +Name[sr]=Уклоњиви уређаји +Name[sr@ijekavian]=Уклоњиви уређаји +Name[sr@ijekavianlatin]=Uklonjivi uređaji +Name[sr@latin]=Uklonjivi uređaji +Name[sv]=Flyttbara enheter +Name[tg]=Дастгоҳи ҷудошаванда +Name[th]=อุปกรณ์ที่สามารถถอด/เสียบได้ +Name[tr]=Çıkarılabilir Aygıtlar +Name[ug]=Removable ئۈسكۈنىلەر +Name[uk]=Портативні пристрої +Name[vi]=Thiết bị gắn ngoài +Name[wa]=Oiståves éndjins +Name[x-test]=xxRemovable Devicesxx +Name[zh_CN]=移动设备 +Name[zh_TW]=可移除裝置 diff --git a/systemsettings/categories/settings-sharing.desktop b/systemsettings/categories/settings-sharing.desktop new file mode 100644 index 00000000..eb9bc5bb --- /dev/null +++ b/systemsettings/categories/settings-sharing.desktop @@ -0,0 +1,92 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=sharing +X-KDE-System-Settings-Parent-Category=network-and-connectivity +Icon=preferences-system-network-sharing + +Name=Sharing +Name[ar]=مشاركة +Name[ast]=Compartición +Name[be]=Абмен +Name[be@latin]=Supolny dostup +Name[bg]=Споделяне +Name[bn_IN]=যৌথ ব্যবহার +Name[br]=Rannañ +Name[bs]=Dijeljenje +Name[ca]=Compartició +Name[ca@valencia]=Compartició +Name[cs]=Sdílení +Name[csb]=Ùwòlnienié +Name[da]=Deling +Name[de]=Freigabe +Name[el]=Διαμοιρασμός +Name[en_GB]=Sharing +Name[eo]=Komunigo +Name[es]=Compartición +Name[et]=Jagamine +Name[eu]=Partekatzea +Name[fa]=اشتراک +Name[fi]=Verkkojaot +Name[fr]=Partage +Name[fy]=Diele +Name[ga]=Comhroinnt +Name[gl]=Compartición +Name[gu]=ભાગીદારી +Name[he]=שיתוף +Name[hi]=साझेदारी +Name[hne]=साझेदारी +Name[hr]=Dijeljenje +Name[hu]=Megosztás +Name[ia]=Compartir +Name[id]=Berbagi +Name[is]=Deiling +Name[it]=Condivisione +Name[ja]=共有 +Name[kk]=Ортақ ресурстар +Name[km]=ការ​ចែក​រំលែក +Name[kn]=ಹಂಚಿಕೊಳ್ಳುವಿಕೆ +Name[ko]=공유 +Name[ku]=Parvekirin +Name[lt]=Dalinimasis +Name[lv]=Koplietošana +Name[mai]=साझेदारी +Name[mk]=Споделување +Name[ml]=പങ്കിടല്‍ +Name[mr]=शेअरींग +Name[ms]=Perkongsian +Name[nb]=Deling +Name[nds]=Delen +Name[ne]=साझेदारी +Name[nl]=Delen +Name[nn]=Deling +Name[or]=ସହଭାଗ +Name[pa]=ਸਾਂਝ +Name[pl]=Współdzielenie +Name[pt]=Partilha +Name[pt_BR]=Compartilhamento +Name[ro]=Partajare +Name[ru]=Общий доступ +Name[se]=Juogádeapmi +Name[si]=හවුල් +Name[sk]=Zdieľanie +Name[sl]=Souporaba +Name[sr]=Дељење +Name[sr@ijekavian]=Дијељење +Name[sr@ijekavianlatin]=Dijeljenje +Name[sr@latin]=Deljenje +Name[sv]=Delning +Name[ta]=Sharing +Name[te]=భాగస్వామ్యం +Name[tg]=Дастрасӣ +Name[th]=การใช้งานร่วมกัน +Name[tr]=Paylaşım +Name[ug]=ھەمبەھىر +Name[uk]=Спільне користування +Name[uz]=Boʻlishish +Name[uz@cyrillic]=Бўлишиш +Name[vi]=Chia sẻ +Name[wa]=Pårtaedje +Name[x-test]=xxSharingxx +Name[zh_CN]=共享 +Name[zh_TW]=分享 diff --git a/systemsettings/categories/settings-shortcuts-and-gestures.desktop b/systemsettings/categories/settings-shortcuts-and-gestures.desktop new file mode 100644 index 00000000..d14bab15 --- /dev/null +++ b/systemsettings/categories/settings-shortcuts-and-gestures.desktop @@ -0,0 +1,71 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=shortcuts-and-gestures +X-KDE-System-Settings-Parent-Category=application-appearance-and-behavior +Icon=preferences-desktop-keyboard + +Name=Shortcuts and Gestures +Name[ar]=الاختصارات والإيماءات +Name[ast]=Accesos rápidos y xestos +Name[bg]=Бързи клавиши и жестове +Name[bn]=শর্টকাট এবং ভঙ্গি +Name[bs]=Prečice i gestovi +Name[ca]=Dreceres i gestos +Name[ca@valencia]=Dreceres i gestos +Name[cs]=Zkratky a gesta +Name[da]=Genveje og gestusser +Name[de]=Kurzbefehle und Gestensteuerung +Name[el]=Συντομεύσεις και χειρονομίες +Name[en_GB]=Shortcuts and Gestures +Name[es]=Accesos rápidos y gestos +Name[et]=Kiirklahvid ja žestid +Name[eu]=Lasterbideak eta keinuak +Name[fi]=Pikanäppäimet ja hiirieleet +Name[fr]=Raccourcis et gestes +Name[ga]=Aicearraí agus Gothaí +Name[gl]=Atallos e acenos do rato +Name[he]=קיצורים ותנועות +Name[hi]=शॉर्टकट व संकेत +Name[hr]=Prečaci i kretnje mišem +Name[hu]=Gyorsbillentyűk és mozdulatok +Name[ia]=Vias breve e gestures +Name[id]=Jalan Pintas dan Gerakan +Name[is]=Flýtilyklar og bendingar +Name[it]=Scorciatoie e gesti +Name[ja]=ショートカットとジェスチャー +Name[kk]=Тіркесімдер мен ым қимылдары +Name[km]=ផ្លូវកាត់ និងកាយវិការ +Name[kn]=ಶೀಘ್ರ ಮಾರ್ಗಗಳು (ಶಾರ್ಟ್ ಕಟ್) ಹಾಗು ಸೂಚ್ಯವರ್ತನೆಗಳು (ಗೆಸ್ಚರ್ಸ್) +Name[ko]=단축키와 제스처 +Name[lt]=Spartieji klavišai ir gestai +Name[lv]=Īsceļi un žesti +Name[mr]=शॉर्टकट व माऊस इशारे +Name[nb]=Snarveier og musebevegelser +Name[nds]=Tastkombinatschonen un Muustekens +Name[nl]=Sneltoetsen en gebaren +Name[nn]=Snarvegar og muserørsler +Name[pa]=ਸ਼ਾਰਟਕੱਟ ਤੇ ਜੈਸੱਚਰ +Name[pl]=Skróty i gesty +Name[pt]=Atalhos e Gestos +Name[pt_BR]=Atalhos e gestos +Name[ro]=Scurtături și gesturi +Name[ru]=Комбинации клавиш и росчерки +Name[si]=කෙටි මං සහ ඉඟි +Name[sk]=Skratky a gestá +Name[sl]=Bližnjice in kretnje +Name[sr]=Пречице и гестови +Name[sr@ijekavian]=Пречице и гестови +Name[sr@ijekavianlatin]=Prečice i gestovi +Name[sr@latin]=Prečice i gestovi +Name[sv]=Genvägar och gester +Name[th]=ปุ่มพิมพ์ลัดและการขยับเมาส์แบบต่าง ๆ +Name[tr]=Kısayollar ve Hareketler +Name[ug]=تېزلەتمىلەر ۋە قول ئىشارەتلىرى +Name[uk]=Скорочення і жести +Name[vi]=Phím tắt và cử chỉ +Name[wa]=Rascourtis eyet djesses +Name[x-test]=xxShortcuts and Gesturesxx +Name[zh_CN]=快捷方式和手势 +Name[zh_TW]=捷徑與手勢 + diff --git a/systemsettings/categories/settings-startup-and-shutdown.desktop b/systemsettings/categories/settings-startup-and-shutdown.desktop new file mode 100644 index 00000000..4ad9664a --- /dev/null +++ b/systemsettings/categories/settings-startup-and-shutdown.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=startup-and-shutdown +X-KDE-System-Settings-Parent-Category=system-administration +Icon=preferences-other + +Name=Startup and Shutdown +Name[ar]=بدء التشغيل والإطفاء +Name[ast]=Arranque y apagáu +Name[bg]=Зареждане и изключване +Name[bn]=স্টার্ট-আপ এবং শাটডাউন +Name[bs]=Podizanje i gašenje +Name[ca]=Engegada i aturada +Name[ca@valencia]=Engegada i parada +Name[cs]=Spuštění a ukončení +Name[da]=Opstart og nedlukning +Name[de]=Starten und Beenden +Name[el]=Εκκίνηση και τερματισμός +Name[en_GB]=Startup and Shutdown +Name[es]=Arranque y apagado +Name[et]=Käivitamine ja seiskamine +Name[eu]=Abioa eta itzaltzea +Name[fi]=Käynnistys ja sammutus +Name[fr]=Démarrage et arrêt +Name[ga]=Tosú agus Múchadh +Name[gl]=Inicio e saída +Name[he]=הפעלה וכיבוי +Name[hi]=स्टारटप व शटडाउन +Name[hr]=Pokretanje i isključivanje +Name[hu]=Indítás és leállítás +Name[ia]=Initia e claude (Shutdown) +Name[id]=Jalankan dan Matikan +Name[is]=Ræsing og stöðvun +Name[it]=Avvio e spegnimento +Name[ja]=起動と終了 +Name[kk]=Бастау мен сөндіру +Name[km]=ចាប់ផ្ដើម និង​បិទ +Name[kn]=ಪ್ರಾರಂಭಿಸು ಹಾಗು ಸ್ಥಗಿತಗೊಳಿಸು +Name[ko]=시작 및 종료 +Name[lt]=Įjungimas ir išjungimas +Name[lv]=Ieslēgšana un izslēgšana +Name[mr]=सुरुवात व समाप्ती +Name[nb]=Oppstart og avslutning +Name[nds]=An- un Utmaken +Name[nl]=Opstarten en afsluiten +Name[nn]=Oppstart og avslutting +Name[pa]=ਸ਼ੁਰੂਆਤ ਤੇ ਬੰਦ ਕਰਨਾ +Name[pl]=Uruchamianie i wyłączanie +Name[pt]=Arranque e Paragem +Name[pt_BR]=Inicialização e desligamento +Name[ro]=Pornire și oprire +Name[ru]=Запуск и завершение +Name[si]=ආරම්භ කිරීම සහ වැසීම +Name[sk]=Spustenie a vypnutie +Name[sl]=Zagon in izklop +Name[sr]=Подизање и гашење +Name[sr@ijekavian]=Подизање и гашење +Name[sr@ijekavianlatin]=Podizanje i gašenje +Name[sr@latin]=Podizanje i gašenje +Name[sv]=Start och avslutning +Name[th]=การเริ่มการทำงานและการปิดเครื่อง +Name[tr]=Başlatma ve Kapatma +Name[ug]=قوزغىلىش ۋە تاقاش +Name[uk]=Запуск і вихід +Name[vi]=Khởi động và tắt máy +Name[wa]=Enondaedje eyet aresse di l' éndjole +Name[x-test]=xxStartup and Shutdownxx +Name[zh_CN]=开机和关机 +Name[zh_TW]=啟動與關閉 diff --git a/systemsettings/categories/settings-system-administration.desktop b/systemsettings/categories/settings-system-administration.desktop new file mode 100644 index 00000000..bcf3d536 --- /dev/null +++ b/systemsettings/categories/settings-system-administration.desktop @@ -0,0 +1,84 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=system-administration +X-KDE-System-Settings-Parent-Category= +X-KDE-Weight=200 +Icon=preferences-system + +Name=System Administration +Name[ar]=إدارة النظام +Name[ast]=Alministración del sistema +Name[be]=Сістэмнае адміністраванне +Name[bg]=Системна администрация +Name[bn]=সিস্টেম অ্যাডমিনস্ট্রেশন +Name[br]=Melestradur ar Reizhiad +Name[bs]=Administracija sistema +Name[ca]=Administració del sistema +Name[ca@valencia]=Administració del sistema +Name[cs]=Administrace systému +Name[cy]=Gweinyddiaith Cysawd +Name[da]=Systemadministration +Name[de]=Systemverwaltung +Name[el]=Διαχείριση συστήματος +Name[en_GB]=System Administration +Name[es]=Administración del sistema +Name[et]=Süsteemi haldamine +Name[eu]=Sistema-administrazioa +Name[fa]=سرپرستی سیستم +Name[fi]=Järjestelmänhallinta +Name[fr]=Administration du système +Name[ga]=Riarachán Córais +Name[gl]=Administración do sistema +Name[gu]=સિસ્ટમ વહીવટ +Name[he]=ניהול המערכת +Name[hi]=तंत्र प्रशासक +Name[hr]=Administriranje sustava +Name[hu]=Rendszeradminisztráció +Name[ia]=Administration de systema +Name[id]=Administrasi Sistem +Name[is]=Kerfisstjórnun +Name[it]=Amministrazione di sistema +Name[ja]=システム管理 +Name[ka]=სისტემის ადმინისტრირება +Name[kk]=Жүйе әкімшілігі +Name[km]=ការ​គ្រប់គ្រង​ប្រព័ន្ធ +Name[kn]=ಗಣಕವ್ಯವಸ್ಥೆಯ ನಿರ್ವಹಣೆ +Name[ko]=시스템 관리 +Name[lt]=Sistemos administravimas +Name[lv]=Sistēmas administrācija +Name[mr]=प्रणाली प्रशासन +Name[nb]=Systemadministrasjon +Name[nds]=Systeempleeg +Name[ne]=प्रणाली प्रशासन +Name[nl]=Systeemadministratie +Name[nn]=Systemadministrasjon +Name[pa]=ਸਿਸਟਮ ਪਰਸ਼ਾਸ਼ਨ +Name[pl]=Administracja systemu +Name[pt]=Administração do Sistema +Name[pt_BR]=Administração do sistema +Name[ro]=Administrare sistem +Name[ru]=Системное администрирование +Name[se]=Vuogádathálddašeapmi +Name[si]=පද්ධති කළමනාකරනය +Name[sk]=Správa systému +Name[sl]=Skrbništvo sistema +Name[sr]=Администрација система +Name[sr@ijekavian]=Администрација система +Name[sr@ijekavianlatin]=Administracija sistema +Name[sr@latin]=Administracija sistema +Name[sv]=Systemadministration +Name[ta]=கணினி-நிர்வாகம் +Name[tg]=Мудири система +Name[th]=การดูแลบริหารระบบ +Name[tr]=Sistem Yönetimi +Name[ug]=سىستېما باشقۇرۇش +Name[uk]=Керування системою +Name[uz]=Tizimni boshqarish +Name[uz@cyrillic]=Тизимни бошқариш +Name[vi]=Quản trị hệ thống +Name[wa]=Manaedjmint d' sistinme +Name[xh]=Umphathi Wendlela yokusebenza +Name[x-test]=xxSystem Administrationxx +Name[zh_CN]=系统管理 +Name[zh_TW]=系統管理 diff --git a/systemsettings/categories/settings-window-behaviour.desktop b/systemsettings/categories/settings-window-behaviour.desktop new file mode 100644 index 00000000..6669cfbf --- /dev/null +++ b/systemsettings/categories/settings-window-behaviour.desktop @@ -0,0 +1,96 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=window-behaviour +X-KDE-System-Settings-Parent-Category=workspace-appearance-and-behavior +Icon=preferences-system-windows + +Name=Window Behavior +Name[af]=Venstergedrag +Name[ar]=سلوك النوافذ +Name[ast]=Comportamientu de la ventana +Name[be]=Паводзіны вокнаў +Name[be@latin]=Pavodziny akna +Name[bg]=Поведение на прозорците +Name[bn]=উইণ্ডো আচরণ +Name[bn_IN]=উইন্ডোর আচরণ +Name[br]=Emzalc'h ar prenester +Name[bs]=Ponašanje prozora +Name[ca]=Comportament de les finestres +Name[ca@valencia]=Comportament de les finestres +Name[cs]=Chování oken +Name[csb]=Ùchòwanié òkna +Name[cy]=Ymddygiad Ffenestri +Name[da]=Vinduesopførsel +Name[de]=Fensterverhalten +Name[el]=Συμπεριφορά παραθύρων +Name[en_GB]=Window Behaviour +Name[eo]=Fenestrokonduto +Name[es]=Comportamiento de la ventana +Name[et]=Akende käitumine +Name[eu]=Leihoaren portaera +Name[fa]=رفتار پنجره +Name[fi]=Ikkunoiden toiminta +Name[fr]=Comportement des fenêtres +Name[fy]=Finstergedrach +Name[ga]=Oibriú na bhFuinneog +Name[gl]=Comportamento das xanelas +Name[gu]=વિન્ડો વર્તણૂક +Name[he]=התנהגות חלונות +Name[hi]=विंडो व्यवहार +Name[hne]=विंडो व्यवहार +Name[hr]=Ponašanje prozora +Name[hu]=Ablakműveletek +Name[ia]=Comportamento de fenestra +Name[id]=Perilaku Jendela +Name[is]=Hegðun glugga +Name[it]=Comportamento delle finestre +Name[ja]=ウィンドウの挙動 +Name[ka]=ფანჯრის ქცევა +Name[kk]=Терезе қасиеттері +Name[km]=ឥរិយាបថ​បង្អួច +Name[kn]=ಕಿಟಕಿ ವರ್ತನೆ +Name[ko]=창 동작 +Name[ku]=Helwesta Paceyan +Name[lt]=Langų elgsena +Name[lv]=Logu izturēšanās +Name[mai]=विंडो व्यवहार +Name[mk]=Однесување на прозорци +Name[ml]=ജാലകത്തിന്റെ വിശേഷത +Name[mr]=चौकट वर्तन +Name[nb]=Vindusoppførsel +Name[nds]=Finsterbedregen +Name[ne]=सञ्झ्याल व्यवहार +Name[nl]=Venstergedrag +Name[nn]=Vindaugs­åtferd +Name[pa]=ਵਿੰਡੋ ਰਵੱਈਆ +Name[pl]=Zachowania okien +Name[pt]=Comportamento das Janelas +Name[pt_BR]=Comportamento da janela +Name[ro]=Comportament fereastră +Name[ru]=Поведение окон +Name[se]=Láseláhtten +Name[si]=කවුළු හැසිරීම +Name[sk]=Správanie okien +Name[sl]=Obnašanje oken +Name[sr]=Понашање прозора +Name[sr@ijekavian]=Понашање прозора +Name[sr@ijekavianlatin]=Ponašanje prozora +Name[sr@latin]=Ponašanje prozora +Name[sv]=Fönsterbeteende +Name[ta]=சாளர நடத்தை +Name[te]=విండో ప్రవర్తన +Name[tg]=Холати тиреза +Name[th]=พฤติกรรมของหน้าต่าง +Name[tr]=Pencere Davranışı +Name[ug]=كۆزنەكنىڭ ئىش-ھەرىكەتلىرى +Name[uk]=Поведінка вікон +Name[uz]=Oynaning xususiyatlari +Name[uz@cyrillic]=Ойнанинг хусусиятлари +Name[vi]=Ứng xử của Cửa sổ +Name[wa]=Dujhance des fniesses +Name[xh]=Ukuziphatha kwe Window +Name[x-test]=xxWindow Behaviorxx +Name[zh_CN]=窗口行为 +Name[zh_TW]=視窗行為 + diff --git a/systemsettings/categories/settings-workspace-appearance-and-behavior.desktop b/systemsettings/categories/settings-workspace-appearance-and-behavior.desktop new file mode 100644 index 00000000..64d07dfa --- /dev/null +++ b/systemsettings/categories/settings-workspace-appearance-and-behavior.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=workspace-appearance-and-behavior +X-KDE-System-Settings-Parent-Category= +X-KDE-Weight=80 +Icon=preferences-desktop-theme + +Name=Workspace Appearance and Behavior +Name[ar]=مظهر وسلوك مساحة العمل +Name[ast]=Apariencia y comportamientu del espaciu de trabayu +Name[bg]=Изглед и поведение на работната среда +Name[bn]=ওয়ার্কস্পেস-এর চেহারা এবং আচরণ +Name[bs]=Izgled i ponašanje radnog prostora +Name[ca]=Aparença i comportament de l'espai de treball +Name[ca@valencia]=Aparença i comportament de l'espai de treball +Name[cs]=Vzhled a chování oken +Name[da]=Arbejdsområdets udseende og opførsel +Name[de]=Erscheinungsbild und Verhalten der Arbeitsfläche +Name[el]=Εμφάνιση και συμπεριφορά χώρου εργασίας +Name[en_GB]=Workspace Appearance and Behaviour +Name[es]=Apariencia y comportamiento del espacio de trabajo +Name[et]=Töötsooni välimus ja käitumine +Name[eu]=Laneko eremuaren itxura eta portaera +Name[fi]=Työtilan ulkoasu ja toiminta +Name[fr]=Apparence et comportement de l'espace de travail +Name[gl]=Aparencia e comportamento do espazo de traballo +Name[he]=התנהגות ומראה סביבת העבודה +Name[hr]=Izgled i ponašanje radnog prostora +Name[hu]=A munkaterület megjelenése és működése +Name[ia]=Apparentia e comportamento del spatio de labor (Workspace) +Name[id]=Tampilan dan Perilaku Ruang Kerja +Name[is]=Útlit og hegðun vinnusvæðis +Name[it]=Aspetto e comportamento dello spazio di lavoro +Name[ja]=ワークスペースの外観と挙動 +Name[kk]=Жұмыс орның көрініс пен тәртібі +Name[km]=រូបរាង និង​ឥរិយាបថ​របស់​តំបន់​ធ្វើការ +Name[kn]=ಕಾರ್ಯಕ್ಷೇತ್ರ ಗೋಚರಿಕೆ ಹಾಗು ವರ್ತನೆ +Name[ko]=작업 공간 모양과 행동 +Name[lt]=Darbo erdvės išvaizda ir elgsena +Name[lv]=Darba telpas izskats un izturēšanās +Name[mr]=कार्यस्थान दर्शनीयता व वर्तन +Name[nb]=Utseende og oppførsel for arbeidsflaten +Name[nds]=Arbeitrebeet-Utsehn un -Bedregen +Name[nl]=Uiterlijk en gedrag van werkruimte +Name[nn]=Utsjånad og åtferd til arbeids­område +Name[pa]=ਵਰਕਸਪੇਸ ਦਿੱਖ ਤੇ ਰਵੱਈਆ +Name[pl]=Wygląd i zachowanie przestrzeni roboczej +Name[pt]=Aparência e Comportamento da Área de Trabalho +Name[pt_BR]=Comportamento e aparência do espaço de trabalho +Name[ro]=Aspect și comportament pentru spațiul de lucru +Name[ru]=Внешний вид и поведение среды рабочего стола +Name[si]=වැඩබිම් පෙනුම සහ හැසිරීම +Name[sk]=Vzhľad a správanie pracovnej plochy +Name[sl]=Videz in obnašanje delovnega prostora +Name[sr]=Изглед и понашање радног простора +Name[sr@ijekavian]=Изглед и понашање радног простора +Name[sr@ijekavianlatin]=Izgled i ponašanje radnog prostora +Name[sr@latin]=Izgled i ponašanje radnog prostora +Name[sv]=Arbetsytans utseende och beteende +Name[tg]=Рафтор ва намуди зоҳирии муҳити корӣ +Name[th]=รูปลักษณ์และพฤติกรรมของพื้นที่ทำงาน +Name[tr]=Çalışma Alanı Görünümü ve Davranışı +Name[ug]=خىزمەت بوشلۇقىنىڭ كۆرۈنۈشى ۋە ئىش-ھەرىكەتلىرى +Name[uk]=Вигляд і поведінка робочого простору +Name[vi]=Diện mạo và hành vi không gian làm việc +Name[wa]=Rivnance eyet dujhance di l' espåce di boutaedje +Name[x-test]=xxWorkspace Appearance and Behaviorxx +Name[zh_CN]=工作空间外观和行为 +Name[zh_TW]=工作空間外觀與行為 diff --git a/systemsettings/categories/settings-workspace-behavior.desktop b/systemsettings/categories/settings-workspace-behavior.desktop new file mode 100644 index 00000000..efdd5c8b --- /dev/null +++ b/systemsettings/categories/settings-workspace-behavior.desktop @@ -0,0 +1,69 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=SystemSettingsCategory +X-KDE-System-Settings-Category=workspace-behavior +X-KDE-System-Settings-Parent-Category=workspace-appearance-and-behavior +Icon=plasma + +Name=Workspace Behavior +Name[ar]=سلوك مساحة العمل +Name[ast]=Comportamientu del espaciu de trabayu +Name[bg]=Поведение на работната среда +Name[bs]=Ponašanje radnog prostora +Name[ca]=Comportament de l'espai de treball +Name[ca@valencia]=Comportament de l'espai de treball +Name[cs]=Chování pracovní plochy +Name[da]=Arbejdsområdets opførsel +Name[de]=Verhalten der Arbeitsfläche +Name[el]=Συμπεριφορά χώρου εργασίας +Name[en_GB]=Workspace Behaviour +Name[es]=Comportamiento del espacio de trabajo +Name[et]=Töötsooni käitumine +Name[eu]=Laneko eremuaren portaera +Name[fi]=Työtilan toiminta +Name[fr]=Comportement de l'espace de travail +Name[ga]=Oibriú an Spáis Oibre +Name[gl]=Comportamento do espazo de traballo +Name[gu]=વેબ વર્તણૂક +Name[he]=התנהגות סביבת העבודה +Name[hi]=कार्यक्षेत्र बर्ताव +Name[hr]=Ponašanje radnog prostora +Name[hu]=Működés +Name[ia]=Comportamento del spatio de labor +Name[is]=Hegðun vinnurýmis +Name[it]=Comportamento dello spazio di lavoro +Name[ja]=ワークスペースの挙動 +Name[kk]=Жұмыс орның қасиеттері +Name[km]=ឥរិយាបថ​តំបន់​ការងារ +Name[kn]=ಕಾರ್ಯಸ್ಥಳದ ವರ್ತನೆ +Name[ko]=작업 공간 행동 +Name[lt]=Darbo erdvės elgsena +Name[lv]=Darba telpas izturēšanās +Name[mr]=कार्यस्थान वर्तन +Name[nb]=Oppførsel for arbeidsflaten +Name[nds]=Arbeitrebeet-Bedregen +Name[nl]=Gedrag van werkruimte +Name[nn]=Åtferd til arbeids­område +Name[pa]=ਵਰਕਸਪੇਸ ਰਵੱਈਆ +Name[pl]=Zachowanie przestrzeni roboczej +Name[pt]=Comportamento da Área de Trabalho +Name[pt_BR]=Comportamento do espaço de trabalho +Name[ro]=Comportament spațiu de lucru +Name[ru]=Поведение рабочей среды +Name[sk]=Správanie pracovnej plochy +Name[sl]=Obnašanje delovnega prostora +Name[sr]=Понашање радног простора +Name[sr@ijekavian]=Понашање радног простора +Name[sr@ijekavianlatin]=Ponašanje radnog prostora +Name[sr@latin]=Ponašanje radnog prostora +Name[sv]=Arbetsytans beteende +Name[tg]=Рафтори муҳити корӣ +Name[th]=พฤติกรรมของพื้นที่ทำงาน +Name[tr]=Çalışma Alanı Davranışı +Name[ug]=خىزمەت بوشلۇقىنىڭ ئىش-ھەرىكەتلىرى +Name[uk]=Поведінка робочого простору +Name[vi]=Hành vi không gian làm việc +Name[wa]=Dujhance di l' espåce di boutaedje +Name[x-test]=xxWorkspace Behaviorxx +Name[zh_CN]=工作空间行为 +Name[zh_TW]=工作空間行為 diff --git a/systemsettings/categories/systemsettingscategory.desktop b/systemsettings/categories/systemsettingscategory.desktop new file mode 100644 index 00000000..3df3ad0c --- /dev/null +++ b/systemsettings/categories/systemsettingscategory.desktop @@ -0,0 +1,96 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=SystemSettingsCategory +Name=System Settings Category +Name[ar]=فئة إعدادات النظام +Name[ast]=Categoría de preferencies del sistema +Name[be]=Катэгорыя сістэмных настаўленняў +Name[be@latin]=Katehoryja systemnych naładaŭ +Name[bg]=Категория системни настройки +Name[bn]=সিস্টেম সেটিংস শ্রেণী +Name[bs]=Kategorija sistemskih postavki +Name[ca]=Categoria d'arranjament del sistema +Name[ca@valencia]=Categoria d'arranjament del sistema +Name[cs]=Kategorie systémových nastavení +Name[csb]=Kategòrëjô systemòwégò nastôwù +Name[da]=Kategori af Systemindstillinger +Name[de]=Systemeinstellungen-Kategorie +Name[el]=Κατηγορία ρυθμίσεων συστήματος +Name[en_GB]=System Settings Category +Name[eo]=Sistemagorda kategorio +Name[es]=Categoría de preferencias del sistema +Name[et]=Süsteemi seadistuste kategooria +Name[eu]=Sistema-ezarpenen kategoria +Name[fa]=دسته تنظیمات سیستم +Name[fi]=Järjestelmäasetusten luokka +Name[fr]=Catégorie des paramètres du système +Name[fy]=Systeem ynstellings katogory +Name[ga]=Catagóir Socruithe an Chórais +Name[gl]=Categoría de configuración do sistema +Name[gu]=સિસ્ટમ ગોઠવણીઓ વર્ગ +Name[he]=קטגוריית הגדרות מערכת +Name[hi]=तंत्र विन्यास वर्ग +Name[hne]=तंत्र सेटिंग वर्ग +Name[hr]=Kategorija sustavskih postavki +Name[hu]=Rendszerbeállítási kategória +Name[ia]=Categoria de preferentias de systema +Name[id]=Kategori Pengaturan Sistem +Name[is]=Kerfisstillingaflokkur +Name[it]=Categoria delle impostazioni di sistema +Name[ja]=システム設定のカテゴリ +Name[kk]=Жүйе параметрлер санаты +Name[km]=ប្រភេទ​ការ​កំណត់​ប្រព័ន្ធ​ +Name[kn]=ವ್ಯವಸ್ಥಾ ಸಂಯೋಜನೆಗಳ ಪಂಗಡ +Name[ko]=시스템 설정 분류 +Name[ku]=Kategoriya Mîhengên Pergalê +Name[lt]=Sistemos nustatymų kategorija +Name[lv]=Sistēmas iestatījumu kategorija +Name[mai]=तंत्र सेटिंग वर्ग +Name[mk]=Категорија со системски поставувања +Name[ml]=സിസ്റ്റം സജ്ജീകരണങ്ങളുടെ വിഭാഗം +Name[mr]=प्रणाली संयोजना वर्ग +Name[nb]=Kategori for systeminnstillinger +Name[nds]=Kategorie Systeeminstellen +Name[ne]=प्रणाली सेटिङ कोटि +Name[nl]=Systeeminstellingen-catagorie +Name[nn]=Kategori for systemval +Name[or]=ତନ୍ତ୍ର ବିନ୍ୟାସ ବିଭାଗ +Name[pa]=ਸਿਸਟਮ ਸੈਟਿੰਗ ਕੈਟਾਗਰੀ +Name[pl]=Kategoria ustawień systemowych +Name[pt]=Categoria da Configuração do Sistema +Name[pt_BR]=Categoria das configurações do sistema +Name[ro]=Categorie Configurări de sistem +Name[ru]=Настройка системы +Name[se]=Vuogádatheivehusaid láhki +Name[si]=පද්ධති සැකසුම් ප්‍රභේද +Name[sk]=Kategória systémových nastavení +Name[sl]=Kategorija sistemskih nastavitev +Name[sr]=Категорија системских поставки +Name[sr@ijekavian]=Категорија системских поставки +Name[sr@ijekavianlatin]=Kategorija sistemskih postavki +Name[sr@latin]=Kategorija sistemskih postavki +Name[sv]=Systeminställningskategori +Name[ta]=System Settings Category +Name[te]=సిస్టమ్ అమరికల వర్గము +Name[tg]=Категория параметров системы +Name[th]=หมวดหมู่การตั้งค่าระบบ +Name[tr]=Sistem Ayarları Kategorisi +Name[ug]=سىستېما تەڭشەك كاتېگورىيىسى +Name[uk]=Категорія системних параметрів +Name[vi]=Thể loại trong Thiết lập hệ thống +Name[wa]=Categoreye d' apontiaedjes do sistinme +Name[x-test]=xxSystem Settings Categoryxx +Name[zh_CN]=系统设置类别 +Name[zh_TW]=系統設定類別 + +# the category identifier +[PropertyDef::X-KDE-System-Settings-Category] +Type=QString + +# the parent category identifier +[PropertyDef::X-KDE-System-Settings-Parent-Category] +Type=QString + +# parent category identifier version 2 +[PropertyDef::X-KDE-System-Settings-Parent-Category-V2] +Type=QString diff --git a/systemsettings/classic/CMakeLists.txt b/systemsettings/classic/CMakeLists.txt new file mode 100644 index 00000000..3fab1c6c --- /dev/null +++ b/systemsettings/classic/CMakeLists.txt @@ -0,0 +1,14 @@ +SET(classic_mode_srcs + ClassicMode.cpp + CategoryList.cpp +) + +KDE4_ADD_UI_FILES( classic_mode_srcs configClassic.ui ) +KDE4_ADD_PLUGIN(classic_mode ${classic_mode_srcs}) + +TARGET_LINK_LIBRARIES(classic_mode ${KDE4_KCMUTILS_LIBS} ${KDE4_KHTML_LIBS} systemsettingsview ) + +INSTALL( TARGETS classic_mode DESTINATION ${PLUGIN_INSTALL_DIR} ) +INSTALL( FILES settings-classic-view.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +INSTALL( FILES main.html systemsettings-classic.css DESTINATION ${DATA_INSTALL_DIR}/systemsettings/classic/ ) + diff --git a/systemsettings/classic/CategoryList.cpp b/systemsettings/classic/CategoryList.cpp new file mode 100644 index 00000000..2e9e3e03 --- /dev/null +++ b/systemsettings/classic/CategoryList.cpp @@ -0,0 +1,136 @@ +/* + Copyright (c) 2000,2001 Matthias Elter + Copyright (c) 2009 Ben Cooksley + + 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 "CategoryList.h" + +#include "MenuItem.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char kcc_infotext[]= I18N_NOOP("System Settings"); +static const char title_infotext[]= I18N_NOOP("Configure your system"); +static const char intro_infotext[]= I18N_NOOP("Welcome to \"System Settings\", " + "a central place to configure your computer system."); + +class CategoryList::Private { +public: + Private() {} + + KHTMLPart * categoryView; + QModelIndex categoryMenu; + QAbstractItemModel * itemModel; + QMap itemMap; +}; + +CategoryList::CategoryList( QWidget *parent, QAbstractItemModel *model ) + : KHBox(parent), d( new Private() ) +{ + setMinimumSize( 400, 400 ); + d->itemModel = model; + + // set what's this help + this->setWhatsThis( i18n( intro_infotext ) ); + d->categoryView = new KHTMLPart( this ); + d->categoryView->view()->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); + d->categoryView->widget()->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ); + connect( d->categoryView->browserExtension(), + SIGNAL( openUrlRequest( const KUrl&, + const KParts::OpenUrlArguments&, + const KParts::BrowserArguments& ) ), + this, SLOT(slotModuleLinkClicked(KUrl)) ); +} + +CategoryList::~CategoryList() +{ + delete d; +} + +void CategoryList::updatePixmap() +{ + QString content; + QString moduleName; + KIconLoader * iconL = KIconLoader::global(); + d->itemMap.clear(); + + const QString templatePath = KStandardDirs::locate( "data", "systemsettings/classic/main.html" ); + QFile templateFile( templatePath ); + templateFile.open( QIODevice::ReadOnly ); + QTextStream templateText( &templateFile ); + QString templateString = templateText.readAll(); + templateString = templateString.arg( KStandardDirs::locate( "data", "kdeui/about/kde_infopage.css" ) ); + if ( kapp->layoutDirection() == Qt::RightToLeft ) { + templateString = templateString.arg( "@import \"%1\";" ).arg( KStandardDirs::locate( "data", "kdeui/about/kde_infopage_rtl.css" ) ); + } else { + templateString = templateString.arg( QString() ); + } + templateString = templateString.arg( i18n( kcc_infotext ) ); + templateString = templateString.arg( i18n( title_infotext ) ); + templateString = templateString.arg( i18n( intro_infotext ) ); + if ( d->categoryMenu.isValid() ) { + moduleName = d->itemModel->data( d->categoryMenu, Qt::DisplayRole ).toString(); + } + content += "
" + moduleName + "
"; + content += "\n"; + for( int done = 0; d->itemModel->rowCount( d->categoryMenu ) > done; ++done ) { + QModelIndex childIndex = d->itemModel->index( done, 0, d->categoryMenu ); + MenuItem *childItem = d->itemModel->data( childIndex, Qt::UserRole ).value(); + KUrl link( "kcm://" ); + link.setFileName( childItem->item().fileName() ); + kDebug() << childItem->name() << childItem->item().fileName() << link.url(); + const QString szLink = ""; + content += "\n"; + } + content += "
" + szLink + ""; + const QString szName = childItem->name(); + const QString szComment = childItem->service()->comment(); + content += szLink + szName + "" + szLink + szComment + ""; + content = content.arg( iconL->iconPath(childItem->service()->icon(), - KIconLoader::SizeSmallMedium ) ); + d->itemMap.insert( link.url(), childIndex ); + content += "
"; + d->categoryView->begin( KUrl( templatePath ) ); + d->categoryView->write( templateString.arg( content ) ); + d->categoryView->end(); +} + +void CategoryList::changeModule( QModelIndex newItem ) +{ + d->categoryMenu = newItem; + updatePixmap(); +} + +void CategoryList::slotModuleLinkClicked( const KUrl& moduleName ) +{ + QModelIndex module = d->itemMap.value( moduleName.url() ); + kDebug() << "Link name: " + moduleName.url(); + emit moduleSelected( module ); +} + +#include "CategoryList.moc" diff --git a/systemsettings/classic/CategoryList.h b/systemsettings/classic/CategoryList.h new file mode 100644 index 00000000..9891819d --- /dev/null +++ b/systemsettings/classic/CategoryList.h @@ -0,0 +1,53 @@ +/* + Copyright (c) 2000,2001 Matthias Elter + + 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 CATEGORYLIST_H +#define CATEGORYLIST_H + +#include + +class QModelIndex; +class QAbstractItemModel; + +class KUrl; + +class CategoryList : public KHBox +{ + Q_OBJECT + +public: + explicit CategoryList( QWidget *parent, QAbstractItemModel *model ); + virtual ~CategoryList(); + + void changeModule( QModelIndex newItem); + +Q_SIGNALS: + void moduleSelected( QModelIndex itemSelected ); + +private Q_SLOTS: + void slotModuleLinkClicked( const KUrl& ); + +private: + void updatePixmap(); + +private: + class Private; + Private *const d; +}; + +#endif diff --git a/systemsettings/classic/ClassicMode.cpp b/systemsettings/classic/ClassicMode.cpp new file mode 100644 index 00000000..d9e85608 --- /dev/null +++ b/systemsettings/classic/ClassicMode.cpp @@ -0,0 +1,265 @@ +/************************************************************************** + * Copyright (C) 2009 Ben Cooksley * + * Copyright (C) 2008 Mathias Soeken * + * * + * 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 "ClassicMode.h" +#include "ui_configClassic.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "MenuItem.h" +#include "MenuModel.h" +#include "ModuleView.h" +#include "CategoryList.h" +#include "MenuProxyModel.h" + +K_PLUGIN_FACTORY(ClassicModeFactory, registerPlugin();) +K_EXPORT_PLUGIN(ClassicModeFactory("classic_mode")) + +class ClassicMode::Private { +public: + Private() : moduleView( 0 ) {} + virtual ~Private() { + delete aboutClassic; + } + + QSplitter * classicWidget; + QTreeView * classicTree; + Ui::ConfigClassic classicConfig; + CategoryList * classicCategory; + QStackedWidget * stackedWidget; + ModuleView * moduleView; + QModelIndex currentItem; + + MenuProxyModel * proxyModel; + MenuModel * model; + KAboutData * aboutClassic; +}; + +ClassicMode::ClassicMode( QObject * parent, const QVariantList& ) + : BaseMode( parent ), d( new Private() ) +{ + d->aboutClassic = new KAboutData( "TreeView", 0, ki18n("Tree View"), + "1.0", ki18n("Provides a classic tree-based view of control modules."), + KAboutData::License_GPL, ki18n("(c) 2009, Ben Cooksley")); + d->aboutClassic->addAuthor(ki18n("Ben Cooksley"), ki18n("Author"), "bcooksley@kde.org"); + d->aboutClassic->addAuthor(ki18n("Mathias Soeken"), ki18n("Developer"), "msoeken@informatik.uni-bremen.de"); + d->aboutClassic->setProgramIconName("view-list-tree"); +} + +ClassicMode::~ClassicMode() +{ + if( !d->classicTree ) { + delete d->classicWidget; + } + delete d; +} + +void ClassicMode::initEvent() +{ + // Create the model + d->model = new MenuModel( rootItem(), this ); + + // Move items that are the sole child of a category up.... + moveUp( rootItem() ); + + // Create the proxy model + d->proxyModel = new MenuProxyModel( this ); + d->proxyModel->setSourceModel( d->model ); + d->proxyModel->sort( 0 ); + d->classicWidget = new QSplitter( Qt::Horizontal, 0 ); + d->classicWidget->setChildrenCollapsible( false ); + d->moduleView = new ModuleView( d->classicWidget ); + d->classicTree = 0; +} + +QWidget * ClassicMode::mainWidget() +{ + if( !d->classicTree ) { + initWidget(); + } + return d->classicWidget; +} + +KAboutData * ClassicMode::aboutData() +{ + return d->aboutClassic; +} + +ModuleView * ClassicMode::moduleView() const +{ + return d->moduleView; +} + +QList ClassicMode::views() const +{ + QList theViews; + theViews << d->classicTree; + return theViews; +} + +void ClassicMode::saveState() +{ + config().writeEntry( "viewLayout", d->classicWidget->sizes() ); + config().sync(); +} + +void ClassicMode::expandColumns() +{ + d->classicTree->resizeColumnToContents(0); +} + +void ClassicMode::searchChanged( const QString& text ) +{ + d->proxyModel->setFilterRegExp(text); + if( d->classicTree ) { + d->classicCategory->changeModule( d->classicTree->currentIndex() ); + } +} + +void ClassicMode::selectModule( const QModelIndex& selectedModule ) +{ + d->classicTree->setCurrentIndex( selectedModule ); + if( d->proxyModel->rowCount(selectedModule) > 0 ) { + d->classicTree->setExpanded(selectedModule, true); + } + changeModule( selectedModule ); +} + +void ClassicMode::changeModule( const QModelIndex& activeModule ) +{ + if( activeModule == d->currentItem ) { + return; + } + if( !d->moduleView->resolveChanges() ) { + return; + } + d->moduleView->closeModules(); + d->currentItem = activeModule; + if( d->proxyModel->rowCount(activeModule) > 0 ) { + d->stackedWidget->setCurrentWidget( d->classicCategory ); + d->classicCategory->changeModule(activeModule); + emit viewChanged( false ); + } else { + d->moduleView->loadModule( activeModule ); + } +} + +void ClassicMode::moduleLoaded() +{ + d->stackedWidget->setCurrentWidget( d->moduleView ); +} + +void ClassicMode::initWidget() +{ + // Create the widget + d->classicTree = new QTreeView( d->classicWidget ); + d->classicCategory = new CategoryList( d->classicWidget, d->proxyModel ); + + d->stackedWidget = new QStackedWidget( d->classicWidget ); + d->stackedWidget->layout()->setMargin(0); + d->stackedWidget->addWidget( d->classicCategory ); + d->stackedWidget->addWidget( d->moduleView ); + + d->classicWidget->addWidget( d->classicTree ); + d->classicWidget->addWidget( d->stackedWidget ); + + d->classicTree->setModel( d->proxyModel ); + d->classicTree->setHeaderHidden( true ); + d->classicTree->setIconSize( QSize( 24, 24 ) ); + d->classicTree->setSortingEnabled( true ); + d->classicTree->setMouseTracking( true ); + d->classicTree->setMinimumWidth( 200 ); + d->classicTree->setSelectionMode( QAbstractItemView::SingleSelection ); + d->classicTree->sortByColumn( 0, Qt::AscendingOrder ); + + d->classicCategory->changeModule( d->classicTree->rootIndex() ); + + connect( d->classicCategory, SIGNAL(moduleSelected(QModelIndex)), this, SLOT(selectModule(QModelIndex)) ); + connect( d->classicTree, SIGNAL(activated(QModelIndex)), this, SLOT(changeModule(QModelIndex)) ); + connect( d->classicTree, SIGNAL(collapsed(QModelIndex)), this, SLOT(expandColumns()) ); + connect( d->classicTree, SIGNAL(expanded(QModelIndex)), this, SLOT(expandColumns()) ); + connect( d->moduleView, SIGNAL(moduleChanged(bool)), this, SLOT(moduleLoaded()) ); + + if( !KGlobalSettings::singleClick() ) { + // Needed because otherwise activated() is not fired with single click, which is apparently expected for tree views + connect( d->classicTree, SIGNAL(clicked(QModelIndex)), this, SLOT(changeModule(QModelIndex)) ); + } + + if( config().readEntry( "autoExpandOneLevel", false ) ) { + for( int processed = 0; d->proxyModel->rowCount() > processed; processed++ ) { + d->classicTree->setExpanded( d->proxyModel->index( processed, 0 ), true ); + } + } + + expandColumns(); + QList defaultSizes; + defaultSizes << 250 << 500; + d->classicWidget->setSizes( config().readEntry( "viewLayout", defaultSizes ) ); +} + +void ClassicMode::leaveModuleView() +{ + d->moduleView->closeModules(); + d->stackedWidget->setCurrentWidget( d->classicCategory ); +} + +void ClassicMode::giveFocus() +{ + d->classicTree->setFocus(); +} + +void ClassicMode::addConfiguration( KConfigDialog * config ) +{ + QWidget * configWidget = new QWidget( config ); + d->classicConfig.setupUi( configWidget ); + config->addPage( configWidget, i18n("Tree View"), aboutData()->programIconName() ); +} + +void ClassicMode::loadConfiguration() +{ + d->classicConfig.CbExpand->setChecked( config().readEntry( "autoExpandOneLevel", false ) ); +} + +void ClassicMode::saveConfiguration() +{ + config().writeEntry("autoExpandOneLevel", d->classicConfig.CbExpand->isChecked()); +} + +void ClassicMode::moveUp( MenuItem * item ) +{ + foreach( MenuItem * child, item->children() ) { + if( child->children().count() == 1 ) { + d->model->addException( child ); + } + moveUp( child ); + } +} + +#include "ClassicMode.moc" diff --git a/systemsettings/classic/ClassicMode.h b/systemsettings/classic/ClassicMode.h new file mode 100644 index 00000000..23ba91da --- /dev/null +++ b/systemsettings/classic/ClassicMode.h @@ -0,0 +1,65 @@ +/************************************************************************** + * Copyright (C) 2009 Ben Cooksley * + * * + * 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 CLASSICMODE_H +#define CLASSICMODE_H + +#include "BaseMode.h" + +class MenuItem; +class ModuleView; +class QModelIndex; + +class ClassicMode : public BaseMode +{ + Q_OBJECT + +public: + ClassicMode(QObject * parent, const QVariantList& ); + ~ClassicMode(); + void initEvent(); + void leaveModuleView(); + QWidget * mainWidget(); + KAboutData * aboutData(); + ModuleView * moduleView() const; + +protected: + QList views() const; + +public Q_SLOTS: + void expandColumns(); + void searchChanged( const QString& text ); + void selectModule( const QModelIndex& selectedModule ); + void changeModule( const QModelIndex& activeModule ); + void saveState(); + void giveFocus(); + void addConfiguration( KConfigDialog * config ); + void loadConfiguration(); + void saveConfiguration(); + +private Q_SLOTS: + void moduleLoaded(); + void initWidget(); + void moveUp( MenuItem * item ); + +private: + class Private; + Private *const d; +}; + +#endif diff --git a/systemsettings/classic/configClassic.ui b/systemsettings/classic/configClassic.ui new file mode 100644 index 00000000..3a00b412 --- /dev/null +++ b/systemsettings/classic/configClassic.ui @@ -0,0 +1,38 @@ + + + ConfigClassic + + + + 0 + 0 + 400 + 66 + + + + + + + Expand the first level automatically + + + + + + + Qt::Vertical + + + + 20 + 28 + + + + + + + + + diff --git a/systemsettings/classic/main.html b/systemsettings/classic/main.html new file mode 100644 index 00000000..2d80b192 --- /dev/null +++ b/systemsettings/classic/main.html @@ -0,0 +1,59 @@ + + + + + + + + + +