Cherry-picking new upstream version 0.11.0

* Synced debian foo with experimental
* Bumped compat to 10
* Removed --parallel from rules, standard compat 10
* Bumped minimum version debhelper (>= 10)
* Bumped minimum version liblxqt0-dev (>= 0.11.0)
* Bumped minimum version libqt5xdg-dev (>= 2.0.0)
* Added build dependency libqt5xdgiconloader-dev (>= 2.0.0)
* Added build dependency libqt5svg5-dev
* Removed build dependency liboobs-1-dev
* Added recommends lxqt-admin-l10n
* Added a lintian-override for lxqt-admin-user-helper
* Exported LC_ALL=C.UTF-8 - define language settings for reproducible
  builds
* Fixed VCS-Fields, use https
* Bumped copyright years
* Added hardening to rules
* Added translation control to rules
* Set CMAKE_BUILD_TYPE=RelWithDebInfo
* Added README.md to docs
ubuntu/cosmic debian/0.11.0-2
Alf Gaida 8 years ago
parent 0f3c4fbd41
commit f71380240d

2
.gitignore vendored

@ -1 +1,3 @@
build build
lxqt-admin.kdev4
*/translations/lxqt-admin

@ -2,7 +2,7 @@ Upstream Authors:
LXQt team: http://lxqt.org LXQt team: http://lxqt.org
Copyright: Copyright:
Copyright (c) 2014 LXQt team Copyright (c) 2014-2016 LXQt team
License: LGPL-2.1+ License: LGPL-2.1+
The full text of the licenses can be found in the 'COPYING' file. The full text of the licenses can be found in the 'COPYING' file.

