--- kdeadmin-4.2.98.orig/debian/kpackage.manpages +++ kdeadmin-4.2.98/debian/kpackage.manpages @@ -0,0 +1 @@ +debian/man/out/kpackage.1 --- kdeadmin-4.2.98.orig/debian/copyright +++ kdeadmin-4.2.98/debian/copyright @@ -0,0 +1,178 @@ +This package was debianized by Ana Beatriz Guerrero Lopez on +Wed, 23 May 2007 18:15:59 +0200. + +It was downloaded from ftp://ftp.kde.org + +Upstream Author: The KDE development team +Numerous people, too many to count, have contributed to kdelibs as a +whole. The KDE project tries to make an extensive list of people who contributed +to KDE at http://www.kde.org/people/credits/ + +Copyright: +Unless something else is mentioned, copyright is +(C) 1996-2008, The K Desktop Enviroment project http://www.kde.org + + kcron: + Copyright (C) 1999, Gary Meyer + Copyright (C) 1999, Robert Berry + Copyright (C) 2007, Nicolas Ternisien + + kdat: + Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com + Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net + Copyright (C) 1997 Johannes Sixt + Copyright (C) 1996 Keith Brown and KtSoft + + knetworkconf: + Copyright (C) 2003-2005 by Juan Luis Baptiste + Copyright (C) 2000-2001 Ximian, inc + Copyright (C) Michael Vogt + Copyright (C) Grzegorz Golawski + Copyright (C) David Lee Ludwig + Copyright (C) Kenneth Christiansen + + kpackage: + Copyright (C) 1999-2007 Toivo Pedaste + Copyright (C) Damyan Pepper + + ksystemlog: + Copyright (C) 2007 Nicolas Ternisien + + ksysv: + Copyright (C) 1997-2000 Peter Putzer + Copyright (C) 1999 Preston Brown + Copyright (C) 2002 Waldo Bastian + + kuser: + Copyright (C) 1998 Denis Perchine + Copyright (C) 2004-2006 Szombathelyi Gyurgy + Copyright (C) 2002 Waldo Bastian + + lilo-config: + Copyright (C) 2000-2001 Bernhard Rosenkraenzer + + strigi-analyzer: + Copyright (C) 2002 Laurence Anderson + + system-config-printer-kde: + Copyright (C) 2008 Jonathan Riddell + Copyright (C) 2007 Tim Waugh + Copyright (C) 2007 Red Hat, Inc. + + + +License: + +Unless something else is mentioned, the code files in this package are under +the GNU General Public License: + + | This program is free software; you can redistribute it and/or modify + | it under the terms of the GNU General Public License as published by + | the Free Software Foundation; either version 2 of the License or, + | (at your option) any later version. + | + | This package is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, write to the Free Software Foundation, + | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + The full text of the GNU General Public License version 2 is available on + Debian systems in /usr/share/common-licenses/GPL-2. + + +Files under doc/ + +These files are under the GNU Free Documentation License v1.2 + + | Permission is granted to copy, distribute and/or modify this + | document under the terms of the GNU Free Documentation License, + | Version 1.1 or any later version published by the Free Software + | Foundation; with no Invariant Sections, with no Front-Cover Texts, + | and with no Back-Cover Texts. + + The full text of the GNU Free Documentation License is available on + Debian systems in /usr/share/common-licenses/GFDL-1.2 + + As well, all the Manpages.dox included are under this license, unless + specified otherwise below. + + +Files under kcron/ + + These files are under the GPL v2 or later. + + +Files under kdat/ + + These files are under the GPL v2 or later. + + +Files under knetworkconf/ + + These files are under the GPL v2 or later, with some files under + the LGPL v2 or later. + + +Files under kpackage/ + + These files are under the GPL v2 or later. + + +Files under ksysv/ + + These files are under the GPL v2 or later. Some under GPLv2only. Effectively GPLv2only. + + +Files under kuser/ + + These files are under the GPL v2 or later. Some under GPLv2only. Effectively GPLv2only. + + +Files under lilo-config/ + + These files are under the GPL v2 or later. + + +Files under strigi-analyzer/ + + These files are under the GPL v2. + +Files under system-config-printer-kde/ + + cmake/ is under bsd license (CMAKE-COPYING-SCRIPTS): + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Rest GPLv2 or later. + + + +The Debian packaging is (C) 2007-2008, Debian Qt/KDE Maintainers and +is licensed under the GPL, see `/usr/share/common-licenses/GPL'. + + --- kdeadmin-4.2.98.orig/debian/control +++ kdeadmin-4.2.98/debian/control @@ -0,0 +1,124 @@ +Source: kdeadmin +Section: kde +Priority: optional +Maintainer: Kubuntu Developers +XSBC-Original-Maintainer: Debian Qt/KDE Maintainers +Uploaders: Ana Beatriz Guerrero Lopez , Sune Vuorela , Fathi Boudra , Armin Berres , Matthew Rosewarne +Build-Depends: cdbs (>= 0.4.51), debhelper (>= 7), quilt, pkg-kde-tools (>= 0.4.2), + kdepimlibs5-dev (>= 4:4.2.98), docbook-to-man, python-qt4-dev, + python-kde4 (>= 4:4.2.98), system-config-printer-common, python-cups +Standards-Version: 3.8.0 +Homepage: http://www.kde.org/ +Vcs-Browser: http://bazaar.launchpad.net/~kubuntu-members/kdeadmin/ubuntu +Vcs-Bzr: https://code.launchpad.net/~kubuntu-members/kdeadmin/ubuntu + +Package: kdeadmin +Section: kde +Architecture: all +Depends: kcron (>= ${source:Version}), ksystemlog (>= ${source:Version}), + kuser (>= ${source:Version}) +Recommends: system-config-printer-kde (>= ${source:Version}) +Conflicts: kdeadmin-kde4 +Replaces: kdeadmin-kde4 +Description: system administration tools from the official KDE 4 release + KDE is produced by an international technology team that creates free and open + source software for desktop and portable computing. Among KDE's products are a + modern desktop system for Linux and UNIX platforms, comprehensive office + productivity and groupware suites and hundreds of software titles in many + categories including Internet and web applications, multimedia, entertainment, + educational, graphics and software development. + . + This metapackage includes a collection of system administration tools + provided with the official release of KDE 4. + +Package: kcron +Section: admin +Architecture: any +Depends: ${shlibs:Depends} +Suggests: khelpcenter +Conflicts: kcron-kde4 +Replaces: kcron-kde4 +Description: program scheduler for KDE 4 + KCron is a system settings module for scheduling programs to run at specific + intervals using cron, the UNIX scheduling service. + . + This package is part of the KDE 4 administration module. + +# Package: knetworkconf +# Section: net +# Architecture: any +# Depends: ${shlibs:Depends} +# Conflicts: knetworkconf-kde4 +# Replaces: knetworkconf-kde4 +# Description: network configuration tool for KDE 4 +# KNetworkConf is a system settings module to configure networking. +# It can be used to manage network devices, gateways, and host information. +# . +# This package is part of the KDE 4 administration module. + +Package: kpackage +Section: admin +Architecture: any +Depends: ${shlibs:Depends}, smartpm-core +Suggests: khelpcenter, rpm +Conflicts: kpackage-kde4 +Replaces: kpackage-kde4 +Description: package management tool for KDE 4 + KPackage is a frontend to the SMART package manager, supporting Debian, RPM, + and other package formats. It can be used to search for, examine, install, + and remove packages. + . + This package is part of the KDE 4 administration module. + +Package: ksystemlog +Section: admin +Architecture: any +Depends: ${shlibs:Depends} +Conflicts: ksystemlog-kde4 +Replaces: ksystemlog-kde4 +Description: system log viewer for KDE 4 + KSystemLog show all logs of your system, grouped by General (Default system + log, Authentication, Kernel, X.org...), and optional Services. (Apache, Cups, + etc, ...). It includes many features to read nicely your log files: + * Colorize log lines depending on their severities + * Tabbed view to allow displaying several logs at the same time + * Auto display new lines logged + * Detailed informations for each log lines + . + This package is part of the KDE 4 administration module. + +Package: kuser +Section: admin +Architecture: any +Depends: ${shlibs:Depends} +Suggests: khelpcenter +Conflicts: kuser-kde4 +Replaces: kuser-kde4 +Description: user and group administration tool for KDE 4 + KUser is an application for managing users and groups on your system. + . + This package is part of the KDE 4 administration module. + +Package: system-config-printer-kde +Section: admin +Architecture: all +Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, python-qt4-dbus, + python-kde4 (>= 4:4.2.0), system-config-printer-common (>= 0.7.80+svn1942-0ubuntu2), + hal-cups-utils +Description: KDE 4 printer configuration utility + This package contains a KDE4 based application which can be used to configure + and manage printers. + . + This package is part of the KDE 4 administration module. + +Package: kdeadmin-dbg +Section: libdevel +Architecture: any +Depends: kdebase-runtime-dbg, kdeadmin (= ${source:Version}) +Priority: extra +Conflicts: kdeadmin-dbg-kde4 +Replaces: kdeadmin-dbg-kde4 +Description: debugging symbols for kdeadmin + This package contains the debugging symbols associated with kdeadmin. + They will automatically be used by gdb for debugging kdeadmin-related + issues. --- kdeadmin-4.2.98.orig/debian/KUBUNTU-DEBIAN-DIFFERENCES +++ kdeadmin-4.2.98/debian/KUBUNTU-DEBIAN-DIFFERENCES @@ -0,0 +1,8 @@ + - Keep our conflicts/replaces on -kde4 packages + - Make kdeadmin not depend on kpackage, it's in universe + - Don't ship knetworkconf, it is utterly busted + - kdeadmin-dbg depends kdeadmin + - We ship kubuntu_01_use_sudo with kpackage + - For KDE 4.2, we ship trunk system-config-printer-kde + - Keep KCron description that sez it's a KConfig Module + - Don't keep KCron manpage, it's not a binary anymore --- kdeadmin-4.2.98.orig/debian/kpackage.install +++ kdeadmin-4.2.98/debian/kpackage.install @@ -0,0 +1,48 @@ +usr/bin/kpackage +usr/share/applications/kde4/kpackage.desktop +usr/share/doc/kde/HTML/en/kpackage/common +usr/share/doc/kde/HTML/en/kpackage/handle.png +usr/share/doc/kde/HTML/en/kpackage/index.cache.bz2 +usr/share/doc/kde/HTML/en/kpackage/index.docbook +usr/share/doc/kde/HTML/en/kpackage/install.png +usr/share/doc/kde/HTML/en/kpackage/left.png +usr/share/doc/kde/HTML/en/kpackage/right-change.png +usr/share/doc/kde/HTML/en/kpackage/right-dep.png +usr/share/doc/kde/HTML/en/kpackage/right-files.png +usr/share/doc/kde/HTML/en/kpackage/right-prop.png +usr/share/doc/kde/HTML/en/kpackage/root-prompt.png +usr/share/doc/kde/HTML/en/kpackage/searchf.png +usr/share/doc/kde/HTML/en/kpackage/searchl.png +usr/share/doc/kde/HTML/en/kpackage/search.png +usr/share/doc/kde/HTML/en/kpackage/uninstall.png +usr/share/icons/hicolor/128x128/apps/kpackage.png +usr/share/icons/hicolor/16x16/apps/kpackage.png +usr/share/icons/hicolor/22x22/apps/kpackage.png +usr/share/icons/hicolor/32x32/apps/kpackage.png +usr/share/icons/hicolor/48x48/apps/kpackage.png +usr/share/icons/hicolor/64x64/apps/kpackage.png +usr/share/kde4/apps/kpackage/kpackageui.rc +usr/share/kde4/apps/kpackage/pics/bnew.png +usr/share/kde4/apps/kpackage/pics/bsd.png +usr/share/kde4/apps/kpackage/pics/bupdated.png +usr/share/kde4/apps/kpackage/pics/cross.png +usr/share/kde4/apps/kpackage/pics/dbad.png +usr/share/kde4/apps/kpackage/pics/deb.png +usr/share/kde4/apps/kpackage/pics/dnew.png +usr/share/kde4/apps/kpackage/pics/dupdated.png +usr/share/kde4/apps/kpackage/pics/ftin.xpm +usr/share/kde4/apps/kpackage/pics/ftout.xpm +usr/share/kde4/apps/kpackage/pics/kiss.png +usr/share/kde4/apps/kpackage/pics/knew.png +usr/share/kde4/apps/kpackage/pics/kupdated.png +usr/share/kde4/apps/kpackage/pics/noball.png +usr/share/kde4/apps/kpackage/pics/ptick.png +usr/share/kde4/apps/kpackage/pics/question.png +usr/share/kde4/apps/kpackage/pics/rnew.png +usr/share/kde4/apps/kpackage/pics/rpm.png +usr/share/kde4/apps/kpackage/pics/rupdated.png +usr/share/kde4/apps/kpackage/pics/slack.png +usr/share/kde4/apps/kpackage/pics/snew.png +usr/share/kde4/apps/kpackage/pics/supdated.png +usr/share/kde4/apps/kpackage/pics/tick.png +usr/share/kde4/config.kcfg/kpackageSettings.kcfg --- kdeadmin-4.2.98.orig/debian/compat +++ kdeadmin-4.2.98/debian/compat @@ -0,0 +1 @@ +7 --- kdeadmin-4.2.98.orig/debian/installgen +++ kdeadmin-4.2.98/debian/installgen @@ -0,0 +1,21 @@ +[kcron] +from:/kcron/ + +[knetworkconf] +miss dst:usr/lib/pkgconfig/system-tools-backends.pc$ +from:/knetworkconf/ + +[kpackage] +from:/kpackage/ + +[ksystemlog] +from:/ksystemlog/ + +[kuser] +from:/kuser/ + +[system-config-printer-kde] +from:/system-config-printer-kde/ + +[lilo-config_virtual] +missing from:/lilo-config/ --- kdeadmin-4.2.98.orig/debian/kpackage.mime +++ kdeadmin-4.2.98/debian/kpackage.mime @@ -0,0 +1,2 @@ +application/x-deb; kpackage -caption "Package Manager" %s; nametemplate=%s.deb; test=test "$DISPLAY" != ""; priority=7 +application/x-rpm; kpackage -caption "Package Manager" %s; nametemplate=%s.rpm; test=test "$DISPLAY" != ""; priority=7 --- kdeadmin-4.2.98.orig/debian/ksystemlog.install +++ kdeadmin-4.2.98/debian/ksystemlog.install @@ -0,0 +1,10 @@ +usr/bin/ksystemlog +usr/share/applications/kde4/ksystemlog.desktop +usr/share/doc/kde/HTML/en/ksystemlog/common +usr/share/doc/kde/HTML/en/ksystemlog/filter-process.png +usr/share/doc/kde/HTML/en/ksystemlog/first-opening.png +usr/share/doc/kde/HTML/en/ksystemlog/groupby-hour.png +usr/share/doc/kde/HTML/en/ksystemlog/index.cache.bz2 +usr/share/doc/kde/HTML/en/ksystemlog/index.docbook +usr/share/doc/kde/HTML/en/ksystemlog/main-screen.png +usr/share/kde4/apps/ksystemlog/ksystemlogui.rc --- kdeadmin-4.2.98.orig/debian/README.source +++ kdeadmin-4.2.98/debian/README.source @@ -0,0 +1,6 @@ +This package uses quilt for upstream source code patch management. Please read +/usr/share/doc/quilt/README.source for more information how to apply, unapply, +add, modify or remove patches. + +Please note that /usr/share/doc/quilt/README.source is only available in quilt +version 0.46-4.1 or later. --- kdeadmin-4.2.98.orig/debian/kuser.install +++ kdeadmin-4.2.98/debian/kuser.install @@ -0,0 +1,18 @@ +usr/bin/kuser +usr/share/applications/kde4/kuser.desktop +usr/share/doc/kde/HTML/en/kuser/common +usr/share/doc/kde/HTML/en/kuser/index.cache.bz2 +usr/share/doc/kde/HTML/en/kuser/index.docbook +usr/share/doc/kde/HTML/en/kuser/kuser.png +usr/share/icons/hicolor/128x128/apps/kuser.png +usr/share/icons/hicolor/16x16/apps/kuser.png +usr/share/icons/hicolor/22x22/apps/kuser.png +usr/share/icons/hicolor/32x32/apps/kuser.png +usr/share/icons/hicolor/48x48/apps/kuser.png +usr/share/icons/hicolor/64x64/apps/kuser.png +usr/share/kde4/apps/kuser/icons/oxygen/22x22/actions/user-group-delete.png +usr/share/kde4/apps/kuser/icons/oxygen/22x22/actions/user-group-properties.png +usr/share/kde4/apps/kuser/kuserui.rc +usr/share/kde4/apps/kuser/pics/group.png +usr/share/kde4/apps/kuser/pics/user.png +usr/share/kde4/config.kcfg/kuser.kcfg --- kdeadmin-4.2.98.orig/debian/system-config-printer-kde.install +++ kdeadmin-4.2.98/debian/system-config-printer-kde.install @@ -0,0 +1,8 @@ +usr/share/kde4/apps/system-config-printer-kde/new-printer.ui +usr/share/kde4/apps/system-config-printer-kde/system-config-printer.ui +usr/share/kde4/apps/system-config-printer-kde/system-config-printer-kde.py +usr/share/kde4/apps/system-config-printer-kde/options.py +usr/share/kde4/apps/system-config-printer-kde/optionwidgets.py +usr/share/kde4/apps/system-config-printer-kde/ipp-browse-dialog.ui +usr/share/kde4/apps/system-config-printer-kde/smb-browse-dialog.ui +usr/share/kde4/services/system-config-printer-kde.desktop --- kdeadmin-4.2.98.orig/debian/kcron.install +++ kdeadmin-4.2.98/debian/kcron.install @@ -0,0 +1,10 @@ +usr/lib/kde4/kcm_cron.so +usr/share/doc/kde/HTML/en/kcron/common +usr/share/doc/kde/HTML/en/kcron/index.cache.bz2 +usr/share/doc/kde/HTML/en/kcron/index.docbook +usr/share/doc/kde/HTML/en/kcron/kcron.png +usr/share/doc/kde/HTML/en/kcron/kcronstart.png +usr/share/doc/kde/HTML/en/kcron/newtask.png +usr/share/doc/kde/HTML/en/kcron/newvariable.png +usr/share/doc/kde/HTML/en/kcron/print.png +usr/share/kde4/services/kcm_cron.desktop --- kdeadmin-4.2.98.orig/debian/kuser.manpages +++ kdeadmin-4.2.98/debian/kuser.manpages @@ -0,0 +1 @@ +debian/man/out/kuser.1 --- kdeadmin-4.2.98.orig/debian/rules +++ kdeadmin-4.2.98/debian/rules @@ -0,0 +1,4 @@ +#!/usr/bin/make -f + +include /usr/share/pkg-kde-tools/qt-kde-team/1/debian-qt-kde.mk + --- kdeadmin-4.2.98.orig/debian/changelog +++ kdeadmin-4.2.98/debian/changelog @@ -0,0 +1,1688 @@ +kdeadmin (4:4.2.98-0ubuntu2) karmic; urgency=low + + * Rebuild with new pkg-kde-tools to build translation templates + + -- Jonathan Riddell Wed, 29 Jul 2009 18:11:56 +0100 + +kdeadmin (4:4.2.98-0ubuntu1) karmic; urgency=low + + * New upstream release candidate: + - Bump build-depend versions + + -- Jonathan Thomas Tue, 21 Jul 2009 20:24:22 -0400 + +kdeadmin (4:4.2.96-0ubuntu1) karmic; urgency=low + + * New upstream release + - Bump build-depend versions + + -- Alessandro Ghersi Fri, 10 Jul 2009 13:32:52 +0200 + +kdeadmin (4:4.2.95-0ubuntu1) karmic; urgency=low + + * New upstream release + - bump KDE versions to 4.2.95 (KDE 4.3 RC) + + -- Steve Stalcup Sat, 27 Jun 2009 12:18:27 -0400 + +kdeadmin (4:4.2.90-0ubuntu1) karmic; urgency=low + + * New upstream release: + - Bump build-depend versions + + -- Jonathan Thomas Wed, 03 Jun 2009 20:09:15 -0400 + +kdeadmin (4:4.2.85-0ubuntu1) karmic; urgency=low + + * New upstream beta release: + - Bump build-depend versions + - Remove system-config-printer-kde trunk patch, integrated upstream + - Update .install files + + -- Jonathan Thomas Thu, 14 May 2009 14:22:44 -0400 + +kdeadmin (4:4.2.2-1ubuntu2) karmic; urgency=low + + * Remove kcron.manpages, it does not exist + + -- Jonathan Riddell Mon, 11 May 2009 08:40:30 +0000 + +kdeadmin (4:4.2.2-1ubuntu1) karmic; urgency=low + + [ Michael Casadevall ] + * Merge from debian unstable, remaining changes: + - debian/patches/kubuntu_01_use_sudo.diff + - Use sudo in kpackage + - debian/patches/kubuntu_02_system_config_printer_trunk.diff + - Closes LP: #272765 "Can't configure advanced printer options" + - Closes LP: #281727 "crashed with UnicodeEncodeError in on_tvMainList_cursor_changed()" + - Closes LP: #348975 "strange layout on advanced tab of printer setup" + - Closes LP: #318407 "crashed with TypeError in on_btnPrintTestPage_clicked" + + [ Jonathan Thomas ] + * Merge things a wee bit more + * Update KUBUNTU-DEBIAN-DIFFERENCES + + -- Michael Casadevall Tue, 05 May 2009 04:25:42 -0400 + +kdeadmin (4:4.2.2-0ubuntu3) karmic; urgency=low + + * Drop the kcron manpage as there is no kcron binary anymore (LP: #306266) + * Update kcron description to reflect that it is a system settings module + + -- Harald Sitter Wed, 29 Apr 2009 08:52:52 +0200 + +kdeadmin (4:4.2.2-1) unstable; urgency=low + + * New upstream release: + - KPackage's configure dialog has been redone. (Closes: #364737) + - Ksystemlog does not longer crash on updates of systemlog. (Closes: #420645) + + -- Ana Beatriz Guerrero Lopez Sun, 05 Apr 2009 04:37:37 +0200 + +kdeadmin (4:4.2.2-0ubuntu2) jaunty; urgency=low + + * Update kubuntu_02_system_config_printer_trunk.diff from trunk + - Closes LP: #272765 "Can't configure advanced printer options" + - Closes LP: #281727 "crashed with UnicodeEncodeError in on_tvMainList_cursor_changed()" + - Closes LP: #348975 "strange layout on advanced tab of printer setup" + - Closes LP: #318407 "crashed with TypeError in on_btnPrintTestPage_clicked" + + -- Jonathan Riddell Thu, 09 Apr 2009 22:05:44 +0100 + +kdeadmin (4:4.2.2-0ubuntu1) jaunty; urgency=low + + * New upstream release + - debian/control: Bump build-depends + - debian/patches/kubuntu_02_system_config_printer_trunk.diff: + + Fix the patch so it doesn't remove all the files in the + cmake-modules directory; we do need them. + - Remove system-config-printer-kde.desktop from the patch; no need + to meddle with the translations as we don't use the file. + + -- Andreas Wenning Sun, 29 Mar 2009 10:44:26 +0200 + +kdeadmin (4:4.2.1-1) experimental; urgency=low + + * New upstream release. + + +++ Changes by Modestas Vainius: + + * Point Debian Vcs URLs to pkg-kde/trunk (new location). + + -- Debian Qt/KDE Maintainers Wed, 04 Mar 2009 05:46:08 +0100 + +kdeadmin (4:4.2.1-0ubuntu5) jaunty; urgency=low + + * Update kubuntu_02_system_config_printer_trunk.diff from bzr + + -- Jonathan Riddell Fri, 27 Mar 2009 12:25:49 +0000 + +kdeadmin (4:4.2.1-0ubuntu4) jaunty; urgency=low + + * Drop the system-config-printer-kde depends on python-dev since it is no + longer required with kdebindings >= 4:4.2.1-0ubuntu4. + * Also drop the depends on python-kde4-dev since + '/usr/lib/python2.6/dist-packages/PyQt4/uic/widget-plugins/kde4.py' was + moved to python-kde4 + * Fixed the broken link in Vcs-browser + + -- Ryan Kavanagh Thu, 19 Mar 2009 10:39:57 -0400 + +kdeadmin (4:4.2.1-0ubuntu3) jaunty; urgency=low + + * Remove knetworkconf packaging, too buggy: + - Comment out in debian/control + - Move .install file entries to not-installed + - Remove kubuntu_03_fix_knetworkconf_scriptsdir.diff + * Edit kubuntu_02_system_config_printer.diff to place the KCM in the general + section instead of Advanced (LP: #331790) + + -- Jonathan Thomas Tue, 17 Mar 2009 14:46:17 -0400 + +kdeadmin (4:4.2.1-0ubuntu2) jaunty; urgency=low + + [ Jonathan Thomas ] + * Add kubuntu_03_fix_knetworkconf_scriptsdir.diff from Gentoo to give + knetworkconf some clue where to find its backend. (LP: #229366) + + [ Scott Kitterman ] + * Change vcs* fields in debian/control from Debian to Kubuntu repositories + + -- Scott Kitterman Mon, 09 Mar 2009 09:05:27 -0400 + +kdeadmin (4:4.2.1-0ubuntu1) jaunty; urgency=low + + * New upstream release + * debian/control: Bump build-depends versions + * Update kubuntu_02_system_config_printer_trunk.diff to make it apply + + -- Didier Roche Sat, 28 Feb 2009 21:58:34 +0100 + +kdeadmin (4:4.2.0-1) experimental; urgency=low + + * New upstream release. + + +++ Changes by Modestas Vainius: + + * Bump KDE build dependencies to 4.2.0. + * Bump Standards-Version to 3.8.0: add README.source. + * Remove explicit cmake build dependency. + * Add debian/installgen. + * Add system-config-printer-kde utility (new package): + - add 01_system_config_printer_kde_cupsutils.diff patch to fix import + paths of cupshelpers which are cupsutils on Debian; + - set INSTALL_SYSTEM_CONFIG_PRINTER cmake flag; + - build depend on python-support. + * Bump debian/compat and debhelper build dependency to v7 (to get more + sophisticated debian/tmp handling). + * Switch from internal debian/cdbs/kde.mk to pkg-kde-tools: + - build depend on pkg-kde-tools 0.4; + - remove debian/cdbs directory; + - replace debian/cdbs/kde.mk with + /usr/share/pkg-kde-tools/qt-kde-team/1/debian-qt-kde.mk in debian/rules. + + +++ Changes by Sune Vuorela: + + * Copyright file update. + + -- Debian Qt/KDE Maintainers Tue, 27 Jan 2009 08:18:57 +0100 + +kdeadmin (4:4.2.0-0ubuntu4) jaunty; urgency=low + + * Update kubuntu_02_system_config_printer_trunk.diff, LP: #331192 + Update for system-config-printer-common change + + -- Jonathan Riddell Tue, 24 Feb 2009 15:00:50 +0000 + +kdeadmin (4:4.2.0-0ubuntu3) jaunty; urgency=low + + * Fix series and system-config-printer-kde.install + + -- Jonathan Riddell Wed, 11 Feb 2009 18:35:01 +0000 + +kdeadmin (4:4.2.0-0ubuntu2) jaunty; urgency=low + + * Add kubuntu_02_system_config_printer_trunk.diff with changes from bzr branch + bzr+ssh://bazaar.launchpad.net/~kubuntu-members/system-config-printer/kcm-scpk/ + * Add depends on python-kde4-dev, python-dev for system-config-printer-kde + which seems to be needed for kcontrol modules in system settings + + -- Jonathan Riddell Wed, 11 Feb 2009 18:21:08 +0000 + +kdeadmin (4:4.2.0-0ubuntu1) jaunty; urgency=low + + * New upstream release: + - Bump build-depends versions for new upstream release + - Update install files for new files and the documentation install + location transition + - Update KUBUNTU-DEBIAN-DIFFERENCES to reflect a dropped patch + + -- Jonathan Thomas Thu, 22 Jan 2009 15:48:07 -0500 + +kdeadmin (4:4.1.96-0ubuntu1) jaunty; urgency=low + + * New upstream release + * Drop kubuntu_02_fix_crash_system-config-printer-kde.diff patch completely + * Bump versions in build-deps + * remove 'not-installed' file, not applicable + + -- Steve Stalcup Thu, 08 Jan 2009 17:38:01 -0500 + +kdeadmin (4:4.1.85-0ubuntu1) jaunty; urgency=low + + [ Harald Sitter ] + * Change Vcs-Browser to Launchpad and replace Vcs-Svn with Vcs-Bzr + + [ Richard Birnie ] + * New upstream release + * Added patch kubuntu_02_fix_crash_system-config-printer-kde.diff + Already committed in KDE svn. This patch can be dropped with RC1 + (LP: #306192) + * Bumped build-deps on kdepimlibs5-dev and python-kde4 to 4.1.85 + + -- Richard Birnie Mon, 15 Dec 2008 19:09:50 +0000 + +kdeadmin (4:4.1.80-0ubuntu1) jaunty; urgency=low + + [ Jonathan Thomas ] + * New upstream beta release + - Bump build-dep versions + - Remove kubuntu_02_add_delete_homedir.diff + + [ Harald Sitter ] + * Add system-config-printer-kde package + + build depend on python-qt4-dev, python-kde4, system-config-printer-common + and python-cups + + -- Harald Sitter Mon, 24 Nov 2008 21:58:45 +0100 + +kdeadmin (4:4.1.3-1) experimental; urgency=low + + * New upstream release + - bump build-deps + + -- Sune Vuorela Sat, 01 Nov 2008 17:25:41 +0100 + +kdeadmin (4:4.1.2-1ubuntu1) jaunty; urgency=low + + * Merge with Debian, remaining changes: + - Bump Standards-Version to 3.8.0 + - Use our custom kde4.mk + - Keep our kdepimlibs5-dev build-depend (>= 4:4.1.2) + - Keep our conflicts/replaces on -kde4 packages + - Make kdeadmin not depend on kpackage, it's in universe + - kdeadmin-dbg depends kdeadmin + - We ship lilo, so don't include not-installed changes + - We ship kubuntu_02_add_delete_homedir.diff with kuser + - We ship kubuntu_01_use_sudo with kpackage + - .orig md5sum different + * Updated KUBUNTU-DEBIAN-DIFFERENCES + + -- Jonathan Thomas Wed, 05 Nov 2008 14:25:08 -0500 + +kdeadmin (4:4.1.2-1) experimental; urgency=low + + * New upstream release. + * Update paths in knetworkconf.install. + + -- Ana Beatriz Guerrero Lopez Tue, 30 Sep 2008 15:08:40 +0200 + +kdeadmin (4:4.1.2-0ubuntu2) intrepid; urgency=low + + * Added kubuntu_02_add_delete_homedir.diff that makes the functions to + add/delete homedirs etc. actually being called. (LP: #278218) + + -- Andreas Wenning Sun, 19 Oct 2008 02:57:20 +0200 + +kdeadmin (4:4.1.2-0ubuntu1) intrepid; urgency=low + + * New upstream release. + + -- Jonathan Thomas Thu, 25 Sep 2008 15:15:39 -0400 + +kdeadmin (4:4.1.1-1) experimental; urgency=low + + * New upstreams release. + + -- Sune Vuorela Sun, 31 Aug 2008 23:43:14 +0200 + +kdeadmin (4:4.1.1-0ubuntu2) intrepid; urgency=low + + * Rebuild against kdelibs 4:4.1.1+really4.1.1 + + -- Harald Sitter Tue, 02 Sep 2008 03:15:10 +0200 + +kdeadmin (4:4.1.1-1) experimental; urgency=low + + * New upstreams release. + + -- Sune Vuorela Sun, 31 Aug 2008 23:43:14 +0200 + +kdeadmin (4:4.1.1-0ubuntu1) intrepid; urgency=low + + * New upstream release + + -- Jonathan Thomas (The man) Thu, 28 Aug 2008 16:10:02 -0400 + +kdeadmin (4:4.1.0-1) experimental; urgency=low + + * New upstream release. + * Remove 97_fix_target_link_libraries, no longer needed. + + -- Ana Beatriz Guerrero Lopez Mon, 28 Jul 2008 06:49:42 +0200 + +kdeadmin (4:4.1.0-0ubuntu3) intrepid; urgency=low + + * Make kdeadmin not depend on kpackage, it's in universe + + -- Jonathan Riddell Tue, 05 Aug 2008 11:12:54 +0100 + +kdeadmin (4:4.1.0-0ubuntu2) intrepid; urgency=low + + * switch to kde4.mk from cdbs + + -- Jonathan Riddell Fri, 01 Aug 2008 15:29:36 +0000 + +kdeadmin (4:4.1.0-1) experimental; urgency=low + + * New upstream release. + * Remove 97_fix_target_link_libraries, no longer needed. + + -- Ana Beatriz Guerrero Lopez Mon, 28 Jul 2008 06:49:42 +0200 + +kdeadmin (4:4.1.0-0ubuntu1) intrepid; urgency=low + + * New upstream release + * debian/control: + - bumped Build-Dep kdepimlibs5-dev to (>= 4:4.1.0) for KDE 4.1.0 release + + -- Guillaume Martres Thu, 24 Jul 2008 18:01:47 +0200 + +kdeadmin (4:4.0.98-1) experimental; urgency=low + + * New upstream release, Release Candidate 1. + + -- Ana Beatriz Guerrero Lopez Tue, 15 Jul 2008 00:45:37 +0200 + +kdeadmin (4:4.0.98-0ubuntu1) intrepid; urgency=low + + * New upstream release candidate release + * Bump Standards-Version to 3.8.0 + * -dbg depends kdeadmin + + -- Harald Sitter Sat, 12 Jul 2008 12:24:02 +0200 + +kdeadmin (4:4.0.84-1) experimental; urgency=low + + * New upstream snapshot + + -- Sune Vuorela Sun, 29 Jun 2008 14:01:16 +0200 + +kdeadmin (4:4.0.83-0ubuntu1) intrepid; urgency=low + + * New upstream beta release + + -- Jonathan Riddell Thu, 19 Jun 2008 11:45:14 +0000 + +kdeadmin (4:4.0.82+svn819867-1) experimental; urgency=low + + * New upstream snapshot. + * Update build-depends to >= 4:4.0.81. + + -- Ana Beatriz Guerrero Lopez Sun, 15 Jun 2008 23:15:14 +0200 + +kdeadmin (4:4.0.80-1ubuntu2) intrepid; urgency=low + + * Update kde.mk, use /usr/share/kde4/config for settings, mark + packages as Kubuntu not Debian + + -- Jonathan Riddell Mon, 09 Jun 2008 14:54:24 +0100 + +kdeadmin (4:4.0.80-1ubuntu1) intrepid; urgency=low + + * Merge with Debian + * Add conflicts on -kde4 packages + + -- Jonathan Riddell Wed, 28 May 2008 10:11:39 +0100 + +kdeadmin (4:4.0.80-1) experimental; urgency=low + + * New upstream snapshot. + + -- Fathi Boudra Sat, 24 May 2008 11:31:16 +0200 + +kdeadmin (4:4.0.74-1) experimental; urgency=low + + * New upstream snapshot. + * Update ksystemlog install file. + + -- Fathi Boudra Sun, 18 May 2008 00:36:54 +0200 + +kdeadmin (4:4.0.73-0ubuntu1) intrepid; urgency=low + + * New upstream development release, merge with Debian + + -- Jonathan Riddell Mon, 12 May 2008 13:17:36 +0100 + +kdeadmin (4:4.0.73+svn806431-1) UNRELEASED; urgency=low + + * New upstream snapshot: + - The latest upstream commit is r806431 by scripty + - Date: Sun May 11 11:54:06 2008 UTC + + * Update ksystemlog install file. + + -- Fathi Boudra Sun, 11 May 2008 18:03:59 +0200 + +kdeadmin (4:4.0.72-1) experimental; urgency=low + + * New upstream snapshot. + * Add 97_fix_target_link_libraries patch. + + -- Sune Vuorela Thu, 01 May 2008 00:38:56 +0200 + +kdeadmin (4:4.0.68+svn794641-1) experimental; urgency=low + + * New upstream snapshot. + + -- Ana Beatriz Guerrero Lopez Tue, 08 Apr 2008 18:25:56 +0200 + +kdeadmin (4:4.0.66+svn791114-1) experimental; urgency=low + + * First KDE 4.1 snapshot packaged. + * New application: KSystemLog. + * Update installed files. + * Bump build depends on >= 4.0.66. + + -- Ana Beatriz Guerrero Lopez Tue, 01 Apr 2008 15:40:48 +0200 + +kdeadmin (4:4.0.2-1) experimental; urgency=low + + * New upstream release. + + +++ Changes by Matthew Rosewarne: + + * Move knetworkconf to Section: net. + + -- Debian Qt/KDE Maintainers Wed, 13 Feb 2008 19:08:17 -0500 + +kdeadmin (4:4.0.1-1) experimental; urgency=low + + * New upstream release. + + +++ Changes by Ana Beatriz Guerrero Lopez: + + * Bump kdepimlibs5-dev build dependency to >= 4:4.0.1-1. + + +++ Changes by Fathi Boudra: + + * Bump compat/debhelper to 6. + * Add Vcs-Browser and Vcs-Svn fields. + + -- Debian Qt/KDE Maintainers Wed, 06 Feb 2008 18:45:28 +0100 + +kdeadmin (4:4.0.0-2) experimental; urgency=low + + +++ Changes by Matthew Rosewarne: + + * Tweak package descriptions. + * Add Depends: smartpm-core to kpackage and rpm Recommends to Suggests. + * Change kdeadmin-dbg Depends from kdelibs-dbg to kdebase-runtime-dbg. + * Use source:Version for kdeadmin metapackage. + * Add Suggests: kdeadmin to kdeadmin-dbg. + + -- Debian Qt/KDE Maintainers Sat, 26 Jan 2008 17:56:26 +0100 + +kdeadmin (4:4.0.0-1) experimental; urgency=low + + * New upstream version. + * Bump build-depends to >=4:4.0.0-1. + + +++ Changes by Matthew Rosewarne: + + * Add Homepage: to control. + * Tweak package descriptions. + * Replace source:Version with binary:Version. + + -- Ana Beatriz Guerrero Lopez Sat, 05 Jan 2008 14:29:22 +0100 + +kdeadmin (4:3.98.0~svn755919-1) experimental; urgency=low + + * New svn snapshot release to revision 755919. + * Update years in copyright. + + -- Ana Beatriz Guerrero Lopez Thu, 03 Jan 2008 21:13:13 +0100 + +kdeadmin (4:3.98.0~svn753247-1) experimental; urgency=low + + * Svn snapshot of revision 753247. + * Remove LDFLAGS+="-Wl,--as-needed". It was integrated into + cdbs/kde.mk. + * Update *.install files. + + -- Ana Beatriz Guerrero Lopez Fri, 28 Dec 2007 19:32:29 +0100 + +kdeadmin (4:3.97.0-1) experimental; urgency=low + + * New upstream release. + * Update Standards-Version to 3.7.3. + * Update *.install files and build-depends. + * Add export LDFLAGS+="-Wl,--as-needed" in rules to make dpkg-shlibdeps + happier. + + -- Ana Beatriz Guerrero Lopez Sat, 08 Dec 2007 02:40:11 +0100 + +kdeadmin (4:3.96.0-1) experimental; urgency=low + + * KDE 4.0 rc1, first upload to the Debian archive. + * Update *.install files. + * Split out programs: kcron, knetworkconf, kpackage and kuser. + * Update build-deps. + * Add not-installed file. + + -- Ana Beatriz Guerrero Lopez Fri, 23 Nov 2007 20:42:05 +0100 + +kdeadmin (4:3.90.1-1) experimental; urgency=low + + * Initial release. + + -- Ana Beatriz Guerrero Lopez Wed, 23 May 2007 18:15:59 +0200 + +kdeadmin (4:3.5.9-0ubuntu5) hardy; urgency=low + + * Added kubuntu_14_dhcp_knm_back.diff: + Knetworkmanager ignores cards defined in /etc/network/interfaces + When setting a card to dhcp procotol, get it removed from the + config file so that knetworkmanager sees it again + + -- Anthony Mercatante Thu, 03 Apr 2008 18:25:48 +0200 + +kdeadmin (4:3.5.9-0ubuntu4) hardy; urgency=low + + * Added kubuntu_13_no_samba_tweak.diff. + Knetworkconf reads smb.conf parameters but doesn't write them + causing the parameters to be removed from the config file. + Knetworkconf doesn't allow changing those, so there is no reason + to let it read them. + + -- Anthony Mercatante Thu, 03 Apr 2008 15:30:44 +0200 + +kdeadmin (4:3.5.9-0ubuntu3) hardy; urgency=low + + * Added workarround patch kubuntu_12_fix_localhost_for_sudo.patch + Avoids sudo to break due to 127.0.*.* beeing deleted. + + -- Anthony Mercatante Fri, 28 Mar 2008 11:41:56 +0100 + +kdeadmin (4:3.5.9-0ubuntu2) hardy; urgency=low + + * Add kubuntu_11_knetworkconf_icons.diff from Adam Spain, + closes LP: #93878 "low quality icons" + + -- Jonathan Riddell Mon, 03 Mar 2008 14:20:34 +0000 + +kdeadmin (4:3.5.9-0ubuntu1) hardy; urgency=low + + * New upstream release + + -- Jonathan Riddell Thu, 14 Feb 2008 12:27:05 +0000 + +kdeadmin (4:3.5.8-1ubuntu2) hardy; urgency=low + + * Run buildprep before upload + + -- Jonathan Riddell Thu, 15 Nov 2007 09:40:36 +0000 + +kdeadmin (4:3.5.8-1ubuntu1) hardy; urgency=low + + * Merge with Debian, remaining changes + - kubuntu_08_kpackage_sudo.diff, sudo support + - kubuntu_10_knetworkconf_localhost.diff, LP #66813 + * Add kubuntu_11_knetworkconf_8.04.diff for 8.04 detection in knetworkconf + + -- Jonathan Riddell Wed, 14 Nov 2007 17:25:38 +0000 + +kdeadmin (4:3.5.8-1) unstable; urgency=low + + * New upstream release. + * Implement use of uploaders.mk and update control. + + +++ Changes by Ana Beatriz Guerrero Lopez: + + * Update section in Debian menu files. + * Redo buildprep and dump build-dependencies to 3.5.8. + + -- Debian Qt/KDE Maintainers Thu, 11 Oct 2007 01:22:40 +0200 + +kdeadmin (4:3.5.8-0ubuntu1) gutsy; urgency=low + + * New upstream release + + -- Jonathan Riddell Tue, 09 Oct 2007 11:41:22 +0100 + +kdeadmin (4:3.5.7-1ubuntu2) gutsy; urgency=low + + * Fix build failure with g++-4.3. LP: #138590. + + -- Matthias Klose Thu, 13 Sep 2007 00:08:50 +0000 + +kdeadmin (4:3.5.7-1ubuntu1) gutsy; urgency=low + + * Merge with Debian for new upstream version + + -- Jonathan Riddell Wed, 23 May 2007 15:38:29 +0100 + +kdeadmin (4:3.5.7-1) unstable; urgency=low + + * New upstream release. + + -- Debian Qt/KDE Maintainers Tue, 15 May 2007 23:46:52 +0100 + +kdeadmin (4:3.5.6-2ubuntu1) gutsy; urgency=low + + * Merge with Debian + + -- Jonathan Riddell Mon, 30 Apr 2007 15:08:30 +0100 + +kdeadmin (4:3.5.6-2) unstable; urgency=low + + * Upload to unstable after Etch release. + * Update Uploaders. + + +++ Changes by Modestas Vainius: + + * knetworkconf RC bug fix: recognize allow-* statements in + /etc/network/interfaces as stanzas, not as ordinary options. This + misrecognition led to corruption of the interfaces file in case allow-* + stanza followed the iface stanza that new options were added to. Patch + no. 02 (Closes: #410144) + * Add myself to Uploaders. + + +++ Changes by Sune Vuorela: + * The debian cron does not know about this way of silencing tasks, so let us + remove the silence option (Patch 3) (Closes: 386157) + + -- Debian Qt/KDE Maintainers Thu, 19 Apr 2007 14:15:20 +0100 + +kdeadmin (4:3.5.6-1) experimental; urgency=low + + * New upstream release. + + -- Ana Beatriz Guerrero Lopez Tue, 16 Jan 2007 23:59:27 +0100 + +kdeadmin (4:3.5.5-3) unstable; urgency=medium + + +++ Changes by Sune Vuorela: + + * Make kdeaddons-dbg depend on kdelibs-dbg to get useful backtraces when + debugging. + * Really recognize sarge and etch stable versions (Closes: #405696, #387047). + + +++ Changes by Ana Beatriz Guerrero Lopez: + + * Update Uploaders. + + -- Debian Qt/KDE Maintainers Mon, 8 Jan 2007 10:17:47 +0100 + +kdeadmin (4:3.5.5-2) unstable; urgency=low + + +++ Changes by Ana Beatriz Guerrero Lopez: + + * Removed useless program secpolicy. (Closes: #399426) + + -- Debian Qt/KDE Maintainers Tue, 21 Nov 2006 00:00:56 +0100 + +kdeadmin (4:3.5.6-0ubuntu1) feisty; urgency=low + + * New upstream release + * Remove kubuntu_12_knetworkconf_feisty.diff, applied upstream + + -- Jonathan Riddell Wed, 17 Jan 2007 11:22:29 +0000 + +kdeadmin (4:3.5.5-1ubuntu4) feisty; urgency=low + + * Re-write kubuntu_12_kubuntu_feisty.diff since it didn't apply + on previous build + + -- Anthony Mercatante Fri, 19 Jan 2006 01:07:23 +0100 + +kdeadmin (4:3.5.5-1ubuntu3) feisty; urgency=low + + * Added kubuntu_12_knetworkconf_feisty.diff to properly autodetect + feisty as knetworkconf backend. + + -- Luka Renko Sun, 10 Dec 2006 16:16:12 +0100 + +kdeadmin (4:3.5.5-1ubuntu2) feisty; urgency=low + + * rebuild with --enable-gcc-hidden-visibility + + -- Jonathan Riddell Thu, 16 Nov 2006 19:39:16 +0000 + +kdeadmin (4:3.5.5-1ubuntu1) feisty; urgency=low + + * Merge with Debian + + -- Jonathan Riddell Wed, 15 Nov 2006 22:22:50 +0000 + +kdeadmin (4:3.5.5-1) unstable; urgency=low + + * New upstream release. + + +++ Changes by Christopher Martin: + + * Add a menu entry for secpolicy. Thanks to Vassilis Pandis. + (Closes: #382201) + + +++ Changes by Fathi Boudra: + + * Add support for Etch (patch commited upstream r586643). + Thanks to Sune Vuorela. (Closes: #387047) + + -- Debian Qt/KDE Maintainers Wed, 4 Oct 2006 20:13:07 -0400 + +kdeadmin (4:3.5.4-1) unstable; urgency=low + + * New upstream release. + + * KDE_3_5_BRANCH update (up to r567757). + + -- Debian Qt/KDE Maintainers Sat, 29 Jul 2006 20:46:53 -0400 + +kdeadmin (4:3.5.5-0ubuntu2) edgy; urgency=low + + * kubuntu_10_knetworkconf_localhost.diff added, hostname should not + be appended as alias to localhost in /etc/hosts + Closes Malone #66813 + + -- Luka Renko Thu, 19 Oct 2006 23:06:57 +0200 + +kdeadmin (4:3.5.5-0ubuntu1) edgy; urgency=low + + * New upstream release + * kubuntu_09_networkconf_edgy.diff removed, merged upstream + + -- Jonathan Riddell Tue, 3 Oct 2006 10:56:07 +0000 + +kdeadmin (4:3.5.4-0ubuntu3) edgy; urgency=low + + * Rebuild with latest cdbs to add gettext domain to .desktop files for + langpacks-desktopfiles-kde, no source changes + + -- Jonathan Riddell Tue, 5 Sep 2006 22:53:10 +0000 + +kdeadmin (4:3.5.4-0ubuntu2) edgy; urgency=low + + * Add kubuntu_09_networkconf_edgy.diff to support Edgy in knetworkconf + + -- Jonathan Riddell Mon, 7 Aug 2006 09:08:39 -0400 + +kdeadmin (4:3.5.4-0ubuntu1) edgy; urgency=low + + * New upstream release + + -- Jonathan Riddell Tue, 25 Jul 2006 10:12:17 +0000 + +kdeadmin (4:3.5.3-1ubuntu3) edgy; urgency=low + + * Add kubuntu_08_kpackage_sudo.diff, use sudo in kpackage, + closes Malone #47741 + + -- Jonathan Riddell Wed, 28 Jun 2006 17:40:42 +0000 + +kdeadmin (4:3.5.3-1ubuntu2) edgy; urgency=low + + * Rebuild with build-dep on latest kdelibs, fixes Qt binary compatibility break + + -- Jonathan Riddell Wed, 28 Jun 2006 16:11:40 +0000 + +kdeadmin (4:3.5.3-1ubuntu1) edgy; urgency=low + + * Merge with Debian + + -- Jonathan Riddell Tue, 27 Jun 2006 16:22:44 +0000 + +kdeadmin (4:3.5.3-1) unstable; urgency=low + + * New upstream release. + + Fixes x-debian-package/x-deb inconsistency. (Closes: #362968) + + Fixes "ksvg can't be closed" problem. (Closes: #354851) + + * KDE_3_5_BRANCH update (up to r548158). + + +++ Changes by Pierre Habouzit: + + * dash has an internal echo that does not know about -e. Force it to use + /bin/echo instead. (Closes: #358296) + + +++ Changes by Christopher Martin: + + * Fix kdeadmin description typo. (Closes: #364036) + + -- Debian Qt/KDE Maintainers Sun, 4 Jun 2006 18:11:09 -0400 + +kdeadmin (4:3.5.2-1) unstable; urgency=low + + * New upstream release. + + -- Debian Qt/KDE Maintainers Wed, 29 Mar 2006 13:13:03 -0500 + +kdeadmin (4:3.5.1-2) unstable; urgency=low + + +++ Changes by Christopher Martin: + + * Drop system-tools-backends.pc from knetworkconf, since it conflicts with + gnome-system-tools. (Closes: #353321) + + -- Debian Qt/KDE Maintainers Sun, 19 Feb 2006 14:30:28 -0500 + +kdeadmin (4:3.5.1-1) unstable; urgency=low + + * New upstream release. + + +++ Changes by Christopher Martin: + + * Upload to unstable. + + -- Debian Qt/KDE Maintainers Sun, 29 Jan 2006 10:10:44 -0500 + +kdeadmin (4:3.5.0-4) unstable; urgency=low + + +++ Changes by Christopher Martin: + + * Upload to unstable. + + * KDE_3_5_BRANCH update (up to r495373). + + -- Debian Qt/KDE Maintainers Sat, 7 Jan 2006 17:21:53 -0500 + +kdeadmin (4:3.5.0-3) experimental; urgency=low + + * Upload to experimental. + + * KDE_3_5_BRANCH update (up to r488946). + + -- Debian Qt/KDE Maintainers Fri, 16 Dec 2005 10:14:03 -0500 + +kdeadmin (4:3.5.2-0ubuntu8) dapper; urgency=low + + * debian/cdbs/kde.mk: + - added dh_iconcache. + + -- Daniel Holbach Thu, 18 May 2006 21:01:04 +0200 + +kdeadmin (4:3.5.2-0ubuntu7) dapper; urgency=low + + * Add kubuntu_07_enabled_dhcp.patch to fix problem where interface + without IP address was considered as down/disabled and therefore + preventing it do be enabled with ifup (Malone #38578) + + -- Luka Renko Sun, 30 Apr 2006 21:42:59 +0200 + +kdeadmin (4:3.5.2-0ubuntu6) dapper; urgency=low + + * Add kubuntu_06_route_byte_order.patch to fix wrong gateway due to + byte order on PPC (Malone: #23750) + * Add kubuntu_07_unmanaged_if.patch to fix problem with unamanaged + interface partially written to config file (Malone #18069) + + -- Luka Renko Fri, 28 Apr 2006 15:03:32 +0200 + +kdeadmin (4:3.5.2-0ubuntu5) dapper; urgency=low + + * Add kubuntu_03_dns_alias.diff to fix wrong warning about missing + alias in DNS server add dialog (Malone #35507) + * Add kubuntu_04_enable_apply.diff: before enable/disable interface + check if settings have been changed and ask user to apply + (Malone #35509) + * Add kubuntu_05_net_calc_crash.diff to fix crash in netmask/broadcast + calculation in case of empty/uninitialized fields (Malone #30775) + + -- Luka Renko Tue, 26 Apr 2006 00:07:20 +0200 + +kdeadmin (4:3.5.2-0ubuntu4) dapper; urgency=low + + * Added kubuntu_02_wep_key.diff to fix WEP key (Malone #24516) + + -- Luka Renko Mon, 24 Apr 2006 21:45:42 +0200 + +kdeadmin (4:3.5.2-0ubuntu3) dapper; urgency=low + + * Edit debian/cdbs/kde.mk to mark .po files as UTF-8 + + -- Jonathan Riddell Fri, 21 Apr 2006 19:14:28 +0100 + +kdeadmin (4:3.5.2-0ubuntu2) dapper; urgency=low + + * Add kubuntu_01_ubuntu_version.diff change dapper version number + + -- Jonathan Riddell Fri, 31 Mar 2006 00:50:12 +0100 + +kdeadmin (4:3.5.2-0ubuntu1) dapper; urgency=low + + * New upstream release + + -- Jonathan Riddell Mon, 20 Mar 2006 12:06:28 +0000 + +kdeadmin (4:3.5.1-0ubuntu1) dapper; urgency=low + + * New upstream release + + -- Jonathan Riddell Mon, 23 Jan 2006 14:26:06 +0000 + +kdeadmin (4:3.5.0-0ubuntu2) dapper; urgency=low + + * Add kubuntu_01_knetworkconf_branch_fixes.diff fixes + - http://bugzilla.ubuntu.com/9871 knetworkconf doesn't save gateway + - http://bugzilla.ubuntu.com/16921 knetworkconf too big for 1024x768 + - Ensure changes are applied when clicking OK and don't leave zombie + processes around + + -- Jonathan Riddell Mon, 19 Dec 2005 15:19:17 +0000 + +kdeadmin (4:3.5.0-0ubuntu1) dapper; urgency=low + + * New upstream release + + -- Jonathan Riddell Tue, 6 Dec 2005 12:26:57 +0000 + +kdeadmin (4:3.5-rc2-0ubuntu1) dapper; urgency=low + + * New upstream pre-release + * Generate .pot files + + -- Jonathan Riddell Mon, 21 Nov 2005 21:44:24 +0000 + +kdeadmin (4:3.5-rc1-1ubuntu1) dapper; urgency=low + + * Sync with Debian + + -- Jonathan Riddell Sun, 13 Nov 2005 16:22:21 +0000 + +kdeadmin (4:3.5.0-2) alioth; urgency=low + + * New upstream release. + + +++ Changes by Josh Metzler: + + * Create the new knetworkconf package. + + +++ Changes by Christopher Martin: + + * Bump DH_COMPAT to 5. No changes. + + * Add kdeadmin-dbg, to help track down problems. + + * Build lilo-config on amd64. + + -- Debian Qt/KDE Maintainers Thu, 1 Dec 2005 16:51:09 -0500 + +kdeadmin (4:3.4.3-2) unstable; urgency=low + + * Upload to unstable, rebuilding against kdelibs4c2a. + + * KDE_3_4_BRANCH update (up to r484392). + + -- Debian Qt/KDE Maintainers Wed, 30 Nov 2005 18:01:38 +0100 + +kdeadmin (4:3.4.3-1) experimental; urgency=low + + * New upstream release. + + -- Debian Qt/KDE Maintainers Sun, 16 Oct 2005 14:26:58 -0400 + +kdeadmin (4:3.4.2-1) unstable; urgency=low + + [ Debian Qt/KDE Maintainers ] + * New upstream release. + + +++ Changes by Luk Claes: + + * Added me to uploaders. + + -- Debian Qt/KDE Maintainers Fri, 26 Aug 2005 17:18:42 +0200 + +kdeadmin (4:3.4.1-1) experimental; urgency=low + + * New upstream release. + + -- Debian Qt/KDE Maintainers Tue, 31 May 2005 15:43:52 -0400 + +kdeadmin (4:3.4.3-0ubuntu1) breezy; urgency=low + + * New upstream release + + -- Jonathan Riddell Sun, 9 Oct 2005 02:21:28 +0000 + +kdeadmin (4:3.4.2-0ubuntu1) breezy; urgency=low + + * New upstream release + * Build using unsermake + + -- Jonathan Riddell Tue, 26 Jul 2005 16:24:00 +0000 + +kdeadmin (4:3.4.1-0ubuntu1) breezy; urgency=low + + * Update version number following KDE 3.4.1 release. + * Add all packaged back to meta-package + + -- Jonathan Riddell Wed, 1 Jun 2005 00:02:05 +0000 + +kdeadmin (4:3.4.1-0ubuntu0pre1) breezy; urgency=low + + * New upstream release + + -- Jonathan Riddell Tue, 24 May 2005 16:52:30 +0000 + +kdeadmin (4:3.4.0-0pre2) alioth; urgency=low + + * New upstream release. + + * Bugs reported in the Debian BTS fixed by this release: + + - no longer FTBFS on amd64/gcc-4.0, upstream applied patch by + Andreas Jochens. (Closes: #286998) + + * Converted packaging to CDBS. + + +++ Changes by Pierre Habouzit: + + * Recommends kdebase-bin for lilo-config (kdesu in the menu command). + * Remove kcmlinuz from Depends for kdeadmin meta package. + * Wrote a man page for kdat. + + * [debian/control] : + - reworked package descriptions. + - added myself to Uploaders. + + +++ Changes by Adeodato Simó: + + * Created XPM icons for packages having a menu file. Install them in + /usr/share/pixmaps and update the menu entries to use them. + + +++ Changes by Christopher Martin: + + * New kdeadmin-doc-html package, containing doc-base registered HTML + versions of application handbooks, for users without Konqueror or + KHelpCenter. + + -- Debian Qt/KDE Maintainers Thu, 7 Apr 2005 20:20:24 -0400 + +kdeadmin (4:3.3.2-1) unstable; urgency=low + + +++ Changes by Christopher Martin: + + * KDE_3_3_BRANCH update. + + * Change debian/copyright file to refer to licenses, instead of copyright, + when discussing KDE's licenses. + + +++ Changes by Isaac Clerencia: + + * Added myself to Uploaders + + -- Debian Qt/KDE Maintainers Sun, 23 Jan 2005 23:10:27 +0100 + +kdeadmin (4:3.3.2-0pre1) experimental; urgency=low + + * New upstream release. + * KDE_3_3_BRANCH update. + * Remove build-dependency on automake1.9. + + -- Christopher Martin Thu, 16 Dec 2004 13:59:53 -0500 + +kdeadmin (4:3.3.1-1) unstable; urgency=low + + * New upstream release. + * KDE_3_3_BRANCH update. + + -- Christopher L Cheney Thu, 4 Nov 2004 23:30:00 -0600 + +kdeadmin (4:3.3.0-2) unstable; urgency=low + + * KDE_3_3_BRANCH update. + + -- Christopher L Cheney Sat, 25 Sep 2004 23:51:24 -0500 + +kdeadmin (4:3.3.0-1) unstable; urgency=high + + * New upstream release. + + -- Christopher L Cheney Fri, 13 Aug 2004 23:30:00 -0500 + +kdeadmin (4:3.2.3-1) unstable; urgency=high + + * New upstream release. + + -- Christopher L Cheney Tue, 3 Aug 2004 14:00:00 -0500 + +kdeadmin (4:3.2.2-1) unstable; urgency=low + + * New upstream release. + * debian/kpackage.mime: fix the entries to use a proper + nametemplate. see also #235216. + * debian/*.menu: remove the obsolete kderemove tag. + + -- Christopher L Cheney Mon, 12 Apr 2004 01:00:00 -0500 + +kdeadmin (4:3.2.1-1) unstable; urgency=low + + * New upstream release. + + -- Christopher L Cheney Fri, 5 Mar 2004 18:00:00 -0600 + +kdeadmin (4:3.2.0-0pre1v1) experimental; urgency=low + + * New upstream release. + + -- Christopher L Cheney Wed, 18 Feb 2004 19:00:00 -0600 + +kdeadmin (4:3.1.95-1) unstable; urgency=low + + * New upstream release. + + -- Christopher L Cheney Fri, 23 Jan 2004 23:00:00 -0600 + +kdeadmin (4:3.1.5-1) unstable; urgency=low + + * New upstream release. + * Added libtool arm patch. + + -- Christopher L Cheney Mon, 12 Jan 2004 14:00:00 -0600 + +kdeadmin (4:3.1.4-2) unstable; urgency=low + + * Changed Maintainer to Debian Qt/KDE Maintainers + + -- Christopher L Cheney Tue, 6 Jan 2004 19:00:00 -0600 + +kdeadmin (4:3.1.4-1) unstable; urgency=low + + * New upstream release. + * Added patch to update autotools files. + * Added patch to remove pedantic-errors from KDE_CHECK_FUNC_EXT since it + causes configure checks to fail due to #line numbers being > 32767. + + -- Christopher L Cheney Thu, 16 Oct 2003 01:00:00 -0500 + +kdeadmin (4:3.1.3-1) unstable; urgency=low + + * New upstream release. + + -- Christopher L Cheney Fri, 1 Aug 2003 14:00:00 -0500 + +kdeadmin (4:3.1.2-1) unstable; urgency=low + + * New upstream release. + + -- Christopher L Cheney Thu, 22 May 2003 22:00:00 -0500 + +kdeadmin (4:3.1.1-1) unstable; urgency=low + + * New upstream release. + * Add 'chmod +x configure' to rules. (Closes: #181357, #181563) + + -- Christopher L Cheney Wed, 12 Mar 2003 01:00:00 -0600 + +kdeadmin (4:3.1.0-1) unstable; urgency=low + + * New upstream release. + * Rebuilt debian dir. + + -- Christopher L Cheney Mon, 03 Feb 2003 22:00:00 -0600 + +kdeadmin (4:2.2.2-7.2) stable-security; urgency=high + + * Non-maintainer upload by the Security Team + * Added special detection routine for big/little endianess on MIPS since + the line "byteorder : {big|little} endian" from /proc/cpuinfo was + removed as of Linux 2.4.20, resulting in the mipsel buildd being + unable to build this package. + + -- Martin Schulze Wed, 8 Jan 2003 20:01:04 +0100 + +kdeadmin (4:2.2.2-7.1) stable-security; urgency=high + + * Non-maintainer upload by the Security Team + * Applied upstream patches to fix several potential vulnerabilities. + http://www.kde.org/info/security/advisory-20021220-1.txt + + -- Martin Schulze Sun, 5 Jan 2003 21:09:43 +0100 + +kdeadmin (4:2.2.2-7) unstable; urgency=high + + * Fixed lilo Build-Dep (added [i386]) + + -- Christopher L Cheney Mon, 4 Mar 2002 08:00:00 -0600 + +kdeadmin (4:2.2.2-6) unstable; urgency=high + + * Changing Maintainer to Chris. + * Fixing PowerPC breakage. + + -- Daniel Stone Wed, 27 Feb 2002 21:28:09 +1100 + +kdeadmin (4:2.2.2-5) unstable; urgency=low + + * debian/control, kpackage/Makefile.am: + - Update kpackage for rpm 4.0.3, thanks Joey Hess. (Tighten [Build]Deps on + rpm, librpm0-dev->librpm-dev). (closes: #128195, #127948) + * debian/control: + - Tighten Build-Deps so it only builds with libpng2. + + -- Daniel Stone Tue, 1 Jan 2002 06:50:15 -0500 + +kdeadmin (4:2.2.2-4) unstable; urgency=low + + * Crap! I lost the Build-Dep on docbook-to-man in the merge between my -2 + and RevKrusty's; reinstated. (closes: #122044) + * Really install the new manpages. + + -- Daniel Stone Sun, 2 Dec 2001 11:23:19 +1100 + +kdeadmin (4:2.2.2-3) unstable; urgency=low + + * New maintainer. (closes: #114101) + * debian/{secpolicy,kwuftpd,kuser,ksysv,kpackage,kcron}.sgml: + - New manpages. + * secpolicy/main.cpp: fix this dodgyness, it now gives an actual description: + daniel@tsubasa:~/kde-2.2.2/kdeadmin-2.2.2/kdeadmin-2.2.2% ./secpolicy/secpolicy --help + Usage: secpolicy [Qt-options] [KDE-options] + What does this do? + + -- Daniel Stone Sat, 1 Dec 2001 23:59:40 +1100 + +kdeadmin (4:2.2.2-2) unstable; urgency=low + + * Sync with upstream + * Cleanup build process + * Update documentation for freeze + * Fix build-deps/deps/etc... + + -- Ivan E. Moore II Thu, 29 Nov 2001 04:15:00 -0700 + +kdeadmin (4:2.2.2-1) unstable; urgency=low + + * New upstream version + * use auto* again + * lintian cleanup + + -- Ivan E. Moore II Wed, 07 Nov 2001 19:26:00 -0700 + +kdeadmin (4:2.2.1-1.3) unstable; urgency=low + + * take out checks for auto* as it just hoses things + + -- Ivan E. Moore II Mon, 08 Oct 2001 19:26:00 -0700 + +kdeadmin (4:2.2.1-1.2) unstable; urgency=low + + * fix configure + + -- Ivan E. Moore II Fri, 05 Oct 2001 09:28:00 -0700 + +kdeadmin (4:2.2.1-1.1) unstable; urgency=low + + * Workaround for stupid automake 1.5 issues + + -- Ivan E. Moore II Wed, 03 Oct 2001 09:28:00 -0700 + +kdeadmin (4:2.2.1-1) unstable; urgency=low + + * New upstream version + * Change maintainer + * Lintian error cleanup + + -- Ivan E. Moore II Sat, 25 Aug 2001 14:31:00 -0700 + +kdeadmin (4:2.2.0-final-1) unstable; urgency=low + + * New upstream version 2.2 + + -- Ivan E. Moore II Mon, 30 Jul 2001 00:01:00 -0700 + +kdeadmin (4:2.2.0-0.1beta1-2) unstable; urgency=low + + * Use apt by default and not rpm for kpackage (Closes: #106937) + + -- Ivan E. Moore II Sat, 28 Jul 2001 18:33:00 -0700 + +kdeadmin (4:2.2.0-0.1beta1-1) unstable; urgency=low + + * sync with upstream + * gcc3 build fixes + * ksysctrl removed for now by upstream + + -- Ivan E. Moore II Thu, 26 Jul 2001 18:05:00 -0700 + +kdeadmin (4:2.2.0-0beta1-3) unstable; urgency=low + + * Depend on proper version of rpm so we don't crash (Closes: #103439) + * Sync with upstream + * More alpha build fixes + + -- Ivan E. Moore II Sat, 07 Jul 2001 03:25:00 -0700 + +kdeadmin (4:2.2.0-0beta1-2) unstable; urgency=low + + * Sync with upstream + * Autobuild for alpha now + + -- Ivan E. Moore II Tue, 03 Jul 2001 02:20:00 -0700 + +kdeadmin (4:2.2.0-0beta1-1) unstable; urgency=low + + * Sync with upstream + * fix mips build + + -- Ivan E. Moore II Sat, 30 Jun 2001 20:30:00 -0700 + +kdeadmin (4:2.2-cvs20010622-1) unstable; urgency=low + + * New upstream version + * 2.2 beta1 + * Adding in Enhances: tags + * New package kcmlinuz - linux kernel configuration gui + * Fix kpackage deps and crashes due to rpm (Closes: #99747, #97946) + * build with nis support + + -- Ivan E. Moore II Fri, 22 Jun 2001 06:30:00 -0700 + +kdeadmin (4:2.1.1-2) unstable; urgency=low + + * Update menu tags to include new kde menu removal tag + * Update build-depends to recognize real | virtual + * Adding in lintian overrides + + -- Ivan E. Moore II Sun, 08 Apr 2001 17:28:00 -0700 + +kdeadmin (4:2.1.1-1.0.1) unstable; urgency=low + + * Rebuild with older libc + + -- Ivan E. Moore II Mon, 26 Mar 2001 16:33:00 -0700 + +kdeadmin (4:2.1.1-1) unstable; urgency=low + + * New upstream version + + -- Ivan E. Moore II Mon, 19 Mar 2001 10:29:00 -0700 + +kdeadmin (4:2.1.0-3) unstable; urgency=low + + * Change Build-Depends and rebuild with new librpm packages (Closes: #89695) + + -- Ivan E. Moore II Thu, 15 Mar 2001 10:29:00 -0700 + +kdeadmin (4:2.1.0-2) unstable; urgency=low + + * Adding rpm to build-depends (Closes: #87412) + * Upstream fixes + + -- Ivan E. Moore II Sun, 11 Mar 2001 04:58:00 -0700 + +kdeadmin (4:2.1.0-1) unstable; urgency=low + + * Fresh CVS sync with future 2.1.1 version + * Fixing build process for non-i386 systems (Closes: #87412) + * Adding libbz2-dev to build-depends + + -- Ivan E. Moore II Sun, 04 Mar 2001 06:46:00 -0700 + +kdeadmin (4:2.1-final-1) unstable; urgency=low + + * New upstream version + * Updating standards version + + -- Ivan E. Moore II Mon, 19 Feb 2001 02:31:00 -0700 + +kdeadmin (4:2.1-beta2-1) unstable; urgency=low + + * New upstream beta + + -- Ivan E. Moore II Mon, 22 Jan 2001 06:00:00 -0700 + +kdeadmin (4:2.1-20010115-1) unstable; urgency=low + + * More upstream fixes + * Fixes assertion problems (Closes: #75073) + + -- Ivan E. Moore II Mon, 15 Jan 2001 01:00:00 -0700 + +kdeadmin (4:2.1-20010106-1) unstable; urgency=low + + * More upstream fixes + * Fixing depends as well as updating them + + -- Ivan E. Moore II Sat, 06 Jan 2001 23:30:00 -0700 + +kdeadmin (4:2.1-20010101-1) unstable; urgency=low + + * More upstream fixes + + -- Ivan E. Moore II Mon, 01 Jan 2001 17:05:00 -0700 + +kdeadmin (4:2.1-20001218-1) unstable; urgency=low + + * More upstream fixes + + -- Ivan E. Moore II Mon, 18 Dec 2000 13:11:00 -0700 + +kdeadmin (4:2.1-20001216-1) unstable; urgency=low + + * More upstream fixes + * Adding in conflicts for kdeadmin which I forgot to to along time ago + + -- Ivan E. Moore II Sat, 16 Dec 2000 23:50:00 -0700 + +kdeadmin (4:2.1-20001213-1) unstable; urgency=low + + * New upstream beta version + * Fix deb package indexing (Closes: #79060) + + -- Ivan E. Moore II Wed, 13 Dec 2000 18:00:00 -0700 + +kdeadmin (4:2.0-final-8) unstable; urgency=low + + * Fixing file conflicts (Closes: #77853) + + -- Ivan E. Moore II Sat, 25 Nov 2000 06:45:00 -0700 + +kdeadmin (4:2.0-final-7) unstable; urgency=low + + * More upstream fixes + * build rules cleanup + + -- Ivan E. Moore II Tue, 21 Nov 2000 04:45:00 -0700 + +kdeadmin (4:2.0-final-6) unstable; urgency=low + + * More upstream fixes + * More dependency cleanup - xlib6g vs xlibs + * ftp-server depends fixes + + -- Ivan E. Moore II Sat, 18 Nov 2000 00:45:00 -0700 + +kdeadmin (4:2.0-final-5) unstable; urgency=low + + * More upstream fixes + * More dependency cleanup + + -- Ivan E. Moore II Sat, 18 Nov 2000 00:45:00 -0700 + +kdeadmin (4:2.0-final-4) unstable; urgency=low + + * More upstream fixes + * adding menu hints + + -- Ivan E. Moore II Thu, 09 Nov 2000 22:45:00 -0700 + +kdeadmin (4:2.0-final-3) unstable; urgency=low + + * More upstream fixes + * build against new xlibs + + -- Ivan E. Moore II Sat, 04 Nov 2000 18:00:00 -0700 + +kdeadmin (4:2.0-final-2) unstable; urgency=low + + * More upstream fixes + * kdat no longer provided + + -- Ivan E. Moore II Thu, 02 Nov 2000 18:00:00 -0700 + +kdeadmin (4:2.0-final-0) unstable; urgency=low + + * KDE 2.0 + + -- Ivan E. Moore II Mon, 23 Oct 2000 00:00:00 -0700 + +kdeadmin (4:2.0-20001013-0) unstable; urgency=low + + * More upstream fixes + + -- Ivan E. Moore II Fri, 13 Oct 2000 23:45:00 -0700 + +kdeadmin (4:2.0-20001011-0) unstable; urgency=low + + * KDE 2.0 RC2 + + -- Ivan E. Moore II Thu, 11 Oct 2000 06:00:00 -0700 + +kdeadmin (4:2.0-20001006-0) unstable; urgency=low + + * More upstream fixes + + -- Ivan E. Moore II Fri, 06 Oct 2000 04:00:00 -0700 + +kdeadmin (4:2.0-20001005-0) unstable; urgency=low + + * More upstream fixes + * Compiling against non-versioned kdelibs once again + + -- Ivan E. Moore II Thu, 05 Oct 2000 15:00:00 -0700 + +kdeadmin (4:2.0-20001002-0) unstable; urgency=low + + * KDE 2.0 RC1 + + -- Ivan E. Moore II Mon, 02 Oct 2000 01:30:00 -0700 + +kdeadmin (4:2.0-20000927-0) unstable; urgency=low + + * More upstream fixes + * Building in RPM support to kpackage again. + + -- Ivan E. Moore II Thu, 28 Sep 2000 04:30:00 -0700 + +kdeadmin (4:2.0-20000925-0) unstable; urgency=low + + * More upstream fixes + * Updating build-depends + * Changing task dependencies (Closes: #72407, #72350, #72333) + + -- Ivan E. Moore II Mon, 25 Sep 2000 15:30:00 -0700 + +kdeadmin (4:2.0-20000920-0) unstable; urgency=low + + * More upstream fixes + + -- Ivan E. Moore II Wed, 20 Sep 2000 22:00:00 -0700 + +kdeadmin (4:2.0-20000918-0) unstable; urgency=low + + * More upstream fixes + * Breaking down kdeadmin into individual packages + * Changing section from utils to admin (Closes: #71870) + + -- Ivan E. Moore II Mon, 18 Sep 2000 18:00:00 -0700 + +kdeadmin (4:2.0-20000909-0) unstable; urgency=low + + * More upstream fixes + + -- Ivan E. Moore II Sat, 09 Sep 2000 22:00:00 -0700 + +kdeadmin (4:2.0-20000907-0) unstable; urgency=low + + * More upstream fixes + * Built against new QT 2.2 + + -- Ivan E. Moore II Thu, 07 Sep 2000 04:00:00 -0700 + +kdeadmin (4:2.0-20000901-0) unstable; urgency=low + + * More upstream fixes + * Merging package changes into upstream CVS + + -- Ivan E. Moore II Fri, 01 Sep 2000 17:00:00 -0700 + +kdeadmin (4:2.0-20000825-1.0) experimental; urgency=low + + * KDE 2.0 beta 4 + + -- Ivan E. Moore II Fri, 25 Aug 2000 22:30:00 -0700 + +kdeadmin (4:2.0-20000820-1.0) experimental; urgency=low + + * New upstream beta version + + -- Ivan E. Moore II Sun, 20 Aug 2000 09:30:00 -0700 + +kdeadmin-cvs (4:2.0-20000521-1.0) experimental; urgency=low + + * New upstream CVS version + + -- Ivan E. Moore II Sun, 21 May 2000 18:15:00 -0700 + +kdeadmin-cvs (4:2.0-20000512-1.1) experimental; urgency=low + + * New upstream CVS version + + -- Ivan E. Moore II Fri, 12 May 2000 22:30:00 -0700 + +kdeadmin-cvs (4:2.0-20000308-1.0) experimental; urgency=low + + * New upstream CVS version + + -- Ivan E. Moore II Wed, 08 Mar 2000 22:30:00 -0700 + +kdeadmin-cvs (4:2.0-20000302-1.0) experimental; urgency=low + + * New upstream CVS version + * Adding in build options for pam + + -- Ivan E. Moore II Thu, 02 Mar 2000 22:00:00 -0700 + +kdeadmin-cvs (4:2.0-20000229-1.0) experimental; urgency=low + + * New upstream CVS version + * Adding in build-depends + + -- Ivan E. Moore II Tue, 29 Feb 2000 22:00:00 -0700 + +kdeadmin-cvs (4:2.0-19991001-1) unstable; urgency=low + + * Cleaning out old workaround in menu.in + * Fixing up dependencies + + -- Ivan E. Moore II Fri, 01 Oct 1999 14:22:41 -0400 + +kdeadmin-cvs (4:2.0-19990820-1) unstable; urgency=low + + * new upstream CVS version + * migrating back to /usr from /opt + + -- Ivan E. Moore II Fri, 20 Aug 1999 14:22:41 -0400 + +kdeadmin-cvs (4:2.0-19990524-1) unstable; urgency=low + + * new upstream version + * migrating back to / from /opt + * migrating in some minor build changes + + -- Ivan E. Moore II Mon, 24 May 1999 07:00:41 -0400 + +kdeadmin (4:1.1-19990217-1) unstable; urgency=low + + * new upstream version + + -- Patricia Jung Wed, 17 Feb 1999 19:09:41 +0100 + +kdeadmin (4:1.1-19990207-3) unstable; urgency=low + + * fixed ScriptPath and RunlevelPath for ksysv + + -- Patricia Jung Thu, 11 Feb 1999 22:58:00 +0100 + +kdeadmin (4:1.1-19990207-2) unstable; urgency=low + + * fixed a bug with the wrong libjpeg version + + -- Stephan Kulow Tue, 9 Feb 1999 10:43:42 +0100 + +kdeadmin (4:1.1-19990207-1) unstable; urgency=low + + * new upstream version 1.1 and new epoche + + -- Stephan Kulow Sun, 7 Feb 1999 12:12:58 +0100 + +kdeadmin (2:980419-b4-1) unstable; urgency=low + + * new upstream version Beta4 + + -- Stephan Kulow Sun, 19 Apr 1998 18:20:53 +0200 + +kdeadmin (2:980402-1) frozen; urgency=low + + * new upstream version with bugfixes + + -- Stephan Kulow Thu, 2 Apr 1998 18:05:34 +0200 + +kdeadmin (2:980309-1) unstable; urgency=low + + * Initial Release. + + -- Stephan Kulow Tue, 10 Mar 1998 20:40:02 +0100 + --- kdeadmin-4.2.98.orig/debian/not-installed +++ kdeadmin-4.2.98/debian/not-installed @@ -0,0 +1,60 @@ +#This file serves no purpose that we can see, and conflicts +#with GNOME system tools, so be sure to leave it out. +./usr/lib/pkgconfig/system-tools-backends.pc + +#knetworkconf +./usr/lib/kde4/kcm_knetworkconfmodule.so +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/01.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/02.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/03.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/04.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/05.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/06.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/07.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/08.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/09.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/11.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/about1.png +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/common +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/index.cache.bz2 +./usr/share/doc/kde/HTML/en/kcontrol/knetworkconf/index.docbook +./usr/share/icons/hicolor/16x16/apps/knetworkconf.png +./usr/share/icons/hicolor/22x22/actions/network_connected_lan_knc.png +./usr/share/icons/hicolor/22x22/actions/network_disconnected_lan.png +./usr/share/icons/hicolor/22x22/actions/network_disconnected_wlan.png +./usr/share/icons/hicolor/22x22/actions/network_traffic_wlan.png +./usr/share/icons/hicolor/22x22/apps/knetworkconf.png +./usr/share/icons/hicolor/32x32/apps/knetworkconf.png +./usr/share/kde4/apps/knetworkconf/backends/debug.pl +./usr/share/kde4/apps/knetworkconf/backends/file.pl +./usr/share/kde4/apps/knetworkconf/backends/general.pl +./usr/share/kde4/apps/knetworkconf/backends/network-conf +./usr/share/kde4/apps/knetworkconf/backends/network.pl +./usr/share/kde4/apps/knetworkconf/backends/parse.pl +./usr/share/kde4/apps/knetworkconf/backends/platform.pl +./usr/share/kde4/apps/knetworkconf/backends/process.pl +./usr/share/kde4/apps/knetworkconf/backends/replace.pl +./usr/share/kde4/apps/knetworkconf/backends/report.pl +./usr/share/kde4/apps/knetworkconf/backends/service-list.pl +./usr/share/kde4/apps/knetworkconf/backends/service.pl +./usr/share/kde4/apps/knetworkconf/backends/util.pl +./usr/share/kde4/apps/knetworkconf/backends/xml.pl +./usr/share/kde4/apps/knetworkconf/pixmaps/ark.png +./usr/share/kde4/apps/knetworkconf/pixmaps/blackpanther.png +./usr/share/kde4/apps/knetworkconf/pixmaps/conectiva.png +./usr/share/kde4/apps/knetworkconf/pixmaps/debian.png +./usr/share/kde4/apps/knetworkconf/pixmaps/fedora.png +./usr/share/kde4/apps/knetworkconf/pixmaps/freebsd.png +./usr/share/kde4/apps/knetworkconf/pixmaps/gentoo.png +./usr/share/kde4/apps/knetworkconf/pixmaps/kubuntu.png +./usr/share/kde4/apps/knetworkconf/pixmaps/mandriva.png +./usr/share/kde4/apps/knetworkconf/pixmaps/openna.png +./usr/share/kde4/apps/knetworkconf/pixmaps/pld.png +./usr/share/kde4/apps/knetworkconf/pixmaps/redhat.png +./usr/share/kde4/apps/knetworkconf/pixmaps/slackware.png +./usr/share/kde4/apps/knetworkconf/pixmaps/specifix.png +./usr/share/kde4/apps/knetworkconf/pixmaps/suse.png +./usr/share/kde4/apps/knetworkconf/pixmaps/turbolinux.png +./usr/share/kde4/apps/knetworkconf/pixmaps/vine.png +./usr/share/kde4/apps/knetworkconf/pixmaps/yoper.png +./usr/share/kde4/services/kcm_knetworkconfmodule.desktop --- kdeadmin-4.2.98.orig/debian/man/kpackage.sgml +++ kdeadmin-4.2.98/debian/man/kpackage.sgml @@ -0,0 +1,349 @@ + manpage.1'. You may view + the manual page with: `docbook-to-man manpage.sgml | nroff -man | + less'. A typical entry in a Makefile or Makefile.am is: + +manpage.1: manpage.sgml + docbook-to-man $< > $@ + --> + + Daniel"> + Stone"> + October 21, 2001"> + 1"> + daniel@sfarc.net"> + + KPACKAGE"> + + + Debian GNU/Linux"> + GNU"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2001 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + Installs, removes, and queries packages. + + + + &dhpackage; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DESCRIPTION + + This manual page documents briefly the + &dhpackage; command. + + &dhpackage; is an application to install, remove + and query packages in many formats, including RPM and DEB. + + + + OPTIONS + + These programs follow the usual GNU command line syntax, + with long options starting with two dashes (`-'). A summary of + options is included below. However, the ordering is very strict - + --help/-h must come before hostname. + + + + + + + Show version information. + + + + + + + Show information about the author. + + + + + + + Show license information. + + + + + + + Specify the caption of the window. + + + + + + + Specify the icon of the window. + + + + + + + Specify the mini-icon of the window. + + + + + + + Specify the DCOP server to use. + + + + + + + Disable KDE crash handler (enables core dumps). + + + + + + + Waits for a compatible window manager to start. + + + + + + + Sets the application's GUI style (overrides KDE). + + + + + + + Sets the geometry of the window. + + + + + + + Specifies the X display to use. + + + + + + + Restores the application for the given session ID. + + + + + + + Forces use of an internal colour map on an 8-bit display. + + + + + + + Limits the number of colours allowed in an 8-bit display. + + + + + + + Forces Qt to never grab the mouse or keyboard. + + + + + + + Overrides --nograb, which may be implicitly set. + + + + + + + Forces synchronous mode (for debugging). + + + + + + + Sets the default application font. + + + + + + + Sets the default background colour and application + pallette. + + + + + + + Sets the default foreground colour. + + + + + + + Sets the default button colour. + + + + + + + Sets the application name. + + + + + + + Sets the application title. + + + + + + + Forces the application to use a True Colour visual on 8-bit + displays. + + + + + + + Sets X Input Method (XIM) input style. Possible values are: + onthespot, overthespot, offthespot, and root. + + + + + + + Sets X Input Method (XIM) server. + + + + + + + Disables X Input Method (XIM) support. + + + + + + + Perform the actions on remote server server via SSH. + + + + + + + Name of the file (package) to install. + + + + + + AUTHOR + + This manual page was written by &dhusername; <&dhemail;> for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the GNU General Public License + version 2 or any later version published by the Free Software Foundation. + + +
+ + --- kdeadmin-4.2.98.orig/debian/man/kuser.sgml +++ kdeadmin-4.2.98/debian/man/kuser.sgml @@ -0,0 +1,333 @@ + manpage.1'. You may view + the manual page with: `docbook-to-man manpage.sgml | nroff -man | + less'. A typical entry in a Makefile or Makefile.am is: + +manpage.1: manpage.sgml + docbook-to-man $< > $@ + --> + + Daniel"> + Stone"> + October 21, 2001"> + 8"> + daniel@sfarc.net"> + + KUSER"> + + + Debian GNU/Linux"> + GNU"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2001 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + Configures users on the system. + + + + &dhpackage; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DESCRIPTION + + This manual page documents briefly the + &dhpackage; command. + + &dhpackage; is an application to configure users on + the system. + + + + OPTIONS + + These programs follow the usual GNU command line syntax, + with long options starting with two dashes (`-'). A summary of + options is included below. However, the ordering is very strict - + --help/-h must come before hostname. + + + + + + + Show version information. + + + + + + + Show information about the author. + + + + + + + Show license information. + + + + + + + Specify the caption of the window. + + + + + + + Specify the icon of the window. + + + + + + + Specify the mini-icon of the window. + + + + + + + Specify the DCOP server to use. + + + + + + + Disable KDE crash handler (enables core dumps). + + + + + + + Waits for a compatible window manager to start. + + + + + + + Sets the application's GUI style (overrides KDE). + + + + + + + Sets the geometry of the window. + + + + + + + Specifies the X display to use. + + + + + + + Restores the application for the given session ID. + + + + + + + Forces use of an internal colour map on an 8-bit display. + + + + + + + Limits the number of colours allowed in an 8-bit display. + + + + + + + Forces Qt to never grab the mouse or keyboard. + + + + + + + Overrides --nograb, which may be implicitly set. + + + + + + + Forces synchronous mode (for debugging). + + + + + + + Sets the default application font. + + + + + + + Sets the default background colour and application + pallette. + + + + + + + Sets the default foreground colour. + + + + + + + Sets the default button colour. + + + + + + + Sets the application name. + + + + + + + Sets the application title. + + + + + + + Forces the application to use a True Colour visual on 8-bit + displays. + + + + + + + Sets X Input Method (XIM) input style. Possible values are: + onthespot, overthespot, offthespot, and root. + + + + + + + Sets X Input Method (XIM) server. + + + + + + + Disables X Input Method (XIM) support. + + + + + + AUTHOR + + This manual page was written by &dhusername; <&dhemail;> for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the GNU General Public License + version 2 or any later version published by the Free Software Foundation. + + +
+ + --- kdeadmin-4.2.98.orig/debian/patches/kubuntu_02_system_config_printer_trunk.diff +++ kdeadmin-4.2.98/debian/patches/kubuntu_02_system_config_printer_trunk.diff @@ -0,0 +1,11853 @@ +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/CMakeLists.txt kdeadmin-4.2.2/system-config-printer-kde/CMakeLists.txt +--- orig/kdeadmin-4.2.2/system-config-printer-kde/CMakeLists.txt 2009-01-01 16:27:18.000000000 +0000 ++++ kdeadmin-4.2.2/system-config-printer-kde/CMakeLists.txt 2009-04-09 22:56:36.000000000 +0100 +@@ -1,15 +1,13 @@ +-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules ) ++find_package( KDE4 REQUIRED ) + +-MACRO(PYKDE4_ADD_EXECUTABLE _pyname _exename) +- INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -DTARGET=${DATA_INSTALL_DIR}/system-config-printer-kde/${_pyname} -DLINK_NAME=${BIN_INSTALL_DIR}/${_exename} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/create_exe_symlink.cmake)" ) +-ENDMACRO(PYKDE4_ADD_EXECUTABLE) ++set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules ) + + macro_optional_find_package(PythonLibrary) + macro_optional_find_package(SIP) + + macro_optional_find_package(PyQt4) + IF(NOT PYQT4_FOUND) +- macro_log_feature(PYQT4_FOUND "PyQt4" "PyQt4 was not found. It is needed by system-config-printer-kde to run. (Use -DINSTALL_SYSTEM_CONFIG_PRINTER=TRUE to install anyway)" "http://www.riverbankcomputing.co.uk/software/pyqt/" FALSE) ++ macro_log_feature(PYQT4_FOUND "PyQt4" "PyQt4 was not found. It is needed by system-config-printer-kde to run. (Use -DINSTALL_SYSTEM_CONFIG_PRINTER=TRUE to install anyway)" "http://www.riverbankcomputing.co.uk/pyqt/" FALSE) + ENDIF(NOT PYQT4_FOUND) + + macro_optional_find_package(PyKDE) +@@ -35,10 +33,13 @@ + install( FILES + new-printer.ui + system-config-printer.ui +- system-config-printer-kde.py ++ kcm-scpk.py ++ options.py ++ optionwidgets.py ++ ipp-browse-dialog.ui ++ smb-browse-dialog.ui + DESTINATION ${DATA_INSTALL_DIR}/system-config-printer-kde ) +- PYKDE4_ADD_EXECUTABLE(system-config-printer-kde.py system-config-printer-kde) +- install(FILES system-config-printer-kde.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) ++ install(FILES kcm-scpk.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) + ENDIF(INSTALL_SYSTEM_CONFIG_PRINTER) + + macro_display_feature_log() +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/COMMENTS kdeadmin-4.2.2/system-config-printer-kde/COMMENTS +--- orig/kdeadmin-4.2.2/system-config-printer-kde/COMMENTS 1970-01-01 01:00:00.000000000 +0100 ++++ kdeadmin-4.2.2/system-config-printer-kde/COMMENTS 2009-04-09 22:56:08.000000000 +0100 +@@ -0,0 +1,13 @@ ++01:37 the menu/list on the left looks like a tree, will it eventually become a list like the other modules? icon and all? ++01:38 under configured printers, options and job options tabs, widgets dont have correct alignment ++01:38 job options is pretty scary looking too, we'll probably need to work on that ++01:38 i assume advanced is wip ++01:39 under policies tab, do you think the uesr and group permissions make sense? i know we discussed it a while ago as a way of doing it (or ++ someone else if not you) ++01:39 also.. remove should be disabled until you select a list item ++01:41 under settings, it takes a number of seconds for the change driver wizard to load after clicking the button. will this be improved eventually? ++01:41 also, is the change driver wizard within scope of what we can improve? (not going to comment on it now, but it could be tweaked) ++01:43 the remove printer button gets lost with the other printer buttons on that page. i'll have to think about what to do with that section, i dont ++ know where else remove printer could go ++01:45 the other parts of the UI, i'm not sure how much is up for debate. for example, the new printer wizard. also, i dont know much about print ++ server configuration and if those options are sufficient and presented in the best way +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/ipp-browse-dialog.ui kdeadmin-4.2.2/system-config-printer-kde/ipp-browse-dialog.ui +--- orig/kdeadmin-4.2.2/system-config-printer-kde/ipp-browse-dialog.ui 1970-01-01 01:00:00.000000000 +0100 ++++ kdeadmin-4.2.2/system-config-printer-kde/ipp-browse-dialog.ui 2009-04-09 22:56:08.000000000 +0100 +@@ -0,0 +1,124 @@ ++ ++ IPPBrowseDialog ++ ++ ++ Qt::NonModal ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 300 ++ ++ ++ ++ ++ 50 ++ false ++ ++ ++ ++ Qt::StrongFocus ++ ++ ++ IPP Browser ++ ++ ++ true ++ ++ ++ ++ ++ 21 ++ 250 ++ 361 ++ 41 ++ ++ ++ ++ ++ ++ ++ Refresh ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ Ok ++ ++ ++ Ctrl+O ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ 30 ++ 10 ++ 341 ++ 221 ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ true ++ ++ ++ true ++ ++ ++ 2 ++ ++ ++ ++ 1 ++ ++ ++ ++ ++ 1 ++ ++ ++ ++ ++ ++ ++ KPushButton ++ QPushButton ++
kpushbutton.h
++
++
++ ++ ++
+diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.desktop kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.desktop +--- orig/kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.desktop 1970-01-01 01:00:00.000000000 +0100 ++++ kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.desktop 2009-04-09 22:56:08.000000000 +0100 +@@ -0,0 +1,21 @@ ++[Desktop Entry] ++Exec=kcmshell4 kcm-scpk ++Icon=printer ++Type=Service ++X-KDE-ServiceTypes=KCModule ++X-DocPath=kcontrol/colors/index.html ++ ++X-KDE-Library=kpythonpluginfactory ++X-KDE-ParentApp=kcontrol ++X-KDE-PluginKeyword=system-config-printer-kde/kcm-scpk.py ++ ++X-KDE-System-Settings-Parent-Category=system ++X-KDE-Weight=60 ++ ++Name=Printer Configuration ++ ++Comment=Configure local and remote Printers ++ ++X-KDE-Keywords=python kcm ++ ++Categories=Qt;KDE;System; +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.py kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.py +--- orig/kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.py 1970-01-01 01:00:00.000000000 +0100 ++++ kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.py 2009-04-09 22:56:08.000000000 +0100 +@@ -0,0 +1,4035 @@ ++#!/usr/bin/env python ++# -*- coding: utf-8 -*- ++ ++############################################################################# ++## ++## Copyright 2007-2009 Canonical Ltd ++## Copyright 2008-2009 Richard Birnie ++## Author: Jonathan Riddell ++## Richard Birnie ++## ++## Includes code from System Config Printer: ++## Copyright (C) 2006, 2007, 2008 Red Hat, Inc. ++## Copyright (C) 2006, 2007 Florian Festi ++## Copyright (C) 2006, 2007, 2008 Tim Waugh ++## ++## This program is free software; you can redistribute it and/or ++## modify it under the terms of the GNU General Public License as ++## published by the Free Software Foundation; either version 2 of ++## the License, or (at your option) any later version. ++## ++## This program is distributed in the hope that it will be useful, ++## but WITHOUT ANY WARRANTY; without even the implied warranty of ++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++## GNU General Public License for more details. ++## ++## You should have received a copy of the GNU General Public License ++## along with this program. If not, see . ++## ++############################################################################# ++ ++MIN_REFRESH_INTERVAL = 1 # seconds ++import locale ++ ++import sys, os, time, traceback, re, tempfile, httplib, thread ++ ++#load modules from system-config-printer-common (debug, smburi), change path here if you have it installed elsewhere ++SYSTEM_CONFIG_PRINTER_DIR = "/usr/share/system-config-printer" ++if os.path.exists(SYSTEM_CONFIG_PRINTER_DIR + "/debug.py"): ++ sys.path.append(SYSTEM_CONFIG_PRINTER_DIR) ++ ++from PyQt4.QtCore import * ++from PyQt4.QtGui import * ++from PyQt4 import uic ++ ++from PyKDE4.kdecore import * ++from PyKDE4.kdeui import * ++from PyKDE4.kio import * ++ ++#use _() to keep code the same as gnome system-config-printer ++def _(string): ++ return unicode(i18n(string), "utf-8") ++ ++def translate(self, prop): ++ """reimplement method from uic to change it to use gettext""" ++ if prop.get("notr", None) == "true": ++ return self._cstring(prop) ++ else: ++ if prop.text is None: ++ return "" ++ text = prop.text.encode("UTF-8") ++ return i18n(text) ++ ++uic.properties.Properties._string = translate ++ ++import cups ++cups.require ("1.9.27") ++ ++# These come from system-config-printer ++import config ++import cupshelpers, options ++from optionwidgets import OptionWidget ++from smburi import SMBURI ++from debug import * ++ ++import dbus ++import dbus.mainloop.qt ++import dbus.service ++import urllib ++ ++ellipsis = unichr(0x2026) ++ ++try: ++ try_CUPS_SERVER_REMOTE_ANY = cups.CUPS_SERVER_REMOTE_ANY ++except AttributeError: ++ # cups module was compiled with CUPS < 1.3 ++ try_CUPS_SERVER_REMOTE_ANY = "_remote_any" ++ ++def validDeviceURI (uri): ++ """Returns True is the provided URI is valid.""" ++ if uri.find (":/") > 0: ++ return True ++ return False ++ ++if os.path.exists("system-config-printer.ui"): ++ APPDIR = QDir.currentPath() ++else: ++ file = KStandardDirs.locate("data", "system-config-printer-kde/system-config-printer.ui") ++ APPDIR = file.left(file.lastIndexOf("/")) ++ ++class PyKcm(KCModule): ++ def __init__(self, component_data, parent, gui): ++ KCModule.__init__(self, component_data, parent) ++ ++ uic.loadUi(APPDIR + "/" + "system-config-printer.ui", self) ++ self.setButtons(KCModule.Apply) ++ self.gui = gui ++ ++ def changed(self, state): ++ """a setting has changed, activate the Apply button""" ++ self.emit(SIGNAL("changed(bool)"), state) ++ ++ def save(self): ++ self.gui.on_btnPrinterPropertiesApply_clicked() ++ ++ def load(self): ++ self.gui.on_btnRevert_clicked() ++ ++class GUI(QWidget): ++ """our main class is the main window""" ++ ++ printer_states = { cups.IPP_PRINTER_IDLE: i18nc("Printer state", "Idle"), ++ cups.IPP_PRINTER_PROCESSING: i18nc("Printer state", "Processing"), ++ cups.IPP_PRINTER_BUSY: i18nc("Printer state", "Busy"), ++ cups.IPP_PRINTER_STOPPED: i18nc("Printer state", "Stopped") } ++ ++ ++ def makeui(self, component_data, parent): ++ self.ui = PyKcm(component_data, parent, self) ++ start_printer = None ++ change_ppd = False ++ ++ try: ++ self.language = locale.getlocale(locale.LC_MESSAGES) ++ self.encoding = locale.getlocale(locale.LC_CTYPE) ++ except: ++ nonfatalException() ++ os.environ['LC_ALL'] = 'C' ++ locale.setlocale (locale.LC_ALL, "") ++ self.language = locale.getlocale(locale.LC_MESSAGES) ++ self.encoding = locale.getlocale(locale.LC_CTYPE) ++ ++ self.printer = None ++ self.conflicts = set() # of options ++ self.connect_server = (self.printer and self.printer.getServer()) \ ++ or cups.getServer() ++ self.connect_user = cups.getUser() ++ self.password = '' #FIXME not in Gnome version ++ self.passwd_retry = False #FIXME not in Gnome version ++ self.widget_data_setting = {} #FIXME not in Gnome version ++ #FIXMEcups.setPasswordCB(self.cupsPasswdCallback) ++ ##self.server_is_publishing = False #FIXME new in Gnome version ++ ++ self.changed = set() # of options ++ ++ self.servers = set((self.connect_server,)) ++ ++ try: ++ self.cups = cups.Connection() ++ except RuntimeError: ++ self.cups = None ++ ++ # New Printer Dialog ++ self.newPrinterGUI = np = NewPrinterGUI(self) ++ ++ self.setConnected() ++ ++ self.ui.connect(self.ui.mainlist, SIGNAL("itemSelectionChanged()"), self.on_tvMainList_cursor_changed) ++ self.ui.connect(self.ui.mainlist, SIGNAL("currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)"), self.on_tvMainList_changed) ++ self.ui.connect(self.ui.chkServerBrowse, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) ++ self.ui.connect(self.ui.chkServerShare, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) ++ self.ui.connect(self.ui.chkServerShareAny, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) ++ self.ui.connect(self.ui.chkServerRemoteAdmin, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) ++ self.ui.connect(self.ui.chkServerAllowCancelAll, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) ++ self.ui.connect(self.ui.chkServerLogDebug, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) ++ ++ self.ui.connect(self.ui.btnChangePPD, SIGNAL("clicked()"), self.on_btnChangePPD_clicked) ++ self.ui.connect(self.ui.btnNewClass, SIGNAL("clicked()"), self.on_new_class_activate) ++ self.ui.connect(self.ui.btnNewPrinterNetwork, SIGNAL("clicked()"), self.on_new_printer_activate) ++ self.ui.connect(self.ui.btnPrintTestPage, SIGNAL("clicked()"), self.on_btnPrintTestPage_clicked) ++ self.ui.connect(self.ui.btnSelfTest, SIGNAL("clicked()"), self.on_btnSelfTest_clicked) ++ self.ui.connect(self.ui.btnCleanHeads, SIGNAL("clicked()"), self.on_btnCleanHeads_clicked) ++ ++ self.ui.connect(self.ui.btnNewJobOption, SIGNAL("clicked()"), self.on_btnNewJobOption_clicked) ++ self.ui.connect(self.ui.entNewJobOption, SIGNAL("textChanged(QString)"), self.on_entNewJobOption_changed) ++ ++ self.ui.connect(self.ui.entPDescription, SIGNAL("textEdited(const QString&)"), self.on_printer_changed) ++ self.ui.connect(self.ui.entPLocation, SIGNAL("textEdited(const QString&)"), self.on_printer_changed) ++ self.ui.connect(self.ui.chkPMakeDefault, SIGNAL("stateChanged(int)"), self.chkPMakeDefault_stateChanged) ++ self.ui.connect(self.ui.btnDelete, SIGNAL("clicked()"), self.btnDelete_clicked) ++ self.ui.connect(self.ui.entPDevice, SIGNAL("textEdited(const QString&)"), self.on_printer_changed) ++ self.ui.connect(self.ui.chkPEnabled, SIGNAL("stateChanged(int)"),self.on_printer_changed) ++ self.ui.connect(self.ui.chkPAccepting, SIGNAL("stateChanged(int)"), self.on_printer_changed) ++ self.ui.connect(self.ui.chkPShared, SIGNAL("stateChanged(int)"), self.on_printer_changed) ++ self.ui.connect(self.ui.cmbPStartBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed) ++ self.ui.connect(self.ui.cmbPEndBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed) ++ self.ui.connect(self.ui.rbtnPAllow, SIGNAL("toggled(bool)"), self.on_printer_changed) ++ self.ui.connect(self.ui.btnPAddUser, SIGNAL("clicked()"), self.btnPAddUser_clicked) ++ self.ui.connect(self.ui.btnPDelUser, SIGNAL("clicked()"), self.btnPDelUser_clicked) ++ ++ self.ui.connect(self.ui.btnClassAddMember, SIGNAL("clicked()"), self.on_btnClassAddMember_clicked) ++ self.ui.connect(self.ui.btnClassDelMember, SIGNAL("clicked()"), self.on_btnClassDelMember_clicked) ++ ++ self.ui.mainlist.header().hide() ++ ++ self.policiesTabWidget = self.ui.ntbkPrinter.widget(1) ++ self.memberTabWidget = self.ui.ntbkPrinter.widget(2) ++ self.optionsTabWidget = self.ui.ntbkPrinter.widget(3) ++ ++ self.ui.btnClassAddMember.setIcon(KIcon("arrow-left")) ++ self.ui.btnClassDelMember.setIcon(KIcon("arrow-right")) ++ self.mainListSelectedName = None ++ self.mainListSelectedType = None ++ ++ # Job Options widgets. ++ opts = [ options.OptionAlwaysShown ("copies", int, 1, ++ self.ui.sbJOCopies, ++ self.ui.btnJOResetCopies), ++ options.OptionAlwaysShownSpecial \ ++ ("orientation-requested", int, 3, ++ self.ui.cmbJOOrientationRequested, ++ self.ui.btnJOResetOrientationRequested, ++ combobox_map = [3, 4, 5, 6], ++ special_choice=_("Automatic rotation")), ++ ++ options.OptionAlwaysShown ("fitplot", bool, False, ++ self.ui.cbJOFitplot, ++ self.ui.btnJOResetFitplot), ++ ++ options.OptionAlwaysShown ("number-up", int, 1, ++ self.ui.cmbJONumberUp, ++ self.ui.btnJOResetNumberUp, ++ combobox_map=[1, 2, 4, 6, 9, 16]), ++ ++ options.OptionAlwaysShown ("number-up-layout", str, "lrtb", ++ self.ui.cmbJONumberUpLayout, ++ self.ui.btnJOResetNumberUpLayout, ++ combobox_map = [ "lrtb", ++ "lrbt", ++ "rltb", ++ "rlbt", ++ "tblr", ++ "tbrl", ++ "btlr", ++ "btrl" ]), ++ ++ options.OptionAlwaysShown ("brightness", int, 100, ++ self.ui.sbJOBrightness, ++ self.ui.btnJOResetBrightness), ++ ++ options.OptionAlwaysShown ("finishings", int, 3, ++ self.ui.cmbJOFinishings, ++ self.ui.btnJOResetFinishings, ++ combobox_map = [ 3, 4, 5, 6, ++ 7, 8, 9, 10, ++ 11, 12, 13, 14, ++ 20, 21, 22, 23, ++ 24, 25, 26, 27, ++ 28, 29, 30, 31, ++ 50, 51, 52, 53 ], ++ use_supported = True), ++ ++ options.OptionAlwaysShown ("job-priority", int, 50, ++ self.ui.sbJOJobPriority, ++ self.ui.btnJOResetJobPriority), ++ ++ options.OptionAlwaysShown ("media", str, ++ "A4", # This is the default for ++ # when media-default is ++ # not supplied by the IPP ++ # server. Fortunately it ++ # is a mandatory attribute. ++ self.ui.cmbJOMedia, ++ self.ui.btnJOResetMedia, ++ use_supported = True), ++ ++ options.OptionAlwaysShown ("sides", str, "one-sided", ++ self.ui.cmbJOSides, ++ self.ui.btnJOResetSides, ++ combobox_map = ++ [ "one-sided", ++ "two-sided-long-edge", ++ "two-sided-short-edge" ]), ++ ++ options.OptionAlwaysShown ("job-hold-until", str, ++ "no-hold", ++ self.ui.cmbJOHoldUntil, ++ self.ui.btnJOResetHoldUntil, ++ use_supported = True), ++ ++ options.OptionAlwaysShown ("mirror", bool, False, ++ self.ui.cbJOMirror, ++ self.ui.btnJOResetMirror), ++ ++ options.OptionAlwaysShown ("scaling", int, 100, ++ self.ui.sbJOScaling, ++ self.ui.btnJOResetScaling), ++ ++ ++ options.OptionAlwaysShown ("saturation", int, 100, ++ self.ui.sbJOSaturation, ++ self.ui.btnJOResetSaturation), ++ ++ options.OptionAlwaysShown ("hue", int, 0, ++ self.ui.sbJOHue, ++ self.ui.btnJOResetHue), ++ ++ options.OptionAlwaysShown ("gamma", int, 1000, ++ self.ui.sbJOGamma, ++ self.ui.btnJOResetGamma), ++ ++ options.OptionAlwaysShown ("cpi", float, 10.0, ++ self.ui.sbJOCpi, self.ui.btnJOResetCpi), ++ ++ options.OptionAlwaysShown ("lpi", float, 6.0, ++ self.ui.sbJOLpi, self.ui.btnJOResetLpi), ++ ++ options.OptionAlwaysShown ("page-left", int, 18, ++ self.ui.sbJOPageLeft, ++ self.ui.btnJOResetPageLeft), ++ ++ options.OptionAlwaysShown ("page-right", int, 18, ++ self.ui.sbJOPageRight, ++ self.ui.btnJOResetPageRight), ++ ++ options.OptionAlwaysShown ("page-top", int, 36, ++ self.ui.sbJOPageTop, ++ self.ui.btnJOResetPageTop), ++ ++ options.OptionAlwaysShown ("page-bottom", int, 36, ++ self.ui.sbJOPageBottom, ++ self.ui.btnJOResetPageBottom), ++ ++ options.OptionAlwaysShown ("prettyprint", bool, False, ++ self.ui.cbJOPrettyPrint, ++ self.ui.btnJOResetPrettyPrint), ++ ++ options.OptionAlwaysShown ("wrap", bool, False, self.ui.cbJOWrap, ++ self.ui.btnJOResetWrap), ++ ++ options.OptionAlwaysShown ("columns", int, 1, ++ self.ui.sbJOColumns, ++ self.ui.btnJOResetColumns), ++ ] ++ self.job_options_widgets = {} ++ self.job_options_buttons = {} ++ for option in opts: ++ self.job_options_widgets[option.widget] = option ++ self.job_options_buttons[option.button] = option ++ self.connect(option.button, SIGNAL("clicked()"), self.on_job_option_reset) ++ if type(option.widget) == QSpinBox: ++ self.connect(option.widget, SIGNAL("valueChanged(int)"), self.on_job_option_changed) ++ elif type(option.widget) == QComboBox: ++ self.connect(option.widget, SIGNAL("currentIndexChanged(int)"), self.on_job_option_changed) ++ elif type(option.widget) == QCheckBox: ++ self.connect(option.widget, SIGNAL("stateChanged(int)"), self.on_job_option_changed) ++ else: ++ raise RuntimeError ++ ++ try: ++ self.populateList(start_printer, change_ppd) ++ except cups.HTTPError, (s,): ++ self.cups = None ++ self.setConnected() ++ self.populateList() ++ self.show_HTTP_Error(s) ++ ++ #hide some bits until implemented ++ self.ui.btnNewPrinter.hide() ++ self.ui.newPrinterLabel.hide() ++ self.ui.btnNewPrinterSpecial.hide() ++ self.ui.newPrinterSpecialLabel.hide() ++ self.ui.entPName.hide() ++ self.ui.lblPName.hide() ++ ++ #catch the currentItemChanged signal. This should stop the ++ # 'Do you want to save settings' pop-up at startup ++ self.ui.mainlist.blockSignals(True) ++ self.ui.mainlist.setCurrentItem(self.settingsItem) ++ self.ui.mainlist.blockSignals(False) #unblock the signal ++ ++ #FIXME hide labels until implemented ++ self.ui.lblPOptions.hide() ++ self.ui.lblPInstallOptions.hide() ++ ++ return self.ui ++ ++ # now called dests_iconview_item_activated() in the Gnome version ++ def on_tvMainList_cursor_changed(self): ++ if self.changed: ++ # The unapplied changes for this item have not been saved, ++ # and the user just pressed "Cancel". ++ #FIXME, should offer dialog prompting to save or cancel here ++ return ++ items = self.ui.mainlist.selectedItems() ++ ++ if len(items) < 1: ++ return ++ item = items[0] ++ ++ #FIXME only show settings until ready for the rest ++ #item = self.settingsItem ++ type = unicode(item.text(1)) ++ name = unicode(item.text(0)) ++ ++ #name, type = self.getSelectedItem() ++ #model, self.mainListSelected = self.tvMainList.get_selection().get_selected() ++ #Save the values incase it gets deselected ++ self.mainListSelectedType = type ++ self.mainListSelectedName = name ++ item_selected = True ++ if type == "New": ++ self.ui.ntbkMain.setCurrentIndex(0) ++ elif type == "Settings": ++ self.ui.ntbkMain.setCurrentIndex(1) ++ if self.cups: ++ self.fillServerTab() ++ else: ++ # No connection to CUPS. Make sure the Apply/Revert buttons ++ # are not sensitive. ++ self.setDataButtonState() ++ item_selected = False ++ elif type in ['Printer', 'Class']: ++ try: ++ self.fillPrinterTab(name) ++ # the below not needed, fillPrinterTab() already calls fillPrinterOptions() ++ ##self.fillPrinterOptions("foo", True) #FIXME parameters need fixing ++ self.setDataButtonState() ++ self.ui.ntbkPrinter.setCurrentIndex(0) ++ except RuntimeError: ++ # Perhaps cupsGetPPD2 failed for a browsed printer. ++ self.ui.ntbkMain.setCurrentIndex(3) ++ return ++ ++ self.ui.printerNameLabel.setText(name) ++ self.ui.ntbkMain.setCurrentIndex(2) ++ elif type == "None": ++ self.ui.ntbkMain.setCurrentIndex(3) ++ self.setDataButtonState() ++ item_selected = False ++ ++ """FIXME, copy button ++ is_local = item_selected and not self.printers[name].discovered ++ for widget in [self.copy, self.btnCopy]: ++ widget.set_sensitive(item_selected) ++ for widget in [self.delete, self.btnDelete]: ++ widget.set_sensitive(is_local) ++ """ ++ ++ def printer_properties_response(self): ++ name, type = self.getSelectedItem() ++ if type in ("Printer", "Class"): ++ return self.save_printer(self.printer) ++ elif type == "Settings": ++ return self.save_serversettings() ++ ++ @pyqtSignature("") ++ def on_tvMainList_changed(self, new, old): ++ """about to change, offer to save""" ++ if self.changed: ++ answer = KMessageBox.questionYesNo(self, "Do you want to save changes?", "Save Changes", KStandardGuiItem.save(), KStandardGuiItem.discard() ) ++ ++ if answer == KMessageBox.Yes: #save is equivalent to yes ++ self.printer_properties_response() ++ elif answer == KMessageBox.No: #discard is equivalent to no ++ self.changed = set() # avoid asking the user ++ ++ def busy (self, win = None): ++ try: ++ if not win: ++ win = self ++ win.setCursor(Qt.WaitCursor) ++ KApplication.processEvents() ++ except: ++ nonfatalException () ++ ++ def ready (self, win = None): ++ try: ++ if not win: ++ win = self ++ win.setCursor(Qt.ArrowCursor) ++ KApplication.processEvents() ++ except: ++ nonfatalException () ++ ++ def setConnected(self): ++ connected = bool(self.cups) ++ ++ host = cups.getServer() ++ ++ if host[0] == '/': ++ host = 'localhost' ++ self.setWindowTitle(i18n("Printer configuration - %1", host)) ++ ++ if connected: ++ status_msg = i18n("Connected to %1", host) ++ else: ++ status_msg = i18n("Not connected") ++ #FIXME do we want a statusbar? ++ #self.statusbarMain.push(self.status_context_id, status_msg) ++ ++ for widget in (#FIXMEself.btnNewPrinter, self.btnNewClass, ++ #self.new_printer, self.new_class, ++ self.ui.chkServerBrowse, self.ui.chkServerShare, ++ self.ui.chkServerRemoteAdmin, ++ self.ui.chkServerAllowCancelAll, ++ self.ui.chkServerLogDebug): ++ widget.setEnabled(connected) ++ ++ sharing = self.ui.chkServerShare.isChecked () ++ self.ui.chkServerShareAny.setEnabled (sharing) ++ ++ try: ++ del self.server_settings ++ except: ++ pass ++ ++ def populateList(self, start_printer = None, change_ppd = False): ++ old_name, old_type = self.getSelectedItem() ++ if self.ui.ntbkMain.currentIndex() == 1: ++ serverPageShowing = True ++ else: ++ serverPageShowing = False ++ ++ select_path = None ++ ++ if self.cups: ++ try: ++ # get Printers ++ self.printers = cupshelpers.getPrinters(self.cups) ++ ++ # Get default printer. ++ try: ++ self.default_printer = self.cups.getDefault () ++ except AttributeError: # getDefault appeared in pycups-1.9.31 ++ # This fetches the list of printers and classes *again*, ++ # just to find out the default printer. ++ dests = self.cups.getDests () ++ if dests.has_key ((None,None)): ++ self.default_printer = dests[(None,None)].name ++ else: ++ self.default_printer = None ++ except cups.IPPError, (e, m): ++ self.show_IPP_Error(e, m) ++ self.printers = {} ++ self.default_printer = None ++ else: ++ self.printers = {} ++ self.default_printer = None ++ ++ local_printers = [] ++ local_classes = [] ++ remote_printers = [] ++ remote_classes = [] ++ ++ for name, printer in self.printers.iteritems(): ++ if printer.default: ++ self.default_printer = name ++ self.servers.add(printer.getServer()) ++ ++ if printer.remote: ++ if printer.is_class: remote_classes.append(name) ++ else: remote_printers.append(name) ++ else: ++ if printer.is_class: local_classes.append(name) ++ else: local_printers.append(name) ++ ++ local_printers.sort() ++ local_classes.sort() ++ remote_printers.sort() ++ remote_classes.sort() ++ ++ if (old_name != "" and ++ (not old_name in local_printers) and ++ (not old_name in local_classes) and ++ (not old_name in remote_printers) and ++ (not old_name in remote_classes)): ++ # The previously selected printer no longer exists. ++ old_name = "" ++ ++ if (self.default_printer != None and ++ start_printer == None and ++ old_name == ""): ++ start_printer = self.default_printer ++ ++ if not start_printer: ++ start_printer = old_name ++ ++ expanded = { ++ "_printers" : True, ++ "_classes" : True, ++ "_remote_printers" : True, ++ "_remote_classes" : True, ++ } ++ ++ """ ++ # remove old printers/classes ++ iter = self.mainlist.get_iter_first() ++ iter = self.mainlist.iter_next(iter) # step over server settings ++ while iter: ++ entry = self.mainlist.get_value(iter, 1) ++ path = self.mainlist.get_path(iter) ++ expanded[entry] = self.tvMainList.row_expanded(path) ++ more_entries = self.mainlist.remove(iter) ++ if not more_entries: break ++ """ ++ self.ui.mainlist.clear() ++ QTreeWidgetItem(self.ui.mainlist, ["New Printer", 'New']) ++ self.settingsItem = QTreeWidgetItem(self.ui.mainlist, ["Server Settings", 'Settings']) ++ if serverPageShowing: ++ self.settingsItem.setSelected(True) ++ ++ # add new ++ for printers, text, name in ( ++ (local_printers, i18n("Local Printers"), "_printers"), ++ (local_classes, i18n("Local Classes"), "_classes"), ++ (remote_printers, i18n("Remote Printers"), "_remote_printers"), ++ (remote_classes, i18n("Remote Classes"), "_remote_classes")): ++ if not printers: continue ++ ++ #self.mainlist.addTopLevelItem(QTreeWidgetItem(self.mainlist, text)) ++ rootTreeItem = QTreeWidgetItem(self.ui.mainlist, [text, name]) ++ #iter = self.mainlist.append(None, (text, name)) ++ #path = self.mainlist.get_path(iter) ++ ++ for printer_name in printers: ++ if start_printer == None: ++ start_printer = printer_name ++ treeItem = QTreeWidgetItem(rootTreeItem, [printer_name, "Printer"]) ++ #p_iter = self.mainlist.append(iter, (printer_name, "Printer")) ++ if printer_name==start_printer and not serverPageShowing: ++ treeItem.setSelected(True) ++ expanded[name] = True ++ if expanded[name]: ++ rootTreeItem.setExpanded(True) ++ #self.tvMainList.expand_row(path, False) ++ self.on_tvMainList_cursor_changed() ++ self.setDataButtonState() ++ ++ """FIXME ++ if change_ppd: ++ self.on_btnChangePPD_clicked (self.btnChangePPD) ++ """ ++ ++ #TODO ++ # Connect to Server ++ ++ def on_printer_changed(self, text): ++ widget = self.sender() ++ if not widget: #method called as a method not a slot ++ return ++ if isinstance(widget, QCheckBox): ++ value = widget.isChecked() ++ elif isinstance(widget, QLineEdit): #this should be a KLineEdit but causes errors ++ value = unicode(widget.text()) ++ elif isinstance(widget, QRadioButton): ++ value = widget.isChecked() ++ elif isinstance(widget, QComboBox): #KCombobox causes errors ++ value = unicode(widget.currentText()) ++ else: ++ raise ValueError, "Widget type not supported (yet)" ++ ++ p = self.printer ++ old_values = { ++ self.ui.entPDescription : p.info, ++ self.ui.entPLocation : p.location, ++ self.ui.entPDevice : p.device_uri, ++ self.ui.chkPEnabled : p.enabled, ++ self.ui.chkPAccepting : not p.rejecting, ++ self.ui.chkPShared : p.is_shared, ++ self.ui.cmbPStartBanner : p.job_sheet_start, ++ self.ui.cmbPEndBanner : p.job_sheet_end, ++ self.ui.rbtnPAllow: p.default_allow ++ #FIXME Not implemented in the current UI ++ #self.cmbPErrorPolicy : p.error_policy, ++ #self.cmbPOperationPolicy : p.op_policy, ++ } ++ ++ old_value = old_values[widget] ++ ++ if old_value == value: ++ self.changed.discard(widget) ++ else: ++ self.changed.add(widget) ++ self.setDataButtonState() ++ ++ #TODO ++ # Access control ++ ++ #TODO ++ # Server side options ++ ++ # set buttons sensitivity ++ def setDataButtonState(self): ++ try: # Might not be a printer selected ++ possible = (self.ppd and ++ not bool (self.changed) and ++ self.printer.enabled and ++ not self.printer.rejecting) ++ ++ self.btnPrintTestPage.setEnabled(possible) ++ ++ commands = (self.printer.type & cups.CUPS_PRINTER_COMMANDS) != 0 ++ self.btnSelfTest.setEnabled(commands and possible) ++ self.btnCleanHeads.setEnabled(commands and possible) ++ except: ++ debugprint ("exception in setDataButtonState") ++ pass ++ ++ installablebold = False ++ optionsbold = False ++ """ FIXME, no conflicts button in system settings ++ if self.conflicts: ++ debugprint ("Conflicts detected") ++ self.btnConflict.show() ++ for option in self.conflicts: ++ if option.tab_label == self.lblPInstallOptions: ++ installablebold = True ++ else: ++ optionsbold = True ++ else: ++ self.ui.btnConflict.hide() ++ """ ++ installabletext = i18n("Installable Options") ++ optionstext = i18n("Printer Options") ++ if installablebold: ++ installabletext = i18nc("Conflicted entry", "%1", installabletext) ++ if optionsbold: ++ optionstext = i18nc("Conflicted entry", "%1", optionstext) ++ self.ui.lblPInstallOptions.setText(installabletext) ++ self.ui.lblPOptions.setText(optionstext) ++ ++ """ FIXME ++ store = self.tvPrinterProperties.get_model () ++ if store: ++ for n in range (self.ntbkPrinter.get_n_pages ()): ++ page = self.ntbkPrinter.get_nth_page (n) ++ label = self.ntbkPrinter.get_tab_label (page) ++ if label == self.lblPInstallOptions: ++ iter = store.get_iter ((n,)) ++ store.set_value (iter, 0, installabletext) ++ elif label == self.lblPOptions: ++ iter = store.get_iter ((n,)) ++ store.set_value (iter, 0, optionstext) ++ """ ++ ++ self.ui.changed(len (self.changed) > 0) ++ #self.ui.btnPrinterPropertiesApply.setEnabled(len (self.changed) > 0) ++ #self.ui.btnRevert.setEnabled(len (self.changed) > 0) ++ ++ def save_printer(self, printer, saveall=False): ++ class_deleted = False ++ name = printer.name ++ ++ try: ++ if not printer.is_class and self.ppd: ++ self.getPrinterSettings() ++ if self.ppd.nondefaultsMarked() or saveall: ++ self.passwd_retry = False # use cached Passwd ++ self.cups.addPrinter(name, ppd=self.ppd) ++ ++ if printer.is_class: ++ # update member list ++ new_members = self.getCurrentClassMembers(self.ui.tvClassMembers) ++ if not new_members: ++ result = KMessageBox.warningContinueCancel(self.ui, i18n("Class now has no members. Proceed anyway?"), i18n("Class Empty")) ++ if result == KMessageBox.Continue: ++ return True ++ class_deleted = True ++ ++ # update member list ++ old_members = printer.class_members[:] ++ ++ for member in new_members: ++ member = unicode(member) ++ if member in old_members: ++ old_members.remove(member) ++ else: ++ self.cups.addPrinterToClass(member, name) ++ for member in old_members: ++ self.cups.deletePrinterFromClass(member, name) ++ ++ location = unicode(self.ui.entPLocation.text()) ++ info = unicode(self.ui.entPDescription.text()) ++ device_uri = unicode(self.ui.entPDevice.text()) ++ if device_uri.find (ellipsis) != -1: ++ # The URI is sanitized and not editable. ++ device_uri = printer.device_uri ++ ++ enabled = self.ui.chkPEnabled.isChecked() ++ accepting = self.ui.chkPAccepting.isChecked() ++ shared = self.ui.chkPShared.isChecked() ++ ++ if info!=printer.info or saveall: ++ self.passwd_retry = False # use cached Passwd ++ self.cups.setPrinterInfo(name, info) ++ if location!=printer.location or saveall: ++ self.passwd_retry = False # use cached Passwd ++ self.cups.setPrinterLocation(name, location) ++ if (not printer.is_class and ++ (device_uri!=printer.device_uri or saveall)): ++ self.passwd_retry = False # use cached Passwd ++ self.cups.setPrinterDevice(name, device_uri) ++ ++ if enabled != printer.enabled or saveall: ++ self.passwd_retry = False # use cached Passwd ++ self.printer.setEnabled(enabled) ++ if accepting == printer.rejecting or saveall: ++ self.passwd_retry = False # use cached Passwd ++ self.printer.setAccepting(accepting) ++ if shared != printer.is_shared or saveall: ++ self.passwd_retry = False # use cached Passwd ++ self.printer.setShared(shared) ++ ++ job_sheet_start = unicode(self.ui.cmbPStartBanner.currentText()) ++ job_sheet_end = unicode(self.ui.cmbPEndBanner.currentText()) ++ #FIXME Not implemented in current UI ++ #error_policy = unicode(self.cmbPErrorPolicy.currentText()) ++ #op_policy = unicode(self.cmbPOperationPolicy.currentText()) ++ ++ if (job_sheet_start != printer.job_sheet_start or ++ job_sheet_end != printer.job_sheet_end) or saveall: ++ self.passwd_retry = False # use cached Passwd ++ printer.setJobSheets(job_sheet_start, job_sheet_end) ++ #FIXME Not implemented in current UI ++ #if error_policy != printer.error_policy or saveall: ++ #self.passwd_retry = False # use cached Passwd ++ #printer.setErrorPolicy(error_policy) ++ #if op_policy != printer.op_policy or saveall: ++ #self.passwd_retry = False # use cached Passwd ++ #printer.setOperationPolicy(op_policy) ++ ++ #Access Control ++ default_allow = self.ui.rbtnPAllow.isChecked() ++ except_users = self.getPUsers() ++ ++ if (default_allow != printer.default_allow or ++ except_users != printer.except_users) or saveall: ++ self.passwd_retry = False # use cached Passwd ++ printer.setAccess(default_allow, except_users) ++ ++ for option in printer.attributes: ++ if option not in self.server_side_options: ++ printer.unsetOption(option) ++ for option in self.server_side_options.itervalues(): ++ if (option.is_changed() or ++ saveall and ++ option.get_current_value () != option.system_default): ++ printer.setOption(unicode(option.name), unicode(option.get_current_value()) ) ++ ++ except cups.IPPError, (e, s): ++ self.show_IPP_Error(e, s) ++ return True ++ self.changed = set() # of options ++ ++ if not self.__dict__.has_key ("server_settings"): ++ # We can authenticate with the server correctly at this point, ++ # but we have never fetched the server settings to see whether ++ # the server is publishing shared printers. Fetch the settings ++ # now so that we can update the "not published" label if necessary. ++ try: ++ self.server_settings = self.cups.adminGetServerSettings() ++ except: ++ nonfatalException() ++ ++ if class_deleted: ++ self.populateList () ++ else: ++ # Update our copy of the printer's settings. ++ try: ++ printers = cupshelpers.getPrinters (self.cups) ++ this_printer = { name: printers[name] } ++ self.printers.update (this_printer) ++ except cups.IPPError, (e, s): ++ show_IPP_Error(e, s, self.PrinterPropertiesDialog) ++ ++ return False ++ ++ def getPrinterSettings(self): ++ #self.ppd.markDefaults() ++ for option in self.options.itervalues(): ++ option.writeback() ++ ++ @pyqtSignature("") ++ def on_btnPrintTestPage_clicked(self): ++ self.setTestButton(self.printer) ++ if self.test_button_cancels: ++ jobs = self.printer.testsQueued () ++ for job in jobs: ++ debugprint ("Canceling job %s" % job) ++ try: ++ self.cups.cancelJob (job) ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ self.setTestButton (self.printer) ++ return ++ try: ++ # if we have a page size specific custom test page, use it; ++ # otherwise use cups' default one ++ custom_testpage = None ++ opt = self.ppd.findOption ("PageSize") ++ if opt: ++ print opt ++ custom_testpage = os.path.join(SYSTEM_CONFIG_PRINTER_DIR, 'testpage-%s.ps' % opt.defchoice.lower()) ++ print custom_testpage ++ ++ if custom_testpage and os.path.exists(custom_testpage): ++ debugprint ('Printing custom test page ' + custom_testpage) ++ job_id = self.cups.printTestPage(self.printer.name, ++ file=custom_testpage) ++ print job_id ++ else: ++ debugprint ('Printing default test page') ++ job_id = self.cups.printTestPage(self.printer.name) ++ ++ self.setTestButton (self.printer) ++ KMessageBox.information(self, i18n("Test page submitted as job %1", job_id), i18nc("Test page submitted", "Submitted")) ++ except cups.IPPError, (e, msg): ++ if (e == cups.IPP_NOT_AUTHORIZED and ++ self.connect_server != 'localhost' and ++ self.connect_server[0] != '/'): ++ self.lblError.set_markup (''+ ++ i18n("Not possible") + '\n\n' + ++ i18n("The remote server did not accept " ++ "the print job, most likely " ++ "because the printer is not " ++ "shared.")) ++ self.ErrorDialog.set_transient_for (self.MainWindow) ++ self.ErrorDialog.run () ++ self.ErrorDialog.hide () ++ else: ++ self.show_IPP_Error(e, msg) ++ ++ def maintenance_command (self, command): ++ (tmpfd, tmpfname) = tempfile.mkstemp () ++ os.write (tmpfd, "#CUPS-COMMAND\n%s\n" % command) ++ os.close (tmpfd) ++ try: ++ format = "application/vnd.cups-command" ++ job_id = self.cups.printTestPage (self.printer.name, ++ format=format, ++ file=tmpfname, ++ user=self.connect_user) ++ self.lblInfo.set_markup ('' + ++ i18nc("Maintenance command submitted", "Submitted") + '\n\n' + ++ i18n("Maintenance command submitted as " ++ "job %d", job_id)) ++ self.InfoDialog.set_transient_for (self.MainWindow) ++ self.InfoDialog.run () ++ self.InfoDialog.hide () ++ except cups.IPPError, (e, msg): ++ if (e == cups.IPP_NOT_AUTHORIZED and ++ self.printer.name != 'localhost'): ++ self.lblError.set_markup (''+ ++ i18n("Not possible") + '\n\n' + ++ i18n("The remote server did not accept " ++ "the print job, most likely " ++ "because the printer is not " ++ "shared.")) ++ self.ErrorDialog.set_transient_for (self.MainWindow) ++ self.ErrorDialog.run () ++ self.ErrorDialog.hide () ++ else: ++ self.show_IPP_Error(e, msg) ++ ++ @pyqtSignature("") ++ def on_btnSelfTest_clicked(self): ++ self.maintenance_command ("PrintSelfTestPage") ++ ++ @pyqtSignature("") ++ def on_btnCleanHeads_clicked(self): ++ self.maintenance_command ("Clean all") ++ ++ def fillComboBox(self, combobox, values, value): ++ combobox.clear() ++ for nr, val in enumerate(values): ++ combobox.addItem(val) ++ if val == value: ++ combobox.setCurrentIndex(nr) ++ ++ def fillPrinterTab(self, name): ++ self.changed = set() # of options ++ self.options = {} # keyword -> Option object ++ self.conflicts = set() # of options ++ ++ printer = self.printers[name] ++ self.printer = printer ++ printer.getAttributes () ++ ++ editable = not self.printer.discovered ++ editablePPD = not self.printer.remote ++ ++ try: ++ self.ppd = printer.getPPD() ++ except cups.IPPError, (e, m): ++ # Some IPP error other than IPP_NOT_FOUND. ++ self.show_IPP_Error(e, m) ++ # Treat it as a raw queue. ++ self.ppd = False ++ except RuntimeError: ++ # The underlying cupsGetPPD2() function returned NULL without ++ # setting an IPP error, so it'll be something like a failed ++ # connection. ++ #FIXME show a dialogue ++ debugprint("Error!") ++ """ ++ self.lblError.set_markup('' + ++ _("Error") + '\n\n' + ++ _("There was a problem connecting to " ++ "the CUPS server.")) ++ self.ErrorDialog.set_transient_for(self.MainWindow) ++ self.ErrorDialog.run() ++ self.ErrorDialog.hide() ++ """ ++ raise ++ ++ for widget in (self.ui.entPDescription, self.ui.entPLocation, ++ self.ui.entPName, self.ui.entPDevice): ++ widget.setReadOnly(not editable) ++ ++ for widget in (self.ui.btnChangePPD, ++ self.ui.chkPEnabled, self.ui.chkPAccepting, self.ui.chkPShared, ++ self.ui.cmbPStartBanner, self.ui.cmbPEndBanner, self.ui.btnPAddUser, ++ self.ui.btnPDelUser, self.ui.rbtnPAllow, self.ui.rbtnPDeny): ++ #""",FIXME ++ #self.btnSelectDevice, self.cmbPErrorPolicy, ++ #self.cmbPOperationPolicy,): ++ #""" ++ widget.setEnabled(editable) ++ ++ # Description page ++ self.ui.entPName.setText(printer.name) ++ self.ui.entPDescription.setText(printer.info) ++ self.ui.entPLocation.setText(printer.location) ++ ++ uri = printer.device_uri ++ if uri.startswith("smb://"): ++ (group, host, share, ++ user, password) = SMBURI (uri=uri[6:]).separate () ++ if password: ++ uri = "smb://" ++ if len (user) or len (password): ++ uri += ellipsis ++ uri += SMBURI (group=group, host=host, share=share).get_uri () ++ self.ui.entPDevice.setEnabled(False) ++ else: ++ self.ui.entPDevice.setEnabled(True) ++ ++ self.ui.entPDevice.setText(uri) ++ self.changed.discard(self.ui.entPDevice) ++ ++ # Hide make/model and Device URI for classes ++ for widget in (self.ui.lblPMakeModel2, self.ui.lblPMakeModel, ++ self.ui.lblPDevice2, self.ui.entPDevice, ++ self.ui.btnChangePPD): ++ #, self.btnSelectDevice): ++ if printer.is_class: ++ widget.hide() ++ else: ++ widget.show() ++ ++ ## default printer ++ default = self.cups.getDefault() ++ ++ if printer.name == default: ++ #catch the stateChanged signal to prevent a signal loop ++ self.ui.chkPMakeDefault.blockSignals(True) ++ self.ui.chkPMakeDefault.setChecked(True) #set checked ++ #unblock the signal ++ self.ui.chkPMakeDefault.blockSignals(False) ++ self.ui.chkPMakeDefault.setText(i18n("This is the default printer")) ++ else: ++ #catch the stateChanged signal to prevent a signal loop ++ self.ui.chkPMakeDefault.blockSignals(True) ++ self.ui.chkPMakeDefault.setChecked(False) #set unchecked ++ #unblock the signal ++ self.ui.chkPMakeDefault.blockSignals(False) ++ if default is not None: ++ self.ui.chkPMakeDefault.setText(i18n('Make Default. (The current default is %1)', default)) ++ else: ++ self.ui.chkPMakeDefault.setText(i18n('Make Default. (There is no current default)')) ++ ++ #self.setTestButton (printer) ++ ++ # Policy tab ++ # ---------- ++ ++ ## State ++ self.ui.chkPEnabled.setChecked(printer.enabled) ++ self.ui.chkPAccepting.setChecked(not printer.rejecting) ++ self.ui.chkPShared.setChecked(printer.is_shared) ++ try: ++ if printer.is_shared: ++ flag = cups.CUPS_SERVER_SHARE_PRINTERS ++ publishing = int (self.server_settings[flag]) ++ if publishing: ++ self.ui.lblNotPublished.hide() ++ else: ++ self.ui.lblNotPublished.show() ++ else: ++ self.ui.lblNotPublished.hide() ++ except: ++ self.ui.lblNotPublished.hide() ++ ++ # Job sheets ++ self.ui.cmbPStartBanner.setEnabled(editable) ++ self.ui.cmbPEndBanner.setEnabled(editable) ++ ++#FIXME Not implemented in the current UI ++ # Policies ++ #self.cmbPErrorPolicy.setEnabled(editable) ++ #self.cmbPOperationPolicy.setEnabled(editable) ++ ++ ++ # Access control ++ self.ui.rbtnPAllow.setChecked(printer.default_allow) ++ self.ui.rbtnPDeny.setChecked(not printer.default_allow) ++ self.setPUsers(printer.except_users) ++ ++ #self.entPUser.set_text("") ++ # Server side options (Job options) ++ self.server_side_options = {} ++ for option in self.job_options_widgets.values (): ++ if option.name == "media" and self.ppd: ++ # Slightly special case because the 'system default' ++ # (i.e. what you get when you press Reset) depends ++ # on the printer's PageSize. ++ opt = self.ppd.findOption ("PageSize") ++ if opt: ++ option.set_default (opt.defchoice) ++ ++ option_editable = editable ++ try: ++ value = self.printer.attributes[option.name] ++ except KeyError: ++ option.reinit (None) ++ else: ++ try: ++ if self.printer.possible_attributes.has_key (option.name): ++ supported = self.printer.\ ++ possible_attributes[option.name][1] ++ # Set the option widget. ++ # In CUPS 1.3.x the orientation-requested-default ++ # attribute may have the value None; this means there ++ # is no value set. This suits our needs here, as None ++ # resets the option to the system default and makes the ++ # Reset button insensitive. ++ option.reinit (value, supported=supported) ++ else: ++ option.reinit (value) ++ ++ self.server_side_options[option.name] = option ++ except ValueError, inst: ++ option_editable = False ++ text = ('' + ++ _("Error") + '\n\n' + ++ _("Option '%s' has value '%s' " ++ "and cannot be edited.") % ++ (option.name, value)) ++ QMessageBox.critical(self.ui, i18n("Error"), text) ++ option.widget.setEnabled(option_editable) ++ if not editable: ++ option.button.setEnabled(False) ++ self.other_job_options = [] ++ self.draw_other_job_options (editable=editable) ++ for option in self.printer.attributes.keys (): ++ if self.server_side_options.has_key (option): ++ continue ++ supported = "" ++ if self.printer.possible_attributes.has_key (option): ++ supported = self.printer.possible_attributes[option][1] ++ self.add_job_option (option, value=self.printer.attributes[option], ++ supported=supported, is_new=False, ++ editable=editable) ++ self.ui.entNewJobOption.setText ('') ++ self.ui.entNewJobOption.setEnabled(editable) ++ self.ui.btnNewJobOption.setEnabled(False) ++ ++ if printer.is_class: ++ # remove InstallOptions tab ++ ##tab_nr = self.ui.ntbkPrinter.page_num(self.swPInstallOptions) ++ ##if tab_nr != -1: ++ ## self.ui.ntbkPrinter.remove_page(tab_nr) ++ self.fillClassMembers(name, editable) ++ pass ++ else: ++ # real Printer ++ self.fillPrinterOptions(name, editablePPD) ++ ++ #self.changed = set() # of options ++ self.updatePrinterProperties () ++ self.setDataButtonState() ++ ++ ++ def fillPrinterOptions(self, name, editable): ++ # remove Member tab ++ tab_nr = self.ui.ntbkPrinter.indexOf(self.memberTabWidget) ++ if tab_nr != -1: ++ self.ui.ntbkPrinter.removeTab(tab_nr) ++ policiesTabNo = self.ui.ntbkPrinter.indexOf(self.policiesTabWidget) ++ self.ui.ntbkPrinter.insertTab(policiesTabNo+1, self.optionsTabWidget, i18n("Options")) ++ ++ """ ++ # clean Installable Options Tab ++ for widget in self.vbPInstallOptions.get_children(): ++ self.vbPInstallOptions.remove(widget) ++ ++ """ ++ # clean Options Tab ++ for widget in self.ui.optionsPageWidget.children(): ++ if isinstance(widget, QWidget): ++ self.ui.vbPOptions.removeWidget(widget) ++ widget.hide() ++ del widget ++ """ ++ ++ # insert Options Tab ++ if self.ntbkPrinter.page_num(self.swPOptions) == -1: ++ self.ntbkPrinter.insert_page( ++ self.swPOptions, self.lblPOptions, self.static_tabs) ++ ++ if not self.ppd: ++ tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions) ++ if tab_nr != -1: ++ self.ntbkPrinter.remove_page(tab_nr) ++ tab_nr = self.ntbkPrinter.page_num(self.swPOptions) ++ if tab_nr != -1: ++ self.ntbkPrinter.remove_page(tab_nr) ++ return ++ """ ++ ppd = self.ppd ++ ppd.markDefaults() ++ ++ hasInstallableOptions = False ++ ++ # build option tabs ++ for group in ppd.optionGroups: ++ if group.name == "InstallableOptions": ++ """ ++ hasInstallableOptions = True ++ container = self.vbPInstallOptions ++ tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions) ++ if tab_nr == -1: ++ self.ntbkPrinter.insert_page( ++ self.swPInstallOptions, gtk.Label(group.text), ++ self.static_tabs) ++ """ ++ tab_label = self.ui.lblPInstallOptions ++ else: ++ """ ++ frame = gtk.Frame("%s" % group.text) ++ frame.get_label_widget().set_use_markup(True) ++ frame.set_shadow_type (gtk.SHADOW_NONE) ++ self.vbPOptions.pack_start (frame, False, False, 0) ++ container = gtk.Alignment (0.5, 0.5, 1.0, 1.0) ++ # We want a left padding of 12, but there is a Table with ++ # spacing 6, and the left-most column of it (the conflict ++ # icon) is normally hidden, so just use 6 here. ++ container.set_padding (6, 12, 6, 0) ++ frame.add (container) ++ """ ++ tab_label = self.ui.lblPOptions ++ container = QGroupBox(self) ++ self.ui.vbPOptions.addWidget(container) ++ container.setTitle(group.text) ++ """ ++ ++ table = gtk.Table(1, 3, False) ++ table.set_col_spacings(6) ++ table.set_row_spacings(6) ++ container.add(table) ++ """ ++ table = QGridLayout(container) ++ container.setLayout(table) ++ ++ rows = 0 ++ ++ # InputSlot and ManualFeed need special handling. With ++ # libcups, if ManualFeed is True, InputSlot gets unset. ++ # Likewise, if InputSlot is set, ManualFeed becomes False. ++ # We handle it by toggling the sensitivity of InputSlot ++ # based on ManualFeed. ++ self.option_inputslot = self.option_manualfeed = None ++ ++ for nr, option in enumerate(group.options): ++ if option.keyword == "PageRegion": ++ continue ++ rows += 1 ++ """ ++ table.resize (rows, 3) ++ """ ++ o = OptionWidget(option, ppd, self, tab_label=tab_label) ++ """ ++ table.attach(o.conflictIcon, 0, 1, nr, nr+1, 0, 0, 0, 0) ++ ++ hbox = gtk.HBox() ++ """ ++ if o.label: ++ table.addWidget(o.label, rows-1, 0) ++ """ ++ a = gtk.Alignment (0.5, 0.5, 1.0, 1.0) ++ a.set_padding (0, 0, 0, 6) ++ a.add (o.label) ++ table.attach(a, 1, 2, nr, nr+1, gtk.FILL, 0, 0, 0) ++ table.attach(hbox, 2, 3, nr, nr+1, gtk.FILL, 0, 0, 0) ++ else: ++ table.attach(hbox, 1, 3, nr, nr+1, gtk.FILL, 0, 0, 0) ++ hbox.pack_start(o.selector, False) ++ """ ++ table.addWidget(o.selector, rows-1, 1) ++ self.options[option.keyword] = o ++ o.selector.setEnabled(editable) ++ if option.keyword == "InputSlot": ++ self.option_inputslot = o ++ elif option.keyword == "ManualFeed": ++ self.option_manualfeed = o ++ ++ """ ++ # remove Installable Options tab if not needed ++ if not hasInstallableOptions: ++ tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions) ++ if tab_nr != -1: ++ self.ntbkPrinter.remove_page(tab_nr) ++ ++ # check for conflicts ++ for option in self.options.itervalues(): ++ conflicts = option.checkConflicts() ++ if conflicts: ++ self.conflicts.add(option) ++ ++ self.swPInstallOptions.show_all() ++ self.swPOptions.show_all() ++ """ ++ ++ ++ # Class members ++ ++ def fillClassMembers(self, name, editable): ++ printer = self.printers[name] ++ ++ self.ui.btnClassAddMember.setEnabled(editable) ++ self.ui.btnClassDelMember.setEnabled(editable) ++ ++ # remove Options tab ++ tab_nr = self.ui.ntbkPrinter.indexOf(self.optionsTabWidget) ++ if tab_nr != -1: ++ self.ui.ntbkPrinter.removeTab(tab_nr) ++ policiesTabNo = self.ui.ntbkPrinter.indexOf(self.policiesTabWidget) ++ self.ui.ntbkPrinter.insertTab(policiesTabNo+1, self.memberTabWidget, i18n("Members")) ++ ++ self.ui.tvClassMembers.clear() ++ self.ui.tvClassNotMembers.clear() ++ names = self.printers.keys() ++ names.sort() ++ for name in names: ++ p = self.printers[name] ++ if p is not printer: ++ if name in printer.class_members: ++ self.ui.tvClassMembers.addItem(name) ++ else: ++ self.ui.tvClassNotMembers.addItem(name) ++ ++ def on_btnClassAddMember_clicked(self): ++ self.moveClassMembers(self.ui.tvClassNotMembers, ++ self.ui.tvClassMembers) ++ if self.getCurrentClassMembers(self.ui.tvClassMembers) != self.printer.class_members: ++ self.changed.add(self.ui.tvClassMembers) ++ else: ++ self.changed.discard(self.ui.tvClassMembers) ++ self.setDataButtonState() ++ ++ def on_btnClassDelMember_clicked(self): ++ self.moveClassMembers(self.ui.tvClassMembers, ++ self.ui.tvClassNotMembers) ++ if self.getCurrentClassMembers(self.ui.tvClassMembers) != self.printer.class_members: ++ self.changed.add(self.ui.tvClassMembers) ++ else: ++ self.changed.discard(self.ui.tvClassMembers) ++ self.setDataButtonState() ++ ++ #In Gnome is now on_delete_activate(self, UNUSED): ++ def btnDelete_clicked(self): ++ name, type = self.getSelectedItem() ++ ++ # Confirm ++ if type == "Printer": ++ message_format = i18n("Really delete printer %s?") ++ else: ++ message_format = i18n("Really delete class %s?") ++ ++ answer = KMessageBox.questionYesNo(self, ++ unicode(message_format) % name, ++ "") ++ ++ if answer == KMessageBox.Yes: ++ try: ++ self.cups.deletePrinter(name) ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ elif answer == KMessageBox.No: ++ return ++ ++ self.changed = set() ++ self.populateList() ++ self.ui.mainlist.setCurrentItem(self.ui.mainlist.itemAt(0,0)) ++ ++ #Taken from the gnome version ++ def setDefaultPrinter(self, name): ++ printer = self.printers[name] ++ try: ++ printer.setAsDefault() ++ except cups.HTTPError, (s,): ++ self.show_HTTP_Error(s) ++ return ++ except cups.IPPError(e, msg): ++ show_IPP_Error(e, msg) ++ return ++ ++ def chkPMakeDefault_stateChanged(self): ++ default = self.cups.getDefault() ++ try: ++ if self.ui.chkPMakeDefault.isChecked(): ++ name = self.ui.entPName.text() ++ self.setDefaultPrinter(unicode(name)) ++ self.ui.chkPMakeDefault.setText(i18n("This is the default printer")) ++ else: ++ if default is not None: ++ self.ui.chkPMakeDefault.setText(i18n('Make Default. (The current default is %1)', default)) ++ else: ++ self.ui.chkPMakeDefault.setText(i18n('Make Default. (There is no current default)')) ++ ++ self.ui.changed(len(self.changed) > 0) ++ #self.ui.btnPrinterPropertiesApply.setEnabled(len (self.changed) > 0) ++ #self.ui.btnRevert.setEnabled(len (self.changed) > 0) ++ ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ return ++ ++############################## ++ #Obsolete? Possibly no longer necessary. Not included in ++ #current gnome version ++ # Also need to check system-wide lpoptions because that's how ++ # previous Fedora versions set the default (bug #217395). ++ (tmpfd, tmpfname) = tempfile.mkstemp () ++ success = False ++ try: ++ resource = "/admin/conf/lpoptions" ++ self.cups.getFile(resource, tmpfname) ++ #success = True ++ except cups.HTTPError, (s,): ++ try: ++ os.remove (tmpfname) ++ except OSError: ++ pass ++ ++ if s != cups.HTTP_NOT_FOUND: ++ self.show_HTTP_Error(s) ++ return ++ ++ if success: ++ lines = file (tmpfname).readlines () ++ changed = False ++ i = 0 ++ for line in lines: ++ if line.startswith ("Default "): ++ # This is the system-wide default. ++ name = line.split (' ')[1] ++ if name != self.printer.name: ++ # Stop it from over-riding the server default. ++ lines[i] = "Dest " + line[8:] ++ changed = True ++ i += 1 ++ ++ if changed: ++ file (tmpfname, 'w').writelines (lines) ++ try: ++ self.cups.putFile (resource, tmpfname) ++ except cups.HTTPError, (s,): ++ os.remove (tmpfname) ++ self.show_HTTP_Error(s) ++ return ++######################### ++ # Now reconnect because the server needs to reload. ++ self.reconnect () ++ ++ try: ++ os.remove (tmpfname) ++ except OSError: ++ pass ++ ++ try: ++ self.populateList() ++ except cups.HTTPError, (s,): ++ self.cups = None ++ self.setConnected() ++ self.populateList() ++ self.show_HTTP_Error(s) ++ ++ def option_changed(self, option): ++ if option.is_changed(): ++ self.changed.add(option) ++ else: ++ self.changed.discard(option) ++ ++ if option.conflicts: ++ self.conflicts.add(option) ++ else: ++ self.conflicts.discard(option) ++ self.setDataButtonState() ++ ++ if (self.option_manualfeed and self.option_inputslot and ++ option == self.option_manualfeed): ++ if option.get_current_value() == "True": ++ self.option_inputslot.disable () ++ else: ++ self.option_inputslot.enable () ++ ++ # Access control ++ def getPUsers(self): ++ """return list of usernames from the GUI""" ++ result = [] #empty list to hold result ++ #if there is only one user in the list ++ if self.ui.tvPUsers.topLevelItemCount() < 2: ++ item = self.ui.tvPUsers.itemAt(0, 0) ++ #use a string instead of a QString. ++ #system-config-printer fails in ++ #self.connection.setPrinterUsersDenied(self.name, except_users) ++ #if we use a QString ++ if item is not None: ++ name = str(item.text(0)) ++ result.append(name) ++ else: ++ #create an iterator for the QTreeWidgetObject ++ #had to create an iterator class manually because QTreeWidgetItemIterator ++ #is broken ++ it = Iter(self.ui.tvPUsers) ++ while it: #iterate over the tree ++ try: ++ item = it.next() ++ name = item.text(0) ++ result.append(name) ++ except StopIteration: ++ break ++ ++ result.sort() ++ return result ++ ++ def setPUsers(self, users): ++ """write list of usernames into the GUI""" ++ self.ui.tvPUsers.clear() ++ for user in users: ++ #create a QTreeWidgetItem ++ u = QTreeWidgetItem(self.ui.tvPUsers) ++ u.setText(0, user) #set the label for the item ++ #add the item to the top level of the tree ++ self.ui.tvPUsers.addTopLevelItem(u) ++ ++ def checkPUsersChanged(self): ++ """check if users in GUI and printer are different ++ and set self.changed""" ++ if self.getPUsers() != self.printer.except_users: ++ self.changed.add(self.ui.tvPUsers) ++ else: ++ self.changed.discard(self.ui.tvPUsers) ++ ++ self.setDataButtonState() ++ ++ def btnPAddUser_clicked(self): ++ current_user = os.getenv('USER') ++ user, ok = KInputDialog.getText(i18n('Add User'), i18n('Enter Username'), current_user) ++ type(user) ++ ++ if ok and not user.isEmpty(): ++ u = QTreeWidgetItem(self.ui.tvPUsers) ++ u.setText(0, user) ++ self.ui.tvPUsers.addTopLevelItem(u) ++ ++ self.checkPUsersChanged() ++ ++ def btnPDelUser_clicked(self): ++ users = self.ui.tvPUsers.selectedItems() ++ for u in users: ++ index = self.ui.tvPUsers.indexOfTopLevelItem(u) ++ self.ui.tvPUsers.takeTopLevelItem(index) ++ ++ self.checkPUsersChanged() ++ ++ # Server side options ++ def on_job_option_reset(self): ++ button = self.sender() ++ option = self.job_options_buttons[button] ++ option.reset () ++ # Remember to set this option for removal in the IPP request. ++ if self.server_side_options.has_key (option.name): ++ del self.server_side_options[option.name] ++ if option.is_changed (): ++ self.changed.add(option) ++ else: ++ self.changed.discard(option) ++ self.setDataButtonState() ++ ++ def on_job_option_changed(self): ++ if not self.printer: ++ return ++ widget = self.sender() ++ option = self.job_options_widgets[widget] ++ option.changed () ++ if option.is_changed (): ++ self.server_side_options[option.name] = option ++ self.changed.add(option) ++ else: ++ if self.server_side_options.has_key (option.name): ++ del self.server_side_options[option.name] ++ self.changed.discard(option) ++ self.setDataButtonState() ++ # Don't set the reset button insensitive if the option hasn't ++ # changed from the original value: it's still meaningful to ++ # reset the option to the system default. ++ ++ def draw_other_job_options (self, editable=True): ++ n = len (self.other_job_options) ++ #if n == 0: ++ # self.tblJOOther.hide_all () ++ # return ++ ++ #self.tblJOOther.resize (n, 3) ++ children = self.ui.tblJOOtherWidget.children() ++ for child in children: ++ if type(child) != QGridLayout: ++ self.ui.tblJOOther.removeWidget(child) ++ child.hide() ++ i = 0 ++ self.removeJobOptionButtons = {} ++ for opt in self.other_job_options: ++ self.ui.tblJOOther.addWidget(opt.label, i, 0) ++ self.ui.tblJOOther.addWidget(opt.selector, i, 1) ++ opt.label.show() ++ opt.selector.show() ++ opt.selector.setEnabled(editable) ++ ++ btn = QPushButton("Remove", self.ui.tblJOOtherWidget) ++ self.connect(btn, SIGNAL("clicked()"), self.on_btnJOOtherRemove_clicked) ++ #btn.set_data("pyobject", opt) ++ self.removeJobOptionButtons[btn] = opt ++ btn.setEnabled(editable) ++ self.ui.tblJOOther.addWidget(btn, i, 2) ++ i += 1 ++ ++ #self.tblJOOther.show_all () ++ ++ def add_job_option(self, name, value = "", supported = "", is_new=True, ++ editable=True): ++ option = options.OptionWidget(name, value, supported, ++ self.option_changed) ++ option.is_new = is_new ++ self.other_job_options.append (option) ++ self.draw_other_job_options (editable=editable) ++ self.server_side_options[name] = option ++ if name in self.changed: # was deleted before ++ option.is_new = False ++ self.changed.add(option) ++ self.setDataButtonState() ++ if is_new: ++ ##option.selector.grab_focus () ++ pass #FIXME ++ ++ def on_btnJOOtherRemove_clicked(self): ++ button = self.sender() ++ option = self.removeJobOptionButtons[button] ++ #option = button.get_data("pyobject") ++ self.other_job_options.remove (option) ++ self.draw_other_job_options () ++ if option.is_new: ++ self.changed.discard(option) ++ else: ++ # keep name as reminder that option got deleted ++ self.changed.add(option.name) ++ del self.server_side_options[option.name] ++ self.setDataButtonState() ++ ++ def on_btnNewJobOption_clicked(self): ++ name = self.ui.entNewJobOption.text() ++ self.add_job_option(name) ++ #self.tblJOOther.show_all() ++ self.ui.entNewJobOption.setText('') ++ self.ui.btnNewJobOption.setEnabled(False) ++ self.setDataButtonState() ++ ++ def on_entNewJobOption_changed(self, widget): ++ text = unicode(self.ui.entNewJobOption.text()) ++ active = (len(text) > 0) and text not in self.server_side_options ++ self.ui.btnNewJobOption.setEnabled(active) ++ ++ def on_entNewJobOption_activate(self, widget): ++ self.on_btnNewJobOption_clicked (widget) # wrong widget but ok ++ ++ ########################################################################## ++ ### Server settings ++ ########################################################################## ++ ++ def fillServerTab(self): ++ self.changed = set() ++ try: ++ self.server_settings = self.cups.adminGetServerSettings() ++ except cups.IPPError, (e, m): ++ #FIXME ++ self.show_IPP_Error(e, m) ++ self.ui.tvMainList.get_selection().unselect_all() ++ self.on_tvMainList_cursor_changed(self.ui.tvMainList) ++ return ++ ++ for widget, setting in [ ++ (self.ui.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS), ++ (self.ui.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS), ++ (self.ui.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY), ++ (self.ui.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN), ++ (self.ui.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY), ++ (self.ui.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]: ++ # widget.set_data("setting", setting) ++ self.widget_data_setting[widget] = setting ++ self.disconnect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) ++ if self.server_settings.has_key(setting): ++ widget.setChecked(int(self.server_settings[setting])) ++ widget.setEnabled(True) ++ else: ++ widget.setChecked(False) ++ widget.setEnabled(False) ++ self.connect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) ++ self.setDataButtonState() ++ # Set sensitivity of 'Allow printing from the Internet'. ++ self.on_server_changed (self.ui.chkServerShare) # (any will do here) ++ ++ def on_server_widget_changed(self, value): ++ self.on_server_changed(self.sender()) ++ ++ def on_server_changed(self, widget): ++ setting = self.widget_data_setting[widget] ++ if self.server_settings.has_key (setting): ++ if str(int(widget.isChecked())) == self.server_settings[setting]: ++ self.changed.discard(widget) ++ else: ++ self.changed.add(widget) ++ ++ sharing = self.ui.chkServerShare.isChecked () ++ self.ui.chkServerShareAny.setEnabled ( ++ sharing and self.server_settings.has_key(try_CUPS_SERVER_REMOTE_ANY)) ++ ++ self.setDataButtonState() ++ ++ def save_serversettings(self): ++ setting_dict = self.server_settings.copy() ++ for widget, setting in [ ++ (self.ui.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS), ++ (self.ui.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS), ++ (self.ui.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY), ++ (self.ui.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN), ++ (self.ui.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY), ++ (self.ui.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]: ++ if not self.server_settings.has_key(setting): continue ++ setting_dict[setting] = str(int(widget.isChecked())) ++ try: ++ self.cups.adminSetServerSettings(setting_dict) ++ except cups.IPPError, (e, m): ++ self.show_IPP_Error(e, m) ++ return True ++ except RuntimeError, s: ++ self.show_IPP_Error(None, s) ++ return True ++ self.changed = set() ++ self.setDataButtonState() ++ time.sleep(1) # give the server a chance to process our request ++ ++ # Now reconnect, in case the server needed to reload. ++ self.reconnect () ++ ++ # Refresh the server settings in case they have changed in the ++ # mean time. ++ try: ++ self.fillServerTab() ++ except: ++ nonfatalException() ++ ++ # ==================================================================== ++ # == New Printer Dialog ============================================== ++ # ==================================================================== ++ ++ # new printer ++ def on_new_printer_activate(self): ++ self.ui.setCursor(Qt.WaitCursor) ++ self.newPrinterGUI.init("printer") ++ self.ui.setCursor(Qt.ArrowCursor) ++ ++ # new class ++ def on_new_class_activate(self): ++ self.ui.setCursor(Qt.WaitCursor) ++ self.newPrinterGUI.init("class") ++ self.ui.setCursor(Qt.ArrowCursor) ++ ++ @pyqtSignature("") ++ def on_btnSelectDevice_clicked(self): ++ self.newPrinterGUI.init("device") ++ ++ @pyqtSignature("") ++ def on_btnChangePPD_clicked(self): ++ self.ui.setCursor(Qt.WaitCursor) ++ self.newPrinterGUI.init("ppd") ++ self.ui.setCursor(Qt.ArrowCursor) ++ ++ def checkNPName(self, name): ++ if not name: return False ++ name = name.lower() ++ for printer in self.printers.values(): ++ if not printer.discovered and printer.name.lower()==name: ++ return False ++ return True ++ ++ def makeNameUnique(self, name): ++ """Make a suggested queue name valid and unique.""" ++ name = name.replace (" ", "_") ++ name = name.replace ("/", "_") ++ name = name.replace ("#", "_") ++ if not self.checkNPName (name): ++ suffix=2 ++ while not self.checkNPName (name + str (suffix)): ++ suffix += 1 ++ if suffix == 100: ++ break ++ name += str (suffix) ++ return name ++ ++ #TODO ++ ## Watcher interface helpers ++ ++ @pyqtSignature("") ++ def on_btnRevert_clicked(self): ++ self.changed = set() # avoid asking the user ++ self.on_tvMainList_cursor_changed() ++ ++ @pyqtSignature("") ++ def on_btnPrinterPropertiesApply_clicked(self): ++ err = self.printer_properties_response() ++ if not err: ++ self.populateList() ++ else: ++ nonfatalException() ++ ++ def show_IPP_Error(self, exception, message): ++ if exception == cups.IPP_NOT_AUTHORIZED: ++ KMessageBox.error(self, i18n('The password may be incorrect.'), i18n('Not authorized')) ++ else: ++ KMessageBox.error(self, i18n("There was an error during the CUPS " "operation: '%1'.", message), ++ i18n('CUPS server error')) ++ ++ def show_HTTP_Error(self, status): ++ if (status == cups.HTTP_UNAUTHORIZED or ++ status == cups.HTTP_FORBIDDEN): ++ ++ KMessageBox.error(self,i18n('The password may be incorrect, or the ' ++ 'server may be configured to deny ' ++ 'remote administration.'), ++ i18n('Not authorized') ) ++ else: ++ if status == cups.HTTP_BAD_REQUEST: ++ msg = i18nc("HTTP error", "Bad request") ++ elif status == cups.HTTP_NOT_FOUND: ++ msg = i18nc("HTTP error", "Not found") ++ elif status == cups.HTTP_REQUEST_TIMEOUT: ++ msg = i18nc("HTTP error", "Request timeout") ++ elif status == cups.HTTP_UPGRADE_REQUIRED: ++ msg = i18nc("HTTP error", "Upgrade required") ++ elif status == cups.HTTP_SERVER_ERROR: ++ msg = i18nc("HTTP error", "Server error") ++ elif status == -1: ++ msg = i18nc("HTTP error", "Not connected") ++ else: ++ msg = i18nc("HTTP error", "status %1", status) ++ ++ KMessageBox.error(self, i18n("There was an HTTP error: %1.", msg), i18n('CUPS server error')) ++ ++ def getSelectedItem(self): ++ return unicode(self.mainListSelectedName), unicode(self.mainListSelectedType) ++ """ ++ items = self.mainlist.selectedItems() ++ if len(items) < 1: ++ return ("", 'None') ++ item = items[0] ++ name = item.text(0) ++ type = item.text(1) ++ name = str(name).decode ('utf-8') ++ return name.strip(), type ++ """ ++ ++ def reconnect (self): ++ """Reconnect to CUPS after the server has reloaded.""" ++ # libcups would handle the reconnection if we just told it to ++ # do something, for example fetching a list of classes. ++ # However, our local authentication certificate would be ++ # invalidated by a server restart, so it is better for us to ++ # handle the reconnection ourselves. ++ ++ # Disconnect. ++ self.cups = None ++ self.setConnected() ++ ++ cups.setServer(self.connect_server) ++ cups.setUser(self.connect_user) ++ attempt = 1 ++ while attempt <= 5: ++ try: ++ self.cups = cups.Connection () ++ break ++ except RuntimeError: ++ # Connection failed. ++ time.sleep(1) ++ attempt += 1 ++ ++ self.setConnected() ++ self.passwd_retry = False ++ ++ def updatePrinterProperties(self): ++ debugprint ("update printer properties") ++ printer = self.printer ++ self.ui.lblPMakeModel.setText(printer.make_and_model) ++ state = self.printer_states.get (printer.state, i18nc("Printer state", "Unknown"))[:] ++ reason = printer.other_attributes.get ('printer-state-message', '') ++ if len (reason) > 0: ++ state += ' - ' + reason ++ self.ui.lblPState.setText(state) ++ if len (self.changed) == 0: ++ debugprint ("no changes yet: full printer properties update") ++ ++ # State ++ self.ui.chkPEnabled.setEnabled(printer.enabled) ++ self.ui.chkPAccepting.setEnabled(not printer.rejecting) ++ self.ui.chkPShared.setEnabled(printer.is_shared) ++ ++ # Job sheets ++ self.fillComboBox(self.ui.cmbPStartBanner, ++ printer.job_sheets_supported, ++ printer.job_sheet_start), ++ self.fillComboBox(self.ui.cmbPEndBanner, printer.job_sheets_supported, ++ printer.job_sheet_end) ++ ++#FIXME Not implemented in current UI ++ # Policies ++ #self.fillComboBox(self.cmbPErrorPolicy, ++ #printer.error_policy_supported, ++ #printer.error_policy) ++ #self.fillComboBox(self.cmbPOperationPolicy, ++ #printer.op_policy_supported, ++ #printer.op_policy) ++ ++ ++ # Access control ++ self.ui.rbtnPAllow.setChecked(printer.default_allow) ++ self.ui.rbtnPDeny.setChecked(not printer.default_allow) ++ self.setPUsers(printer.except_users) ++ ++ ++ def setTestButton (self, printer): ++ if printer.testsQueued (): ++ self.test_button_cancels = True ++ self.ui.btnPrintTestPage.setText(i18n('Cancel Tests')) ++ self.ui.btnPrintTestPage.setEnabled(True) ++ else: ++ self.test_button_cancels = False ++ self.ui.btnPrintTestPage.setText(i18n('Print Test Page')) ++ self.setDataButtonState() ++ ++ def getCurrentClassMembers(self, listwidget): ++ count = listwidget.count() ++ result = [] ++ for i in range(count): ++ result.append(listwidget.item(i).text()) ++ result.sort() ++ return result ++ ++ def moveClassMembers(self, treeview_from, treeview_to): ++ rows = treeview_from.selectedItems() ++ for row in rows: ++ treeview_from.takeItem(treeview_from.row(row)) ++ treeview_to.addItem(row) ++ ++ #FIXME obsolete? ++ def cupsPasswdCallback(self, querystring): ++ return "" #FIXME ++ if self.passwd_retry or len(self.password) == 0: ++ waiting = self.WaitWindow.get_property('visible') ++ if waiting: ++ self.WaitWindow.hide () ++ self.lblPasswordPrompt.set_label (self.prompt_primary + ++ querystring) ++ self.PasswordDialog.set_transient_for (self.MainWindow) ++ self.entPasswd.grab_focus () ++ ++ result = self.PasswordDialog.run() ++ self.PasswordDialog.hide() ++ if waiting: ++ self.WaitWindow.show () ++ while gtk.events_pending (): ++ gtk.main_iteration () ++ if result == gtk.RESPONSE_OK: ++ self.password = self.entPasswd.get_text() ++ else: ++ self.password = '' ++ self.passwd_retry = False ++ else: ++ self.passwd_retry = True ++ return self.password ++ ++ ++class NewPrinterGUI(QDialog): ++ ++ new_printer_device_tabs = { ++ "parallel" : 0, # empty tab ++ "usb" : 0, ++ "hal" : 0, ++ "beh" : 0, ++ "hp" : 0, ++ "hpfax" : 0, ++ "socket": 2, ++ "ipp" : 3, ++ "http" : 3, ++ "lpd" : 4, ++ "scsi" : 5, ++ "serial" : 6, ++ "smb" : 7, ++ } ++ ++ ntbkNewPrinterPages = { ++ "name" : 0, ++ "device" : 1, ++ "make" : 2, ++ "model" : 3, ++ "class-members" : 4, ++ "downloadable" : -1, ++ } ++ ++ def __init__(self, mainapp): ++ QDialog.__init__(self, mainapp) ++ self.mainapp = mainapp ++ self.language = mainapp.language ++ self.dialog_mode = "" ++ ++ self.WaitWindow = QMessageBox(self.mainapp) ++ self.WaitWindow.setStandardButtons(QMessageBox.NoButton) ++ ++ uic.loadUi(APPDIR + "/" + "new-printer.ui", self) ++ ++ self.btnNPBack.setIcon(KIcon("go-previous")) ++ self.btnNPForward.setIcon(KIcon("go-next")) ++ self.btnNPCancel.setIcon(KIcon("dialog-cancel")) ++ self.btnNPApply.setIcon(KIcon("dialog-ok")) ++ self.btnNCAddMember.setIcon(KIcon("arrow-left")) ++ self.btnNCDelMember.setIcon(KIcon("arrow-right")) ++ ++ self.connect(self.tvNPDevices, SIGNAL("itemSelectionChanged()"), self.on_tvNPDevices_cursor_changed) ++ self.connect(self.tvNPMakes, SIGNAL("itemSelectionChanged()"), self.on_tvNPMakes_cursor_changed) ++ self.connect(self.tvNPModels, SIGNAL("itemSelectionChanged()"), self.on_tvNPModels_cursor_changed) ++ self.connect(self.entNPTDevice, SIGNAL("textEdited(const QString&)"), self.on_entNPTDevice_changed) ++# self.connect(self.entNPTIPPHostname, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPHostname_changed) ++# self.connect(self.entNPTIPPQueuename, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPQueuename_changed) ++ self.connect(self.entSMBURI, SIGNAL("textEdited(const QString&)"), self.on_entSMBURI_changed) ++ self.rbtnSMBAuthPrompt.setChecked(True) ++ self.on_rbtnSMBAuthSet_toggled(False) ++ self.connect(self.rbtnSMBAuthSet, SIGNAL("toggled(bool)"), self.on_rbtnSMBAuthSet_toggled) ++ self.rbtnNPFoomatic.setChecked(True) ++ self.connect(self.rbtnNPFoomatic, SIGNAL("toggled(bool)"), self.on_rbtnNPFoomatic_toggled) ++ self.connect(self.filechooserPPDButton, SIGNAL("clicked()"),self.on_filechooserPPDButton) ++ self.options = {} # keyword -> Option object ++ self.changed = set() ++ self.conflicts = set() ++ self.ppd = None ++ ++ # Synchronisation objects. ++ self.ppds_lock = thread.allocate_lock() ++ self.devices_lock = thread.allocate_lock() ++ self.smb_lock = thread.allocate_lock() ++ self.ipp_lock = thread.allocate_lock() ++ self.drivers_lock = thread.allocate_lock() ++ ++ #self.connect(self.btnNCAddMember, SIGNAL("clicked()"), self.slot_btnNCAddMember_clicked) ++ #self.connect(self.btnNCDelMember, SIGNAL("clicked()"), self.slot_btnNCDelMember_clicked) ++ ++ # Optionally disable downloadable driver support. ++ #if not config.DOWNLOADABLE_DRIVER_SUPPORT: ++ if True: ++ self.rbtnNPDownloadableDriverSearch.setEnabled(False) ++ self.downloadableDriverSearchFrame.hide() ++ ++ """ ++ # Set up OpenPrinting widgets. ++ self.openprinting = openprinting.OpenPrinting () ++ self.openprinting_query_handle = None ++ combobox = self.cmbNPDownloadableDriverFoundPrinters ++ cell = gtk.CellRendererText() ++ combobox.pack_start (cell, True) ++ combobox.add_attribute(cell, 'text', 0) ++ ++ # SMB browser ++ self.smb_store = gtk.TreeStore (str, # host or share ++ str, # comment ++ gobject.TYPE_PYOBJECT, # domain dict ++ gobject.TYPE_PYOBJECT) # host dict ++ self.tvSMBBrowser.set_model (self.smb_store) ++ self.smb_store.set_sort_column_id (0, gtk.SORT_ASCENDING) ++ ++ # SMB list columns ++ col = gtk.TreeViewColumn (_("Share"), gtk.CellRendererText (), ++ text=0) ++ col.set_resizable (True) ++ col.set_sort_column_id (0) ++ self.tvSMBBrowser.append_column (col) ++ ++ col = gtk.TreeViewColumn (_("Comment"), gtk.CellRendererText (), ++ text=1) ++ self.tvSMBBrowser.append_column (col) ++ slct = self.tvSMBBrowser.get_selection () ++ slct.set_select_function (self.smb_select_function) ++ ++ self.SMBBrowseDialog.set_transient_for(self.NewPrinterWindow) ++ ++ # IPP browser ++ self.ipp_store = gtk.TreeStore (str, # queue ++ str, # location ++ gobject.TYPE_PYOBJECT) # dict ++ self.tvIPPBrowser.set_model (self.ipp_store) ++ self.ipp_store.set_sort_column_id (0, gtk.SORT_ASCENDING) ++ ++ # IPP list columns ++ col = gtk.TreeViewColumn (_("Queue"), gtk.CellRendererText (), ++ text=0) ++ col.set_resizable (True) ++ col.set_sort_column_id (0) ++ self.tvIPPBrowser.append_column (col) ++ ++ col = gtk.TreeViewColumn (_("Location"), gtk.CellRendererText (), ++ text=1) ++ self.tvIPPBrowser.append_column (col) ++ self.IPPBrowseDialog.set_transient_for(self.NewPrinterWindow) ++ ++ self.tvNPDriversTooltips = TreeViewTooltips(self.tvNPDrivers, self.NPDriversTooltips) ++ ++ ppd_filter = gtk.FileFilter() ++ ppd_filter.set_name(_("PostScript Printer Description files (*.ppd, *.PPD, *.ppd.gz, *.PPD.gz, *.PPD.GZ)")) ++ ppd_filter.add_pattern("*.ppd") ++ ppd_filter.add_pattern("*.PPD") ++ ppd_filter.add_pattern("*.ppd.gz") ++ ppd_filter.add_pattern("*.PPD.gz") ++ ppd_filter.add_pattern("*.PPD.GZ") ++ self.filechooserPPD.add_filter(ppd_filter) ++ ++ ppd_filter = gtk.FileFilter() ++ ppd_filter.set_name(_("All files (*)")) ++ ppd_filter.add_pattern("*") ++ self.filechooserPPD.add_filter(ppd_filter) ++ ++ self.xml.signal_autoconnect(self) ++ """ ++ ++ #FIXME hide bits which are not yet implemented ++ self.btnSMBBrowse.hide() ++ self.btnSMBVerify.hide() ++ self.btnNPTLpdProbe.hide() ++ ++ def option_changed(self, option): ++ if option.is_changed(): ++ self.changed.add(option) ++ else: ++ self.changed.discard(option) ++ ++ if option.conflicts: ++ self.conflicts.add(option) ++ else: ++ self.conflicts.discard(option) ++ self.setDataButtonState() ++ ++ return ++ ++ def setDataButtonState(self): ++ self.btnNPForward.setEnabled(not bool(self.conflicts)) ++ ++ def init(self, dialog_mode): ++ self.dialog_mode = dialog_mode ++ self.options = {} # keyword -> Option object ++ self.changed = set() ++ self.conflicts = set() ++ ++ """ ++ combobox = self.cmbNPDownloadableDriverFoundPrinters ++ combobox.set_model (gtk.ListStore (str, str)) ++ self.entNPDownloadableDriverSearch.set_text ('') ++ button = self.btnNPDownloadableDriverSearch ++ label = button.get_children ()[0].get_children ()[0].get_children ()[1] ++ self.btnNPDownloadableDriverSearch_label = label ++ label.set_text (_("Search")) ++ """ ++ ++ if self.dialog_mode == "printer": ++ self.setWindowTitle(i18n("New Printer")) ++ # Start on devices page (1, not 0) ++ self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"]) ++ self.fillDeviceTab() ++ self.on_rbtnNPFoomatic_toggled() ++ # Start fetching information from CUPS in the background ++ self.new_printer_PPDs_loaded = False ++ self.queryPPDs () ++ elif self.dialog_mode == "class": ++ self.setWindowTitle(i18n("New Class")) ++ self.fillNewClassMembers() ++ # Start on name page ++ self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["name"]) ++ elif self.dialog_mode == "device": ++ self.setWindowTitle(i18n("Change Device URI")) ++ self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"]) ++ self.queryDevices () ++ self.loadPPDs() ++ self.fillDeviceTab(self.mainapp.printer.device_uri) ++ # Start fetching information from CUPS in the background ++ self.new_printer_PPDs_loaded = False ++ self.queryPPDs () ++ elif self.dialog_mode == "ppd": ++ self.setWindowTitle(i18n("Change Driver")) ++ self.ntbkNewPrinter.setCurrentIndex(2) ++ self.on_rbtnNPFoomatic_toggled() ++ ++ self.auto_model = "" ++ ppd = self.mainapp.ppd ++ if ppd: ++ attr = ppd.findAttr("Manufacturer") ++ if attr: ++ self.auto_make = attr.value ++ else: ++ self.auto_make = "" ++ attr = ppd.findAttr("ModelName") ++ if not attr: attr = ppd.findAttr("ShortNickName") ++ if not attr: attr = ppd.findAttr("NickName") ++ if attr: ++ if attr.value.startswith(self.auto_make): ++ self.auto_model = attr.value[len(self.auto_make):].strip () ++ else: ++ try: ++ self.auto_model = attr.value.split(" ", 1)[1] ++ except IndexError: ++ self.auto_model = "" ++ else: ++ self.auto_model = "" ++ else: ++ # Special CUPS names for a raw queue. ++ self.auto_make = 'Raw' ++ self.auto_model = 'Queue' ++ ++ self.loadPPDs () ++ self.fillMakeList() ++ ++ if self.dialog_mode in ("printer", "class"): ++ self.entNPName.setText (self.mainapp.makeNameUnique(self.dialog_mode)) ++ #FIXMEself.entNPName.grab_focus() ++ for widget in [self.entNPLocation, ++ self.entNPDescription]: #, ++ #self.entSMBURI, self.entSMBUsername, ++ #self.entSMBPassword, self.entNPTDirectJetHostname]: ++ widget.setText('') ++ ++ try: ++ p = os.popen ('/bin/hostname', 'r') ++ hostname = p.read ().strip () ++ p.close () ++ self.entNPLocation.setText(hostname) ++ except: ++ nonfatalException () ++ ++ self.entNPTDirectJetPort.setText('9100') ++ self.setNPButtons() ++ self.exec_() ++ ++ # get PPDs ++ ++ def queryPPDs(self): ++ debugprint ("queryPPDs") ++ if not self.ppds_lock.acquire(0): ++ debugprint ("queryPPDs: in progress") ++ return ++ debugprint ("Lock acquired for PPDs thread") ++ ++ self.getPPDs_thread(self.language[0]) ++ debugprint ("PPDs thread started") ++ ++ def getPPDs_thread(self, language): ++ try: ++ debugprint ("Connecting (PPDs)") ++ cups.setServer (self.mainapp.connect_server) ++ cups.setUser (self.mainapp.connect_user) ++ cups.setPasswordCB (self.mainapp.cupsPasswdCallback) ++ # cups.setEncryption (...) ++ c = cups.Connection () ++ debugprint ("Fetching PPDs") ++ ppds_dict = c.getPPDs() ++ self.ppds_result = cupshelpers.ppds.PPDs(ppds_dict, ++ language=language) ++ debugprint ("Closing connection (PPDs)") ++ del c ++ except cups.IPPError, (e, msg): ++ self.ppds_result = cups.IPPError (e, msg) ++ except: ++ nonfatalException() ++ self.ppds_result = { } ++ ++ debugprint ("Releasing PPDs lock") ++ self.ppds_lock.release () ++ ++ def fetchPPDs(self, parent=None): ++ debugprint ("fetchPPDs") ++ self.queryPPDs() ++ time.sleep (0.1) ++ ++ # Keep the UI refreshed while we wait for the devices to load. ++ waiting = False ++ while (self.ppds_lock.locked()): ++ if not waiting: ++ waiting = True ++ self.WaitWindow.setText(i18n('Searching') + '

' + ++ i18n('Searching for drivers')) ++ self.WaitWindow.show () ++ ++ KApplication.processEvents() ++ ++ time.sleep (0.1) ++ ++ if waiting: ++ self.WaitWindow.hide () ++ ++ debugprint ("Got PPDs") ++ result = self.ppds_result # atomic operation ++ if isinstance (result, cups.IPPError): ++ # Propagate exception. ++ raise result ++ return result ++ ++ def loadPPDs(self, parent=None): ++ try: ++ return self.ppds ++ except: ++ self.ppds = self.fetchPPDs (parent=parent) ++ return self.ppds ++ ++ def dropPPDs(self): ++ try: ++ del self.ppds ++ except: ++ pass ++ ++ # Class members ++ ++ def fillNewClassMembers(self): ++ self.tvNCMembers.clear() ++ self.tvNCNotMembers.clear() ++ for printer in self.mainapp.printers.itervalues(): ++ self.tvNCNotMembers.addItem(printer.name) ++ ++ @pyqtSignature("") ++ def on_btnNCAddMember_clicked(self): ++ self.mainapp.moveClassMembers(self.tvNCNotMembers, self.tvNCMembers) ++ self.btnNPApply.setEnabled( ++ bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers))) ++ ++ @pyqtSignature("") ++ def on_btnNCDelMember_clicked(self): ++ self.mainapp.moveClassMembers(self.tvNCMembers, self.tvNCNotMembers) ++ self.btnNPApply.setEnabled( ++ bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers))) ++ ++ @pyqtSignature("") ++ def on_btnNPBack_clicked(self): ++ self.nextNPTab(-1) ++ ++ @pyqtSignature("") ++ def on_btnNPForward_clicked(self): ++ self.nextNPTab() ++ ++ def nextNPTab(self, step=1): ++ self.setCursor(Qt.WaitCursor) ++ page_nr = self.ntbkNewPrinter.currentIndex() ++ ++ if self.dialog_mode == "class": ++ #order = [0, 4, 5] ++ order = [self.ntbkNewPrinterPages["name"], self.ntbkNewPrinterPages["class-members"]] ++ elif self.dialog_mode == "printer": ++ if page_nr == 1: # Device (first page) ++ # Choose an appropriate name. ++ name = 'printer' ++ try: ++ if self.device.id: ++ name = self.device.id_dict["MDL"] ++ name = self.mainapp.makeNameUnique (name) ++ self.entNPName.setText(name) ++ except: ++ nonfatalException () ++ self.auto_make, self.auto_model = None, None ++ self.device.uri = self.getDeviceURI() ++ if self.device.type in ("socket", "lpd", "ipp", "bluetooth"): ++ host = self.getNetworkPrinterMakeModel(self.device) ++ faxuri = None ++ if host: ++ faxuri = self.get_hplip_uri_for_network_printer(host, ++ "fax") ++ if faxuri: ++ #create message string ++ q = i18n("This printer supports both " ++ "printing and sending faxes. " ++ "Which functionality should be " ++ "used for this queue?") ++ ++ #buttons need to be KGuiItem objects ++ printer_button = KGuiItem(i18n("Printer")) ++ fax_button = KGuiItem(i18n("Fax")) ++ ++ #This is a bit hackish. Essentially Printer is mapped to the Yes button, Fax to ++ #the No button. KMessageBox doesn't seem to provide a version for 'This OR That' ++ queue_type = KMessageBox.questionYesNo(self.NewPrinterWindow, q , 'Choose function', printer_button, fax_button) ++ ++ #test return value of messagebox Printer == 3, Fax == 4 ++ if (queue_type == 3): ++ self.device.id_dict = \ ++ self.get_hpfax_device_id(faxuri) ++ self.device.uri = faxuri ++ self.auto_make = self.device.id_dict["MFG"] ++ self.auto_model = self.device.id_dict["MDL"] ++ self.device.id = "MFG:" + self.auto_make + \ ++ ";MDL:" + self.auto_model + \ ++ ";DES:" + \ ++ self.device.id_dict["DES"] + ";" ++ uri = self.device.uri ++ if uri and uri.startswith ("smb://"): ++ uri = SMBURI (uri=uri[6:]).sanitize_uri () ++ ++ # Try to access the PPD, in this case our detected IPP ++ # printer is a queue on a remote CUPS server which is ++ # not automatically set up on our local CUPS server ++ # (for example DNS-SD broadcasted queue from Mac OS X) ++ self.remotecupsqueue = None ++ res = re.search ("ipp://(\S+(:\d+|))/printers/(\S+)", uri) ++ if res: ++ resg = res.groups() ++ try: ++ conn = httplib.HTTPConnection(resg[0]) ++ conn.request("GET", "/printers/%s.ppd" % resg[2]) ++ resp = conn.getresponse() ++ if resp.status == 200: self.remotecupsqueue = resg[2] ++ except: ++ debugprint("exception in getting remotecupsqueue") ++ pass ++ ++ # We also want to fetch the printer-info and ++ # printer-location attributes, to pre-fill those ++ # fields for this new queue. ++ oldserver = cups.getServer() ++ oldport = cups.getPort() ++ try: ++ cups.setServer (resg[0]) ++ if len (resg[1]) > 0: ++ cups.setPort (int (resg[1])) ++ else: ++ cups.setPort (631) ++ ++ c = cups.Connection () ++ r = ['printer-info', 'printer-location'] ++ attrs = c.getPrinterAttributes (uri=uri, ++ requested_attributes=r) ++ info = attrs.get ('printer-info', '') ++ location = attrs.get ('printer-location', '') ++ if len (info) > 0: ++ self.entNPDescription.setText(info) ++ if len (location) > 0: ++ self.entNPLocation.setText(location) ++ except: ++ nonfatalException () ++ ++ cups.setServer (oldserver) ++ cups.setPort (oldport) ++ ++ if (not self.remotecupsqueue and ++ not self.new_printer_PPDs_loaded): ++ try: ++ self.loadPPDs(self) ++ except cups.IPPError, (e, msg): ++ #self.ready (self) ++ self.show_IPP_Error(e, msg) ++ return ++ except: ++ self.ready (self) ++ return ++ self.new_printer_PPDs_loaded = True ++ ++ ppdname = None ++ try: ++ if self.remotecupsqueue: ++ # We have a remote CUPS queue, let the client queue ++ # stay raw so that the driver on the server gets used ++ ppdname = 'raw' ++ self.ppd = ppdname ++ name = self.remotecupsqueue ++ name = self.mainapp.makeNameUnique (name) ++ self.entNPName.setText(name) ++ elif self.device.id: ++ id_dict = self.device.id_dict ++ (status, ppdname) = self.ppds.\ ++ getPPDNameFromDeviceID (id_dict["MFG"], ++ id_dict["MDL"], ++ id_dict["DES"], ++ id_dict["CMD"], ++ self.device.uri) ++ else: ++ (status, ppdname) = self.ppds.\ ++ getPPDNameFromDeviceID ("Generic", ++ "Printer", ++ "Generic Printer", ++ [], ++ self.device.uri) ++ ++ if ppdname and not self.remotecupsqueue: ++ ppddict = self.ppds.getInfoFromPPDName (ppdname) ++ make_model = ppddict['ppd-make-and-model'] ++ (make, model) = \ ++ cupshelpers.ppds.ppdMakeModelSplit (make_model) ++ self.auto_make = make ++ self.auto_model = model ++ except: ++ nonfatalException () ++ if not self.remotecupsqueue: ++ self.fillMakeList() ++ elif page_nr == 3: # Model has been selected ++ if not self.device.id: ++ # Choose an appropriate name when no Device ID ++ # is available, based on the model the user has ++ # selected. ++ try: ++ items = self.tvNPModels.selectedItems() ++ name = unicode(items[0].text()) ++ name = self.mainapp.makeNameUnique (name) ++ self.entNPName.setText(name) ++ except: ++ nonfatalException () ++ ++ ##self.ready (self.NewPrinterWindow) ++ if self.remotecupsqueue: ++ order = [1, 0] ++ elif self.rbtnNPFoomatic.isChecked(): ++ order = [1, 2, 3, 6, 0] ++ elif self.rbtnNPPPD.isChecked(): ++ order = [1, 2, 6, 0] ++ else: ++ # Downloadable driver ++ order = [1, 2, 7, 6, 0] ++ elif self.dialog_mode == "device": ++ order = [1] ++ elif self.dialog_mode == "ppd": ++ self.rbtnChangePPDasIs.setChecked(True) ++ if self.rbtnNPFoomatic.isChecked(): ++ order = [2, 3, 5, 6] ++ elif self.rbtnNPPPD.isChecked(): ++ order = [2, 5, 6] ++ else: ++ # Downloadable driver ++ order = [2, 7, 5, 6] ++ ++ next_page_nr = order[order.index(page_nr)+step] ++ ++ # fill Installable Options tab ++ if next_page_nr == 6 and step > 0: ++ #TODO Prepare Installable Options screen. ++ self.ppd = self.getNPPPD() ++ """FIXME todo ++ if next_page_nr == 6: ++ # Prepare Installable Options screen. ++ if isinstance(self.ppd, cups.PPD): ++ self.fillNPInstallableOptions() ++ else: ++ self.installable_options = None ++ # Put a label there explaining why the page is empty. ++ ppd = self.ppd ++ self.ppd = None ++ self.fillNPInstallableOptions() ++ self.ppd = ppd ++ ++ # step over if empty and not in PPD mode ++ if self.dialog_mode != "ppd" and not self.installable_options: ++ next_page_nr = order[order.index(next_page_nr)+1] ++ """ ++ next_page_nr = order[order.index(next_page_nr)+1] ++ self.installable_options = False ++ # Step over empty Installable Options tab ++ if next_page_nr == 6 and not self.installable_options and step<0: ++ next_page_nr = order[order.index(next_page_nr)-1] ++ ++ if next_page_nr == 7: # About to show downloadable drivers ++ if self.drivers_lock.locked (): ++ # Still searching for drivers. ++ self.lblWait.set_markup ('' + ++ i18n('Searching') + '\n\n' + ++ i18n('Searching for drivers')) ++ self.WaitWindow.set_transient_for (self.NewPrinterWindow) ++ self.WaitWindow.show () ++ ++ # Keep the UI refreshed while we wait for the drivers ++ # query to complete. ++ while self.drivers_lock.locked (): ++ self.mainapp.busy(self) ++ time.sleep (0.1) ++ ++ self.ready (self.NewPrinterWindow) ++ self.WaitWindow.hide () ++ ++ self.fillDownloadableDrivers() ++ ++ self.ntbkNewPrinter.setCurrentIndex(next_page_nr) ++ ++ self.setNPButtons() ++ self.setCursor(Qt.ArrowCursor) ++ ++ def setNPButtons(self): ++ nr = self.ntbkNewPrinter.currentIndex() ++ ++ if self.dialog_mode == "device": ++ self.btnNPBack.hide() ++ self.btnNPForward.hide() ++ self.btnNPApply.show() ++ uri = self.getDeviceURI () ++ self.btnNPApply.setEnabled(validDeviceURI (uri)) ++ return ++ ++ if self.dialog_mode == "ppd": ++ if nr == 5: # Apply ++ if not self.installable_options: ++ # There are no installable options, so this is the ++ # last page. ++ debugprint ("No installable options") ++ self.btnNPForward.hide () ++ self.btnNPApply.show () ++ else: ++ self.btnNPForward.show () ++ self.btnNPApply.hide () ++ return ++ elif nr == 6: ++ self.btnNPForward.hide() ++ self.btnNPApply.show() ++ return ++ else: ++ self.btnNPForward.show() ++ self.btnNPApply.hide() ++ if nr == 2: ++ self.btnNPBack.hide() ++ self.btnNPForward.show() ++ downloadable_selected = False ++ if self.rbtnNPDownloadableDriverSearch.isChecked(): ++ combobox = self.cmbNPDownloadableDriverFoundPrinters ++ iter = combobox.get_active_iter () #FIXME ++ if iter and combobox.get_model ().get_value (iter, 1): ++ downloadable_selected = True ++ ++ self.btnNPForward.setEnabled(bool( ++ self.rbtnNPFoomatic.isChecked() or ++ not self.filechooserPPD.text().isEmpty() or ++ downloadable_selected)) ++ return ++ else: ++ self.btnNPBack.show() ++ ++ # class/printer ++ ++ if nr == 1: # Device ++ valid = False ++ try: ++ uri = self.getDeviceURI () ++ valid = validDeviceURI (uri) ++ except: ++ pass ++ self.btnNPForward.setEnabled(valid) ++ self.btnNPBack.hide () ++ else: ++ self.btnNPBack.show() ++ ++ self.btnNPForward.show() ++ self.btnNPApply.hide() ++ ++ if nr == 0: # Name ++ self.btnNPBack.show() ++ if self.dialog_mode == "class": ++ self.btnNPForward.setEnabled(True) ++ if self.dialog_mode == "printer": ++ self.btnNPForward.hide() ++ self.btnNPApply.show() ++ self.btnNPApply.setEnabled( ++ self.mainapp.checkNPName(unicode(self.entNPName.text()))) ++ if nr == 2: # Make/PPD file ++ downloadable_selected = False ++ if self.rbtnNPDownloadableDriverSearch.isChecked(): ++ combobox = self.cmbNPDownloadableDriverFoundPrinters ++ iter = combobox.get_active_iter () #FIXME ++ if iter and combobox.get_model ().get_value (iter, 1): ++ downloadable_selected = True ++ ++ self.btnNPForward.setEnabled(bool( ++ self.rbtnNPFoomatic.isChecked() or ++ not self.filechooserPPD.text().isEmpty() or ++ downloadable_selected)) ++ ++ if nr == 3: # Model/Driver ++ iter = self.tvNPDrivers.currentItem() ++ self.btnNPForward.setEnabled(bool(iter)) ++ if nr == 4: # Class Members ++ self.btnNPForward.hide() ++ self.btnNPApply.show() ++ self.btnNPApply.setEnabled(self.tvNCMembers.count() > 0) ++ if nr == 7: # Downloadable drivers ++ if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1: #FIXME ++ accepted = self.rbtnNPDownloadLicenseYes.get_active () ++ else: ++ treeview = self.tvNPDownloadableDrivers ++ model, iter = treeview.get_selection ().get_selected () ++ accepted = (iter != None) ++ ++ self.btnNPForward.set_sensitive(accepted) ++ ++ def on_filechooserPPDButton(self): ++ home = QDir.homePath() ++ url = KUrl.fromPath(home) ++ filename = KFileDialog.getOpenFileName(url, '*.ppd', self) ++ self.filechooserPPD.setText(filename) ++ self.btnNPForward.setEnabled(True) ++ ++ def getDevices_thread(self): ++ try: ++ debugprint ("Connecting (devices)") ++ cups.setServer (self.mainapp.connect_server) ++ #cups.setUser (self.mainapp.connect_user) ++ cups.setUser ("jr") ++ cups.setPasswordCB (self.mainapp.cupsPasswdCallback) ++ # cups.setEncryption (...) ++ c = cups.Connection () ++ debugprint ("Fetching devices") ++ self.devices_result = cupshelpers.getDevices(c) ++ except cups.IPPError, (e, msg): ++ self.devices_result = cups.IPPError (e, msg) ++ except: ++ debugprint ("Exception in getDevices_thread") ++ self.devices_result = {} ++ ++ try: ++ debugprint ("Closing connection (devices)") ++ del c ++ except: ++ pass ++ ++ debugprint ("Releasing devices lock") ++ self.devices_lock.release () ++ ++ ++ # Device URI ++ def queryDevices(self): ++ if not self.devices_lock.acquire(0): ++ debugprint ("queryDevices: in progress") ++ return ++ debugprint ("Lock acquired for devices thread") ++ self.getDevices_thread() ++ debugprint ("Devices thread started") ++ ++ def fetchDevices(self, parent=None): ++ debugprint ("fetchDevices") ++ self.queryDevices () ++ time.sleep (0.1) ++ ++ # Keep the UI refreshed while we wait for the devices to load. ++ waiting = False ++ #crashes kcm here as soon as this loop exits ++ while (self.devices_lock.locked()): ++ if not waiting: ++ waiting = True ++ self.WaitWindow.setText (i18n('Searching') + '

' + ++ i18n('Searching for printers')) ++ if not parent: ++ parent = self.mainapp ++ self.WaitWindow.show () ++ ++ KApplication.processEvents() ++ ++ time.sleep (0.1) ++ ++ #if waiting: ++ #self.WaitWindow.hide() ++ ++ debugprint ("Got devices") ++ ++ result = self.devices_result # atomic operation ++ ++ if isinstance (result, cups.IPPError): ++ # Propagate exception. ++ raise result ++ return result ++ ++ def get_hpfax_device_id(self, faxuri): ++ os.environ["URI"] = faxuri ++ cmd = 'LC_ALL=C DISPLAY= hp-info -d "${URI}"' ++ debugprint (faxuri + ": " + cmd) ++ try: ++ p = subprocess.Popen (cmd, shell=True, ++ stdin=file("/dev/null"), ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE) ++ (stdout, stderr) = p.communicate () ++ except: ++ # Problem executing command. ++ return None ++ ++ for line in stdout.split ("\n"): ++ if line.find ("fax-type") == -1: ++ continue ++ faxtype = -1 ++ res = re.search ("(\d+)", line) ++ if res: ++ resg = res.groups() ++ faxtype = resg[0] ++ if faxtype >= 0: break ++ if faxtype < 0: ++ return None ++ elif faxtype == 4: ++ return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax 2;DES:HP Fax 2;') ++ else: ++ return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax;DES:HP Fax;') ++ ++ def get_hplip_uri_for_network_printer(self, host, mode): ++ os.environ["HOST"] = host ++ if mode == "print": mod = "-c" ++ elif mode == "fax": mod = "-f" ++ else: mod = "-c" ++ cmd = 'hp-makeuri ' + mod + ' "${HOST}"' ++ debugprint (host + ": " + cmd) ++ uri = None ++ try: ++ p = subprocess.Popen (cmd, shell=True, ++ stdin=file("/dev/null"), ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE) ++ (stdout, stderr) = p.communicate () ++ except: ++ # Problem executing command. ++ return None ++ ++ uri = stdout.strip () ++ return uri ++ ++ def getNetworkPrinterMakeModel(self, device): ++ # Determine host name/IP ++ host = None ++ s = device.uri.find ("://") ++ if s != -1: ++ s += 3 ++ e = device.uri[s:].find (":") ++ if e == -1: e = device.uri[s:].find ("/") ++ if e == -1: e = device.uri[s:].find ("?") ++ if e == -1: e = len (device.uri) ++ host = device.uri[s:s+e] ++ # Try to get make and model via SNMP ++ if host: ++ os.environ["HOST"] = host ++ cmd = '/usr/lib/cups/backend/snmp "${HOST}"' ++ debugprint (host + ": " + cmd) ++ stdout = None ++ try: ++ p = subprocess.Popen (cmd, shell=True, ++ stdin=file("/dev/null"), ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE) ++ (stdout, stderr) = p.communicate () ++ except: ++ # Problem executing command. ++ pass ++ ++ if stdout != None: ++ mm = re.sub("^\s*\S+\s+\S+\s+\"", "", stdout) ++ mm = re.sub("\"\s+.*$", "", mm) ++ if mm and mm != "": device.make_and_model = mm ++ # Extract make and model and create a pseudo device ID, so ++ # that a PPD/driver can be assigned to the device ++ make_and_model = None ++ if len (device.make_and_model) > 7: ++ make_and_model = device.make_and_model ++ elif len (device.info) > 7: ++ make_and_model = device.info ++ make_and_model = re.sub("\s*(\(|\d+\.\d+\.\d+\.\d+).*$", "", make_and_model) ++ if make_and_model and not device.id: ++ mk = None ++ md = None ++ (mk, md) = cupshelpers.ppds.ppdMakeModelSplit (make_and_model) ++ device.id = "MFG:" + mk + ";MDL:" + md + ";DES:" + mk + " " + md + ";" ++ device.id_dict = cupshelpers.parseDeviceID (device.id) ++ # Check whether the device is supported by HPLIP and replace ++ # its URI by an HPLIP URI ++ if host: ++ hplipuri = self.get_hplip_uri_for_network_printer(host, "print") ++ if hplipuri: ++ device.uri = hplipuri ++ s = hplipuri.find ("/usb/") ++ if s == -1: s = hplipuri.find ("/par/") ++ if s == -1: s = hplipuri.find ("/net/") ++ if s != -1: ++ s += 5 ++ e = hplipuri[s:].find ("?") ++ if e == -1: e = len (hplipuri) ++ mdl = hplipuri[s:s+e].replace ("_", " ") ++ if mdl.startswith ("hp ") or mdl.startswith ("HP "): ++ mdl = mdl[3:] ++ device.make_and_model = "HP " + mdl ++ device.id = "MFG:HP;MDL:" + mdl + ";DES:HP " + mdl + ";" ++ device.id_dict = cupshelpers.parseDeviceID (device.id) ++ # Return the host name/IP for further actions ++ return host ++ ++ def fillDeviceTab(self, current_uri=None, query=True): ++ if query: ++ try: ++ devices = self.fetchDevices() ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ devices = {} ++ except: ++ nonfatalException() ++ devices = {} ++ ++ if current_uri: ++ if devices.has_key (current_uri): ++ current = devices.pop(current_uri) ++ else: ++ current = cupshelpers.Device (current_uri) ++ current.info = "Current device" ++ ++ self.devices = devices.values() ++ ++ for device in self.devices: ++ if device.type == "usb": ++ # Find USB URIs with corresponding HPLIP URIs and mark them ++ # for deleting, so that the user will only get the HPLIP ++ # URIs for full device support in the list ++ ser = None ++ s = device.uri.find ("?serial=") ++ if s != -1: ++ s += 8 ++ e = device.uri[s:].find ("?") ++ if e == -1: e = len (device.uri) ++ ser = device.uri[s:s+e] ++ mod = None ++ s = device.uri[6:].find ("/") ++ if s != -1: ++ s += 7 ++ e = device.uri[s:].find ("?") ++ if e == -1: e = len (device.uri) ++ mod = device.uri[s:s+e].lower ().replace ("%20", "_") ++ if mod.startswith ("hp_"): ++ mod = mod[3:] ++ matchfound = 0 ++ for hpdevice in self.devices: ++ hpser = None ++ hpmod = None ++ uri = hpdevice.uri ++ if not uri.startswith ("hp:"): continue ++ if ser: ++ s = uri.find ("?serial=") ++ if s != -1: ++ s += 8 ++ e = uri[s:].find ("?") ++ if e == -1: e = len (uri) ++ hpser = uri[s:s+e] ++ if hpser != ser: continue ++ matchfound = 1 ++ if mod and not (ser and hpser): ++ s = uri.find ("/usb/") ++ if s != -1: ++ s += 5 ++ e = uri[s:].find ("?") ++ if e == -1: e = len (uri) ++ hpmod = uri[s:s+e].lower () ++ if hpmod.startswith ("hp_"): ++ hpmod = hpmod[3:] ++ if hpmod != mod: continue ++ matchfound = 1 ++ if matchfound == 1: break ++ if matchfound == 1: ++ device.uri = "delete" ++ if device.type == "hal": ++ # Remove HAL USB URIs, for these printers there are already ++ # USB URIs ++ if device.uri.startswith("hal:///org/freedesktop/Hal/devices/usb_device"): ++ device.uri = "delete" ++ if device.type == "socket": ++ # Remove default port to more easily find duplicate URIs ++ device.uri = device.uri.replace (":9100", "") ++ try: ++ ## XXX This needs to be moved to *after* the device is ++ # selected. Looping through all the network printers like ++ # this is far too slow. ++ if False and device.type in ("socket", "lpd", "ipp", "bluetooth"): ++ host = self.getNetworkPrinterMakeModel(device) ++ faxuri = None ++ if host: ++ faxuri = self.get_hplip_uri_for_network_printer(host, ++ "fax") ++ if faxuri: ++ self.devices.append(cupshelpers.Device(faxuri, ++ **{'device-class' : "direct", ++ 'device-info' : device.info + " HP Fax HPLIP", ++ 'device-device-make-and-model' : "HP Fax", ++ 'device-id' : "MFG:HP;MDL:Fax;DES:HP Fax;"})) ++ if device.uri.startswith ("hp:"): ++ device.type = "hp" ++ device.info += (" HPLIP") ++ except: ++ nonfatalException () ++ # Mark duplicate URIs for deletion ++ for i in range (len (self.devices)): ++ for j in range (len (self.devices)): ++ if i == j: continue ++ device1 = self.devices[i] ++ device2 = self.devices[j] ++ if device1.uri == "delete" or device2.uri == "delete": ++ continue ++ if device1.uri == device2.uri: ++ # Keep the one with the longer (better) device ID ++ if (not device1.id): ++ device1.uri = "delete" ++ elif (not device2.id): ++ device2.uri = "delete" ++ elif (len (device1.id) < len (device2.id)): ++ device1.uri = "delete" ++ else: ++ device2.uri = "delete" ++ self.devices = filter(lambda x: x.uri not in ("hp:/no_device_found", ++ "hpfax:/no_device_found", ++ "hp", "hpfax", ++ "hal", "beh", ++ "scsi", "http", "delete"), ++ self.devices) ++ self.devices.sort() ++ ++ self.devices.append(cupshelpers.Device('', ++ **{'device-info' :i18nc("Other device", "Other")})) ++ if current_uri: ++ current.info = i18nc("Current device", "%1 (Current)", current.info) ++ self.devices.insert(0, current) ++ self.device = current ++ self.tvNPDevices.clear() ++ ++ for device in self.devices: ++ self.tvNPDevices.addItem(device.info) ++ ++ #self.tvNPDevices.get_selection().select_path(0) ++ self.tvNPDevices.setCurrentRow(0) ++ self.on_tvNPDevices_cursor_changed() ++ ++ def on_entNPTDevice_changed(self, entry): ++ self.setNPButtons() ++ ++ #TODO ++ ## SMB browsing ++ def on_entSMBURI_changed (self, text): ++ uri = unicode(text) ++ (group, host, share, user, password) = SMBURI (uri=uri).separate () ++ if user: ++ self.entSMBUsername.setText(user) ++ if password: ++ self.entSMBPassword.setText(password) ++ if user or password: ++ uri = SMBURI (group=group, host=host, share=share).get_uri () ++ self.entSMBURI.setText(uri) ++ self.rbtnSMBAuthSet.setChecked(True) ++ elif unicode(self.entSMBUsername.text()) == '': ++ self.rbtnSMBAuthPrompt.setChecked(True) ++ ++ self.btnSMBVerify.setEnabled(bool(uri)) ++ ++ def on_rbtnSMBAuthSet_toggled(self, ticked): ++ self.tblSMBAuth.setEnabled(ticked) ++ ++ def on_entNPTIPPHostname_textChanged(self): ++ valid = len (self.entNPTIPPHostname.text ()) > 0 ++ self.btnIPPFindQueue.setEnabled(valid) ++ self.update_IPP_URI_label () ++ ++ ### IPP Browsing ++ def update_IPP_URI_label(self): ++ hostname = unicode(self.entNPTIPPHostname.text()) ++ queue = unicode(self.entNPTIPPQueuename.text()) ++ valid = len (hostname) > 0 and queue != '/printers/' ++ ++ if valid: ++ uri = "ipp://%s%s" % (hostname, queue) ++ self.lblIPPURI.setText(uri) ++ self.lblIPPURI.show () ++ self.entNPTIPPQueuename.show () ++ else: ++ self.lblIPPURI.hide () ++ ++ self.btnIPPVerify.setEnabled(valid) ++ self.setNPButtons () ++ ++ @pyqtSignature("") ++ def on_btnIPPFindQueue_clicked(self): ++ self.mainapp.busy() ++ self.entNPTIPPQueuename.clear() ++ IPPBrowseDialog(self) ++ self.mainapp.ready() ++ ++ @pyqtSignature("") ++ def on_btnIPPVerify_clicked(self): ++ uri = unicode(self.lblIPPURI.text()) ++ match = re.match ("(ipp|https?)://([^/]+)(.*)/([^/]*)", uri) ++ verified = False ++ if match: ++ oldserver = cups.getServer () ++ host = match.group(2) ++ try: ++ cups.setServer (match.group (2)) ++ c = cups.Connection () ++ attributes = c.getPrinterAttributes (uri = uri) ++ verified = True ++ except cups.IPPError, (e, msg): ++ debugprint ("Failed to get attributes: %s (%d)" % (msg, e)) ++ except: ++ nonfatalException () ++ cups.setServer (oldserver) ++ else: ++ debugprint (uri) ++ ++ if verified: ++ KMessageBox.information (self, _("This print share is accessible."), ++ _("Print Share Verified")) ++ else: ++ KMessageBox.error (self, _("This print share is not accessible."), ++ _("Inaccessible")) ++ ++ def on_tvNPDevices_cursor_changed(self): ++ device = self.devices[self.tvNPDevices.currentRow()] ++ self.device = device ++ self.lblNPDeviceDescription.setText('') ++ page = self.new_printer_device_tabs.get(device.type, 1) ++ self.ntbkNPType.setCurrentIndex(page) ++ ++ type = device.type ++ url = device.uri.split(":", 1)[-1] ++ if page == 0: ++ # This is the "no options" page, with just a label to describe ++ # the selected device. ++ if device.type == "parallel": ++ text = i18n("A printer connected to the parallel port.") ++ elif device.type == "usb": ++ text = i18n("A printer connected to a USB port.") ++ elif device.type == "hp": ++ text = i18n("HPLIP software driving a printer, " ++ "or the printer function of a multi-function device.") ++ elif device.type == "hpfax": ++ text = i18n("HPLIP software driving a fax machine, " ++ "or the fax function of a multi-function device.") ++ elif device.type == "hal": ++ text = i18n("Local printer detected by the " ++ "Hardware Abstraction Layer (HAL).") ++ else: ++ text = device.uri ++ ++ self.lblNPDeviceDescription.setText(text) ++ elif device.type=="socket": ++ if device.uri.startswith ("socket"): ++ host = device.uri[9:] ++ i = host.find (":") ++ if i != -1: ++ port = int (host[i + 1:]) ++ host = host[:i] ++ else: ++ port = 9100 ++ ++ self.entNPTDirectJetHostname.setText(host) ++ self.entNPTDirectJetPort.setText(str (port)) ++ elif device.type=="serial": ++ pass ++ """ ++ if not device.is_class: ++ options = device.uri.split("?")[1] ++ options = options.split("+") ++ option_dict = {} ++ for option in options: ++ name, value = option.split("=") ++ option_dict[name] = value ++ ++ for widget, name, optionvalues in ( ++ (self.cmbNPTSerialBaud, "baud", None), ++ (self.cmbNPTSerialBits, "bits", None), ++ (self.cmbNPTSerialParity, "parity", ++ ["none", "odd", "even"]), ++ (self.cmbNPTSerialFlow, "flow", ++ ["none", "soft", "hard", "hard"])): ++ if option_dict.has_key(name): # option given in URI? ++ if optionvalues is None: # use text in widget ++ model = widget.get_model() ++ iter = model.get_iter_first() ++ nr = 0 ++ while iter: ++ value = model.get(iter,0)[0] ++ if value == option_dict[name]: ++ widget.set_active(nr) ++ break ++ iter = model.iter_next(iter) ++ nr += 1 ++ else: # use optionvalues ++ nr = optionvalues.index( ++ option_dict[name]) ++ widget.set_active(nr+1) # compensate "Default" ++ else: ++ widget.set_active(0) ++ """ ++ ++ # XXX FILL TABS FOR VALID DEVICE URIs ++ elif device.type in ("ipp", "http"): ++ if (device.uri.startswith ("ipp:") or ++ device.uri.startswith ("http:")): ++ match = re.match ("(ipp|https?)://([^/]+)(.*)", device.uri) ++ if match: ++ server = match.group (2) ++ printer = match.group (3) ++ else: ++ server = "" ++ printer = "" ++ ++ self.entNPTIPPHostname.setText(server) ++ self.entNPTIPPQueuename.setText(printer) ++ self.lblIPPURI.setText(device.uri) ++ self.lblIPPURI.show() ++ self.entNPTIPPQueuename.show() ++ else: ++ self.entNPTIPPHostname.setText('') ++ self.entNPTIPPQueuename.setText('/printers/') ++ self.entNPTIPPQueuename.show() ++ self.lblIPPURI.hide() ++ elif device.type=="lpd": ++ if device.uri.startswith ("lpd"): ++ host = device.uri[6:] ++ i = host.find ("/") ++ if i != -1: ++ printer = host[i + 1:] ++ host = host[:i] ++ else: ++ printer = "" ++ self.cmbentNPTLpdHost.addItem(host) ++ self.cmbentNPTLpdQueue.addItem(printer) ++ elif device.uri == "lpd": ++ pass ++ elif device.uri == "smb": ++ self.entSMBURI.setText('') ++ self.btnSMBVerify.setEnabled(False) ++ elif device.type == "smb": ++ self.entSMBUsername.setText('') ++ self.entSMBPassword.setText('') ++ self.entSMBURI.setText(device.uri[6:]) ++ self.btnSMBVerify.setEnabled(True) ++ else: ++ self.entNPTDevice.setText(device.uri) ++ ++ self.setNPButtons() ++ ++ def getDeviceURI(self): ++ type = self.device.type ++ if type == "socket": # DirectJet ++ host = unicode(self.entNPTDirectJetHostname.text()) ++ port = unicode(self.entNPTDirectJetPort.text()) ++ device = "socket://" + host ++ if port: ++ device = device + ':' + port ++ elif type in ("http", "ipp"): # IPP ++ if self.lblIPPURI.isVisible: ++ device = unicode(self.lblIPPURI.text()) ++ else: ++ device = "ipp" ++ elif type == "lpd": # LPD ++ host = unicode(self.cmbentNPTLpdHost.currentText()) ++ printer = unicode(self.cmbentNPTLpdQueue.currentText()) ++ device = "lpd://" + host ++ if printer: ++ device = device + "/" + printer ++ elif type == "parallel": # Parallel ++ device = self.device.uri ++ elif type == "scsi": # SCSII ++ device = "" ++ elif type == "serial": # Serial ++ pass ++ """ ++ options = [] ++ for widget, name, optionvalues in ( ++ (self.cmbNPTSerialBaud, "baud", None), ++ (self.cmbNPTSerialBits, "bits", None), ++ (self.cmbNPTSerialParity, "parity", ++ ("none", "odd", "even")), ++ (self.cmbNPTSerialFlow, "flow", ++ ("none", "soft", "hard", "hard"))): ++ nr = widget.get_active() ++ if nr: ++ if optionvalues is not None: ++ option = optionvalues[nr-1] ++ else: ++ option = widget.get_active_text() ++ options.append(name + "=" + option) ++ options = "+".join(options) ++ device = self.device.uri.split("?")[0] #"serial:/dev/ttyS%s" ++ if options: ++ device = device + "?" + options ++ """ ++ elif type == "smb": ++ uri = unicode(self.entSMBURI.text()) ++ (group, host, share, u, p) = SMBURI (uri=uri).separate () ++ user = '' ++ password = '' ++ if self.rbtnSMBAuthSet.isChecked(): ++ user = unicode(self.entSMBUsername.text()) ++ password = unicode(self.entSMBPassword.text()) ++ uri = SMBURI (group=group, host=host, share=share, ++ user=user, password=password).get_uri () ++ device = "smb://" + uri ++ elif not self.device.is_class: ++ device = self.device.uri ++ else: ++ device = str(self.entNPTDevice.text()) ++ return device ++ # class/printer ++ ++ if nr == self.ntbkNewPrinterPages["device"]: # Device ++ valid = False ++ try: ++ uri = self.getDeviceURI () ++ valid = validDeviceURI (uri) ++ except: ++ debugprint("exception in getDeviceURI()") ++ pass ++ self.btnNPForward.setEnabled(valid) ++ self.btnNPBack.hide () ++ else: ++ self.btnNPBack.show() ++ ++ self.btnNPForward.show() ++ self.btnNPApply.hide() ++ ++ if nr == self.ntbkNewPrinterPages["name"]: # Name ++ self.btnNPBack.show() ++ if self.dialog_mode == "printer": ++ self.btnNPForward.hide() ++ self.btnNPApply.show() ++ self.btnNPApply.setEnabled( ++ self.mainapp.checkNPName(self.entNPName.getText())) ++ if nr == self.ntbkNewPrinterPages["make"]: # Make/PPD file ++ downloadable_selected = False ++ if self.rbtnNPDownloadableDriverSearch.get_active (): ++ combobox = self.cmbNPDownloadableDriverFoundPrinters ++ iter = combobox.get_active_iter () ++ if iter and combobox.get_model ().get_value (iter, 1): ++ downloadable_selected = True ++ ++ self.btnNPForward.setEnabled(bool( ++ self.rbtnNPFoomatic.get_active() or ++ not self.filechooserPPD.text().isEmpty() or ++ downloadable_selected)) ++ if nr == self.ntbkNewPrinterPages["model"]: # Model/Driver ++ model, iter = self.tvNPDrivers.get_selection().get_selected() ++ self.btnNPForward.set_sensitive(bool(iter)) ++ if nr == self.ntbkNewPrinterPages["class-members"]: # Class Members ++ self.btnNPForward.hide() ++ self.btnNPApply.show() ++ self.btnNPApply.setEnabled( ++ bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers))) ++ if nr == self.ntbkNewPrinterPages["downloadable"]: # Downloadable drivers ++ if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1: ++ accepted = self.rbtnNPDownloadLicenseYes.get_active () ++ else: ++ accepted = True ++ ++ self.btnNPForward.set_sensitive(accepted) ++ ++ # PPD ++ ++ def on_rbtnNPFoomatic_toggled(self): ++ rbtn1 = self.rbtnNPFoomatic.isChecked() ++ rbtn2 = self.rbtnNPPPD.isChecked() ++ rbtn3 = self.rbtnNPDownloadableDriverSearch.isChecked() ++ self.tvNPMakes.setEnabled(rbtn1) ++ self.filechooserPPD.setEnabled(rbtn2) ++ ++ """FIXME ++ if not rbtn3 and self.openprinting_query_handle: ++ # Need to cancel a search in progress. ++ self.openprinting.cancelOperation (self.openprinting_query_handle) ++ self.openprinting_query_handle = None ++ self.btnNPDownloadableDriverSearch_label.setText(_("Search")) ++ # Clear printer list. ++ self.cmbNPDownloadableDriverFoundPrinters.clear() ++ """ ++ ++ for widget in [self.entNPDownloadableDriverSearch, ++ self.cmbNPDownloadableDriverFoundPrinters]: ++ widget.setEnabled(rbtn3) ++ self.btnNPDownloadableDriverSearch.\ ++ setEnabled(rbtn3 and (self.openprinting_query_handle == None)) ++ ++ self.setNPButtons() ++ ++ def fillMakeList(self): ++ makes = self.ppds.getMakes() ++ self.tvNPMakes.clear() ++ found = False ++ index = 0 ++ for make in makes: ++ self.tvNPMakes.addItem(make) ++ index = index + 1 ++ if make==self.auto_make: ++ self.tvNPMakes.setCurrentRow(index-1) ++ found = True ++ ++ self.on_tvNPMakes_cursor_changed() ++ ++ def on_tvNPMakes_cursor_changed(self): ++ items = self.tvNPMakes.selectedItems() ++ if len(items) > 0: ++ self.NPMake = unicode(items[0].text()) ++ self.fillModelList() ++ ++ def fillModelList(self): ++ models = self.ppds.getModels(self.NPMake) ++ self.tvNPModels.clear() ++ selected = False ++ index = 0 ++ selected = False ++ for pmodel in models: ++ self.tvNPModels.addItem(pmodel) ++ if self.NPMake==self.auto_make and pmodel==self.auto_model: ++ self.tvNPModels.setCurrentRow(index) ++ selected = True ++ index = index + 1 ++ if not selected: ++ self.tvNPModels.setCurrentRow(0) ++ ##self.tvNPModels.columns_autosize() ++ self.on_tvNPModels_cursor_changed() ++ ++ def fillDriverList(self, pmake, pmodel): ++ self.NPModel = pmodel ++ self.tvNPDrivers.clear() ++ ++ ppds = self.ppds.getInfoFromModel(pmake, pmodel) ++ ++ self.NPDrivers = self.ppds.orderPPDNamesByPreference(ppds.keys()) ++ for i in range (len(self.NPDrivers)): ++ ppd = ppds[self.NPDrivers[i]] ++ driver = ppd["ppd-make-and-model"] ++ driver = driver.replace(" (recommended)", "") ++ ++ try: ++ lpostfix = " [%s]" % ppd["ppd-natural-language"] ++ driver += lpostfix ++ except KeyError: ++ pass ++ ++ if i == 0: ++ self.tvNPDrivers.addItem(i18nc("Recommended driver", "%1 (recommended)", driver)) ++ self.tvNPDrivers.setCurrentRow(0) ++ else: ++ self.tvNPDrivers.addItem(driver) ++ ##self.tvNPDrivers.columns_autosize() ++ ++ def on_tvNPModels_cursor_changed(self): ++ items = self.tvNPModels.selectedItems() ++ if len(items) > 0: ++ pmodel = unicode(items[0].text()) ++ self.fillDriverList(self.NPMake, pmodel) ++ ++ def getNPPPD(self): ++ try: ++ if self.rbtnNPFoomatic.isChecked(): ++ #items = self.tvNPDrivers.selectedItems() ++ #nr = unicode(items[0]) ++ nr = self.tvNPDrivers.currentRow() ++ ppd = self.NPDrivers[nr] ++ elif self.rbtnNPPPD.isChecked(): ++ ppd = cups.PPD(unicode(self.filechooserPPD.text())) ++ else: ++ """FIXME ++ # PPD of the driver downloaded from OpenPrinting XXX ++ treeview = self.tvNPDownloadableDrivers ++ model, iter = treeview.get_selection ().get_selected () ++ driver = model.get_value (iter, 1) ++ if driver.has_key ('ppds'): ++ # Only need to download a PPD. ++ file_to_download = driver ++ """ ++ ++ ppd = "XXX" ++ ++ except RuntimeError, e: ++ if self.rbtnNPFoomatic.isChecked(): ++ # Foomatic database problem of some sort. ++ err_title = i18n('Database error') ++ model, iter = (self.tvNPDrivers.get_selection(). ++ get_selected()) ++ nr = model.get_path(iter)[0] ++ driver = self.NPDrivers[nr] ++ if driver.startswith ("gutenprint"): ++ # This printer references some XML that is not ++ # installed by default. Point the user at the ++ # package they need to install. ++ err = i18n("You will need to install the '%1' package " ++ "in order to use this driver.", ++ "gutenprint-foomatic") ++ else: ++ err = i18n("The '%1' driver cannot be " ++ "used with printer '%2 %3'.", driver, self.NPMake, self.NPModel) ++ elif self.rbtnNPPPD.isChecked(): ++ # This error came from trying to open the PPD file. ++ err_title = i18n('PPD error') ++ filename = self.filechooserPPD.text() ++ err = i18n('Failed to read PPD file. Possible reason ' ++ 'follows:') + '\n' ++ os.environ["PPD"] = filename ++ # We want this to be in the current natural language, ++ # so we intentionally don't set LC_ALL=C here. ++ p = os.popen ('/usr/bin/cupstestppd -rvv "$PPD"', 'r') ++ output = p.readlines () ++ p.close () ++ err += reduce (lambda x, y: x + y, output) ++ else: ++ # Failed to get PPD downloaded from OpenPrinting XXX ++ err_title = i18n('Downloadable drivers') ++ err_text = i18n("Support for downloadable " ++ "drivers is not yet completed.") ++ ++ error_text = ('' + ++ i18nc("Error title", "%1", err_title) + '\n\n' + err) ++ KMessageBox.error(self, error_text, err_title) ++ return None ++ ++ if isinstance(ppd, str) or isinstance(ppd, unicode): ++ try: ++ if (ppd != "raw"): ++ f = self.mainapp.cups.getServerPPD(ppd) ++ ppd = cups.PPD(f) ++ os.unlink(f) ++ except AttributeError: ++ nonfatalException() ++ debugprint ("pycups function getServerPPD not available: never mind") ++ except RuntimeError: ++ nonfatalException() ++ debugprint ("libcups from CUPS 1.3 not available: never mind") ++ except cups.IPPError: ++ nonfatalException() ++ debugprint ("CUPS 1.3 server not available: never mind") ++ ++ return ppd ++ ++ # Create new Printer ++ @pyqtSignature("") ++ def on_btnNPApply_clicked(self): ++ if self.dialog_mode in ("class", "printer"): ++ name = unicode(self.entNPName.text()) ++ location = unicode(self.entNPLocation.text()) ++ info = unicode(self.entNPDescription.text()) ++ else: ++ name = self.mainapp.printer.name ++ ++ #replace any whitespace in printer name with underscore otherwise ++ #CUPS throws an error ++ name = name.replace(" ", "_") ++ ++ # Whether to check for missing drivers. ++ check = False ++ checkppd = None ++ ppd = self.ppd ++ ++ if self.dialog_mode=="class": ++ members = self.mainapp.getCurrentClassMembers(self.tvNCMembers) ++ try: ++ for member in members: ++ self.passwd_retry = False # use cached Passwd ++ self.mainapp.cups.addPrinterToClass(str(member), name) ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ return ++ elif self.dialog_mode=="printer": ++ self.device.uri = unicode(self.device.uri) ++ uri = None ++ if self.device.uri: ++ uri = self.device.uri ++ else: ++ uri = self.getDeviceURI() ++ if not self.ppd: # XXX needed? ++ # Go back to previous page to re-select driver. ++ self.nextNPTab(-1) ++ return ++ ++ # write Installable Options to ppd ++ for option in self.options.itervalues(): ++ option.writeback() ++ ++ self.mainapp.busy(self) ++ self.WaitWindow.setText(i18n('Adding') + '

' + ++ i18n('Adding printer')) ++ #self.WaitWindow.set_transient_for (self.NewPrinterWindow) ++ self.WaitWindow.show () ++ KApplication.processEvents() ++ try: ++ self.passwd_retry = False # use cached Passwd ++ if isinstance(ppd, str) or isinstance(ppd, unicode): ++ self.mainapp.cups.addPrinter(name, ppdname=ppd, ++ device=uri, info=info, location=location) ++ check = True ++ elif ppd is None: # raw queue ++ self.mainapp.cups.addPrinter(name, device=uri, ++ info=info, location=location) ++ else: ++ cupshelpers.setPPDPageSize(ppd, self.language[0]) ++ self.mainapp.cups.addPrinter(name, ppd=ppd, ++ device=uri, info=info, location=location) ++ check = True ++ checkppd = ppd ++ cupshelpers.activateNewPrinter (self.mainapp.cups, name) ++ except cups.IPPError, (e, msg): ++ #self.ready(self) ++ self.WaitWindow.hide () ++ self.show_IPP_Error(e, msg) ++ return ++ except: ++ ##self.ready (self.NewPrinterWindow) ++ self.WaitWindow.hide () ++ fatalException (1) ++ self.WaitWindow.hide () ++ ##self.ready (self.NewPrinterWindow) ++ #comment ++ if self.dialog_mode in ("class", "printer"): ++ try: ++ self.passwd_retry = False # use cached Passwd ++ self.mainapp.cups.setPrinterLocation(name, location) ++ self.passwd_retry = False # use cached Passwd ++ self.mainapp.cups.setPrinterInfo(name, info) ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ return ++ elif self.dialog_mode == "device": ++ try: ++ uri = self.getDeviceURI() ++ self.mainapp.cups.addPrinter(name, device=uri) ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ return ++ elif self.dialog_mode == "ppd": ++ if not ppd: ++ ppd = self.ppd = self.getNPPPD() ++ if not ppd: ++ # Go back to previous page to re-select driver. ++ self.nextNPTab(-1) ++ return ++ ++ # set ppd on server and retrieve it ++ # cups doesn't offer a way to just download a ppd ;(= ++ raw = False ++ if isinstance(ppd, str) or isinstance(ppd, unicode): ++ if self.rbtnChangePPDasIs.isChecked(): ++ # To use the PPD as-is we need to prevent CUPS copying ++ # the old options over. Do this by setting it to a ++ # raw queue (no PPD) first. ++ try: ++ self.mainapp.cups.addPrinter(name, ppdname='raw') ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ try: ++ self.mainapp.cups.addPrinter(name, ppdname=ppd) ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ return ++ ++ try: ++ filename = self.mainapp.cups.getPPD(name) ++ ppd = cups.PPD(filename) ++ os.unlink(filename) ++ except cups.IPPError, (e, msg): ++ if e == cups.IPP_NOT_FOUND: ++ raw = True ++ else: ++ self.show_IPP_Error(e, msg) ++ return ++ else: ++ # We have an actual PPD to upload, not just a name. ++ if not self.rbtnChangePPDasIs.isChecked(): ++ cupshelpers.copyPPDOptions(self.mainapp.ppd, ppd) # XXX ++ else: ++ # write Installable Options to ppd ++ for option in self.options.itervalues(): ++ option.writeback() ++ cupshelpers.setPPDPageSize(ppd, self.language[0]) ++ ++ try: ++ self.mainapp.cups.addPrinter(name, ppd=ppd) ++ except cups.IPPError, (e, msg): ++ self.show_IPP_Error(e, msg) ++ ++ if not raw: ++ check = True ++ checkppd = ppd ++ ++ self.accept() ++ self.mainapp.populateList(start_printer=name) ++ if check: ++ try: ++ self.checkDriverExists (name, ppd=checkppd) ++ except: ++ nonfatalException() ++ ++ # Also check to see whether the media option has become ++ # invalid. This can happen if it had previously been ++ # explicitly set to a page size that is not offered with ++ # the new PPD (see bug #441836). ++ """ ++ try: ++ option = self.mainapp.server_side_options['media'] ++ if option.get_current_value () == None: ++ debugprint ("Invalid media option: resetting") ++ option.reset () ++ self.mainapp.changed.add (option) ++ self.mainapp.save_printer (self.mainapp.printer) ++ except KeyError: ++ pass ++ except: ++ print "exception in check to see whether the media option has become invalid" ++ nonfatalException() ++ """ ++ ++ def show_IPP_Error(self, exception, message): ++ if exception == cups.IPP_NOT_AUTHORIZED: ++ KMessageBox.error(self, i18n('The password may be incorrect.'), i18n('Not authorized')) ++ else: ++ KMessageBox.error(self, i18n("There was an error during the CUPS " "operation: '%1'.", message), ++ i18n('CUPS server error')) ++ ++ def checkDriverExists(self, name, ppd=None): ++ """Check that the driver for an existing queue actually ++ exists, and prompt to install the appropriate package ++ if not. ++ ++ ppd: cups.PPD object, if already created""" ++ ++ # Is this queue on the local machine? If not, we can't check ++ # anything at all. ++ server = cups.getServer () ++ if not (server == 'localhost' or server == '127.0.0.1' or ++ server == '::1' or server[0] == '/'): ++ return ++ ++ # Fetch the PPD if we haven't already. ++ if not ppd: ++ try: ++ filename = self.mainapp.cups.getPPD(name) ++ except cups.IPPError, (e, msg): ++ if e == cups.IPP_NOT_FOUND: ++ # This is a raw queue. Nothing to check. ++ return ++ else: ++ self.show_IPP_Error(e, msg) ++ return ++ ++ ppd = cups.PPD(filename) ++ os.unlink(filename) ++ ++ (pkgs, exes) = cupshelpers.missingPackagesAndExecutables (ppd) ++ if len (pkgs) > 0 or len (exes) > 0: ++ # We didn't find a necessary executable. Complain. ++ install = "/usr/bin/system-install-packages" ++ if len (pkgs) > 0 and os.access (install, os.X_OK): ++ pkg = pkgs[0] ++ install_text = ('' + ++ i18n('Install driver') + '\n\n' + ++ i18n("Printer '%1' requires the %2 package but " ++ "it is not currently installed.", name, pkg)) ++ dialog = self.InstallDialog ++ self.lblInstall.set_markup(install_text) ++ else: ++ error_text = ('' + ++ i18n('Missing driver') + '\n\n' + ++ i18n("Printer '%1' requires the '%2' program but " ++ "it is not currently installed. Please " ++ "install it before using this printer.", name, (exes + pkgs)[0])) ++ KMessageBox.error(self, error_text, "Missing Driver") ++ ++ """ ++ if pkg and response == gtk.RESPONSE_OK: ++ # Install the package. ++ def wait_child (sig, stack): ++ (pid, status) = os.wait () ++ ++ signal.signal (signal.SIGCHLD, wait_child) ++ pid = os.fork () ++ if pid == 0: ++ # Child. ++ try: ++ os.execv (install, [install, pkg]) ++ except: ++ pass ++ sys.exit (1) ++ elif pid == -1: ++ pass # should handle error ++ """ ++ ++ #FIXME obsolete? ++ def on_entNPTIPPQueuename_textChanged(self, ent): ++ self.update_IPP_URI_label () ++ ++ #FIXME not in gnome? ++ @pyqtSignature("") ++ def on_btnNPCancel_clicked(self): ++ self.hide() ++ ++ #copy busy and ready functions from the mainapp ++ #since they can't be inherited from the mainapp ++ def busy (self, win = None): ++ try: ++ if not win: ++ win = self ++ win.setCursor(Qt.WaitCursor) ++ KApplication.processEvents() ++ except: ++ nonfatalException () ++ ++ def ready (self, win = None): ++ try: ++ if not win: ++ win = self ++ win.setCursor(Qt.ArrowCursor) ++ KApplication.processEvents() ++ except: ++ nonfatalException () ++#end of class NewPrinterGUI ++ ++class IPPBrowseDialog(QDialog): ++ ++ def __init__(self, newprinter): ++ QDialog.__init__(self, newprinter) ++ self.newprinter = newprinter ++ ++ self.language = newprinter.language ++ self.dialog_mode = "" ++ ++ self.WaitWindow = QMessageBox(self.newprinter) ++ self.WaitWindow.setStandardButtons(QMessageBox.NoButton) ++ ++ uic.loadUi(APPDIR + "/" + "ipp-browse-dialog.ui", self) ++ ++ self.btnIPPBrowseOk.setEnabled(False) ++ self.show() ++ ++ #create an empty data model ++ self.ippStore = self.twIPPBrowser ++ self.twIPPBrowser.sortByColumn(0, Qt.AscendingOrder) ++ ++ #Set tree header labels. Takes list of strings ++ self.ippStore.setHeaderLabels([_("Share"), _("Comment")]) ++ ++ self.browse_ipp_queues() ++ ++ def browse_ipp_queues(self): ++ if not self.newprinter.ipp_lock.acquire(0): ++ return ++ self.browse_ipp_queues_thread() ++ ++ def browse_ipp_queues_thread(self): ++ host = None ++ try: ++ store = self.ippStore ++ store.clear () ++ items = QTreeWidgetItem(QStringList([_('Scanning...'), ''])) ++ store.addTopLevelItem(items) ++ ++ host = self.newprinter.entNPTIPPHostname.text() ++ except: ++ nonfatalException() ++ ++ oldserver = cups.getServer () ++ printers = classes = {} ++ failed = False ++ port = 631 ++ ++ if host != None: ++ #need to pass a unicode string. urllib falls over QStrings ++ (host, port) = urllib.splitnport (unicode(host), defport=port) ++ ++ try: ++ c = cups.Connection (host=host, port=port) ++ printers = c.getPrinters () ++ del c ++ except cups.IPPError, (e, m): ++ debugprint ("IPP browser: %s" % m) ++ failed = True ++ except: ++ nonfatalException() ++ failed = True ++ cups.setServer (oldserver) ++ ++ try: ++ store.clear () ++ for printer, dict in printers.iteritems (): ++ #only these properties seem to be used from dict so ++ #just store these instead of whole dict ++ location = dict.get('printer-location', '') ++ uri = dict.get('printer-uri-supported', 'ipp') ++ items = QTreeWidgetItem(QStringList([printer, location, uri])) ++ store.addTopLevelItem(items) ++ ++ if len (printers) + len (classes) == 0: ++ # Display 'No queues' dialog ++ if failed: ++ title = _("Not possible") ++ text = (_("It is not possible to obtain a list of queues " ++ "from `%s'.") % host + '\n\n' + ++ _("Obtaining a list of queues is a CUPS extension " ++ "to IPP. Network printers do not support it.")) ++ else: ++ title = _("No queues") ++ text = _("There are no queues available.") ++ ++ self.hide () ++ KMessageBox.error (self.newprinter, text, title) ++ ++ try: ++ self.ready(self) ++ except: ++ nonfatalException() ++ ++ self.newprinter.ipp_lock.release() ++ except: ++ nonfatalException() ++ ++ ++ def on_twIPPBrowser_itemClicked(self): ++ self.btnIPPBrowseOk.setEnabled(True) ++ ++ def on_btnIPPBrowseOk_clicked(self): ++ index = self.twIPPBrowser.currentIndex() ++ item = self.twIPPBrowser.itemFromIndex(index) ++ queue = item.text(0) ++ uri = unicode(item.text(2)) ++ self.hide() ++ self.newprinter.entNPTIPPQueuename.setText (queue) ++ self.newprinter.entNPTIPPQueuename.show() ++ #uri = dict.get('printer-uri-supported', 'ipp') ++ match = re.match ("(ipp|https?)://([^/]+)(.*)", uri) ++ if match: ++ self.newprinter.entNPTIPPHostname.setText (match.group (2)) ++ self.newprinter.entNPTIPPQueuename.setText (match.group (3)) ++ ++ self.newprinter.lblIPPURI.setText (uri) ++ self.newprinter.lblIPPURI.show() ++ self.newprinter.setNPButtons() ++ ++ def on_btnIPPBrowseCancel_clicked(self): ++ self.hide() ++ ++ def on_btnIPPBrowseRefresh_clicked(self): ++ self.browse_ipp_queues() ++ ++ #copy busy and ready functions from the mainapp ++ #since they can't be inherited from the mainapp ++ def busy (self, win = None): ++ try: ++ if not win: ++ win = self ++ win.setCursor(Qt.WaitCursor) ++ KApplication.processEvents() ++ except: ++ nonfatalException () ++ ++ def ready (self, win = None): ++ try: ++ if not win: ++ win = self ++ win.setCursor(Qt.ArrowCursor) ++ KApplication.processEvents() ++ except: ++ nonfatalException () ++#End of class IPPBrowseDialog ++ ++#Needed to iterate over a QTreeWidgetItem for the user access ++#list ++class Iter(QTreeWidgetItemIterator): ++ def __init__(self, *args): ++ QTreeWidgetItemIterator.__init__(self, *args) ++ def next(self): ++ self.__iadd__(1) ++ value = self.value() ++ if not value: ++ raise StopIteration ++ else: ++ return self.value() ++ ++def CreatePlugin(widget_parent, parent, component_data): ++ u = GUI() ++ kcm = u.makeui(component_data, widget_parent) ++ return kcm ++ ++#if __name__ == "__main__": ++ #"""start the application""" ++ ++ #appName = "system-config-printer-kde" ++ #catalogue = "system-config-printer-kde" ++ #programName = ki18n("System Config Printer KDE") ++ #version = "1.0" ++ #description = ki18n("Printer configuration tool") ++ #license = KAboutData.License_GPL ++ #copyright = ki18n("2007 Tim Waugh, Red Hat Inc, 2007-2008 Canonical Ltd") ++ #text = KLocalizedString() ++ #homePage = "https://launchpad.net/system-config-printer" ++ #bugEmail = "" ++ ++ #aboutData = KAboutData (appName, catalogue, programName, version, description, ++ #license, copyright, text, homePage, bugEmail) ++ ++ #aboutData.addAuthor(ki18n("Jonathan Riddell"), ki18n("Author")) ++ #aboutData.addAuthor(ki18n("Tim Waugh/Red Hat"), ki18n("System Config Printer Author")) ++ ++ #options = KCmdLineOptions() ++ ++ #KCmdLineArgs.init(sys.argv, aboutData) ++ #KCmdLineArgs.addCmdLineOptions(options) ++ ++ #app = KApplication() ++ #args = KCmdLineArgs.parsedArgs() ++ ++ #applet = GUI() ++ #sys.exit(app.exec_()) +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/new-printer.ui kdeadmin-4.2.2/system-config-printer-kde/new-printer.ui +--- orig/kdeadmin-4.2.2/system-config-printer-kde/new-printer.ui 2008-11-04 17:13:05.000000000 +0000 ++++ kdeadmin-4.2.2/system-config-printer-kde/new-printer.ui 2009-04-09 22:56:08.000000000 +0100 +@@ -1,65 +1,66 @@ +- ++ ++ + form +- +- ++ ++ + + 0 + 0 + 707 +- 534 ++ 583 + + +- ++ + Dialog + +- ++ + + ../../../../.designer/backup/printer-128.png../../../../.designer/backup/printer-128.png + +- +- +- +- ++ ++ ++ ++ + 1 + +- +- +- +- +- ++ ++ ++ ++ ++ + Printer Name + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + Description + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + Location + + + +- +- ++ ++ + +- ++ + +- ++ + Qt::Vertical + +- ++ + + 691 + 40 +@@ -69,45 +70,45 @@ + + + +- +- +- +- +- ++ ++ ++ ++ ++ + Select Connection + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + 7 + +- +- +- +- +- ++ ++ ++ ++ ++ + Description + + + +- +- +- ++ ++ ++ + Device Description + + + +- ++ + +- ++ + Qt::Vertical + +- ++ + + 20 + 40 +@@ -117,24 +118,24 @@ + + + +- +- +- +- +- ++ ++ ++ ++ ++ + Enter Device URI + + + +- +- ++ ++ + +- ++ + +- ++ + Qt::Vertical + +- ++ + + 20 + 330 +@@ -144,41 +145,41 @@ + + + +- +- +- +- +- ++ ++ ++ ++ ++ + Location of the Network Printer + + + +- +- +- ++ ++ ++ + Host: + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + Port number: + + + +- +- ++ ++ + +- ++ + +- ++ + Qt::Vertical + +- ++ + + 328 + 299 +@@ -188,72 +189,72 @@ + + + +- +- +- +- +- ++ ++ ++ ++ ++ + IPP Printer + + + +- +- +- ++ ++ ++ + Host: + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + true + +- ++ + Find Queue... + + + +- +- +- ++ ++ ++ + Queue: + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + URI: + + + +- +- +- ++ ++ ++ + ... + + + +- +- +- ++ ++ ++ + Verify... + + + +- +- +- ++ ++ ++ + Qt::Horizontal + +- ++ + + 298 + 20 +@@ -261,12 +262,12 @@ + + + +- +- +- ++ ++ ++ + Qt::Vertical + +- ++ + + 418 + 297 +@@ -276,61 +277,61 @@ + + + +- +- +- +- +- ++ ++ ++ ++ ++ + Location of the LPD network printer + + + +- +- +- ++ ++ ++ + Host: + + + +- +- +- ++ ++ ++ + true + + +- +- localhost ++ ++ localhost + + + + +- +- +- ++ ++ ++ + Probe + + + +- +- +- ++ ++ ++ + Queue: + + + +- +- +- ++ ++ ++ + true + + + +- ++ + +- ++ + Qt::Vertical + +- ++ + + 288 + 295 +@@ -340,9 +341,9 @@ + + + +- +- +- ++ ++ ++ + + 30 + 80 +@@ -350,14 +351,14 @@ + 20 + + +- ++ + TODO, SCSI + + + +- +- +- ++ ++ ++ + + 60 + 90 +@@ -365,144 +366,213 @@ + 20 + + +- ++ + TODO serial + + + +- +- +- +- +- ++ ++ ++ ++ ++ + SMB Printer + + + +- +- +- ++ ++ ++ + smb:// + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + Browse + + + +- +- +- +- <i>smb://[workgroup/]server[:port]/printer</i> ++ ++ ++ ++ <i>smb://[workgroup/]server[:port]/printer</i> + + + +- +- +- ++ ++ ++ + Authentication + + + +- +- +- ++ ++ ++ + Prompt user if authentication is required + + + +- +- +- ++ ++ ++ + Set authentication details now + + + +- +- +- +- Qt::Horizontal +- +- +- +- 169 +- 68 +- +- +- +- +- +- +- +- +- +- +- QLineEdit::Password +- +- +- +- +- +- +- Password: +- +- +- +- +- +- +- +- +- +- Username: +- +- +- +- +- entSMBPassword +- label_26 +- entSMBUsername +- label_25 +- +- +- +- +- +- Verify +- +- +- +- +- +- +- Qt::Horizontal +- +- +- +- 188 +- 28 +- +- +- +- +- +- +- +- Qt::Vertical +- +- +- +- 404 +- 216 +- +- +- ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QSizePolicy::Fixed ++ ++ ++ ++ 128 ++ 62 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 76 ++ 35 ++ 115 ++ 27 ++ ++ ++ ++ QLineEdit::Password ++ ++ ++ ++ ++ ++ 4 ++ 35 ++ 68 ++ 27 ++ ++ ++ ++ Password: ++ ++ ++ ++ ++ ++ 76 ++ 4 ++ 115 ++ 27 ++ ++ ++ ++ ++ ++ ++ 4 ++ 4 ++ 68 ++ 27 ++ ++ ++ ++ Username: ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QSizePolicy::Fixed ++ ++ ++ ++ 68 ++ 17 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QSizePolicy::Minimum ++ ++ ++ ++ 198 ++ 22 ++ ++ ++ ++ ++ ++ ++ ++ Verify ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QSizePolicy::Fixed ++ ++ ++ ++ 78 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 415 ++ 208 ++ ++ ++ ++ ++ + + + +@@ -510,118 +580,118 @@ + + + +- +- +- +- +- ++ ++ ++ ++ ++ + Select printer from database + + + +- +- +- ++ ++ ++ + The foomatic printer database contains various manufacturer provided PostScript Printer Description (PPD) files and also can generate PPD files for a large number of (non PostScript) printers. But in general manufacturer provided PPD files provide better access to the specific features of the printer. + +- ++ + true + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + Provide PPD file + + + +- +- +- +- <qt>PostScript Printer Description (PPD) files can often be found on the driver disk that comes with the printer. For PostScript printers they are often part of the Windows<sup>®</sup> driver.</qt> ++ ++ ++ ++ <qt>PostScript Printer Description (PPD) files can often be found on the driver disk that comes with the printer. For PostScript printers they are often part of the Windows<sup>®</sup> driver.</qt> + +- ++ + true + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + Browse + + + +- +- +- +- +- +- ++ ++ ++ ++ ++ ++ + Search for a printer driver to download + + + +- +- +- ++ ++ ++ + Enter some search terms for the model of your printer. + + + +- +- +- ++ ++ ++ + Search terms: + + + +- +- ++ ++ + +- +- +- ++ ++ ++ + Search + + + +- +- +- ++ ++ ++ + Printer model: + + + +- +- ++ ++ + + + + + + +- +- +- +- ++ ++ ++ ++ + +- +- ++ ++ + +- ++ + +- ++ + Qt::Horizontal + +- ++ + + 296 + 28 +@@ -629,55 +699,55 @@ + + + +- +- +- ++ ++ ++ + Comments + + + +- +- +- ++ ++ ++ + Models: + + + +- +- +- ++ ++ ++ + Driver: + + + + + +- +- +- +- +- ++ ++ ++ ++ ++ + Printers to be members of this class + + + +- +- +- +- +- ++ ++ ++ ++ ++ + Members of this class + + + +- +- ++ ++ + + +- ++ + Qt::Vertical + +- ++ + + 20 + 40 +@@ -686,25 +756,25 @@ + + + +- +- +- < ++ ++ ++ + + + + +- +- +- > ++ ++ ++ + + + + + +- ++ + Qt::Vertical + +- ++ + + 20 + 291 +@@ -714,72 +784,72 @@ + + + +- +- +- ++ ++ ++ + Others + + + +- +- ++ ++ + +- +- ++ ++ + + + + + +- +- +- +- +- ++ ++ ++ ++ ++ + Try to transfer the current settings + + + +- +- +- ++ ++ ++ + Use the new PPD (Postscript Printer Description) as is. + + + +- +- +- +- This way all current option settings will be lost. The default settings of the new PPD will be used. ++ ++ ++ ++ This way all current option settings will be lost. The default settings of the new PPD will be used. + +- ++ + true + + + +- +- +- +- Try to copy the option settings over from the old PPD. ++ ++ ++ ++ Try to copy the option settings over from the old PPD. + + + +- +- +- ++ ++ ++ + This is done by assuming that options with the same name do have the same meaning. Settings of options that are not present in the new PPD will be lost and options only present in the new PPD will be set to default. + +- ++ + true + + + +- +- +- ++ ++ ++ + Qt::Vertical + +- ++ + + 638 + 317 +@@ -787,14 +857,14 @@ + + + +- +- ++ ++ + + + +- +- +- ++ ++ ++ + + 60 + 50 +@@ -802,14 +872,14 @@ + 20 + + +- ++ + TODO: Installed Options page + + + +- +- +- ++ ++ ++ + + 30 + 60 +@@ -817,19 +887,19 @@ + 20 + + +- ++ + TODO: Downloadable Driver page + + + + + +- ++ + +- ++ + Qt::Horizontal + +- ++ + + 121 + 20 +@@ -837,30 +907,30 @@ + + + +- +- +- +- < Back ++ ++ ++ ++ Back + + + +- +- +- +- Forward > ++ ++ ++ ++ Forward + + + +- +- +- ++ ++ ++ + OK + + + +- +- +- ++ ++ ++ + Cancel + + +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/options.py kdeadmin-4.2.2/system-config-printer-kde/options.py +--- orig/kdeadmin-4.2.2/system-config-printer-kde/options.py 1970-01-01 01:00:00.000000000 +0100 ++++ kdeadmin-4.2.2/system-config-printer-kde/options.py 2009-04-09 22:56:08.000000000 +0100 +@@ -0,0 +1,398 @@ ++# -*- coding: utf-8 -*- ++## system-config-printer ++ ++############################################################################# ++## ++## Copyright 2007-2009 Canonical Ltd ++## Copyright 2008-2009 Richard Birnie ++## Author: Jonathan Riddell ++## Richard Birnie ++## ++## Includes code from System Config Printer: ++## Copyright (C) 2006, 2007, 2008 Red Hat, Inc. ++## Copyright (C) 2006, 2007 Florian Festi ++## Copyright (C) 2006, 2007, 2008 Tim Waugh ++## ++## This program is free software; you can redistribute it and/or ++## modify it under the terms of the GNU General Public License as ++## published by the Free Software Foundation; either version 2 of ++## the License, or (at your option) any later version. ++## ++## This program is distributed in the hope that it will be useful, ++## but WITHOUT ANY WARRANTY; without even the implied warranty of ++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++## GNU General Public License for more details. ++## ++## You should have received a copy of the GNU General Public License ++## along with this program. If not, see . ++## ++############################################################################# ++ ++from PyQt4.QtCore import * ++from PyQt4.QtGui import * ++ ++""" ++These classes are used in the Job Options tab of the printer config dialogue ++""" ++ ++def OptionWidget(name, v, s, on_change): ++ if isinstance(v, list): ++ # XXX ++ if isinstance(s, list): ++ for vv in v + s: ++ if not isinstance(vv, str): raise ValueError ++ return OptionSelectMany(name, v, s, on_change) ++ print v, s ++ raise NotImplemented ++ else: ++ if (isinstance(s, int) or ++ isinstance(s, float) or ++ (isinstance(s, tuple) and ++ len(s) == 2 and ++ ((isinstance(s[0], int) and isinstance(s[1], int)) or ++ (isinstance(s[0], float) and isinstance(s[1], float))))): ++ try: ++ if (isinstance(s, int) or ++ isinstance(s, tuple) and isinstance(s[0], int)): ++ v = int(v) ++ else: ++ v = float(v) ++ except ValueError: ++ return OptionText(name, v, "", on_change) ++ return OptionNumeric(name, v, s, on_change) ++ elif isinstance(s, list): ++ for sv in s: ++ if not isinstance(sv, int): ++ return OptionSelectOne(name, v, s, on_change) ++ try: ++ v = int(v) ++ except ValueError: ++ return OptionSelectOne(name, v, s, on_change) ++ return OptionSelectOneNumber(name, v, s, on_change) ++ elif isinstance(s, str): ++ return OptionText(name, v, s, on_change) ++ else: ++ raise ValueError ++ ++# --------------------------------------------------------------------------- ++ ++class OptionInterface: ++ def get_current_value(self): ++ raise NotImplemented ++ ++ def is_changed(self): ++ raise NotImplemented ++ ++class OptionAlwaysShown(OptionInterface): ++ # States ++ STATE_UNCHANGED=0 ++ STATE_RESET=1 ++ STATE_ADJUSTED=2 ++ ++ def __init__(self, name, ipp_type, system_default, ++ widget, button, combobox_map = None, use_supported = False): ++ self.name = name ++ self.widget = widget ++ self.button = button ++ if ipp_type == bool: ++ def bool_type (x): ++ if type (x) == str: ++ if x.lower () in ("false", "no", "off"): ++ return False ++ # Even the empty string is true. ++ return True ++ return bool (x) ++ ipp_type = bool_type ++ self.ipp_type = ipp_type ++ self.set_default (system_default) ++ self.combobox_map = combobox_map ++ if combobox_map != None and ipp_type == int: ++ i = 0 ++ dict = {} ++ while i < self.widget.count(): ++ dict[combobox_map[i]] = self.widget.itemText(i) ++ i += 1 ++ self.combobox_dict = dict ++ self.use_supported = use_supported ++ self.reinit (None) ++ ++ def set_default(self, system_default): ++ # For the media option, the system default depends on the printer's ++ # PageSize setting. This method allows the main module to tell us ++ # what that is. ++ self.system_default = self.ipp_type (system_default) ++ ++ def reinit(self, original_value, supported=None): ++ """Set the original value of the option and the supported choices. ++ The special value None for original_value resets the option to the ++ system default.""" ++ if (supported != None and ++ self.use_supported): ++ if (type(self.widget) == QComboBox and ++ self.ipp_type == str): ++ self.widget.clear() ++ for each in supported: ++ self.widget.addItem(each) ++ elif (type(self.widget) == QComboBox and ++ self.ipp_type == int and ++ self.combobox_map != None): ++ self.widget.clear() ++ for each in supported: ++ self.widget.addItem(self.combobox_dict[each]) ++ if original_value != None: ++ self.original_value = self.ipp_type (original_value) ++ self.set_widget_value (self.original_value) ++ if original_value != self.get_widget_value(): ++ self.button.setEnabled(True) ++ else: ++ self.original_value = None ++ self.set_widget_value (self.system_default) ++ self.button.setEnabled(False) ++ self.state = self.STATE_UNCHANGED ++ ++ def set_widget_value(self, ipp_value): ++ t = type(self.widget) ++ if t == QSpinBox: ++ return self.widget.setValue(ipp_value) ++ elif t == QComboBox: ++ if self.ipp_type == str and self.combobox_map == None: ++ index = self.widget.findText(ipp_value) ++ if index != -1: ++ self.widget.setCurrentIndex(index) ++ else: ++ # It's an int. ++ if self.combobox_map: ++ index = self.combobox_map.index (ipp_value) ++ else: ++ index = ipp_value ++ return self.widget.setCurrentIndex(index) ++ elif t == QCheckBox: ++ return self.widget.setChecked(ipp_value) ++ else: ++ raise NotImplemented ++ ++ def get_widget_value(self): ++ t = type(self.widget) ++ if t == QSpinBox: ++ # Ideally we would use self.widget.get_value() here, but ++ # it doesn't work if the value has been typed in and then ++ # the Apply button immediately clicked. To handle this, ++ # we use self.widget.get_text() and fall back to ++ # get_value() if the result cannot be interpreted as the ++ # type we expect. ++ try: ++ return self.ipp_type (self.widget.value ()) ++ except ValueError: ++ # Can't convert result of get_text() to ipp_type. ++ return self.ipp_type (self.widget.value ()) ++ elif t == QComboBox: ++ if self.combobox_map: ++ return self.combobox_map[self.widget.currentIndex()] ++ if self.ipp_type == str: ++ return self.widget.currentText() ++ return self.ipp_type (unicode(self.widget.currentText())) ++ elif t == QCheckBox: ++ return self.ipp_type (self.widget.isChecked()) ++ ++ raise NotImplemented ++ ++ def get_current_value(self): ++ return self.get_widget_value () ++ ++ def is_changed(self): ++ if self.original_value != None: ++ # There was a value set previously. ++ if self.state == self.STATE_RESET: ++ # It's been removed. ++ return True ++ if self.state == self.STATE_ADJUSTED: ++ if self.get_current_value () != self.original_value: ++ return True ++ return False ++ ++ # The value is the same as before, and not reset. ++ return False ++ ++ # There was no original value set. ++ if self.state == self.STATE_ADJUSTED: ++ # It's been adjusted. ++ return True ++ ++ # It's been left alone, or possible adjusted and then reset. ++ return False ++ ++ def reset(self): ++ self.set_widget_value (self.system_default) ++ self.state = self.STATE_RESET ++ self.button.setEnabled(False) ++ ++ def changed(self): ++ self.state = self.STATE_ADJUSTED ++ self.button.setEnabled(True) ++ ++class OptionAlwaysShownSpecial(OptionAlwaysShown): ++ def __init__(self, name, ipp_type, system_default, ++ widget, button, combobox_map = None, use_supported = False, ++ special_choice = "System default"): ++ self.special_choice = special_choice ++ self.special_choice_shown = False ++ OptionAlwaysShown.__init__ (self, name, ipp_type, system_default, ++ widget, button, ++ combobox_map=combobox_map, ++ use_supported=use_supported) ++ ++ def show_special_choice (self): ++ if self.special_choice_shown: ++ return ++ ++ self.special_choice_shown = True ++ # Only works for ComboBox widgets ++ self.widget.insertItem(0, self.special_choice) ++ self.widget.setCurrentIndex(0) ++ ##model = self.widget.get_model () ++ ##iter = model.insert (0) ++ ##model.set_value (iter, 0, self.special_choice) ++ ##self.widget.set_active_iter (model.get_iter_first ()) ++ ++ def hide_special_choice (self): ++ if not self.special_choice_shown: ++ return ++ ++ self.special_choice_shown = False ++ # Only works for ComboBox widgets ++ self.widget.removeItem(0) ++ ++ def reinit(self, original_value, supported=None): ++ if original_value != None: ++ self.hide_special_choice () ++ else: ++ self.show_special_choice () ++ ++ OptionAlwaysShown.reinit (self, original_value, supported=supported) ++ ++ def reset(self): ++ self.show_special_choice () ++ OptionAlwaysShown.reset (self) ++ ++ def changed(self): ++ OptionAlwaysShown.changed (self) ++ if self.widget.currentIndex() > 0: ++ self.hide_special_choice () ++ ++class Option(OptionInterface): ++ ++ conflicts = None ++ ++ def __init__(self, name, value, supported, on_change): ++ self.name = name ++ self.value = value ++ self.supported = supported ++ self.on_change = on_change ++ self.is_new = False ++ ++ label = unicode(name) ++ if not label.endswith (':'): ++ label += ':' ++ self.label = QLabel(label) ++ ++ def get_current_value(self): ++ raise NotImplemented ++ ++ def is_changed(self): ++ return (self.is_new or ++ str (self.get_current_value()) != str (self.value)) ++ ++ def changed(self, widget, *args): ++ self.on_change(self) ++ ++# --------------------------------------------------------------------------- ++ ++class OptionSelectOne(Option): ++ ++ def __init__(self, name, value, supported, on_change): ++ Option.__init__(self, name, value, supported, on_change) ++ ++ self.selector = gtk.combo_box_new_text() ++ ++ ++ selected = None ++ for nr, choice in enumerate(supported): ++ self.selector.append_text(str(choice)) ++ if str (value) == str (choice): ++ selected = nr ++ if selected is not None: ++ self.selector.set_active(selected) ++ else: ++ print "Unknown value for %s: %s" % (name, value) ++ print "Choices:", supported ++ self.selector.connect("changed", self.changed) ++ ++ def get_current_value(self): ++ return self.selector.get_active_text() ++ ++# --------------------------------------------------------------------------- ++ ++class OptionSelectOneNumber(OptionSelectOne): ++ ++ def get_current_value(self): ++ return int(self.selector.get_active_text()) ++ ++# --------------------------------------------------------------------------- ++ ++class OptionSelectMany(Option): ++ ++ def __init__(self, name, value, supported, on_change): ++ Option.__init__(self, name, value, supported, on_change) ++ self.checkboxes = [] ++ vbox = gtk.VBox() ++ ++ for s in supported: ++ checkbox = gtk.CheckButton(label=s) ++ checkbox.set_active(s in value) ++ vbox.add(checkbox) ++ checkbox.connect("toggled", self.changed) ++ self.checkboxes.append(checkbox) ++ self.selector = vbox ++ ++ def get_current_value(self): ++ return[s for s, chk in zip(self.supported, self.checkboxes) ++ if chk.get_active()] ++ ++# --------------------------------------------------------------------------- ++ ++class OptionNumeric(Option): ++ def __init__(self, name, value, supported, on_change): ++ self.is_float = (isinstance(supported, float) or ++ (isinstance(supported, tuple) and ++ isinstance(supported[0], float))) ++ if self.is_float: ++ digits = 2 ++ else: ++ digits = 0 ++ ++ if not isinstance(supported, tuple): ++ supported = (0, supported) ++ Option.__init__(self, name, value, supported, on_change) ++ adj = gtk.Adjustment(value, supported[0], supported[1], 1.0, 5.0, 0.0) ++ self.selector = gtk.SpinButton(adj, climb_rate=1.0, digits=digits) ++ if not self.is_float: ++ self.selector.set_numeric(True) ++ self.selector.connect("changed", self.changed) ++ ++ def get_current_value(self): ++ if self.is_float: ++ return self.selector.get_value() ++ return self.selector.get_value_as_int() ++ ++# --------------------------------------------------------------------------- ++ ++class OptionText(Option): ++ def __init__(self, name, value, supported, on_change): ++ Option.__init__(self, name, value, supported, on_change) ++ ++ self.selector = QLineEdit() ++ self.selector.setText(value) ++ self.selector.connect(self.selector, SIGNAL("textChanged(QString)"), self.changed) ++ ++ def get_current_value(self): ++ return self.selector.text() +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/optionwidgets.py kdeadmin-4.2.2/system-config-printer-kde/optionwidgets.py +--- orig/kdeadmin-4.2.2/system-config-printer-kde/optionwidgets.py 1970-01-01 01:00:00.000000000 +0100 ++++ kdeadmin-4.2.2/system-config-printer-kde/optionwidgets.py 2009-04-09 22:56:08.000000000 +0100 +@@ -0,0 +1,221 @@ ++# -*- coding: utf-8 -*- ++## system-config-printer ++ ++############################################################################# ++## ++## Copyright 2007-2009 Canonical Ltd ++## Copyright 2008-2009 Richard Birnie ++## Author: Jonathan Riddell ++## Richard Birnie ++## ++## Includes code from System Config Printer: ++## Copyright (C) 2006, 2007, 2008 Red Hat, Inc. ++## Copyright (C) 2006, 2007 Florian Festi ++## Copyright (C) 2006, 2007, 2008 Tim Waugh ++## ++## This program is free software; you can redistribute it and/or ++## modify it under the terms of the GNU General Public License as ++## published by the Free Software Foundation; either version 2 of ++## the License, or (at your option) any later version. ++## ++## This program is distributed in the hope that it will be useful, ++## but WITHOUT ANY WARRANTY; without even the implied warranty of ++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++## GNU General Public License for more details. ++## ++## You should have received a copy of the GNU General Public License ++## along with this program. If not, see . ++## ++############################################################################# ++ ++import cups ++from PyQt4.QtCore import * ++from PyQt4.QtGui import * ++from PyKDE4.kdecore import i18n ++ ++""" ++These classes are used to dynamically generate the UI on the Options tab of the printer config dialogue ++""" ++ ++def OptionWidget(option, ppd, gui, tab_label=None): ++ """Factory function""" ++ ui = option.ui ++ if (ui == cups.PPD_UI_BOOLEAN and ++ len (option.choices) != 2): ++ # This option is advertised as a Boolean but in fact has more ++ # than two choices. ++ print "Treating Boolean option %s as PickOne" % option.keyword ++ ui = cups.PPD_UI_PICKONE ++ ++ if ui == cups.PPD_UI_BOOLEAN: ++ return OptionBool(option, ppd, gui, tab_label=tab_label) ++ pass ++ elif ui == cups.PPD_UI_PICKONE: ++ return OptionPickOne(option, ppd, gui, tab_label=tab_label) ++ elif ui == cups.PPD_UI_PICKMANY: ++ ##return OptionPickMany(option, ppd, gui, tab_label=tab_label) ++ pass ++ ++# --------------------------------------------------------------------------- ++class Option(QObject): ++ ++ def __init__(self, option, ppd, gui, tab_label=None): ++ QObject.__init__(self) ++ self.option = option ++ self.ppd = ppd ++ self.gui = gui ++ self.enabled = True ++ self.tab_label = tab_label ++ ++ ##vbox = gtk.VBox() ++ ++ #self.btnConflict = gtk.Button() ++ #icon = gtk.image_new_from_stock(gtk.STOCK_DIALOG_WARNING, ++ # gtk.ICON_SIZE_SMALL_TOOLBAR) ++ #self.btnConflict.add(icon) ++ #self.btnConflict.set_no_show_all(True) #avoid the button taking ++ # over control again ++ #vbox.add(self.btnConflict) # vbox reserves space while button ++ #vbox.set_size_request(32, 28) # is hidden ++ #self.conflictIcon = vbox ++ ++ #self.btnConflict.connect("clicked", self.on_btnConflict_clicked) ++ #icon.show() ++ ++ self.constraints = [c for c in ppd.constraints ++ if c.option1 == option.keyword] ++ #for c in self.constraints: ++ # if not c.choice1 or not c.choice2: ++ # print c.option1, repr(c.choice1), c.option2, repr(c.choice2) ++ self.conflicts = set() ++ self.conflict_message = "" ++ ++ def enable(self, enabled=True): ++ self.selector.setEnabled(enabled) ++ self.enabled = enabled ++ ++ def disable(self): ++ self.enable (False) ++ ++ def is_enabled(self): ++ return self.enabled ++ ++ def get_current_value(self): ++ raise NotImplemented ++ ++ def is_changed(self): ++ return self.get_current_value()!= self.option.defchoice ++ ++ def writeback(self): ++ if self.enabled: ++ self.ppd.markOption(self.option.keyword, self.get_current_value()) ++ ++ def checkConflicts(self, update_others=True): ++ value = self.get_current_value() ++ for constraint in self.constraints: ++ option2 = self.gui.options.get(constraint.option2, None) ++ if option2 is None: continue ++ ++ if (constraint.choice1==value and ++ option2.get_current_value() == constraint.choice2): ++ # conflict ++ self.conflicts.add(constraint) ++ if update_others: ++ option2.checkConflicts(update_others=False) ++ elif constraint in self.conflicts: ++ # remove conflict ++ self.conflicts.remove(constraint) ++ option2.checkConflicts(update_others=False) ++ ++ ++ tooltip = [unicode(i18n("Conflicts with:"))] ++ for c in self.conflicts: ++ option = self.gui.options.get(c.option2) ++ tooltip.append(option.option.text) ++ ++ tooltip = "\n".join(tooltip) ++ ++ self.conflict_message = tooltip # XXX more verbose ++ ++ if self.conflicts: ++ #FIXME: btnConflict not impemented yet ++ #self.gui.btnConflict.setTooltip(tooltip + "OPTION-" + self.option.keyword) ++ #self.btnConflict.show() ++ pass ++ else: ++ #self.btnConflict.hide() ++ pass ++ ++ self.gui.option_changed(self) ++ return self.conflicts ++ ++ def on_change(self, index): ++ self.checkConflicts() ++ ++""" ++ def on_btnConflict_clicked(self, button): ++ self.dialog.set_markup(self.conflict_message) ++ self.dialog.run() ++ self.dialog.hide() ++ ++# --------------------------------------------------------------------------- ++""" ++ ++ ++class OptionBool(Option): ++ ++ def __init__(self, option, ppd, gui, tab_label=None): ++ self.selector = QCheckBox(option.text, gui) ++ self.label = None ++ self.false = u"False" # hack to allow "None" instead of "False" ++ self.true = u"True" ++ for c in option.choices: ++ if c["choice"] in ("None", "False", "Off"): ++ self.false = c["choice"] ++ if c["choice"] in ("True", "On"): ++ self.true = c["choice"] ++ self.selector.setChecked(option.defchoice == self.true) ++ #self.selector.set_alignment(0.0, 0.5) ++ self.connect(self.selector, SIGNAL("toggled(bool)"), self.on_change) ++ Option.__init__(self, option, ppd, gui, tab_label=tab_label) ++ ++ def get_current_value(self): ++ return (self.false, self.true)[self.selector.isChecked()] ++ ++# --------------------------------------------------------------------------- ++ ++class OptionPickOne(Option): ++ widget_name = "OptionPickOne" ++ ++ def __init__(self, option, ppd, gui, tab_label=None): ++ self.selector = QComboBox(gui) ++ ++ label = option.text ++ if not label.endswith (':'): ++ label += ':' ++ self.label = QLabel(label, gui) ++ ++ selected = None ++ for nr, choice in enumerate(option.choices): ++ self.selector.addItem(choice['text']) ++ if option.defchoice == choice['choice']: ++ selected = self.selector.count() - 1 ++ if selected is not None: ++ self.selector.setCurrentIndex(selected) ++ else: ++ print option.text, "unknown value:", option.defchoice ++ self.connect(self.selector, SIGNAL("currentIndexChanged(int)"), self.on_change) ++ ++ Option.__init__(self, option, ppd, gui, tab_label=tab_label) ++ ++ def get_current_value(self): ++ return self.option.choices[self.selector.currentIndex()]['choice'] ++ ++# --------------------------------------------------------------------------- ++ ++class OptionPickMany(OptionPickOne): ++ widget_name = "OptionPickMany" ++ ++ def __init__(self, option, ppd, gui, tab_label=None): ++ raise NotImplemented ++ Option.__init__(self, option, ppd, gui, tab_label=tab_label) +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/smb-browse-dialog.ui kdeadmin-4.2.2/system-config-printer-kde/smb-browse-dialog.ui +--- orig/kdeadmin-4.2.2/system-config-printer-kde/smb-browse-dialog.ui 1970-01-01 01:00:00.000000000 +0100 ++++ kdeadmin-4.2.2/system-config-printer-kde/smb-browse-dialog.ui 2009-04-09 22:56:08.000000000 +0100 +@@ -0,0 +1,124 @@ ++ ++ SMBBrowseDialog ++ ++ ++ Qt::NonModal ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 300 ++ ++ ++ ++ ++ 50 ++ false ++ ++ ++ ++ Qt::StrongFocus ++ ++ ++ SMB Browser ++ ++ ++ true ++ ++ ++ ++ ++ 21 ++ 250 ++ 361 ++ 41 ++ ++ ++ ++ ++ ++ ++ Refresh ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ Ok ++ ++ ++ Ctrl+O ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ 30 ++ 10 ++ 341 ++ 221 ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ true ++ ++ ++ true ++ ++ ++ 2 ++ ++ ++ ++ 1 ++ ++ ++ ++ ++ 1 ++ ++ ++ ++ ++ ++ ++ KPushButton ++ QPushButton ++
kpushbutton.h
++
++
++ ++ ++
+diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.desktop kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.desktop +--- orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.desktop 2009-03-26 14:43:48.000000000 +0000 ++++ kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.desktop 2009-04-09 22:56:08.000000000 +0100 +@@ -1,31 +1,12 @@ + [Desktop Entry] + Name=Printing +-Name[ca]=Impressió +-Name[cs]=Tisk +-Name[da]=Udskrift +-Name[de]=Drucken + Name[el]=Εκτύπωση +-Name[es]=Imprimiendo +-Name[et]=Trükkimine +-Name[fr]=Impression +-Name[ga]=Priontáil + Name[gl]=Impresión +-Name[hne]=छपाई +-Name[hu]=Nyomtatás +-Name[is]=Prentun +-Name[it]=Stampa +-Name[ja]=印刷 +-Name[lt]=Spausdinimas + Name[lv]=Drukāšana +-Name[nb]=Utskrift + Name[nds]=Drucken + Name[nl]=Printers +-Name[nn]=Utskrift +-Name[pa]=ਪਰਿੰਟਿੰਗ +-Name[pl]=Drukowanie + Name[pt]=Impressão + Name[pt_BR]=Imprimindo +-Name[ro]=Imprimare + Name[ru]=Печать + Name[sv]=Utskrift + Name[tr]=Yazdırma +@@ -34,32 +15,13 @@ + Name[zh_CN]=打印 + Name[zh_TW]=列印 + Comment=Configure printers +-Comment[ca]=Configura les impressores +-Comment[cs]=Nastavení tisku +-Comment[da]=Indstil printere +-Comment[de]=Drucker einrichten + Comment[el]=Ρύθμιση εκτυπωτών +-Comment[es]=Configurar impresoras +-Comment[et]=Printerite seadistamine +-Comment[fr]=Configurer les imprimantes +-Comment[ga]=Cumraigh printéirí + Comment[gl]=Configuración das impresoras +-Comment[hne]=प्रिंटर मन ल कान्फिगर करव +-Comment[hu]=Nyomtatóbeállítás +-Comment[is]=Stilla prentara +-Comment[it]=Configura le stampanti +-Comment[ja]=プリンタの設定 +-Comment[lt]=Konfigūruoti spausdintuvus + Comment[lv]=Konfigurēt drukas ierīces +-Comment[nb]=Sett opp skrivere + Comment[nds]=Druckers instellen + Comment[nl]=Printers instellen +-Comment[nn]=Set opp skrivarar +-Comment[pa]=ਪਰਿੰਟਿੰਗ ਸੰਰਚਨਾ +-Comment[pl]=Konfiguracja drukarek + Comment[pt]=Configurar as impressoras + Comment[pt_BR]=Configurar impressoras +-Comment[ro]=Configurează imprimantele + Comment[ru]=Настройка принтеров + Comment[sv]=Anpassa skrivare + Comment[tr]=Yazıcıları yapılandır +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.py kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.py +--- orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.py 2008-12-21 20:20:45.000000000 +0000 ++++ kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.py 1970-01-01 01:00:00.000000000 +0100 +@@ -1,3250 +0,0 @@ +-#!/usr/bin/env python +-# -*- coding: utf-8 -*- +- +-############################################################################# +-## +-## Copyright (C) 2007 Canonical Ltd +-## Author: Jonathan Riddell +-## +-## Includes code from System Config Printer +-## Copyright (C) 2007 Tim Waugh +-## Copyright (C) 2007 Red Hat, Inc. +-## +-## This program is free software; you can redistribute it and/or +-## modify it under the terms of the GNU General Public License as +-## published by the Free Software Foundation; either version 2 of +-## the License, or (at your option) any later version. +-## +-## This program is distributed in the hope that it will be useful, +-## but WITHOUT ANY WARRANTY; without even the implied warranty of +-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-## GNU General Public License for more details. +-## +-## You should have received a copy of the GNU General Public License +-## along with this program. If not, see . +-## +-############################################################################# +- +-MIN_REFRESH_INTERVAL = 1 # seconds +-import locale +- +-import sys, os, time, traceback, re, tempfile, httplib +-#tempfile +-import thread +- +-#load modules from system-config-printer-common (debug, smburi), change path here if you have it installed elsewhere +-SYSTEM_CONFIG_PRINTER_DIR = "/usr/share/system-config-printer" +-if os.path.exists(SYSTEM_CONFIG_PRINTER_DIR + "/debug.py"): +- sys.path.append(SYSTEM_CONFIG_PRINTER_DIR) +- +-from PyQt4.QtCore import * +-from PyQt4.QtGui import * +-from PyQt4 import uic +- +-from PyKDE4.kdecore import * +-from PyKDE4.kdeui import * +- +-#use _() to keep code the same as gnome system-config-printer +-def _(string): +- return unicode(i18n(string), "utf-8") +- +-def translate(self, prop): +- """reimplement method from uic to change it to use gettext""" +- if prop.get("notr", None) == "true": +- return self._cstring(prop) +- else: +- if prop.text is None: +- return "" +- text = prop.text.encode("UTF-8") +- return i18n(text) +- +-uic.properties.Properties._string = translate +- +-import cups +-cups.require ("1.9.27") +- +-# These come from system-config-printer +-import config +-import cupshelpers #, options +-from smburi import SMBURI +-from debug import * +- +-import dbus +-import dbus.mainloop.qt +-import dbus.service +- +-ellipsis = unichr(0x2026) +- +-try: +- try_CUPS_SERVER_REMOTE_ANY = cups.CUPS_SERVER_REMOTE_ANY +-except AttributeError: +- # cups module was compiled with CUPS < 1.3 +- try_CUPS_SERVER_REMOTE_ANY = "_remote_any" +- +-def validDeviceURI (uri): +- """Returns True is the provided URI is valid.""" +- if uri.find (":/") > 0: +- return True +- return False +- +-class GUI(QWidget): +- """our main class is the main window""" +- +- printer_states = { cups.IPP_PRINTER_IDLE: i18nc("Printer state", "Idle"), +- cups.IPP_PRINTER_PROCESSING: i18nc("Printer state", "Processing"), +- cups.IPP_PRINTER_BUSY: i18nc("Printer state", "Busy"), +- cups.IPP_PRINTER_STOPPED: i18nc("Printer state", "Stopped") } +- +- def __init__(self, start_printer = None, change_ppd = False): +- QWidget.__init__(self) +- +- try: +- self.language = locale.getlocale(locale.LC_MESSAGES) +- self.encoding = locale.getlocale(locale.LC_CTYPE) +- except: +- nonfatalException() +- os.environ['LC_ALL'] = 'C' +- locale.setlocale (locale.LC_ALL, "") +- self.language = locale.getlocale(locale.LC_MESSAGES) +- self.encoding = locale.getlocale(locale.LC_CTYPE) +- +- self.printer = None +- self.conflicts = set() # of options +- self.connect_server = (self.printer and self.printer.getServer()) \ +- or cups.getServer() +- self.connect_user = cups.getUser() +- self.password = '' #FIXME not in Gnome version +- self.passwd_retry = False #FIXME not in Gnome version +- self.widget_data_setting = {} #FIXME not in Gnome version +- #FIXMEcups.setPasswordCB(self.cupsPasswdCallback) +- ##self.server_is_publishing = False #FIXME new in Gnome version +- +- self.changed = set() # of options +- +- self.servers = set((self.connect_server,)) +- +- try: +- self.cups = cups.Connection() +- except RuntimeError: +- #warn the user that cups is not running +- message = i18n("CUPS is not currently running. CUPS is required for complete printing functionality. Please start CUPS then restart this application.") +- answer = QMessageBox.warning(self, i18n("Print Server Not Running"), message, QMessageBox.Ok) +- #still allow the app to start for those that really want that +- if answer == QMessageBox.Ok: +- pass +- +- self.cups = None +- +- if os.path.exists("system-config-printer.ui"): +- APPDIR = QDir.currentPath() +- else: +- file = KStandardDirs.locate("appdata", "system-config-printer.ui") +- APPDIR = file.left(file.lastIndexOf("/")) +- +- uic.loadUi(APPDIR + "/" + "system-config-printer.ui", self) +- self.show() +- +- # New Printer Dialog +- self.newPrinterGUI = np = NewPrinterGUI(self) +- #np.NewPrinterWindow.set_transient_for(self.MainWindow) +- +- self.setConnected() +- +- self.connect(self.mainlist, SIGNAL("itemSelectionChanged()"), self.on_tvMainList_cursor_changed) +- self.connect(self.mainlist, SIGNAL("currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)"), self.on_tvMainList_changed) +- self.connect(self.chkServerBrowse, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) +- self.connect(self.chkServerShare, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) +- self.connect(self.chkServerShareAny, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) +- self.connect(self.chkServerRemoteAdmin, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) +- self.connect(self.chkServerAllowCancelAll, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) +- self.connect(self.chkServerLogDebug, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) +- +- self.connect(self.btnNewClass, SIGNAL("clicked()"), self.on_new_class_activate) +- self.connect(self.btnNewPrinter, SIGNAL("clicked()"), self.on_new_printer_activate) +- +- self.connect(self.entPDescription, SIGNAL("textEdited(const QString&)"), self.on_printer_changed) +- self.connect(self.entPLocation, SIGNAL("textEdited(const QString&)"), self.on_printer_changed) +- self.connect(self.entPDevice, SIGNAL("textEdited(const QString&)"), self.on_printer_changed) +- self.connect(self.chkPEnabled, SIGNAL("stateChanged(int)"), self.on_printer_changed) +- self.connect(self.chkPAccepting, SIGNAL("stateChanged(int)"), self.on_printer_changed) +- self.connect(self.chkPShared, SIGNAL("stateChanged(int)"), self.on_printer_changed) +- self.connect(self.cmbPErrorPolicy, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed) +- self.connect(self.cmbPOperationPolicy, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed) +- self.connect(self.cmbPStartBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed) +- self.connect(self.cmbPEndBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed) +- #self.connect(self.rbtnPAllow, SIGNAL("toggled(bool)"), self.on_printer_changed) +- +- try: +- self.populateList(start_printer, change_ppd) +- except cups.HTTPError, (s,): +- self.cups = None +- self.setConnected() +- self.populateList() +- self.show_HTTP_Error(s) +- +- self.mainlist.header().hide() +- +- #hide some bits until implemented +- self.btnNewPrinterNetwork.hide() +- self.newPrinterNetworkLabel.hide() +- self.btnNewPrinterSpecial.hide() +- self.newPrinterSpecialLabel.hide() +- self.btnNewPrinter.setText(i18n("New Printer")) +- self.btnPrinterPropertiesApply.setIcon(KIcon("dialog-ok-apply")) +- self.btnRevert.setIcon(KIcon("document-revert")) +- self.newPrinterLabel.hide() +- #(obsolete) only show settings until ready for the rest +- #self.mainlist.hide() +- self.mainlist.setCurrentItem(self.settingsItem) +- #FIXME hide labels until implemented +- self.lblPOptions.hide() +- self.lblPInstallOptions.hide() +- +- self.setWindowIcon(KIcon("printer")) +- +- # now called dests_iconview_item_activated() in the Gnome version +- def on_tvMainList_cursor_changed(self): +- if self.changed: +- # The unapplied changes for this item have not been saved, +- # and the user just pressed "Cancel". +- #FIXME, should offer dialog prompting to save or cancel here +- return +- items = self.mainlist.selectedItems() +- if len(items) < 1: +- return +- item = items[0] +- #FIXME only show settings until ready for the rest +- #item = self.settingsItem +- type = str(item.text(1)) +- name = str(item.text(0)) +- #name, type = self.getSelectedItem() +- #model, self.mainListSelected = self.tvMainList.get_selection().get_selected() +- #Save the values incase it gets deselected +- self.mainListSelectedType = type +- self.mainListSelectedName = name +- item_selected = True +- if type == "New": +- #self.ntbkMain.set_current_page(0) +- self.ntbkMain.setCurrentIndex(0) +- elif type == "Settings": +- #self.ntbkMain.set_current_page(0) +- self.ntbkMain.setCurrentIndex(1) +- if self.cups: +- self.fillServerTab() +- else: +- # No connection to CUPS. Make sure the Apply/Revert buttons +- # are not sensitive. +- self.setDataButtonState() +- item_selected = False +- elif type in ['Printer', 'Class']: +- try: +- self.fillPrinterTab(name) +- self.fillPrinterOptions() +- self.setDataButtonState() +- except RuntimeError: +- # Perhaps cupsGetPPD2 failed for a browsed printer. +- self.ntbkMain.setCurrentIndex(3) +- #self.ntbkMain.set_current_page(2) +- return +- +- #self.ntbkMain.set_current_page(1) +- self.ntbkMain.setCurrentIndex(2) +- elif type == "None": +- #self.ntbkMain.set_current_page(2) +- self.ntbkMain.setCurrentIndex(3) +- self.setDataButtonState() +- item_selected = False +- +- """FIXME, copy button +- is_local = item_selected and not self.printers[name].discovered +- for widget in [self.copy, self.btnCopy]: +- widget.set_sensitive(item_selected) +- for widget in [self.delete, self.btnDelete]: +- widget.set_sensitive(is_local) +- """ +- +- def printer_properties_response(self): +- name, type = self.getSelectedItem() +- if type in ("Printer", "Class"): +- return self.save_printer(self.printer) +- elif type == "Settings": +- return self.save_serversettings() +- +- def on_tvMainList_changed(self, new, old): +- """about to change, offer to save""" +- if self.changed: +- answer = QMessageBox.question(self, "Save Changes", "Do you want to save changes?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, QMessageBox.Save) +- if answer == QMessageBox.Save: +- self.printer_properties_response() +- elif answer == QMessageBox.Discard: +- self.changed = set() # avoid asking the user +- +- def busy (self, win = None): +- try: +- if not win: +- win = self +- win.setCursor(Qt.WaitCursor) +- QApplication.processEvents() +- except: +- nonfatalException () +- +- def ready (self, win = None): +- try: +- if not win: +- win = self +- win.setCursor(Qt.ArrowCursor) +- QApplication.processEvents() +- except: +- nonfatalException () +- +- def setConnected(self): +- connected = bool(self.cups) +- +- host = cups.getServer() +- +- if host[0] == '/': +- host = 'localhost' +- self.setWindowTitle(i18n("Printer configuration - %1", host)) +- +- if connected: +- status_msg = i18n("Connected to %1", host) +- else: +- status_msg = i18n("Not connected") +- #FIXME do we want a statusbar? +- #self.statusbarMain.push(self.status_context_id, status_msg) +- +- for widget in (#FIXMEself.btnNewPrinter, self.btnNewClass, +- #self.new_printer, self.new_class, +- self.chkServerBrowse, self.chkServerShare, +- self.chkServerRemoteAdmin, +- self.chkServerAllowCancelAll, +- self.chkServerLogDebug): +- widget.setEnabled(connected) +- +- sharing = self.chkServerShare.isChecked () +- self.chkServerShareAny.setEnabled (sharing) +- +- try: +- del self.server_settings +- except: +- pass +- +- def populateList(self, start_printer = None, change_ppd = False): +- #FIXMEold_name, old_type = self.getSelectedItem() +- old_name = "" +- old_type = "" +- +- select_path = None +- +- if self.cups: +- try: +- # get Printers +- self.printers = cupshelpers.getPrinters(self.cups) +- +- # Get default printer. +- try: +- self.default_printer = self.cups.getDefault () +- except AttributeError: # getDefault appeared in pycups-1.9.31 +- # This fetches the list of printers and classes *again*, +- # just to find out the default printer. +- dests = self.cups.getDests () +- if dests.has_key ((None,None)): +- self.default_printer = dests[(None,None)].name +- else: +- self.default_printer = None +- except cups.IPPError, (e, m): +- self.show_IPP_Error(e, m) +- self.printers = {} +- self.default_printer = None +- else: +- self.printers = {} +- self.default_printer = None +- +- local_printers = [] +- local_classes = [] +- remote_printers = [] +- remote_classes = [] +- +- for name, printer in self.printers.iteritems(): +- if printer.default: +- self.default_printer = name +- self.servers.add(printer.getServer()) +- +- if printer.remote: +- if printer.is_class: remote_classes.append(name) +- else: remote_printers.append(name) +- else: +- if printer.is_class: local_classes.append(name) +- else: local_printers.append(name) +- +- local_printers.sort() +- local_classes.sort() +- remote_printers.sort() +- remote_classes.sort() +- +- if (old_name != "" and +- (not old_name in local_printers) and +- (not old_name in local_classes) and +- (not old_name in remote_printers) and +- (not old_name in remote_classes)): +- # The previously selected printer no longer exists. +- old_name = "" +- +- if (self.default_printer != None and +- start_printer == None and +- old_name == ""): +- start_printer = self.default_printer +- +- if not start_printer: +- start_printer = old_name +- +- expanded = { +- "_printers" : True, +- "_classes" : True, +- "_remote_printers" : True, +- "_remote_classes" : True, +- } +- +- """ +- # remove old printers/classes +- iter = self.mainlist.get_iter_first() +- iter = self.mainlist.iter_next(iter) # step over server settings +- while iter: +- entry = self.mainlist.get_value(iter, 1) +- path = self.mainlist.get_path(iter) +- expanded[entry] = self.tvMainList.row_expanded(path) +- more_entries = self.mainlist.remove(iter) +- if not more_entries: break +- """ +- self.mainlist.clear() +- QTreeWidgetItem(self.mainlist, ["New Printer", 'New']) +- self.settingsItem = QTreeWidgetItem(self.mainlist, ["Server Settings", 'Settings']) +- +- # add new +- for printers, text, name in ( +- (local_printers, i18n("Local Printers"), "_printers"), +- (local_classes, i18n("Local Classes"), "_classes"), +- (remote_printers, i18n("Remote Printers"), "_remote_printers"), +- (remote_classes, i18n("Remote Classes"), "_remote_classes")): +- if not printers: continue +- +- #self.mainlist.addTopLevelItem(QTreeWidgetItem(self.mainlist, text)) +- rootTreeItem = QTreeWidgetItem(self.mainlist, [text, name]) +- #iter = self.mainlist.append(None, (text, name)) +- #path = self.mainlist.get_path(iter) +- +- for printer_name in printers: +- if start_printer == None: +- start_printer = printer_name +- treeItem = QTreeWidgetItem(rootTreeItem, [printer_name, "Printer"]) +- #p_iter = self.mainlist.append(iter, (printer_name, "Printer")) +- if printer_name==start_printer: +- treeItem.setSelected(True) +- expanded[name] = True +- if expanded[name]: +- rootTreeItem.setExpanded(True) +- #self.tvMainList.expand_row(path, False) +- self.on_tvMainList_cursor_changed() +- self.setDataButtonState() +- +- """FIXME +- if change_ppd: +- self.on_btnChangePPD_clicked (self.btnChangePPD) +- """ +- +- #TODO +- # Connect to Server +- +- def on_printer_changed(self, text): +- widget = self.sender() +- if not widget: #method called as a method not a slot +- return +- if isinstance(widget, QCheckBox): +- value = widget.isChecked() +- elif isinstance(widget, QLineEdit): +- value = unicode(widget.text()) +- elif isinstance(widget, QRadioButton): +- value = widget.isChecked() +- elif isinstance(widget, QComboBox): +- value = unicode(widget.currentText()) +- else: +- raise ValueError, "Widget type not supported (yet)" +- +- p = self.printer +- old_values = { +- self.entPDescription : p.info, +- self.entPLocation : p.location, +- self.entPDevice : p.device_uri, +- self.chkPEnabled : p.enabled, +- self.chkPAccepting : not p.rejecting, +- self.chkPShared : p.is_shared, +- self.cmbPStartBanner : p.job_sheet_start, +- self.cmbPEndBanner : p.job_sheet_end, +- self.cmbPErrorPolicy : p.error_policy, +- self.cmbPOperationPolicy : p.op_policy, +- #self.rbtnPAllow: p.default_allow, #FIXME access control tab +- } +- +- old_value = old_values[widget] +- +- if old_value == value: +- self.changed.discard(widget) +- else: +- self.changed.add(widget) +- self.setDataButtonState() +- +- #TODO +- # Access control +- +- #TODO +- # Server side options +- +- # set buttons sensitivity +- def setDataButtonState(self): +- try: # Might not be a printer selected +- possible = (self.ppd and +- not bool (self.changed) and +- self.printer.enabled and +- not self.printer.rejecting) +- +- self.btnPrintTestPage.setEnabled(possible) +- +- commands = (self.printer.type & cups.CUPS_PRINTER_COMMANDS) != 0 +- self.btnSelfTest.setEnabled(commands and possible) +- self.btnCleanHeads.setEnabled(commands and possible) +- except: +- debugprint ("exception in setDataButtonState") +- pass +- +- installablebold = False +- optionsbold = False +- if self.conflicts: +- debugprint ("Conflicts detected") +- self.btnConflict.show() +- for option in self.conflicts: +- if option.tab_label == self.lblPInstallOptions: +- installablebold = True +- else: +- optionsbold = True +- else: +- self.btnConflict.hide() +- installabletext = i18n("Installable Options") +- optionstext = i18n("Printer Options") +- if installablebold: +- installabletext = i18nc("Conflicted entry", "%1", installabletext) +- if optionsbold: +- optionstext = i18nc("Conflicted entry", "%1", optionstext) +- self.lblPInstallOptions.setText(installabletext) +- self.lblPOptions.setText(optionstext) +- +- """ FIXME +- store = self.tvPrinterProperties.get_model () +- if store: +- for n in range (self.ntbkPrinter.get_n_pages ()): +- page = self.ntbkPrinter.get_nth_page (n) +- label = self.ntbkPrinter.get_tab_label (page) +- if label == self.lblPInstallOptions: +- iter = store.get_iter ((n,)) +- store.set_value (iter, 0, installabletext) +- elif label == self.lblPOptions: +- iter = store.get_iter ((n,)) +- store.set_value (iter, 0, optionstext) +- """ +- +- self.btnPrinterPropertiesApply.setEnabled(len (self.changed) > 0) +- self.btnRevert.setEnabled(len (self.changed) > 0) +- +- def save_printer(self, printer, saveall=False): +- class_deleted = False +- name = printer.name +- +- try: +- if not printer.is_class and self.ppd: +- self.getPrinterSettings() +- if self.ppd.nondefaultsMarked() or saveall: +- self.passwd_retry = False # use cached Passwd +- self.cups.addPrinter(name, ppd=self.ppd) +- +- #FIXME classes +- if printer.is_class: +- pass +- """ +- # update member list +- new_members = self.getCurrentClassMembers(self.tvClassMembers) +- if not new_members: +- dialog = gtk.MessageDialog( +- flags=0, type=gtk.MESSAGE_WARNING, +- buttons=gtk.BUTTONS_YES_NO, +- message_format=_("This will delete this class!")) +- dialog.format_secondary_text(_("Proceed anyway?")) +- result = dialog.run() +- dialog.destroy() +- if result==gtk.RESPONSE_NO: +- return True +- class_deleted = True +- +- # update member list +- old_members = printer.class_members[:] +- +- for member in new_members: +- if member in old_members: +- old_members.remove(member) +- else: +- self.cups.addPrinterToClass(member, name) +- for member in old_members: +- self.cups.deletePrinterFromClass(member, name) +- """ +- +- location = unicode(self.entPLocation.text()) +- info = unicode(self.entPDescription.text()) +- device_uri = unicode(self.entPDevice.text()) +- if device_uri.find (ellipsis) != -1: +- # The URI is sanitized and not editable. +- device_uri = printer.device_uri +- +- enabled = self.chkPEnabled.isChecked() +- accepting = self.chkPAccepting.isChecked() +- shared = self.chkPShared.isChecked() +- +- if info!=printer.info or saveall: +- self.passwd_retry = False # use cached Passwd +- self.cups.setPrinterInfo(name, info) +- if location!=printer.location or saveall: +- self.passwd_retry = False # use cached Passwd +- self.cups.setPrinterLocation(name, location) +- if (not printer.is_class and +- (device_uri!=printer.device_uri or saveall)): +- self.passwd_retry = False # use cached Passwd +- self.cups.setPrinterDevice(name, device_uri) +- +- if enabled != printer.enabled or saveall: +- self.passwd_retry = False # use cached Passwd +- self.printer.setEnabled(enabled) +- if accepting == printer.rejecting or saveall: +- self.passwd_retry = False # use cached Passwd +- self.printer.setAccepting(accepting) +- if shared != printer.is_shared or saveall: +- self.passwd_retry = False # use cached Passwd +- self.printer.setShared(shared) +- +- job_sheet_start = unicode(self.cmbPStartBanner.currentText()) +- job_sheet_end = unicode(self.cmbPEndBanner.currentText()) +- error_policy = unicode(self.cmbPErrorPolicy.currentText()) +- op_policy = unicode(self.cmbPOperationPolicy.currentText()) +- +- if (job_sheet_start != printer.job_sheet_start or +- job_sheet_end != printer.job_sheet_end) or saveall: +- self.passwd_retry = False # use cached Passwd +- printer.setJobSheets(job_sheet_start, job_sheet_end) +- if error_policy != printer.error_policy or saveall: +- self.passwd_retry = False # use cached Passwd +- printer.setErrorPolicy(error_policy) +- if op_policy != printer.op_policy or saveall: +- self.passwd_retry = False # use cached Passwd +- printer.setOperationPolicy(op_policy) +- +- """FIXME TODO access +- default_allow = self.rbtnPAllow.get_active() +- except_users = self.getPUsers() +- +- if (default_allow != printer.default_allow or +- except_users != printer.except_users) or saveall: +- self.passwd_retry = False # use cached Passwd +- printer.setAccess(default_allow, except_users) +- +- for option in printer.attributes: +- if option not in self.server_side_options: +- printer.unsetOption(option) +- for option in self.server_side_options.itervalues(): +- if option.is_changed() or saveall: +- printer.setOption(option.name, option.get_current_value()) +- """ +- except cups.IPPError, (e, s): +- self.show_IPP_Error(e, s) +- return True +- self.changed = set() # of options +- if not self.__dict__.has_key ("server_settings"): +- # We can authenticate with the server correctly at this point, +- # but we have never fetched the server settings to see whether +- # the server is publishing shared printers. Fetch the settings +- # now so that we can update the "not published" label if necessary. +- try: +- self.server_settings = self.cups.adminGetServerSettings() +- except: +- nonfatalException() +- +- if class_deleted: +- self.populateList () +- else: +- # Update our copy of the printer's settings. +- printers = cupshelpers.getPrinters (self.cups) +- this_printer = { name: printers[name] } +- self.printers.update (this_printer) +- +- return False +- +- def getPrinterSettings(self): +- #self.ppd.markDefaults() +- for option in self.options.itervalues(): +- option.writeback() +- +- @pyqtSignature("") +- def on_btnPrintTestPage_clicked(self): +- if self.test_button_cancels: +- jobs = self.printer.testsQueued () +- for job in jobs: +- debugprint ("Canceling job %s" % job) +- try: +- self.cups.cancelJob (job) +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- self.setTestButton (self.printer) +- return +- try: +- # if we have a page size specific custom test page, use it; +- # otherwise use cups' default one +- custom_testpage = None +- opt = self.ppd.findOption ("PageSize") +- if opt: +- custom_testpage = os.path.join(SYSTEM_CONFIG_PRINTER_DIR, 'testpage-%s.ps' % opt.defchoice.lower()) +- +- if custom_testpage and os.path.exists(custom_testpage): +- debugprint ('Printing custom test page ' + custom_testpage) +- job_id = self.cups.printTestPage(self.printer.name, +- file=custom_testpage) +- else: +- debugprint ('Printing default test page') +- job_id = self.cups.printTestPage(self.printer.name) +- +- self.setTestButton (self.printer) +- QMessageBox.information(self, i18nc("Test page submitted", "Submitted"), i18n("Test page submitted as " +- "job %d") % job_id) +- except cups.IPPError, (e, msg): +- if (e == cups.IPP_NOT_AUTHORIZED and +- self.connect_server != 'localhost' and +- self.connect_server[0] != '/'): +- self.lblError.set_markup (''+ +- i18n("Not possible") + '\n\n' + +- i18n("The remote server did not accept " +- "the print job, most likely " +- "because the printer is not " +- "shared.")) +- self.ErrorDialog.set_transient_for (self.MainWindow) +- self.ErrorDialog.run () +- self.ErrorDialog.hide () +- else: +- self.show_IPP_Error(e, msg) +- +- def maintenance_command (self, command): +- (tmpfd, tmpfname) = tempfile.mkstemp () +- os.write (tmpfd, "#CUPS-COMMAND\n%s\n" % command) +- os.close (tmpfd) +- try: +- format = "application/vnd.cups-command" +- job_id = self.cups.printTestPage (self.printer.name, +- format=format, +- file=tmpfname, +- user=self.connect_user) +- self.lblInfo.set_markup ('' + +- i18nc("Maintenance command submitted", "Submitted") + '\n\n' + +- i18n("Maintenance command submitted as " +- "job %d") % job_id) +- self.InfoDialog.set_transient_for (self.MainWindow) +- self.InfoDialog.run () +- self.InfoDialog.hide () +- except cups.IPPError, (e, msg): +- if (e == cups.IPP_NOT_AUTHORIZED and +- self.printer.name != 'localhost'): +- self.lblError.set_markup (''+ +- i18n("Not possible") + '\n\n' + +- i18n("The remote server did not accept " +- "the print job, most likely " +- "because the printer is not " +- "shared.")) +- self.ErrorDialog.set_transient_for (self.MainWindow) +- self.ErrorDialog.run () +- self.ErrorDialog.hide () +- else: +- self.show_IPP_Error(e, msg) +- +- @pyqtSignature("") +- def on_btnSelfTest_clicked(self): +- self.maintenance_command ("PrintSelfTestPage") +- +- @pyqtSignature("") +- def on_btnCleanHeads_clicked(self): +- self.maintenance_command ("Clean all") +- +- def fillComboBox(self, combobox, values, value): +- combobox.clear() +- for nr, val in enumerate(values): +- combobox.addItem(val) +- if val == value: +- combobox.setCurrentIndex(nr) +- +- def fillPrinterTab(self, name): +- self.changed = set() # of options +- self.options = {} # keyword -> Option object +- self.conflicts = set() # of options +- +- printer = self.printers[name] +- self.printer = printer +- printer.getAttributes () +- +- editable = not self.printer.discovered +- editablePPD = not self.printer.remote +- +- try: +- self.ppd = printer.getPPD() +- except cups.IPPError, (e, m): +- # Some IPP error other than IPP_NOT_FOUND. +- self.show_IPP_Error(e, m) +- # Treat it as a raw queue. +- self.ppd = False +- except RuntimeError: +- # The underlying cupsGetPPD2() function returned NULL without +- # setting an IPP error, so it'll be something like a failed +- # connection. +- #FIXME show a dialogue +- debugprint("Error!") +- """ +- self.lblError.set_markup('' + +- _("Error") + '\n\n' + +- _("There was a problem connecting to " +- "the CUPS server.")) +- self.ErrorDialog.set_transient_for(self.MainWindow) +- self.ErrorDialog.run() +- self.ErrorDialog.hide() +- """ +- raise +- +- for widget in (self.entPDescription, self.entPLocation, +- self.entPDevice): +- widget.setReadOnly(not editable) +- +- for widget in (self.btnSelectDevice, self.btnChangePPD): +- """,FIXME +- self.chkPEnabled, self.chkPAccepting, self.chkPShared, +- self.cmbPStartBanner, self.cmbPEndBanner, +- self.cmbPErrorPolicy, self.cmbPOperationPolicy, +- self.rbtnPAllow, self.rbtnPDeny, self.tvPUsers, +- self.entPUser, self.btnPAddUser, self.btnPDelUser): +- """ +- widget.setEnabled(editable) +- +- # Description page +- self.entPDescription.setText(printer.info) +- self.entPLocation.setText(printer.location) +- #obsolete self.lblPMakeModel.setText(printer.make_and_model) +- #obsolete self.lblPState.setText(printer.state_description) +- +- uri = printer.device_uri +- if uri.startswith("smb://"): +- (group, host, share, +- user, password) = SMBURI (uri=uri[6:]).separate () +- if password: +- uri = "smb://" +- if len (user) or len (password): +- uri += ellipsis +- uri += SMBURI (group=group, host=host, share=share).get_uri () +- self.entPDevice.setEnabled(False) +- else: +- self.entPDevice.setEnabled(True) +- self.entPDevice.setText(uri) +- self.changed.discard(self.entPDevice) +- +- # Hide make/model and Device URI for classes +- for widget in (self.lblPMakeModel2, self.lblPMakeModel, +- self.btnChangePPD, self.lblPDevice2, +- self.entPDevice, self.btnSelectDevice): +- if printer.is_class: +- widget.hide() +- else: +- widget.show() +- +- +- # default printer +- self.btnPMakeDefault.setEnabled(not printer.default) +- if printer.default: +- self.lblPDefault.setText(i18n("This is the default printer")) +- elif self.default_printer: +- self.lblPDefault.setText(self.default_printer) +- else: +- self.lblPDefault.setText(i18n("No default printer set.")) +- +- self.setTestButton (printer) +- +- # Policy tab +- # ---------- +- +- # State +- self.chkPEnabled.setChecked(printer.enabled) +- self.chkPAccepting.setChecked(not printer.rejecting) +- self.chkPShared.setChecked(printer.is_shared) +- try: +- if printer.is_shared: +- flag = cups.CUPS_SERVER_SHARE_PRINTERS +- publishing = int (self.server_settings[flag]) +- if publishing: +- self.lblNotPublished.hide() +- else: +- self.lblNotPublished.show() +- else: +- self.lblNotPublished.hide() +- except: +- self.lblNotPublished.hide() +- +- # Job sheets +- self.cmbPStartBanner.setEnabled(editable) +- self.cmbPEndBanner.setEnabled(editable) +- +- # Policies +- self.cmbPErrorPolicy.setEnabled(editable) +- self.cmbPOperationPolicy.setEnabled(editable) +- +- """ +- # Access control +- self.rbtnPAllow.set_active(printer.default_allow) +- self.rbtnPDeny.set_active(not printer.default_allow) +- self.setPUsers(printer.except_users) +- +- self.entPUser.set_text("") +- +- # Server side options (Job options) +- self.server_side_options = {} +- for option in self.job_options_widgets.values (): +- if option.name == "media" and self.ppd: +- # Slightly special case because the 'system default' +- # (i.e. what you get when you press Reset) depends +- # on the printer's PageSize. +- opt = self.ppd.findOption ("PageSize") +- if opt: +- option.set_default (opt.defchoice) +- +- option_editable = editable +- try: +- value = self.printer.attributes[option.name] +- except KeyError: +- option.reinit (None) +- else: +- try: +- if self.printer.possible_attributes.has_key (option.name): +- supported = self.printer.\ +- possible_attributes[option.name][1] +- # Set the option widget. +- # In CUPS 1.3.x the orientation-requested-default +- # attribute may have the value None; this means there +- # is no value set. This suits our needs here, as None +- # resets the option to the system default and makes the +- # Reset button insensitive. +- option.reinit (value, supported=supported) +- else: +- option.reinit (value) +- +- self.server_side_options[option.name] = option +- except: +- option_editable = False +- self.lblError.set_markup ('' + +- _("Error") + '\n\n' + +- _("Option '%s' has value '%s' " +- "and cannot be edited.") % +- (option.name, value)) +- self.ErrorDialog.set_transient_for (self.MainWindow) +- self.ErrorDialog.run() +- self.ErrorDialog.hide() +- option.widget.set_sensitive (option_editable) +- if not editable: +- option.button.set_sensitive (False) +- self.other_job_options = [] +- self.draw_other_job_options (editable=editable) +- for option in self.printer.attributes.keys (): +- if self.server_side_options.has_key (option): +- continue +- supported = "" +- if self.printer.possible_attributes.has_key (option): +- supported = self.printer.possible_attributes[option][1] +- self.add_job_option (option, value=self.printer.attributes[option], +- supported=supported, is_new=False, +- editable=editable) +- self.entNewJobOption.set_text ('') +- self.entNewJobOption.set_sensitive (editable) +- self.btnNewJobOption.set_sensitive (False) +- +- if printer.is_class: +- # remove InstallOptions tab +- tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions) +- if tab_nr != -1: +- self.ntbkPrinter.remove_page(tab_nr) +- self.fillClassMembers(name, editable) +- else: +- # real Printer +- self.fillPrinterOptions(name, editablePPD) +- +- """ +- self.changed = set() # of options +- self.updatePrinterProperties () +- self.setDataButtonState() +- +- def fillPrinterOptions(self): +- return #FIXME TODO options tabs +- +- #In Gnome is now on_delete_activate(self, UNUSED): +- @pyqtSignature("") +- def on_btnDelete_clicked(self): +- name, type = self.getSelectedItem() +- print name +- +- # Confirm +- if type == "Printer": +- message_format = i18n("Really delete printer %s?") +- else: +- message_format = i18n("Really delete class %s?") +- +- cancel = QMessageBox.question(self,"", +- unicode(message_format) % name, +- i18n("&Yes"), i18n("&No"), +- QString(), 0, 1) +- +- if cancel: +- return +- try: +- self.cups.deletePrinter(name) +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- +- self.changed = set() +- self.populateList() +- self.mainlist.setCurrentItem(self.mainlist.itemAt(0,0)) +- +- #in Gnome side is now set_default_printer (self, name): +- @pyqtSignature("") +- def on_btnPMakeDefault_clicked(self): +- try: +- self.cups.setDefault(self.printer.name) +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- return +- +- # Also need to check system-wide lpoptions because that's how +- # previous Fedora versions set the default (bug #217395). +- (tmpfd, tmpfname) = tempfile.mkstemp () +- success = False +- try: +- resource = "/admin/conf/lpoptions" +- self.cups.getFile(resource, tmpfname) +- #success = True +- except cups.HTTPError, (s,): +- try: +- os.remove (tmpfname) +- except OSError: +- pass +- +- if s != cups.HTTP_NOT_FOUND: +- self.show_HTTP_Error(s) +- return +- +- if success: +- lines = file (tmpfname).readlines () +- changed = False +- i = 0 +- for line in lines: +- if line.startswith ("Default "): +- # This is the system-wide default. +- name = line.split (' ')[1] +- if name != self.printer.name: +- # Stop it from over-riding the server default. +- lines[i] = "Dest " + line[8:] +- changed = True +- i += 1 +- +- if changed: +- file (tmpfname, 'w').writelines (lines) +- try: +- self.cups.putFile (resource, tmpfname) +- except cups.HTTPError, (s,): +- os.remove (tmpfname) +- print s +- self.show_HTTP_Error(s) +- return +- +- # Now reconnect because the server needs to reload. +- self.reconnect () +- +- try: +- os.remove (tmpfname) +- except OSError: +- pass +- +- try: +- self.populateList() +- except cups.HTTPError, (s,): +- self.cups = None +- self.setConnected() +- self.populateList() +- self.show_HTTP_Error(s) +- +- ########################################################################## +- ### Server settings +- ########################################################################## +- +- def fillServerTab(self): +- self.changed = set() +- try: +- self.server_settings = self.cups.adminGetServerSettings() +- except cups.IPPError, (e, m): +- #FIXME +- self.show_IPP_Error(e, m) +- self.tvMainList.get_selection().unselect_all() +- self.on_tvMainList_cursor_changed(self.tvMainList) +- return +- +- for widget, setting in [ +- (self.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS), +- (self.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS), +- (self.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY), +- (self.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN), +- (self.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY), +- (self.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]: +- # widget.set_data("setting", setting) +- self.widget_data_setting[widget] = setting +- self.disconnect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) +- if self.server_settings.has_key(setting): +- widget.setChecked(int(self.server_settings[setting])) +- widget.setEnabled(True) +- else: +- widget.setChecked(False) +- widget.setEnabled(False) +- self.connect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed) +- self.setDataButtonState() +- # Set sensitivity of 'Allow printing from the Internet'. +- self.on_server_changed (self.chkServerShare) # (any will do here) +- +- def on_server_widget_changed(self, value): +- self.on_server_changed(self.sender()) +- +- def on_server_changed(self, widget): +- #setting = widget.get_data("setting") +- #print "widget_data_setting " + str(self.widget_data_setting) +- #print "widget " + str(widget) +- setting = self.widget_data_setting[widget] +- if self.server_settings.has_key (setting): +- if str(int(widget.isChecked())) == self.server_settings[setting]: +- self.changed.discard(widget) +- else: +- self.changed.add(widget) +- +- sharing = self.chkServerShare.isChecked () +- self.chkServerShareAny.setEnabled ( +- sharing and self.server_settings.has_key(try_CUPS_SERVER_REMOTE_ANY)) +- +- self.setDataButtonState() +- +- def save_serversettings(self): +- setting_dict = self.server_settings.copy() +- for widget, setting in [ +- (self.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS), +- (self.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS), +- (self.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY), +- (self.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN), +- (self.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY), +- (self.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]: +- if not self.server_settings.has_key(setting): continue +- setting_dict[setting] = str(int(widget.isChecked())) +- try: +- self.cups.adminSetServerSettings(setting_dict) +- except cups.IPPError, (e, m): +- self.show_IPP_Error(e, m) +- return True +- except RuntimeError, s: +- self.show_IPP_Error(None, s) +- return True +- self.changed = set() +- self.setDataButtonState() +- time.sleep(1) # give the server a chance to process our request +- +- # Now reconnect, in case the server needed to reload. +- self.reconnect () +- +- # Refresh the server settings in case they have changed in the +- # mean time. +- try: +- self.fillServerTab() +- except: +- nonfatalException() +- +- # ==================================================================== +- # == New Printer Dialog ============================================== +- # ==================================================================== +- +- # new printer +- def on_new_printer_activate(self): +- self.busy() +- self.newPrinterGUI.init("printer") +- self.ready() +- +- # new class +- def on_new_class_activate(self): +- self.newPrinterGUI.init("class") +- +- @pyqtSignature("") +- def on_btnSelectDevice_clicked(self): +- self.newPrinterGUI.init("device") +- +- @pyqtSignature("") +- def on_btnChangePPD_clicked(self): +- self.busy(self) +- self.newPrinterGUI.init("ppd") +- self.ready(self) +- +- def checkNPName(self, name): +- if not name: return False +- name = name.lower() +- for printer in self.printers.values(): +- if not printer.discovered and printer.name.lower()==name: +- return False +- return True +- +- def makeNameUnique(self, name): +- """Make a suggested queue name valid and unique.""" +- name = name.replace (" ", "_") +- name = name.replace ("/", "_") +- name = name.replace ("#", "_") +- if not self.checkNPName (name): +- suffix=2 +- while not self.checkNPName (name + str (suffix)): +- suffix += 1 +- if suffix == 100: +- break +- name += str (suffix) +- return name +- +- #TODO +- ## Watcher interface helpers +- +- @pyqtSignature("") +- def on_btnRevert_clicked(self): +- self.changed = set() # avoid asking the user +- self.on_tvMainList_cursor_changed() +- +- @pyqtSignature("") +- def on_btnPrinterPropertiesApply_clicked(self): +- err = self.printer_properties_response() +- if not err: +- self.populateList() +- else: +- nonfatalException() +- +- def show_IPP_Error(self, exception, message): +- if exception == cups.IPP_NOT_AUTHORIZED: +- QMessageBox.critical(self, i18n('Not authorized'), i18n('The password may be incorrect.')) +- else: +- QMessageBox.critical(self, i18n('CUPS server error'), i18n("There was an error during the CUPS "\ +- "operation: '%1'.", message)) +- def show_HTTP_Error(self, status): +- if (status == cups.HTTP_UNAUTHORIZED or +- status == cups.HTTP_FORBIDDEN): +- QMessageBox.critical(self, i18n('Not authorized'), +- i18n('The password may be incorrect, or the ' +- 'server may be configured to deny ' +- 'remote administration.')) +- else: +- if status == cups.HTTP_BAD_REQUEST: +- msg = i18nc("HTTP error", "Bad request") +- elif status == cups.HTTP_NOT_FOUND: +- msg = i18nc("HTTP error", "Not found") +- elif status == cups.HTTP_REQUEST_TIMEOUT: +- msg = i18nc("HTTP error", "Request timeout") +- elif status == cups.HTTP_UPGRADE_REQUIRED: +- msg = i18nc("HTTP error", "Upgrade required") +- elif status == cups.HTTP_SERVER_ERROR: +- msg = i18nc("HTTP error", "Server error") +- elif status == -1: +- msg = i18nc("HTTP error", "Not connected") +- else: +- msg = i18nc("HTTP error", "status %1", status) +- +- QMessageBox.critical(self, i18n('CUPS server error'), i18n("There was an HTTP error: %1.", msg)) +- +- def getSelectedItem(self): +- return str(self.mainListSelectedName).decode ('utf-8'), str(self.mainListSelectedType) +- """ +- items = self.mainlist.selectedItems() +- if len(items) < 1: +- return ("", 'None') +- item = items[0] +- name = item.text(0) +- type = item.text(1) +- name = str(name).decode ('utf-8') +- return name.strip(), type +- """ +- +- def reconnect (self): +- """Reconnect to CUPS after the server has reloaded.""" +- # libcups would handle the reconnection if we just told it to +- # do something, for example fetching a list of classes. +- # However, our local authentication certificate would be +- # invalidated by a server restart, so it is better for us to +- # handle the reconnection ourselves. +- +- # Disconnect. +- self.cups = None +- self.setConnected() +- +- cups.setServer(self.connect_server) +- cups.setUser(self.connect_user) +- attempt = 1 +- while attempt <= 5: +- try: +- self.cups = cups.Connection () +- break +- except RuntimeError: +- # Connection failed. +- time.sleep(1) +- attempt += 1 +- +- self.setConnected() +- self.passwd_retry = False +- +- def updatePrinterProperties(self): +- debugprint ("update printer properties") +- printer = self.printer +- self.lblPMakeModel.setText(printer.make_and_model) +- state = self.printer_states.get (printer.state, i18nc("Printer state", "Unknown")) +- reason = printer.other_attributes.get ('printer-state-message', '') +- if len (reason) > 0: +- state += ' - ' + reason +- self.lblPState.setText(state) +- if len (self.changed) == 0: +- debugprint ("no changes yet: full printer properties update") +- # State +- self.chkPEnabled.setEnabled(printer.enabled) +- self.chkPAccepting.setEnabled(not printer.rejecting) +- self.chkPShared.setEnabled(printer.is_shared) +- +- # Job sheets +- self.fillComboBox(self.cmbPStartBanner, +- printer.job_sheets_supported, +- printer.job_sheet_start), +- self.fillComboBox(self.cmbPEndBanner, printer.job_sheets_supported, +- printer.job_sheet_end) +- +- # Policies +- self.fillComboBox(self.cmbPErrorPolicy, +- printer.error_policy_supported, +- printer.error_policy) +- self.fillComboBox(self.cmbPOperationPolicy, +- printer.op_policy_supported, +- printer.op_policy) +- +- """ +- # Access control +- self.rbtnPAllow.set_active(printer.default_allow) +- self.rbtnPDeny.set_active(not printer.default_allow) +- self.setPUsers(printer.except_users) +- """ +- +- def setTestButton (self, printer): +- if printer.testsQueued (): +- self.test_button_cancels = True +- self.btnPrintTestPage.setText(i18n('Cancel Tests')) +- self.btnPrintTestPage.setEnabled(True) +- else: +- self.test_button_cancels = False +- self.btnPrintTestPage.setText(i18n('Print Test Page')) +- self.setDataButtonState() +- +- def getCurrentClassMembers(self, listwidget): +- count = listwidget.count() +- result = [] +- for i in range(count): +- result.append(listwidget.item(i).text()) +- result.sort() +- return result +- +- def moveClassMembers(self, treeview_from, treeview_to): +- rows = treeview_from.selectedItems() +- for row in rows: +- treeview_from.takeItem(treeview_from.row(row)) +- treeview_to.addItem(row) +- +- # Password handling +- +- #FIXME obsolete? +- def cupsPasswdCallback(self, querystring): +- return "" #FIXME +- if self.passwd_retry or len(self.password) == 0: +- waiting = self.WaitWindow.get_property('visible') +- if waiting: +- self.WaitWindow.hide () +- self.lblPasswordPrompt.set_label (self.prompt_primary + +- querystring) +- self.PasswordDialog.set_transient_for (self.MainWindow) +- self.entPasswd.grab_focus () +- +- result = self.PasswordDialog.run() +- self.PasswordDialog.hide() +- if waiting: +- self.WaitWindow.show () +- while gtk.events_pending (): +- gtk.main_iteration () +- if result == gtk.RESPONSE_OK: +- self.password = self.entPasswd.get_text() +- else: +- self.password = '' +- self.passwd_retry = False +- else: +- self.passwd_retry = True +- return self.password +- +-class NewPrinterGUI(QDialog): +- +- new_printer_device_tabs = { +- "parallel" : 0, # empty tab +- "usb" : 0, +- "hal" : 0, +- "beh" : 0, +- "hp" : 0, +- "hpfax" : 0, +- "socket": 2, +- "ipp" : 3, +- "http" : 3, +- "lpd" : 4, +- "scsi" : 5, +- "serial" : 6, +- "smb" : 7, +- } +- +- ntbkNewPrinterPages = { +- "name" : 0, +- "device" : 1, +- "make" : 2, +- "model" : 3, +- "class-members" : 4, +- "downloadable" : -1, +- } +- +- def __init__(self, mainapp): +- QDialog.__init__(self, mainapp) +- self.mainapp = mainapp +- self.language = mainapp.language +- self.dialog_mode = "" +- +- self.WaitWindow = QMessageBox(self.mainapp) +- self.WaitWindow.setStandardButtons(QMessageBox.NoButton) +- +- if os.path.exists("system-config-printer.ui"): +- APPDIR = QDir.currentPath() +- else: +- file = KStandardDirs.locate("appdata", "system-config-printer.ui") +- APPDIR = file.left(file.lastIndexOf("/")) +- +- uic.loadUi(APPDIR + "/" + "new-printer.ui", self) +- +- self.connect(self.tvNPDevices, SIGNAL("itemSelectionChanged()"), self.on_tvNPDevices_cursor_changed) +- self.connect(self.tvNPMakes, SIGNAL("itemSelectionChanged()"), self.on_tvNPMakes_cursor_changed) +- self.connect(self.tvNPModels, SIGNAL("itemSelectionChanged()"), self.on_tvNPModels_cursor_changed) +- self.connect(self.entNPTDevice, SIGNAL("textEdited(const QString&)"), self.on_entNPTDevice_changed) +-# self.connect(self.entNPTIPPHostname, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPHostname_changed) +-# self.connect(self.entNPTIPPQueuename, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPQueuename_changed) +- self.connect(self.entSMBURI, SIGNAL("textEdited(const QString&)"), self.on_entSMBURI_changed) +- self.rbtnSMBAuthPrompt.setChecked(True) +- self.on_rbtnSMBAuthSet_toggled(False) +- self.connect(self.rbtnSMBAuthSet, SIGNAL("toggled(bool)"), self.on_rbtnSMBAuthSet_toggled) +- self.rbtnNPFoomatic.setChecked(True) +- self.connect(self.rbtnNPFoomatic, SIGNAL("toggled(bool)"), self.on_rbtnNPFoomatic_toggled) +- self.connect(self.filechooserPPDButton, SIGNAL("clicked()"),self.on_filechooserPPDButton) +- self.options = {} # keyword -> Option object +- self.changed = set() +- self.conflicts = set() +- self.ppd = None +- +- # Synchronisation objects. +- self.ppds_lock = thread.allocate_lock() +- self.devices_lock = thread.allocate_lock() +- self.smb_lock = thread.allocate_lock() +- self.ipp_lock = thread.allocate_lock() +- self.drivers_lock = thread.allocate_lock() +- +- #self.connect(self.btnNCAddMember, SIGNAL("clicked()"), self.slot_btnNCAddMember_clicked) +- #self.connect(self.btnNCDelMember, SIGNAL("clicked()"), self.slot_btnNCDelMember_clicked) +- +- """ +- # share with mainapp +- self.WaitWindow = mainapp.WaitWindow +- self.lblWait = mainapp.lblWait +- self.busy = mainapp.busy +- self.ready = mainapp.ready +- self.show_IPP_Error = mainapp.show_IPP_Error +- self.show_HTTP_Error = mainapp.show_HTTP_Error +- """ +- +- # Optionally disable downloadable driver support. +- if not config.DOWNLOADABLE_DRIVER_SUPPORT: +- self.rbtnNPDownloadableDriverSearch.setEnabled(False) +- self.downloadableDriverSearchFrame.hide() +- +- """ +- # Set up OpenPrinting widgets. +- self.openprinting = openprinting.OpenPrinting () +- self.openprinting_query_handle = None +- combobox = self.cmbNPDownloadableDriverFoundPrinters +- cell = gtk.CellRendererText() +- combobox.pack_start (cell, True) +- combobox.add_attribute(cell, 'text', 0) +- +- # SMB browser +- self.smb_store = gtk.TreeStore (str, # host or share +- str, # comment +- gobject.TYPE_PYOBJECT, # domain dict +- gobject.TYPE_PYOBJECT) # host dict +- self.tvSMBBrowser.set_model (self.smb_store) +- self.smb_store.set_sort_column_id (0, gtk.SORT_ASCENDING) +- +- # SMB list columns +- col = gtk.TreeViewColumn (_("Share"), gtk.CellRendererText (), +- text=0) +- col.set_resizable (True) +- col.set_sort_column_id (0) +- self.tvSMBBrowser.append_column (col) +- +- col = gtk.TreeViewColumn (_("Comment"), gtk.CellRendererText (), +- text=1) +- self.tvSMBBrowser.append_column (col) +- slct = self.tvSMBBrowser.get_selection () +- slct.set_select_function (self.smb_select_function) +- +- self.SMBBrowseDialog.set_transient_for(self.NewPrinterWindow) +- +- # IPP browser +- self.ipp_store = gtk.TreeStore (str, # queue +- str, # location +- gobject.TYPE_PYOBJECT) # dict +- self.tvIPPBrowser.set_model (self.ipp_store) +- self.ipp_store.set_sort_column_id (0, gtk.SORT_ASCENDING) +- +- # IPP list columns +- col = gtk.TreeViewColumn (_("Queue"), gtk.CellRendererText (), +- text=0) +- col.set_resizable (True) +- col.set_sort_column_id (0) +- self.tvIPPBrowser.append_column (col) +- +- col = gtk.TreeViewColumn (_("Location"), gtk.CellRendererText (), +- text=1) +- self.tvIPPBrowser.append_column (col) +- self.IPPBrowseDialog.set_transient_for(self.NewPrinterWindow) +- +- self.tvNPDriversTooltips = TreeViewTooltips(self.tvNPDrivers, self.NPDriversTooltips) +- +- ppd_filter = gtk.FileFilter() +- ppd_filter.set_name(_("PostScript Printer Description files (*.ppd, *.PPD, *.ppd.gz, *.PPD.gz, *.PPD.GZ)")) +- ppd_filter.add_pattern("*.ppd") +- ppd_filter.add_pattern("*.PPD") +- ppd_filter.add_pattern("*.ppd.gz") +- ppd_filter.add_pattern("*.PPD.gz") +- ppd_filter.add_pattern("*.PPD.GZ") +- self.filechooserPPD.add_filter(ppd_filter) +- +- ppd_filter = gtk.FileFilter() +- ppd_filter.set_name(_("All files (*)")) +- ppd_filter.add_pattern("*") +- self.filechooserPPD.add_filter(ppd_filter) +- +- self.xml.signal_autoconnect(self) +- """ +- +- #FIXME hide bits which are not yet implemented +- self.btnSMBBrowse.hide() +- self.btnSMBVerify.hide() +- self.btnIPPFindQueue.hide() +- self.btnIPPVerify.hide() +- self.btnNPTLpdProbe.hide() +- +- def option_changed(self, option): +- if option.is_changed(): +- self.changed.add(option) +- else: +- self.changed.discard(option) +- +- if option.conflicts: +- self.conflicts.add(option) +- else: +- self.conflicts.discard(option) +- self.setDataButtonState() +- +- return +- +- def setDataButtonState(self): +- self.btnNPForward.setEnabled(not bool(self.conflicts)) +- +- def init(self, dialog_mode): +- self.dialog_mode = dialog_mode +- self.options = {} # keyword -> Option object +- self.changed = set() +- self.conflicts = set() +- +- """ +- combobox = self.cmbNPDownloadableDriverFoundPrinters +- combobox.set_model (gtk.ListStore (str, str)) +- self.entNPDownloadableDriverSearch.set_text ('') +- button = self.btnNPDownloadableDriverSearch +- label = button.get_children ()[0].get_children ()[0].get_children ()[1] +- self.btnNPDownloadableDriverSearch_label = label +- label.set_text (_("Search")) +- """ +- +- if self.dialog_mode == "printer": +- self.setWindowTitle(i18n("New Printer")) +- # Start on devices page (1, not 0) +- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"]) +- self.fillDeviceTab() +- self.on_rbtnNPFoomatic_toggled() +- # Start fetching information from CUPS in the background +- self.new_printer_PPDs_loaded = False +- self.queryPPDs () +- +- elif self.dialog_mode == "class": +- self.setWindowTitle(i18n("New Class")) +- self.fillNewClassMembers() +- # Start on name page +- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["name"]) +- elif self.dialog_mode == "device": +- self.setWindowTitle(i18n("Change Device URI")) +- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"]) +- self.queryDevices () +- self.loadPPDs() +- self.fillDeviceTab(self.mainapp.printer.device_uri) +- # Start fetching information from CUPS in the background +- self.new_printer_PPDs_loaded = False +- self.queryPPDs () +- elif self.dialog_mode == "ppd": +- self.setWindowTitle(i18n("Change Driver")) +- self.ntbkNewPrinter.setCurrentIndex(2) +- self.on_rbtnNPFoomatic_toggled() +- +- self.auto_model = "" +- ppd = self.mainapp.ppd +- if ppd: +- attr = ppd.findAttr("Manufacturer") +- if attr: +- self.auto_make = attr.value +- else: +- self.auto_make = "" +- attr = ppd.findAttr("ModelName") +- if not attr: attr = ppd.findAttr("ShortNickName") +- if not attr: attr = ppd.findAttr("NickName") +- if attr: +- if attr.value.startswith(self.auto_make): +- self.auto_model = attr.value[len(self.auto_make):].strip () +- else: +- try: +- self.auto_model = attr.value.split(" ", 1)[1] +- except IndexError: +- self.auto_model = "" +- else: +- self.auto_model = "" +- else: +- # Special CUPS names for a raw queue. +- self.auto_make = 'Raw' +- self.auto_model = 'Queue' +- +- self.loadPPDs () +- self.fillMakeList() +- +- if self.dialog_mode in ("printer", "class"): +- self.entNPName.setText (self.mainapp.makeNameUnique(self.dialog_mode)) +- #FIXMEself.entNPName.grab_focus() +- for widget in [self.entNPLocation, +- self.entNPDescription]: #, +- #self.entSMBURI, self.entSMBUsername, +- #self.entSMBPassword, self.entNPTDirectJetHostname]: +- widget.setText('') +- +- try: +- p = os.popen ('/bin/hostname', 'r') +- hostname = p.read ().strip () +- p.close () +- self.entNPLocation.setText(hostname) +- except: +- nonfatalException () +- +- self.entNPTDirectJetPort.setText('9100') +- self.setNPButtons() +- self.exec_() +- +- # get PPDs +- +- def queryPPDs(self): +- debugprint ("queryPPDs") +- if not self.ppds_lock.acquire(0): +- debugprint ("queryPPDs: in progress") +- return +- debugprint ("Lock acquired for PPDs thread") +- # Start new thread +- thread.start_new_thread (self.getPPDs_thread, (self.language[0],)) +- debugprint ("PPDs thread started") +- +- def getPPDs_thread(self, language): +- try: +- debugprint ("Connecting (PPDs)") +- cups.setServer (self.mainapp.connect_server) +- cups.setUser (self.mainapp.connect_user) +- cups.setPasswordCB (self.mainapp.cupsPasswdCallback) +- # cups.setEncryption (...) +- c = cups.Connection () +- debugprint ("Fetching PPDs") +- ppds_dict = c.getPPDs() +- self.ppds_result = cupshelpers.ppds.PPDs(ppds_dict, +- language=language) +- debugprint ("Closing connection (PPDs)") +- del c +- except cups.IPPError, (e, msg): +- self.ppds_result = cups.IPPError (e, msg) +- except: +- nonfatalException() +- self.ppds_result = { } +- +- debugprint ("Releasing PPDs lock") +- self.ppds_lock.release () +- +- def fetchPPDs(self, parent=None): +- debugprint ("fetchPPDs") +- self.queryPPDs() +- time.sleep (0.1) +- +- # Keep the UI refreshed while we wait for the devices to load. +- waiting = False +- while (self.ppds_lock.locked()): +- if not waiting: +- waiting = True +- self.WaitWindow.setText(i18n('Searching') + '

' + +- i18n('Searching for drivers')) +- self.WaitWindow.show () +- +- QApplication.processEvents() +- +- time.sleep (0.1) +- +- if waiting: +- self.WaitWindow.hide () +- +- debugprint ("Got PPDs") +- result = self.ppds_result # atomic operation +- if isinstance (result, cups.IPPError): +- # Propagate exception. +- raise result +- return result +- +- def loadPPDs(self, parent=None): +- try: +- return self.ppds +- except: +- self.ppds = self.fetchPPDs (parent=parent) +- return self.ppds +- +- def dropPPDs(self): +- try: +- del self.ppds +- except: +- pass +- +- # Class members +- +- def fillNewClassMembers(self): +- self.tvNCMembers.clear() +- self.tvNCNotMembers.clear() +- for printer in self.mainapp.printers.itervalues(): +- self.tvNCNotMembers.addItem(printer.name) +- +- @pyqtSignature("") +- def on_btnNCAddMember_clicked(self): +- self.mainapp.moveClassMembers(self.tvNCNotMembers, self.tvNCMembers) +- self.btnNPApply.setEnabled( +- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers))) +- +- @pyqtSignature("") +- def on_btnNCDelMember_clicked(self): +- self.mainapp.moveClassMembers(self.tvNCMembers, self.tvNCNotMembers) +- self.btnNPApply.setEnabled( +- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers))) +- +- @pyqtSignature("") +- def on_btnNPBack_clicked(self): +- self.nextNPTab(-1) +- +- @pyqtSignature("") +- def on_btnNPForward_clicked(self): +- self.nextNPTab() +- +- def nextNPTab(self, step=1): +- page_nr = self.ntbkNewPrinter.currentIndex() +- +- if self.dialog_mode == "class": +- #order = [0, 4, 5] +- order = [self.ntbkNewPrinterPages["name"], self.ntbkNewPrinterPages["class-members"]] +- elif self.dialog_mode == "printer": +- #self.busy(self) +- if page_nr == 1: # Device (first page) +- # Choose an appropriate name. +- name = 'printer' +- try: +- if self.device.id: +- name = self.device.id_dict["MDL"] +- name = self.mainapp.makeNameUnique (name) +- self.entNPName.setText(name) +- except: +- nonfatalException () +- self.auto_make, self.auto_model = None, None +- self.device.uri = self.getDeviceURI() +- if self.device.type in ("socket", "lpd", "ipp", "bluetooth"): +- host = self.getNetworkPrinterMakeModel(self.device) +- faxuri = None +- if host: +- faxuri = self.get_hplip_uri_for_network_printer(host, +- "fax") +- if faxuri: +- ##FIXME +- dialog = gtk.Dialog(self.device.info, +- self.NewPrinterWindow, +- gtk.DIALOG_MODAL | +- gtk.DIALOG_DESTROY_WITH_PARENT, +- (i18n("Printer"), 1, +- i18n("Fax"), 2)) +- label = gtk.Label(i18n("This printer supports both " +- "printing and sending faxes. " +- "Which functionality should be " +- "used for this queue?")) +- dialog.vbox.pack_start(label, True, True, 0) +- label.show() +- queue_type = dialog.run() +- dialog.destroy() +- if (queue_type == 2): +- self.device.id_dict = \ +- self.get_hpfax_device_id(faxuri) +- self.device.uri = faxuri +- self.auto_make = self.device.id_dict["MFG"] +- self.auto_model = self.device.id_dict["MDL"] +- self.device.id = "MFG:" + self.auto_make + \ +- ";MDL:" + self.auto_model + \ +- ";DES:" + \ +- self.device.id_dict["DES"] + ";" +- uri = self.device.uri +- if uri and uri.startswith ("smb://"): +- uri = SMBURI (uri=uri[6:]).sanitize_uri () +- +- # Try to access the PPD, in this case our detected IPP +- # printer is a queue on a remote CUPS server which is +- # not automatically set up on our local CUPS server +- # (for example DNS-SD broadcasted queue from Mac OS X) +- self.remotecupsqueue = None +- res = re.search ("ipp://(\S+(:\d+|))/printers/(\S+)", uri) +- if res: +- resg = res.groups() +- try: +- conn = httplib.HTTPConnection(resg[0]) +- conn.request("GET", "/printers/%s.ppd" % resg[2]) +- resp = conn.getresponse() +- if resp.status == 200: self.remotecupsqueue = resg[2] +- except: +- debugprint("exception in getting remotecupsqueue") +- pass +- +- # We also want to fetch the printer-info and +- # printer-location attributes, to pre-fill those +- # fields for this new queue. +- oldserver = cups.getServer() +- oldport = cups.getPort() +- try: +- cups.setServer (resg[0]) +- if len (resg[1]) > 0: +- cups.setPort (int (resg[1])) +- else: +- cups.setPort (631) +- +- c = cups.Connection () +- r = ['printer-info', 'printer-location'] +- attrs = c.getPrinterAttributes (uri=uri, +- requested_attributes=r) +- info = attrs.get ('printer-info', '') +- location = attrs.get ('printer-location', '') +- if len (info) > 0: +- self.entNPDescription.setText(info) +- if len (location) > 0: +- self.entNPLocation.setText(location) +- except: +- nonfatalException () +- +- cups.setServer (oldserver) +- cups.setPort (oldport) +- +- if (not self.remotecupsqueue and +- not self.new_printer_PPDs_loaded): +- try: +- self.loadPPDs(self) +- except cups.IPPError, (e, msg): +- #self.ready (self) +- self.show_IPP_Error(e, msg) +- return +- except: +- self.ready (self) +- return +- self.new_printer_PPDs_loaded = True +- +- ppdname = None +- try: +- if self.remotecupsqueue: +- # We have a remote CUPS queue, let the client queue +- # stay raw so that the driver on the server gets used +- ppdname = 'raw' +- self.ppd = ppdname +- name = self.remotecupsqueue +- name = self.mainapp.makeNameUnique (name) +- self.entNPName.setText(name) +- elif self.device.id: +- id_dict = self.device.id_dict +- (status, ppdname) = self.ppds.\ +- getPPDNameFromDeviceID (id_dict["MFG"], +- id_dict["MDL"], +- id_dict["DES"], +- id_dict["CMD"], +- self.device.uri) +- else: +- (status, ppdname) = self.ppds.\ +- getPPDNameFromDeviceID ("Generic", +- "Printer", +- "Generic Printer", +- [], +- self.device.uri) +- +- if ppdname and not self.remotecupsqueue: +- ppddict = self.ppds.getInfoFromPPDName (ppdname) +- make_model = ppddict['ppd-make-and-model'] +- (make, model) = \ +- cupshelpers.ppds.ppdMakeModelSplit (make_model) +- self.auto_make = make +- self.auto_model = model +- except: +- nonfatalException () +- if not self.remotecupsqueue: +- self.fillMakeList() +- elif page_nr == 3: # Model has been selected +- if not self.device.id: +- # Choose an appropriate name when no Device ID +- # is available, based on the model the user has +- # selected. +- try: +- items = self.tvNPModels.selectedItems() +- name = unicode(items[0].text()) +- name = self.mainapp.makeNameUnique (name) +- self.entNPName.setText(name) +- except: +- nonfatalException () +- +- ##self.ready (self.NewPrinterWindow) +- if self.remotecupsqueue: +- order = [1, 0] +- elif self.rbtnNPFoomatic.isChecked(): +- order = [1, 2, 3, 6, 0] +- elif self.rbtnNPPPD.isChecked(): +- order = [1, 2, 6, 0] +- else: +- # Downloadable driver +- order = [1, 2, 7, 6, 0] +- elif self.dialog_mode == "device": +- order = [1] +- elif self.dialog_mode == "ppd": +- self.rbtnChangePPDasIs.setChecked(True) +- if self.rbtnNPFoomatic.isChecked(): +- order = [2, 3, 5, 6] +- elif self.rbtnNPPPD.isChecked(): +- order = [2, 5, 6] +- else: +- # Downloadable driver +- order = [2, 7, 5, 6] +- +- next_page_nr = order[order.index(page_nr)+step] +- +- # fill Installable Options tab +- if next_page_nr == 6 and step > 0: +- #TODO Prepare Installable Options screen. +- self.ppd = self.getNPPPD() +- """FIXME todo +- if next_page_nr == 6: +- # Prepare Installable Options screen. +- if isinstance(self.ppd, cups.PPD): +- self.fillNPInstallableOptions() +- else: +- self.installable_options = None +- # Put a label there explaining why the page is empty. +- ppd = self.ppd +- self.ppd = None +- self.fillNPInstallableOptions() +- self.ppd = ppd +- +- # step over if empty and not in PPD mode +- if self.dialog_mode != "ppd" and not self.installable_options: +- next_page_nr = order[order.index(next_page_nr)+1] +- """ +- next_page_nr = order[order.index(next_page_nr)+1] +- self.installable_options = False +- # Step over empty Installable Options tab +- if next_page_nr == 6 and not self.installable_options and step<0: +- next_page_nr = order[order.index(next_page_nr)-1] +- +- if next_page_nr == 7: # About to show downloadable drivers +- if self.drivers_lock.locked (): +- # Still searching for drivers. +- self.lblWait.set_markup ('' + +- i18n('Searching') + '\n\n' + +- i18n('Searching for drivers')) +- self.WaitWindow.set_transient_for (self.NewPrinterWindow) +- self.WaitWindow.show () +- self.busy(self) +- +- # Keep the UI refreshed while we wait for the drivers +- # query to complete. +- while self.drivers_lock.locked (): +- while gtk.events_pending (): +- gtk.main_iteration () +- time.sleep (0.1) +- +- self.ready (self.NewPrinterWindow) +- self.WaitWindow.hide () +- +- self.fillDownloadableDrivers() +- +- self.ntbkNewPrinter.setCurrentIndex(next_page_nr) +- +- self.setNPButtons() +- +- def setNPButtons(self): +- nr = self.ntbkNewPrinter.currentIndex() +- +- if self.dialog_mode == "device": +- self.btnNPBack.hide() +- self.btnNPForward.hide() +- self.btnNPApply.show() +- uri = self.getDeviceURI () +- self.btnNPApply.setEnabled(validDeviceURI (uri)) +- return +- +- if self.dialog_mode == "ppd": +- if nr == 5: # Apply +- if not self.installable_options: +- # There are no installable options, so this is the +- # last page. +- debugprint ("No installable options") +- self.btnNPForward.hide () +- self.btnNPApply.show () +- else: +- self.btnNPForward.show () +- self.btnNPApply.hide () +- return +- elif nr == 6: +- self.btnNPForward.hide() +- self.btnNPApply.show() +- return +- else: +- self.btnNPForward.show() +- self.btnNPApply.hide() +- if nr == 2: +- self.btnNPBack.hide() +- self.btnNPForward.show() +- downloadable_selected = False +- if self.rbtnNPDownloadableDriverSearch.isChecked(): +- combobox = self.cmbNPDownloadableDriverFoundPrinters +- iter = combobox.get_active_iter () #FIXME +- if iter and combobox.get_model ().get_value (iter, 1): +- downloadable_selected = True +- +- self.btnNPForward.setEnabled(bool( +- self.rbtnNPFoomatic.isChecked() or +- not self.filechooserPPD.text().isEmpty() or +- downloadable_selected)) +- return +- else: +- self.btnNPBack.show() +- +- # class/printer +- +- if nr == 1: # Device +- valid = False +- try: +- uri = self.getDeviceURI () +- valid = validDeviceURI (uri) +- except: +- pass +- self.btnNPForward.setEnabled(valid) +- self.btnNPBack.hide () +- else: +- self.btnNPBack.show() +- +- self.btnNPForward.show() +- self.btnNPApply.hide() +- +- if nr == 0: # Name +- self.btnNPBack.show() +- if self.dialog_mode == "class": +- self.btnNPForward.setEnabled(True) +- if self.dialog_mode == "printer": +- self.btnNPForward.hide() +- self.btnNPApply.show() +- self.btnNPApply.setEnabled( +- self.mainapp.checkNPName(unicode(self.entNPName.text()))) +- if nr == 2: # Make/PPD file +- downloadable_selected = False +- if self.rbtnNPDownloadableDriverSearch.isChecked(): +- combobox = self.cmbNPDownloadableDriverFoundPrinters +- iter = combobox.get_active_iter () #FIXME +- if iter and combobox.get_model ().get_value (iter, 1): +- downloadable_selected = True +- +- self.btnNPForward.setEnabled(bool( +- self.rbtnNPFoomatic.isChecked() or +- not self.filechooserPPD.text().isEmpty() or +- downloadable_selected)) +- +- if nr == 3: # Model/Driver +- iter = self.tvNPDrivers.currentItem() +- self.btnNPForward.setEnabled(bool(iter)) +- if nr == 4: # Class Members +- self.btnNPForward.hide() +- self.btnNPApply.show() +- self.btnNPApply.setEnabled(self.tvNCMembers.count() > 0) +- if nr == 7: # Downloadable drivers +- if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1: #FIXME +- accepted = self.rbtnNPDownloadLicenseYes.get_active () +- else: +- treeview = self.tvNPDownloadableDrivers +- model, iter = treeview.get_selection ().get_selected () +- accepted = (iter != None) +- +- self.btnNPForward.set_sensitive(accepted) +- +- def on_filechooserPPDButton(self): +- home = QDir.homePath() +- fd = QFileDialog() +- fd.setFileMode(fd.ExistingFile) +- filename = fd.getOpenFileName(self, 'Open PPD file', home) +- self.filechooserPPD.setText(filename) +- self.btnNPForward.setEnabled(True) +- +- def getDevices_thread(self): +- try: +- debugprint ("Connecting (devices)") +- cups.setServer (self.mainapp.connect_server) +- #cups.setUser (self.mainapp.connect_user) +- cups.setUser ("jr") +- cups.setPasswordCB (self.mainapp.cupsPasswdCallback) +- # cups.setEncryption (...) +- c = cups.Connection () +- debugprint ("Fetching devices") +- self.devices_result = cupshelpers.getDevices(c) +- except cups.IPPError, (e, msg): +- self.devices_result = cups.IPPError (e, msg) +- except: +- debugprint ("Exception in getDevices_thread") +- self.devices_result = {} +- +- try: +- debugprint ("Closing connection (devices)") +- del c +- except: +- pass +- +- debugprint ("Releasing devices lock") +- self.devices_lock.release () +- +- # Device URI +- def queryDevices(self): +- if not self.devices_lock.acquire(0): +- debugprint ("queryDevices: in progress") +- return +- debugprint ("Lock acquired for devices thread") +- # Start new thread +- thread.start_new_thread (self.getDevices_thread, ()) +- #self.getDevices_thread() +- debugprint ("Devices thread started") +- +- def fetchDevices(self, parent=None): +- debugprint ("fetchDevices") +- self.queryDevices () +- time.sleep (0.1) +- +- # Keep the UI refreshed while we wait for the devices to load. +- waiting = False +- while (self.devices_lock.locked()): +- if not waiting: +- waiting = True +- self.WaitWindow.setText (i18n('Searching') + '

' + +- i18n('Searching for printers')) +- #if not parent: +- # parent = self.mainapp.MainWindow +- #self.WaitWindow.set_transient_for (parent) +- #self.WaitWindow.show () +- self.WaitWindow.show() +- +- QApplication.processEvents() +- +- time.sleep (0.1) +- +- if waiting: +- #self.WaitWindow.hide () +- self.WaitWindow.hide() +- +- debugprint ("Got devices") +- result = self.devices_result # atomic operation +- if isinstance (result, cups.IPPError): +- # Propagate exception. +- raise result +- return result +- +- def get_hpfax_device_id(self, faxuri): +- os.environ["URI"] = faxuri +- cmd = 'LC_ALL=C DISPLAY= hp-info -d "${URI}"' +- debugprint (faxuri + ": " + cmd) +- try: +- p = subprocess.Popen (cmd, shell=True, +- stdin=file("/dev/null"), +- stdout=subprocess.PIPE, +- stderr=subprocess.PIPE) +- (stdout, stderr) = p.communicate () +- except: +- # Problem executing command. +- return None +- +- for line in stdout.split ("\n"): +- if line.find ("fax-type") == -1: +- continue +- faxtype = -1 +- res = re.search ("(\d+)", line) +- if res: +- resg = res.groups() +- faxtype = resg[0] +- if faxtype >= 0: break +- if faxtype < 0: +- return None +- elif faxtype == 4: +- return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax 2;DES:HP Fax 2;') +- else: +- return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax;DES:HP Fax;') +- +- def get_hplip_uri_for_network_printer(self, host, mode): +- os.environ["HOST"] = host +- if mode == "print": mod = "-c" +- elif mode == "fax": mod = "-f" +- else: mod = "-c" +- cmd = 'hp-makeuri ' + mod + ' "${HOST}"' +- debugprint (host + ": " + cmd) +- uri = None +- try: +- p = subprocess.Popen (cmd, shell=True, +- stdin=file("/dev/null"), +- stdout=subprocess.PIPE, +- stderr=subprocess.PIPE) +- (stdout, stderr) = p.communicate () +- except: +- # Problem executing command. +- return None +- +- uri = stdout.strip () +- return uri +- +- def getNetworkPrinterMakeModel(self, device): +- # Determine host name/IP +- host = None +- s = device.uri.find ("://") +- if s != -1: +- s += 3 +- e = device.uri[s:].find (":") +- if e == -1: e = device.uri[s:].find ("/") +- if e == -1: e = device.uri[s:].find ("?") +- if e == -1: e = len (device.uri) +- host = device.uri[s:s+e] +- # Try to get make and model via SNMP +- if host: +- os.environ["HOST"] = host +- cmd = '/usr/lib/cups/backend/snmp "${HOST}"' +- debugprint (host + ": " + cmd) +- stdout = None +- try: +- p = subprocess.Popen (cmd, shell=True, +- stdin=file("/dev/null"), +- stdout=subprocess.PIPE, +- stderr=subprocess.PIPE) +- (stdout, stderr) = p.communicate () +- except: +- # Problem executing command. +- pass +- +- if stdout != None: +- mm = re.sub("^\s*\S+\s+\S+\s+\"", "", stdout) +- mm = re.sub("\"\s+.*$", "", mm) +- if mm and mm != "": device.make_and_model = mm +- # Extract make and model and create a pseudo device ID, so +- # that a PPD/driver can be assigned to the device +- make_and_model = None +- if len (device.make_and_model) > 7: +- make_and_model = device.make_and_model +- elif len (device.info) > 7: +- make_and_model = device.info +- make_and_model = re.sub("\s*(\(|\d+\.\d+\.\d+\.\d+).*$", "", make_and_model) +- if make_and_model and not device.id: +- mk = None +- md = None +- (mk, md) = cupshelpers.ppds.ppdMakeModelSplit (make_and_model) +- device.id = "MFG:" + mk + ";MDL:" + md + ";DES:" + mk + " " + md + ";" +- device.id_dict = cupshelpers.parseDeviceID (device.id) +- # Check whether the device is supported by HPLIP and replace +- # its URI by an HPLIP URI +- if host: +- hplipuri = self.get_hplip_uri_for_network_printer(host, "print") +- if hplipuri: +- device.uri = hplipuri +- s = hplipuri.find ("/usb/") +- if s == -1: s = hplipuri.find ("/par/") +- if s == -1: s = hplipuri.find ("/net/") +- if s != -1: +- s += 5 +- e = hplipuri[s:].find ("?") +- if e == -1: e = len (hplipuri) +- mdl = hplipuri[s:s+e].replace ("_", " ") +- if mdl.startswith ("hp ") or mdl.startswith ("HP "): +- mdl = mdl[3:] +- device.make_and_model = "HP " + mdl +- device.id = "MFG:HP;MDL:" + mdl + ";DES:HP " + mdl + ";" +- device.id_dict = cupshelpers.parseDeviceID (device.id) +- # Return the host name/IP for further actions +- return host +- +- def fillDeviceTab(self, current_uri=None, query=True): +- if query: +- try: +- devices = self.fetchDevices() +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- devices = {} +- except: +- nonfatalException() +- devices = {} +- +- if current_uri: +- if devices.has_key (current_uri): +- current = devices.pop(current_uri) +- else: +- current = cupshelpers.Device (current_uri) +- current.info = "Current device" +- +- self.devices = devices.values() +- +- for device in self.devices: +- if device.type == "usb": +- # Find USB URIs with corresponding HPLIP URIs and mark them +- # for deleting, so that the user will only get the HPLIP +- # URIs for full device support in the list +- ser = None +- s = device.uri.find ("?serial=") +- if s != -1: +- s += 8 +- e = device.uri[s:].find ("?") +- if e == -1: e = len (device.uri) +- ser = device.uri[s:s+e] +- mod = None +- s = device.uri[6:].find ("/") +- if s != -1: +- s += 7 +- e = device.uri[s:].find ("?") +- if e == -1: e = len (device.uri) +- mod = device.uri[s:s+e].lower ().replace ("%20", "_") +- if mod.startswith ("hp_"): +- mod = mod[3:] +- matchfound = 0 +- for hpdevice in self.devices: +- hpser = None +- hpmod = None +- uri = hpdevice.uri +- if not uri.startswith ("hp:"): continue +- if ser: +- s = uri.find ("?serial=") +- if s != -1: +- s += 8 +- e = uri[s:].find ("?") +- if e == -1: e = len (uri) +- hpser = uri[s:s+e] +- if hpser != ser: continue +- matchfound = 1 +- if mod and not (ser and hpser): +- s = uri.find ("/usb/") +- if s != -1: +- s += 5 +- e = uri[s:].find ("?") +- if e == -1: e = len (uri) +- hpmod = uri[s:s+e].lower () +- if hpmod.startswith ("hp_"): +- hpmod = hpmod[3:] +- if hpmod != mod: continue +- matchfound = 1 +- if matchfound == 1: break +- if matchfound == 1: +- device.uri = "delete" +- if device.type == "hal": +- # Remove HAL USB URIs, for these printers there are already +- # USB URIs +- if device.uri.startswith("hal:///org/freedesktop/Hal/devices/usb_device"): +- device.uri = "delete" +- if device.type == "socket": +- # Remove default port to more easily find duplicate URIs +- device.uri = device.uri.replace (":9100", "") +- try: +- ## XXX This needs to be moved to *after* the device is +- # selected. Looping through all the network printers like +- # this is far too slow. +- if False and device.type in ("socket", "lpd", "ipp", "bluetooth"): +- host = self.getNetworkPrinterMakeModel(device) +- faxuri = None +- if host: +- faxuri = self.get_hplip_uri_for_network_printer(host, +- "fax") +- if faxuri: +- self.devices.append(cupshelpers.Device(faxuri, +- **{'device-class' : "direct", +- 'device-info' : device.info + " HP Fax HPLIP", +- 'device-device-make-and-model' : "HP Fax", +- 'device-id' : "MFG:HP;MDL:Fax;DES:HP Fax;"})) +- if device.uri.startswith ("hp:"): +- device.type = "hp" +- device.info += (" HPLIP") +- except: +- nonfatalException () +- # Mark duplicate URIs for deletion +- for i in range (len (self.devices)): +- for j in range (len (self.devices)): +- if i == j: continue +- device1 = self.devices[i] +- device2 = self.devices[j] +- if device1.uri == "delete" or device2.uri == "delete": +- continue +- if device1.uri == device2.uri: +- # Keep the one with the longer (better) device ID +- if (not device1.id): +- device1.uri = "delete" +- elif (not device2.id): +- device2.uri = "delete" +- elif (len (device1.id) < len (device2.id)): +- device1.uri = "delete" +- else: +- device2.uri = "delete" +- self.devices = filter(lambda x: x.uri not in ("hp:/no_device_found", +- "hpfax:/no_device_found", +- "hp", "hpfax", +- "hal", "beh", +- "scsi", "http", "delete"), +- self.devices) +- self.devices.sort() +- +- self.devices.append(cupshelpers.Device('', +- **{'device-info' :i18nc("Other device", "Other")})) +- if current_uri: +- current.info = i18nc("Current device", "%1 (Current)", current.info) +- self.devices.insert(0, current) +- self.device = current +- self.tvNPDevices.clear() +- +- for device in self.devices: +- self.tvNPDevices.addItem(device.info) +- +- #self.tvNPDevices.get_selection().select_path(0) +- self.tvNPDevices.setCurrentRow(0) +- self.on_tvNPDevices_cursor_changed() +- +- def on_entNPTDevice_changed(self, entry): +- self.setNPButtons() +- +- #TODO +- ## SMB browsing +- def on_entSMBURI_changed (self, text): +- uri = unicode(text) +- (group, host, share, user, password) = SMBURI (uri=uri).separate () +- if user: +- self.entSMBUsername.setText(user) +- if password: +- self.entSMBPassword.setText(password) +- if user or password: +- uri = SMBURI (group=group, host=host, share=share).get_uri () +- self.entSMBURI.setText(uri) +- self.rbtnSMBAuthSet.setChecked(True) +- elif unicode(self.entSMBUsername.text()) == '': +- self.rbtnSMBAuthPrompt.setChecked(True) +- +- self.btnSMBVerify.setEnabled(bool(uri)) +- +- def on_rbtnSMBAuthSet_toggled(self, ticked): +- self.tblSMBAuth.setEnabled(ticked) +- +- def on_entNPTIPPHostname_textChanged(self): +- valid = len (self.entNPTIPPHostname.text ()) > 0 +- self.btnIPPFindQueue.setEnabled(valid) +- self.update_IPP_URI_label () +- +- ### IPP Browsing +- def update_IPP_URI_label(self): +- hostname = unicode(self.entNPTIPPHostname.text()) +- queue = unicode(self.entNPTIPPQueuename.text()) +- valid = len (hostname) > 0 and queue != '/printers/' +- +- if valid: +- uri = "ipp://%s%s" % (hostname, queue) +- self.lblIPPURI.setText(uri) +- self.lblIPPURI.show () +- self.entNPTIPPQueuename.show () +- else: +- self.lblIPPURI.hide () +- +- self.btnIPPVerify.setEnabled(valid) +- self.setNPButtons () +- +- #FIXME this seems totally different from the Gnome one +- @pyqtSignature("") +- def on_btnIPPFindQueue_clicked(self): +- self.IPPBrowseBox.clear() +- host = str(self.entNPTIPPHostname.text()) +- cups.setServer (host) +- printers = classes = {} +- try: +- c = cups.Connection() +- printers = c.getPrinters () +- classes = c.getClasses () +- del c +- except RuntimeError: +- pass +- except cups.IPP_Error, (e, msg): +- pass +- +- for printer, dict in printers.iteritems (): +- +- self.IPPBrowseBox.addItem(printer) +-# store.set_value (iter, 0, printer) +-# store.set_value (iter, 1, dict.get ('printer-location', '')) +-# store.set_value (iter, 2, dict) +- for pclass, dict in classes.iteritems (): +- pass +-# iter = store.append (None) +-# store.set_value (iter, 0, pclass) +-# store.set_value (iter, 1, dict.get ('printer-location', '')) +-# store.set_value (iter, 2, dict) +- +- if len (printers) + len (classes) == 0: +- # Display 'No queues' dialog +- QMessageBox.information(self, i18n("No queues"),i18n("There are no queues available.")) +- +- def on_tvNPDevices_cursor_changed(self): +- device = self.devices[self.tvNPDevices.currentRow()] +- self.device = device +- self.lblNPDeviceDescription.setText('') +- page = self.new_printer_device_tabs.get(device.type, 1) +- self.ntbkNPType.setCurrentIndex(page) +- +- type = device.type +- url = device.uri.split(":", 1)[-1] +- if page == 0: +- # This is the "no options" page, with just a label to describe +- # the selected device. +- if device.type == "parallel": +- text = i18n("A printer connected to the parallel port.") +- elif device.type == "usb": +- text = i18n("A printer connected to a USB port.") +- elif device.type == "hp": +- text = i18n("HPLIP software driving a printer, " +- "or the printer function of a multi-function device.") +- elif device.type == "hpfax": +- text = i18n("HPLIP software driving a fax machine, " +- "or the fax function of a multi-function device.") +- elif device.type == "hal": +- text = i18n("Local printer detected by the " +- "Hardware Abstraction Layer (HAL).") +- else: +- text = device.uri +- +- self.lblNPDeviceDescription.setText(text) +- elif device.type=="socket": +- if device.uri.startswith ("socket"): +- host = device.uri[9:] +- i = host.find (":") +- if i != -1: +- port = int (host[i + 1:]) +- host = host[:i] +- else: +- port = 9100 +- +- self.entNPTDirectJetHostname.setText(host) +- self.entNPTDirectJetPort.setText(str (port)) +- elif device.type=="serial": +- if not device.is_class: +- options = device.uri.split("?")[1] +- options = options.split("+") +- option_dict = {} +- for option in options: +- name, value = option.split("=") +- option_dict[name] = value +- +- for widget, name, optionvalues in ( +- (self.cmbNPTSerialBaud, "baud", None), +- (self.cmbNPTSerialBits, "bits", None), +- (self.cmbNPTSerialParity, "parity", +- ["none", "odd", "even"]), +- (self.cmbNPTSerialFlow, "flow", +- ["none", "soft", "hard", "hard"])): +- if option_dict.has_key(name): # option given in URI? +- if optionvalues is None: # use text in widget +- model = widget.get_model() +- iter = model.get_iter_first() +- nr = 0 +- while iter: +- value = model.get(iter,0)[0] +- if value == option_dict[name]: +- widget.set_active(nr) +- break +- iter = model.iter_next(iter) +- nr += 1 +- else: # use optionvalues +- nr = optionvalues.index( +- option_dict[name]) +- widget.set_active(nr+1) # compensate "Default" +- else: +- widget.set_active(0) +- +- # XXX FILL TABS FOR VALID DEVICE URIs +- elif device.type in ("ipp", "http"): +- if (device.uri.startswith ("ipp:") or +- device.uri.startswith ("http:")): +- match = re.match ("(ipp|https?)://([^/]+)(.*)", device.uri) +- if match: +- server = match.group (2) +- printer = match.group (3) +- else: +- server = "" +- printer = "" +- +- self.entNPTIPPHostname.setText(server) +- self.entNPTIPPQueuename.setText(printer) +- self.lblIPPURI.setText(device.uri) +- self.lblIPPURI.show() +- self.entNPTIPPQueuename.show() +- else: +- self.entNPTIPPHostname.setText('') +- self.entNPTIPPQueuename.setText('/printers/') +- self.entNPTIPPQueuename.show() +- self.lblIPPURI.hide() +- elif device.type=="lpd": +- if device.uri.startswith ("lpd"): +- host = device.uri[6:] +- i = host.find ("/") +- if i != -1: +- printer = host[i + 1:] +- host = host[:i] +- else: +- printer = "" +- self.cmbentNPTLpdHost.addItem(host) +- self.cmbentNPTLpdQueue.addItem(printer) +- elif device.uri == "lpd": +- pass +- elif device.uri == "smb": +- self.entSMBURI.setText('') +- self.btnSMBVerify.setEnabled(False) +- elif device.type == "smb": +- self.entSMBUsername.setText('') +- self.entSMBPassword.setText('') +- self.entSMBURI.setText(device.uri[6:]) +- self.btnSMBVerify.setEnabled(True) +- else: +- self.entNPTDevice.setText(device.uri) +- +- self.setNPButtons() +- +- def getDeviceURI(self): +- type = self.device.type +- if type == "socket": # DirectJet +- host = unicode(self.entNPTDirectJetHostname.text()) +- port = unicode(self.entNPTDirectJetPort.text()) +- device = "socket://" + host +- if port: +- device = device + ':' + port +- elif type in ("http", "ipp"): # IPP +- if self.lblIPPURI.isVisible: +- device = unicode(self.lblIPPURI.text()) +- else: +- device = "ipp" +- elif type == "lpd": # LPD +- host = unicode(self.cmbentNPTLpdHost.currentText()) +- printer = unicode(self.cmbentNPTLpdQueue.currentText()) +- device = "lpd://" + host +- if printer: +- device = device + "/" + printer +- elif type == "parallel": # Parallel +- device = self.device.uri +- elif type == "scsi": # SCSII +- device = "" +- elif type == "serial": # Serial +- options = [] +- for widget, name, optionvalues in ( +- (self.cmbNPTSerialBaud, "baud", None), +- (self.cmbNPTSerialBits, "bits", None), +- (self.cmbNPTSerialParity, "parity", +- ("none", "odd", "even")), +- (self.cmbNPTSerialFlow, "flow", +- ("none", "soft", "hard", "hard"))): +- nr = widget.get_active() +- if nr: +- if optionvalues is not None: +- option = optionvalues[nr-1] +- else: +- option = widget.get_active_text() +- options.append(name + "=" + option) +- options = "+".join(options) +- device = self.device.uri.split("?")[0] #"serial:/dev/ttyS%s" +- if options: +- device = device + "?" + options +- elif type == "smb": +- uri = unicode(self.entSMBURI.text()) +- (group, host, share, u, p) = SMBURI (uri=uri).separate () +- user = '' +- password = '' +- if self.rbtnSMBAuthSet.isChecked(): +- user = unicode(self.entSMBUsername.text()) +- password = unicode(self.entSMBPassword.text()) +- uri = SMBURI (group=group, host=host, share=share, +- user=user, password=password).get_uri () +- device = "smb://" + uri +- elif not self.device.is_class: +- device = self.device.uri +- else: +- device = str(self.entNPTDevice.text()) +- return device +- # class/printer +- +- if nr == self.ntbkNewPrinterPages["device"]: # Device +- valid = False +- try: +- uri = self.getDeviceURI () +- valid = validDeviceURI (uri) +- except: +- debugprint("exception in getDeviceURI()") +- pass +- self.btnNPForward.setEnabled(valid) +- self.btnNPBack.hide () +- else: +- self.btnNPBack.show() +- +- self.btnNPForward.show() +- self.btnNPApply.hide() +- +- if nr == self.ntbkNewPrinterPages["name"]: # Name +- self.btnNPBack.show() +- if self.dialog_mode == "printer": +- self.btnNPForward.hide() +- self.btnNPApply.show() +- self.btnNPApply.setEnabled( +- self.mainapp.checkNPName(self.entNPName.getText())) +- if nr == self.ntbkNewPrinterPages["make"]: # Make/PPD file +- downloadable_selected = False +- if self.rbtnNPDownloadableDriverSearch.get_active (): +- combobox = self.cmbNPDownloadableDriverFoundPrinters +- iter = combobox.get_active_iter () +- if iter and combobox.get_model ().get_value (iter, 1): +- downloadable_selected = True +- +- self.btnNPForward.setEnabled(bool( +- self.rbtnNPFoomatic.get_active() or +- not self.filechooserPPD.text().isEmpty() or +- downloadable_selected)) +- if nr == self.ntbkNewPrinterPages["model"]: # Model/Driver +- model, iter = self.tvNPDrivers.get_selection().get_selected() +- self.btnNPForward.set_sensitive(bool(iter)) +- if nr == self.ntbkNewPrinterPages["class-members"]: # Class Members +- self.btnNPForward.hide() +- self.btnNPApply.show() +- self.btnNPApply.setEnabled( +- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers))) +- if nr == self.ntbkNewPrinterPages["downloadable"]: # Downloadable drivers +- if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1: +- accepted = self.rbtnNPDownloadLicenseYes.get_active () +- else: +- accepted = True +- +- self.btnNPForward.set_sensitive(accepted) +- +- # PPD +- +- def on_rbtnNPFoomatic_toggled(self): +- rbtn1 = self.rbtnNPFoomatic.isChecked() +- rbtn2 = self.rbtnNPPPD.isChecked() +- rbtn3 = self.rbtnNPDownloadableDriverSearch.isChecked() +- self.tvNPMakes.setEnabled(rbtn1) +- self.filechooserPPD.setEnabled(rbtn2) +- +- """FIXME +- if not rbtn3 and self.openprinting_query_handle: +- # Need to cancel a search in progress. +- self.openprinting.cancelOperation (self.openprinting_query_handle) +- self.openprinting_query_handle = None +- self.btnNPDownloadableDriverSearch_label.setText(_("Search")) +- # Clear printer list. +- self.cmbNPDownloadableDriverFoundPrinters.clear() +- """ +- +- for widget in [self.entNPDownloadableDriverSearch, +- self.cmbNPDownloadableDriverFoundPrinters]: +- widget.setEnabled(rbtn3) +- self.btnNPDownloadableDriverSearch.\ +- setEnabled(rbtn3 and (self.openprinting_query_handle == None)) +- +- self.setNPButtons() +- +- # PPD from foomatic +- +- def fillMakeList(self): +- makes = self.ppds.getMakes() +- self.tvNPMakes.clear() +- found = False +- index = 0 +- for make in makes: +- self.tvNPMakes.addItem(make) +- index = index + 1 +- if make==self.auto_make: +- self.tvNPMakes.setCurrentRow(index-1) +- found = True +- +- self.on_tvNPMakes_cursor_changed() +- +- def on_tvNPMakes_cursor_changed(self): +- items = self.tvNPMakes.selectedItems() +- if len(items) > 0: +- self.NPMake = unicode(items[0].text()) +- self.fillModelList() +- +- def fillModelList(self): +- models = self.ppds.getModels(self.NPMake) +- self.tvNPModels.clear() +- selected = False +- index = 0 +- selected = False +- for pmodel in models: +- self.tvNPModels.addItem(pmodel) +- if self.NPMake==self.auto_make and pmodel==self.auto_model: +- self.tvNPModels.setCurrentRow(index) +- selected = True +- index = index + 1 +- if not selected: +- self.tvNPModels.setCurrentRow(0) +- ##self.tvNPModels.columns_autosize() +- self.on_tvNPModels_cursor_changed() +- +- def fillDriverList(self, pmake, pmodel): +- self.NPModel = pmodel +- self.tvNPDrivers.clear() +- +- ppds = self.ppds.getInfoFromModel(pmake, pmodel) +- +- self.NPDrivers = self.ppds.orderPPDNamesByPreference(ppds.keys()) +- for i in range (len(self.NPDrivers)): +- ppd = ppds[self.NPDrivers[i]] +- driver = ppd["ppd-make-and-model"] +- driver = driver.replace(" (recommended)", "") +- +- try: +- lpostfix = " [%s]" % ppd["ppd-natural-language"] +- driver += lpostfix +- except KeyError: +- pass +- +- if i == 0: +- self.tvNPDrivers.addItem(i18nc("Recommended driver", "%1 (recommended)", driver)) +- self.tvNPDrivers.setCurrentRow(0) +- else: +- self.tvNPDrivers.addItem(driver) +- ##self.tvNPDrivers.columns_autosize() +- +- def on_tvNPModels_cursor_changed(self): +- items = self.tvNPModels.selectedItems() +- if len(items) > 0: +- pmodel = unicode(items[0].text()) +- self.fillDriverList(self.NPMake, pmodel) +- +- def getNPPPD(self): +- try: +- if self.rbtnNPFoomatic.isChecked(): +- #items = self.tvNPDrivers.selectedItems() +- #nr = unicode(items[0]) +- nr = self.tvNPDrivers.currentRow() +- ppd = self.NPDrivers[nr] +- elif self.rbtnNPPPD.isChecked(): +- ppd = cups.PPD(unicode(self.filechooserPPD.text())) +- else: +- """FIXME +- # PPD of the driver downloaded from OpenPrinting XXX +- treeview = self.tvNPDownloadableDrivers +- model, iter = treeview.get_selection ().get_selected () +- driver = model.get_value (iter, 1) +- if driver.has_key ('ppds'): +- # Only need to download a PPD. +- file_to_download = driver +- """ +- +- ppd = "XXX" +- +- except RuntimeError, e: +- if self.rbtnNPFoomatic.isChecked(): +- # Foomatic database problem of some sort. +- err_title = i18n('Database error') +- model, iter = (self.tvNPDrivers.get_selection(). +- get_selected()) +- nr = model.get_path(iter)[0] +- driver = self.NPDrivers[nr] +- if driver.startswith ("gutenprint"): +- # This printer references some XML that is not +- # installed by default. Point the user at the +- # package they need to install. +- err = i18n("You will need to install the '%1' package " +- "in order to use this driver.", +- "gutenprint-foomatic") +- else: +- err = i18n("The '%1' driver cannot be " +- "used with printer '%2 %3'.", driver, self.NPMake, self.NPModel) +- elif self.rbtnNPPPD.isChecked(): +- # This error came from trying to open the PPD file. +- err_title = i18n('PPD error') +- filename = self.filechooserPPD.text() +- err = i18n('Failed to read PPD file. Possible reason ' +- 'follows:') + '\n' +- os.environ["PPD"] = filename +- # We want this to be in the current natural language, +- # so we intentionally don't set LC_ALL=C here. +- p = os.popen ('/usr/bin/cupstestppd -rvv "$PPD"', 'r') +- output = p.readlines () +- p.close () +- err += reduce (lambda x, y: x + y, output) +- else: +- # Failed to get PPD downloaded from OpenPrinting XXX +- err_title = i18n('Downloadable drivers') +- err_text = i18n("Support for downloadable " +- "drivers is not yet completed.") +- +- error_text = ('' + +- i18nc("Error title", "%1", err_title) + '\n\n' + err) +- QMessageBox.critical(self, err_title, error_text) +- return None +- +- if isinstance(ppd, str) or isinstance(ppd, unicode): +- try: +- if (ppd != "raw"): +- f = self.mainapp.cups.getServerPPD(ppd) +- ppd = cups.PPD(f) +- os.unlink(f) +- except AttributeError: +- nonfatalException() +- debugprint ("pycups function getServerPPD not available: never mind") +- except RuntimeError: +- nonfatalException() +- debugprint ("libcups from CUPS 1.3 not available: never mind") +- except cups.IPPError: +- nonfatalException() +- debugprint ("CUPS 1.3 server not available: never mind") +- +- return ppd +- +- # Create new Printer +- @pyqtSignature("") +- def on_btnNPApply_clicked(self): +- if self.dialog_mode in ("class", "printer"): +- name = unicode(self.entNPName.text()) +- location = unicode(self.entNPLocation.text()) +- info = unicode(self.entNPDescription.text()) +- else: +- name = self.mainapp.printer.name +- +- #replace any whitespace in printer name with underscore otherwise +- #CUPS throws an error +- name = name.replace(" ", "_") +- +- # Whether to check for missing drivers. +- check = False +- checkppd = None +- ppd = self.ppd +- +- if self.dialog_mode=="class": +- members = self.mainapp.getCurrentClassMembers(self.tvNCMembers) +- try: +- for member in members: +- self.passwd_retry = False # use cached Passwd +- self.mainapp.cups.addPrinterToClass(str(member), name) +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- return +- elif self.dialog_mode=="printer": +- self.device.uri = unicode(self.device.uri) +- uri = None +- if self.device.uri: +- uri = self.device.uri +- else: +- uri = self.getDeviceURI() +- if not self.ppd: # XXX needed? +- # Go back to previous page to re-select driver. +- self.nextNPTab(-1) +- return +- +- # write Installable Options to ppd +- for option in self.options.itervalues(): +- option.writeback() +- +- #self.busy(self) +- self.WaitWindow.setText(i18n('Adding') + '

' + +- i18n('Adding printer')) +- #self.WaitWindow.set_transient_for (self.NewPrinterWindow) +- self.WaitWindow.show () +- QApplication.processEvents() +- try: +- self.passwd_retry = False # use cached Passwd +- if isinstance(ppd, str) or isinstance(ppd, unicode): +- self.mainapp.cups.addPrinter(name, ppdname=ppd, +- device=uri, info=info, location=location) +- check = True +- elif ppd is None: # raw queue +- self.mainapp.cups.addPrinter(name, device=uri, +- info=info, location=location) +- else: +- cupshelpers.setPPDPageSize(ppd, self.language[0]) +- self.mainapp.cups.addPrinter(name, ppd=ppd, +- device=uri, info=info, location=location) +- check = True +- checkppd = ppd +- cupshelpers.activateNewPrinter (self.mainapp.cups, name) +- except cups.IPPError, (e, msg): +- #self.ready(self) +- self.WaitWindow.hide () +- self.show_IPP_Error(e, msg) +- return +- except: +- ##self.ready (self.NewPrinterWindow) +- self.WaitWindow.hide () +- fatalException (1) +- self.WaitWindow.hide () +- ##self.ready (self.NewPrinterWindow) +- #comment +- if self.dialog_mode in ("class", "printer"): +- try: +- self.passwd_retry = False # use cached Passwd +- self.mainapp.cups.setPrinterLocation(name, location) +- self.passwd_retry = False # use cached Passwd +- self.mainapp.cups.setPrinterInfo(name, info) +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- return +- elif self.dialog_mode == "device": +- try: +- uri = self.getDeviceURI() +- self.mainapp.cups.addPrinter(name, device=uri) +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- return +- elif self.dialog_mode == "ppd": +- if not ppd: +- ppd = self.ppd = self.getNPPPD() +- if not ppd: +- # Go back to previous page to re-select driver. +- self.nextNPTab(-1) +- return +- +- # set ppd on server and retrieve it +- # cups doesn't offer a way to just download a ppd ;(= +- raw = False +- if isinstance(ppd, str) or isinstance(ppd, unicode): +- if self.rbtnChangePPDasIs.isChecked(): +- # To use the PPD as-is we need to prevent CUPS copying +- # the old options over. Do this by setting it to a +- # raw queue (no PPD) first. +- try: +- self.mainapp.cups.addPrinter(name, ppdname='raw') +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- try: +- self.mainapp.cups.addPrinter(name, ppdname=ppd) +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- return +- +- try: +- filename = self.mainapp.cups.getPPD(name) +- ppd = cups.PPD(filename) +- os.unlink(filename) +- except cups.IPPError, (e, msg): +- if e == cups.IPP_NOT_FOUND: +- raw = True +- else: +- self.show_IPP_Error(e, msg) +- return +- else: +- # We have an actual PPD to upload, not just a name. +- if not self.rbtnChangePPDasIs.isChecked(): +- cupshelpers.copyPPDOptions(self.mainapp.ppd, ppd) # XXX +- else: +- # write Installable Options to ppd +- for option in self.options.itervalues(): +- option.writeback() +- cupshelpers.setPPDPageSize(ppd, self.language[0]) +- +- try: +- self.mainapp.cups.addPrinter(name, ppd=ppd) +- except cups.IPPError, (e, msg): +- self.show_IPP_Error(e, msg) +- +- if not raw: +- check = True +- checkppd = ppd +- +- self.accept() +- self.mainapp.populateList(start_printer=name) +- if check: +- try: +- self.checkDriverExists (name, ppd=checkppd) +- except: +- nonfatalException() +- +- # Also check to see whether the media option has become +- # invalid. This can happen if it had previously been +- # explicitly set to a page size that is not offered with +- # the new PPD (see bug #441836). +- """ +- try: +- option = self.mainapp.server_side_options['media'] +- if option.get_current_value () == None: +- debugprint ("Invalid media option: resetting") +- option.reset () +- self.mainapp.changed.add (option) +- self.mainapp.save_printer (self.mainapp.printer) +- except KeyError: +- pass +- except: +- print "exception in check to see whether the media option has become invalid" +- nonfatalException() +- """ +- +- def show_IPP_Error(self, exception, message): +- if exception == cups.IPP_NOT_AUTHORIZED: +- QMessageBox.critical(self, i18n('Not authorized'), i18n('The password may be incorrect.')) +- else: +- QMessageBox.critical(self, i18n('CUPS server error'), i18n("There was an error during the CUPS "\ +- "operation: '%1'.", message)) +- +- def checkDriverExists(self, name, ppd=None): +- """Check that the driver for an existing queue actually +- exists, and prompt to install the appropriate package +- if not. +- +- ppd: cups.PPD object, if already created""" +- +- # Is this queue on the local machine? If not, we can't check +- # anything at all. +- server = cups.getServer () +- if not (server == 'localhost' or server == '127.0.0.1' or +- server == '::1' or server[0] == '/'): +- return +- +- # Fetch the PPD if we haven't already. +- if not ppd: +- try: +- filename = self.mainapp.cups.getPPD(name) +- except cups.IPPError, (e, msg): +- if e == cups.IPP_NOT_FOUND: +- # This is a raw queue. Nothing to check. +- return +- else: +- self.show_IPP_Error(e, msg) +- return +- +- ppd = cups.PPD(filename) +- os.unlink(filename) +- +- (pkgs, exes) = cupshelpers.missingPackagesAndExecutables (ppd) +- if len (pkgs) > 0 or len (exes) > 0: +- # We didn't find a necessary executable. Complain. +- install = "/usr/bin/system-install-packages" +- if len (pkgs) > 0 and os.access (install, os.X_OK): +- pkg = pkgs[0] +- install_text = ('' + +- i18n('Install driver') + '\n\n' + +- i18n("Printer '%1' requires the %2 package but " +- "it is not currently installed.", name, pkg)) +- dialog = self.InstallDialog +- self.lblInstall.set_markup(install_text) +- else: +- error_text = ('' + +- i18n('Missing driver') + '\n\n' + +- i18n("Printer '%1' requires the '%2' program but " +- "it is not currently installed. Please " +- "install it before using this printer.", name, (exes + pkgs)[0])) +- QMessageBox.error(self, "", error_text) +- +- """ +- if pkg and response == gtk.RESPONSE_OK: +- # Install the package. +- def wait_child (sig, stack): +- (pid, status) = os.wait () +- +- signal.signal (signal.SIGCHLD, wait_child) +- pid = os.fork () +- if pid == 0: +- # Child. +- try: +- os.execv (install, [install, pkg]) +- except: +- pass +- sys.exit (1) +- elif pid == -1: +- pass # should handle error +- """ +- +- #FIXME obsolete? +- def on_entNPTIPPQueuename_textChanged(self, ent): +- self.update_IPP_URI_label () +- +- #FIXME obsolete? +- def on_IPPBrowseBox_currentTextChanged(self, text): +- self.update_IPP_URI_label() +- +- #FIXME not in gnome? +- @pyqtSignature("") +- def on_btnNPCancel_clicked(self): +- self.hide() +-#end of class NewPrinterGUI +- +-if __name__ == "__main__": +- """start the application""" +- +- appName = "system-config-printer-kde" +- catalogue = "system-config-printer-kde" +- programName = ki18n("System Config Printer KDE") +- version = "1.0" +- description = ki18n("Printer configuration tool") +- license = KAboutData.License_GPL +- copyright = ki18n("2007 Tim Waugh, Red Hat Inc, 2007-2008 Canonical Ltd") +- text = KLocalizedString() +- homePage = "https://launchpad.net/system-config-printer" +- bugEmail = "" +- +- aboutData = KAboutData (appName, catalogue, programName, version, description, +- license, copyright, text, homePage, bugEmail) +- +- aboutData.addAuthor(ki18n("Jonathan Riddell"), ki18n("Author")) +- aboutData.addAuthor(ki18n("Tim Waugh/Red Hat"), ki18n("System Config Printer Author")) +- +- options = KCmdLineOptions() +- +- KCmdLineArgs.init(sys.argv, aboutData) +- KCmdLineArgs.addCmdLineOptions(options) +- +- app = KApplication() +- args = KCmdLineArgs.parsedArgs() +- +- applet = GUI() +- sys.exit(app.exec_()) +diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer.ui kdeadmin-4.2.2/system-config-printer-kde/system-config-printer.ui +--- orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer.ui 2008-12-10 16:14:00.000000000 +0000 ++++ kdeadmin-4.2.2/system-config-printer-kde/system-config-printer.ui 2009-04-09 22:56:08.000000000 +0100 +@@ -1,179 +1,230 @@ +- ++ ++ + form +- +- ++ ++ + + 0 + 0 +- 878 +- 444 ++ 826 ++ 509 + + +- ++ + + ../../../../.designer/backup/printer-128.png../../../../.designer/backup/printer-128.png + +- +- +- +- +- ++ ++ ++ ++ ++ + 0 + 0 + + +- ++ + true + + +- ++ + + + + + +- +- +- ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ + 2 + +- +- +- +- +- +- Add New Printer +- +- +- +- +- +- +- New Local Printer +- +- +- +- +- +- +- New printer attached to this computer. +- +- +- +- +- +- +- New Network Printer +- +- +- +- +- +- +- New remote printer ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ + +- +- +- +- +- +- New Special Printer ++ ++ ++ 75 ++ true ++ + +- +- +- +- +- +- TextLabel +- +- +- +- +- +- +- New Printer Class ++ ++ Add New Printer + + + +- +- +- +- Add a new printer group. +- +- ++ ++ ++ ++ ++ ++ New Local Printer ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Add a new printer which is directly connected to your ++computer. ++ ++ ++ ++ ++ ++ ++ New Network Printer ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Add a new printer which is connected to your home ++network or on the Internet. ++ ++ ++ ++ ++ ++ ++ New Special Printer ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Add a new special printer such as a Fax or PDF by ++specifying an executable command. ++ ++ ++ ++ ++ ++ ++ New Printer Class ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Add a new printer class to specify a group of computers to ++print to. ++ ++ ++ ++ + +- +- +- ++ ++ ++ + Qt::Vertical + +- ++ + +- 20 +- 40 ++ 528 ++ 317 + + + + + + +- +- +- +- ++ ++ ++ ++ + +- +- ++ ++ + Basic Server Settings + + + + +- +- ++ ++ + + + + + +- +- ++ ++ + + + + + +- +- ++ ++ + + + + + + +- +- +- ++ ++ ++ + Show printers shared by other systems + + + +- +- +- ++ ++ ++ + Share published printers connected to this system + + + +- ++ + +- ++ + Qt::Horizontal + +- ++ + QSizePolicy::Fixed + +- ++ + + 16 + 24 +@@ -181,46 +232,46 @@ + + + +- +- +- +- ++ ++ ++ ++ + 0 + 0 + + +- ++ + Allow printing from the internet + + + +- +- +- ++ ++ ++ + Allow remote administration + + + +- +- +- ++ ++ ++ + Allow users to cancel any job (not just their own) + + + +- +- +- ++ ++ ++ + Save debugging information for troubleshooting + + + +- ++ + +- ++ + Qt::Vertical + +- ++ + + 505 + 131 +@@ -230,325 +281,1503 @@ + + + +- +- +- +- +- +- +- 1 +- 0 +- +- +- +- 0 +- +- +- +- Settings +- +- +- +- +- +- Description: +- +- +- +- +- +- +- +- +- +- Location: +- +- +- +- +- +- +- +- +- +- Device URI: +- +- +- +- +- +- +- +- +- +- Change +- +- +- +- +- +- +- Make and Model: +- +- +- +- +- +- +- - +- +- +- true +- +- +- +- +- +- +- Change +- +- +- +- +- +- +- Printer State: +- +- +- +- +- +- +- - +- +- +- +- +- +- +- Default Printer: +- +- +- +- +- +- +- - +- +- +- +- +- +- +- Make Default +- +- +- +- +- +- +- Remove Printer ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 75 ++ true ++ ++ ++ ++ My Printer + + + +- +- +- ++ ++ ++ + Qt::Horizontal + +- ++ + +- 432 ++ 468 + 20 + + + + +- +- +- +- Qt::Vertical +- +- +- +- 548 +- 84 +- +- +- +- +- +- +- +- Print Test Page +- +- +- +- +- +- +- Print Self-Test Page +- +- +- +- +- +- +- Clean Print Heads +- +- +- + +- +- +- +- Policies +- +- +- +- +- +- Enabled +- +- +- +- +- +- +- +- 0 +- 0 +- +- +- +- Not published +-See server settings +- +- +- +- +- +- +- Accepting Jobs +- +- +- +- +- +- +- Shared +- +- +- +- +- +- +- +- 0 +- 0 +- +- +- +- Error Policy +- +- +- +- +- +- +- +- +- +- +- 0 +- 0 +- +- +- +- Operation Policy +- +- +- +- +- +- +- +- +- +- +- 0 +- 0 +- +- +- +- Starting Banner +- +- +- +- +- +- +- +- +- +- +- 0 +- 0 +- +- +- +- Ending Banner +- +- +- +- +- +- +- +- +- +- Qt::Vertical +- +- +- +- 521 +- 20 +- +- +- +- +- +- +- ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ 0 ++ ++ ++ ++ Settings ++ ++ ++ ++ ++ ++ ++ 75 ++ true ++ ++ ++ ++ Printer Description ++ ++ ++ ++ ++ ++ ++ ++ ++ Printer Name: ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Location: ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Printer Description: ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Device Uri: ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ Make Default (Current Default is Foo at Bar) ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ ++ ++ ++ ++ 75 ++ true ++ ++ ++ ++ Driver Details ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Printer Model: ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ - ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Change... ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Printer State: ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ - ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ ++ ++ ++ ++ 75 ++ true ++ ++ ++ ++ Printer Status ++ ++ ++ ++ ++ ++ ++ ++ ++ enable ++ ++ ++ ++ ++ ++ ++ accepting ++ ++ ++ ++ ++ ++ ++ sharing ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Print Test Page ++ ++ ++ ++ ++ ++ ++ Print Self Test ++ ++ ++ ++ ++ ++ ++ Clean Print Heads ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 99 ++ 17 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Remove Printer ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 371 ++ 17 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Policies ++ ++ ++ ++ ++ ++ ++ 75 ++ true ++ ++ ++ ++ Banner Settings ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Starting Banner: ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 314 ++ 13 ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Ending Banner: ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 314 ++ 13 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ ++ ++ ++ ++ 75 ++ true ++ ++ ++ ++ User and Group Permissions ++ ++ ++ ++ ++ ++ ++ Allow printing for everyone except these users. ++ ++ ++ ++ ++ ++ ++ Deny printing for everyone except these users ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ true ++ ++ ++ ++ 1 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Add ++ ++ ++ ++ ++ ++ ++ Remove ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 354 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Members ++ ++ ++ ++ ++ ++ Add or Remove Members ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 125 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 358 ++ ++ ++ ++ ++ ++ ++ ++ ++ Options ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 531 ++ ++ ++ ++ ++ ++ ++ ++ ++ Job Options ++ ++ ++ ++ ++ ++ Qt::ScrollBarAlwaysOn ++ ++ ++ true ++ ++ ++ ++ ++ 0 ++ 0 ++ 509 ++ 1026 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Specify the default job options for this printer. Jobs ++arriving at this print server will have these options added ++if they are not already set by the application. ++ ++ ++ ++ ++ ++ ++ <b>Common Options</b> ++ ++ ++ ++ ++ ++ ++ ++ ++ Copies ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Orientation ++ ++ ++ ++ ++ ++ ++ ++ Portrait (no rotation) ++ ++ ++ ++ ++ Landscape (90°) ++ ++ ++ ++ ++ Reverse landscape (270°) ++ ++ ++ ++ ++ Reverse portrait (180°) ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Scale to fit ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Pages per slide ++ ++ ++ ++ ++ ++ ++ ++ 1 ++ ++ ++ ++ ++ 2 ++ ++ ++ ++ ++ 4 ++ ++ ++ ++ ++ 6 ++ ++ ++ ++ ++ 9 ++ ++ ++ ++ ++ 16 ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ ++ ++ Pages per side layout: ++ ++ ++ ++ ++ ++ ++ ++ Left to right, top to bottom ++ ++ ++ ++ ++ Left to right, bottom to top ++ ++ ++ ++ ++ Right to left, top to bottom ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Brightness: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ % ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Finishings: ++ ++ ++ ++ ++ ++ ++ ++ None ++ ++ ++ ++ ++ Staple ++ ++ ++ ++ ++ Punch ++ ++ ++ ++ ++ Cover ++ ++ ++ ++ ++ Bind ++ ++ ++ ++ ++ Saddle stitch ++ ++ ++ ++ ++ Edge stitch ++ ++ ++ ++ ++ Fold ++ ++ ++ ++ ++ Trim ++ ++ ++ ++ ++ Bale ++ ++ ++ ++ ++ Booklet maker ++ ++ ++ ++ ++ Job offset ++ ++ ++ ++ ++ Staple (top left) ++ ++ ++ ++ ++ Staple (bottom left) ++ ++ ++ ++ ++ Staple (top right) ++ ++ ++ ++ ++ Staple (bottom right) ++ ++ ++ ++ ++ Edge stitch (left) ++ ++ ++ ++ ++ Edge stitch (top) ++ ++ ++ ++ ++ Edge stitch (right) ++ ++ ++ ++ ++ Edge stitch (bottom) ++ ++ ++ ++ ++ Staple dual (left) ++ ++ ++ ++ ++ Staple dual (top) ++ ++ ++ ++ ++ Staple dual (right) ++ ++ ++ ++ ++ Staple dual (bottom) ++ ++ ++ ++ ++ Bind (left) ++ ++ ++ ++ ++ Bind (top) ++ ++ ++ ++ ++ Bind (right) ++ ++ ++ ++ ++ Bind (bottom) ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Job priority: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Media: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Sides: ++ ++ ++ ++ ++ ++ ++ ++ One-sided ++ ++ ++ ++ ++ Two-sided (long edge) ++ ++ ++ ++ ++ Two-sided (short edge) ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Hold until: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <b>Image Options</b> ++ ++ ++ ++ ++ ++ ++ ++ ++ Mirror ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Scaling ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ % ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ ++ ++ Saturation ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ % ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Hue adjustment ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ° ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Gamme ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 97 ++ 94 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <b>Text Options</b> ++ ++ ++ ++ ++ ++ ++ ++ ++ Character per inch: ++ ++ ++ Qt::PlainText ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Lines per inch ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Left margin ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Points ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Right margin ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Points ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Top margin ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Points ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Bottom margin ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Points ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ ++ ++ Pretty print ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Word wrap ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ Columns ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ To add a new option, enter its name in the box below and click to add. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Add ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 119 ++ 1018 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +- +- +- +- +- +- +- +- +- +- +- +- +- +- Apply +- +- +- +- +- +- +- Revert +- ++ + + + + ++ ++ ++ KComboBox ++ QComboBox ++
kcombobox.h
++
++ ++ KLineEdit ++ QLineEdit ++
klineedit.h
++
++ ++ KPushButton ++ QPushButton ++
kpushbutton.h
++
++
+ + +
--- kdeadmin-4.2.98.orig/debian/patches/kubuntu_01_use_sudo.diff +++ kdeadmin-4.2.98/debian/patches/kubuntu_01_use_sudo.diff @@ -0,0 +1,13 @@ +Index: kdeadmin-4.2.0/kpackage/kpackageSettings.kcfg +=================================================================== +--- kdeadmin-4.2.0.orig/kpackage/kpackageSettings.kcfg 2008-01-04 18:58:33.000000000 -0500 ++++ kdeadmin-4.2.0/kpackage/kpackageSettings.kcfg 2009-01-22 15:48:04.000000000 -0500 +@@ -11,7 +11,7 @@ + + + +- su ++ sudo + + + --- kdeadmin-4.2.98.orig/debian/patches/series +++ kdeadmin-4.2.98/debian/patches/series @@ -0,0 +1 @@ +kubuntu_01_use_sudo.diff