@ -0,0 +1,99 @@
lxqt-admin-0.11.0 / 2016-09-24
==============================
* user: Add failure message box
* user: Provide icon name in polkit policy
* Update README.md
* Add Catalan translations
* Add copyright headers
* Add Arabic Translations for Desktop Files
* lxqt-admin-user: Fix a change password crash
* lxqt-admin-user: Makes the Refresh toolbar button visible
* lxqt-admin-time: Adjust dialog size on startup
* Update openSUSE section in README
* Update README.md
* Support NTP and Local RTC settings with timedated provided by systemd. Code cleanup.
* Replace calling timedatectl command with calling its dbus interface instead and provide proper error messages.
* Use dbus interface of timedate systemd daemon instead of timedatectl command.
* Add the ability to update group members.
* Support changing of user password.
* Show group members.
* Try to use a helper script and polkit policy configurations to do user admin.
* Remove liboobs dependency from lxqt-admin-time and use timedatectl to handle all time configurations.
* Try to handle timezones with timedatectl provided by systemd instead of liboobs.
* Add groupmod
* Try to remove liboobs dependency.
* Add README.md
* build: Use external translations
* ts-files removal (#32)
* Bump years to 2016
* Don't track IDE settings
* Italian translation update
* Russian translations update Remove duplicated ru_RU translations
* updated: *_hu.ts
0.10.0 / 2015-10-31
===================
* Fix license file
* Add Greek (el) translation
* Rename LxQt to LXQt everywhere
* Removed invisible dialog titles. Updated template. Added german translation.
* Handles CMake policy CMP0063
* Initialize in the same order of declaration in the class definition
* Use the LXQtCompilerSettings CMake module
* Updates the build system to use the Targets infrastructure
* Remove trailing whitespaces
* Create lxqt-admin-time_hr.ts
* Create lxqt-admin-user_hr.ts
* Hungarian translations added
* Create lxqt-admin-time_it.desktop
* Create lxqt-admin-user_it.desktop
* Initial Polish translation
* Create lxqt-admin-user_it.desktop
* lxqt-admin-user: set minimum default GID value for new group to 1000
* Initial Polish translation
0.9.0 / 2015-01-25
==================
* Create lxqt-admin-user_it.desktop
* Create lxqt-admin-user_it.ts
* Create lxqt-admin-time_it.ts
* Add Portuguese language
* Added Japanese translation
* Unify naming for a unique lxqt. No more suffixes
* Update Russian translation
* Updates translations sources
* Whole GUI of time/date setup has been rewritten from scratch the app has now style of LXQT config dialogs based on LxQt::ConfigDialog the time and date setting is divided into one configuration widget and timezone selection is divided into second config widget
* Add icon to config window
* Add .gitignore
* Make use of QApplication::exec()
* Use the new LxQt::SingleApplication
* CMakeLists.txt maintenance.
* Update translation a little more
* Add Russian translation
* updates Translations
* Updates the translations infrastructure
* Drop Qt4 support in CMakeLists.txt in subfolders
* Drop Qt4 support in code
* Clean up CMakeLists.txt and drop Qt 4
0.8.0 / 2014-06-21
==================
* simplify Qt version switching
* Support build with Qt5.
* Use new LXQt header files.
* Update copyright notice.
* Support changing group members.
* Support adding/removing/editing users and groups.
* Redesign the UI.
* Add a group configuration dialog.
* Improve user dialog.
* Add a user config dialog.
* Update time every seconds unless it's changed manually by the user.
* Add basic skeleton for lxqt-admin-user tool.
* Add a very basic time config tool, lxqt-admin-time.
* Initial commit.

@ -11,12 +11,6 @@ find_package(Qt5Widgets REQUIRED QUIET)
find_package(lxqt REQUIRED QUIET) find_package(lxqt REQUIRED QUIET)
find_package(KF5WindowSystem REQUIRED QUIET) find_package(KF5WindowSystem REQUIRED QUIET)
find_package(PkgConfig)
pkg_check_modules(OOBS REQUIRED
glib-2.0
liboobs-1
)
include(LXQtCompilerSettings NO_POLICY_SCOPE) include(LXQtCompilerSettings NO_POLICY_SCOPE)
include(LXQtTranslate) include(LXQtTranslate)

@ -0,0 +1,67 @@
# lxqt-admin
## Overview
This repository is providing two GUI tools to adjust settings of the operating system LXQt is running on.
Both are using [polkit](https://www.freedesktop.org/wiki/Software/polkit/) to handle permissions.
In contrast to the specific backends described below earlier versions of lxqt-admin were relying on [system-tools-backends](http://system-tools-backends.freedesktop.org) and their wrapper [liboobs](https://github.com/GNOME/liboobs). These were replaced as both go unmaintained for years and were hence dropped from many distributions heavily restricting the usage of lxqt-admin. As long as they can be built it should still be possible to compile lxqt-admin release ≤ 0.10 against them in order to make use of it on platforms lacking systemd like BSD.
### Time and date configuration
Adjusts time and date. Binary is `lxqt-admin-time`.
![lxqt-admin-time](lxqt-admin-time.png)
It is using `systemd-timedated` as backend which is accessed by its D-Bus interface. Among other this means the option
to sync the system time by NTP is relying on `systemd-timesyncd` as backend.
### User and Group Settings
Management of users and groups. Binary is `lxqt-admin-user`.
![lxqt-admin-user](lxqt-admin-user.png)
The backend is a script `lxqt-admin-user-helper`. By default it is in turn using the shadow tools to do the actual work.
The script can be modified to use different tools, though.
## Installing
### Compiling sources
Runtime dependencies are polkit and [liblxqt](https://github.com/lxde/liblxqt). A polkit agent should be available with [lxqt-policykit](https://github.com/lxde/lxqt-policykit/) representing the first choice in LXQt.
Additional build dependencies are CMake and optionally Git to pull latest VCS checkouts. The localization files were outsourced to repository [lxqt-l10n](https://github.com/lxde/lxqt-l10n) so the corresponding dependencies are needed, too. Please refer to this repository's `README.md` for further information.
Code configuration is handled by CMake. CMake variable `CMAKE_INSTALL_PREFIX` will normally have to be set to `/usr`.
To build run `make`, to install `make install` which accepts variable `DESTDIR` as usual.
### Binary packages
#### Arch Linux
[AUR](https://aur.archlinux.org) packages `lxqt-admin` and `lxqt-admin-git` are providing the current stable release and the
actual master checkout at compile time as usual.
Note that package `lxqt-admin` had to be kept in the AUR due to lack of the dependency liboobs as depicted [above](#overview).
So it will be transferred to community as of release 0.11.
#### Debian
Package `lxqt-admin` is available in the official repositories as of Debian stretch.
#### Fedora
Fedora doesn't provide lxqt-admin so far due to lack of the dependency liboobs as depicted [above](#overview). This will hopefully change
once release LXQt release 0.11 makes it into the Fedora repositories.
#### openSUSE
openSUSE does not ship with lxqt-admin in it's standard repositories since the functionality is covered by openSUSE's [YaST](http://yast.github.io/).
However it is still possible to install it on openSUSE. The package and its dependencies, like the [above](#overview) mentioned, outdated liboobs are available through the [X11:LXQt](https://build.opensuse.org/project/show/X11:LXQt) repository.
## Usage
Much like similar tools provided by [lxqt-config](https://github.com/lxde/lxqt-config) the tools of lxqt-admin can be launched from the [Configuration Center](https://github.com/lxde/lxqt-config#configuration-center) as well as from the panel's main menu - Preferences - LXQt settings.
The actual usage should be self-explanatory. To apply settings the GUI of the polkit authentication agent that's in use is
launched to acquire the root password.

1
debian/.gitignore vendored

@ -1,6 +1,7 @@
/*.debhelper /*.debhelper
/*.log /*.log
/*.substvars /*.substvars
/debhelper-build-stamp
/files /files
/lxqt-admin/ /lxqt-admin/

25
debian/changelog vendored

@ -1,3 +1,28 @@
lxqt-admin (0.11.0-2) unstable; urgency=medium
* Cherry-picking new upstream version 0.11.0
* Synced debian foo with experimental
* Bumped compat to 10
* Removed --parallel from rules, standard compat 10
* Bumped minimum version debhelper (>= 10)
* Bumped minimum version liblxqt0-dev (>= 0.11.0)
* Bumped minimum version libqt5xdg-dev (>= 2.0.0)
* Added build dependency libqt5xdgiconloader-dev (>= 2.0.0)
* Added build dependency libqt5svg5-dev
* Removed build dependency liboobs-1-dev
* Added recommends lxqt-admin-l10n
* Added a lintian-override for lxqt-admin-user-helper
* Exported LC_ALL=C.UTF-8 - define language settings for reproducible
builds
* Fixed VCS-Fields, use https
* Bumped copyright years
* Added hardening to rules
* Added translation control to rules
* Set CMAKE_BUILD_TYPE=RelWithDebInfo
* Added README.md to docs
-- Alf Gaida <agaida@siduction.org> Tue, 18 Oct 2016 01:54:42 +0200
lxqt-admin (0.10.0-3) unstable; urgency=medium lxqt-admin (0.10.0-3) unstable; urgency=medium
* Remove dbg package in favor of dbgsym. * Remove dbg package in favor of dbgsym.

2
debian/compat vendored

@ -1 +1 @@
9 10

16
debian/control vendored

@ -5,26 +5,28 @@ Uploaders: Alf Gaida <agaida@siduction.org>,
Andrew Lee (李健秋) <ajqlee@debian.org> Andrew Lee (李健秋) <ajqlee@debian.org>
Section: x11 Section: x11
Priority: optional Priority: optional
Build-Depends: debhelper (>= 9), Build-Depends: debhelper (>= 10),
cmake (>= 3.0.2), cmake (>= 3.0.2),
liboobs-1-dev,
libkf5windowsystem-dev, libkf5windowsystem-dev,
liblxqt0-dev (>= 0.10.0), liblxqt0-dev (>= 0.11.0),
libqt5svg5-dev,
libqt5x11extras5-dev, libqt5x11extras5-dev,
libqt5xdg-dev (>= 1.3.0), libqt5xdg-dev (>= 2.0.0),
libqt5xdgiconloader-dev (>= 2.0.0),
libx11-dev, libx11-dev,
pkg-config, pkg-config,
qttools5-dev, qttools5-dev,
qttools5-dev-tools qttools5-dev-tools
Standards-Version: 3.9.6 Standards-Version: 3.9.8
Vcs-Browser: http://anonscm.debian.org/cgit/pkg-lxqt/lxqt-admin.git/?h=debian/sid Vcs-Browser: https://anonscm.debian.org/cgit/pkg-lxqt/lxqt-admin.git/?h=debian/sid
Vcs-Git: git://anonscm.debian.org/pkg-lxqt/lxqt-admin.git -b debian/sid Vcs-Git: https://anonscm.debian.org/git/pkg-lxqt/lxqt-admin.git -b debian/sid
Homepage: https://github.com/lxde/lxqt-admin Homepage: https://github.com/lxde/lxqt-admin
Package: lxqt-admin Package: lxqt-admin
Architecture: any Architecture: any
Depends: ${misc:Depends}, Depends: ${misc:Depends},
${shlibs:Depends} ${shlibs:Depends}
Recommends: lxqt-admin-l10n
Description: Admin tools for LXQt Description: Admin tools for LXQt
Admin tools for LXQt, as of now: Admin tools for LXQt, as of now:
* lxqt-admin-time * lxqt-admin-time

6
debian/copyright vendored

@ -1,14 +1,14 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: lxqt-admin Upstream-Name: lxqt-admin
Source: https://github.com/lxde/lxqt-admin Source: https://github.com/lxde/lxqt-admin
Files: * Files: *
Copyright: 2014-2015 LXQt team Copyright: 2014-2016 LXQt team
2014 Hong Jen Yee (PCMan) <pcman.tw@gmail.com> 2014 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
License: LGPL-2.1+ License: LGPL-2.1+
Files: debian/* Files: debian/*
Copyright: 2014-2015 Alf Gaida <agaida@siduction.org> Copyright: 2014-2016 Alf Gaida <agaida@siduction.org>
2015 Andrew Lee (李健秋) <ajqlee@debian.org> 2015 Andrew Lee (李健秋) <ajqlee@debian.org>
License: LGPL-2.1+ License: LGPL-2.1+

1
debian/docs vendored

@ -1 +1,2 @@
AUTHORS AUTHORS
README.md

@ -1,6 +1,7 @@
# there will be no manual for a foreseable time # there will be no manual for a foreseable time
lxqt-admin: binary-without-manpage usr/bin/lxqt-admin-time lxqt-admin: binary-without-manpage usr/bin/lxqt-admin-time
lxqt-admin: binary-without-manpage usr/bin/lxqt-admin-user lxqt-admin: binary-without-manpage usr/bin/lxqt-admin-user
lxqt-admin: binary-without-manpage usr/bin/lxqt-admin-user-helper
# the category is right, but not in freedesktop right now # the category is right, but not in freedesktop right now
lxqt-admin: desktop-entry-invalid-category LXQt usr/share/applications/lxqt-admin-time.desktop lxqt-admin: desktop-entry-invalid-category LXQt usr/share/applications/lxqt-admin-time.desktop

12
debian/rules vendored

@ -1,9 +1,15 @@
#!/usr/bin/make -f #!/usr/bin/make -f
#export DH_VERBOSE=1 # export DH_VERBOSE=1
export LC_ALL=C.UTF-8
export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%: %:
dh ${@} --buildsystem cmake \ dh ${@} --buildsystem cmake
--parallel
override_dh_auto_configure:
dh_auto_configure -- \
-DPULL_TRANSLATIONS=OFF\
-DUPDATE_TRANSLATIONS=OFF\
-DCMAKE_BUILD_TYPE=RelWithDebInfo

@ -1,63 +1,50 @@
-----BEGIN PGP PUBLIC KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)
mQINBFJevCYBEACx+Hvy+Vsuf+V5jeLUnzjAmHoy8DfTeGWr3ts30IapLHrfi0+U mQINBFXQeMMBEACif4+9pTrC6uNmRng0ZbzLh7p3cazmbnp2YFgDQDJZ7ZNmebxy
WpzNnISO77yTr4VNboVZH+GHM/rnPfieODfB4ZW6CZLlInMSKUXcgQsEqXpyBZhA ngRuRhjGuDcFAL/37BwJnrBpfZFK9ljoH4Fo5Jm9cOELaTy7AIcEiV9dKMyrKF1E
Ib/SPy2bOfHly1uRJes0uRDsH5+v/hD74sByfnjQlrvI68O6wvGZmDFMNNPVO8+/ C76d8jHVuzuPbI92DkFdLZAdk+qjrrAy0x43PvUd+aaBGLcFs1ZMk7gOvElc2d95
OWBSBNkBuVrrZOMSPsLwQGJ4UtUQ4whburaPJG4VZJc5DLbzJGbEuACc0IAEYJS3 zWWSp5anjukmGbp+EsStnWJkF6VHj56qmklfYy5ioiVBOSpXo/RsACAcIlz8C8A1
7AfXVXn4j4Gc9F3o1xTUnbOBnwGPquWwUIm3FM7Ec2OdkvMt3EwvnkMAfeVrq3iE d4tNMiB2uF2OrUfrL8DD6m3nBqep+AYbIQrxMl9kUQH3I33e9kH/L+SHQyE6phS8
FDD/KZTxdL0BZH3QD8gB7Jm4v4f3Nkobg6JCvCbcH3wBdZW4mASbwWzfRaDC2zHb Czq06WjV4TcJ9VWxm7hQCNLYSxhZYYr1AW45lS5+xmfBOq2qeLgvjbFxa8PPrsp6
ErTglD7PpShLKZZ0pr9okWZEGw4Ku3q8ALi1JXK/ePTmsBlvkVskOJ3Nnd0avgH4 Bqgt8MjwUkXjU5IB7YulUBvFU2l0MJZWDBuNy0oNtCe1cU3JyIqLKjvzQQQ9eD5L
+Q/vZoKfH8EhNY745rI+8CE9iv6V9XiSUt4CKEWAENt4A8hq6U2vV+jZv3B6AgD7 o3Ul704TLHz0z+67Rxh05Mi4JvyFMjnooSJkNH8/7yXoBN0ZGOh1/5zMU1gK5bmP
ZjiI59yD4YuYubu8rCnNizTgh1voVw3ietknn/x2H5yH8fByWZ5uL87C0ky/uma6 6hKgis2exSZNIS74mF6/PqGgcwk3PyI4T3keUQoNPj11M2EznLHxY19QZfQ5oMed
ZGbiiAtM4kdkyDMrfRV5nlEG9EKAGPVu5mjeSCrfkETwZ9OFPz1AuDye4ZEXrrcC 8xOlHKjpcm8PYMB4gduNXlV7gI9h7UxuC5GuPiP2lmM6wUyHu48divxDk5UYgPEC
iRQ7RX6/GtW18aHER0kzGnfwx5KJzkDrRBY8A2PdXLBcrsN4WpK9EX01PQARAQAB xlPI2wHCNDsuy0EruCYIvrMSZfpYCCSrmXiOORBLO5qXkauILLkJarHqjQARAQAB
tCNKZXJvbWUgTGVjbGFuY2hlIDxqZXJvbWVAbGVjbGFuLmNoPokCPwQTAQIAKQUC tCBBbGYgR2FpZGEgPGFnYWlkYUBzaWR1Y3Rpb24ub3JnPokCOAQTAQIAIgUCVdB4
Ul68JgIbAwUJAeEzgAcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEDfgrx/a wwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQQsnI069epeOT2xAAgSHf
SPNzSHIP/1ewXcC0TFBcvDD7MrIP7anyNfiWfW7cxkR8GSamkg6HTa6Ndyr1FFjJ 41103cnElGf6TokPl4J6hdRPy2CUAjmBtMfr8eajYvGDGgnmsh9AGYGURjfFVCCf
OoDFUP37jWhu59CsHxs2D0zRWJktezfvElscRgqbHcdpIznqsGdI8hXCZafhBGVb Ag+8b6nF3xg03UmgsuSO8H78HGv9kKzF9aHmLt+SXq3jUX+LnIkFHErZWjFAKdJr
sdAB2LRawcXGxnXt7XajPcSVwLWRE62caBqohznU2iWvI780WNjEbZoA0LhZwaFF luu1j6ltxLe9PQljxZnugzMaUbW8eEPKvcriiDn3S4/DtikW/jpGA0MTY4ZWs9pZ
UUPJm8ea9v0IkZVKUyg9WONZ1U7FEG9SaEiSpI8kJdx1fvCwZVDV/NRO5GqnJaho L/6iRRH99L2X/cWO4sCgDXCTt4oK0f5OvwiuCoVOM+PYoIm31JICCKOlqamkCn7d
P1LCne4YdwS6pt1/fRgk32IHxxZfHlLzLHxb6v1JmIg72x28qCmGyK9oFBDbbnYu 2KH3nsy0v7tXgnrnb/zr8jVGsZLzUE51AFOzb5Ec74/2SAq8X4gbTppttLXEIooq
6Aq8XbHogOrD5vJM2Pfm2IhV0+JHOjfQbddv8tsAH1M+LI+tToXmg5st1AU3wnTn nbepitW/PePkPY5gpfwHtFbl88qFnir+ABMefqRZkzeh0tsxJVLVHGP1KZykXpv7
pda3hjA1avKwkfBPW/osHc8782ViyS9iX2e9iDtMv608guij4NjpGExzGCypHOd8 96A6Q1h7Zo9Ny7WwN5Xl02g35LVCaPyzd3A8A4315uMuP3iziq57UktKqh9d5S3t
+VXRwJDjvgDynkL206MZ+wn0j5wHsIE8F3Y5Bp1thQOrdDli5MYNQoXhjFmH46XT jfK7e9UfFQZBLfxn2sNPsjdYSNUQp/PXTTk/599h359WVuUIR866T8K7N7EEon3p
bcr84IgW0+AiXZdoFUqvwtzrWy2Onuw5R3k4OyV4skN4DkWXyAk/V+Y4K39JvTKf qLItZljQ9Nmr/yGwKi9iQgi2LtZj5KUcF1zBLzZKf95FvoqSZqBXdFSjm+eYGaCH
H9YuiQ9blNzCu8WiAnjKnh9kNl9E/TyEwI6cHFmIPqF8ST9tJytWHtrKvU9csvXX Q2IBnhyP92lEknSK9ystUJXmY69tQKBFqJxScwaS+7a/rfLKssQjSWxqk+SX4QeW
n8XNJmpcv2R1e6N+VuWWm5zUPTouv3AxCacLbm8Lh3ymGsk7ZEyhiQIcBBABAgAG e9z9FUpo71bq0Zkc/M9aOCoEEmhg4Ob/JWy08oC5Ag0EVdB4wwEQAKZDCc/C41y0
BQJSsFYyAAoJEBMY76xfu9vO6v0P/3wSj3/kE4nP4HfgcVJSzi+lm1ycpbLDZtgh omLFCAJybvHiFScM+jOpyGpQvceoviEhIT7h1br/pnSEMkgPQEDPWJGtKueg1/94
P1G+zJLVmA+E41vEZimeiYQxBAelatJz+CHzQo3LZ2oVChzVrZcVHn9k4P3pib69 sXTH24uefr3Y6JdZoBtprxl4JXUoOndgq1QH1xuUsy3/9YWU8Qboy9j8a8w0oCDE
qCVif3/y0Wmecn+u2TWbOvJ7mthfO7T3W7rkW1/9ES7bUaXcXWQ2sjUBVqFkFsVt T8Z03KHCwqzD3K+44jhmhF+0eLoaaY8ohS8ziP+DcFKVHyatmS5yCCdjVrj6PxMp
xgJDo8wcxA+K4Yf06GCbxFwrB7X5GraWIkzqGnyse3XAQn8aORAXmE8Yd0FHOjEZ uy/y5SXT1kmiPdVAIzQlM5DlN6o46TV+BH0pPvVYjtwf31o0FckJxy5S1v0koCNB
Beb9shChnkYc3lEvNY8ioCaYSF9xr/Iz9cwpfPkpqFiVYWadtb+Gqeh6zC7vPmcT vX2b7tTDPKzn8G18eUVhGoUTZBUCp1gg36wJ0YY4xgZ9vI/xDCeHeAkyvGtaTAoy
zHxrgkq1WwQlSBm724tPt9xuGQoOglqEa23vlQZfv20nyrYjLeYUy6pMCRq7vn/n qP4rHoUO5KVRSDh7frSlrdbLGWHaQwOhcqoKd4qP/164wHPGkgHL1vztdOc7l1wx
nkQOcXF7yQlnqR6xKk0tWsM4e6du0ZvbjBbhHV/kBFVGCLm/upTwoMVm0WJTbr4T q3gMh2uwmJR0NRrw4WVuaIqL9lEbGBNijlmGsuqXfsMRhc/qoqgVDWvrcCtEoOwl
5XfIZo7eA0lvGtUhe1PgcOidBikHfAIfYxu0BoMXoL4jbcQdR5+YBDEfsS0jPhCl TONGobW3jpCCjpa9SeGNjxuY6IVLn0lfX4hItNVY9sFA+H+yj4uBQ7zsmMUXafxt
mew2ScW/R/UhUknJUVFTma0KHXzEmKiqeeUCDtwEi6fxdicAYkbcekgkfFiD/w8N Yllm0f98yGNg5lnJg4bLOYu3IkpogUKNA3qkZ+6vRtwH70/bJGp7qdx/3G4W5dMX
Lk3Uf+0x2MdKA36nUobFkk38oU+GW37kFWJs3f1YRuQFao896eNW/E8ekVMLNxOl asd/rJjdELW+R/NVULAmK1ETSklaa3Z6vbTu8bN8gvP8pmMJ8f/U8+qzkuAqc201
nCjnSbabaxDnxPTyW2KlNjf/QUEK4pT6S5QmuCSrle3PQpaSbAZDHzLBIL9gd3m6 Z4O+s7ZsQfTiz5mm7zPGIYTnppDSno/rABEBAAGJAh8EGAECAAkFAlXQeMMCGwwA
MH7+SvV4uQINBFJevCYBEADiXDUqstSdhIyuionS2KtE3IeEBIqS7GY8QPRBylIZ CgkQQsnI069epeMt0g/+JrwLhULD6NOxaLgxboh/KZkh/7ViU4cB+QPT8JIcWxkZ
ACVHFI/1HxChBqYVGFaDEQn3gj5lUUQPubfWaxzjF6+UNVQW4+cxmTocndAwfDbI zj8uk85TUitEUzKmjp/ItCrhQE5WNNWbz/FBnAuLtaQuHhcHMA3Vu95UUCGi1vyZ
+E5BLdieFUzbAA05MV5ZjPhTNbSk1jpy4bNy0FILwNqc89Y6SoCbv1r3tZLCrBas ZRlS3YRM6S9BOzrjG7fGQJmO/RU3g6rb0TAwGFxDHj8t4JEDTc3zASG7wV/VTn06
1+AfWknBynx0siGMbLFxtzR6hUkNz9URxt13FrzpUWMpAL8ZQGczOTSaWLrZA5l9 d8XIH9CZOw3kUuhkQ3OR/PEj1BCeCC+caC+tBjO0fgvDp8RV7NFQQ9kH8R3/xlWd
xLzJ9ww8uM+C2Xej3/sANxi+kQE2GVMKurPS0TICwVWZxbdW/ytIkO67Rhse0q3t 6KMPtILE6fUft6LubWRGd1P5JBuzXivELolASajewbYtL/s87CCji3ngq0aT9raK
vzjdawfCFRxv7XQB2ZJ6irDxbpHiJoojSWCHJadIyCG03iOiaqsSVvi4KnxtUck+ m02wqFzNbX1iv+w2iqPQXq6pdRyxtJ8+Q8Z7zEBGJS5nkrYjsLTduZIjJHYHYH7f
udOEJUV5sxdzgeRrsDpeaN//KCWW9WjfsSkvOqP6S1gmWpNFdzF5XrzcgvqvSNqo 3/ydVjQ3z12iqHKElgaRI7RUmpNiNxVIr+TtuxzeC6G+CF++XNkUtJODvCmRaoJS
XejfakUTJqsIIEHO0zGuJFVzJNh2hQ/9dhjIspUORhtNKaljNvePiBrj2yqmd9PY waYsitz8+LSv3tawZJ0iQkKc9nerQMuBD+AzIr3i4NgXiEIN513esUtnKzeyIIsL
FlH1KMHe4H+YVIwPiyeNA87Pu+1yNo8gT7mXhGRfibgWjbt146WUJ7+l2StJMApn ntUcBjXKuLCj8OZrZtexjq7edWWbN57/3ikyS2Z7y0i3O30qk5jmccSaS6kA7xTY
eNSCartNaUNPnw96i2l5c9AsJ3SWC6XWpWzOLVj+9XceeA11lu/ogqEMHzx81NjH WCDFzbN2v2y+vGu9KYn+2HtrP2BtNa8JTh3waNeLUTpn4GV4mMrsZjOy6vhhHb91
2TePxwKTKxZnAvDmqryp++IgY2/OgIoIk3ZRdYu/dPijTOYWfCet/9/9kAFr9PeJ 1TKfI1gvjk7lE9xaWmcDjdI55dw3jIq8kK9SdgORGq9/S3g7KJNRjme+6GjqQfk=
KwARAQABiQIlBBgBAgAPBQJSXrwmAhsMBQkB4TOAAAoJEDfgrx/aSPNzJv0QAKkx =h7ww
lCKEZ6ahAUuNWslsHnNWaHFHNawEO3NIEtQZGVFk2BYISupizvjZF6MnymO/9UFM
pzV6fp3xNdqaKWQBjScOgMgCASRixW2tMAKbJGHZKp3dBixpHgXxy2oOGMS+mQ5m
gWy07usq2YesoMD0K/SG6EnoRPHBvrJihArzMFVUY9hD3hk8bhiy8w9bCYFe+gkm
zpQl3/KN01kyt5LjzEBcIOw8qIBQe9Pk8PyOK75lPoNME714LatgOsyw2kaSQ9Sv
hziRGC5z/fV3PmH7XhSjENPKnCJU51GUMMLaL28t9o7Afh6Q8UV31/JO36vmQXQV
+b+0BoGqEmf3AKBASb2Cr2q4pZFjywwSUXHZ9hQyu1tpbE1dS6aI01kM0y270pk7
W/ajuzuOxAVL1bJAanL/5+DWM03esZPVdEWhxpWEM40Z6Rhq+Xb2a5xfwCN9PmaQ
o9fez0I+yh53s7Ypv0tBj05FPe5L48+pDi6pz5nddN1B0FzF58jVfsBZUjBlY24+
VwQeAaWkRXZrSEdtBS5ufsi80x/cNCSTJBWqtborKL1iGgf5MDPYRMSvmZXAeIld
pyL/0pbW7iokewyKzpFfo7KEbwLxB+flWaBZ867JpF4yyRj3b4qcvcyV8QnsoB7Z
KhxTl3gGwD/t0HUcu85zcfs4GkealYhIWfGaAso2
=fF8P
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----

4
debian/watch vendored

@ -1,3 +1,3 @@
version=3 version=4
opts="pgpsigurlmangle=s/$/.asc/" \ opts="pgpsigurlmangle=s/$/.asc/" \
https://github.com/lxde/lxqt-admin/releases .*/([\d\.]+).tar.gz https://github.com/lxde/lxqt-admin/releases .*/lxqt-admin-([\d\.]+).tar.xz

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

@ -3,13 +3,13 @@ project(lxqt-admin-time)
# build static helper class first # build static helper class first
include_directories ( include_directories (
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
${OOBS_INCLUDE_DIRS}
) )
set ( lxqt-admin-time_HDRS set ( lxqt-admin-time_HDRS
timeadmindialog.h timeadmindialog.h
datetime.h datetime.h
timezone.h timezone.h
timedatectl.h
) )
set ( lxqt-admin-time_SRCS set ( lxqt-admin-time_SRCS
@ -17,6 +17,7 @@ set ( lxqt-admin-time_SRCS
timeadmindialog.cpp timeadmindialog.cpp
datetime.cpp datetime.cpp
timezone.cpp timezone.cpp
timedatectl.cpp
) )
set ( lxqt-admin-time_MOCS set ( lxqt-admin-time_MOCS
@ -42,6 +43,16 @@ lxqt_translate_ts(lxqt-admin-time_QM_FILES
${lxqt-admin-time_UIS} ${lxqt-admin-time_UIS}
INSTALL_DIR INSTALL_DIR
"${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}"
PULL_TRANSLATIONS
${PULL_TRANSLATIONS}
CLEAN_TRANSLATIONS
${CLEAN_TRANSLATIONS}
TRANSLATIONS_REPO
${TRANSLATIONS_REPO}
TRANSLATIONS_REFSPEC
${TRANSLATIONS_REFSPEC}
REPO_SUBDIR
"lxqt-admin/${PROJECT_NAME}"
) )
lxqt_translate_desktop(DESKTOP_FILES lxqt_translate_desktop(DESKTOP_FILES
@ -64,8 +75,8 @@ add_executable(lxqt-admin-time
target_link_libraries(lxqt-admin-time target_link_libraries(lxqt-admin-time
KF5::WindowSystem KF5::WindowSystem
Qt5::Widgets Qt5::Widgets
Qt5::DBus
lxqt lxqt
${OOBS_LIBRARIES}
) )
install(TARGETS lxqt-admin-time RUNTIME DESTINATION bin) install(TARGETS lxqt-admin-time RUNTIME DESTINATION bin)

@ -31,15 +31,16 @@
#include <QTimer> #include <QTimer>
#include <QTextCharFormat> #include <QTextCharFormat>
DateTime::DateTime(QWidget *parent) : DateTimePage::DateTimePage(bool useNtp, bool localRtc, QWidget *parent) :
QWidget(parent), QWidget(parent),
ui(new Ui::DateTime) ui(new Ui::DateTime),
mUseNtp(useNtp),
mLocalRtc(localRtc)
{ {
ui->setupUi(this); ui->setupUi(this);
mTimer = new QTimer(this); mTimer = new QTimer(this);
connect(mTimer,SIGNAL(timeout()),SLOT(timeout())); connect(mTimer,SIGNAL(timeout()),SLOT(timeout()));
//highlight today //highlight today
QDate date = QDate::currentDate(); QDate date = QDate::currentDate();
QTextCharFormat format = ui->calendar->dateTextFormat(date); QTextCharFormat format = ui->calendar->dateTextFormat(date);
@ -51,43 +52,56 @@ DateTime::DateTime(QWidget *parent) :
reload(); reload();
} }
DateTime::~DateTime() DateTimePage::~DateTimePage()
{ {
delete ui; delete ui;
} }
void DateTime::timeout() void DateTimePage::timeout()
{ {
ui->edit_time->blockSignals(true); ui->edit_time->blockSignals(true);
ui->edit_time->setTime(QTime::currentTime()); ui->edit_time->setTime(QTime::currentTime());
ui->edit_time->blockSignals(false); ui->edit_time->blockSignals(false);
} }
void DateTime::reload() void DateTimePage::reload()
{ {
ui->calendar->setSelectedDate(QDate::currentDate()); ui->calendar->setSelectedDate(QDate::currentDate());
ui->edit_time->setTime(QTime::currentTime()); ui->edit_time->setTime(QTime::currentTime());
ui->localRTC->setChecked(mLocalRtc);
ui->ntp->setChecked(mUseNtp);
mTimer->start(1000); mTimer->start(1000);
mModified = 0; mModified = 0;
emit changed(mModified); emit changed();
} }
void DateTime::on_edit_time_userTimeChanged(const QTime &time) void DateTimePage::on_edit_time_userTimeChanged(const QTime &time)
{ {
mModified |= M_TIME; mModified |= M_TIME;
mTimer->stop(); mTimer->stop();
emit changed();
emit changed(mModified);
} }
QDateTime DateTime::dateTime() const QDateTime DateTimePage::dateTime() const
{ {
QDateTime dt(ui->calendar->selectedDate(),ui->edit_time->time()); QDateTime dt(ui->calendar->selectedDate(),ui->edit_time->time());
return dt; return dt;
} }
void DateTime::on_calendar_selectionChanged() bool DateTimePage::useNtp() const
{
return ui->ntp->isChecked();
}
bool DateTimePage::localRtc() const
{
return ui->localRTC->isChecked();
}
void DateTimePage::on_calendar_selectionChanged()
{ {
QDate date = ui->calendar->selectedDate(); QDate date = ui->calendar->selectedDate();
if (date != QDate::currentDate()) if (date != QDate::currentDate())
@ -98,6 +112,32 @@ void DateTime::on_calendar_selectionChanged()
{ {
mModified &= ~M_DATE; mModified &= ~M_DATE;
} }
emit changed();
}
void DateTimePage::on_ntp_toggled(bool toggled)
{
if(toggled != mUseNtp)
{
mModified |= M_NTP;
}
else
{
mModified &= ~M_NTP;
}
emit changed();
}
emit changed(mModified); void DateTimePage::on_localRTC_toggled(bool toggled)
{
if(toggled != mLocalRtc)
{
mModified |= M_LOCAL_RTC;
}
else
{
mModified &= ~M_LOCAL_RTC;
}
emit changed();
} }

@ -34,38 +34,46 @@ namespace Ui {
class DateTime; class DateTime;
} }
class DateTime : public QWidget class DateTimePage : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit DateTime(QWidget *parent = 0); explicit DateTimePage(bool useNtp, bool localRtc, QWidget *parent = 0);
~DateTime(); ~DateTimePage();
enum modified_enum {M_DATE = 0x1, M_TIME = 0x2}; enum ModifiedFlag {M_DATE = (1 << 0), M_TIME = (1 << 1), M_NTP = (1 << 2), M_LOCAL_RTC = (1 << 3)};
Q_DECLARE_FLAGS(modified_t, modified_enum) Q_DECLARE_FLAGS(ModifiedFlags,ModifiedFlag)
ModifiedFlags modified() const
{
return mModified;
}
QDateTime dateTime() const; QDateTime dateTime() const;
inline modified_t modified() const {return mModified;} bool useNtp() const;
bool localRtc() const;
public Q_SLOTS: public Q_SLOTS:
void reload(); void reload();
private Q_SLOTS: private Q_SLOTS:
void on_edit_time_userTimeChanged(const QTime &time); void on_edit_time_userTimeChanged(const QTime &time);
void timeout(); void timeout();
void on_calendar_selectionChanged(); void on_calendar_selectionChanged();
void on_ntp_toggled(bool toggled);
void on_localRTC_toggled(bool toggled);
Q_SIGNALS: Q_SIGNALS:
void changed(bool); void changed();
private: private:
Ui::DateTime *ui; Ui::DateTime *ui;
QTimer * mTimer; QTimer * mTimer;
modified_t mModified; bool mUseNtp;
bool mLocalRtc;
ModifiedFlags mModified;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(DateTime::modified_t)
#endif // DATETIME_H #endif // DATETIME_H

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>354</width> <width>365</width>
<height>308</height> <height>323</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@ -16,7 +16,7 @@
<height>50</height> <height>50</height>
</size> </size>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,1,0,0,0">
<item> <item>
<widget class="QLabel" name="label_time"> <widget class="QLabel" name="label_time">
<property name="text"> <property name="text">
@ -64,6 +64,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="ntp">
<property name="text">
<string>Enable network time synchronization (NTP)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="localRTC">
<property name="text">
<string>RTC is in local time</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
@ -77,24 +91,41 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections>
<connection>
<sender>ntp</sender>
<signal>toggled(bool)</signal>
<receiver>calendar</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>221</x>
<y>269</y>
</hint>
<hint type="destinationlabel">
<x>228</x>
<y>162</y>
</hint>
</hints>
</connection>
<connection>
<sender>ntp</sender>
<signal>toggled(bool)</signal>
<receiver>edit_time</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>105</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>173</x>
<y>55</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

@ -31,82 +31,59 @@
#include <QMessageBox> #include <QMessageBox>
#include <QDateTime> #include <QDateTime>
#include <QMap> #include <QMap>
#include <QDebug>
#include "datetime.h" #include "datetime.h"
#include "timezone.h" #include "timezone.h"
#define ZONETAB_PATH "/usr/share/zoneinfo/zone.tab" #define ZONETAB_PATH "/usr/share/zoneinfo/zone.tab"
TimeAdminDialog::TimeAdminDialog(QWidget *parent): TimeAdminDialog::TimeAdminDialog(QWidget *parent):
LXQt::ConfigDialog(tr("Time and date configuration"),new LXQt::Settings("TimeDate"), parent), LXQt::ConfigDialog(tr("Time and date configuration"),new LXQt::Settings("TimeDate"), parent)
mTimeConfig(OOBS_TIME_CONFIG(oobs_time_config_get())),
mUserLogedIn(false)
{ {
oobs_object_update(OOBS_OBJECT(mTimeConfig));
setMinimumSize(QSize(400,400)); setMinimumSize(QSize(400,400));
mWindowTitle = windowTitle(); mWindowTitle = windowTitle();
mDateTimeWidget = new DateTimePage(mTimeDateCtl.useNtp(), mTimeDateCtl.localRtc(), this);
mDateTimeWidget = new DateTime(this);
addPage(mDateTimeWidget,tr("Date and time")); addPage(mDateTimeWidget,tr("Date and time"));
connect(this,SIGNAL(reset()),mDateTimeWidget,SLOT(reload())); connect(this,SIGNAL(reset()),mDateTimeWidget,SLOT(reload()));
connect(mDateTimeWidget,&DateTime::changed,this,&TimeAdminDialog::onChanged); connect(mDateTimeWidget,&DateTimePage::changed,this,&TimeAdminDialog::onChanged);
mDateTimeWidget->setProperty("pModified",M_TIMEDATE);
QStringList zones; QStringList zones;
QString currentZone; QString currentZone;
loadTimeZones(zones,currentZone); loadTimeZones(zones,currentZone);
mTimezoneWidget = new Timezone(zones,currentZone,this); mTimezoneWidget = new TimezonePage(zones,currentZone,this);
addPage(mTimezoneWidget,tr("Timezone")); addPage(mTimezoneWidget,tr("Timezone"));
connect(this,&TimeAdminDialog::reset,mTimezoneWidget,&Timezone::reload); connect(this,&TimeAdminDialog::reset,mTimezoneWidget,&TimezonePage::reload);
connect(mTimezoneWidget,&Timezone::changed,this,&TimeAdminDialog::onChanged); connect(mTimezoneWidget,&TimezonePage::changed,this,&TimeAdminDialog::onChanged);
mTimezoneWidget->setProperty("pModified",M_TIMEZONE);
setButtons(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
connect(this, &LXQt::ConfigDialog::clicked, this, &TimeAdminDialog::onButtonClicked);
adjustSize();
} }
TimeAdminDialog::~TimeAdminDialog() TimeAdminDialog::~TimeAdminDialog()
{ {
if(mTimeConfig)
g_object_unref(mTimeConfig);
} }
void TimeAdminDialog::onChanged(bool ch) void TimeAdminDialog::onChanged()
{ {
widgets_modified_enum flag = (widgets_modified_enum)
sender()->property("pModified").toUInt();
ch ? mWidgetsModified |= flag : mWidgetsModified &= ~flag;
showChangedStar(); showChangedStar();
} }
void TimeAdminDialog::showChangedStar() void TimeAdminDialog::showChangedStar()
{ {
if (mWidgetsModified) if(mTimezoneWidget->isChanged() || mDateTimeWidget->modified())
setWindowTitle(mWindowTitle + "*"); setWindowTitle(mWindowTitle + "*");
else else
setWindowTitle(mWindowTitle); setWindowTitle(mWindowTitle);
} }
void TimeAdminDialog::closeEvent(QCloseEvent *event)
{
//save changes to system
if (mWidgetsModified)
{
if (logInUser())
{
saveChangesToSystem();
event->accept();
}
else
{
event->ignore();
}
}
}
void TimeAdminDialog::loadTimeZones(QStringList & timeZones, QString & currentTimezone) void TimeAdminDialog::loadTimeZones(QStringList & timeZones, QString & currentTimezone)
{ {
currentTimezone = mTimeDateCtl.timeZone();
timeZones.clear(); timeZones.clear();
QFile file(ZONETAB_PATH); QFile file(ZONETAB_PATH);
if(file.open(QIODevice::ReadOnly)) if(file.open(QIODevice::ReadOnly))
@ -124,44 +101,61 @@ void TimeAdminDialog::loadTimeZones(QStringList & timeZones, QString & currentTi
} }
file.close(); file.close();
} }
currentTimezone = QString::fromLatin1(oobs_time_config_get_timezone(mTimeConfig));
} }
void TimeAdminDialog::saveChangesToSystem() void TimeAdminDialog::saveChangesToSystem()
{ {
QByteArray timeZone = mTimezoneWidget->timezone().toLatin1(); QString errorMessage;
// FIXME: currently timezone settings does not work. is this a bug of system-tools-backend? if(mTimezoneWidget->isChanged())
if(!timeZone.isEmpty() && mWidgetsModified.testFlag(M_TIMEZONE)) {
oobs_time_config_set_timezone(mTimeConfig, timeZone.constData()); QString timeZone = mTimezoneWidget->timezone();
if(!timeZone.isEmpty())
{
if(false == mTimeDateCtl.setTimeZone(timeZone, errorMessage)) {
QMessageBox::critical(this, tr("Error"), errorMessage);
}
}
}
if(mWidgetsModified.testFlag(M_TIMEDATE)) auto modified = mDateTimeWidget->modified();
bool useNtp = mDateTimeWidget->useNtp();
if(modified.testFlag(DateTimePage::M_NTP))
{ {
QDate d = mDateTimeWidget->dateTime().date(); if(false == mTimeDateCtl.setUseNtp(useNtp, errorMessage)) {
QTime t = mDateTimeWidget->dateTime().time(); QMessageBox::critical(this, tr("Error"), errorMessage);
// oobs seems to use 0 based month }
oobs_time_config_set_time(mTimeConfig, d.year(), d.month() - 1, d.day(), t.hour(), t.minute(), t.second()); }
if(modified.testFlag(DateTimePage::M_LOCAL_RTC))
{
if(false == mTimeDateCtl.setLocalRtc(mDateTimeWidget->localRtc(), errorMessage)) {
QMessageBox::critical(this, tr("Error"), errorMessage);
}
}
// we can only change the date & time explicitly when NTP is disabled.
if(false == useNtp)
{
if(modified.testFlag(DateTimePage::M_DATE) || modified.testFlag(DateTimePage::M_TIME))
{
if(false == mTimeDateCtl.setDateTime(mDateTimeWidget->dateTime(), errorMessage)) {
QMessageBox::critical(this, tr("Error"), errorMessage);
}
}
} }
oobs_object_commit(OOBS_OBJECT(mTimeConfig));
} }
bool TimeAdminDialog::logInUser() void TimeAdminDialog::onButtonClicked(QDialogButtonBox::StandardButton button)
{ {
if (mUserLogedIn) if(button == QDialogButtonBox::Ok)
return true;
GError* err = NULL;
if(oobs_object_authenticate(OOBS_OBJECT(mTimeConfig), &err))
{ {
mUserLogedIn = true; saveChangesToSystem();
return true; accept();
} }
else if(err) else if(button == QDialogButtonBox::Cancel)
{ {
QMessageBox::critical(this, tr("Authentication Error"), QString::fromUtf8(err->message)); reject();
g_error_free(err);
} }
return false;
} }

@ -26,13 +26,10 @@
* END_COMMON_COPYRIGHT_HEADER */ * END_COMMON_COPYRIGHT_HEADER */
#include <LXQt/ConfigDialog> #include <LXQt/ConfigDialog>
#include <glib.h> #include "timedatectl.h"
#include <oobs/oobs-timeconfig.h>
#include <oobs/oobs-ntpconfig.h>
#include <oobs/oobs-ntpserver.h>
class DateTime; class DateTimePage;
class Timezone; class TimezonePage;
class TimeAdminDialog: public LXQt::ConfigDialog class TimeAdminDialog: public LXQt::ConfigDialog
{ {
@ -42,30 +39,18 @@ public:
TimeAdminDialog(QWidget * parent = NULL) ; TimeAdminDialog(QWidget * parent = NULL) ;
~TimeAdminDialog(); ~TimeAdminDialog();
typedef enum {M_TIMEDATE = 1 , M_TIMEZONE = 0x2} widgets_modified_enum;
Q_DECLARE_FLAGS(widgets_modified_t, widgets_modified_enum)
protected:
virtual void closeEvent(QCloseEvent * event);
private Q_SLOTS: private Q_SLOTS:
void onChanged(bool); void onChanged();
void onButtonClicked(QDialogButtonBox::StandardButton button);
private: private:
bool logInUser();
void saveChangesToSystem(); void saveChangesToSystem();
void loadTimeZones(QStringList & timeZones, QString & currentTimezone); void loadTimeZones(QStringList & timeZones, QString & currentTimezone);
void showChangedStar(); void showChangedStar();
private: private:
OobsTimeConfig* mTimeConfig; TimeDateCtl mTimeDateCtl;
DateTime * mDateTimeWidget; DateTimePage * mDateTimeWidget;
Timezone * mTimezoneWidget; TimezonePage * mTimezoneWidget;
bool mUserLogedIn;
QString mWindowTitle; QString mWindowTitle;
widgets_modified_t mWidgetsModified;
}; };
Q_DECLARE_METATYPE(TimeAdminDialog::widgets_modified_enum)
Q_DECLARE_OPERATORS_FOR_FLAGS(TimeAdminDialog::widgets_modified_t)

@ -0,0 +1,112 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2016 LXQt team
* Authors:
* Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "timedatectl.h"
#include <QProcess>
#include <QDebug>
#include <QDBusInterface>
#include <QDBusConnection>
#include <QMessageBox>
TimeDateCtl::TimeDateCtl()
{
mIface = new QDBusInterface(QStringLiteral("org.freedesktop.timedate1"),
QStringLiteral("/org/freedesktop/timedate1"),
QStringLiteral("org.freedesktop.timedate1"),
QDBusConnection::systemBus());
}
TimeDateCtl::~TimeDateCtl()
{
delete mIface;
}
QString TimeDateCtl::timeZone() const
{
return mIface->property("Timezone").toString();
}
bool TimeDateCtl::setTimeZone(QString timeZone, QString& errorMessage)
{
mIface->call("SetTimezone", timeZone, true);
QDBusError err = mIface->lastError();
if(err.isValid())
{
errorMessage = err.message();
return false;
}
return true;
}
bool TimeDateCtl::setDateTime(QDateTime dateTime, QString& errorMessage)
{
// the timedatectl dbus service accepts "usec" input.
// Qt can only get "msec" => convert to usec here.
mIface->call("SetTime", dateTime.toMSecsSinceEpoch() * 1000, false, true);
QDBusError err = mIface->lastError();
if(err.isValid())
{
errorMessage = err.message();
return false;
}
return true;
}
bool TimeDateCtl::useNtp() const
{
return mIface->property("NTP").toBool();
}
bool TimeDateCtl::setUseNtp(bool value, QString& errorMessage)
{
mIface->call("SetNTP", value, true);
QDBusError err = mIface->lastError();
if(err.isValid())
{
errorMessage = err.message();
return false;
}
return true;
}
bool TimeDateCtl::localRtc() const
{
return mIface->property("LocalRTC").toBool();
}
bool TimeDateCtl::setLocalRtc(bool value, QString& errorMessage)
{
mIface->call("SetLocalRTC", value, false, true);
QDBusError err = mIface->lastError();
if(err.isValid())
{
errorMessage = err.message();
return false;
}
return true;
}

@ -0,0 +1,57 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2016 LXQt team
* Authors:
* Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef TIMEDATECTL_H
#define TIMEDATECTL_H
#include <QString>
#include <QDateTime>
class QDBusInterface;
class TimeDateCtl
{
public:
explicit TimeDateCtl();
~TimeDateCtl();
bool useNtp() const;
bool setUseNtp(bool value, QString& errorMessage);
bool localRtc() const;
bool setLocalRtc(bool value, QString& errorMessage);
QString timeZone() const;
bool setTimeZone(QString timeZone, QString& errorMessage);
bool setDateTime(QDateTime dateTime, QString& errorMessage);
private:
QDBusInterface* mIface;
};
#endif // TIMEDATECTL_H

@ -28,7 +28,7 @@
#include "timezone.h" #include "timezone.h"
#include "ui_timezone.h" #include "ui_timezone.h"
Timezone::Timezone(const QStringList & zones, const QString & currentimezone, QWidget *parent) : TimezonePage::TimezonePage(const QStringList & zones, const QString & currentimezone, QWidget *parent) :
QWidget(parent), QWidget(parent),
ui(new Ui::Timezone), ui(new Ui::Timezone),
mZoneChanged(false), mZoneChanged(false),
@ -47,12 +47,12 @@ Timezone::Timezone(const QStringList & zones, const QString & currentimezone, QW
reload(); reload();
} }
Timezone::~Timezone() TimezonePage::~TimezonePage()
{ {
delete ui; delete ui;
} }
void Timezone::reload() void TimezonePage::reload()
{ {
ui->list_zones->setCurrentRow(-1); ui->list_zones->setCurrentRow(-1);
mZoneChanged = false; mZoneChanged = false;
@ -60,10 +60,10 @@ void Timezone::reload()
if (list.count()) if (list.count())
ui->list_zones->setCurrentItem(list.at(0)); ui->list_zones->setCurrentItem(list.at(0));
emit changed(mZoneChanged); emit changed();
} }
QString Timezone::timezone() const QString TimezonePage::timezone() const
{ {
if (ui->list_zones->currentItem()) if (ui->list_zones->currentItem())
return ui->list_zones->currentItem()->text(); return ui->list_zones->currentItem()->text();
@ -71,16 +71,17 @@ QString Timezone::timezone() const
return QString(); return QString();
} }
void Timezone::on_list_zones_itemActivated(QListWidgetItem * item) void TimezonePage::on_list_zones_itemSelectionChanged()
{ {
bool old = mZoneChanged; QList<QListWidgetItem*> selected = ui->list_zones->selectedItems();
if(selected.empty())
return;
QListWidgetItem *item = selected.first();
mZoneChanged = item->text() != ui->label_timezone->text(); mZoneChanged = item->text() != ui->label_timezone->text();
emit changed();
if (mZoneChanged != old)
emit changed(mZoneChanged);
} }
void Timezone::on_edit_filter_textChanged(const QString &arg1) void TimezonePage::on_edit_filter_textChanged(const QString &arg1)
{ {
QRegExp reg(arg1, Qt::CaseInsensitive,QRegExp::Wildcard); QRegExp reg(arg1, Qt::CaseInsensitive,QRegExp::Wildcard);
ui->list_zones->clear(); ui->list_zones->clear();

@ -35,13 +35,13 @@ class Timezone;
} }
class QListWidgetItem; class QListWidgetItem;
class Timezone : public QWidget class TimezonePage : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Timezone(const QStringList & zones, const QString & currentimezone, QWidget *parent = 0); explicit TimezonePage(const QStringList & zones, const QString & currentimezone, QWidget *parent = 0);
~Timezone(); ~TimezonePage();
QString timezone() const; QString timezone() const;
inline bool isChanged() const {return mZoneChanged;} inline bool isChanged() const {return mZoneChanged;}
@ -49,10 +49,10 @@ public slots:
void reload(); void reload();
Q_SIGNALS: Q_SIGNALS:
void changed(bool); void changed();
private slots: private slots:
void on_list_zones_itemActivated(QListWidgetItem *item); void on_list_zones_itemSelectionChanged();
void on_edit_filter_textChanged(const QString &arg1); void on_edit_filter_textChanged(const QString &arg1);
private: private:

@ -42,22 +42,6 @@
<item> <item>
<widget class="QListWidget" name="list_zones"/> <widget class="QListWidget" name="list_zones"/>
</item> </item>
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="23"/>
<source>Time:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>HH:mm:ss</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../datetime.ui" line="53"/>
<source>Date:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../datetime.ui" line="89"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="19"/>
<source>Your current timezone:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>TextLabel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Filter</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.ui" line="54"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

@ -0,0 +1,4 @@
#TRANSLATIONS
Name[ar]=التّاريخ والوقت
GenericName[ar]=إعدادات التّاريخ والوقت
Comment[ar]=اضبط تاريخ النّظام ووقته

@ -0,0 +1,3 @@
Name[ca]=Data i hora
GenericName[ca]=Ajusts de la data i l'hora
Comment[ca]=Configureu la data i l'hora del vostre sistema

@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="23"/>
<source>Time:</source>
<translation>Zeit:</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>HH:mm:ss</source>
<translatorcomment>No need to translate.</translatorcomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../datetime.ui" line="53"/>
<source>Date:</source>
<translation>Datum:</translation>
</message>
<message>
<location filename="../datetime.ui" line="89"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Das Sichern der Einstellungen benötigt Administrator-Rechte.&lt;br&gt;Nach dem Betätigen der Schließen-Schaltfläche wird die Berechtigung eingeholt.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation>Zeit und Datum einstellen</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation>Datum und Zeit</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation>Zeitzone</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation>Authentifizierungsfehler</translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="19"/>
<source>Your current timezone:</source>
<translation>Derzeitige Zeitzone:</translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>TextLabel</source>
<translation>Textfeld</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Filter</source>
<translation>Filter</translation>
</message>
<message>
<location filename="../timezone.ui" line="54"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Das Sichern der Einstellungen benötigt Administrator-Rechte.&lt;br&gt;Nach dem Betätigen der Schließen-Schaltfläche wird die Berechtigung eingeholt.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation>Keine</translation>
</message>
</context>
</TS>

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="el">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="23"/>
<source>Time:</source>
<translation>Ώρα:</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>HH:mm:ss</source>
<translation>HH:mm:ss</translation>
</message>
<message>
<location filename="../datetime.ui" line="53"/>
<source>Date:</source>
<translation>Ημερομηνία:</translation>
</message>
<message>
<location filename="../datetime.ui" line="89"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Η αποθήκευση των αλλαγών απαιτεί δικαιώματα διαχειριστή.&lt;br&gt;Θα ερωτηθείτε αφού κάνετε κλικ στο κουμπί του κλεισίματος&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation>Διαμόρφωση της ώρας και της ημερομηνίας</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation>Ημερομηνία και ώρα</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation>Ωρολογιακή ζώνη</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation>Σφάλμα πιστοποίησης</translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="19"/>
<source>Your current timezone:</source>
<translation>Η τρέχουσα ζώνη ώρας:</translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>TextLabel</source>
<translation>Ετικέτα κειμένου</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Filter</source>
<translation>Φίλτρο</translation>
</message>
<message>
<location filename="../timezone.ui" line="54"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Η αποθήκευση των αλλαγών απαιτεί δικαιώματα διαχειριστή.&lt;br&gt;Θα ερωτηθείτε αφού κάνετε κλικ στο κουμπί του κλεισίματος&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation>Καμία</translation>
</message>
</context>
</TS>

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="hr_HR">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="20"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../datetime.ui" line="32"/>
<source>Time and date setup</source>
<translation type="unfinished">Postavke datuma i vremena</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>Time:</source>
<translation type="unfinished">Vrijeme:</translation>
</message>
<message>
<location filename="../datetime.ui" line="55"/>
<source>HH:mm:ss</source>
<translation type="unfinished">HH:mm:ss</translation>
</message>
<message>
<location filename="../datetime.ui" line="69"/>
<source>Date:</source>
<translation type="unfinished">Nadnevak</translation>
</message>
<message>
<location filename="../datetime.ui" line="105"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Spremanje pronjena zahtjeva adminstracijske dozvole.&lt;br&gt;Biti će zatražene nakon što kliknete na dugme zatvori&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation type="unfinished">Konfiguracija vremena i nadnevka</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation type="unfinished">Nadnevak i vrijeme</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation type="unfinished">Vremenska zona</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>Timezone setup</source>
<translation type="unfinished">Postavljanje vremenske zone</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Your current timezone:</source>
<translation type="unfinished">Vaša trenutna vremenska zona</translation>
</message>
<message>
<location filename="../timezone.ui" line="42"/>
<source>TextLabel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.ui" line="51"/>
<source>Filter</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.ui" line="70"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Spremanje pronjena zahtjeva adminstracijske dozvole.&lt;br&gt;Biti će zatražene nakon što kliknete na dugme zatvori&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation type="unfinished">Nijedan</translation>
</message>
</context>
</TS>

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="hu_HU">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="20"/>
<source>Form</source>
<translation>Űrlap</translation>
</message>
<message>
<location filename="../datetime.ui" line="32"/>
<source>Time and date setup</source>
<translation>Dátum és időbeállítás</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>Time:</source>
<translation>Idő:</translation>
</message>
<message>
<location filename="../datetime.ui" line="55"/>
<source>HH:mm:ss</source>
<translation></translation>
</message>
<message>
<location filename="../datetime.ui" line="69"/>
<source>Date:</source>
<translation>Dátum:</translation>
</message>
<message>
<location filename="../datetime.ui" line="105"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Változtatások csak rendszergazdaként menthetők,&lt;br&gt;jelszóbekérés a kilépés után.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation>Dátum és időbeállítások</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation>Dátum és idő</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation>Időzóna</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation>Hitelesítési hiba</translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="14"/>
<source>Form</source>
<translation>Űrlap</translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>Timezone setup</source>
<translation>Időzóna beállítás</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Your current timezone:</source>
<translation>Mostani időzóna:</translation>
</message>
<message>
<location filename="../timezone.ui" line="42"/>
<source>TextLabel</source>
<translation>Szövegcím</translation>
</message>
<message>
<location filename="../timezone.ui" line="51"/>
<source>Filter</source>
<translation>Szűrő</translation>
</message>
<message>
<location filename="../timezone.ui" line="70"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Változtatások csak rendszergazdaként menthetők,&lt;br&gt;jelszóbekérés a kilépés után.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation>Nincs</translation>
</message>
</context>
</TS>

@ -1,100 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="it_IT" sourcelanguage="it_IT">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="20"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../datetime.ui" line="32"/>
<source>Time and date setup</source>
<translation>Imposta data e ora</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>Time:</source>
<translation>Ora:</translation>
</message>
<message>
<location filename="../datetime.ui" line="55"/>
<source>HH:mm:ss</source>
<translation></translation>
</message>
<message>
<location filename="../datetime.ui" line="69"/>
<source>Date:</source>
<translation>Data:</translation>
</message>
<message>
<location filename="../datetime.ui" line="105"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>Il salvataggio richiede privilegi di amministratore,
saranno chiesti dopo la chiusura di questa finestra.</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation>Configura data e ora</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation>Data e ora</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation>Fuso orario</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation>Errore di autenticazione</translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="14"/>
<source>Form</source>
<translation></translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>Timezone setup</source>
<translation>Configura fuso orario</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Your current timezone:</source>
<translation>Fuso orario attuale:</translation>
</message>
<message>
<location filename="../timezone.ui" line="42"/>
<source>TextLabel</source>
<translation>nessuno</translation>
</message>
<message>
<location filename="../timezone.ui" line="51"/>
<source>Filter</source>
<translation>Filtro</translation>
</message>
<message>
<location filename="../timezone.ui" line="70"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">Il salvataggio richiede privilegi di amministratore,
saranno chiesti dopo la chiusura di questa finestra.</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation></translation>
</message>
</context>
</TS>

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ja">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="20"/>
<source>Form</source>
<translation></translation>
</message>
<message>
<location filename="../datetime.ui" line="32"/>
<source>Time and date setup</source>
<translation></translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>Time:</source>
<translation>:</translation>
</message>
<message>
<location filename="../datetime.ui" line="55"/>
<source>HH:mm:ss</source>
<translation>HH:mm:ss</translation>
</message>
<message>
<location filename="../datetime.ui" line="69"/>
<source>Date:</source>
<translation></translation>
</message>
<message>
<location filename="../datetime.ui" line="105"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation></translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation></translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation></translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation></translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="14"/>
<source>Form</source>
<translation></translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>Timezone setup</source>
<translation></translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Your current timezone:</source>
<translation></translation>
</message>
<message>
<location filename="../timezone.ui" line="42"/>
<source>TextLabel</source>
<translation></translation>
</message>
<message>
<location filename="../timezone.ui" line="51"/>
<source>Filter</source>
<translation></translation>
</message>
<message>
<location filename="../timezone.ui" line="70"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation></translation>
</message>
</context>
</TS>

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="pl_PL">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="20"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../datetime.ui" line="32"/>
<source>Time and date setup</source>
<translation>Konfiguracja daty i czasu</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>Time:</source>
<translation>Czas:</translation>
</message>
<message>
<location filename="../datetime.ui" line="55"/>
<source>HH:mm:ss</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../datetime.ui" line="69"/>
<source>Date:</source>
<translation>Data:</translation>
</message>
<message>
<location filename="../datetime.ui" line="105"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Zapisywanie zmian wymaga uprawnień administratora.&lt;br&gt;Zostaniesz poproszony o hasło.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation>Konfiguracja daty i czasu</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation>Data i czas</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation>Strefa czasowa</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation>Błąd autoryzacji</translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>Timezone setup</source>
<translation>Ustawienia strefy czasowej</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Your current timezone:</source>
<translation>Twoja aktualna strefa czasowa:</translation>
</message>
<message>
<location filename="../timezone.ui" line="42"/>
<source>TextLabel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../timezone.ui" line="51"/>
<source>Filter</source>
<translation>Filtr</translation>
</message>
<message>
<location filename="../timezone.ui" line="70"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Zapisywanie zmian wymaga uprawnień administratora.&lt;br&gt;Zostaniesz poproszony o hasło.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation>Żadna</translation>
</message>
</context>
</TS>

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="pt">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="20"/>
<source>Form</source>
<translation>Formulário</translation>
</message>
<message>
<location filename="../datetime.ui" line="32"/>
<source>Time and date setup</source>
<translation>Configuração de data e hora</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>Time:</source>
<translation>Hora:</translation>
</message>
<message>
<location filename="../datetime.ui" line="55"/>
<source>HH:mm:ss</source>
<translation>H:mm:ss</translation>
</message>
<message>
<location filename="../datetime.ui" line="69"/>
<source>Date:</source>
<translation>Data:</translation>
</message>
<message>
<location filename="../datetime.ui" line="105"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A gravação de alterações requer permissões de administrador.&lt;br&gt;A senha será solicitada ao clicar em Fechar.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation>Configuração de data e hora</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation>Data e hora</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation>Fuso horário</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation>Erro de autenticação</translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="14"/>
<source>Form</source>
<translation>Formulário</translation>
</message>
<message>
<location filename="../timezone.ui" line="26"/>
<source>Timezone setup</source>
<translation>Configuração de fuso horário</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Your current timezone:</source>
<translation>O seu fuso horário:</translation>
</message>
<message>
<location filename="../timezone.ui" line="42"/>
<source>TextLabel</source>
<translation>Texto</translation>
</message>
<message>
<location filename="../timezone.ui" line="51"/>
<source>Filter</source>
<translation>Filtrar</translation>
</message>
<message>
<location filename="../timezone.ui" line="70"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A gravação de alterações requer permissões de administrador.&lt;br&gt;A senha será solicitada ao clicar em Fechar.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation>Nenhum</translation>
</message>
</context>
</TS>

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="32"/>
<source>Time and date setup</source>
<translation>Настройка даты и времени</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>Time:</source>
<translation>Время:</translation>
</message>
<message>
<location filename="../datetime.ui" line="55"/>
<source>HH:mm:ss</source>
<translation>ЧЧ:мм:сс</translation>
</message>
<message>
<location filename="../datetime.ui" line="69"/>
<source>Date:</source>
<translation>Дата:</translation>
</message>
<message>
<location filename="../datetime.ui" line="105"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Для сохранения изменений необходимы права администратора.&lt;br&gt;Пароль будет запрошен после нажатия на кнопку «Закрыть»&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation>Настройки даты и времени</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation>Дата и время</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation>Часовой пояс</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation>Ошибка аутентификации</translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="26"/>
<source>Timezone setup</source>
<translation>Настройки часового пояса</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Your current timezone:</source>
<translation>Ваш текущий часовой пояс:</translation>
</message>
<message>
<location filename="../timezone.ui" line="51"/>
<source>Filter</source>
<translation>Фильтр</translation>
</message>
<message>
<location filename="../timezone.ui" line="70"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Для сохранения изменений необходимы права администратора.&lt;br&gt;Пароль будет запрошен после нажатия на кнопку «Закрыть»&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation>Нет</translation>
</message>
</context>
</TS>

@ -1,6 +0,0 @@
[Desktop Entry]
Name[ru_RU]=Дата и время
GenericName[ru_RU]=Настройки даты и времени
Comment[ru_RU]=Настроить дату и время вашей системы
#TRANSLATIONS_DIR=translations

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
<name>DateTime</name>
<message>
<location filename="../datetime.ui" line="32"/>
<source>Time and date setup</source>
<translation>Настройка даты и времени</translation>
</message>
<message>
<location filename="../datetime.ui" line="39"/>
<source>Time:</source>
<translation>Время:</translation>
</message>
<message>
<location filename="../datetime.ui" line="55"/>
<source>HH:mm:ss</source>
<translation>ЧЧ:мм:сс</translation>
</message>
<message>
<location filename="../datetime.ui" line="69"/>
<source>Date:</source>
<translation>Дата:</translation>
</message>
<message>
<location filename="../datetime.ui" line="105"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Для сохранения изменений необходимы права администратора.&lt;br&gt;Пароль будет запрошен после нажатия на кнопку «Закрыть»&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
</context>
<context>
<name>TimeAdminDialog</name>
<message>
<location filename="../timeadmindialog.cpp" line="42"/>
<source>Time and date configuration</source>
<translation>Настройки даты и времени</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="53"/>
<source>Date and time</source>
<translation>Дата и время</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="62"/>
<source>Timezone</source>
<translation>Часовой пояс</translation>
</message>
<message>
<location filename="../timeadmindialog.cpp" line="162"/>
<source>Authentication Error</source>
<translation>Ошибка аутентификации</translation>
</message>
</context>
<context>
<name>Timezone</name>
<message>
<location filename="../timezone.ui" line="26"/>
<source>Timezone setup</source>
<translation>Настройки часового пояса</translation>
</message>
<message>
<location filename="../timezone.ui" line="35"/>
<source>Your current timezone:</source>
<translation>Ваш текущий часовой пояс:</translation>
</message>
<message>
<location filename="../timezone.ui" line="51"/>
<source>Filter</source>
<translation>Фильтр</translation>
</message>
<message>
<location filename="../timezone.ui" line="70"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saving changes requires admin permissions.&lt;br&gt;You will be requested after clicking close button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Для сохранения изменений необходимы права администратора.&lt;br&gt;Пароль будет запрошен после нажатия на кнопку «Закрыть»&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../timezone.cpp" line="42"/>
<source>None</source>
<translation>Нет</translation>
</message>
</context>
</TS>

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

@ -3,7 +3,6 @@ project(lxqt-admin-user)
# build static helper class first # build static helper class first
include_directories ( include_directories (
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
${OOBS_INCLUDE_DIRS}
) )
set ( lxqt-admin-user_SRCS set ( lxqt-admin-user_SRCS
@ -11,12 +10,14 @@ set ( lxqt-admin-user_SRCS
mainwindow.cpp mainwindow.cpp
userdialog.cpp userdialog.cpp
groupdialog.cpp groupdialog.cpp
usermanager.cpp
) )
set ( lxqt-admin-user_MOCS set ( lxqt-admin-user_MOCS
mainwindow.h mainwindow.h
userdialog.h userdialog.h
groupdialog.h groupdialog.h
usermanager.h
) )
set( lxqt-admin-user_UIS set( lxqt-admin-user_UIS
@ -37,6 +38,16 @@ lxqt_translate_ts(lxqt-admin-user_QM_FILES
${lxqt-admin-user_UIS} ${lxqt-admin-user_UIS}
INSTALL_DIR INSTALL_DIR
"${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}"
PULL_TRANSLATIONS
${PULL_TRANSLATIONS}
CLEAN_TRANSLATIONS
${CLEAN_TRANSLATIONS}
TRANSLATIONS_REPO
${TRANSLATIONS_REPO}
TRANSLATIONS_REFSPEC
${TRANSLATIONS_REFSPEC}
REPO_SUBDIR
"lxqt-admin/${PROJECT_NAME}"
) )
lxqt_translate_desktop(DESKTOP_FILES lxqt_translate_desktop(DESKTOP_FILES
@ -59,8 +70,17 @@ target_link_libraries(lxqt-admin-user
KF5::WindowSystem KF5::WindowSystem
Qt5::Widgets Qt5::Widgets
lxqt lxqt
${OOBS_LIBRARIES}
) )
install(TARGETS lxqt-admin-user RUNTIME DESTINATION bin) install(TARGETS lxqt-admin-user RUNTIME DESTINATION bin)
install(FILES ${DESKTOP_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications) install(FILES ${DESKTOP_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
# for policykit
# manpage for pcmanfm-qt
configure_file(
"org.lxqt.lxqt-admin-user.policy.in"
"${CMAKE_CURRENT_BINARY_DIR}/org.lxqt.lxqt-admin-user.policy"
@ONLY
)
install(PROGRAMS "lxqt-admin-user-helper" DESTINATION bin)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.lxqt.lxqt-admin-user.policy" DESTINATION "share/polkit-1/actions")

@ -20,111 +20,60 @@
#include "groupdialog.h" #include "groupdialog.h"
#include <QMessageBox> #include <QMessageBox>
#include "usermanager.h"
#include <QDebug>
#define DEFAULT_GID_MIN 1000 #define DEFAULT_GID_MIN 1000
#define DEFAULT_GID_MAX 32768 #define DEFAULT_GID_MAX 32768
GroupDialog::GroupDialog(OobsGroup *group, QWidget *parent, Qt::WindowFlags f): GroupDialog::GroupDialog(UserManager* userManager, GroupInfo* group, QWidget *parent, Qt::WindowFlags f):
QDialog(parent, f), QDialog(parent, f),
mGroup(group ? OOBS_GROUP(g_object_ref(group)) : NULL) mUserManager(userManager),
mGroup(group)
{ {
ui.setupUi(this); ui.setupUi(this);
ui.groupName->setText(group->name());
ui.gid->setValue(group->gid());
OobsGroupsConfig* groupsConfig = OOBS_GROUPS_CONFIG(oobs_groups_config_get()); const QStringList& members = group->members(); // all users in this group
if(group) // edit an exiting group
{
ui.groupName->setReadOnly(true);
ui.groupName->setText(oobs_group_get_name(group));
mOldGId = oobs_group_get_gid(group);
ui.gid->setValue(mOldGId);
}
else // create a new group
{
mOldGId = -1;
ui.gid->setValue(oobs_groups_config_find_free_gid(groupsConfig, DEFAULT_GID_MIN, DEFAULT_GID_MAX));
}
GList* groupUsers = oobs_group_get_users(mGroup); // all users in this group
// load all users // load all users
OobsUsersConfig* usersConfig = OOBS_USERS_CONFIG(oobs_users_config_get()); for(const UserInfo* user: userManager->users())
OobsList* users = oobs_users_config_get_users(usersConfig);
if(users)
{
OobsListIter it;
gboolean valid = oobs_list_get_iter_first(users, &it);
while(valid)
{ {
OobsUser* user = OOBS_USER(oobs_list_get(users, &it));
QListWidgetItem* item = new QListWidgetItem(); QListWidgetItem* item = new QListWidgetItem();
item->setText(oobs_user_get_login_name(user)); item->setText(user->name());
item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable|Qt::ItemIsSelectable); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable|Qt::ItemIsSelectable);
if(g_list_find(groupUsers, user)) // the user is in this group if(members.indexOf(user->name()) != -1) // the user is in this group
item->setCheckState(Qt::Checked); item->setCheckState(Qt::Checked);
else else
item->setCheckState(Qt::Unchecked); item->setCheckState(Qt::Unchecked);
QVariant obj = QVariant::fromValue<void*>(user); QVariant obj = QVariant::fromValue<void*>((void*)user);
item->setData(Qt::UserRole, obj); item->setData(Qt::UserRole, obj);
ui.userList->addItem(item); ui.userList->addItem(item);
valid = oobs_list_iter_next(users, &it);
} }
}
g_list_free(groupUsers);
} }
GroupDialog::~GroupDialog() GroupDialog::~GroupDialog()
{ {
if(mGroup)
g_object_unref(mGroup);
} }
void GroupDialog::accept() void GroupDialog::accept()
{ {
OobsGroupsConfig* groupsConfig = OOBS_GROUPS_CONFIG(oobs_groups_config_get()); QString groupName = ui.groupName->text();
gid_t gid = ui.gid->value();
if(gid != mOldGId && oobs_groups_config_is_gid_used(groupsConfig, gid))
{
QMessageBox::critical(this, tr("Error"), tr("The group ID is in use."));
return;
}
if(!mGroup) // create a new group
{
QByteArray groupName = ui.groupName->text().toLatin1();
if(groupName.isEmpty()) if(groupName.isEmpty())
{ {
QMessageBox::critical(this, tr("Error"), tr("The group name cannot be empty.")); QMessageBox::critical(this, tr("Error"), tr("The group name cannot be empty."));
return; return;
} }
if(oobs_groups_config_is_name_used(groupsConfig, groupName)) mGroup->setName(groupName);
{ mGroup->setGid(ui.gid->value());
QMessageBox::critical(this, tr("Error"), tr("The group name is in use."));
return;
}
mGroup = oobs_group_new(groupName);
}
oobs_group_set_gid(mGroup, gid);
// update users // update users
GList* groupUsers = oobs_group_get_users(mGroup); // all users in this group mGroup->removeAllMemberss();
int rowCount = ui.userList->count(); for(int row = 0; row < ui.userList->count(); ++row) {
for(int row = 0; row < rowCount; ++row)
{
QListWidgetItem* item = ui.userList->item(row); QListWidgetItem* item = ui.userList->item(row);
QVariant obj = item->data(Qt::UserRole); if(item->checkState() == Qt::Checked) {
OobsUser* user = OOBS_USER(obj.value<void*>()); mGroup->addMember(item->text());
if(g_list_find(groupUsers, user)) // the user belongs to this group previously
{
if(item->checkState() == Qt::Unchecked) // it's unchecked, remove it
oobs_group_remove_user(mGroup, user);
} }
else // the user does not belong to this group previously
{
if(item->checkState() == Qt::Checked) // it's checked, we want it!
oobs_group_add_user(mGroup, user);
} }
}
g_list_free(groupUsers);
oobs_object_commit(OOBS_OBJECT(mGroup));
QDialog::accept(); QDialog::accept();
} }

@ -23,32 +23,24 @@
#include <QDialog> #include <QDialog>
#include "ui_groupdialog.h" #include "ui_groupdialog.h"
#include <glib.h>
#include <oobs/oobs-usersconfig.h> class GroupInfo;
#include <oobs/oobs-groupsconfig.h> class UserManager;
class GroupDialog : public QDialog class GroupDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
GroupDialog(OobsGroup* group = NULL, QWidget *parent = NULL, Qt::WindowFlags f = 0); GroupDialog(UserManager* userManager, GroupInfo* group, QWidget *parent = nullptr, Qt::WindowFlags f = 0);
~GroupDialog(); ~GroupDialog();
OobsGroup* group()
{
return mGroup;
}
virtual void accept(); virtual void accept();
private:
bool hasUser(OobsUser* user);
private: private:
Ui::GroupDialog ui; Ui::GroupDialog ui;
OobsGroup* mGroup; UserManager* mUserManager;
gid_t mOldGId; GroupInfo* mGroup;
}; };
#endif // GROUPDIALOG_H #endif // GROUPDIALOG_H

@ -26,6 +26,9 @@
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QSpinBox" name="gid"> <widget class="QSpinBox" name="gid">
<property name="specialValueText">
<string>Default</string>
</property>
<property name="maximum"> <property name="maximum">
<number>32768</number> <number>32768</number>
</property> </property>

@ -0,0 +1,13 @@
#!/bin/sh
case "$1" in
# we only allow executing these commands
useradd|usermod|userdel|groupadd|groupmod|groupdel|passwd|gpasswd)
# TODO: platforms using different commands can add wrapper scripts here.
export LC_ALL=C
exec "$@"
;;
*)
echo "Command '$1' is not allowed!"
exit 1
;;
esac

@ -21,161 +21,125 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QDebug> #include <QDebug>
#include <QMessageBox> #include <QMessageBox>
#include <QInputDialog>
#include <QLineEdit>
#include <QRegExpValidator>
#include <QRegExp>
#include "userdialog.h" #include "userdialog.h"
#include "groupdialog.h" #include "groupdialog.h"
#include "usermanager.h"
MainWindow::MainWindow(): MainWindow::MainWindow():
QMainWindow(), QMainWindow(),
mUsersConfig(OOBS_USERS_CONFIG(oobs_users_config_get())), mUserManager(new UserManager(this))
mGroupsConfig(OOBS_GROUPS_CONFIG(oobs_groups_config_get()))
{ {
ui.setupUi(this); ui.setupUi(this);
connect(ui.actionAdd, SIGNAL(triggered(bool)), SLOT(onAdd())); connect(ui.actionAdd, SIGNAL(triggered(bool)), SLOT(onAdd()));
connect(ui.actionDelete, SIGNAL(triggered(bool)), SLOT(onDelete())); connect(ui.actionDelete, SIGNAL(triggered(bool)), SLOT(onDelete()));
connect(ui.actionProperties, SIGNAL(triggered(bool)), SLOT(onEditProperties())); connect(ui.actionProperties, SIGNAL(triggered(bool)), SLOT(onEditProperties()));
connect(ui.actionRefresh, SIGNAL(triggered(bool)), SLOT(onRefresh())); connect(ui.actionChangePasswd, SIGNAL(triggered(bool)), SLOT(onChangePasswd()));
connect(ui.actionRefresh, SIGNAL(triggered(bool)), SLOT(reload()));
onRefresh(); // load the settings connect(ui.userList, &QListWidget::activated, this, &MainWindow::onRowActivated);
connect(ui.groupList, &QListWidget::activated, this, &MainWindow::onRowActivated);
g_signal_connect(mUsersConfig, "changed" , G_CALLBACK(onUsersConfigChanged), this); connect(mUserManager, &UserManager::changed, this, &MainWindow::reload);
g_signal_connect(mGroupsConfig, "changed" , G_CALLBACK(onGroupsConfigChanged), this); reload();
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
if(mUsersConfig)
{
g_signal_handlers_disconnect_by_func(mUsersConfig, (void*)G_CALLBACK(onUsersConfigChanged), this);
g_object_unref(mUsersConfig);
}
if(mGroupsConfig)
g_object_unref(mGroupsConfig);
} }
void MainWindow::loadUsers() void MainWindow::reloadUsers()
{ {
ui.userList->clear(); ui.userList->clear();
OobsList* users = oobs_users_config_get_users(mUsersConfig); const auto& users = mUserManager->users();
if(users) for(const UserInfo* user: users)
{ {
OobsListIter it; uid_t uid = user->uid();
gboolean valid = oobs_list_get_iter_first(users, &it); if(uid > 499 && !user->shell().isEmpty()) // exclude system users
while(valid) {
{
GObject* obj = oobs_list_get(users, &it);
OobsUser* user = OOBS_USER(obj);
uid_t uid = oobs_user_get_uid(user);
if(uid > 499 && oobs_user_get_shell(user)) // exclude system users
{
QString fullName = QString::fromUtf8(oobs_user_get_full_name(user));
QString loginName = QString::fromLatin1(oobs_user_get_login_name(user));
QString homeDir = QString::fromLocal8Bit(oobs_user_get_home_directory(user));
QString groupName;
OobsGroup* group = oobs_user_get_main_group(user);
if(group)
groupName = QString::fromLatin1(oobs_group_get_name(group));
QTreeWidgetItem* item = new QTreeWidgetItem(); QTreeWidgetItem* item = new QTreeWidgetItem();
item->setData(0, Qt::DisplayRole, loginName); item->setData(0, Qt::DisplayRole, user->name());
QVariant obj = QVariant::fromValue<void*>(user); QVariant obj = QVariant::fromValue<void*>((void*)user);
item->setData(0, Qt::UserRole, obj); item->setData(0, Qt::UserRole, obj);
item->setData(1, Qt::DisplayRole, uid); item->setData(1, Qt::DisplayRole, uid);
item->setData(2, Qt::DisplayRole, fullName); item->setData(2, Qt::DisplayRole, user->fullName());
item->setData(3, Qt::DisplayRole, groupName); GroupInfo* group = mUserManager->findGroupInfo(user->gid());
item->setData(4, Qt::DisplayRole, homeDir); if(group != nullptr) {
ui.userList->addTopLevelItem(item); item->setData(3, Qt::DisplayRole, group->name());
} }
valid = oobs_list_iter_next(users, &it); item->setData(4, Qt::DisplayRole, user->homeDir());
ui.userList->addTopLevelItem(item);
} }
} }
} }
void MainWindow::loadGroups() void MainWindow::reloadGroups()
{ {
ui.groupList->clear(); ui.groupList->clear();
// load groups // load groups
OobsList* groups = oobs_groups_config_get_groups(mGroupsConfig); const auto& groups = mUserManager->groups();
if(groups) for(const GroupInfo* group: groups)
{ {
OobsListIter it;
gboolean valid = oobs_list_get_iter_first(groups, &it);
while(valid)
{
OobsGroup* group = OOBS_GROUP(oobs_list_get(groups, &it));
QTreeWidgetItem* item = new QTreeWidgetItem(); QTreeWidgetItem* item = new QTreeWidgetItem();
item->setData(0, Qt::DisplayRole, QString::fromLatin1(oobs_group_get_name(group))); item->setData(0, Qt::DisplayRole, group->name());
QVariant obj = QVariant::fromValue<void*>(group); QVariant obj = QVariant::fromValue<void*>((void*)group);
item->setData(0, Qt::UserRole, obj); item->setData(0, Qt::UserRole, obj);
item->setData(1, Qt::DisplayRole, oobs_group_get_gid(group)); item->setData(1, Qt::DisplayRole, group->gid());
item->setData(2, Qt::DisplayRole, group->members().join(", "));
ui.groupList->addTopLevelItem(item); ui.groupList->addTopLevelItem(item);
valid = oobs_list_iter_next(groups, &it);
}
} }
} }
OobsUser *MainWindow::userFromItem(QTreeWidgetItem *item) void MainWindow::reload() {
{ reloadUsers();
if(item) reloadGroups();
{
QVariant obj = item->data(0, Qt::UserRole);
OobsUser* user = OOBS_USER(obj.value<void*>());
return user;
}
return NULL;
} }
OobsGroup* MainWindow::groupFromItem(QTreeWidgetItem *item) UserInfo *MainWindow::userFromItem(QTreeWidgetItem *item)
{ {
if(item) if(item)
{ {
QVariant obj = item->data(0, Qt::UserRole); QVariant obj = item->data(0, Qt::UserRole);
return OOBS_GROUP(obj.value<void*>()); return reinterpret_cast<UserInfo*>(obj.value<void*>());
} }
return NULL; return nullptr;
} }
template <class T> GroupInfo* MainWindow::groupFromItem(QTreeWidgetItem *item)
bool MainWindow::authenticate(T *obj)
{ {
GError* err = NULL; if(item)
if(!oobs_object_authenticate(OOBS_OBJECT(obj), &err))
{
if(err)
{ {
QMessageBox::critical(this, tr("Error"), QString::fromUtf8(err->message)); QVariant obj = item->data(0, Qt::UserRole);
g_error_free(err); return reinterpret_cast<GroupInfo*>(obj.value<void*>());
}
return false;
} }
return true; return nullptr;
} }
void MainWindow::onAdd() void MainWindow::onAdd()
{ {
if(ui.tabWidget->currentIndex() == PageUsers) if(ui.tabWidget->currentIndex() == PageUsers)
{ {
if(authenticate(mUsersConfig)) UserInfo newUser;
{ UserDialog dlg(mUserManager, &newUser, this);
UserDialog dlg(NULL, this);
if(dlg.exec() == QDialog::Accepted) if(dlg.exec() == QDialog::Accepted)
{ {
OobsUser* user = dlg.user(); mUserManager->addUser(&newUser);
oobs_users_config_add_user(mUsersConfig, user); QByteArray newPasswd;
oobs_object_commit(OOBS_OBJECT(mUsersConfig)); if(getNewPassword(newUser.name(), newPasswd)) {
mUserManager->changePassword(&newUser, newPasswd);
} }
} }
} }
else if (ui.tabWidget->currentIndex() == PageGroups) else if (ui.tabWidget->currentIndex() == PageGroups)
{ {
if(authenticate(mGroupsConfig)) GroupInfo newGroup;
{ GroupDialog dlg(mUserManager, &newGroup, this);
GroupDialog dlg(NULL, this);
if(dlg.exec() == QDialog::Accepted) if(dlg.exec() == QDialog::Accepted)
{ {
OobsGroup* group = dlg.group(); mUserManager->addGroup(&newGroup);
oobs_groups_config_add_group(mGroupsConfig, group);
oobs_object_commit(OOBS_OBJECT(mGroupsConfig));
}
} }
} }
} }
@ -185,65 +149,116 @@ void MainWindow::onDelete()
if(ui.tabWidget->currentIndex() == PageUsers) if(ui.tabWidget->currentIndex() == PageUsers)
{ {
QTreeWidgetItem* item = ui.userList->currentItem(); QTreeWidgetItem* item = ui.userList->currentItem();
OobsUser* user = userFromItem(item); UserInfo* user = userFromItem(item);
if(user) if(user)
{ {
if(QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected user?"), QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok) if(QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected user?"), QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok)
{ {
oobs_users_config_delete_user(mUsersConfig, user); mUserManager->deleteUser(user);
oobs_object_commit(OOBS_OBJECT(mUsersConfig));
} }
} }
} }
else if(ui.tabWidget->currentIndex() == PageGroups) else if(ui.tabWidget->currentIndex() == PageGroups)
{ {
QTreeWidgetItem* item = ui.groupList->currentItem(); QTreeWidgetItem* item = ui.groupList->currentItem();
OobsGroup* group = groupFromItem(item); GroupInfo* group = groupFromItem(item);
if(group) if(group)
{ {
if(QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected group?"), QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok) if(QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected group?"), QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok)
{ {
oobs_groups_config_delete_group(mGroupsConfig, group); mUserManager->deleteGroup(group);
oobs_object_commit(OOBS_OBJECT(mGroupsConfig));
} }
} }
} }
} }
bool MainWindow::getNewPassword(const QString& name, QByteArray& passwd) {
QInputDialog dlg(this);
dlg.setTextEchoMode(QLineEdit::Password);
dlg.setLabelText(tr("Input the new password for %1:").arg(name));
QLineEdit* edit = dlg.findChild<QLineEdit*>(QString());
if(edit) {
// NOTE: do we need to add a validator to limit the input?
// QRegExpValidator* validator = new QRegExpValidator(QRegExp(QStringLiteral("\\w*")), edit);
// edit->setValidator(validator);
}
if(dlg.exec() == QDialog::Accepted) {
passwd = dlg.textValue().toUtf8();
if(passwd.isEmpty()) {
if(QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to set a empty password?"), QMessageBox::Ok|QMessageBox::Cancel) != QMessageBox::Ok)
return false;
}
return true;
}
return false;
}
void MainWindow::onChangePasswd() {
QString name;
UserInfo* user = nullptr;
GroupInfo* group = nullptr;
if(ui.tabWidget->currentIndex() == PageUsers)
{
QTreeWidgetItem* item = ui.userList->currentItem();
user = userFromItem(item);
if (!user)
return;
name = user->name();
}
else if(ui.tabWidget->currentIndex() == PageGroups)
{
QTreeWidgetItem* item = ui.groupList->currentItem();
group = groupFromItem(item);
if (!group)
return;
name = group->name();
}
QByteArray newPasswd;
if(getNewPassword(name, newPasswd)) {
if(user) {
mUserManager->changePassword(user, newPasswd);
}
if(group) {
mUserManager->changePassword(group, newPasswd);
}
}
}
void MainWindow::onRowActivated(const QModelIndex& index)
{
onEditProperties();
}
void MainWindow::onEditProperties() void MainWindow::onEditProperties()
{ {
if(ui.tabWidget->currentIndex() == PageUsers) if(ui.tabWidget->currentIndex() == PageUsers)
{ {
QTreeWidgetItem* item = ui.userList->currentItem(); QTreeWidgetItem* item = ui.userList->currentItem();
OobsUser* user = userFromItem(item); UserInfo* user = userFromItem(item);
if(user) if(user) {
{ UserInfo newSettings(*user);
if(authenticate(mUsersConfig)) UserDialog dlg(mUserManager, &newSettings, this);
if(dlg.exec() == QDialog::Accepted)
{ {
UserDialog dlg(user, this); mUserManager->modifyUser(user, &newSettings);
dlg.exec();
} }
} }
} }
else if(ui.tabWidget->currentIndex() == PageGroups) else if(ui.tabWidget->currentIndex() == PageGroups)
{ {
QTreeWidgetItem* item = ui.groupList->currentItem(); QTreeWidgetItem* item = ui.groupList->currentItem();
OobsGroup* group = groupFromItem(item); GroupInfo* group = groupFromItem(item);
if(group) if(group) {
{ GroupInfo newSettings(*group);
if(authenticate(mGroupsConfig)) GroupDialog dlg(mUserManager, &newSettings, this);
if(dlg.exec() == QDialog::Accepted)
{ {
GroupDialog dlg(group, this); mUserManager->modifyGroup(group, &newSettings);
dlg.exec();
} }
} }
} }
} }
void MainWindow::onRefresh()
{
oobs_object_update(OOBS_OBJECT(mUsersConfig));
loadUsers();
oobs_object_update(OOBS_OBJECT(mGroupsConfig));
loadGroups();
}

@ -24,9 +24,9 @@
#include <QMainWindow> #include <QMainWindow>
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include <glib.h> class UserInfo;
#include <oobs/oobs-usersconfig.h> class GroupInfo;
#include <oobs/oobs-groupsconfig.h> class UserManager;
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
@ -44,34 +44,23 @@ public:
virtual ~MainWindow(); virtual ~MainWindow();
private: private:
void loadUsers(); UserInfo* userFromItem(QTreeWidgetItem* item);
void loadGroups(); GroupInfo* groupFromItem(QTreeWidgetItem *item);
OobsUser* userFromItem(QTreeWidgetItem* item); bool getNewPassword(const QString& name, QByteArray& passwd);
OobsGroup* groupFromItem(QTreeWidgetItem *item); void reloadUsers();
void reloadGroups();
template <class T>
bool authenticate(T* obj);
static void onUsersConfigChanged(OobsObject* obj, MainWindow* _this)
{
_this->loadUsers();
}
static void onGroupsConfigChanged(OobsObject* obj, MainWindow* _this)
{
_this->loadGroups();
}
private Q_SLOTS: private Q_SLOTS:
void onAdd(); void onAdd();
void onDelete(); void onDelete();
void onEditProperties(); void onEditProperties();
void onRefresh(); void onChangePasswd();
void reload();
void onRowActivated(const QModelIndex& index);
private: private:
Ui::MainWindow ui; Ui::MainWindow ui;
OobsUsersConfig* mUsersConfig; UserManager* mUserManager;
OobsGroupsConfig* mGroupsConfig;
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>640</width> <width>676</width>
<height>480</height> <height>362</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -15,7 +15,16 @@
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="margin"> <property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
@ -42,9 +51,6 @@
<property name="expandsOnDoubleClick"> <property name="expandsOnDoubleClick">
<bool>false</bool> <bool>false</bool>
</property> </property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
<column> <column>
<property name="text"> <property name="text">
<string>Login Name</string> <string>Login Name</string>
@ -107,6 +113,11 @@
<string>Group ID</string> <string>Group ID</string>
</property> </property>
</column> </column>
<column>
<property name="text">
<string>Members</string>
</property>
</column>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -134,14 +145,14 @@
<addaction name="actionAdd"/> <addaction name="actionAdd"/>
<addaction name="actionDelete"/> <addaction name="actionDelete"/>
<addaction name="actionProperties"/> <addaction name="actionProperties"/>
<addaction name="actionChangePasswd"/>
<addaction name="actionRefresh"/> <addaction name="actionRefresh"/>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
<action name="actionAdd"> <action name="actionAdd">
<property name="icon"> <property name="icon">
<iconset theme="list-add"> <iconset theme="list-add">
<normaloff/> <normaloff>.</normaloff>.</iconset>
</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Add</string> <string>Add</string>
@ -153,8 +164,7 @@
<action name="actionDelete"> <action name="actionDelete">
<property name="icon"> <property name="icon">
<iconset theme="list-remove"> <iconset theme="list-remove">
<normaloff/> <normaloff>.</normaloff>.</iconset>
</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Delete</string> <string>Delete</string>
@ -166,8 +176,7 @@
<action name="actionProperties"> <action name="actionProperties">
<property name="icon"> <property name="icon">
<iconset theme="document-properties"> <iconset theme="document-properties">
<normaloff/> <normaloff>.</normaloff>.</iconset>
</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Properties</string> <string>Properties</string>
@ -179,8 +188,7 @@
<action name="actionRefresh"> <action name="actionRefresh">
<property name="icon"> <property name="icon">
<iconset theme="view-refresh"> <iconset theme="view-refresh">
<normaloff/> <normaloff>.</normaloff>.</iconset>
</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Refresh</string> <string>Refresh</string>
@ -189,6 +197,18 @@
<string>Refresh the lists</string> <string>Refresh the lists</string>
</property> </property>
</action> </action>
<action name="actionChangePasswd">
<property name="icon">
<iconset theme="dialog-password">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Change Password</string>
</property>
<property name="toolTip">
<string>Change password for the selected user or group</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
<policyconfig>
<action id="org.lxqt.lxqt-admin-user">
<message>Authentication is required for user administration</message>
<icon_name>preferences-system</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">@CMAKE_INSTALL_PREFIX@/bin/lxqt-admin-user-helper</annotate>
</action>
</policyconfig>

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

@ -0,0 +1,4 @@
#TRANSLATIONS
Name[ar]=المستخدمون والمجموعات
GenericName[ar]=إعدادات المستخدمون والمجموعات
Comment[ar]=اضبط مستخدمو النّظام ومجموعاته

@ -0,0 +1,3 @@
Name[ca]=Usuaris i grups
GenericName[ca]=Ajusts dels usuaris i dels grups
Comment[ca]=Configureu els usuaris i els grups del vostre sistema

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation>Gruppeneinstellungen</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>Gruppen-Name:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>Gruppen-ID:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>Benutzer in dieser Gruppe:</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="86"/>
<location filename="../groupdialog.cpp" line="95"/>
<location filename="../groupdialog.cpp" line="100"/>
<source>Error</source>
<translation>Fehler</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="86"/>
<source>The group ID is in use.</source>
<translation>Die Gruppen-ID existiert bereits.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="95"/>
<source>The group name cannot be empty.</source>
<translation>Der Gruppen-Name kann nicht leer sein.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="100"/>
<source>The group name is in use.</source>
<translation>Der Gruppen-Name existiert bereits.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation>Nutzer- und Gruppeneinstellungen</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation>&amp;Nutzer</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation>Anmeldename</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>Nutzer-ID</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation>Vollständiger Name</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation>Gruppe</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation>Nutzerverzeichnis</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>Systemnutzer anzeigen (nur für erfahrene Nutzer)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>&amp;Gruppen</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation>Name</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>Gruppen-ID</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation>Werkzeugleiste</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation>Hinzufügen</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation>Neue Nutzer oder Gruppen hinzufügen</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation>Entfernen</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation>Ausgewähltes Element löschen</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation>Eigenschaften</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation>Eigenschaften des ausgewählten Elements editieren</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation>Erneuern</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation>Listen erneuern</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation>Fehler</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation>Bestätigen</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation>Wollen Sie den ausgewählten Nutzer wirklich löschen?</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation>Wollen Sie die ausgewählte Gruppe wirklich löschen?</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation>Nutzereinstellungen</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation>Allgemein</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>Vollständiger Name:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>Anmeldename:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>Kennwort setzen:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>Nutzer-ID:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>Hauptgruppe:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation>Erweitert</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>Befehlsinterpreter (shell):</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>Nutzerverzeichnis:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="67"/>
<source>Change password:</source>
<translation>Kennwort ändern:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="128"/>
<location filename="../userdialog.cpp" line="141"/>
<location filename="../userdialog.cpp" line="146"/>
<source>Error</source>
<translation>Fehler</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="128"/>
<source>The user ID is in use.</source>
<translation>Die Nutzer-ID existiert bereits.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="141"/>
<source>The user name cannot be empty.</source>
<translation>Der Nutzername kann nicht leer sein.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="146"/>
<source>The user name is in use.</source>
<translation>Der Nutzername existiert bereits.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="162"/>
<source>Confirm</source>
<translation>Bestätigen</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="162"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation>Wollen Sie wirklich ein &quot;leeres Kennwort&quot; für den Nutzer vergeben?</translation>
</message>
</context>
</TS>

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="el">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation>Ρυθμίσεις ομάδας</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>Όνομα ομάδας:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>Αναγνωριστικό ομάδας:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>Χρήστες που ανήκουν στην ομάδα: </translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation>Σφάλμα</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation>Το αναγνωριστικό της ομάδας χρησιμοποιείται ήδη.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation>Το όνομα της ομάδας δεν μπορεί να είναι κενό.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation>Το όνομα της ομάδας χρησιμοποιείται ήδη.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation>Ρυθμίσεις χρηστών και ομάδων</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation>&amp;Χρήστες</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation>Όνομα χρήστη</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>Αναγνωριστικό χρήστη</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation>Πλήρες όνομα</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation>Ομάδα</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation>Προσωπικός κατάλογος</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>Εμφάνιση των χρηστών του συστήματος (μόνο για προηγμένους χρήστες)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>&amp;Ομάδες</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation>Όνομα</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>Αναγνωριστικό ομάδας</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation>Γραμμή εργαλείων</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation>Προσθήκη</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation>Προσθήκη νέων χρηστών ή ομάδων</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation>Διαγραφή</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation>Διαγραφή του επιλεγμένου αντικειμένου</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation>Ιδιότητες</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation>Επεξεργασία των ιδιοτήτων για το επιλεγμένο αντικείμενο</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation>Ανανέωση</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation>Ανανέωση της λίστας</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation>Σφάλμα</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation>Επιβεβαίωση</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation>Είστε σίγουρος-η ότι θέλετε να διαγράψετε τον επιλεγμένο χρήστη;</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation>Είστε σίγουρος-η ότι θέλετε να διαγράψετε την επιλεγμένη ομάδα;</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation>Ρυθμίσεις χρήστη</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation>Γενικά</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>Πλήρες όνομα:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>Όνομα χρήστη:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>Ορισμός του κωδικού πρόσβασης:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>Αναγνωριστικό χρήστη:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>Κύρια ομάδα:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation>Προηγμένο</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>Κέλυφος σύνδεσης:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>Προσωπικός κατάλογος:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation>Αλλαγή του κωδικού πρόσβασης:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation>Σφάλμα</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation>Το αναγνωριστικό του χρήστη χρησιμοποιείται ήδη. </translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation>Το όνομα χρήστη δεν μπορεί να είναι κενό.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation>Το όνομα του χρήστη χρησιμοποιείται ήδη.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation>Επιβεβαίωση</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation>Είστε σίγουρος-η ότι θέλετε να χρησιμοποιήσετε έναν «κενό κωδικό πρόσβασης» για τον χρήστη;</translation>
</message>
</context>
</TS>

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="hr_HR">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation type="unfinished">Postavke grupe</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation type="unfinished">Ime grupe:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation type="unfinished">ID grupe</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation type="unfinished">Korisnici koji pripadaju ovoj grupi</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation type="unfinished">Greška</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation type="unfinished">ID grupe je u uporabi.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation type="unfinished">Ime grupe ne može biti prazno.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation type="unfinished">Ime grupe je u uporabi.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation type="unfinished">Postavke korisnika i grupe</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation type="unfinished">&amp;Korisnici</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation type="unfinished">Ime prijave</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation type="unfinished">ID korisnika</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation type="unfinished">Puno ime</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation type="unfinished">Grupa</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation type="unfinished">Osobna mapa</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation type="unfinished">&amp;Grupe</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation type="unfinished">Ime</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation type="unfinished">ID grupe</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation type="unfinished">alatna traka</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation type="unfinished">Dodaj</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation type="unfinished">Dodaj nove korisnike ili grupe</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation type="unfinished">Izbriši</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation type="unfinished">Izbriši odabranu stavku</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation type="unfinished">Svojstva</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation type="unfinished">uredi svojstva odabrane stavke</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation type="unfinished">Osvježi</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation type="unfinished">Osvježi liste</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation type="unfinished">Greška</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation type="unfinished">Potvrdi</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation type="unfinished">Jeste li sigurni da želite izbrisati odabranoga korisnika?</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation type="unfinished">Jeste li sigurni da želite izbrisati odabranu grupu?</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation type="unfinished">Postavke korisnika</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation type="unfinished">Općenito</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation type="unfinished">Puno ime:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation type="unfinished">Ime prijave:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation type="unfinished">Postavi lozinku:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation type="unfinished">ID korisnika:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation type="unfinished">Glavna grupa:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation type="unfinished">Napredno</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation type="unfinished">Ljuska prijave:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation type="unfinished">Osobna mapa:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation type="unfinished">Promjeni lozinku:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation type="unfinished">Greška</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation type="unfinished">ID korisnika je u uporabi.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation type="unfinished">Korisničko ime ne može biti prazno.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation type="unfinished">Korisničko ime je u uoprabi.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation type="unfinished">Potvrdi</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation type="unfinished">Jeste li sigurni da želite koristiti &quot;praznu lozinku&quot; za korisnika?</translation>
</message>
</context>
</TS>

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="hu_HU">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation>Csoportbeállítás</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>Csoportnév:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>Csoport ID</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>A csoport tagjai:</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation>Hiba</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation>Csoport ID foglalt.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation>Csoportnév nem lehet üres.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation>Csoportnév foglalt.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation>Felhasználók és csoportok</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation>&amp;Felhasználók</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation>Bejelenkezési név</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>Felhasználó ID</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation>Teljes név</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation>Csoport</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation>Saját könyvtár</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>Rendszer felhasználók is látszanak (csak haladóknak)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>&amp;Csoportok</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation>Név</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>Csoport ID</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation>eszközsáv</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation>Hozzáad</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation>Új felhasználó, vagy csoport hozzáadása</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation>Törlés</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation>Kiválasztott törlése</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation>Tulajdonságok</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation>A választott elem módosítása</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation>Frisítés</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation>Lista frissítése</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation>Hiba</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation>Megerősítés</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation>Tényleg töröljük az illető felhasználót?</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation>Tényleg töröljük az illető csoportot?</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation>Felhasználó beállítása</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation>Alap</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>Teljes név:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>Bejelenkezési név:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>Jelszóbeállítás:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>Felhasználó ID:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>Főcsoport</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation>Bővített</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>Parancsértelmező:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>Saját könyvtár:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation>Jelszóváltoztatás:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation>Hiba</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation>Felhasználó ID foglalt.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation>Felhasználónév nem lehet üres.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation>Felhasználónév foglalt.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation>Megerősítés</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation>Üres legyen a jelszava a felhasználónak?</translation>
</message>
</context>
</TS>

@ -1,264 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="it_IT" sourcelanguage="it_IT">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation>Gestione gruppi</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>Nome del gruppo:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>ID gruppo:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>Utenti appartenenti:</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation>Errore</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation>ID già in uso</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation>Il nome non può essere vuoto.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation>Il nome è già in uso.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation>Impostazioni utenti e gruppi</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translatorcomment>remove &amp;_ in source</translatorcomment>
<translation type="unfinished">Utenti</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation>Nome Login</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>ID utente</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation>Nome completo</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation>Gruppo</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation>Cartella Home</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>Mostra utenti di sistema (avanzato)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>Gruppi</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation>Nome</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>ID gruppo</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation>Aggiungi</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation>Aggiungi utenti o gruppi nuovi</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation>Cancella</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation>Cancella selezionato</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation>Proprietà</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation>Modifica proprietà</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation>Aggiorna</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation>Aggiorna lista</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation>Errore</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation>Conferma</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation>Si è sicuro di voler cancellare l&apos;utente selezionato?</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation>Si è sicuro di voler cancellare il gruppo selezionato?</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation>Impostazioni utente</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation>Generali</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>Nome completo:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>Nome al Login:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>Scegli il password:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>ID utente</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>Gruppo principale:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation>Avanzate:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>Shell del login:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>Cartella home:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation>Cambia password:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation>Errore</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation>ID già in uso.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation>Il nome non può essere vuoto.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation>Il nome è già in uso.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation>Conferma</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation>Si è sicuro di volere un password vuoto per l&apos;utente?</translation>
</message>
</context>
</TS>

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ja">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation></translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>ID:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>:</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation></translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation>ID使</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation></translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation>使</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation>(&amp;U)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>ID</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>()</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>(&amp;G)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>ID</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation></translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation></translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation></translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>ID:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation></translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation>:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation>ID使</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation>使</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation></translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation></translation>
</message>
</context>
</TS>

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="pl_PL">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation>Ustawienia Grup</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>Nazwa grupy:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>ID grupy:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>Użytkownicy należący do tej grupy:</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation>Błąd</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation>ID grupy jest już w użyciu.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation>Nazwa grupy nie może być pusta.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation>Ta nazwa grupy jest już w użyciu.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation>Ustawienia użytkowników i grup</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation>&amp;Użytkownicy</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation>Login</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>ID użytkownika</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation>Pełna nazwa</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation>Grupa</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation>Katalog domowy</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>Pokaż użytkowników systemowych (dla zaawansowanych)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>&amp;Grupy</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation>Nazwa</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>ID grupy</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation>Pasek narzędzi</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation>Dodaj</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation>Dodaj nowych użytkowników lub grupy</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation>Usuń</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation>Usuń zaznaczoną pozycję</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation>Właściwości</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation>edytuj właściwości dla wybranej pozycji</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation>Odśwież</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation>Odśwież listę</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation>Błąd</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation>Potwierdzenie</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation>Czy na pewno chcesz usunąć wybranego użytkownika?</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation>Czy na pewno chcesz usunąć wybraną grupę?</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation>Ustawienia użytkownika</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation>Ogólne</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>Pełna nazwa:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>Login:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>Ustaw hasło:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>ID użytkownika:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>Grupa główna:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation>Zaawansowane</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>Powłoka:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>Katalog domowy:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation>Zmień hasło:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation>Błąd</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation>To ID użytkownika jest już w użyciu.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation>Nazwa użytkownika nie może być pusta.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation>Ta nazwa użytkownika jest już w użyciu.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation>Potwierdzenie</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation>Czy na pewno chcesz użyć &quot;pustego hasła&quot; dla tego użytkownika?</translation>
</message>
</context>
</TS>

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="pt">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation>Definições de grupo</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>Nome do grupo:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>ID do grupo:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>Utilizadores pertencentes a este grupo:</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation>Erro</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation>O ID do grupo já está em utilização.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation>O nome do grupo não pode estar vazio.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation>O nome do grupo já está em utilização.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation>Definições de grupo e utilizador</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation>&amp;Utilizadores</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation>Nome de acesso</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>ID de utilizador</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation>Nome completo</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation>Grupo</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation>Pasta pessoal</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>Mostrar utilizadores de sistema</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>&amp;Grupos</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation>Nome</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>ID do grupo</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation>Barra de ferramentas</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation>Adicionar</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation>Adicionar utilizadores ou grupos</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation>Eliminar</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation>Eliminar item selecionado</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation>Propriedades</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation>Editar propriedades do item selecionado</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation>Atualizar</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation>Atualizar as listas</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation>Erro</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation>Confirmação</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation>Tem a certeza que quer eliminar o utilizador selecionado?</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation>Tem a certeza que quer eliminar o grupo selecionado?</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation>Definições de utilizador</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation>Geral</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>Nome completo:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>Nome de acesso:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>Definir senha:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>ID de utilizador:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>Grupo principal:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation>Avançado</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>Consola de acesso:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>Pasta pessoal:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation>Mudar senha:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation>Erro</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation>O ID do utilizador já está em utilização.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation>O nome de utilizador não pode estar vazio.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation>O nome de utilizador já está em utilização.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation>Confirmação</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation>Tem a certeza que quer definir uma senha vazia para o utilizador?</translation>
</message>
</context>
</TS>

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation>Настройки группы</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>Имя группы:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>ID группы:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>Пользователи, относящиеся к этой группе:</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation>Ошибка</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation>ID группы уже используется.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation>Имя группы не может быть пустым.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation>Имя группы уже используется.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation>Настройки пользователя и группы</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation>&amp;Пользователи</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation>Логин пользователя</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>ID пользователя</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation>Полное имя</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation>Группа</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation>Домашний каталог</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>Показывать системных пользователей (только для продвинутых пользователей)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>&amp;Группы</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation>Имя</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>ID группы</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation>Панель</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation>Добавить</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation>Добавить новых пользователей или группы</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation>Удалить</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation>Удалить выбранный элемент</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation>Свойства</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation>Редактировать свойства выделенного элемента</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation>Обновить</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation>Обновить список</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation>Ошибка</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation>Подтвердить</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation>Вы действительно хотите удалить выбранного пользователя?</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation>Вы действительно хотите удалить выбранную группу?</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation>Настройки пользователя</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation>Общие</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>Полное имя:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>Логин пользователя:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>Установить пароль:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>ID пользователя:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>Главная группа:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation>Расширенные</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>Оболочка:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>Домашний каталог:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation>Изменить пароль:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation>Ошибка</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation>Пользовательский ID уже используется.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation>Имя пользователя не может быть пустым.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation>Имя пользователя уже используется.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation>Подтвердить</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation>Вы действительно хотите использовать пустой пароль для этого пользователя?</translation>
</message>
</context>
</TS>

@ -1,6 +0,0 @@
[Desktop Entry]
Name[ru_RU]=Пользователи и группы
GenericName[ru_RU]=Настройки пользователей и групп
Comment[ru_RU]=Настроить пользователей и группы вашей системы
#TRANSLATIONS_DIR=translations

@ -1,263 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
<name>GroupDialog</name>
<message>
<location filename="../groupdialog.ui" line="14"/>
<source>Group Settings</source>
<translation>Настройки группы</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="20"/>
<source>Group name:</source>
<translation>Имя группы:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="37"/>
<source>Group ID:</source>
<translation>ID группы:</translation>
</message>
<message>
<location filename="../groupdialog.ui" line="44"/>
<source>Users belong to this group:</source>
<translation>Пользователи, относящиеся к этой группе:</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<location filename="../groupdialog.cpp" line="92"/>
<location filename="../groupdialog.cpp" line="97"/>
<source>Error</source>
<translation>Ошибка</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="83"/>
<source>The group ID is in use.</source>
<translation>ID группы уже используется.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="92"/>
<source>The group name cannot be empty.</source>
<translation>Имя группы не может быть пустым.</translation>
</message>
<message>
<location filename="../groupdialog.cpp" line="97"/>
<source>The group name is in use.</source>
<translation>Имя группы уже используется.</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>User and Group Settings</source>
<translation>Настройки пользователя и группы</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="31"/>
<source>&amp;Users</source>
<translation>&amp;Пользователи</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="50"/>
<source>Login Name</source>
<translation>Логин пользователя</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="55"/>
<source>User ID</source>
<translation>ID пользователя</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="60"/>
<source>Full Name</source>
<translation>Полное имя</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="65"/>
<source>Group</source>
<translation>Группа</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="70"/>
<source>Home Directory</source>
<translation>Домашний каталог</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Show system users (for advanced users only)</source>
<translation>Показывать системных пользователей (только для продвинутых пользователей)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="89"/>
<source>&amp;Groups</source>
<translation>&amp;Группы</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="102"/>
<source>Name</source>
<translation>Имя</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="107"/>
<source>Group ID</source>
<translation>ID группы</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="120"/>
<source>toolBar</source>
<translation>Панель</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="147"/>
<source>Add</source>
<translation>Добавить</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="150"/>
<source>Add new users or groups</source>
<translation>Добавить новых пользователей или группы</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="160"/>
<source>Delete</source>
<translation>Удалить</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="163"/>
<source>Delete selected item</source>
<translation>Удалить выбранный элемент</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="173"/>
<source>Properties</source>
<translation>Свойства</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="176"/>
<source>edit properties of the selected item</source>
<translation>Редактировать свойства выделенного элемента</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="186"/>
<source>Refresh</source>
<translation>Обновить</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="189"/>
<source>Refresh the lists</source>
<translation>Обновить список</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="145"/>
<source>Error</source>
<translation>Ошибка</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Confirm</source>
<translation>Подтвердить</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="191"/>
<source>Are you sure you want to delete the selected user?</source>
<translation>Вы действительно хотите удалить выбранного пользователя?</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Are you sure you want to delete the selected group?</source>
<translation>Вы действительно хотите удалить выбранную группу?</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<location filename="../userdialog.ui" line="14"/>
<source>User Settings</source>
<translation>Настройки пользователя</translation>
</message>
<message>
<location filename="../userdialog.ui" line="24"/>
<source>General</source>
<translation>Общие</translation>
</message>
<message>
<location filename="../userdialog.ui" line="33"/>
<source>Full name:</source>
<translation>Полное имя:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="43"/>
<source>Login name:</source>
<translation>Логин пользователя:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="53"/>
<source>Set password:</source>
<translation>Установить пароль:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="77"/>
<source>User ID:</source>
<translation>ID пользователя:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="84"/>
<source>Main group:</source>
<translation>Главная группа:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="99"/>
<source>Advanced</source>
<translation>Расширенные</translation>
</message>
<message>
<location filename="../userdialog.ui" line="105"/>
<source>Login shell:</source>
<translation>Оболочка:</translation>
</message>
<message>
<location filename="../userdialog.ui" line="122"/>
<source>Home directory:</source>
<translation>Домашний каталог:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="64"/>
<source>Change password:</source>
<translation>Изменить пароль:</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<location filename="../userdialog.cpp" line="138"/>
<location filename="../userdialog.cpp" line="143"/>
<source>Error</source>
<translation>Ошибка</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="125"/>
<source>The user ID is in use.</source>
<translation>Пользовательский ID уже используется.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="138"/>
<source>The user name cannot be empty.</source>
<translation>Имя пользователя не может быть пустым.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="143"/>
<source>The user name is in use.</source>
<translation>Имя пользователя уже используется.</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Confirm</source>
<translation>Подтвердить</translation>
</message>
<message>
<location filename="../userdialog.cpp" line="159"/>
<source>Are you sure you want to use an &quot;empty password&quot; for the user?</source>
<translation>Вы действительно хотите использовать пустой пароль для этого пользователя?</translation>
</message>
</context>
</TS>

@ -20,76 +20,65 @@
#include "userdialog.h" #include "userdialog.h"
#include <QMessageBox> #include <QMessageBox>
#include <QListWidgetItem>
#include <QDebug>
#include "usermanager.h"
#define DEFAULT_UID_MIN 1000 #define DEFAULT_UID_MIN 1000
#define DEFAULT_UID_MAX 32768 #define DEFAULT_UID_MAX 32768
UserDialog::UserDialog(OobsUser* user, QWidget* parent): UserDialog::UserDialog(UserManager* userManager, UserInfo* user, QWidget* parent):
QDialog(), QDialog(parent),
mUser(user ? OOBS_USER(g_object_ref(user)) : NULL), mUserManager(userManager),
mUser(user),
mFullNameChanged(false), mFullNameChanged(false),
mHomeDirChanged(false) mHomeDirChanged(false)
{ {
ui.setupUi(this); ui.setupUi(this);
bool isNewUser = (user->uid() == 0 && user->name().isEmpty());
// load all groups // load all groups
OobsGroupsConfig* groupsConfig = OOBS_GROUPS_CONFIG(oobs_groups_config_get()); for(const GroupInfo* group: mUserManager->groups())
OobsList* groups = oobs_groups_config_get_groups(groupsConfig);
if(groups)
{ {
OobsListIter it; ui.mainGroup->addItem(group->name());
gboolean valid = oobs_list_get_iter_first(groups, &it);
while(valid) QListWidgetItem* item = new QListWidgetItem();
item->setText(group->name());
item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable|Qt::ItemIsSelectable);
if(!isNewUser)
{ {
OobsGroup* group = OOBS_GROUP(oobs_list_get(groups, &it)); if(group->hasMember(user->name()) || user->gid() == group->gid()) // the user is in this group
ui.mainGroup->addItem(oobs_group_get_name(group)); item->setCheckState(Qt::Checked);
valid = oobs_list_iter_next(groups, &it); else
item->setCheckState(Qt::Unchecked);
} }
else
item->setCheckState(Qt::Unchecked);
ui.groupList->addItem(item);
} }
connect(ui.loginName, SIGNAL(textChanged(QString)), SLOT(onLoginNameChanged(QString))); connect(ui.loginName, SIGNAL(textChanged(QString)), SLOT(onLoginNameChanged(QString)));
OobsUsersConfig* userConfig = OOBS_USERS_CONFIG(oobs_users_config_get()); ui.loginShell->addItems(mUserManager->availableShells());
// add known shells to the combo box for selection
GList* shells = oobs_users_config_get_available_shells(userConfig);
for(GList* l = shells; l; l = l->next)
{
const char* shell = (const char*)l->data;
ui.loginShell->addItem(QLatin1String(shell));
}
if(user) // edit an existing user if(isNewUser) // new user
{ {
mOldUid = oobs_user_get_uid(user); ui.mainGroup->setCurrentIndex(-1);
ui.loginName->setReadOnly(true); ui.loginShell->setCurrentIndex(-1);
ui.loginName->setText(oobs_user_get_login_name(user));
ui.changePasswd->setText(tr("Change password:"));
ui.uid->setValue(mOldUid);
ui.fullName->setText(oobs_user_get_full_name(user));
ui.loginShell->setEditText(oobs_user_get_shell(user));
ui.homeDir->setText(QString::fromLocal8Bit(oobs_user_get_home_directory(user)));
OobsGroup* group = oobs_user_get_main_group(user);
ui.mainGroup->setEditText(oobs_group_get_name(group));
} }
else // create a new user else // edit an existing user
{ {
mOldUid = -1; ui.loginName->setText(user->name());
ui.loginName->setReadOnly(false); ui.uid->setValue(user->uid());
ui.loginName->setFocus(); ui.fullName->setText(user->fullName());
ui.changePasswd->setChecked(true); ui.loginShell->setEditText(user->shell());
ui.uid->setValue(oobs_users_config_find_free_uid(userConfig, DEFAULT_UID_MIN, DEFAULT_UID_MAX)); ui.homeDir->setText(user->homeDir());
ui.loginShell->setEditText(oobs_users_config_get_default_shell(userConfig)); GroupInfo* group = userManager->findGroupInfo(user->gid());
ui.mainGroup->setCurrentIndex(-1); if(group)
ui.mainGroup->setEditText(group->name());
} }
} }
UserDialog::~UserDialog() UserDialog::~UserDialog()
{ {
if(mUser)
g_object_unref(mUser);
} }
void UserDialog::onLoginNameChanged(const QString& text) void UserDialog::onLoginNameChanged(const QString& text)
@ -121,61 +110,33 @@ void UserDialog::onHomeDirChanged(const QString& text)
void UserDialog::accept() void UserDialog::accept()
{ {
OobsUsersConfig* usersConfig = OOBS_USERS_CONFIG(oobs_users_config_get()); mUser->setUid(ui.uid->value());
uid_t uid = ui.uid->value(); QString loginName = ui.loginName->text();
if(uid != mOldUid && oobs_users_config_is_uid_used(usersConfig, uid))
{
QMessageBox::critical(this, tr("Error"), tr("The user ID is in use."));
return;
}
bool createNew;
if(mUser)
createNew = false;
else
{
createNew = true;
QByteArray loginName = ui.loginName->text().toLatin1();
if(loginName.isEmpty()) if(loginName.isEmpty())
{ {
QMessageBox::critical(this, tr("Error"), tr("The user name cannot be empty.")); QMessageBox::critical(this, tr("Error"), tr("The user name cannot be empty."));
return; return;
} }
if(oobs_users_config_is_login_used(usersConfig, loginName)) mUser->setName(loginName);
{ mUser->setFullName(ui.fullName->text());
QMessageBox::critical(this, tr("Error"), tr("The user name is in use."));
return;
}
mUser = oobs_user_new(loginName);
}
oobs_user_set_uid(mUser, uid);
QByteArray fullName = ui.fullName->text().toUtf8();
oobs_user_set_full_name(mUser, fullName);
// change password
if(ui.changePasswd->isChecked())
{
QByteArray passwd = ui.passwd->text().toLatin1();
if(passwd.isEmpty()) // show warnings if the password is empty
{
if(QMessageBox::warning(this, tr("Confirm"), tr("Are you sure you want to use an \"empty password\" for the user?"), QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes)
oobs_user_set_password_empty(mUser, true);
}
else
oobs_user_set_password(mUser, passwd);
}
QByteArray homeDir = ui.homeDir->text().toLocal8Bit(); mUser->setHomeDir(ui.homeDir->text());
oobs_user_set_home_directory(mUser, homeDir);
// main group // main group
OobsGroupsConfig* groupsConfig = OOBS_GROUPS_CONFIG(oobs_groups_config_get()); QString groupName = ui.mainGroup->currentText();
QByteArray groupName = ui.mainGroup->currentText().toLatin1(); if(!groupName.isEmpty()) {
OobsGroup* group = oobs_groups_config_get_from_name(groupsConfig, groupName); GroupInfo* group = mUserManager->findGroupInfo(groupName);
oobs_user_set_main_group(mUser, group); if(group)
mUser->setGid(group->gid());
}
if(!createNew) // other groups
oobs_object_commit_async(OOBS_OBJECT(mUser), NULL, NULL); mUser->removeAllGroups();
for(int row = 0; row < ui.groupList->count(); ++row) {
QListWidgetItem* item = ui.groupList->item(row);
if(item->checkState() == Qt::Checked) {
mUser->addGroup(item->text());
}
}
QDialog::accept(); QDialog::accept();
} }

@ -23,23 +23,19 @@
#include <QDialog> #include <QDialog>
#include "ui_userdialog.h" #include "ui_userdialog.h"
#include <glib.h> #include "usermanager.h"
#include <oobs/oobs-usersconfig.h>
#include <oobs/oobs-groupsconfig.h> class UserManager;
class UserInfo;
class UserDialog : public QDialog class UserDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
UserDialog(OobsUser* user = NULL, QWidget* parent = NULL); UserDialog(UserManager* userManager, UserInfo* user, QWidget* parent = nullptr);
~UserDialog(); ~UserDialog();
OobsUser* user()
{
return mUser;
}
virtual void accept(); virtual void accept();
private Q_SLOTS: private Q_SLOTS:
@ -49,14 +45,8 @@ private Q_SLOTS:
private: private:
Ui::UserDialog ui; Ui::UserDialog ui;
OobsUser* mUser; UserManager* mUserManager;
uid_t mOldUid; UserInfo* mUser;
#if 0
QByteArray mOldLoginName;
QByteArray mOldFullName;
QByteArray mOldGroupName;
QByteArray mOldHomeDir;
#endif
bool mFullNameChanged; bool mFullNameChanged;
bool mHomeDirChanged; bool mHomeDirChanged;

@ -27,16 +27,6 @@
<property name="fieldGrowthPolicy"> <property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum> <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property> </property>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Full name:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="fullName"/>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
@ -48,44 +38,40 @@
<widget class="QLineEdit" name="loginName"/> <widget class="QLineEdit" name="loginName"/>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="changePasswd"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>Set password:</string> <string>Full name:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="passwd"> <widget class="QLineEdit" name="fullName"/>
<property name="enabled"> </item>
<bool>false</bool> <item row="3" column="0">
</property> <widget class="QLabel" name="label_2">
<property name="echoMode"> <property name="text">
<enum>QLineEdit::Password</enum> <string>User ID:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="3" column="1">
<widget class="QSpinBox" name="uid"> <widget class="QSpinBox" name="uid">
<property name="specialValueText">
<string>Default</string>
</property>
<property name="maximum"> <property name="maximum">
<number>32768</number> <number>32768</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>User ID:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>Main group:</string> <string>Main group:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="4" column="1">
<widget class="QComboBox" name="mainGroup"> <widget class="QComboBox" name="mainGroup">
<property name="editable"> <property name="editable">
<bool>true</bool> <bool>true</bool>
@ -94,6 +80,30 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Groups</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>The user belongs to the following groups:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="groupList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2"> <widget class="QWidget" name="tab_2">
<attribute name="title"> <attribute name="title">
<string>Advanced</string> <string>Advanced</string>
@ -173,21 +183,5 @@
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>changePasswd</sender>
<signal>toggled(bool)</signal>
<receiver>passwd</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>71</x>
<y>125</y>
</hint>
<hint type="destinationlabel">
<x>192</x>
<y>129</y>
</hint>
</hints>
</connection>
</connections> </connections>
</ui> </ui>

@ -0,0 +1,393 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2016 LXQt team
* Authors:
* Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "usermanager.h"
#include <QDebug>
#include <algorithm>
#include <QFileSystemWatcher>
#include <QTimer>
#include <QProcess>
#include <QFile>
#include <QMessageBox>
#include <unistd.h>
static const QString PASSWD_FILE = QStringLiteral("/etc/passwd");
static const QString GROUP_FILE = QStringLiteral("/etc/group");
static const QString LOGIN_DEFS_FILE = QStringLiteral("/etc/login.defs");
UserManager::UserManager(QObject *parent):
QObject(parent),
mWatcher(new QFileSystemWatcher(QStringList() << PASSWD_FILE << GROUP_FILE, this))
{
loadUsersAndGroups();
connect(mWatcher, &QFileSystemWatcher::fileChanged, this, &UserManager::onFileChanged);
}
UserManager::~UserManager() {
qDeleteAll(mUsers);
qDeleteAll(mGroups);
}
void UserManager::loadUsersAndGroups()
{
// load groups
setgrent();
struct group * grp;
while((grp = getgrent())) {
GroupInfo* group = new GroupInfo(grp);
mGroups.append(group);
// add members of this group
for(char** member_name = grp->gr_mem; *member_name; ++member_name) {
group->addMember(QString::fromLatin1(*member_name));
}
}
endgrent();
std::sort(mGroups.begin(), mGroups.end(), [](GroupInfo* g1, GroupInfo* g2) {
return g1->name() < g2->name();
});
// load users
setpwent();
struct passwd * pw;
while((pw = getpwent())) {
UserInfo* user = new UserInfo(pw);
mUsers.append(user);
// add groups to this user
for(const GroupInfo* group: mGroups) {
if(group->hasMember(user->name())) {
user->addGroup(group->name());
}
}
}
endpwent();
std::sort(mUsers.begin(), mUsers.end(), [](UserInfo*& u1, UserInfo*& u2) {
return u1->name() < u2->name();
});
}
// load settings from /etc/login.defs
void UserManager::loadLoginDefs() {
// FIXME: parse /etc/login.defs to get max UID, max system UID...etc.
QFile file(LOGIN_DEFS_FILE);
if(file.open(QIODevice::ReadOnly)) {
while(!file.atEnd()) {
QByteArray line = file.readLine().trimmed();
if(line.isEmpty() || line.startsWith('#'))
continue;
QStringList parts = QString::fromUtf8(line).split(QRegExp("\\s"), QString::SkipEmptyParts);
if(parts.length() >= 2) {
QString& key = parts[0];
QString& val = parts[1];
if(key == QLatin1Literal("SYS_UID_MIN")) {
}
else if(key == QLatin1Literal("SYS_UID_MAX")) {
}
else if(key == QLatin1Literal("UID_MIN")) {
}
else if(key == QLatin1Literal("UID_MAX")) {
}
else if(key == QLatin1Literal("SYS_GID_MIN")) {
}
else if(key == QLatin1Literal("SYS_GID_MAX")) {
}
else if(key == QLatin1Literal("GID_MIN")) {
}
else if(key == QLatin1Literal("GID_MAX")) {
}
}
}
file.close();
}
}
UserInfo* UserManager::findUserInfo(const char* name) {
auto it = std::find_if(mUsers.begin(), mUsers.end(), [name](const UserInfo* user) {
return user->name() == name;
});
return it != mUsers.end() ? *it : nullptr;
}
UserInfo* UserManager::findUserInfo(QString name) {
auto it = std::find_if(mUsers.begin(), mUsers.end(), [name](const UserInfo* user) {
return user->name() == name;
});
return it != mUsers.end() ? *it : nullptr;
}
UserInfo* UserManager::findUserInfo(uid_t uid) {
auto it = std::find_if(mUsers.begin(), mUsers.end(), [uid](const UserInfo* user) {
return user->uid() == uid;
});
return it != mUsers.end() ? *it : nullptr;
}
GroupInfo* UserManager::findGroupInfo(const char* name) {
auto it = std::find_if(mGroups.begin(), mGroups.end(), [name](const GroupInfo* group) {
return group->name() == name;
});
return it != mGroups.end() ? *it : nullptr;
}
GroupInfo* UserManager::findGroupInfo(QString name) {
auto it = std::find_if(mGroups.begin(), mGroups.end(), [name](const GroupInfo* group) {
return group->name() == name;
});
return it != mGroups.end() ? *it : nullptr;
}
GroupInfo* UserManager::findGroupInfo(gid_t gid) {
auto it = std::find_if(mGroups.begin(), mGroups.end(), [gid](const GroupInfo* group) {
return group->gid() == gid;
});
return it != mGroups.end() ? *it : nullptr;
}
void UserManager::reload() {
mWatcher->addPath(PASSWD_FILE);
mWatcher->addPath(GROUP_FILE);
qDeleteAll(mUsers); // free the old UserInfo objects
mUsers.clear();
qDeleteAll(mGroups); // free the old GroupInfo objects
mGroups.clear();
loadUsersAndGroups();
Q_EMIT changed();
}
void UserManager::onFileChanged(const QString &path) {
// QFileSystemWatcher is very broken and has a ridiculous design.
// we get "fileChanged()" when the file is deleted or modified,
// but there is no way to distinguish them. If the file is deleted,
// the QFileSystemWatcher stop working silently. Hence we workaround
// this by remove the paths from the watcher and add them back again
// to force the creation of new notifiers.
mWatcher->removePath(PASSWD_FILE);
mWatcher->removePath(GROUP_FILE);
QTimer::singleShot(500, this, &UserManager::reload);
}
bool UserManager::pkexec(const QStringList& command, const QByteArray& stdinData) {
Q_ASSERT(!command.isEmpty());
QProcess process;
qDebug() << command;
QStringList args;
args << QStringLiteral("--disable-internal-agent")
<< QStringLiteral("lxqt-admin-user-helper")
<< command;
process.start(QStringLiteral("pkexec"), args);
if(!stdinData.isEmpty()) {
process.waitForStarted();
process.write(stdinData);
process.waitForBytesWritten();
process.closeWriteChannel();
}
process.waitForFinished(-1);
QByteArray pkexec_error = process.readAllStandardError();
qDebug() << pkexec_error;
const bool succeeded = process.exitCode() == 0;
if (!succeeded)
{
QMessageBox * msg = new QMessageBox{QMessageBox::Critical, tr("lxqt-admin-user")
, tr("<strong>Action (%1) failed:</strong><br/><pre>%2</pre>").arg(command[0]).arg(pkexec_error.constData())};
msg->setAttribute(Qt::WA_DeleteOnClose, true);
msg->show();
}
return succeeded;
}
bool UserManager::addUser(UserInfo* user) {
if(!user || user->name().isEmpty())
return false;
QStringList command;
command << QStringLiteral("useradd");
if(user->uid() != 0) {
command << QStringLiteral("-u") << QString::number(user->uid());
}
if(!user->homeDir().isEmpty()) {
command << QStringLiteral("-d") << user->homeDir();
command << QStringLiteral("-m"); // create the user's home directory if it does not exist.
}
if(!user->shell().isEmpty()) {
command << QStringLiteral("-s") << user->shell();
}
if(!user->fullName().isEmpty()) {
command << QStringLiteral("-c") << user->fullName();
}
if(user->gid() != 0) {
command << QStringLiteral("-g") << QString::number(user->gid());
}
if(!user->groups().isEmpty()) { // set group membership
command << QStringLiteral("-G") << user->groups().join(',');
}
command << user->name();
return pkexec(command);
}
bool UserManager::modifyUser(UserInfo* user, UserInfo* newSettings) {
if(!user || user->name().isEmpty() || !newSettings)
return false;
QStringList command;
command << QStringLiteral("usermod");
if(newSettings->uid() != user->uid())
command << QStringLiteral("-u") << QString::number(newSettings->uid());
if(newSettings->homeDir() != user->homeDir()) {
command << QStringLiteral("-d") << newSettings->homeDir();
// command << QStringLiteral("-m"); // create the user's home directory if it does not exist.
}
if(newSettings->shell() != user->shell()) {
command << QStringLiteral("-s") << newSettings->shell();
}
if(newSettings->fullName() != user->fullName())
command << QStringLiteral("-c") << newSettings->fullName();
if(newSettings->gid() != user->gid())
command << QStringLiteral("-g") << QString::number(newSettings->gid());
if(newSettings->name() != user->name()) // change login name
command << QStringLiteral("-l") << newSettings->name();
if(newSettings->groups() != user->groups()) { // change group membership
command << QStringLiteral("-G") << newSettings->groups().join(',');
}
command << user->name();
return pkexec(command);
}
bool UserManager::deleteUser(UserInfo* user) {
if(!user || user->name().isEmpty())
return false;
QStringList command;
command << QStringLiteral("userdel");
command << user->name();
return pkexec(command);
}
bool UserManager::changePassword(UserInfo* user, QByteArray newPasswd) {
// In theory, the current user should be able to use "passwd" to
// reset his/her own password without root permission, but...
// /usr/bin/passwd is a setuid program running as root and QProcess
// does not seem to capture its stdout... So... requires root for now.
if(geteuid() == user->uid()) {
// FIXME: there needs to be a way to let a user change his/her own password.
// Maybe we can use our pkexec helper script to achieve this.
}
QStringList command;
command << QStringLiteral("passwd");
command << user->name();
// we need to type the new password for two times.
QByteArray stdinData;
stdinData += newPasswd;
stdinData += "\n";
stdinData += newPasswd;
stdinData += "\n";
return pkexec(command, stdinData);
}
bool UserManager::addGroup(GroupInfo* group) {
if(!group || group->name().isEmpty())
return false;
QStringList command;
command << QStringLiteral("groupadd");
if(group->gid() != 0) {
command << QStringLiteral("-g") << QString::number(group->gid());
}
command << group->name();
return pkexec(command);
}
bool UserManager::modifyGroup(GroupInfo* group, GroupInfo* newSettings) {
if(!group || group->name().isEmpty() || !newSettings)
return false;
QStringList command;
command << QStringLiteral("groupmod");
if(newSettings->gid() != group->gid())
command << QStringLiteral("-g") << QString::number(newSettings->gid());
if(newSettings->name() != group->name())
command << QStringLiteral("-n") << newSettings->name();
command << group->name();
if(!pkexec(command))
return false;
// if group members are changed, use gpasswd to reset members
if(newSettings->members() != group->members()) {
command.clear();
command << QStringLiteral("gpasswd");
command << QStringLiteral("-M"); // Set the list of group members.
command << newSettings->members().join(',');
command << group->name();
return pkexec(command);
}
return true;
}
bool UserManager::deleteGroup(GroupInfo* group) {
if(!group || group->name().isEmpty())
return false;
QStringList command;
command << QStringLiteral("groupdel");
command << group->name();
return pkexec(command);
}
bool UserManager::changePassword(GroupInfo* group, QByteArray newPasswd) {
QStringList command;
command << QStringLiteral("gpasswd");
command << group->name();
// we need to type the new password for two times.
QByteArray stdinData = newPasswd;
stdinData += "\n";
stdinData += newPasswd;
stdinData += "\n";
return pkexec(command, stdinData);
}
const QStringList& UserManager::availableShells() {
if(mAvailableShells.isEmpty()) {
QFile file("/etc/shells");
if(file.open(QIODevice::ReadOnly)) {
while(!file.atEnd()) {
QByteArray line = file.readLine().trimmed();
if(line.isEmpty() || line.startsWith('#'))
continue;
mAvailableShells.append(QString::fromLocal8Bit(line));
}
file.close();
}
}
return mAvailableShells;
}

@ -0,0 +1,239 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2016 LXQt team
* Authors:
* Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef USERMANAGER_H
#define USERMANAGER_H
#include <QObject>
#include <QStringList>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
class QFileSystemWatcher;
class UserInfo
{
public:
explicit UserInfo():mUid(0), mGid(0) {
}
explicit UserInfo(struct passwd* pw):
mUid(pw->pw_uid),
mGid(pw->pw_gid),
mName(QString::fromLatin1(pw->pw_name)),
mFullName(QString::fromUtf8(pw->pw_gecos)),
mShell(QString::fromLocal8Bit(pw->pw_shell)),
mHomeDir(QString::fromLocal8Bit(pw->pw_dir))
{
}
uid_t uid()const {
return mUid;
}
void setUid(uid_t uid) {
mUid = uid;
}
gid_t gid() const {
return mGid;
}
void setGid(gid_t gid) {
mGid = gid;
}
QString name() const {
return mName;
}
void setName(const QString& name) {
mName = name;
}
QString fullName() const {
return mFullName;
}
void setFullName(const QString& fullName) {
mFullName = fullName;
}
QString shell() const {
return mShell;
}
void setShell(const QString& shell) {
mShell = shell;
}
QString homeDir() const {
return mHomeDir;
}
void setHomeDir(const QString& homeDir) {
mHomeDir = homeDir;
}
const QStringList& groups() const {
return mGroups;
}
void addGroup(const QString& group) {
mGroups.append(group);
}
void removeGroup(const QString& group) {
mGroups.removeOne(group);
}
void removeAllGroups() {
mGroups.clear();
}
bool hasGroup(const QString& group) {
return mGroups.contains(group);
}
private:
uid_t mUid;
gid_t mGid;
QString mName;
QString mFullName;
QString mShell;
QString mHomeDir;
QStringList mGroups;
};
class GroupInfo
{
public:
explicit GroupInfo(): mGid(0) {
}
explicit GroupInfo(struct group* grp):
mGid(grp->gr_gid),
mName(grp->gr_name)
{
}
gid_t gid() const {
return mGid;
}
void setGid(gid_t gid) {
mGid = gid;
}
QString name() const {
return mName;
}
void setName(const QString& name) {
mName = name;
}
const QStringList& members() const {
return mMembers;
}
void setMembers(const QStringList& members) {
mMembers = members;
}
void addMember(const QString& userName) {
mMembers.append(userName);
}
void removeMember(const QString& userName) {
mMembers.removeOne(userName);
}
void removeAllMemberss() {
mMembers.clear();
}
bool hasMember(const QString& userName) const {
return mMembers.contains(userName);
}
private:
gid_t mGid;
QString mName;
QStringList mMembers;
};
class UserManager : public QObject
{
Q_OBJECT
public:
explicit UserManager(QObject *parent = 0);
~UserManager();
const QList<UserInfo*>& users() const {
return mUsers;
}
const QList<GroupInfo*>& groups() const {
return mGroups;
}
const QStringList& availableShells();
bool addUser(UserInfo* user);
bool modifyUser(UserInfo* user, UserInfo* newSettings);
bool deleteUser(UserInfo* user);
bool changePassword(UserInfo* user, QByteArray newPasswd);
bool addGroup(GroupInfo* group);
bool modifyGroup(GroupInfo* group, GroupInfo* newSettings);
bool deleteGroup(GroupInfo* group);
bool changePassword(GroupInfo* group, QByteArray newPasswd);
// FIXME: add APIs to change group membership with "gpasswd"
UserInfo* findUserInfo(const char* name);
UserInfo* findUserInfo(QString name);
UserInfo* findUserInfo(uid_t uid);
GroupInfo* findGroupInfo(const char* name);
GroupInfo* findGroupInfo(QString name);
GroupInfo* findGroupInfo(gid_t gid);
private:
void loadUsersAndGroups();
void loadLoginDefs();
bool pkexec(const QStringList &command, const QByteArray &stdinData = QByteArray());
Q_SIGNALS:
void changed();
protected Q_SLOTS:
void onFileChanged(const QString &path);
void reload();
private:
QList<UserInfo*> mUsers;
QList<GroupInfo*> mGroups;
QFileSystemWatcher* mWatcher;
QStringList mAvailableShells;
};
#endif // USERMANAGER_H

@ -1,3 +0,0 @@
[Project]
Manager=KDevCMakeManager
Name=lxqt-admin
Loading…
Cancel
Save