1
diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/CMakeLists.txt kdeadmin-4.2.2/system-config-printer-kde/CMakeLists.txt
2
--- orig/kdeadmin-4.2.2/system-config-printer-kde/CMakeLists.txt 2009-01-01 16:27:18.000000000 +0000
3
+++ kdeadmin-4.2.2/system-config-printer-kde/CMakeLists.txt 2009-04-09 22:56:36.000000000 +0100
5
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules )
6
+find_package( KDE4 REQUIRED )
8
-MACRO(PYKDE4_ADD_EXECUTABLE _pyname _exename)
9
- 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)" )
10
-ENDMACRO(PYKDE4_ADD_EXECUTABLE)
11
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules )
13
macro_optional_find_package(PythonLibrary)
14
macro_optional_find_package(SIP)
16
macro_optional_find_package(PyQt4)
18
- 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)
19
+ 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)
20
ENDIF(NOT PYQT4_FOUND)
22
macro_optional_find_package(PyKDE)
26
system-config-printer.ui
27
- system-config-printer-kde.py
31
+ ipp-browse-dialog.ui
32
+ smb-browse-dialog.ui
33
DESTINATION ${DATA_INSTALL_DIR}/system-config-printer-kde )
34
- PYKDE4_ADD_EXECUTABLE(system-config-printer-kde.py system-config-printer-kde)
35
- install(FILES system-config-printer-kde.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
36
+ install(FILES kcm-scpk.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
37
ENDIF(INSTALL_SYSTEM_CONFIG_PRINTER)
39
macro_display_feature_log()
40
diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/COMMENTS kdeadmin-4.2.2/system-config-printer-kde/COMMENTS
41
--- orig/kdeadmin-4.2.2/system-config-printer-kde/COMMENTS 1970-01-01 01:00:00.000000000 +0100
42
+++ kdeadmin-4.2.2/system-config-printer-kde/COMMENTS 2009-04-09 22:56:08.000000000 +0100
44
+01:37 <seele> the menu/list on the left looks like a tree, will it eventually become a list like the other modules? icon and all?
45
+01:38 <seele> under configured printers, options and job options tabs, widgets dont have correct alignment
46
+01:38 <seele> job options is pretty scary looking too, we'll probably need to work on that
47
+01:38 <seele> i assume advanced is wip
48
+01:39 <seele> 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
49
+ someone else if not you)
50
+01:39 <seele> also.. remove should be disabled until you select a list item
51
+01:41 <seele> under settings, it takes a number of seconds for the change driver wizard to load after clicking the button. will this be improved eventually?
52
+01:41 <seele> 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)
53
+01:43 <seele> 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
54
+ know where else remove printer could go
55
+01:45 <seele> 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
56
+ server configuration and if those options are sufficient and presented in the best way
57
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
58
--- orig/kdeadmin-4.2.2/system-config-printer-kde/ipp-browse-dialog.ui 1970-01-01 01:00:00.000000000 +0100
59
+++ kdeadmin-4.2.2/system-config-printer-kde/ipp-browse-dialog.ui 2009-04-09 22:56:08.000000000 +0100
62
+ <class>IPPBrowseDialog</class>
63
+ <widget class="QDialog" name="IPPBrowseDialog" >
64
+ <property name="windowModality" >
65
+ <enum>Qt::NonModal</enum>
67
+ <property name="geometry" >
72
+ <height>300</height>
75
+ <property name="font" >
81
+ <property name="focusPolicy" >
82
+ <enum>Qt::StrongFocus</enum>
84
+ <property name="windowTitle" >
85
+ <string>IPP Browser</string>
87
+ <property name="modal" >
90
+ <widget class="QWidget" name="layoutWidget" >
91
+ <property name="geometry" >
99
+ <layout class="QHBoxLayout" name="horizontalLayout" >
101
+ <widget class="KPushButton" name="btnIPPBrowseRefresh" >
102
+ <property name="text" >
103
+ <string>Refresh</string>
108
+ <spacer name="horizontalSpacer" >
109
+ <property name="orientation" >
110
+ <enum>Qt::Horizontal</enum>
112
+ <property name="sizeHint" stdset="0" >
115
+ <height>20</height>
121
+ <widget class="KPushButton" name="btnIPPBrowseOk" >
122
+ <property name="text" >
123
+ <string>Ok</string>
125
+ <property name="shortcut" >
126
+ <string>Ctrl+O</string>
131
+ <widget class="KPushButton" name="btnIPPBrowseCancel" >
132
+ <property name="text" >
133
+ <string>Cancel</string>
139
+ <widget class="QTreeWidget" name="twIPPBrowser" >
140
+ <property name="geometry" >
145
+ <height>221</height>
148
+ <property name="sizePolicy" >
149
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
150
+ <horstretch>0</horstretch>
151
+ <verstretch>0</verstretch>
154
+ <property name="sortingEnabled" >
157
+ <property name="allColumnsShowFocus" >
160
+ <property name="columnCount" >
164
+ <property name="text" >
169
+ <property name="text" >
177
+ <class>KPushButton</class>
178
+ <extends>QPushButton</extends>
179
+ <header>kpushbutton.h</header>
185
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
186
--- orig/kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.desktop 1970-01-01 01:00:00.000000000 +0100
187
+++ kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.desktop 2009-04-09 22:56:08.000000000 +0100
190
+Exec=kcmshell4 kcm-scpk
193
+X-KDE-ServiceTypes=KCModule
194
+X-DocPath=kcontrol/colors/index.html
196
+X-KDE-Library=kpythonpluginfactory
197
+X-KDE-ParentApp=kcontrol
198
+X-KDE-PluginKeyword=system-config-printer-kde/kcm-scpk.py
200
+X-KDE-System-Settings-Parent-Category=system
203
+Name=Printer Configuration
205
+Comment=Configure local and remote Printers
207
+X-KDE-Keywords=python kcm
209
+Categories=Qt;KDE;System;
210
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
211
--- orig/kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.py 1970-01-01 01:00:00.000000000 +0100
212
+++ kdeadmin-4.2.2/system-config-printer-kde/kcm-scpk.py 2009-04-09 22:56:08.000000000 +0100
214
+#!/usr/bin/env python
215
+# -*- coding: utf-8 -*-
217
+#############################################################################
219
+## Copyright 2007-2009 Canonical Ltd
220
+## Copyright 2008-2009 Richard Birnie <arbyuk@googlemail.com>
221
+## Author: Jonathan Riddell <jriddell@ubuntu.com>
222
+## Richard Birnie <arbyuk@googlemail.com>
224
+## Includes code from System Config Printer:
225
+## Copyright (C) 2006, 2007, 2008 Red Hat, Inc.
226
+## Copyright (C) 2006, 2007 Florian Festi <ffesti@redhat.com>
227
+## Copyright (C) 2006, 2007, 2008 Tim Waugh <twaugh@redhat.com>
229
+## This program is free software; you can redistribute it and/or
230
+## modify it under the terms of the GNU General Public License as
231
+## published by the Free Software Foundation; either version 2 of
232
+## the License, or (at your option) any later version.
234
+## This program is distributed in the hope that it will be useful,
235
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
236
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
237
+## GNU General Public License for more details.
239
+## You should have received a copy of the GNU General Public License
240
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
242
+#############################################################################
244
+MIN_REFRESH_INTERVAL = 1 # seconds
247
+import sys, os, time, traceback, re, tempfile, httplib, thread
249
+#load modules from system-config-printer-common (debug, smburi), change path here if you have it installed elsewhere
250
+SYSTEM_CONFIG_PRINTER_DIR = "/usr/share/system-config-printer"
251
+if os.path.exists(SYSTEM_CONFIG_PRINTER_DIR + "/debug.py"):
252
+ sys.path.append(SYSTEM_CONFIG_PRINTER_DIR)
254
+from PyQt4.QtCore import *
255
+from PyQt4.QtGui import *
256
+from PyQt4 import uic
258
+from PyKDE4.kdecore import *
259
+from PyKDE4.kdeui import *
260
+from PyKDE4.kio import *
262
+#use _() to keep code the same as gnome system-config-printer
264
+ return unicode(i18n(string), "utf-8")
266
+def translate(self, prop):
267
+ """reimplement method from uic to change it to use gettext"""
268
+ if prop.get("notr", None) == "true":
269
+ return self._cstring(prop)
271
+ if prop.text is None:
273
+ text = prop.text.encode("UTF-8")
276
+uic.properties.Properties._string = translate
279
+cups.require ("1.9.27")
281
+# These come from system-config-printer
283
+import cupshelpers, options
284
+from optionwidgets import OptionWidget
285
+from smburi import SMBURI
289
+import dbus.mainloop.qt
293
+ellipsis = unichr(0x2026)
296
+ try_CUPS_SERVER_REMOTE_ANY = cups.CUPS_SERVER_REMOTE_ANY
297
+except AttributeError:
298
+ # cups module was compiled with CUPS < 1.3
299
+ try_CUPS_SERVER_REMOTE_ANY = "_remote_any"
301
+def validDeviceURI (uri):
302
+ """Returns True is the provided URI is valid."""
303
+ if uri.find (":/") > 0:
307
+if os.path.exists("system-config-printer.ui"):
308
+ APPDIR = QDir.currentPath()
310
+ file = KStandardDirs.locate("data", "system-config-printer-kde/system-config-printer.ui")
311
+ APPDIR = file.left(file.lastIndexOf("/"))
313
+class PyKcm(KCModule):
314
+ def __init__(self, component_data, parent, gui):
315
+ KCModule.__init__(self, component_data, parent)
317
+ uic.loadUi(APPDIR + "/" + "system-config-printer.ui", self)
318
+ self.setButtons(KCModule.Apply)
321
+ def changed(self, state):
322
+ """a setting has changed, activate the Apply button"""
323
+ self.emit(SIGNAL("changed(bool)"), state)
326
+ self.gui.on_btnPrinterPropertiesApply_clicked()
329
+ self.gui.on_btnRevert_clicked()
332
+ """our main class is the main window"""
334
+ printer_states = { cups.IPP_PRINTER_IDLE: i18nc("Printer state", "Idle"),
335
+ cups.IPP_PRINTER_PROCESSING: i18nc("Printer state", "Processing"),
336
+ cups.IPP_PRINTER_BUSY: i18nc("Printer state", "Busy"),
337
+ cups.IPP_PRINTER_STOPPED: i18nc("Printer state", "Stopped") }
340
+ def makeui(self, component_data, parent):
341
+ self.ui = PyKcm(component_data, parent, self)
342
+ start_printer = None
346
+ self.language = locale.getlocale(locale.LC_MESSAGES)
347
+ self.encoding = locale.getlocale(locale.LC_CTYPE)
349
+ nonfatalException()
350
+ os.environ['LC_ALL'] = 'C'
351
+ locale.setlocale (locale.LC_ALL, "")
352
+ self.language = locale.getlocale(locale.LC_MESSAGES)
353
+ self.encoding = locale.getlocale(locale.LC_CTYPE)
355
+ self.printer = None
356
+ self.conflicts = set() # of options
357
+ self.connect_server = (self.printer and self.printer.getServer()) \
358
+ or cups.getServer()
359
+ self.connect_user = cups.getUser()
360
+ self.password = '' #FIXME not in Gnome version
361
+ self.passwd_retry = False #FIXME not in Gnome version
362
+ self.widget_data_setting = {} #FIXME not in Gnome version
363
+ #FIXMEcups.setPasswordCB(self.cupsPasswdCallback)
364
+ ##self.server_is_publishing = False #FIXME new in Gnome version
366
+ self.changed = set() # of options
368
+ self.servers = set((self.connect_server,))
371
+ self.cups = cups.Connection()
372
+ except RuntimeError:
375
+ # New Printer Dialog
376
+ self.newPrinterGUI = np = NewPrinterGUI(self)
378
+ self.setConnected()
380
+ self.ui.connect(self.ui.mainlist, SIGNAL("itemSelectionChanged()"), self.on_tvMainList_cursor_changed)
381
+ self.ui.connect(self.ui.mainlist, SIGNAL("currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)"), self.on_tvMainList_changed)
382
+ self.ui.connect(self.ui.chkServerBrowse, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
383
+ self.ui.connect(self.ui.chkServerShare, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
384
+ self.ui.connect(self.ui.chkServerShareAny, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
385
+ self.ui.connect(self.ui.chkServerRemoteAdmin, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
386
+ self.ui.connect(self.ui.chkServerAllowCancelAll, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
387
+ self.ui.connect(self.ui.chkServerLogDebug, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
389
+ self.ui.connect(self.ui.btnChangePPD, SIGNAL("clicked()"), self.on_btnChangePPD_clicked)
390
+ self.ui.connect(self.ui.btnNewClass, SIGNAL("clicked()"), self.on_new_class_activate)
391
+ self.ui.connect(self.ui.btnNewPrinterNetwork, SIGNAL("clicked()"), self.on_new_printer_activate)
392
+ self.ui.connect(self.ui.btnPrintTestPage, SIGNAL("clicked()"), self.on_btnPrintTestPage_clicked)
393
+ self.ui.connect(self.ui.btnSelfTest, SIGNAL("clicked()"), self.on_btnSelfTest_clicked)
394
+ self.ui.connect(self.ui.btnCleanHeads, SIGNAL("clicked()"), self.on_btnCleanHeads_clicked)
396
+ self.ui.connect(self.ui.btnNewJobOption, SIGNAL("clicked()"), self.on_btnNewJobOption_clicked)
397
+ self.ui.connect(self.ui.entNewJobOption, SIGNAL("textChanged(QString)"), self.on_entNewJobOption_changed)
399
+ self.ui.connect(self.ui.entPDescription, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
400
+ self.ui.connect(self.ui.entPLocation, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
401
+ self.ui.connect(self.ui.chkPMakeDefault, SIGNAL("stateChanged(int)"), self.chkPMakeDefault_stateChanged)
402
+ self.ui.connect(self.ui.btnDelete, SIGNAL("clicked()"), self.btnDelete_clicked)
403
+ self.ui.connect(self.ui.entPDevice, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
404
+ self.ui.connect(self.ui.chkPEnabled, SIGNAL("stateChanged(int)"),self.on_printer_changed)
405
+ self.ui.connect(self.ui.chkPAccepting, SIGNAL("stateChanged(int)"), self.on_printer_changed)
406
+ self.ui.connect(self.ui.chkPShared, SIGNAL("stateChanged(int)"), self.on_printer_changed)
407
+ self.ui.connect(self.ui.cmbPStartBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
408
+ self.ui.connect(self.ui.cmbPEndBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
409
+ self.ui.connect(self.ui.rbtnPAllow, SIGNAL("toggled(bool)"), self.on_printer_changed)
410
+ self.ui.connect(self.ui.btnPAddUser, SIGNAL("clicked()"), self.btnPAddUser_clicked)
411
+ self.ui.connect(self.ui.btnPDelUser, SIGNAL("clicked()"), self.btnPDelUser_clicked)
413
+ self.ui.connect(self.ui.btnClassAddMember, SIGNAL("clicked()"), self.on_btnClassAddMember_clicked)
414
+ self.ui.connect(self.ui.btnClassDelMember, SIGNAL("clicked()"), self.on_btnClassDelMember_clicked)
416
+ self.ui.mainlist.header().hide()
418
+ self.policiesTabWidget = self.ui.ntbkPrinter.widget(1)
419
+ self.memberTabWidget = self.ui.ntbkPrinter.widget(2)
420
+ self.optionsTabWidget = self.ui.ntbkPrinter.widget(3)
422
+ self.ui.btnClassAddMember.setIcon(KIcon("arrow-left"))
423
+ self.ui.btnClassDelMember.setIcon(KIcon("arrow-right"))
424
+ self.mainListSelectedName = None
425
+ self.mainListSelectedType = None
427
+ # Job Options widgets.
428
+ opts = [ options.OptionAlwaysShown ("copies", int, 1,
429
+ self.ui.sbJOCopies,
430
+ self.ui.btnJOResetCopies),
431
+ options.OptionAlwaysShownSpecial \
432
+ ("orientation-requested", int, 3,
433
+ self.ui.cmbJOOrientationRequested,
434
+ self.ui.btnJOResetOrientationRequested,
435
+ combobox_map = [3, 4, 5, 6],
436
+ special_choice=_("Automatic rotation")),
438
+ options.OptionAlwaysShown ("fitplot", bool, False,
439
+ self.ui.cbJOFitplot,
440
+ self.ui.btnJOResetFitplot),
442
+ options.OptionAlwaysShown ("number-up", int, 1,
443
+ self.ui.cmbJONumberUp,
444
+ self.ui.btnJOResetNumberUp,
445
+ combobox_map=[1, 2, 4, 6, 9, 16]),
447
+ options.OptionAlwaysShown ("number-up-layout", str, "lrtb",
448
+ self.ui.cmbJONumberUpLayout,
449
+ self.ui.btnJOResetNumberUpLayout,
450
+ combobox_map = [ "lrtb",
459
+ options.OptionAlwaysShown ("brightness", int, 100,
460
+ self.ui.sbJOBrightness,
461
+ self.ui.btnJOResetBrightness),
463
+ options.OptionAlwaysShown ("finishings", int, 3,
464
+ self.ui.cmbJOFinishings,
465
+ self.ui.btnJOResetFinishings,
466
+ combobox_map = [ 3, 4, 5, 6,
473
+ use_supported = True),
475
+ options.OptionAlwaysShown ("job-priority", int, 50,
476
+ self.ui.sbJOJobPriority,
477
+ self.ui.btnJOResetJobPriority),
479
+ options.OptionAlwaysShown ("media", str,
480
+ "A4", # This is the default for
481
+ # when media-default is
482
+ # not supplied by the IPP
483
+ # server. Fortunately it
484
+ # is a mandatory attribute.
485
+ self.ui.cmbJOMedia,
486
+ self.ui.btnJOResetMedia,
487
+ use_supported = True),
489
+ options.OptionAlwaysShown ("sides", str, "one-sided",
490
+ self.ui.cmbJOSides,
491
+ self.ui.btnJOResetSides,
494
+ "two-sided-long-edge",
495
+ "two-sided-short-edge" ]),
497
+ options.OptionAlwaysShown ("job-hold-until", str,
499
+ self.ui.cmbJOHoldUntil,
500
+ self.ui.btnJOResetHoldUntil,
501
+ use_supported = True),
503
+ options.OptionAlwaysShown ("mirror", bool, False,
504
+ self.ui.cbJOMirror,
505
+ self.ui.btnJOResetMirror),
507
+ options.OptionAlwaysShown ("scaling", int, 100,
508
+ self.ui.sbJOScaling,
509
+ self.ui.btnJOResetScaling),
512
+ options.OptionAlwaysShown ("saturation", int, 100,
513
+ self.ui.sbJOSaturation,
514
+ self.ui.btnJOResetSaturation),
516
+ options.OptionAlwaysShown ("hue", int, 0,
518
+ self.ui.btnJOResetHue),
520
+ options.OptionAlwaysShown ("gamma", int, 1000,
522
+ self.ui.btnJOResetGamma),
524
+ options.OptionAlwaysShown ("cpi", float, 10.0,
525
+ self.ui.sbJOCpi, self.ui.btnJOResetCpi),
527
+ options.OptionAlwaysShown ("lpi", float, 6.0,
528
+ self.ui.sbJOLpi, self.ui.btnJOResetLpi),
530
+ options.OptionAlwaysShown ("page-left", int, 18,
531
+ self.ui.sbJOPageLeft,
532
+ self.ui.btnJOResetPageLeft),
534
+ options.OptionAlwaysShown ("page-right", int, 18,
535
+ self.ui.sbJOPageRight,
536
+ self.ui.btnJOResetPageRight),
538
+ options.OptionAlwaysShown ("page-top", int, 36,
539
+ self.ui.sbJOPageTop,
540
+ self.ui.btnJOResetPageTop),
542
+ options.OptionAlwaysShown ("page-bottom", int, 36,
543
+ self.ui.sbJOPageBottom,
544
+ self.ui.btnJOResetPageBottom),
546
+ options.OptionAlwaysShown ("prettyprint", bool, False,
547
+ self.ui.cbJOPrettyPrint,
548
+ self.ui.btnJOResetPrettyPrint),
550
+ options.OptionAlwaysShown ("wrap", bool, False, self.ui.cbJOWrap,
551
+ self.ui.btnJOResetWrap),
553
+ options.OptionAlwaysShown ("columns", int, 1,
554
+ self.ui.sbJOColumns,
555
+ self.ui.btnJOResetColumns),
557
+ self.job_options_widgets = {}
558
+ self.job_options_buttons = {}
559
+ for option in opts:
560
+ self.job_options_widgets[option.widget] = option
561
+ self.job_options_buttons[option.button] = option
562
+ self.connect(option.button, SIGNAL("clicked()"), self.on_job_option_reset)
563
+ if type(option.widget) == QSpinBox:
564
+ self.connect(option.widget, SIGNAL("valueChanged(int)"), self.on_job_option_changed)
565
+ elif type(option.widget) == QComboBox:
566
+ self.connect(option.widget, SIGNAL("currentIndexChanged(int)"), self.on_job_option_changed)
567
+ elif type(option.widget) == QCheckBox:
568
+ self.connect(option.widget, SIGNAL("stateChanged(int)"), self.on_job_option_changed)
573
+ self.populateList(start_printer, change_ppd)
574
+ except cups.HTTPError, (s,):
576
+ self.setConnected()
577
+ self.populateList()
578
+ self.show_HTTP_Error(s)
580
+ #hide some bits until implemented
581
+ self.ui.btnNewPrinter.hide()
582
+ self.ui.newPrinterLabel.hide()
583
+ self.ui.btnNewPrinterSpecial.hide()
584
+ self.ui.newPrinterSpecialLabel.hide()
585
+ self.ui.entPName.hide()
586
+ self.ui.lblPName.hide()
588
+ #catch the currentItemChanged signal. This should stop the
589
+ # 'Do you want to save settings' pop-up at startup
590
+ self.ui.mainlist.blockSignals(True)
591
+ self.ui.mainlist.setCurrentItem(self.settingsItem)
592
+ self.ui.mainlist.blockSignals(False) #unblock the signal
594
+ #FIXME hide labels until implemented
595
+ self.ui.lblPOptions.hide()
596
+ self.ui.lblPInstallOptions.hide()
600
+ # now called dests_iconview_item_activated() in the Gnome version
601
+ def on_tvMainList_cursor_changed(self):
603
+ # The unapplied changes for this item have not been saved,
604
+ # and the user just pressed "Cancel".
605
+ #FIXME, should offer dialog prompting to save or cancel here
607
+ items = self.ui.mainlist.selectedItems()
613
+ #FIXME only show settings until ready for the rest
614
+ #item = self.settingsItem
615
+ type = unicode(item.text(1))
616
+ name = unicode(item.text(0))
618
+ #name, type = self.getSelectedItem()
619
+ #model, self.mainListSelected = self.tvMainList.get_selection().get_selected()
620
+ #Save the values incase it gets deselected
621
+ self.mainListSelectedType = type
622
+ self.mainListSelectedName = name
623
+ item_selected = True
625
+ self.ui.ntbkMain.setCurrentIndex(0)
626
+ elif type == "Settings":
627
+ self.ui.ntbkMain.setCurrentIndex(1)
629
+ self.fillServerTab()
631
+ # No connection to CUPS. Make sure the Apply/Revert buttons
632
+ # are not sensitive.
633
+ self.setDataButtonState()
634
+ item_selected = False
635
+ elif type in ['Printer', 'Class']:
637
+ self.fillPrinterTab(name)
638
+ # the below not needed, fillPrinterTab() already calls fillPrinterOptions()
639
+ ##self.fillPrinterOptions("foo", True) #FIXME parameters need fixing
640
+ self.setDataButtonState()
641
+ self.ui.ntbkPrinter.setCurrentIndex(0)
642
+ except RuntimeError:
643
+ # Perhaps cupsGetPPD2 failed for a browsed printer.
644
+ self.ui.ntbkMain.setCurrentIndex(3)
647
+ self.ui.printerNameLabel.setText(name)
648
+ self.ui.ntbkMain.setCurrentIndex(2)
649
+ elif type == "None":
650
+ self.ui.ntbkMain.setCurrentIndex(3)
651
+ self.setDataButtonState()
652
+ item_selected = False
654
+ """FIXME, copy button
655
+ is_local = item_selected and not self.printers[name].discovered
656
+ for widget in [self.copy, self.btnCopy]:
657
+ widget.set_sensitive(item_selected)
658
+ for widget in [self.delete, self.btnDelete]:
659
+ widget.set_sensitive(is_local)
662
+ def printer_properties_response(self):
663
+ name, type = self.getSelectedItem()
664
+ if type in ("Printer", "Class"):
665
+ return self.save_printer(self.printer)
666
+ elif type == "Settings":
667
+ return self.save_serversettings()
670
+ def on_tvMainList_changed(self, new, old):
671
+ """about to change, offer to save"""
673
+ answer = KMessageBox.questionYesNo(self, "Do you want to save changes?", "Save Changes", KStandardGuiItem.save(), KStandardGuiItem.discard() )
675
+ if answer == KMessageBox.Yes: #save is equivalent to yes
676
+ self.printer_properties_response()
677
+ elif answer == KMessageBox.No: #discard is equivalent to no
678
+ self.changed = set() # avoid asking the user
680
+ def busy (self, win = None):
684
+ win.setCursor(Qt.WaitCursor)
685
+ KApplication.processEvents()
687
+ nonfatalException ()
689
+ def ready (self, win = None):
693
+ win.setCursor(Qt.ArrowCursor)
694
+ KApplication.processEvents()
696
+ nonfatalException ()
698
+ def setConnected(self):
699
+ connected = bool(self.cups)
701
+ host = cups.getServer()
705
+ self.setWindowTitle(i18n("Printer configuration - %1", host))
708
+ status_msg = i18n("Connected to %1", host)
710
+ status_msg = i18n("Not connected")
711
+ #FIXME do we want a statusbar?
712
+ #self.statusbarMain.push(self.status_context_id, status_msg)
714
+ for widget in (#FIXMEself.btnNewPrinter, self.btnNewClass,
715
+ #self.new_printer, self.new_class,
716
+ self.ui.chkServerBrowse, self.ui.chkServerShare,
717
+ self.ui.chkServerRemoteAdmin,
718
+ self.ui.chkServerAllowCancelAll,
719
+ self.ui.chkServerLogDebug):
720
+ widget.setEnabled(connected)
722
+ sharing = self.ui.chkServerShare.isChecked ()
723
+ self.ui.chkServerShareAny.setEnabled (sharing)
726
+ del self.server_settings
730
+ def populateList(self, start_printer = None, change_ppd = False):
731
+ old_name, old_type = self.getSelectedItem()
732
+ if self.ui.ntbkMain.currentIndex() == 1:
733
+ serverPageShowing = True
735
+ serverPageShowing = False
742
+ self.printers = cupshelpers.getPrinters(self.cups)
744
+ # Get default printer.
746
+ self.default_printer = self.cups.getDefault ()
747
+ except AttributeError: # getDefault appeared in pycups-1.9.31
748
+ # This fetches the list of printers and classes *again*,
749
+ # just to find out the default printer.
750
+ dests = self.cups.getDests ()
751
+ if dests.has_key ((None,None)):
752
+ self.default_printer = dests[(None,None)].name
754
+ self.default_printer = None
755
+ except cups.IPPError, (e, m):
756
+ self.show_IPP_Error(e, m)
758
+ self.default_printer = None
761
+ self.default_printer = None
763
+ local_printers = []
765
+ remote_printers = []
766
+ remote_classes = []
768
+ for name, printer in self.printers.iteritems():
769
+ if printer.default:
770
+ self.default_printer = name
771
+ self.servers.add(printer.getServer())
774
+ if printer.is_class: remote_classes.append(name)
775
+ else: remote_printers.append(name)
777
+ if printer.is_class: local_classes.append(name)
778
+ else: local_printers.append(name)
780
+ local_printers.sort()
781
+ local_classes.sort()
782
+ remote_printers.sort()
783
+ remote_classes.sort()
785
+ if (old_name != "" and
786
+ (not old_name in local_printers) and
787
+ (not old_name in local_classes) and
788
+ (not old_name in remote_printers) and
789
+ (not old_name in remote_classes)):
790
+ # The previously selected printer no longer exists.
793
+ if (self.default_printer != None and
794
+ start_printer == None and
796
+ start_printer = self.default_printer
798
+ if not start_printer:
799
+ start_printer = old_name
802
+ "_printers" : True,
804
+ "_remote_printers" : True,
805
+ "_remote_classes" : True,
809
+ # remove old printers/classes
810
+ iter = self.mainlist.get_iter_first()
811
+ iter = self.mainlist.iter_next(iter) # step over server settings
813
+ entry = self.mainlist.get_value(iter, 1)
814
+ path = self.mainlist.get_path(iter)
815
+ expanded[entry] = self.tvMainList.row_expanded(path)
816
+ more_entries = self.mainlist.remove(iter)
817
+ if not more_entries: break
819
+ self.ui.mainlist.clear()
820
+ QTreeWidgetItem(self.ui.mainlist, ["New Printer", 'New'])
821
+ self.settingsItem = QTreeWidgetItem(self.ui.mainlist, ["Server Settings", 'Settings'])
822
+ if serverPageShowing:
823
+ self.settingsItem.setSelected(True)
826
+ for printers, text, name in (
827
+ (local_printers, i18n("Local Printers"), "_printers"),
828
+ (local_classes, i18n("Local Classes"), "_classes"),
829
+ (remote_printers, i18n("Remote Printers"), "_remote_printers"),
830
+ (remote_classes, i18n("Remote Classes"), "_remote_classes")):
831
+ if not printers: continue
833
+ #self.mainlist.addTopLevelItem(QTreeWidgetItem(self.mainlist, text))
834
+ rootTreeItem = QTreeWidgetItem(self.ui.mainlist, [text, name])
835
+ #iter = self.mainlist.append(None, (text, name))
836
+ #path = self.mainlist.get_path(iter)
838
+ for printer_name in printers:
839
+ if start_printer == None:
840
+ start_printer = printer_name
841
+ treeItem = QTreeWidgetItem(rootTreeItem, [printer_name, "Printer"])
842
+ #p_iter = self.mainlist.append(iter, (printer_name, "Printer"))
843
+ if printer_name==start_printer and not serverPageShowing:
844
+ treeItem.setSelected(True)
845
+ expanded[name] = True
847
+ rootTreeItem.setExpanded(True)
848
+ #self.tvMainList.expand_row(path, False)
849
+ self.on_tvMainList_cursor_changed()
850
+ self.setDataButtonState()
854
+ self.on_btnChangePPD_clicked (self.btnChangePPD)
858
+ # Connect to Server
860
+ def on_printer_changed(self, text):
861
+ widget = self.sender()
862
+ if not widget: #method called as a method not a slot
864
+ if isinstance(widget, QCheckBox):
865
+ value = widget.isChecked()
866
+ elif isinstance(widget, QLineEdit): #this should be a KLineEdit but causes errors
867
+ value = unicode(widget.text())
868
+ elif isinstance(widget, QRadioButton):
869
+ value = widget.isChecked()
870
+ elif isinstance(widget, QComboBox): #KCombobox causes errors
871
+ value = unicode(widget.currentText())
873
+ raise ValueError, "Widget type not supported (yet)"
877
+ self.ui.entPDescription : p.info,
878
+ self.ui.entPLocation : p.location,
879
+ self.ui.entPDevice : p.device_uri,
880
+ self.ui.chkPEnabled : p.enabled,
881
+ self.ui.chkPAccepting : not p.rejecting,
882
+ self.ui.chkPShared : p.is_shared,
883
+ self.ui.cmbPStartBanner : p.job_sheet_start,
884
+ self.ui.cmbPEndBanner : p.job_sheet_end,
885
+ self.ui.rbtnPAllow: p.default_allow
886
+ #FIXME Not implemented in the current UI
887
+ #self.cmbPErrorPolicy : p.error_policy,
888
+ #self.cmbPOperationPolicy : p.op_policy,
891
+ old_value = old_values[widget]
893
+ if old_value == value:
894
+ self.changed.discard(widget)
896
+ self.changed.add(widget)
897
+ self.setDataButtonState()
903
+ # Server side options
905
+ # set buttons sensitivity
906
+ def setDataButtonState(self):
907
+ try: # Might not be a printer selected
908
+ possible = (self.ppd and
909
+ not bool (self.changed) and
910
+ self.printer.enabled and
911
+ not self.printer.rejecting)
913
+ self.btnPrintTestPage.setEnabled(possible)
915
+ commands = (self.printer.type & cups.CUPS_PRINTER_COMMANDS) != 0
916
+ self.btnSelfTest.setEnabled(commands and possible)
917
+ self.btnCleanHeads.setEnabled(commands and possible)
919
+ debugprint ("exception in setDataButtonState")
922
+ installablebold = False
923
+ optionsbold = False
924
+ """ FIXME, no conflicts button in system settings
926
+ debugprint ("Conflicts detected")
927
+ self.btnConflict.show()
928
+ for option in self.conflicts:
929
+ if option.tab_label == self.lblPInstallOptions:
930
+ installablebold = True
934
+ self.ui.btnConflict.hide()
936
+ installabletext = i18n("Installable Options")
937
+ optionstext = i18n("Printer Options")
938
+ if installablebold:
939
+ installabletext = i18nc("Conflicted entry", "<b>%1</b>", installabletext)
941
+ optionstext = i18nc("Conflicted entry", "<b>%1</b>", optionstext)
942
+ self.ui.lblPInstallOptions.setText(installabletext)
943
+ self.ui.lblPOptions.setText(optionstext)
946
+ store = self.tvPrinterProperties.get_model ()
948
+ for n in range (self.ntbkPrinter.get_n_pages ()):
949
+ page = self.ntbkPrinter.get_nth_page (n)
950
+ label = self.ntbkPrinter.get_tab_label (page)
951
+ if label == self.lblPInstallOptions:
952
+ iter = store.get_iter ((n,))
953
+ store.set_value (iter, 0, installabletext)
954
+ elif label == self.lblPOptions:
955
+ iter = store.get_iter ((n,))
956
+ store.set_value (iter, 0, optionstext)
959
+ self.ui.changed(len (self.changed) > 0)
960
+ #self.ui.btnPrinterPropertiesApply.setEnabled(len (self.changed) > 0)
961
+ #self.ui.btnRevert.setEnabled(len (self.changed) > 0)
963
+ def save_printer(self, printer, saveall=False):
964
+ class_deleted = False
965
+ name = printer.name
968
+ if not printer.is_class and self.ppd:
969
+ self.getPrinterSettings()
970
+ if self.ppd.nondefaultsMarked() or saveall:
971
+ self.passwd_retry = False # use cached Passwd
972
+ self.cups.addPrinter(name, ppd=self.ppd)
974
+ if printer.is_class:
975
+ # update member list
976
+ new_members = self.getCurrentClassMembers(self.ui.tvClassMembers)
977
+ if not new_members:
978
+ result = KMessageBox.warningContinueCancel(self.ui, i18n("Class now has no members. Proceed anyway?"), i18n("Class Empty"))
979
+ if result == KMessageBox.Continue:
981
+ class_deleted = True
983
+ # update member list
984
+ old_members = printer.class_members[:]
986
+ for member in new_members:
987
+ member = unicode(member)
988
+ if member in old_members:
989
+ old_members.remove(member)
991
+ self.cups.addPrinterToClass(member, name)
992
+ for member in old_members:
993
+ self.cups.deletePrinterFromClass(member, name)
995
+ location = unicode(self.ui.entPLocation.text())
996
+ info = unicode(self.ui.entPDescription.text())
997
+ device_uri = unicode(self.ui.entPDevice.text())
998
+ if device_uri.find (ellipsis) != -1:
999
+ # The URI is sanitized and not editable.
1000
+ device_uri = printer.device_uri
1002
+ enabled = self.ui.chkPEnabled.isChecked()
1003
+ accepting = self.ui.chkPAccepting.isChecked()
1004
+ shared = self.ui.chkPShared.isChecked()
1006
+ if info!=printer.info or saveall:
1007
+ self.passwd_retry = False # use cached Passwd
1008
+ self.cups.setPrinterInfo(name, info)
1009
+ if location!=printer.location or saveall:
1010
+ self.passwd_retry = False # use cached Passwd
1011
+ self.cups.setPrinterLocation(name, location)
1012
+ if (not printer.is_class and
1013
+ (device_uri!=printer.device_uri or saveall)):
1014
+ self.passwd_retry = False # use cached Passwd
1015
+ self.cups.setPrinterDevice(name, device_uri)
1017
+ if enabled != printer.enabled or saveall:
1018
+ self.passwd_retry = False # use cached Passwd
1019
+ self.printer.setEnabled(enabled)
1020
+ if accepting == printer.rejecting or saveall:
1021
+ self.passwd_retry = False # use cached Passwd
1022
+ self.printer.setAccepting(accepting)
1023
+ if shared != printer.is_shared or saveall:
1024
+ self.passwd_retry = False # use cached Passwd
1025
+ self.printer.setShared(shared)
1027
+ job_sheet_start = unicode(self.ui.cmbPStartBanner.currentText())
1028
+ job_sheet_end = unicode(self.ui.cmbPEndBanner.currentText())
1029
+ #FIXME Not implemented in current UI
1030
+ #error_policy = unicode(self.cmbPErrorPolicy.currentText())
1031
+ #op_policy = unicode(self.cmbPOperationPolicy.currentText())
1033
+ if (job_sheet_start != printer.job_sheet_start or
1034
+ job_sheet_end != printer.job_sheet_end) or saveall:
1035
+ self.passwd_retry = False # use cached Passwd
1036
+ printer.setJobSheets(job_sheet_start, job_sheet_end)
1037
+ #FIXME Not implemented in current UI
1038
+ #if error_policy != printer.error_policy or saveall:
1039
+ #self.passwd_retry = False # use cached Passwd
1040
+ #printer.setErrorPolicy(error_policy)
1041
+ #if op_policy != printer.op_policy or saveall:
1042
+ #self.passwd_retry = False # use cached Passwd
1043
+ #printer.setOperationPolicy(op_policy)
1046
+ default_allow = self.ui.rbtnPAllow.isChecked()
1047
+ except_users = self.getPUsers()
1049
+ if (default_allow != printer.default_allow or
1050
+ except_users != printer.except_users) or saveall:
1051
+ self.passwd_retry = False # use cached Passwd
1052
+ printer.setAccess(default_allow, except_users)
1054
+ for option in printer.attributes:
1055
+ if option not in self.server_side_options:
1056
+ printer.unsetOption(option)
1057
+ for option in self.server_side_options.itervalues():
1058
+ if (option.is_changed() or
1060
+ option.get_current_value () != option.system_default):
1061
+ printer.setOption(unicode(option.name), unicode(option.get_current_value()) )
1063
+ except cups.IPPError, (e, s):
1064
+ self.show_IPP_Error(e, s)
1066
+ self.changed = set() # of options
1068
+ if not self.__dict__.has_key ("server_settings"):
1069
+ # We can authenticate with the server correctly at this point,
1070
+ # but we have never fetched the server settings to see whether
1071
+ # the server is publishing shared printers. Fetch the settings
1072
+ # now so that we can update the "not published" label if necessary.
1074
+ self.server_settings = self.cups.adminGetServerSettings()
1076
+ nonfatalException()
1079
+ self.populateList ()
1081
+ # Update our copy of the printer's settings.
1083
+ printers = cupshelpers.getPrinters (self.cups)
1084
+ this_printer = { name: printers[name] }
1085
+ self.printers.update (this_printer)
1086
+ except cups.IPPError, (e, s):
1087
+ show_IPP_Error(e, s, self.PrinterPropertiesDialog)
1091
+ def getPrinterSettings(self):
1092
+ #self.ppd.markDefaults()
1093
+ for option in self.options.itervalues():
1094
+ option.writeback()
1096
+ @pyqtSignature("")
1097
+ def on_btnPrintTestPage_clicked(self):
1098
+ self.setTestButton(self.printer)
1099
+ if self.test_button_cancels:
1100
+ jobs = self.printer.testsQueued ()
1102
+ debugprint ("Canceling job %s" % job)
1104
+ self.cups.cancelJob (job)
1105
+ except cups.IPPError, (e, msg):
1106
+ self.show_IPP_Error(e, msg)
1107
+ self.setTestButton (self.printer)
1110
+ # if we have a page size specific custom test page, use it;
1111
+ # otherwise use cups' default one
1112
+ custom_testpage = None
1113
+ opt = self.ppd.findOption ("PageSize")
1116
+ custom_testpage = os.path.join(SYSTEM_CONFIG_PRINTER_DIR, 'testpage-%s.ps' % opt.defchoice.lower())
1117
+ print custom_testpage
1119
+ if custom_testpage and os.path.exists(custom_testpage):
1120
+ debugprint ('Printing custom test page ' + custom_testpage)
1121
+ job_id = self.cups.printTestPage(self.printer.name,
1122
+ file=custom_testpage)
1125
+ debugprint ('Printing default test page')
1126
+ job_id = self.cups.printTestPage(self.printer.name)
1128
+ self.setTestButton (self.printer)
1129
+ KMessageBox.information(self, i18n("Test page submitted as job %1", job_id), i18nc("Test page submitted", "Submitted"))
1130
+ except cups.IPPError, (e, msg):
1131
+ if (e == cups.IPP_NOT_AUTHORIZED and
1132
+ self.connect_server != 'localhost' and
1133
+ self.connect_server[0] != '/'):
1134
+ self.lblError.set_markup ('<span size="larger">'+
1135
+ i18n("<b>Not possible</b>") + '</span>\n\n' +
1136
+ i18n("The remote server did not accept "
1137
+ "the print job, most likely "
1138
+ "because the printer is not "
1140
+ self.ErrorDialog.set_transient_for (self.MainWindow)
1141
+ self.ErrorDialog.run ()
1142
+ self.ErrorDialog.hide ()
1144
+ self.show_IPP_Error(e, msg)
1146
+ def maintenance_command (self, command):
1147
+ (tmpfd, tmpfname) = tempfile.mkstemp ()
1148
+ os.write (tmpfd, "#CUPS-COMMAND\n%s\n" % command)
1151
+ format = "application/vnd.cups-command"
1152
+ job_id = self.cups.printTestPage (self.printer.name,
1155
+ user=self.connect_user)
1156
+ self.lblInfo.set_markup ('<span size="larger">' +
1157
+ i18nc("Maintenance command submitted", "<b>Submitted</b>") + '</span>\n\n' +
1158
+ i18n("Maintenance command submitted as "
1159
+ "job %d", job_id))
1160
+ self.InfoDialog.set_transient_for (self.MainWindow)
1161
+ self.InfoDialog.run ()
1162
+ self.InfoDialog.hide ()
1163
+ except cups.IPPError, (e, msg):
1164
+ if (e == cups.IPP_NOT_AUTHORIZED and
1165
+ self.printer.name != 'localhost'):
1166
+ self.lblError.set_markup ('<span size="larger">'+
1167
+ i18n("<b>Not possible</b>") + '</span>\n\n' +
1168
+ i18n("The remote server did not accept "
1169
+ "the print job, most likely "
1170
+ "because the printer is not "
1172
+ self.ErrorDialog.set_transient_for (self.MainWindow)
1173
+ self.ErrorDialog.run ()
1174
+ self.ErrorDialog.hide ()
1176
+ self.show_IPP_Error(e, msg)
1178
+ @pyqtSignature("")
1179
+ def on_btnSelfTest_clicked(self):
1180
+ self.maintenance_command ("PrintSelfTestPage")
1182
+ @pyqtSignature("")
1183
+ def on_btnCleanHeads_clicked(self):
1184
+ self.maintenance_command ("Clean all")
1186
+ def fillComboBox(self, combobox, values, value):
1188
+ for nr, val in enumerate(values):
1189
+ combobox.addItem(val)
1191
+ combobox.setCurrentIndex(nr)
1193
+ def fillPrinterTab(self, name):
1194
+ self.changed = set() # of options
1195
+ self.options = {} # keyword -> Option object
1196
+ self.conflicts = set() # of options
1198
+ printer = self.printers[name]
1199
+ self.printer = printer
1200
+ printer.getAttributes ()
1202
+ editable = not self.printer.discovered
1203
+ editablePPD = not self.printer.remote
1206
+ self.ppd = printer.getPPD()
1207
+ except cups.IPPError, (e, m):
1208
+ # Some IPP error other than IPP_NOT_FOUND.
1209
+ self.show_IPP_Error(e, m)
1210
+ # Treat it as a raw queue.
1212
+ except RuntimeError:
1213
+ # The underlying cupsGetPPD2() function returned NULL without
1214
+ # setting an IPP error, so it'll be something like a failed
1216
+ #FIXME show a dialogue
1217
+ debugprint("Error!")
1219
+ self.lblError.set_markup('<span size="larger">' +
1220
+ _("<b>Error</b>") + '</span>\n\n' +
1221
+ _("There was a problem connecting to "
1222
+ "the CUPS server."))
1223
+ self.ErrorDialog.set_transient_for(self.MainWindow)
1224
+ self.ErrorDialog.run()
1225
+ self.ErrorDialog.hide()
1229
+ for widget in (self.ui.entPDescription, self.ui.entPLocation,
1230
+ self.ui.entPName, self.ui.entPDevice):
1231
+ widget.setReadOnly(not editable)
1233
+ for widget in (self.ui.btnChangePPD,
1234
+ self.ui.chkPEnabled, self.ui.chkPAccepting, self.ui.chkPShared,
1235
+ self.ui.cmbPStartBanner, self.ui.cmbPEndBanner, self.ui.btnPAddUser,
1236
+ self.ui.btnPDelUser, self.ui.rbtnPAllow, self.ui.rbtnPDeny):
1238
+ #self.btnSelectDevice, self.cmbPErrorPolicy,
1239
+ #self.cmbPOperationPolicy,):
1241
+ widget.setEnabled(editable)
1243
+ # Description page
1244
+ self.ui.entPName.setText(printer.name)
1245
+ self.ui.entPDescription.setText(printer.info)
1246
+ self.ui.entPLocation.setText(printer.location)
1248
+ uri = printer.device_uri
1249
+ if uri.startswith("smb://"):
1250
+ (group, host, share,
1251
+ user, password) = SMBURI (uri=uri[6:]).separate ()
1254
+ if len (user) or len (password):
1256
+ uri += SMBURI (group=group, host=host, share=share).get_uri ()
1257
+ self.ui.entPDevice.setEnabled(False)
1259
+ self.ui.entPDevice.setEnabled(True)
1261
+ self.ui.entPDevice.setText(uri)
1262
+ self.changed.discard(self.ui.entPDevice)
1264
+ # Hide make/model and Device URI for classes
1265
+ for widget in (self.ui.lblPMakeModel2, self.ui.lblPMakeModel,
1266
+ self.ui.lblPDevice2, self.ui.entPDevice,
1267
+ self.ui.btnChangePPD):
1268
+ #, self.btnSelectDevice):
1269
+ if printer.is_class:
1274
+ ## default printer
1275
+ default = self.cups.getDefault()
1277
+ if printer.name == default:
1278
+ #catch the stateChanged signal to prevent a signal loop
1279
+ self.ui.chkPMakeDefault.blockSignals(True)
1280
+ self.ui.chkPMakeDefault.setChecked(True) #set checked
1281
+ #unblock the signal
1282
+ self.ui.chkPMakeDefault.blockSignals(False)
1283
+ self.ui.chkPMakeDefault.setText(i18n("This is the default printer"))
1285
+ #catch the stateChanged signal to prevent a signal loop
1286
+ self.ui.chkPMakeDefault.blockSignals(True)
1287
+ self.ui.chkPMakeDefault.setChecked(False) #set unchecked
1288
+ #unblock the signal
1289
+ self.ui.chkPMakeDefault.blockSignals(False)
1290
+ if default is not None:
1291
+ self.ui.chkPMakeDefault.setText(i18n('Make Default. (The current default is %1)', default))
1293
+ self.ui.chkPMakeDefault.setText(i18n('Make Default. (There is no current default)'))
1295
+ #self.setTestButton (printer)
1301
+ self.ui.chkPEnabled.setChecked(printer.enabled)
1302
+ self.ui.chkPAccepting.setChecked(not printer.rejecting)
1303
+ self.ui.chkPShared.setChecked(printer.is_shared)
1305
+ if printer.is_shared:
1306
+ flag = cups.CUPS_SERVER_SHARE_PRINTERS
1307
+ publishing = int (self.server_settings[flag])
1309
+ self.ui.lblNotPublished.hide()
1311
+ self.ui.lblNotPublished.show()
1313
+ self.ui.lblNotPublished.hide()
1315
+ self.ui.lblNotPublished.hide()
1318
+ self.ui.cmbPStartBanner.setEnabled(editable)
1319
+ self.ui.cmbPEndBanner.setEnabled(editable)
1321
+#FIXME Not implemented in the current UI
1323
+ #self.cmbPErrorPolicy.setEnabled(editable)
1324
+ #self.cmbPOperationPolicy.setEnabled(editable)
1328
+ self.ui.rbtnPAllow.setChecked(printer.default_allow)
1329
+ self.ui.rbtnPDeny.setChecked(not printer.default_allow)
1330
+ self.setPUsers(printer.except_users)
1332
+ #self.entPUser.set_text("")
1333
+ # Server side options (Job options)
1334
+ self.server_side_options = {}
1335
+ for option in self.job_options_widgets.values ():
1336
+ if option.name == "media" and self.ppd:
1337
+ # Slightly special case because the 'system default'
1338
+ # (i.e. what you get when you press Reset) depends
1339
+ # on the printer's PageSize.
1340
+ opt = self.ppd.findOption ("PageSize")
1342
+ option.set_default (opt.defchoice)
1344
+ option_editable = editable
1346
+ value = self.printer.attributes[option.name]
1348
+ option.reinit (None)
1351
+ if self.printer.possible_attributes.has_key (option.name):
1352
+ supported = self.printer.\
1353
+ possible_attributes[option.name][1]
1354
+ # Set the option widget.
1355
+ # In CUPS 1.3.x the orientation-requested-default
1356
+ # attribute may have the value None; this means there
1357
+ # is no value set. This suits our needs here, as None
1358
+ # resets the option to the system default and makes the
1359
+ # Reset button insensitive.
1360
+ option.reinit (value, supported=supported)
1362
+ option.reinit (value)
1364
+ self.server_side_options[option.name] = option
1365
+ except ValueError, inst:
1366
+ option_editable = False
1367
+ text = ('<span ' +
1368
+ 'size="larger">' +
1369
+ _("<b>Error</b>") + '</span>\n\n' +
1370
+ _("Option '%s' has value '%s' "
1371
+ "and cannot be edited.") %
1372
+ (option.name, value))
1373
+ QMessageBox.critical(self.ui, i18n("Error"), text)
1374
+ option.widget.setEnabled(option_editable)
1376
+ option.button.setEnabled(False)
1377
+ self.other_job_options = []
1378
+ self.draw_other_job_options (editable=editable)
1379
+ for option in self.printer.attributes.keys ():
1380
+ if self.server_side_options.has_key (option):
1383
+ if self.printer.possible_attributes.has_key (option):
1384
+ supported = self.printer.possible_attributes[option][1]
1385
+ self.add_job_option (option, value=self.printer.attributes[option],
1386
+ supported=supported, is_new=False,
1387
+ editable=editable)
1388
+ self.ui.entNewJobOption.setText ('')
1389
+ self.ui.entNewJobOption.setEnabled(editable)
1390
+ self.ui.btnNewJobOption.setEnabled(False)
1392
+ if printer.is_class:
1393
+ # remove InstallOptions tab
1394
+ ##tab_nr = self.ui.ntbkPrinter.page_num(self.swPInstallOptions)
1395
+ ##if tab_nr != -1:
1396
+ ## self.ui.ntbkPrinter.remove_page(tab_nr)
1397
+ self.fillClassMembers(name, editable)
1401
+ self.fillPrinterOptions(name, editablePPD)
1403
+ #self.changed = set() # of options
1404
+ self.updatePrinterProperties ()
1405
+ self.setDataButtonState()
1408
+ def fillPrinterOptions(self, name, editable):
1409
+ # remove Member tab
1410
+ tab_nr = self.ui.ntbkPrinter.indexOf(self.memberTabWidget)
1412
+ self.ui.ntbkPrinter.removeTab(tab_nr)
1413
+ policiesTabNo = self.ui.ntbkPrinter.indexOf(self.policiesTabWidget)
1414
+ self.ui.ntbkPrinter.insertTab(policiesTabNo+1, self.optionsTabWidget, i18n("Options"))
1417
+ # clean Installable Options Tab
1418
+ for widget in self.vbPInstallOptions.get_children():
1419
+ self.vbPInstallOptions.remove(widget)
1422
+ # clean Options Tab
1423
+ for widget in self.ui.optionsPageWidget.children():
1424
+ if isinstance(widget, QWidget):
1425
+ self.ui.vbPOptions.removeWidget(widget)
1430
+ # insert Options Tab
1431
+ if self.ntbkPrinter.page_num(self.swPOptions) == -1:
1432
+ self.ntbkPrinter.insert_page(
1433
+ self.swPOptions, self.lblPOptions, self.static_tabs)
1436
+ tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions)
1438
+ self.ntbkPrinter.remove_page(tab_nr)
1439
+ tab_nr = self.ntbkPrinter.page_num(self.swPOptions)
1441
+ self.ntbkPrinter.remove_page(tab_nr)
1445
+ ppd.markDefaults()
1447
+ hasInstallableOptions = False
1449
+ # build option tabs
1450
+ for group in ppd.optionGroups:
1451
+ if group.name == "InstallableOptions":
1453
+ hasInstallableOptions = True
1454
+ container = self.vbPInstallOptions
1455
+ tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions)
1457
+ self.ntbkPrinter.insert_page(
1458
+ self.swPInstallOptions, gtk.Label(group.text),
1461
+ tab_label = self.ui.lblPInstallOptions
1464
+ frame = gtk.Frame("<b>%s</b>" % group.text)
1465
+ frame.get_label_widget().set_use_markup(True)
1466
+ frame.set_shadow_type (gtk.SHADOW_NONE)
1467
+ self.vbPOptions.pack_start (frame, False, False, 0)
1468
+ container = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
1469
+ # We want a left padding of 12, but there is a Table with
1470
+ # spacing 6, and the left-most column of it (the conflict
1471
+ # icon) is normally hidden, so just use 6 here.
1472
+ container.set_padding (6, 12, 6, 0)
1473
+ frame.add (container)
1475
+ tab_label = self.ui.lblPOptions
1476
+ container = QGroupBox(self)
1477
+ self.ui.vbPOptions.addWidget(container)
1478
+ container.setTitle(group.text)
1481
+ table = gtk.Table(1, 3, False)
1482
+ table.set_col_spacings(6)
1483
+ table.set_row_spacings(6)
1484
+ container.add(table)
1486
+ table = QGridLayout(container)
1487
+ container.setLayout(table)
1491
+ # InputSlot and ManualFeed need special handling. With
1492
+ # libcups, if ManualFeed is True, InputSlot gets unset.
1493
+ # Likewise, if InputSlot is set, ManualFeed becomes False.
1494
+ # We handle it by toggling the sensitivity of InputSlot
1495
+ # based on ManualFeed.
1496
+ self.option_inputslot = self.option_manualfeed = None
1498
+ for nr, option in enumerate(group.options):
1499
+ if option.keyword == "PageRegion":
1503
+ table.resize (rows, 3)
1505
+ o = OptionWidget(option, ppd, self, tab_label=tab_label)
1507
+ table.attach(o.conflictIcon, 0, 1, nr, nr+1, 0, 0, 0, 0)
1512
+ table.addWidget(o.label, rows-1, 0)
1514
+ a = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
1515
+ a.set_padding (0, 0, 0, 6)
1517
+ table.attach(a, 1, 2, nr, nr+1, gtk.FILL, 0, 0, 0)
1518
+ table.attach(hbox, 2, 3, nr, nr+1, gtk.FILL, 0, 0, 0)
1520
+ table.attach(hbox, 1, 3, nr, nr+1, gtk.FILL, 0, 0, 0)
1521
+ hbox.pack_start(o.selector, False)
1523
+ table.addWidget(o.selector, rows-1, 1)
1524
+ self.options[option.keyword] = o
1525
+ o.selector.setEnabled(editable)
1526
+ if option.keyword == "InputSlot":
1527
+ self.option_inputslot = o
1528
+ elif option.keyword == "ManualFeed":
1529
+ self.option_manualfeed = o
1532
+ # remove Installable Options tab if not needed
1533
+ if not hasInstallableOptions:
1534
+ tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions)
1536
+ self.ntbkPrinter.remove_page(tab_nr)
1538
+ # check for conflicts
1539
+ for option in self.options.itervalues():
1540
+ conflicts = option.checkConflicts()
1542
+ self.conflicts.add(option)
1544
+ self.swPInstallOptions.show_all()
1545
+ self.swPOptions.show_all()
1551
+ def fillClassMembers(self, name, editable):
1552
+ printer = self.printers[name]
1554
+ self.ui.btnClassAddMember.setEnabled(editable)
1555
+ self.ui.btnClassDelMember.setEnabled(editable)
1557
+ # remove Options tab
1558
+ tab_nr = self.ui.ntbkPrinter.indexOf(self.optionsTabWidget)
1560
+ self.ui.ntbkPrinter.removeTab(tab_nr)
1561
+ policiesTabNo = self.ui.ntbkPrinter.indexOf(self.policiesTabWidget)
1562
+ self.ui.ntbkPrinter.insertTab(policiesTabNo+1, self.memberTabWidget, i18n("Members"))
1564
+ self.ui.tvClassMembers.clear()
1565
+ self.ui.tvClassNotMembers.clear()
1566
+ names = self.printers.keys()
1568
+ for name in names:
1569
+ p = self.printers[name]
1570
+ if p is not printer:
1571
+ if name in printer.class_members:
1572
+ self.ui.tvClassMembers.addItem(name)
1574
+ self.ui.tvClassNotMembers.addItem(name)
1576
+ def on_btnClassAddMember_clicked(self):
1577
+ self.moveClassMembers(self.ui.tvClassNotMembers,
1578
+ self.ui.tvClassMembers)
1579
+ if self.getCurrentClassMembers(self.ui.tvClassMembers) != self.printer.class_members:
1580
+ self.changed.add(self.ui.tvClassMembers)
1582
+ self.changed.discard(self.ui.tvClassMembers)
1583
+ self.setDataButtonState()
1585
+ def on_btnClassDelMember_clicked(self):
1586
+ self.moveClassMembers(self.ui.tvClassMembers,
1587
+ self.ui.tvClassNotMembers)
1588
+ if self.getCurrentClassMembers(self.ui.tvClassMembers) != self.printer.class_members:
1589
+ self.changed.add(self.ui.tvClassMembers)
1591
+ self.changed.discard(self.ui.tvClassMembers)
1592
+ self.setDataButtonState()
1594
+ #In Gnome is now on_delete_activate(self, UNUSED):
1595
+ def btnDelete_clicked(self):
1596
+ name, type = self.getSelectedItem()
1599
+ if type == "Printer":
1600
+ message_format = i18n("Really delete printer %s?")
1602
+ message_format = i18n("Really delete class %s?")
1604
+ answer = KMessageBox.questionYesNo(self,
1605
+ unicode(message_format) % name,
1608
+ if answer == KMessageBox.Yes:
1610
+ self.cups.deletePrinter(name)
1611
+ except cups.IPPError, (e, msg):
1612
+ self.show_IPP_Error(e, msg)
1613
+ elif answer == KMessageBox.No:
1616
+ self.changed = set()
1617
+ self.populateList()
1618
+ self.ui.mainlist.setCurrentItem(self.ui.mainlist.itemAt(0,0))
1620
+ #Taken from the gnome version
1621
+ def setDefaultPrinter(self, name):
1622
+ printer = self.printers[name]
1624
+ printer.setAsDefault()
1625
+ except cups.HTTPError, (s,):
1626
+ self.show_HTTP_Error(s)
1628
+ except cups.IPPError(e, msg):
1629
+ show_IPP_Error(e, msg)
1632
+ def chkPMakeDefault_stateChanged(self):
1633
+ default = self.cups.getDefault()
1635
+ if self.ui.chkPMakeDefault.isChecked():
1636
+ name = self.ui.entPName.text()
1637
+ self.setDefaultPrinter(unicode(name))
1638
+ self.ui.chkPMakeDefault.setText(i18n("This is the default printer"))
1640
+ if default is not None:
1641
+ self.ui.chkPMakeDefault.setText(i18n('Make Default. (The current default is %1)', default))
1643
+ self.ui.chkPMakeDefault.setText(i18n('Make Default. (There is no current default)'))
1645
+ self.ui.changed(len(self.changed) > 0)
1646
+ #self.ui.btnPrinterPropertiesApply.setEnabled(len (self.changed) > 0)
1647
+ #self.ui.btnRevert.setEnabled(len (self.changed) > 0)
1649
+ except cups.IPPError, (e, msg):
1650
+ self.show_IPP_Error(e, msg)
1653
+##############################
1654
+ #Obsolete? Possibly no longer necessary. Not included in
1655
+ #current gnome version
1656
+ # Also need to check system-wide lpoptions because that's how
1657
+ # previous Fedora versions set the default (bug #217395).
1658
+ (tmpfd, tmpfname) = tempfile.mkstemp ()
1661
+ resource = "/admin/conf/lpoptions"
1662
+ self.cups.getFile(resource, tmpfname)
1664
+ except cups.HTTPError, (s,):
1666
+ os.remove (tmpfname)
1670
+ if s != cups.HTTP_NOT_FOUND:
1671
+ self.show_HTTP_Error(s)
1675
+ lines = file (tmpfname).readlines ()
1678
+ for line in lines:
1679
+ if line.startswith ("Default "):
1680
+ # This is the system-wide default.
1681
+ name = line.split (' ')[1]
1682
+ if name != self.printer.name:
1683
+ # Stop it from over-riding the server default.
1684
+ lines[i] = "Dest " + line[8:]
1689
+ file (tmpfname, 'w').writelines (lines)
1691
+ self.cups.putFile (resource, tmpfname)
1692
+ except cups.HTTPError, (s,):
1693
+ os.remove (tmpfname)
1694
+ self.show_HTTP_Error(s)
1696
+#########################
1697
+ # Now reconnect because the server needs to reload.
1701
+ os.remove (tmpfname)
1706
+ self.populateList()
1707
+ except cups.HTTPError, (s,):
1709
+ self.setConnected()
1710
+ self.populateList()
1711
+ self.show_HTTP_Error(s)
1713
+ def option_changed(self, option):
1714
+ if option.is_changed():
1715
+ self.changed.add(option)
1717
+ self.changed.discard(option)
1719
+ if option.conflicts:
1720
+ self.conflicts.add(option)
1722
+ self.conflicts.discard(option)
1723
+ self.setDataButtonState()
1725
+ if (self.option_manualfeed and self.option_inputslot and
1726
+ option == self.option_manualfeed):
1727
+ if option.get_current_value() == "True":
1728
+ self.option_inputslot.disable ()
1730
+ self.option_inputslot.enable ()
1733
+ def getPUsers(self):
1734
+ """return list of usernames from the GUI"""
1735
+ result = [] #empty list to hold result
1736
+ #if there is only one user in the list
1737
+ if self.ui.tvPUsers.topLevelItemCount() < 2:
1738
+ item = self.ui.tvPUsers.itemAt(0, 0)
1739
+ #use a string instead of a QString.
1740
+ #system-config-printer fails in
1741
+ #self.connection.setPrinterUsersDenied(self.name, except_users)
1742
+ #if we use a QString
1743
+ if item is not None:
1744
+ name = str(item.text(0))
1745
+ result.append(name)
1747
+ #create an iterator for the QTreeWidgetObject
1748
+ #had to create an iterator class manually because QTreeWidgetItemIterator
1750
+ it = Iter(self.ui.tvPUsers)
1751
+ while it: #iterate over the tree
1754
+ name = item.text(0)
1755
+ result.append(name)
1756
+ except StopIteration:
1762
+ def setPUsers(self, users):
1763
+ """write list of usernames into the GUI"""
1764
+ self.ui.tvPUsers.clear()
1765
+ for user in users:
1766
+ #create a QTreeWidgetItem
1767
+ u = QTreeWidgetItem(self.ui.tvPUsers)
1768
+ u.setText(0, user) #set the label for the item
1769
+ #add the item to the top level of the tree
1770
+ self.ui.tvPUsers.addTopLevelItem(u)
1772
+ def checkPUsersChanged(self):
1773
+ """check if users in GUI and printer are different
1774
+ and set self.changed"""
1775
+ if self.getPUsers() != self.printer.except_users:
1776
+ self.changed.add(self.ui.tvPUsers)
1778
+ self.changed.discard(self.ui.tvPUsers)
1780
+ self.setDataButtonState()
1782
+ def btnPAddUser_clicked(self):
1783
+ current_user = os.getenv('USER')
1784
+ user, ok = KInputDialog.getText(i18n('Add User'), i18n('Enter Username'), current_user)
1787
+ if ok and not user.isEmpty():
1788
+ u = QTreeWidgetItem(self.ui.tvPUsers)
1789
+ u.setText(0, user)
1790
+ self.ui.tvPUsers.addTopLevelItem(u)
1792
+ self.checkPUsersChanged()
1794
+ def btnPDelUser_clicked(self):
1795
+ users = self.ui.tvPUsers.selectedItems()
1797
+ index = self.ui.tvPUsers.indexOfTopLevelItem(u)
1798
+ self.ui.tvPUsers.takeTopLevelItem(index)
1800
+ self.checkPUsersChanged()
1802
+ # Server side options
1803
+ def on_job_option_reset(self):
1804
+ button = self.sender()
1805
+ option = self.job_options_buttons[button]
1807
+ # Remember to set this option for removal in the IPP request.
1808
+ if self.server_side_options.has_key (option.name):
1809
+ del self.server_side_options[option.name]
1810
+ if option.is_changed ():
1811
+ self.changed.add(option)
1813
+ self.changed.discard(option)
1814
+ self.setDataButtonState()
1816
+ def on_job_option_changed(self):
1817
+ if not self.printer:
1819
+ widget = self.sender()
1820
+ option = self.job_options_widgets[widget]
1822
+ if option.is_changed ():
1823
+ self.server_side_options[option.name] = option
1824
+ self.changed.add(option)
1826
+ if self.server_side_options.has_key (option.name):
1827
+ del self.server_side_options[option.name]
1828
+ self.changed.discard(option)
1829
+ self.setDataButtonState()
1830
+ # Don't set the reset button insensitive if the option hasn't
1831
+ # changed from the original value: it's still meaningful to
1832
+ # reset the option to the system default.
1834
+ def draw_other_job_options (self, editable=True):
1835
+ n = len (self.other_job_options)
1837
+ # self.tblJOOther.hide_all ()
1840
+ #self.tblJOOther.resize (n, 3)
1841
+ children = self.ui.tblJOOtherWidget.children()
1842
+ for child in children:
1843
+ if type(child) != QGridLayout:
1844
+ self.ui.tblJOOther.removeWidget(child)
1847
+ self.removeJobOptionButtons = {}
1848
+ for opt in self.other_job_options:
1849
+ self.ui.tblJOOther.addWidget(opt.label, i, 0)
1850
+ self.ui.tblJOOther.addWidget(opt.selector, i, 1)
1852
+ opt.selector.show()
1853
+ opt.selector.setEnabled(editable)
1855
+ btn = QPushButton("Remove", self.ui.tblJOOtherWidget)
1856
+ self.connect(btn, SIGNAL("clicked()"), self.on_btnJOOtherRemove_clicked)
1857
+ #btn.set_data("pyobject", opt)
1858
+ self.removeJobOptionButtons[btn] = opt
1859
+ btn.setEnabled(editable)
1860
+ self.ui.tblJOOther.addWidget(btn, i, 2)
1863
+ #self.tblJOOther.show_all ()
1865
+ def add_job_option(self, name, value = "", supported = "", is_new=True,
1867
+ option = options.OptionWidget(name, value, supported,
1868
+ self.option_changed)
1869
+ option.is_new = is_new
1870
+ self.other_job_options.append (option)
1871
+ self.draw_other_job_options (editable=editable)
1872
+ self.server_side_options[name] = option
1873
+ if name in self.changed: # was deleted before
1874
+ option.is_new = False
1875
+ self.changed.add(option)
1876
+ self.setDataButtonState()
1878
+ ##option.selector.grab_focus ()
1881
+ def on_btnJOOtherRemove_clicked(self):
1882
+ button = self.sender()
1883
+ option = self.removeJobOptionButtons[button]
1884
+ #option = button.get_data("pyobject")
1885
+ self.other_job_options.remove (option)
1886
+ self.draw_other_job_options ()
1888
+ self.changed.discard(option)
1890
+ # keep name as reminder that option got deleted
1891
+ self.changed.add(option.name)
1892
+ del self.server_side_options[option.name]
1893
+ self.setDataButtonState()
1895
+ def on_btnNewJobOption_clicked(self):
1896
+ name = self.ui.entNewJobOption.text()
1897
+ self.add_job_option(name)
1898
+ #self.tblJOOther.show_all()
1899
+ self.ui.entNewJobOption.setText('')
1900
+ self.ui.btnNewJobOption.setEnabled(False)
1901
+ self.setDataButtonState()
1903
+ def on_entNewJobOption_changed(self, widget):
1904
+ text = unicode(self.ui.entNewJobOption.text())
1905
+ active = (len(text) > 0) and text not in self.server_side_options
1906
+ self.ui.btnNewJobOption.setEnabled(active)
1908
+ def on_entNewJobOption_activate(self, widget):
1909
+ self.on_btnNewJobOption_clicked (widget) # wrong widget but ok
1911
+ ##########################################################################
1912
+ ### Server settings
1913
+ ##########################################################################
1915
+ def fillServerTab(self):
1916
+ self.changed = set()
1918
+ self.server_settings = self.cups.adminGetServerSettings()
1919
+ except cups.IPPError, (e, m):
1921
+ self.show_IPP_Error(e, m)
1922
+ self.ui.tvMainList.get_selection().unselect_all()
1923
+ self.on_tvMainList_cursor_changed(self.ui.tvMainList)
1926
+ for widget, setting in [
1927
+ (self.ui.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS),
1928
+ (self.ui.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS),
1929
+ (self.ui.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY),
1930
+ (self.ui.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN),
1931
+ (self.ui.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY),
1932
+ (self.ui.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]:
1933
+ # widget.set_data("setting", setting)
1934
+ self.widget_data_setting[widget] = setting
1935
+ self.disconnect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
1936
+ if self.server_settings.has_key(setting):
1937
+ widget.setChecked(int(self.server_settings[setting]))
1938
+ widget.setEnabled(True)
1940
+ widget.setChecked(False)
1941
+ widget.setEnabled(False)
1942
+ self.connect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
1943
+ self.setDataButtonState()
1944
+ # Set sensitivity of 'Allow printing from the Internet'.
1945
+ self.on_server_changed (self.ui.chkServerShare) # (any will do here)
1947
+ def on_server_widget_changed(self, value):
1948
+ self.on_server_changed(self.sender())
1950
+ def on_server_changed(self, widget):
1951
+ setting = self.widget_data_setting[widget]
1952
+ if self.server_settings.has_key (setting):
1953
+ if str(int(widget.isChecked())) == self.server_settings[setting]:
1954
+ self.changed.discard(widget)
1956
+ self.changed.add(widget)
1958
+ sharing = self.ui.chkServerShare.isChecked ()
1959
+ self.ui.chkServerShareAny.setEnabled (
1960
+ sharing and self.server_settings.has_key(try_CUPS_SERVER_REMOTE_ANY))
1962
+ self.setDataButtonState()
1964
+ def save_serversettings(self):
1965
+ setting_dict = self.server_settings.copy()
1966
+ for widget, setting in [
1967
+ (self.ui.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS),
1968
+ (self.ui.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS),
1969
+ (self.ui.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY),
1970
+ (self.ui.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN),
1971
+ (self.ui.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY),
1972
+ (self.ui.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]:
1973
+ if not self.server_settings.has_key(setting): continue
1974
+ setting_dict[setting] = str(int(widget.isChecked()))
1976
+ self.cups.adminSetServerSettings(setting_dict)
1977
+ except cups.IPPError, (e, m):
1978
+ self.show_IPP_Error(e, m)
1980
+ except RuntimeError, s:
1981
+ self.show_IPP_Error(None, s)
1983
+ self.changed = set()
1984
+ self.setDataButtonState()
1985
+ time.sleep(1) # give the server a chance to process our request
1987
+ # Now reconnect, in case the server needed to reload.
1990
+ # Refresh the server settings in case they have changed in the
1993
+ self.fillServerTab()
1995
+ nonfatalException()
1997
+ # ====================================================================
1998
+ # == New Printer Dialog ==============================================
1999
+ # ====================================================================
2002
+ def on_new_printer_activate(self):
2003
+ self.ui.setCursor(Qt.WaitCursor)
2004
+ self.newPrinterGUI.init("printer")
2005
+ self.ui.setCursor(Qt.ArrowCursor)
2008
+ def on_new_class_activate(self):
2009
+ self.ui.setCursor(Qt.WaitCursor)
2010
+ self.newPrinterGUI.init("class")
2011
+ self.ui.setCursor(Qt.ArrowCursor)
2013
+ @pyqtSignature("")
2014
+ def on_btnSelectDevice_clicked(self):
2015
+ self.newPrinterGUI.init("device")
2017
+ @pyqtSignature("")
2018
+ def on_btnChangePPD_clicked(self):
2019
+ self.ui.setCursor(Qt.WaitCursor)
2020
+ self.newPrinterGUI.init("ppd")
2021
+ self.ui.setCursor(Qt.ArrowCursor)
2023
+ def checkNPName(self, name):
2024
+ if not name: return False
2025
+ name = name.lower()
2026
+ for printer in self.printers.values():
2027
+ if not printer.discovered and printer.name.lower()==name:
2031
+ def makeNameUnique(self, name):
2032
+ """Make a suggested queue name valid and unique."""
2033
+ name = name.replace (" ", "_")
2034
+ name = name.replace ("/", "_")
2035
+ name = name.replace ("#", "_")
2036
+ if not self.checkNPName (name):
2038
+ while not self.checkNPName (name + str (suffix)):
2042
+ name += str (suffix)
2046
+ ## Watcher interface helpers
2048
+ @pyqtSignature("")
2049
+ def on_btnRevert_clicked(self):
2050
+ self.changed = set() # avoid asking the user
2051
+ self.on_tvMainList_cursor_changed()
2053
+ @pyqtSignature("")
2054
+ def on_btnPrinterPropertiesApply_clicked(self):
2055
+ err = self.printer_properties_response()
2057
+ self.populateList()
2059
+ nonfatalException()
2061
+ def show_IPP_Error(self, exception, message):
2062
+ if exception == cups.IPP_NOT_AUTHORIZED:
2063
+ KMessageBox.error(self, i18n('The password may be incorrect.'), i18n('Not authorized'))
2065
+ KMessageBox.error(self, i18n("There was an error during the CUPS " "operation: '%1'.", message),
2066
+ i18n('CUPS server error'))
2068
+ def show_HTTP_Error(self, status):
2069
+ if (status == cups.HTTP_UNAUTHORIZED or
2070
+ status == cups.HTTP_FORBIDDEN):
2072
+ KMessageBox.error(self,i18n('The password may be incorrect, or the '
2073
+ 'server may be configured to deny '
2074
+ 'remote administration.'),
2075
+ i18n('Not authorized') )
2077
+ if status == cups.HTTP_BAD_REQUEST:
2078
+ msg = i18nc("HTTP error", "Bad request")
2079
+ elif status == cups.HTTP_NOT_FOUND:
2080
+ msg = i18nc("HTTP error", "Not found")
2081
+ elif status == cups.HTTP_REQUEST_TIMEOUT:
2082
+ msg = i18nc("HTTP error", "Request timeout")
2083
+ elif status == cups.HTTP_UPGRADE_REQUIRED:
2084
+ msg = i18nc("HTTP error", "Upgrade required")
2085
+ elif status == cups.HTTP_SERVER_ERROR:
2086
+ msg = i18nc("HTTP error", "Server error")
2087
+ elif status == -1:
2088
+ msg = i18nc("HTTP error", "Not connected")
2090
+ msg = i18nc("HTTP error", "status %1", status)
2092
+ KMessageBox.error(self, i18n("There was an HTTP error: %1.", msg), i18n('CUPS server error'))
2094
+ def getSelectedItem(self):
2095
+ return unicode(self.mainListSelectedName), unicode(self.mainListSelectedType)
2097
+ items = self.mainlist.selectedItems()
2098
+ if len(items) < 1:
2099
+ return ("", 'None')
2101
+ name = item.text(0)
2102
+ type = item.text(1)
2103
+ name = str(name).decode ('utf-8')
2104
+ return name.strip(), type
2107
+ def reconnect (self):
2108
+ """Reconnect to CUPS after the server has reloaded."""
2109
+ # libcups would handle the reconnection if we just told it to
2110
+ # do something, for example fetching a list of classes.
2111
+ # However, our local authentication certificate would be
2112
+ # invalidated by a server restart, so it is better for us to
2113
+ # handle the reconnection ourselves.
2117
+ self.setConnected()
2119
+ cups.setServer(self.connect_server)
2120
+ cups.setUser(self.connect_user)
2122
+ while attempt <= 5:
2124
+ self.cups = cups.Connection ()
2126
+ except RuntimeError:
2127
+ # Connection failed.
2131
+ self.setConnected()
2132
+ self.passwd_retry = False
2134
+ def updatePrinterProperties(self):
2135
+ debugprint ("update printer properties")
2136
+ printer = self.printer
2137
+ self.ui.lblPMakeModel.setText(printer.make_and_model)
2138
+ state = self.printer_states.get (printer.state, i18nc("Printer state", "Unknown"))[:]
2139
+ reason = printer.other_attributes.get ('printer-state-message', '')
2140
+ if len (reason) > 0:
2141
+ state += ' - ' + reason
2142
+ self.ui.lblPState.setText(state)
2143
+ if len (self.changed) == 0:
2144
+ debugprint ("no changes yet: full printer properties update")
2147
+ self.ui.chkPEnabled.setEnabled(printer.enabled)
2148
+ self.ui.chkPAccepting.setEnabled(not printer.rejecting)
2149
+ self.ui.chkPShared.setEnabled(printer.is_shared)
2152
+ self.fillComboBox(self.ui.cmbPStartBanner,
2153
+ printer.job_sheets_supported,
2154
+ printer.job_sheet_start),
2155
+ self.fillComboBox(self.ui.cmbPEndBanner, printer.job_sheets_supported,
2156
+ printer.job_sheet_end)
2158
+#FIXME Not implemented in current UI
2160
+ #self.fillComboBox(self.cmbPErrorPolicy,
2161
+ #printer.error_policy_supported,
2162
+ #printer.error_policy)
2163
+ #self.fillComboBox(self.cmbPOperationPolicy,
2164
+ #printer.op_policy_supported,
2165
+ #printer.op_policy)
2169
+ self.ui.rbtnPAllow.setChecked(printer.default_allow)
2170
+ self.ui.rbtnPDeny.setChecked(not printer.default_allow)
2171
+ self.setPUsers(printer.except_users)
2174
+ def setTestButton (self, printer):
2175
+ if printer.testsQueued ():
2176
+ self.test_button_cancels = True
2177
+ self.ui.btnPrintTestPage.setText(i18n('Cancel Tests'))
2178
+ self.ui.btnPrintTestPage.setEnabled(True)
2180
+ self.test_button_cancels = False
2181
+ self.ui.btnPrintTestPage.setText(i18n('Print Test Page'))
2182
+ self.setDataButtonState()
2184
+ def getCurrentClassMembers(self, listwidget):
2185
+ count = listwidget.count()
2187
+ for i in range(count):
2188
+ result.append(listwidget.item(i).text())
2192
+ def moveClassMembers(self, treeview_from, treeview_to):
2193
+ rows = treeview_from.selectedItems()
2195
+ treeview_from.takeItem(treeview_from.row(row))
2196
+ treeview_to.addItem(row)
2199
+ def cupsPasswdCallback(self, querystring):
2201
+ if self.passwd_retry or len(self.password) == 0:
2202
+ waiting = self.WaitWindow.get_property('visible')
2204
+ self.WaitWindow.hide ()
2205
+ self.lblPasswordPrompt.set_label (self.prompt_primary +
2207
+ self.PasswordDialog.set_transient_for (self.MainWindow)
2208
+ self.entPasswd.grab_focus ()
2210
+ result = self.PasswordDialog.run()
2211
+ self.PasswordDialog.hide()
2213
+ self.WaitWindow.show ()
2214
+ while gtk.events_pending ():
2215
+ gtk.main_iteration ()
2216
+ if result == gtk.RESPONSE_OK:
2217
+ self.password = self.entPasswd.get_text()
2219
+ self.password = ''
2220
+ self.passwd_retry = False
2222
+ self.passwd_retry = True
2223
+ return self.password
2226
+class NewPrinterGUI(QDialog):
2228
+ new_printer_device_tabs = {
2229
+ "parallel" : 0, # empty tab
2244
+ ntbkNewPrinterPages = {
2249
+ "class-members" : 4,
2250
+ "downloadable" : -1,
2253
+ def __init__(self, mainapp):
2254
+ QDialog.__init__(self, mainapp)
2255
+ self.mainapp = mainapp
2256
+ self.language = mainapp.language
2257
+ self.dialog_mode = ""
2259
+ self.WaitWindow = QMessageBox(self.mainapp)
2260
+ self.WaitWindow.setStandardButtons(QMessageBox.NoButton)
2262
+ uic.loadUi(APPDIR + "/" + "new-printer.ui", self)
2264
+ self.btnNPBack.setIcon(KIcon("go-previous"))
2265
+ self.btnNPForward.setIcon(KIcon("go-next"))
2266
+ self.btnNPCancel.setIcon(KIcon("dialog-cancel"))
2267
+ self.btnNPApply.setIcon(KIcon("dialog-ok"))
2268
+ self.btnNCAddMember.setIcon(KIcon("arrow-left"))
2269
+ self.btnNCDelMember.setIcon(KIcon("arrow-right"))
2271
+ self.connect(self.tvNPDevices, SIGNAL("itemSelectionChanged()"), self.on_tvNPDevices_cursor_changed)
2272
+ self.connect(self.tvNPMakes, SIGNAL("itemSelectionChanged()"), self.on_tvNPMakes_cursor_changed)
2273
+ self.connect(self.tvNPModels, SIGNAL("itemSelectionChanged()"), self.on_tvNPModels_cursor_changed)
2274
+ self.connect(self.entNPTDevice, SIGNAL("textEdited(const QString&)"), self.on_entNPTDevice_changed)
2275
+# self.connect(self.entNPTIPPHostname, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPHostname_changed)
2276
+# self.connect(self.entNPTIPPQueuename, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPQueuename_changed)
2277
+ self.connect(self.entSMBURI, SIGNAL("textEdited(const QString&)"), self.on_entSMBURI_changed)
2278
+ self.rbtnSMBAuthPrompt.setChecked(True)
2279
+ self.on_rbtnSMBAuthSet_toggled(False)
2280
+ self.connect(self.rbtnSMBAuthSet, SIGNAL("toggled(bool)"), self.on_rbtnSMBAuthSet_toggled)
2281
+ self.rbtnNPFoomatic.setChecked(True)
2282
+ self.connect(self.rbtnNPFoomatic, SIGNAL("toggled(bool)"), self.on_rbtnNPFoomatic_toggled)
2283
+ self.connect(self.filechooserPPDButton, SIGNAL("clicked()"),self.on_filechooserPPDButton)
2284
+ self.options = {} # keyword -> Option object
2285
+ self.changed = set()
2286
+ self.conflicts = set()
2289
+ # Synchronisation objects.
2290
+ self.ppds_lock = thread.allocate_lock()
2291
+ self.devices_lock = thread.allocate_lock()
2292
+ self.smb_lock = thread.allocate_lock()
2293
+ self.ipp_lock = thread.allocate_lock()
2294
+ self.drivers_lock = thread.allocate_lock()
2296
+ #self.connect(self.btnNCAddMember, SIGNAL("clicked()"), self.slot_btnNCAddMember_clicked)
2297
+ #self.connect(self.btnNCDelMember, SIGNAL("clicked()"), self.slot_btnNCDelMember_clicked)
2299
+ # Optionally disable downloadable driver support.
2300
+ #if not config.DOWNLOADABLE_DRIVER_SUPPORT:
2302
+ self.rbtnNPDownloadableDriverSearch.setEnabled(False)
2303
+ self.downloadableDriverSearchFrame.hide()
2306
+ # Set up OpenPrinting widgets.
2307
+ self.openprinting = openprinting.OpenPrinting ()
2308
+ self.openprinting_query_handle = None
2309
+ combobox = self.cmbNPDownloadableDriverFoundPrinters
2310
+ cell = gtk.CellRendererText()
2311
+ combobox.pack_start (cell, True)
2312
+ combobox.add_attribute(cell, 'text', 0)
2315
+ self.smb_store = gtk.TreeStore (str, # host or share
2317
+ gobject.TYPE_PYOBJECT, # domain dict
2318
+ gobject.TYPE_PYOBJECT) # host dict
2319
+ self.tvSMBBrowser.set_model (self.smb_store)
2320
+ self.smb_store.set_sort_column_id (0, gtk.SORT_ASCENDING)
2322
+ # SMB list columns
2323
+ col = gtk.TreeViewColumn (_("Share"), gtk.CellRendererText (),
2325
+ col.set_resizable (True)
2326
+ col.set_sort_column_id (0)
2327
+ self.tvSMBBrowser.append_column (col)
2329
+ col = gtk.TreeViewColumn (_("Comment"), gtk.CellRendererText (),
2331
+ self.tvSMBBrowser.append_column (col)
2332
+ slct = self.tvSMBBrowser.get_selection ()
2333
+ slct.set_select_function (self.smb_select_function)
2335
+ self.SMBBrowseDialog.set_transient_for(self.NewPrinterWindow)
2338
+ self.ipp_store = gtk.TreeStore (str, # queue
2340
+ gobject.TYPE_PYOBJECT) # dict
2341
+ self.tvIPPBrowser.set_model (self.ipp_store)
2342
+ self.ipp_store.set_sort_column_id (0, gtk.SORT_ASCENDING)
2344
+ # IPP list columns
2345
+ col = gtk.TreeViewColumn (_("Queue"), gtk.CellRendererText (),
2347
+ col.set_resizable (True)
2348
+ col.set_sort_column_id (0)
2349
+ self.tvIPPBrowser.append_column (col)
2351
+ col = gtk.TreeViewColumn (_("Location"), gtk.CellRendererText (),
2353
+ self.tvIPPBrowser.append_column (col)
2354
+ self.IPPBrowseDialog.set_transient_for(self.NewPrinterWindow)
2356
+ self.tvNPDriversTooltips = TreeViewTooltips(self.tvNPDrivers, self.NPDriversTooltips)
2358
+ ppd_filter = gtk.FileFilter()
2359
+ ppd_filter.set_name(_("PostScript Printer Description files (*.ppd, *.PPD, *.ppd.gz, *.PPD.gz, *.PPD.GZ)"))
2360
+ ppd_filter.add_pattern("*.ppd")
2361
+ ppd_filter.add_pattern("*.PPD")
2362
+ ppd_filter.add_pattern("*.ppd.gz")
2363
+ ppd_filter.add_pattern("*.PPD.gz")
2364
+ ppd_filter.add_pattern("*.PPD.GZ")
2365
+ self.filechooserPPD.add_filter(ppd_filter)
2367
+ ppd_filter = gtk.FileFilter()
2368
+ ppd_filter.set_name(_("All files (*)"))
2369
+ ppd_filter.add_pattern("*")
2370
+ self.filechooserPPD.add_filter(ppd_filter)
2372
+ self.xml.signal_autoconnect(self)
2375
+ #FIXME hide bits which are not yet implemented
2376
+ self.btnSMBBrowse.hide()
2377
+ self.btnSMBVerify.hide()
2378
+ self.btnNPTLpdProbe.hide()
2380
+ def option_changed(self, option):
2381
+ if option.is_changed():
2382
+ self.changed.add(option)
2384
+ self.changed.discard(option)
2386
+ if option.conflicts:
2387
+ self.conflicts.add(option)
2389
+ self.conflicts.discard(option)
2390
+ self.setDataButtonState()
2394
+ def setDataButtonState(self):
2395
+ self.btnNPForward.setEnabled(not bool(self.conflicts))
2397
+ def init(self, dialog_mode):
2398
+ self.dialog_mode = dialog_mode
2399
+ self.options = {} # keyword -> Option object
2400
+ self.changed = set()
2401
+ self.conflicts = set()
2404
+ combobox = self.cmbNPDownloadableDriverFoundPrinters
2405
+ combobox.set_model (gtk.ListStore (str, str))
2406
+ self.entNPDownloadableDriverSearch.set_text ('')
2407
+ button = self.btnNPDownloadableDriverSearch
2408
+ label = button.get_children ()[0].get_children ()[0].get_children ()[1]
2409
+ self.btnNPDownloadableDriverSearch_label = label
2410
+ label.set_text (_("Search"))
2413
+ if self.dialog_mode == "printer":
2414
+ self.setWindowTitle(i18n("New Printer"))
2415
+ # Start on devices page (1, not 0)
2416
+ self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"])
2417
+ self.fillDeviceTab()
2418
+ self.on_rbtnNPFoomatic_toggled()
2419
+ # Start fetching information from CUPS in the background
2420
+ self.new_printer_PPDs_loaded = False
2422
+ elif self.dialog_mode == "class":
2423
+ self.setWindowTitle(i18n("New Class"))
2424
+ self.fillNewClassMembers()
2425
+ # Start on name page
2426
+ self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["name"])
2427
+ elif self.dialog_mode == "device":
2428
+ self.setWindowTitle(i18n("Change Device URI"))
2429
+ self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"])
2430
+ self.queryDevices ()
2432
+ self.fillDeviceTab(self.mainapp.printer.device_uri)
2433
+ # Start fetching information from CUPS in the background
2434
+ self.new_printer_PPDs_loaded = False
2436
+ elif self.dialog_mode == "ppd":
2437
+ self.setWindowTitle(i18n("Change Driver"))
2438
+ self.ntbkNewPrinter.setCurrentIndex(2)
2439
+ self.on_rbtnNPFoomatic_toggled()
2441
+ self.auto_model = ""
2442
+ ppd = self.mainapp.ppd
2444
+ attr = ppd.findAttr("Manufacturer")
2446
+ self.auto_make = attr.value
2448
+ self.auto_make = ""
2449
+ attr = ppd.findAttr("ModelName")
2450
+ if not attr: attr = ppd.findAttr("ShortNickName")
2451
+ if not attr: attr = ppd.findAttr("NickName")
2453
+ if attr.value.startswith(self.auto_make):
2454
+ self.auto_model = attr.value[len(self.auto_make):].strip ()
2457
+ self.auto_model = attr.value.split(" ", 1)[1]
2458
+ except IndexError:
2459
+ self.auto_model = ""
2461
+ self.auto_model = ""
2463
+ # Special CUPS names for a raw queue.
2464
+ self.auto_make = 'Raw'
2465
+ self.auto_model = 'Queue'
2468
+ self.fillMakeList()
2470
+ if self.dialog_mode in ("printer", "class"):
2471
+ self.entNPName.setText (self.mainapp.makeNameUnique(self.dialog_mode))
2472
+ #FIXMEself.entNPName.grab_focus()
2473
+ for widget in [self.entNPLocation,
2474
+ self.entNPDescription]: #,
2475
+ #self.entSMBURI, self.entSMBUsername,
2476
+ #self.entSMBPassword, self.entNPTDirectJetHostname]:
2477
+ widget.setText('')
2480
+ p = os.popen ('/bin/hostname', 'r')
2481
+ hostname = p.read ().strip ()
2483
+ self.entNPLocation.setText(hostname)
2485
+ nonfatalException ()
2487
+ self.entNPTDirectJetPort.setText('9100')
2488
+ self.setNPButtons()
2493
+ def queryPPDs(self):
2494
+ debugprint ("queryPPDs")
2495
+ if not self.ppds_lock.acquire(0):
2496
+ debugprint ("queryPPDs: in progress")
2498
+ debugprint ("Lock acquired for PPDs thread")
2500
+ self.getPPDs_thread(self.language[0])
2501
+ debugprint ("PPDs thread started")
2503
+ def getPPDs_thread(self, language):
2505
+ debugprint ("Connecting (PPDs)")
2506
+ cups.setServer (self.mainapp.connect_server)
2507
+ cups.setUser (self.mainapp.connect_user)
2508
+ cups.setPasswordCB (self.mainapp.cupsPasswdCallback)
2509
+ # cups.setEncryption (...)
2510
+ c = cups.Connection ()
2511
+ debugprint ("Fetching PPDs")
2512
+ ppds_dict = c.getPPDs()
2513
+ self.ppds_result = cupshelpers.ppds.PPDs(ppds_dict,
2514
+ language=language)
2515
+ debugprint ("Closing connection (PPDs)")
2517
+ except cups.IPPError, (e, msg):
2518
+ self.ppds_result = cups.IPPError (e, msg)
2520
+ nonfatalException()
2521
+ self.ppds_result = { }
2523
+ debugprint ("Releasing PPDs lock")
2524
+ self.ppds_lock.release ()
2526
+ def fetchPPDs(self, parent=None):
2527
+ debugprint ("fetchPPDs")
2531
+ # Keep the UI refreshed while we wait for the devices to load.
2533
+ while (self.ppds_lock.locked()):
2536
+ self.WaitWindow.setText(i18n('<b>Searching</b>') + '<br /><br />' +
2537
+ i18n('Searching for drivers'))
2538
+ self.WaitWindow.show ()
2540
+ KApplication.processEvents()
2545
+ self.WaitWindow.hide ()
2547
+ debugprint ("Got PPDs")
2548
+ result = self.ppds_result # atomic operation
2549
+ if isinstance (result, cups.IPPError):
2550
+ # Propagate exception.
2554
+ def loadPPDs(self, parent=None):
2558
+ self.ppds = self.fetchPPDs (parent=parent)
2561
+ def dropPPDs(self):
2569
+ def fillNewClassMembers(self):
2570
+ self.tvNCMembers.clear()
2571
+ self.tvNCNotMembers.clear()
2572
+ for printer in self.mainapp.printers.itervalues():
2573
+ self.tvNCNotMembers.addItem(printer.name)
2575
+ @pyqtSignature("")
2576
+ def on_btnNCAddMember_clicked(self):
2577
+ self.mainapp.moveClassMembers(self.tvNCNotMembers, self.tvNCMembers)
2578
+ self.btnNPApply.setEnabled(
2579
+ bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
2581
+ @pyqtSignature("")
2582
+ def on_btnNCDelMember_clicked(self):
2583
+ self.mainapp.moveClassMembers(self.tvNCMembers, self.tvNCNotMembers)
2584
+ self.btnNPApply.setEnabled(
2585
+ bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
2587
+ @pyqtSignature("")
2588
+ def on_btnNPBack_clicked(self):
2589
+ self.nextNPTab(-1)
2591
+ @pyqtSignature("")
2592
+ def on_btnNPForward_clicked(self):
2595
+ def nextNPTab(self, step=1):
2596
+ self.setCursor(Qt.WaitCursor)
2597
+ page_nr = self.ntbkNewPrinter.currentIndex()
2599
+ if self.dialog_mode == "class":
2600
+ #order = [0, 4, 5]
2601
+ order = [self.ntbkNewPrinterPages["name"], self.ntbkNewPrinterPages["class-members"]]
2602
+ elif self.dialog_mode == "printer":
2603
+ if page_nr == 1: # Device (first page)
2604
+ # Choose an appropriate name.
2607
+ if self.device.id:
2608
+ name = self.device.id_dict["MDL"]
2609
+ name = self.mainapp.makeNameUnique (name)
2610
+ self.entNPName.setText(name)
2612
+ nonfatalException ()
2613
+ self.auto_make, self.auto_model = None, None
2614
+ self.device.uri = self.getDeviceURI()
2615
+ if self.device.type in ("socket", "lpd", "ipp", "bluetooth"):
2616
+ host = self.getNetworkPrinterMakeModel(self.device)
2619
+ faxuri = self.get_hplip_uri_for_network_printer(host,
2622
+ #create message string
2623
+ q = i18n("This printer supports both "
2624
+ "printing and sending faxes. "
2625
+ "Which functionality should be "
2626
+ "used for this queue?")
2628
+ #buttons need to be KGuiItem objects
2629
+ printer_button = KGuiItem(i18n("Printer"))
2630
+ fax_button = KGuiItem(i18n("Fax"))
2632
+ #This is a bit hackish. Essentially Printer is mapped to the Yes button, Fax to
2633
+ #the No button. KMessageBox doesn't seem to provide a version for 'This OR That'
2634
+ queue_type = KMessageBox.questionYesNo(self.NewPrinterWindow, q , 'Choose function', printer_button, fax_button)
2636
+ #test return value of messagebox Printer == 3, Fax == 4
2637
+ if (queue_type == 3):
2638
+ self.device.id_dict = \
2639
+ self.get_hpfax_device_id(faxuri)
2640
+ self.device.uri = faxuri
2641
+ self.auto_make = self.device.id_dict["MFG"]
2642
+ self.auto_model = self.device.id_dict["MDL"]
2643
+ self.device.id = "MFG:" + self.auto_make + \
2644
+ ";MDL:" + self.auto_model + \
2646
+ self.device.id_dict["DES"] + ";"
2647
+ uri = self.device.uri
2648
+ if uri and uri.startswith ("smb://"):
2649
+ uri = SMBURI (uri=uri[6:]).sanitize_uri ()
2651
+ # Try to access the PPD, in this case our detected IPP
2652
+ # printer is a queue on a remote CUPS server which is
2653
+ # not automatically set up on our local CUPS server
2654
+ # (for example DNS-SD broadcasted queue from Mac OS X)
2655
+ self.remotecupsqueue = None
2656
+ res = re.search ("ipp://(\S+(:\d+|))/printers/(\S+)", uri)
2658
+ resg = res.groups()
2660
+ conn = httplib.HTTPConnection(resg[0])
2661
+ conn.request("GET", "/printers/%s.ppd" % resg[2])
2662
+ resp = conn.getresponse()
2663
+ if resp.status == 200: self.remotecupsqueue = resg[2]
2665
+ debugprint("exception in getting remotecupsqueue")
2668
+ # We also want to fetch the printer-info and
2669
+ # printer-location attributes, to pre-fill those
2670
+ # fields for this new queue.
2671
+ oldserver = cups.getServer()
2672
+ oldport = cups.getPort()
2674
+ cups.setServer (resg[0])
2675
+ if len (resg[1]) > 0:
2676
+ cups.setPort (int (resg[1]))
2678
+ cups.setPort (631)
2680
+ c = cups.Connection ()
2681
+ r = ['printer-info', 'printer-location']
2682
+ attrs = c.getPrinterAttributes (uri=uri,
2683
+ requested_attributes=r)
2684
+ info = attrs.get ('printer-info', '')
2685
+ location = attrs.get ('printer-location', '')
2686
+ if len (info) > 0:
2687
+ self.entNPDescription.setText(info)
2688
+ if len (location) > 0:
2689
+ self.entNPLocation.setText(location)
2691
+ nonfatalException ()
2693
+ cups.setServer (oldserver)
2694
+ cups.setPort (oldport)
2696
+ if (not self.remotecupsqueue and
2697
+ not self.new_printer_PPDs_loaded):
2699
+ self.loadPPDs(self)
2700
+ except cups.IPPError, (e, msg):
2701
+ #self.ready (self)
2702
+ self.show_IPP_Error(e, msg)
2707
+ self.new_printer_PPDs_loaded = True
2711
+ if self.remotecupsqueue:
2712
+ # We have a remote CUPS queue, let the client queue
2713
+ # stay raw so that the driver on the server gets used
2715
+ self.ppd = ppdname
2716
+ name = self.remotecupsqueue
2717
+ name = self.mainapp.makeNameUnique (name)
2718
+ self.entNPName.setText(name)
2719
+ elif self.device.id:
2720
+ id_dict = self.device.id_dict
2721
+ (status, ppdname) = self.ppds.\
2722
+ getPPDNameFromDeviceID (id_dict["MFG"],
2728
+ (status, ppdname) = self.ppds.\
2729
+ getPPDNameFromDeviceID ("Generic",
2731
+ "Generic Printer",
2735
+ if ppdname and not self.remotecupsqueue:
2736
+ ppddict = self.ppds.getInfoFromPPDName (ppdname)
2737
+ make_model = ppddict['ppd-make-and-model']
2739
+ cupshelpers.ppds.ppdMakeModelSplit (make_model)
2740
+ self.auto_make = make
2741
+ self.auto_model = model
2743
+ nonfatalException ()
2744
+ if not self.remotecupsqueue:
2745
+ self.fillMakeList()
2746
+ elif page_nr == 3: # Model has been selected
2747
+ if not self.device.id:
2748
+ # Choose an appropriate name when no Device ID
2749
+ # is available, based on the model the user has
2752
+ items = self.tvNPModels.selectedItems()
2753
+ name = unicode(items[0].text())
2754
+ name = self.mainapp.makeNameUnique (name)
2755
+ self.entNPName.setText(name)
2757
+ nonfatalException ()
2759
+ ##self.ready (self.NewPrinterWindow)
2760
+ if self.remotecupsqueue:
2762
+ elif self.rbtnNPFoomatic.isChecked():
2763
+ order = [1, 2, 3, 6, 0]
2764
+ elif self.rbtnNPPPD.isChecked():
2765
+ order = [1, 2, 6, 0]
2767
+ # Downloadable driver
2768
+ order = [1, 2, 7, 6, 0]
2769
+ elif self.dialog_mode == "device":
2771
+ elif self.dialog_mode == "ppd":
2772
+ self.rbtnChangePPDasIs.setChecked(True)
2773
+ if self.rbtnNPFoomatic.isChecked():
2774
+ order = [2, 3, 5, 6]
2775
+ elif self.rbtnNPPPD.isChecked():
2778
+ # Downloadable driver
2779
+ order = [2, 7, 5, 6]
2781
+ next_page_nr = order[order.index(page_nr)+step]
2783
+ # fill Installable Options tab
2784
+ if next_page_nr == 6 and step > 0:
2785
+ #TODO Prepare Installable Options screen.
2786
+ self.ppd = self.getNPPPD()
2788
+ if next_page_nr == 6:
2789
+ # Prepare Installable Options screen.
2790
+ if isinstance(self.ppd, cups.PPD):
2791
+ self.fillNPInstallableOptions()
2793
+ self.installable_options = None
2794
+ # Put a label there explaining why the page is empty.
2797
+ self.fillNPInstallableOptions()
2800
+ # step over if empty and not in PPD mode
2801
+ if self.dialog_mode != "ppd" and not self.installable_options:
2802
+ next_page_nr = order[order.index(next_page_nr)+1]
2804
+ next_page_nr = order[order.index(next_page_nr)+1]
2805
+ self.installable_options = False
2806
+ # Step over empty Installable Options tab
2807
+ if next_page_nr == 6 and not self.installable_options and step<0:
2808
+ next_page_nr = order[order.index(next_page_nr)-1]
2810
+ if next_page_nr == 7: # About to show downloadable drivers
2811
+ if self.drivers_lock.locked ():
2812
+ # Still searching for drivers.
2813
+ self.lblWait.set_markup ('<span size="larger">' +
2814
+ i18n('<b>Searching</b>') + '</span>\n\n' +
2815
+ i18n('Searching for drivers'))
2816
+ self.WaitWindow.set_transient_for (self.NewPrinterWindow)
2817
+ self.WaitWindow.show ()
2819
+ # Keep the UI refreshed while we wait for the drivers
2820
+ # query to complete.
2821
+ while self.drivers_lock.locked ():
2822
+ self.mainapp.busy(self)
2825
+ self.ready (self.NewPrinterWindow)
2826
+ self.WaitWindow.hide ()
2828
+ self.fillDownloadableDrivers()
2830
+ self.ntbkNewPrinter.setCurrentIndex(next_page_nr)
2832
+ self.setNPButtons()
2833
+ self.setCursor(Qt.ArrowCursor)
2835
+ def setNPButtons(self):
2836
+ nr = self.ntbkNewPrinter.currentIndex()
2838
+ if self.dialog_mode == "device":
2839
+ self.btnNPBack.hide()
2840
+ self.btnNPForward.hide()
2841
+ self.btnNPApply.show()
2842
+ uri = self.getDeviceURI ()
2843
+ self.btnNPApply.setEnabled(validDeviceURI (uri))
2846
+ if self.dialog_mode == "ppd":
2847
+ if nr == 5: # Apply
2848
+ if not self.installable_options:
2849
+ # There are no installable options, so this is the
2851
+ debugprint ("No installable options")
2852
+ self.btnNPForward.hide ()
2853
+ self.btnNPApply.show ()
2855
+ self.btnNPForward.show ()
2856
+ self.btnNPApply.hide ()
2859
+ self.btnNPForward.hide()
2860
+ self.btnNPApply.show()
2863
+ self.btnNPForward.show()
2864
+ self.btnNPApply.hide()
2866
+ self.btnNPBack.hide()
2867
+ self.btnNPForward.show()
2868
+ downloadable_selected = False
2869
+ if self.rbtnNPDownloadableDriverSearch.isChecked():
2870
+ combobox = self.cmbNPDownloadableDriverFoundPrinters
2871
+ iter = combobox.get_active_iter () #FIXME
2872
+ if iter and combobox.get_model ().get_value (iter, 1):
2873
+ downloadable_selected = True
2875
+ self.btnNPForward.setEnabled(bool(
2876
+ self.rbtnNPFoomatic.isChecked() or
2877
+ not self.filechooserPPD.text().isEmpty() or
2878
+ downloadable_selected))
2881
+ self.btnNPBack.show()
2885
+ if nr == 1: # Device
2888
+ uri = self.getDeviceURI ()
2889
+ valid = validDeviceURI (uri)
2892
+ self.btnNPForward.setEnabled(valid)
2893
+ self.btnNPBack.hide ()
2895
+ self.btnNPBack.show()
2897
+ self.btnNPForward.show()
2898
+ self.btnNPApply.hide()
2900
+ if nr == 0: # Name
2901
+ self.btnNPBack.show()
2902
+ if self.dialog_mode == "class":
2903
+ self.btnNPForward.setEnabled(True)
2904
+ if self.dialog_mode == "printer":
2905
+ self.btnNPForward.hide()
2906
+ self.btnNPApply.show()
2907
+ self.btnNPApply.setEnabled(
2908
+ self.mainapp.checkNPName(unicode(self.entNPName.text())))
2909
+ if nr == 2: # Make/PPD file
2910
+ downloadable_selected = False
2911
+ if self.rbtnNPDownloadableDriverSearch.isChecked():
2912
+ combobox = self.cmbNPDownloadableDriverFoundPrinters
2913
+ iter = combobox.get_active_iter () #FIXME
2914
+ if iter and combobox.get_model ().get_value (iter, 1):
2915
+ downloadable_selected = True
2917
+ self.btnNPForward.setEnabled(bool(
2918
+ self.rbtnNPFoomatic.isChecked() or
2919
+ not self.filechooserPPD.text().isEmpty() or
2920
+ downloadable_selected))
2922
+ if nr == 3: # Model/Driver
2923
+ iter = self.tvNPDrivers.currentItem()
2924
+ self.btnNPForward.setEnabled(bool(iter))
2925
+ if nr == 4: # Class Members
2926
+ self.btnNPForward.hide()
2927
+ self.btnNPApply.show()
2928
+ self.btnNPApply.setEnabled(self.tvNCMembers.count() > 0)
2929
+ if nr == 7: # Downloadable drivers
2930
+ if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1: #FIXME
2931
+ accepted = self.rbtnNPDownloadLicenseYes.get_active ()
2933
+ treeview = self.tvNPDownloadableDrivers
2934
+ model, iter = treeview.get_selection ().get_selected ()
2935
+ accepted = (iter != None)
2937
+ self.btnNPForward.set_sensitive(accepted)
2939
+ def on_filechooserPPDButton(self):
2940
+ home = QDir.homePath()
2941
+ url = KUrl.fromPath(home)
2942
+ filename = KFileDialog.getOpenFileName(url, '*.ppd', self)
2943
+ self.filechooserPPD.setText(filename)
2944
+ self.btnNPForward.setEnabled(True)
2946
+ def getDevices_thread(self):
2948
+ debugprint ("Connecting (devices)")
2949
+ cups.setServer (self.mainapp.connect_server)
2950
+ #cups.setUser (self.mainapp.connect_user)
2951
+ cups.setUser ("jr")
2952
+ cups.setPasswordCB (self.mainapp.cupsPasswdCallback)
2953
+ # cups.setEncryption (...)
2954
+ c = cups.Connection ()
2955
+ debugprint ("Fetching devices")
2956
+ self.devices_result = cupshelpers.getDevices(c)
2957
+ except cups.IPPError, (e, msg):
2958
+ self.devices_result = cups.IPPError (e, msg)
2960
+ debugprint ("Exception in getDevices_thread")
2961
+ self.devices_result = {}
2964
+ debugprint ("Closing connection (devices)")
2969
+ debugprint ("Releasing devices lock")
2970
+ self.devices_lock.release ()
2974
+ def queryDevices(self):
2975
+ if not self.devices_lock.acquire(0):
2976
+ debugprint ("queryDevices: in progress")
2978
+ debugprint ("Lock acquired for devices thread")
2979
+ self.getDevices_thread()
2980
+ debugprint ("Devices thread started")
2982
+ def fetchDevices(self, parent=None):
2983
+ debugprint ("fetchDevices")
2984
+ self.queryDevices ()
2987
+ # Keep the UI refreshed while we wait for the devices to load.
2989
+ #crashes kcm here as soon as this loop exits
2990
+ while (self.devices_lock.locked()):
2993
+ self.WaitWindow.setText (i18n('<b>Searching</b>') + '<br/><br/>' +
2994
+ i18n('Searching for printers'))
2996
+ parent = self.mainapp
2997
+ self.WaitWindow.show ()
2999
+ KApplication.processEvents()
3004
+ #self.WaitWindow.hide()
3006
+ debugprint ("Got devices")
3008
+ result = self.devices_result # atomic operation
3010
+ if isinstance (result, cups.IPPError):
3011
+ # Propagate exception.
3015
+ def get_hpfax_device_id(self, faxuri):
3016
+ os.environ["URI"] = faxuri
3017
+ cmd = 'LC_ALL=C DISPLAY= hp-info -d "${URI}"'
3018
+ debugprint (faxuri + ": " + cmd)
3020
+ p = subprocess.Popen (cmd, shell=True,
3021
+ stdin=file("/dev/null"),
3022
+ stdout=subprocess.PIPE,
3023
+ stderr=subprocess.PIPE)
3024
+ (stdout, stderr) = p.communicate ()
3026
+ # Problem executing command.
3029
+ for line in stdout.split ("\n"):
3030
+ if line.find ("fax-type") == -1:
3033
+ res = re.search ("(\d+)", line)
3035
+ resg = res.groups()
3037
+ if faxtype >= 0: break
3040
+ elif faxtype == 4:
3041
+ return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax 2;DES:HP Fax 2;')
3043
+ return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax;DES:HP Fax;')
3045
+ def get_hplip_uri_for_network_printer(self, host, mode):
3046
+ os.environ["HOST"] = host
3047
+ if mode == "print": mod = "-c"
3048
+ elif mode == "fax": mod = "-f"
3050
+ cmd = 'hp-makeuri ' + mod + ' "${HOST}"'
3051
+ debugprint (host + ": " + cmd)
3054
+ p = subprocess.Popen (cmd, shell=True,
3055
+ stdin=file("/dev/null"),
3056
+ stdout=subprocess.PIPE,
3057
+ stderr=subprocess.PIPE)
3058
+ (stdout, stderr) = p.communicate ()
3060
+ # Problem executing command.
3063
+ uri = stdout.strip ()
3066
+ def getNetworkPrinterMakeModel(self, device):
3067
+ # Determine host name/IP
3069
+ s = device.uri.find ("://")
3072
+ e = device.uri[s:].find (":")
3073
+ if e == -1: e = device.uri[s:].find ("/")
3074
+ if e == -1: e = device.uri[s:].find ("?")
3075
+ if e == -1: e = len (device.uri)
3076
+ host = device.uri[s:s+e]
3077
+ # Try to get make and model via SNMP
3079
+ os.environ["HOST"] = host
3080
+ cmd = '/usr/lib/cups/backend/snmp "${HOST}"'
3081
+ debugprint (host + ": " + cmd)
3084
+ p = subprocess.Popen (cmd, shell=True,
3085
+ stdin=file("/dev/null"),
3086
+ stdout=subprocess.PIPE,
3087
+ stderr=subprocess.PIPE)
3088
+ (stdout, stderr) = p.communicate ()
3090
+ # Problem executing command.
3093
+ if stdout != None:
3094
+ mm = re.sub("^\s*\S+\s+\S+\s+\"", "", stdout)
3095
+ mm = re.sub("\"\s+.*$", "", mm)
3096
+ if mm and mm != "": device.make_and_model = mm
3097
+ # Extract make and model and create a pseudo device ID, so
3098
+ # that a PPD/driver can be assigned to the device
3099
+ make_and_model = None
3100
+ if len (device.make_and_model) > 7:
3101
+ make_and_model = device.make_and_model
3102
+ elif len (device.info) > 7:
3103
+ make_and_model = device.info
3104
+ make_and_model = re.sub("\s*(\(|\d+\.\d+\.\d+\.\d+).*$", "", make_and_model)
3105
+ if make_and_model and not device.id:
3108
+ (mk, md) = cupshelpers.ppds.ppdMakeModelSplit (make_and_model)
3109
+ device.id = "MFG:" + mk + ";MDL:" + md + ";DES:" + mk + " " + md + ";"
3110
+ device.id_dict = cupshelpers.parseDeviceID (device.id)
3111
+ # Check whether the device is supported by HPLIP and replace
3112
+ # its URI by an HPLIP URI
3114
+ hplipuri = self.get_hplip_uri_for_network_printer(host, "print")
3116
+ device.uri = hplipuri
3117
+ s = hplipuri.find ("/usb/")
3118
+ if s == -1: s = hplipuri.find ("/par/")
3119
+ if s == -1: s = hplipuri.find ("/net/")
3122
+ e = hplipuri[s:].find ("?")
3123
+ if e == -1: e = len (hplipuri)
3124
+ mdl = hplipuri[s:s+e].replace ("_", " ")
3125
+ if mdl.startswith ("hp ") or mdl.startswith ("HP "):
3127
+ device.make_and_model = "HP " + mdl
3128
+ device.id = "MFG:HP;MDL:" + mdl + ";DES:HP " + mdl + ";"
3129
+ device.id_dict = cupshelpers.parseDeviceID (device.id)
3130
+ # Return the host name/IP for further actions
3133
+ def fillDeviceTab(self, current_uri=None, query=True):
3136
+ devices = self.fetchDevices()
3137
+ except cups.IPPError, (e, msg):
3138
+ self.show_IPP_Error(e, msg)
3141
+ nonfatalException()
3145
+ if devices.has_key (current_uri):
3146
+ current = devices.pop(current_uri)
3148
+ current = cupshelpers.Device (current_uri)
3149
+ current.info = "Current device"
3151
+ self.devices = devices.values()
3153
+ for device in self.devices:
3154
+ if device.type == "usb":
3155
+ # Find USB URIs with corresponding HPLIP URIs and mark them
3156
+ # for deleting, so that the user will only get the HPLIP
3157
+ # URIs for full device support in the list
3159
+ s = device.uri.find ("?serial=")
3162
+ e = device.uri[s:].find ("?")
3163
+ if e == -1: e = len (device.uri)
3164
+ ser = device.uri[s:s+e]
3166
+ s = device.uri[6:].find ("/")
3169
+ e = device.uri[s:].find ("?")
3170
+ if e == -1: e = len (device.uri)
3171
+ mod = device.uri[s:s+e].lower ().replace ("%20", "_")
3172
+ if mod.startswith ("hp_"):
3175
+ for hpdevice in self.devices:
3178
+ uri = hpdevice.uri
3179
+ if not uri.startswith ("hp:"): continue
3181
+ s = uri.find ("?serial=")
3184
+ e = uri[s:].find ("?")
3185
+ if e == -1: e = len (uri)
3186
+ hpser = uri[s:s+e]
3187
+ if hpser != ser: continue
3189
+ if mod and not (ser and hpser):
3190
+ s = uri.find ("/usb/")
3193
+ e = uri[s:].find ("?")
3194
+ if e == -1: e = len (uri)
3195
+ hpmod = uri[s:s+e].lower ()
3196
+ if hpmod.startswith ("hp_"):
3198
+ if hpmod != mod: continue
3200
+ if matchfound == 1: break
3201
+ if matchfound == 1:
3202
+ device.uri = "delete"
3203
+ if device.type == "hal":
3204
+ # Remove HAL USB URIs, for these printers there are already
3206
+ if device.uri.startswith("hal:///org/freedesktop/Hal/devices/usb_device"):
3207
+ device.uri = "delete"
3208
+ if device.type == "socket":
3209
+ # Remove default port to more easily find duplicate URIs
3210
+ device.uri = device.uri.replace (":9100", "")
3212
+ ## XXX This needs to be moved to *after* the device is
3213
+ # selected. Looping through all the network printers like
3214
+ # this is far too slow.
3215
+ if False and device.type in ("socket", "lpd", "ipp", "bluetooth"):
3216
+ host = self.getNetworkPrinterMakeModel(device)
3219
+ faxuri = self.get_hplip_uri_for_network_printer(host,
3222
+ self.devices.append(cupshelpers.Device(faxuri,
3223
+ **{'device-class' : "direct",
3224
+ 'device-info' : device.info + " HP Fax HPLIP",
3225
+ 'device-device-make-and-model' : "HP Fax",
3226
+ 'device-id' : "MFG:HP;MDL:Fax;DES:HP Fax;"}))
3227
+ if device.uri.startswith ("hp:"):
3228
+ device.type = "hp"
3229
+ device.info += (" HPLIP")
3231
+ nonfatalException ()
3232
+ # Mark duplicate URIs for deletion
3233
+ for i in range (len (self.devices)):
3234
+ for j in range (len (self.devices)):
3235
+ if i == j: continue
3236
+ device1 = self.devices[i]
3237
+ device2 = self.devices[j]
3238
+ if device1.uri == "delete" or device2.uri == "delete":
3240
+ if device1.uri == device2.uri:
3241
+ # Keep the one with the longer (better) device ID
3242
+ if (not device1.id):
3243
+ device1.uri = "delete"
3244
+ elif (not device2.id):
3245
+ device2.uri = "delete"
3246
+ elif (len (device1.id) < len (device2.id)):
3247
+ device1.uri = "delete"
3249
+ device2.uri = "delete"
3250
+ self.devices = filter(lambda x: x.uri not in ("hp:/no_device_found",
3251
+ "hpfax:/no_device_found",
3254
+ "scsi", "http", "delete"),
3256
+ self.devices.sort()
3258
+ self.devices.append(cupshelpers.Device('',
3259
+ **{'device-info' :i18nc("Other device", "Other")}))
3261
+ current.info = i18nc("Current device", "%1 (Current)", current.info)
3262
+ self.devices.insert(0, current)
3263
+ self.device = current
3264
+ self.tvNPDevices.clear()
3266
+ for device in self.devices:
3267
+ self.tvNPDevices.addItem(device.info)
3269
+ #self.tvNPDevices.get_selection().select_path(0)
3270
+ self.tvNPDevices.setCurrentRow(0)
3271
+ self.on_tvNPDevices_cursor_changed()
3273
+ def on_entNPTDevice_changed(self, entry):
3274
+ self.setNPButtons()
3278
+ def on_entSMBURI_changed (self, text):
3279
+ uri = unicode(text)
3280
+ (group, host, share, user, password) = SMBURI (uri=uri).separate ()
3282
+ self.entSMBUsername.setText(user)
3284
+ self.entSMBPassword.setText(password)
3285
+ if user or password:
3286
+ uri = SMBURI (group=group, host=host, share=share).get_uri ()
3287
+ self.entSMBURI.setText(uri)
3288
+ self.rbtnSMBAuthSet.setChecked(True)
3289
+ elif unicode(self.entSMBUsername.text()) == '':
3290
+ self.rbtnSMBAuthPrompt.setChecked(True)
3292
+ self.btnSMBVerify.setEnabled(bool(uri))
3294
+ def on_rbtnSMBAuthSet_toggled(self, ticked):
3295
+ self.tblSMBAuth.setEnabled(ticked)
3297
+ def on_entNPTIPPHostname_textChanged(self):
3298
+ valid = len (self.entNPTIPPHostname.text ()) > 0
3299
+ self.btnIPPFindQueue.setEnabled(valid)
3300
+ self.update_IPP_URI_label ()
3303
+ def update_IPP_URI_label(self):
3304
+ hostname = unicode(self.entNPTIPPHostname.text())
3305
+ queue = unicode(self.entNPTIPPQueuename.text())
3306
+ valid = len (hostname) > 0 and queue != '/printers/'
3309
+ uri = "ipp://%s%s" % (hostname, queue)
3310
+ self.lblIPPURI.setText(uri)
3311
+ self.lblIPPURI.show ()
3312
+ self.entNPTIPPQueuename.show ()
3314
+ self.lblIPPURI.hide ()
3316
+ self.btnIPPVerify.setEnabled(valid)
3317
+ self.setNPButtons ()
3319
+ @pyqtSignature("")
3320
+ def on_btnIPPFindQueue_clicked(self):
3321
+ self.mainapp.busy()
3322
+ self.entNPTIPPQueuename.clear()
3323
+ IPPBrowseDialog(self)
3324
+ self.mainapp.ready()
3326
+ @pyqtSignature("")
3327
+ def on_btnIPPVerify_clicked(self):
3328
+ uri = unicode(self.lblIPPURI.text())
3329
+ match = re.match ("(ipp|https?)://([^/]+)(.*)/([^/]*)", uri)
3332
+ oldserver = cups.getServer ()
3333
+ host = match.group(2)
3335
+ cups.setServer (match.group (2))
3336
+ c = cups.Connection ()
3337
+ attributes = c.getPrinterAttributes (uri = uri)
3339
+ except cups.IPPError, (e, msg):
3340
+ debugprint ("Failed to get attributes: %s (%d)" % (msg, e))
3342
+ nonfatalException ()
3343
+ cups.setServer (oldserver)
3348
+ KMessageBox.information (self, _("This print share is accessible."),
3349
+ _("Print Share Verified"))
3351
+ KMessageBox.error (self, _("This print share is not accessible."),
3352
+ _("Inaccessible"))
3354
+ def on_tvNPDevices_cursor_changed(self):
3355
+ device = self.devices[self.tvNPDevices.currentRow()]
3356
+ self.device = device
3357
+ self.lblNPDeviceDescription.setText('')
3358
+ page = self.new_printer_device_tabs.get(device.type, 1)
3359
+ self.ntbkNPType.setCurrentIndex(page)
3361
+ type = device.type
3362
+ url = device.uri.split(":", 1)[-1]
3364
+ # This is the "no options" page, with just a label to describe
3365
+ # the selected device.
3366
+ if device.type == "parallel":
3367
+ text = i18n("A printer connected to the parallel port.")
3368
+ elif device.type == "usb":
3369
+ text = i18n("A printer connected to a USB port.")
3370
+ elif device.type == "hp":
3371
+ text = i18n("HPLIP software driving a printer, "
3372
+ "or the printer function of a multi-function device.")
3373
+ elif device.type == "hpfax":
3374
+ text = i18n("HPLIP software driving a fax machine, "
3375
+ "or the fax function of a multi-function device.")
3376
+ elif device.type == "hal":
3377
+ text = i18n("Local printer detected by the "
3378
+ "Hardware Abstraction Layer (HAL).")
3382
+ self.lblNPDeviceDescription.setText(text)
3383
+ elif device.type=="socket":
3384
+ if device.uri.startswith ("socket"):
3385
+ host = device.uri[9:]
3386
+ i = host.find (":")
3388
+ port = int (host[i + 1:])
3393
+ self.entNPTDirectJetHostname.setText(host)
3394
+ self.entNPTDirectJetPort.setText(str (port))
3395
+ elif device.type=="serial":
3398
+ if not device.is_class:
3399
+ options = device.uri.split("?")[1]
3400
+ options = options.split("+")
3402
+ for option in options:
3403
+ name, value = option.split("=")
3404
+ option_dict[name] = value
3406
+ for widget, name, optionvalues in (
3407
+ (self.cmbNPTSerialBaud, "baud", None),
3408
+ (self.cmbNPTSerialBits, "bits", None),
3409
+ (self.cmbNPTSerialParity, "parity",
3410
+ ["none", "odd", "even"]),
3411
+ (self.cmbNPTSerialFlow, "flow",
3412
+ ["none", "soft", "hard", "hard"])):
3413
+ if option_dict.has_key(name): # option given in URI?
3414
+ if optionvalues is None: # use text in widget
3415
+ model = widget.get_model()
3416
+ iter = model.get_iter_first()
3419
+ value = model.get(iter,0)[0]
3420
+ if value == option_dict[name]:
3421
+ widget.set_active(nr)
3423
+ iter = model.iter_next(iter)
3425
+ else: # use optionvalues
3426
+ nr = optionvalues.index(
3427
+ option_dict[name])
3428
+ widget.set_active(nr+1) # compensate "Default"
3430
+ widget.set_active(0)
3433
+ # XXX FILL TABS FOR VALID DEVICE URIs
3434
+ elif device.type in ("ipp", "http"):
3435
+ if (device.uri.startswith ("ipp:") or
3436
+ device.uri.startswith ("http:")):
3437
+ match = re.match ("(ipp|https?)://([^/]+)(.*)", device.uri)
3439
+ server = match.group (2)
3440
+ printer = match.group (3)
3445
+ self.entNPTIPPHostname.setText(server)
3446
+ self.entNPTIPPQueuename.setText(printer)
3447
+ self.lblIPPURI.setText(device.uri)
3448
+ self.lblIPPURI.show()
3449
+ self.entNPTIPPQueuename.show()
3451
+ self.entNPTIPPHostname.setText('')
3452
+ self.entNPTIPPQueuename.setText('/printers/')
3453
+ self.entNPTIPPQueuename.show()
3454
+ self.lblIPPURI.hide()
3455
+ elif device.type=="lpd":
3456
+ if device.uri.startswith ("lpd"):
3457
+ host = device.uri[6:]
3458
+ i = host.find ("/")
3460
+ printer = host[i + 1:]
3464
+ self.cmbentNPTLpdHost.addItem(host)
3465
+ self.cmbentNPTLpdQueue.addItem(printer)
3466
+ elif device.uri == "lpd":
3468
+ elif device.uri == "smb":
3469
+ self.entSMBURI.setText('')
3470
+ self.btnSMBVerify.setEnabled(False)
3471
+ elif device.type == "smb":
3472
+ self.entSMBUsername.setText('')
3473
+ self.entSMBPassword.setText('')
3474
+ self.entSMBURI.setText(device.uri[6:])
3475
+ self.btnSMBVerify.setEnabled(True)
3477
+ self.entNPTDevice.setText(device.uri)
3479
+ self.setNPButtons()
3481
+ def getDeviceURI(self):
3482
+ type = self.device.type
3483
+ if type == "socket": # DirectJet
3484
+ host = unicode(self.entNPTDirectJetHostname.text())
3485
+ port = unicode(self.entNPTDirectJetPort.text())
3486
+ device = "socket://" + host
3488
+ device = device + ':' + port
3489
+ elif type in ("http", "ipp"): # IPP
3490
+ if self.lblIPPURI.isVisible:
3491
+ device = unicode(self.lblIPPURI.text())
3494
+ elif type == "lpd": # LPD
3495
+ host = unicode(self.cmbentNPTLpdHost.currentText())
3496
+ printer = unicode(self.cmbentNPTLpdQueue.currentText())
3497
+ device = "lpd://" + host
3499
+ device = device + "/" + printer
3500
+ elif type == "parallel": # Parallel
3501
+ device = self.device.uri
3502
+ elif type == "scsi": # SCSII
3504
+ elif type == "serial": # Serial
3508
+ for widget, name, optionvalues in (
3509
+ (self.cmbNPTSerialBaud, "baud", None),
3510
+ (self.cmbNPTSerialBits, "bits", None),
3511
+ (self.cmbNPTSerialParity, "parity",
3512
+ ("none", "odd", "even")),
3513
+ (self.cmbNPTSerialFlow, "flow",
3514
+ ("none", "soft", "hard", "hard"))):
3515
+ nr = widget.get_active()
3517
+ if optionvalues is not None:
3518
+ option = optionvalues[nr-1]
3520
+ option = widget.get_active_text()
3521
+ options.append(name + "=" + option)
3522
+ options = "+".join(options)
3523
+ device = self.device.uri.split("?")[0] #"serial:/dev/ttyS%s"
3525
+ device = device + "?" + options
3527
+ elif type == "smb":
3528
+ uri = unicode(self.entSMBURI.text())
3529
+ (group, host, share, u, p) = SMBURI (uri=uri).separate ()
3532
+ if self.rbtnSMBAuthSet.isChecked():
3533
+ user = unicode(self.entSMBUsername.text())
3534
+ password = unicode(self.entSMBPassword.text())
3535
+ uri = SMBURI (group=group, host=host, share=share,
3536
+ user=user, password=password).get_uri ()
3537
+ device = "smb://" + uri
3538
+ elif not self.device.is_class:
3539
+ device = self.device.uri
3541
+ device = str(self.entNPTDevice.text())
3545
+ if nr == self.ntbkNewPrinterPages["device"]: # Device
3548
+ uri = self.getDeviceURI ()
3549
+ valid = validDeviceURI (uri)
3551
+ debugprint("exception in getDeviceURI()")
3553
+ self.btnNPForward.setEnabled(valid)
3554
+ self.btnNPBack.hide ()
3556
+ self.btnNPBack.show()
3558
+ self.btnNPForward.show()
3559
+ self.btnNPApply.hide()
3561
+ if nr == self.ntbkNewPrinterPages["name"]: # Name
3562
+ self.btnNPBack.show()
3563
+ if self.dialog_mode == "printer":
3564
+ self.btnNPForward.hide()
3565
+ self.btnNPApply.show()
3566
+ self.btnNPApply.setEnabled(
3567
+ self.mainapp.checkNPName(self.entNPName.getText()))
3568
+ if nr == self.ntbkNewPrinterPages["make"]: # Make/PPD file
3569
+ downloadable_selected = False
3570
+ if self.rbtnNPDownloadableDriverSearch.get_active ():
3571
+ combobox = self.cmbNPDownloadableDriverFoundPrinters
3572
+ iter = combobox.get_active_iter ()
3573
+ if iter and combobox.get_model ().get_value (iter, 1):
3574
+ downloadable_selected = True
3576
+ self.btnNPForward.setEnabled(bool(
3577
+ self.rbtnNPFoomatic.get_active() or
3578
+ not self.filechooserPPD.text().isEmpty() or
3579
+ downloadable_selected))
3580
+ if nr == self.ntbkNewPrinterPages["model"]: # Model/Driver
3581
+ model, iter = self.tvNPDrivers.get_selection().get_selected()
3582
+ self.btnNPForward.set_sensitive(bool(iter))
3583
+ if nr == self.ntbkNewPrinterPages["class-members"]: # Class Members
3584
+ self.btnNPForward.hide()
3585
+ self.btnNPApply.show()
3586
+ self.btnNPApply.setEnabled(
3587
+ bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
3588
+ if nr == self.ntbkNewPrinterPages["downloadable"]: # Downloadable drivers
3589
+ if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1:
3590
+ accepted = self.rbtnNPDownloadLicenseYes.get_active ()
3594
+ self.btnNPForward.set_sensitive(accepted)
3598
+ def on_rbtnNPFoomatic_toggled(self):
3599
+ rbtn1 = self.rbtnNPFoomatic.isChecked()
3600
+ rbtn2 = self.rbtnNPPPD.isChecked()
3601
+ rbtn3 = self.rbtnNPDownloadableDriverSearch.isChecked()
3602
+ self.tvNPMakes.setEnabled(rbtn1)
3603
+ self.filechooserPPD.setEnabled(rbtn2)
3606
+ if not rbtn3 and self.openprinting_query_handle:
3607
+ # Need to cancel a search in progress.
3608
+ self.openprinting.cancelOperation (self.openprinting_query_handle)
3609
+ self.openprinting_query_handle = None
3610
+ self.btnNPDownloadableDriverSearch_label.setText(_("Search"))
3611
+ # Clear printer list.
3612
+ self.cmbNPDownloadableDriverFoundPrinters.clear()
3615
+ for widget in [self.entNPDownloadableDriverSearch,
3616
+ self.cmbNPDownloadableDriverFoundPrinters]:
3617
+ widget.setEnabled(rbtn3)
3618
+ self.btnNPDownloadableDriverSearch.\
3619
+ setEnabled(rbtn3 and (self.openprinting_query_handle == None))
3621
+ self.setNPButtons()
3623
+ def fillMakeList(self):
3624
+ makes = self.ppds.getMakes()
3625
+ self.tvNPMakes.clear()
3628
+ for make in makes:
3629
+ self.tvNPMakes.addItem(make)
3631
+ if make==self.auto_make:
3632
+ self.tvNPMakes.setCurrentRow(index-1)
3635
+ self.on_tvNPMakes_cursor_changed()
3637
+ def on_tvNPMakes_cursor_changed(self):
3638
+ items = self.tvNPMakes.selectedItems()
3639
+ if len(items) > 0:
3640
+ self.NPMake = unicode(items[0].text())
3641
+ self.fillModelList()
3643
+ def fillModelList(self):
3644
+ models = self.ppds.getModels(self.NPMake)
3645
+ self.tvNPModels.clear()
3649
+ for pmodel in models:
3650
+ self.tvNPModels.addItem(pmodel)
3651
+ if self.NPMake==self.auto_make and pmodel==self.auto_model:
3652
+ self.tvNPModels.setCurrentRow(index)
3656
+ self.tvNPModels.setCurrentRow(0)
3657
+ ##self.tvNPModels.columns_autosize()
3658
+ self.on_tvNPModels_cursor_changed()
3660
+ def fillDriverList(self, pmake, pmodel):
3661
+ self.NPModel = pmodel
3662
+ self.tvNPDrivers.clear()
3664
+ ppds = self.ppds.getInfoFromModel(pmake, pmodel)
3666
+ self.NPDrivers = self.ppds.orderPPDNamesByPreference(ppds.keys())
3667
+ for i in range (len(self.NPDrivers)):
3668
+ ppd = ppds[self.NPDrivers[i]]
3669
+ driver = ppd["ppd-make-and-model"]
3670
+ driver = driver.replace(" (recommended)", "")
3673
+ lpostfix = " [%s]" % ppd["ppd-natural-language"]
3674
+ driver += lpostfix
3679
+ self.tvNPDrivers.addItem(i18nc("Recommended driver", "%1 (recommended)", driver))
3680
+ self.tvNPDrivers.setCurrentRow(0)
3682
+ self.tvNPDrivers.addItem(driver)
3683
+ ##self.tvNPDrivers.columns_autosize()
3685
+ def on_tvNPModels_cursor_changed(self):
3686
+ items = self.tvNPModels.selectedItems()
3687
+ if len(items) > 0:
3688
+ pmodel = unicode(items[0].text())
3689
+ self.fillDriverList(self.NPMake, pmodel)
3691
+ def getNPPPD(self):
3693
+ if self.rbtnNPFoomatic.isChecked():
3694
+ #items = self.tvNPDrivers.selectedItems()
3695
+ #nr = unicode(items[0])
3696
+ nr = self.tvNPDrivers.currentRow()
3697
+ ppd = self.NPDrivers[nr]
3698
+ elif self.rbtnNPPPD.isChecked():
3699
+ ppd = cups.PPD(unicode(self.filechooserPPD.text()))
3702
+ # PPD of the driver downloaded from OpenPrinting XXX
3703
+ treeview = self.tvNPDownloadableDrivers
3704
+ model, iter = treeview.get_selection ().get_selected ()
3705
+ driver = model.get_value (iter, 1)
3706
+ if driver.has_key ('ppds'):
3707
+ # Only need to download a PPD.
3708
+ file_to_download = driver
3713
+ except RuntimeError, e:
3714
+ if self.rbtnNPFoomatic.isChecked():
3715
+ # Foomatic database problem of some sort.
3716
+ err_title = i18n('Database error')
3717
+ model, iter = (self.tvNPDrivers.get_selection().
3719
+ nr = model.get_path(iter)[0]
3720
+ driver = self.NPDrivers[nr]
3721
+ if driver.startswith ("gutenprint"):
3722
+ # This printer references some XML that is not
3723
+ # installed by default. Point the user at the
3724
+ # package they need to install.
3725
+ err = i18n("You will need to install the '%1' package "
3726
+ "in order to use this driver.",
3727
+ "gutenprint-foomatic")
3729
+ err = i18n("The '%1' driver cannot be "
3730
+ "used with printer '%2 %3'.", driver, self.NPMake, self.NPModel)
3731
+ elif self.rbtnNPPPD.isChecked():
3732
+ # This error came from trying to open the PPD file.
3733
+ err_title = i18n('PPD error')
3734
+ filename = self.filechooserPPD.text()
3735
+ err = i18n('Failed to read PPD file. Possible reason '
3736
+ 'follows:') + '\n'
3737
+ os.environ["PPD"] = filename
3738
+ # We want this to be in the current natural language,
3739
+ # so we intentionally don't set LC_ALL=C here.
3740
+ p = os.popen ('/usr/bin/cupstestppd -rvv "$PPD"', 'r')
3741
+ output = p.readlines ()
3743
+ err += reduce (lambda x, y: x + y, output)
3745
+ # Failed to get PPD downloaded from OpenPrinting XXX
3746
+ err_title = i18n('Downloadable drivers')
3747
+ err_text = i18n("Support for downloadable "
3748
+ "drivers is not yet completed.")
3750
+ error_text = ('<span size="larger">' +
3751
+ i18nc("Error title", "<b>%1</b>", err_title) + '</span>\n\n' + err)
3752
+ KMessageBox.error(self, error_text, err_title)
3755
+ if isinstance(ppd, str) or isinstance(ppd, unicode):
3757
+ if (ppd != "raw"):
3758
+ f = self.mainapp.cups.getServerPPD(ppd)
3761
+ except AttributeError:
3762
+ nonfatalException()
3763
+ debugprint ("pycups function getServerPPD not available: never mind")
3764
+ except RuntimeError:
3765
+ nonfatalException()
3766
+ debugprint ("libcups from CUPS 1.3 not available: never mind")
3767
+ except cups.IPPError:
3768
+ nonfatalException()
3769
+ debugprint ("CUPS 1.3 server not available: never mind")
3773
+ # Create new Printer
3774
+ @pyqtSignature("")
3775
+ def on_btnNPApply_clicked(self):
3776
+ if self.dialog_mode in ("class", "printer"):
3777
+ name = unicode(self.entNPName.text())
3778
+ location = unicode(self.entNPLocation.text())
3779
+ info = unicode(self.entNPDescription.text())
3781
+ name = self.mainapp.printer.name
3783
+ #replace any whitespace in printer name with underscore otherwise
3784
+ #CUPS throws an error
3785
+ name = name.replace(" ", "_")
3787
+ # Whether to check for missing drivers.
3792
+ if self.dialog_mode=="class":
3793
+ members = self.mainapp.getCurrentClassMembers(self.tvNCMembers)
3795
+ for member in members:
3796
+ self.passwd_retry = False # use cached Passwd
3797
+ self.mainapp.cups.addPrinterToClass(str(member), name)
3798
+ except cups.IPPError, (e, msg):
3799
+ self.show_IPP_Error(e, msg)
3801
+ elif self.dialog_mode=="printer":
3802
+ self.device.uri = unicode(self.device.uri)
3804
+ if self.device.uri:
3805
+ uri = self.device.uri
3807
+ uri = self.getDeviceURI()
3808
+ if not self.ppd: # XXX needed?
3809
+ # Go back to previous page to re-select driver.
3810
+ self.nextNPTab(-1)
3813
+ # write Installable Options to ppd
3814
+ for option in self.options.itervalues():
3815
+ option.writeback()
3817
+ self.mainapp.busy(self)
3818
+ self.WaitWindow.setText(i18n('<b>Adding</b>') + '<br /><br />' +
3819
+ i18n('Adding printer'))
3820
+ #self.WaitWindow.set_transient_for (self.NewPrinterWindow)
3821
+ self.WaitWindow.show ()
3822
+ KApplication.processEvents()
3824
+ self.passwd_retry = False # use cached Passwd
3825
+ if isinstance(ppd, str) or isinstance(ppd, unicode):
3826
+ self.mainapp.cups.addPrinter(name, ppdname=ppd,
3827
+ device=uri, info=info, location=location)
3829
+ elif ppd is None: # raw queue
3830
+ self.mainapp.cups.addPrinter(name, device=uri,
3831
+ info=info, location=location)
3833
+ cupshelpers.setPPDPageSize(ppd, self.language[0])
3834
+ self.mainapp.cups.addPrinter(name, ppd=ppd,
3835
+ device=uri, info=info, location=location)
3838
+ cupshelpers.activateNewPrinter (self.mainapp.cups, name)
3839
+ except cups.IPPError, (e, msg):
3841
+ self.WaitWindow.hide ()
3842
+ self.show_IPP_Error(e, msg)
3845
+ ##self.ready (self.NewPrinterWindow)
3846
+ self.WaitWindow.hide ()
3847
+ fatalException (1)
3848
+ self.WaitWindow.hide ()
3849
+ ##self.ready (self.NewPrinterWindow)
3851
+ if self.dialog_mode in ("class", "printer"):
3853
+ self.passwd_retry = False # use cached Passwd
3854
+ self.mainapp.cups.setPrinterLocation(name, location)
3855
+ self.passwd_retry = False # use cached Passwd
3856
+ self.mainapp.cups.setPrinterInfo(name, info)
3857
+ except cups.IPPError, (e, msg):
3858
+ self.show_IPP_Error(e, msg)
3860
+ elif self.dialog_mode == "device":
3862
+ uri = self.getDeviceURI()
3863
+ self.mainapp.cups.addPrinter(name, device=uri)
3864
+ except cups.IPPError, (e, msg):
3865
+ self.show_IPP_Error(e, msg)
3867
+ elif self.dialog_mode == "ppd":
3869
+ ppd = self.ppd = self.getNPPPD()
3871
+ # Go back to previous page to re-select driver.
3872
+ self.nextNPTab(-1)
3875
+ # set ppd on server and retrieve it
3876
+ # cups doesn't offer a way to just download a ppd ;(=
3878
+ if isinstance(ppd, str) or isinstance(ppd, unicode):
3879
+ if self.rbtnChangePPDasIs.isChecked():
3880
+ # To use the PPD as-is we need to prevent CUPS copying
3881
+ # the old options over. Do this by setting it to a
3882
+ # raw queue (no PPD) first.
3884
+ self.mainapp.cups.addPrinter(name, ppdname='raw')
3885
+ except cups.IPPError, (e, msg):
3886
+ self.show_IPP_Error(e, msg)
3888
+ self.mainapp.cups.addPrinter(name, ppdname=ppd)
3889
+ except cups.IPPError, (e, msg):
3890
+ self.show_IPP_Error(e, msg)
3894
+ filename = self.mainapp.cups.getPPD(name)
3895
+ ppd = cups.PPD(filename)
3896
+ os.unlink(filename)
3897
+ except cups.IPPError, (e, msg):
3898
+ if e == cups.IPP_NOT_FOUND:
3901
+ self.show_IPP_Error(e, msg)
3904
+ # We have an actual PPD to upload, not just a name.
3905
+ if not self.rbtnChangePPDasIs.isChecked():
3906
+ cupshelpers.copyPPDOptions(self.mainapp.ppd, ppd) # XXX
3908
+ # write Installable Options to ppd
3909
+ for option in self.options.itervalues():
3910
+ option.writeback()
3911
+ cupshelpers.setPPDPageSize(ppd, self.language[0])
3914
+ self.mainapp.cups.addPrinter(name, ppd=ppd)
3915
+ except cups.IPPError, (e, msg):
3916
+ self.show_IPP_Error(e, msg)
3923
+ self.mainapp.populateList(start_printer=name)
3926
+ self.checkDriverExists (name, ppd=checkppd)
3928
+ nonfatalException()
3930
+ # Also check to see whether the media option has become
3931
+ # invalid. This can happen if it had previously been
3932
+ # explicitly set to a page size that is not offered with
3933
+ # the new PPD (see bug #441836).
3936
+ option = self.mainapp.server_side_options['media']
3937
+ if option.get_current_value () == None:
3938
+ debugprint ("Invalid media option: resetting")
3940
+ self.mainapp.changed.add (option)
3941
+ self.mainapp.save_printer (self.mainapp.printer)
3945
+ print "exception in check to see whether the media option has become invalid"
3946
+ nonfatalException()
3949
+ def show_IPP_Error(self, exception, message):
3950
+ if exception == cups.IPP_NOT_AUTHORIZED:
3951
+ KMessageBox.error(self, i18n('The password may be incorrect.'), i18n('Not authorized'))
3953
+ KMessageBox.error(self, i18n("There was an error during the CUPS " "operation: '%1'.", message),
3954
+ i18n('CUPS server error'))
3956
+ def checkDriverExists(self, name, ppd=None):
3957
+ """Check that the driver for an existing queue actually
3958
+ exists, and prompt to install the appropriate package
3961
+ ppd: cups.PPD object, if already created"""
3963
+ # Is this queue on the local machine? If not, we can't check
3964
+ # anything at all.
3965
+ server = cups.getServer ()
3966
+ if not (server == 'localhost' or server == '127.0.0.1' or
3967
+ server == '::1' or server[0] == '/'):
3970
+ # Fetch the PPD if we haven't already.
3973
+ filename = self.mainapp.cups.getPPD(name)
3974
+ except cups.IPPError, (e, msg):
3975
+ if e == cups.IPP_NOT_FOUND:
3976
+ # This is a raw queue. Nothing to check.
3979
+ self.show_IPP_Error(e, msg)
3982
+ ppd = cups.PPD(filename)
3983
+ os.unlink(filename)
3985
+ (pkgs, exes) = cupshelpers.missingPackagesAndExecutables (ppd)
3986
+ if len (pkgs) > 0 or len (exes) > 0:
3987
+ # We didn't find a necessary executable. Complain.
3988
+ install = "/usr/bin/system-install-packages"
3989
+ if len (pkgs) > 0 and os.access (install, os.X_OK):
3991
+ install_text = ('<span weight="bold" size="larger">' +
3992
+ i18n('Install driver') + '</span>\n\n' +
3993
+ i18n("Printer '%1' requires the %2 package but "
3994
+ "it is not currently installed.", name, pkg))
3995
+ dialog = self.InstallDialog
3996
+ self.lblInstall.set_markup(install_text)
3998
+ error_text = ('<span weight="bold" size="larger">' +
3999
+ i18n('Missing driver') + '</span>\n\n' +
4000
+ i18n("Printer '%1' requires the '%2' program but "
4001
+ "it is not currently installed. Please "
4002
+ "install it before using this printer.", name, (exes + pkgs)[0]))
4003
+ KMessageBox.error(self, error_text, "Missing Driver")
4006
+ if pkg and response == gtk.RESPONSE_OK:
4007
+ # Install the package.
4008
+ def wait_child (sig, stack):
4009
+ (pid, status) = os.wait ()
4011
+ signal.signal (signal.SIGCHLD, wait_child)
4016
+ os.execv (install, [install, pkg])
4021
+ pass # should handle error
4025
+ def on_entNPTIPPQueuename_textChanged(self, ent):
4026
+ self.update_IPP_URI_label ()
4028
+ #FIXME not in gnome?
4029
+ @pyqtSignature("")
4030
+ def on_btnNPCancel_clicked(self):
4033
+ #copy busy and ready functions from the mainapp
4034
+ #since they can't be inherited from the mainapp
4035
+ def busy (self, win = None):
4039
+ win.setCursor(Qt.WaitCursor)
4040
+ KApplication.processEvents()
4042
+ nonfatalException ()
4044
+ def ready (self, win = None):
4048
+ win.setCursor(Qt.ArrowCursor)
4049
+ KApplication.processEvents()
4051
+ nonfatalException ()
4052
+#end of class NewPrinterGUI
4054
+class IPPBrowseDialog(QDialog):
4056
+ def __init__(self, newprinter):
4057
+ QDialog.__init__(self, newprinter)
4058
+ self.newprinter = newprinter
4060
+ self.language = newprinter.language
4061
+ self.dialog_mode = ""
4063
+ self.WaitWindow = QMessageBox(self.newprinter)
4064
+ self.WaitWindow.setStandardButtons(QMessageBox.NoButton)
4066
+ uic.loadUi(APPDIR + "/" + "ipp-browse-dialog.ui", self)
4068
+ self.btnIPPBrowseOk.setEnabled(False)
4071
+ #create an empty data model
4072
+ self.ippStore = self.twIPPBrowser
4073
+ self.twIPPBrowser.sortByColumn(0, Qt.AscendingOrder)
4075
+ #Set tree header labels. Takes list of strings
4076
+ self.ippStore.setHeaderLabels([_("Share"), _("Comment")])
4078
+ self.browse_ipp_queues()
4080
+ def browse_ipp_queues(self):
4081
+ if not self.newprinter.ipp_lock.acquire(0):
4083
+ self.browse_ipp_queues_thread()
4085
+ def browse_ipp_queues_thread(self):
4088
+ store = self.ippStore
4090
+ items = QTreeWidgetItem(QStringList([_('Scanning...'), '']))
4091
+ store.addTopLevelItem(items)
4093
+ host = self.newprinter.entNPTIPPHostname.text()
4095
+ nonfatalException()
4097
+ oldserver = cups.getServer ()
4098
+ printers = classes = {}
4103
+ #need to pass a unicode string. urllib falls over QStrings
4104
+ (host, port) = urllib.splitnport (unicode(host), defport=port)
4107
+ c = cups.Connection (host=host, port=port)
4108
+ printers = c.getPrinters ()
4110
+ except cups.IPPError, (e, m):
4111
+ debugprint ("IPP browser: %s" % m)
4114
+ nonfatalException()
4116
+ cups.setServer (oldserver)
4120
+ for printer, dict in printers.iteritems ():
4121
+ #only these properties seem to be used from dict so
4122
+ #just store these instead of whole dict
4123
+ location = dict.get('printer-location', '')
4124
+ uri = dict.get('printer-uri-supported', 'ipp')
4125
+ items = QTreeWidgetItem(QStringList([printer, location, uri]))
4126
+ store.addTopLevelItem(items)
4128
+ if len (printers) + len (classes) == 0:
4129
+ # Display 'No queues' dialog
4131
+ title = _("Not possible")
4132
+ text = (_("It is not possible to obtain a list of queues "
4133
+ "from `%s'.") % host + '\n\n' +
4134
+ _("Obtaining a list of queues is a CUPS extension "
4135
+ "to IPP. Network printers do not support it."))
4137
+ title = _("No queues")
4138
+ text = _("There are no queues available.")
4141
+ KMessageBox.error (self.newprinter, text, title)
4146
+ nonfatalException()
4148
+ self.newprinter.ipp_lock.release()
4150
+ nonfatalException()
4153
+ def on_twIPPBrowser_itemClicked(self):
4154
+ self.btnIPPBrowseOk.setEnabled(True)
4156
+ def on_btnIPPBrowseOk_clicked(self):
4157
+ index = self.twIPPBrowser.currentIndex()
4158
+ item = self.twIPPBrowser.itemFromIndex(index)
4159
+ queue = item.text(0)
4160
+ uri = unicode(item.text(2))
4162
+ self.newprinter.entNPTIPPQueuename.setText (queue)
4163
+ self.newprinter.entNPTIPPQueuename.show()
4164
+ #uri = dict.get('printer-uri-supported', 'ipp')
4165
+ match = re.match ("(ipp|https?)://([^/]+)(.*)", uri)
4167
+ self.newprinter.entNPTIPPHostname.setText (match.group (2))
4168
+ self.newprinter.entNPTIPPQueuename.setText (match.group (3))
4170
+ self.newprinter.lblIPPURI.setText (uri)
4171
+ self.newprinter.lblIPPURI.show()
4172
+ self.newprinter.setNPButtons()
4174
+ def on_btnIPPBrowseCancel_clicked(self):
4177
+ def on_btnIPPBrowseRefresh_clicked(self):
4178
+ self.browse_ipp_queues()
4180
+ #copy busy and ready functions from the mainapp
4181
+ #since they can't be inherited from the mainapp
4182
+ def busy (self, win = None):
4186
+ win.setCursor(Qt.WaitCursor)
4187
+ KApplication.processEvents()
4189
+ nonfatalException ()
4191
+ def ready (self, win = None):
4195
+ win.setCursor(Qt.ArrowCursor)
4196
+ KApplication.processEvents()
4198
+ nonfatalException ()
4199
+#End of class IPPBrowseDialog
4201
+#Needed to iterate over a QTreeWidgetItem for the user access
4203
+class Iter(QTreeWidgetItemIterator):
4204
+ def __init__(self, *args):
4205
+ QTreeWidgetItemIterator.__init__(self, *args)
4208
+ value = self.value()
4210
+ raise StopIteration
4212
+ return self.value()
4214
+def CreatePlugin(widget_parent, parent, component_data):
4216
+ kcm = u.makeui(component_data, widget_parent)
4219
+#if __name__ == "__main__":
4220
+ #"""start the application"""
4222
+ #appName = "system-config-printer-kde"
4223
+ #catalogue = "system-config-printer-kde"
4224
+ #programName = ki18n("System Config Printer KDE")
4226
+ #description = ki18n("Printer configuration tool")
4227
+ #license = KAboutData.License_GPL
4228
+ #copyright = ki18n("2007 Tim Waugh, Red Hat Inc, 2007-2008 Canonical Ltd")
4229
+ #text = KLocalizedString()
4230
+ #homePage = "https://launchpad.net/system-config-printer"
4233
+ #aboutData = KAboutData (appName, catalogue, programName, version, description,
4234
+ #license, copyright, text, homePage, bugEmail)
4236
+ #aboutData.addAuthor(ki18n("Jonathan Riddell"), ki18n("Author"))
4237
+ #aboutData.addAuthor(ki18n("Tim Waugh/Red Hat"), ki18n("System Config Printer Author"))
4239
+ #options = KCmdLineOptions()
4241
+ #KCmdLineArgs.init(sys.argv, aboutData)
4242
+ #KCmdLineArgs.addCmdLineOptions(options)
4244
+ #app = KApplication()
4245
+ #args = KCmdLineArgs.parsedArgs()
4248
+ #sys.exit(app.exec_())
4249
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
4250
--- orig/kdeadmin-4.2.2/system-config-printer-kde/new-printer.ui 2008-11-04 17:13:05.000000000 +0000
4251
+++ kdeadmin-4.2.2/system-config-printer-kde/new-printer.ui 2009-04-09 22:56:08.000000000 +0100
4253
-<ui version="4.0" >
4254
+<?xml version="1.0" encoding="UTF-8"?>
4257
- <widget class="QDialog" name="form" >
4258
- <property name="geometry" >
4259
+ <widget class="QDialog" name="form">
4260
+ <property name="geometry">
4265
- <height>534</height>
4266
+ <height>583</height>
4269
- <property name="windowTitle" >
4270
+ <property name="windowTitle">
4271
<string>Dialog</string>
4273
- <property name="windowIcon" >
4274
+ <property name="windowIcon">
4276
<normaloff>../../../../.designer/backup/printer-128.png</normaloff>../../../../.designer/backup/printer-128.png</iconset>
4278
- <layout class="QGridLayout" >
4279
- <item row="0" column="0" colspan="5" >
4280
- <widget class="QStackedWidget" name="ntbkNewPrinter" >
4281
- <property name="currentIndex" >
4282
+ <layout class="QGridLayout">
4283
+ <item row="0" column="0" colspan="5">
4284
+ <widget class="QStackedWidget" name="ntbkNewPrinter">
4285
+ <property name="currentIndex">
4288
- <widget class="QWidget" name="page" >
4289
- <layout class="QGridLayout" >
4290
- <item row="0" column="0" >
4291
- <widget class="QLabel" name="label" >
4292
- <property name="text" >
4293
+ <widget class="QWidget" name="page">
4294
+ <layout class="QGridLayout">
4295
+ <item row="0" column="0">
4296
+ <widget class="QLabel" name="label">
4297
+ <property name="text">
4298
<string>Printer Name</string>
4302
- <item row="1" column="0" >
4303
- <widget class="QLineEdit" name="entNPName" />
4304
+ <item row="1" column="0">
4305
+ <widget class="QLineEdit" name="entNPName"/>
4307
- <item row="2" column="0" >
4308
- <widget class="QLabel" name="label_2" >
4309
- <property name="text" >
4310
+ <item row="2" column="0">
4311
+ <widget class="QLabel" name="label_2">
4312
+ <property name="text">
4313
<string>Description</string>
4317
- <item row="3" column="0" >
4318
- <widget class="QLineEdit" name="entNPDescription" />
4319
+ <item row="3" column="0">
4320
+ <widget class="QLineEdit" name="entNPDescription"/>
4322
- <item row="4" column="0" >
4323
- <widget class="QLabel" name="label_3" >
4324
- <property name="text" >
4325
+ <item row="4" column="0">
4326
+ <widget class="QLabel" name="label_3">
4327
+ <property name="text">
4328
<string>Location</string>
4332
- <item row="5" column="0" >
4333
- <widget class="QLineEdit" name="entNPLocation" />
4334
+ <item row="5" column="0">
4335
+ <widget class="QLineEdit" name="entNPLocation"/>
4337
- <item row="6" column="0" >
4338
+ <item row="6" column="0">
4340
- <property name="orientation" >
4341
+ <property name="orientation">
4342
<enum>Qt::Vertical</enum>
4344
- <property name="sizeHint" stdset="0" >
4345
+ <property name="sizeHint" stdset="0">
4353
- <widget class="QWidget" name="page_3" >
4354
- <layout class="QGridLayout" >
4355
- <item row="0" column="0" colspan="3" >
4356
- <widget class="QLabel" name="label_7" >
4357
- <property name="text" >
4358
+ <widget class="QWidget" name="page_3">
4359
+ <layout class="QGridLayout">
4360
+ <item row="0" column="0" colspan="3">
4361
+ <widget class="QLabel" name="label_7">
4362
+ <property name="text">
4363
<string>Select Connection</string>
4367
- <item row="1" column="0" >
4368
- <widget class="QListWidget" name="tvNPDevices" />
4369
+ <item row="1" column="0">
4370
+ <widget class="QListWidget" name="tvNPDevices"/>
4372
- <item row="1" column="1" >
4373
- <widget class="QStackedWidget" name="ntbkNPType" >
4374
- <property name="currentIndex" >
4375
+ <item row="1" column="1">
4376
+ <widget class="QStackedWidget" name="ntbkNPType">
4377
+ <property name="currentIndex">
4380
- <widget class="QWidget" name="page_4" >
4381
- <layout class="QGridLayout" >
4382
- <item row="0" column="0" >
4383
- <widget class="QLabel" name="label_8" >
4384
- <property name="text" >
4385
+ <widget class="QWidget" name="page_4">
4386
+ <layout class="QGridLayout">
4387
+ <item row="0" column="0">
4388
+ <widget class="QLabel" name="label_8">
4389
+ <property name="text">
4390
<string>Description</string>
4394
- <item row="1" column="0" >
4395
- <widget class="QLabel" name="lblNPDeviceDescription" >
4396
- <property name="text" >
4397
+ <item row="1" column="0">
4398
+ <widget class="QLabel" name="lblNPDeviceDescription">
4399
+ <property name="text">
4400
<string>Device Description</string>
4404
- <item row="2" column="0" >
4405
+ <item row="2" column="0">
4407
- <property name="orientation" >
4408
+ <property name="orientation">
4409
<enum>Qt::Vertical</enum>
4411
- <property name="sizeHint" stdset="0" >
4412
+ <property name="sizeHint" stdset="0">
4416
@@ -117,24 +118,24 @@
4420
- <widget class="QWidget" name="page_5" >
4421
- <layout class="QGridLayout" >
4422
- <item row="0" column="0" >
4423
- <widget class="QLabel" name="label_9" >
4424
- <property name="text" >
4425
+ <widget class="QWidget" name="page_5">
4426
+ <layout class="QGridLayout">
4427
+ <item row="0" column="0">
4428
+ <widget class="QLabel" name="label_9">
4429
+ <property name="text">
4430
<string>Enter Device URI</string>
4434
- <item row="1" column="0" >
4435
- <widget class="QLineEdit" name="entNPTDevice" />
4436
+ <item row="1" column="0">
4437
+ <widget class="QLineEdit" name="entNPTDevice"/>
4439
- <item row="2" column="0" >
4440
+ <item row="2" column="0">
4442
- <property name="orientation" >
4443
+ <property name="orientation">
4444
<enum>Qt::Vertical</enum>
4446
- <property name="sizeHint" stdset="0" >
4447
+ <property name="sizeHint" stdset="0">
4450
<height>330</height>
4451
@@ -144,41 +145,41 @@
4455
- <widget class="QWidget" name="page_6" >
4456
- <layout class="QGridLayout" >
4457
- <item row="0" column="0" colspan="2" >
4458
- <widget class="QLabel" name="label_10" >
4459
- <property name="text" >
4460
+ <widget class="QWidget" name="page_6">
4461
+ <layout class="QGridLayout">
4462
+ <item row="0" column="0" colspan="2">
4463
+ <widget class="QLabel" name="label_10">
4464
+ <property name="text">
4465
<string>Location of the Network Printer</string>
4469
- <item row="1" column="0" >
4470
- <widget class="QLabel" name="label_11" >
4471
- <property name="text" >
4472
+ <item row="1" column="0">
4473
+ <widget class="QLabel" name="label_11">
4474
+ <property name="text">
4475
<string>Host:</string>
4479
- <item row="1" column="1" >
4480
- <widget class="QLineEdit" name="entNPTDirectJetHostname" />
4481
+ <item row="1" column="1">
4482
+ <widget class="QLineEdit" name="entNPTDirectJetHostname"/>
4484
- <item row="2" column="0" >
4485
- <widget class="QLabel" name="label_12" >
4486
- <property name="text" >
4487
+ <item row="2" column="0">
4488
+ <widget class="QLabel" name="label_12">
4489
+ <property name="text">
4490
<string>Port number:</string>
4494
- <item row="2" column="1" >
4495
- <widget class="QLineEdit" name="entNPTDirectJetPort" />
4496
+ <item row="2" column="1">
4497
+ <widget class="QLineEdit" name="entNPTDirectJetPort"/>
4499
- <item row="3" column="0" colspan="2" >
4500
+ <item row="3" column="0" colspan="2">
4502
- <property name="orientation" >
4503
+ <property name="orientation">
4504
<enum>Qt::Vertical</enum>
4506
- <property name="sizeHint" stdset="0" >
4507
+ <property name="sizeHint" stdset="0">
4510
<height>299</height>
4511
@@ -188,72 +189,72 @@
4515
- <widget class="QWidget" name="page_7" >
4516
- <layout class="QGridLayout" name="gridLayout" >
4517
- <item row="0" column="0" colspan="4" >
4518
- <widget class="QLabel" name="label_13" >
4519
- <property name="text" >
4520
+ <widget class="QWidget" name="page_7">
4521
+ <layout class="QGridLayout" name="gridLayout">
4522
+ <item row="0" column="0" colspan="4">
4523
+ <widget class="QLabel" name="label_13">
4524
+ <property name="text">
4525
<string>IPP Printer</string>
4529
- <item row="1" column="0" >
4530
- <widget class="QLabel" name="label_14" >
4531
- <property name="text" >
4532
+ <item row="1" column="0">
4533
+ <widget class="QLabel" name="label_14">
4534
+ <property name="text">
4535
<string>Host:</string>
4539
- <item row="1" column="1" colspan="2" >
4540
- <widget class="QLineEdit" name="entNPTIPPHostname" />
4541
+ <item row="1" column="1" colspan="2">
4542
+ <widget class="QLineEdit" name="entNPTIPPHostname"/>
4544
- <item row="1" column="3" >
4545
- <widget class="QPushButton" name="btnIPPFindQueue" >
4546
- <property name="enabled" >
4547
+ <item row="1" column="3">
4548
+ <widget class="QPushButton" name="btnIPPFindQueue">
4549
+ <property name="enabled">
4552
- <property name="text" >
4553
+ <property name="text">
4554
<string>Find Queue...</string>
4558
- <item row="2" column="0" >
4559
- <widget class="QLabel" name="label_15" >
4560
- <property name="text" >
4561
+ <item row="2" column="0">
4562
+ <widget class="QLabel" name="label_15">
4563
+ <property name="text">
4564
<string>Queue:</string>
4568
- <item row="2" column="1" colspan="3" >
4569
- <widget class="QLineEdit" name="entNPTIPPQueuename" />
4570
+ <item row="2" column="1" colspan="3">
4571
+ <widget class="QLineEdit" name="entNPTIPPQueuename"/>
4573
- <item row="3" column="0" >
4574
- <widget class="QLabel" name="label_34" >
4575
- <property name="text" >
4576
+ <item row="3" column="0">
4577
+ <widget class="QLabel" name="label_34">
4578
+ <property name="text">
4579
<string>URI:</string>
4583
- <item row="3" column="1" colspan="2" >
4584
- <widget class="QLabel" name="lblIPPURI" >
4585
- <property name="text" >
4586
+ <item row="3" column="1" colspan="2">
4587
+ <widget class="QLabel" name="lblIPPURI">
4588
+ <property name="text">
4589
<string>...</string>
4593
- <item row="4" column="0" colspan="2" >
4594
- <widget class="QPushButton" name="btnIPPVerify" >
4595
- <property name="text" >
4596
+ <item row="4" column="0" colspan="2">
4597
+ <widget class="QPushButton" name="btnIPPVerify">
4598
+ <property name="text">
4599
<string>Verify...</string>
4603
- <item row="4" column="2" colspan="2" >
4604
- <spacer name="horizontalSpacer" >
4605
- <property name="orientation" >
4606
+ <item row="4" column="2" colspan="2">
4607
+ <spacer name="horizontalSpacer">
4608
+ <property name="orientation">
4609
<enum>Qt::Horizontal</enum>
4611
- <property name="sizeHint" stdset="0" >
4612
+ <property name="sizeHint" stdset="0">
4616
@@ -261,12 +262,12 @@
4620
- <item row="5" column="0" colspan="4" >
4621
- <spacer name="verticalSpacer" >
4622
- <property name="orientation" >
4623
+ <item row="5" column="0" colspan="4">
4624
+ <spacer name="verticalSpacer">
4625
+ <property name="orientation">
4626
<enum>Qt::Vertical</enum>
4628
- <property name="sizeHint" stdset="0" >
4629
+ <property name="sizeHint" stdset="0">
4632
<height>297</height>
4633
@@ -276,61 +277,61 @@
4637
- <widget class="QWidget" name="page_8" >
4638
- <layout class="QGridLayout" name="gridLayout_3" >
4639
- <item row="0" column="0" colspan="3" >
4640
- <widget class="QLabel" name="label_17" >
4641
- <property name="text" >
4642
+ <widget class="QWidget" name="page_8">
4643
+ <layout class="QGridLayout" name="gridLayout_3">
4644
+ <item row="0" column="0" colspan="3">
4645
+ <widget class="QLabel" name="label_17">
4646
+ <property name="text">
4647
<string>Location of the LPD network printer</string>
4651
- <item row="1" column="0" >
4652
- <widget class="QLabel" name="label_18" >
4653
- <property name="text" >
4654
+ <item row="1" column="0">
4655
+ <widget class="QLabel" name="label_18">
4656
+ <property name="text">
4657
<string>Host:</string>
4661
- <item row="1" column="1" >
4662
- <widget class="QComboBox" name="cmbentNPTLpdHost" >
4663
- <property name="editable" >
4664
+ <item row="1" column="1">
4665
+ <widget class="QComboBox" name="cmbentNPTLpdHost">
4666
+ <property name="editable">
4670
- <property name="text" >
4671
- <string comment="KDE::DoNotExtract">localhost</string>
4672
+ <property name="text">
4673
+ <string>localhost</string>
4678
- <item row="1" column="2" >
4679
- <widget class="QPushButton" name="btnNPTLpdProbe" >
4680
- <property name="text" >
4681
+ <item row="1" column="2">
4682
+ <widget class="QPushButton" name="btnNPTLpdProbe">
4683
+ <property name="text">
4684
<string comment="Try to discover network printers">Probe</string>
4688
- <item row="2" column="0" >
4689
- <widget class="QLabel" name="label_19" >
4690
- <property name="text" >
4691
+ <item row="2" column="0">
4692
+ <widget class="QLabel" name="label_19">
4693
+ <property name="text">
4694
<string>Queue:</string>
4698
- <item row="2" column="1" colspan="2" >
4699
- <widget class="QComboBox" name="cmbentNPTLpdQueue" >
4700
- <property name="editable" >
4701
+ <item row="2" column="1" colspan="2">
4702
+ <widget class="QComboBox" name="cmbentNPTLpdQueue">
4703
+ <property name="editable">
4708
- <item row="3" column="1" colspan="2" >
4709
+ <item row="3" column="1" colspan="2">
4711
- <property name="orientation" >
4712
+ <property name="orientation">
4713
<enum>Qt::Vertical</enum>
4715
- <property name="sizeHint" stdset="0" >
4716
+ <property name="sizeHint" stdset="0">
4719
<height>295</height>
4724
- <widget class="QWidget" name="page_9" >
4725
- <widget class="QLabel" name="label_20" >
4726
- <property name="geometry" >
4727
+ <widget class="QWidget" name="page_9">
4728
+ <widget class="QLabel" name="label_20">
4729
+ <property name="geometry">
4733
@@ -350,14 +351,14 @@
4737
- <property name="text" >
4738
+ <property name="text">
4739
<string comment="KDE::DoNotExtract">TODO, SCSI</string>
4743
- <widget class="QWidget" name="page_10" >
4744
- <widget class="QLabel" name="label_21" >
4745
- <property name="geometry" >
4746
+ <widget class="QWidget" name="page_10">
4747
+ <widget class="QLabel" name="label_21">
4748
+ <property name="geometry">
4752
@@ -365,144 +366,213 @@
4756
- <property name="text" >
4757
+ <property name="text">
4758
<string comment="KDE::DoNotExtract">TODO serial</string>
4762
- <widget class="QWidget" name="page_11" >
4763
- <layout class="QGridLayout" name="gridLayout_4" >
4764
- <item row="0" column="0" colspan="4" >
4765
- <widget class="QLabel" name="label_22" >
4766
- <property name="text" >
4767
+ <widget class="QWidget" name="page_11">
4768
+ <layout class="QGridLayout" name="gridLayout_2">
4769
+ <item row="0" column="0" colspan="3">
4770
+ <widget class="QLabel" name="label_22">
4771
+ <property name="text">
4772
<string>SMB Printer</string>
4776
- <item row="1" column="0" >
4777
- <widget class="QLabel" name="label_23" >
4778
- <property name="text" >
4779
+ <item row="1" column="0">
4780
+ <widget class="QLabel" name="lblSMBUri">
4781
+ <property name="text">
4782
<string comment="KDE::DoNotExtract">smb://</string>
4786
- <item row="1" column="1" colspan="2" >
4787
- <widget class="QLineEdit" name="entSMBURI" />
4788
+ <item row="1" column="1">
4789
+ <widget class="QLineEdit" name="entSMBURI"/>
4791
- <item row="1" column="3" >
4792
- <widget class="QPushButton" name="btnSMBBrowse" >
4793
- <property name="text" >
4794
+ <item row="1" column="2">
4795
+ <widget class="QPushButton" name="btnSMBBrowse">
4796
+ <property name="text">
4797
<string>Browse</string>
4801
- <item row="2" column="0" colspan="4" >
4802
- <widget class="QLabel" name="lblSMBHint" >
4803
- <property name="text" >
4804
- <string><i>smb://[workgroup/]server[:port]/printer</i></string>
4805
+ <item row="2" column="0" colspan="3">
4806
+ <widget class="QLabel" name="lblSMBHint">
4807
+ <property name="text">
4808
+ <string><i>smb://[workgroup/]server[:port]/printer</i></string>
4812
- <item row="3" column="0" colspan="4" >
4813
- <widget class="QLabel" name="label_16" >
4814
- <property name="text" >
4815
+ <item row="3" column="0" colspan="3">
4816
+ <widget class="QLabel" name="label_16">
4817
+ <property name="text">
4818
<string>Authentication</string>
4822
- <item row="4" column="0" colspan="4" >
4823
- <widget class="QRadioButton" name="rbtnSMBAuthPrompt" >
4824
- <property name="text" >
4825
+ <item row="4" column="0" colspan="3">
4826
+ <widget class="QRadioButton" name="rbtnSMBAuthPrompt">
4827
+ <property name="text">
4828
<string>Prompt user if authentication is required</string>
4832
- <item row="5" column="0" colspan="4" >
4833
- <widget class="QRadioButton" name="rbtnSMBAuthSet" >
4834
- <property name="text" >
4835
+ <item row="5" column="0" colspan="3">
4836
+ <widget class="QRadioButton" name="rbtnSMBAuthSet">
4837
+ <property name="text">
4838
<string>Set authentication details now</string>
4842
- <item row="6" column="0" colspan="2" >
4843
- <spacer name="horizontalSpacer_2" >
4844
- <property name="orientation" >
4845
- <enum>Qt::Horizontal</enum>
4847
- <property name="sizeHint" stdset="0" >
4849
- <width>169</width>
4850
- <height>68</height>
4855
- <item row="6" column="2" colspan="2" >
4856
- <widget class="QWidget" native="1" name="tblSMBAuth" >
4857
- <layout class="QGridLayout" name="gridLayout_2" >
4858
- <item row="1" column="1" >
4859
- <widget class="QLineEdit" name="entSMBPassword" >
4860
- <property name="echoMode" >
4861
- <enum>QLineEdit::Password</enum>
4865
- <item row="1" column="0" >
4866
- <widget class="QLabel" name="label_26" >
4867
- <property name="text" >
4868
- <string>Password:</string>
4872
- <item row="0" column="1" >
4873
- <widget class="QLineEdit" name="entSMBUsername" />
4875
- <item row="0" column="0" >
4876
- <widget class="QLabel" name="label_25" >
4877
- <property name="text" >
4878
- <string>Username:</string>
4883
- <zorder>entSMBPassword</zorder>
4884
- <zorder>label_26</zorder>
4885
- <zorder>entSMBUsername</zorder>
4886
- <zorder>label_25</zorder>
4889
- <item row="7" column="0" colspan="2" >
4890
- <widget class="QPushButton" name="btnSMBVerify" >
4891
- <property name="text" >
4892
- <string>Verify</string>
4896
- <item row="7" column="2" colspan="2" >
4898
- <property name="orientation" >
4899
- <enum>Qt::Horizontal</enum>
4901
- <property name="sizeHint" stdset="0" >
4903
- <width>188</width>
4904
- <height>28</height>
4909
- <item row="8" column="0" colspan="4" >
4911
- <property name="orientation" >
4912
- <enum>Qt::Vertical</enum>
4914
- <property name="sizeHint" stdset="0" >
4916
- <width>404</width>
4917
- <height>216</height>
4921
+ <item row="6" column="0" colspan="3">
4922
+ <layout class="QVBoxLayout" name="verticalLayout">
4924
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
4926
+ <spacer name="horizontalSpacer_2">
4927
+ <property name="orientation">
4928
+ <enum>Qt::Horizontal</enum>
4930
+ <property name="sizeType">
4931
+ <enum>QSizePolicy::Fixed</enum>
4933
+ <property name="sizeHint" stdset="0">
4935
+ <width>128</width>
4936
+ <height>62</height>
4942
+ <widget class="QWidget" name="tblSMBAuth" native="true">
4943
+ <widget class="QLineEdit" name="entSMBPassword">
4944
+ <property name="geometry">
4948
+ <width>115</width>
4949
+ <height>27</height>
4952
+ <property name="echoMode">
4953
+ <enum>QLineEdit::Password</enum>
4956
+ <widget class="QLabel" name="label_26">
4957
+ <property name="geometry">
4962
+ <height>27</height>
4965
+ <property name="text">
4966
+ <string>Password:</string>
4969
+ <widget class="QLineEdit" name="entSMBUsername">
4970
+ <property name="geometry">
4974
+ <width>115</width>
4975
+ <height>27</height>
4979
+ <widget class="QLabel" name="label_25">
4980
+ <property name="geometry">
4985
+ <height>27</height>
4988
+ <property name="text">
4989
+ <string>Username:</string>
4995
+ <spacer name="horizontalSpacer_3">
4996
+ <property name="orientation">
4997
+ <enum>Qt::Horizontal</enum>
4999
+ <property name="sizeType">
5000
+ <enum>QSizePolicy::Fixed</enum>
5002
+ <property name="sizeHint" stdset="0">
5005
+ <height>17</height>
5013
+ <layout class="QHBoxLayout" name="horizontalLayout">
5016
+ <property name="orientation">
5017
+ <enum>Qt::Horizontal</enum>
5019
+ <property name="sizeType">
5020
+ <enum>QSizePolicy::Minimum</enum>
5022
+ <property name="sizeHint" stdset="0">
5024
+ <width>198</width>
5025
+ <height>22</height>
5031
+ <widget class="QPushButton" name="btnSMBVerify">
5032
+ <property name="text">
5033
+ <string>Verify</string>
5038
+ <spacer name="horizontalSpacer_4">
5039
+ <property name="orientation">
5040
+ <enum>Qt::Horizontal</enum>
5042
+ <property name="sizeType">
5043
+ <enum>QSizePolicy::Fixed</enum>
5045
+ <property name="sizeHint" stdset="0">
5048
+ <height>20</height>
5057
+ <property name="orientation">
5058
+ <enum>Qt::Vertical</enum>
5060
+ <property name="sizeHint" stdset="0">
5062
+ <width>415</width>
5063
+ <height>208</height>
5072
@@ -510,118 +580,118 @@
5076
- <widget class="QWidget" name="page_12" >
5077
- <layout class="QGridLayout" >
5078
- <item row="0" column="0" colspan="2" >
5079
- <widget class="QRadioButton" name="rbtnNPFoomatic" >
5080
- <property name="text" >
5081
+ <widget class="QWidget" name="page_12">
5082
+ <layout class="QGridLayout">
5083
+ <item row="0" column="0" colspan="2">
5084
+ <widget class="QRadioButton" name="rbtnNPFoomatic">
5085
+ <property name="text">
5086
<string>Select printer from database</string>
5090
- <item row="1" column="0" colspan="2" >
5091
- <widget class="QLabel" name="label_27" >
5092
- <property name="text" >
5093
+ <item row="1" column="0" colspan="2">
5094
+ <widget class="QLabel" name="label_27">
5095
+ <property name="text">
5096
<string>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.</string>
5098
- <property name="wordWrap" >
5099
+ <property name="wordWrap">
5104
- <item row="2" column="0" colspan="2" >
5105
- <widget class="QListWidget" name="tvNPMakes" />
5106
+ <item row="2" column="0" colspan="2">
5107
+ <widget class="QListWidget" name="tvNPMakes"/>
5109
- <item row="3" column="0" colspan="2" >
5110
- <widget class="QRadioButton" name="rbtnNPPPD" >
5111
- <property name="text" >
5112
+ <item row="3" column="0" colspan="2">
5113
+ <widget class="QRadioButton" name="rbtnNPPPD">
5114
+ <property name="text">
5115
<string>Provide PPD file</string>
5119
- <item row="4" column="0" colspan="2" >
5120
- <widget class="QLabel" name="label_28" >
5121
- <property name="text" >
5122
- <string><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></string>
5123
+ <item row="4" column="0" colspan="2">
5124
+ <widget class="QLabel" name="label_28">
5125
+ <property name="text">
5126
+ <string><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></string>
5128
- <property name="wordWrap" >
5129
+ <property name="wordWrap">
5134
- <item row="5" column="0" >
5135
- <widget class="QLineEdit" name="filechooserPPD" />
5136
+ <item row="5" column="0">
5137
+ <widget class="QLineEdit" name="filechooserPPD"/>
5139
- <item row="5" column="1" >
5140
- <widget class="QPushButton" name="filechooserPPDButton" >
5141
- <property name="text" >
5142
+ <item row="5" column="1">
5143
+ <widget class="QPushButton" name="filechooserPPDButton">
5144
+ <property name="text">
5145
<string>Browse</string>
5149
- <item row="6" column="0" colspan="2" >
5150
- <widget class="QWidget" native="1" name="downloadableDriverSearchFrame" >
5151
- <layout class="QGridLayout" >
5152
- <item row="0" column="0" colspan="3" >
5153
- <widget class="QRadioButton" name="rbtnNPDownloadableDriverSearch" >
5154
- <property name="text" >
5155
+ <item row="6" column="0" colspan="2">
5156
+ <widget class="QWidget" name="downloadableDriverSearchFrame" native="true">
5157
+ <layout class="QGridLayout">
5158
+ <item row="0" column="0" colspan="3">
5159
+ <widget class="QRadioButton" name="rbtnNPDownloadableDriverSearch">
5160
+ <property name="text">
5161
<string>Search for a printer driver to download</string>
5165
- <item row="1" column="0" colspan="3" >
5166
- <widget class="QLabel" name="label_29" >
5167
- <property name="text" >
5168
+ <item row="1" column="0" colspan="3">
5169
+ <widget class="QLabel" name="label_29">
5170
+ <property name="text">
5171
<string>Enter some search terms for the model of your printer.</string>
5175
- <item row="2" column="0" >
5176
- <widget class="QLabel" name="label_30" >
5177
- <property name="text" >
5178
+ <item row="2" column="0">
5179
+ <widget class="QLabel" name="label_30">
5180
+ <property name="text">
5181
<string>Search terms:</string>
5185
- <item row="2" column="1" >
5186
- <widget class="QLineEdit" name="entNPDownloadableDriverSearch" />
5187
+ <item row="2" column="1">
5188
+ <widget class="QLineEdit" name="entNPDownloadableDriverSearch"/>
5190
- <item row="2" column="2" >
5191
- <widget class="QPushButton" name="btnNPDownloadableDriverSearch" >
5192
- <property name="text" >
5193
+ <item row="2" column="2">
5194
+ <widget class="QPushButton" name="btnNPDownloadableDriverSearch">
5195
+ <property name="text">
5196
<string>Search</string>
5200
- <item row="3" column="0" >
5201
- <widget class="QLabel" name="label_31" >
5202
- <property name="text" >
5203
+ <item row="3" column="0">
5204
+ <widget class="QLabel" name="label_31">
5205
+ <property name="text">
5206
<string>Printer model:</string>
5210
- <item row="3" column="1" colspan="2" >
5211
- <widget class="QComboBox" name="cmbNPDownloadableDriverFoundPrinters" />
5212
+ <item row="3" column="1" colspan="2">
5213
+ <widget class="QComboBox" name="cmbNPDownloadableDriverFoundPrinters"/>
5220
- <widget class="QWidget" name="page_13" >
5221
- <layout class="QGridLayout" >
5222
- <item rowspan="2" row="1" column="0" >
5223
- <widget class="QListWidget" name="tvNPModels" />
5224
+ <widget class="QWidget" name="page_13">
5225
+ <layout class="QGridLayout">
5226
+ <item row="1" column="0" rowspan="2">
5227
+ <widget class="QListWidget" name="tvNPModels"/>
5229
- <item row="1" column="1" colspan="2" >
5230
- <widget class="QListWidget" name="tvNPDrivers" />
5231
+ <item row="1" column="1" colspan="2">
5232
+ <widget class="QListWidget" name="tvNPDrivers"/>
5234
- <item row="2" column="1" >
5235
+ <item row="2" column="1">
5237
- <property name="orientation" >
5238
+ <property name="orientation">
5239
<enum>Qt::Horizontal</enum>
5241
- <property name="sizeHint" stdset="0" >
5242
+ <property name="sizeHint" stdset="0">
5246
@@ -629,55 +699,55 @@
5250
- <item row="2" column="2" >
5251
- <widget class="QPushButton" name="btnNPPDComments" >
5252
- <property name="text" >
5253
+ <item row="2" column="2">
5254
+ <widget class="QPushButton" name="btnNPPDComments">
5255
+ <property name="text">
5256
<string>Comments</string>
5260
- <item row="0" column="0" >
5261
- <widget class="QLabel" name="label_32" >
5262
- <property name="text" >
5263
+ <item row="0" column="0">
5264
+ <widget class="QLabel" name="label_32">
5265
+ <property name="text">
5266
<string>Models:</string>
5270
- <item row="0" column="1" >
5271
- <widget class="QLabel" name="label_33" >
5272
- <property name="text" >
5273
+ <item row="0" column="1">
5274
+ <widget class="QLabel" name="label_33">
5275
+ <property name="text">
5276
<string>Driver:</string>
5282
- <widget class="QWidget" name="page_2" >
5283
- <layout class="QGridLayout" >
5284
- <item row="0" column="0" >
5285
- <widget class="QLabel" name="label_4" >
5286
- <property name="text" >
5287
+ <widget class="QWidget" name="page_2">
5288
+ <layout class="QGridLayout">
5289
+ <item row="0" column="0">
5290
+ <widget class="QLabel" name="label_4">
5291
+ <property name="text">
5292
<string>Printers to be members of this class</string>
5296
- <item row="1" column="0" >
5297
- <layout class="QGridLayout" >
5298
- <item row="0" column="0" >
5299
- <widget class="QLabel" name="label_6" >
5300
- <property name="text" >
5301
+ <item row="1" column="0">
5302
+ <layout class="QGridLayout">
5303
+ <item row="0" column="0">
5304
+ <widget class="QLabel" name="label_6">
5305
+ <property name="text">
5306
<string>Members of this class</string>
5310
- <item rowspan="2" row="0" column="1" >
5311
- <layout class="QVBoxLayout" >
5312
+ <item row="0" column="1" rowspan="2">
5313
+ <layout class="QVBoxLayout">
5316
- <property name="orientation" >
5317
+ <property name="orientation">
5318
<enum>Qt::Vertical</enum>
5320
- <property name="sizeHint" stdset="0" >
5321
+ <property name="sizeHint" stdset="0">
5325
@@ -686,25 +756,25 @@
5329
- <widget class="QPushButton" name="btnNCAddMember" >
5330
- <property name="text" >
5331
- <string><</string>
5332
+ <widget class="QPushButton" name="btnNCAddMember">
5333
+ <property name="text">
5339
- <widget class="QPushButton" name="btnNCDelMember" >
5340
- <property name="text" >
5341
- <string>></string>
5342
+ <widget class="QPushButton" name="btnNCDelMember">
5343
+ <property name="text">
5350
- <property name="orientation" >
5351
+ <property name="orientation">
5352
<enum>Qt::Vertical</enum>
5354
- <property name="sizeHint" stdset="0" >
5355
+ <property name="sizeHint" stdset="0">
5358
<height>291</height>
5359
@@ -714,72 +784,72 @@
5363
- <item row="0" column="2" >
5364
- <widget class="QLabel" name="label_5" >
5365
- <property name="text" >
5366
+ <item row="0" column="2">
5367
+ <widget class="QLabel" name="label_5">
5368
+ <property name="text">
5369
<string>Others</string>
5373
- <item row="1" column="0" >
5374
- <widget class="QListWidget" name="tvNCMembers" />
5375
+ <item row="1" column="0">
5376
+ <widget class="QListWidget" name="tvNCMembers"/>
5378
- <item row="1" column="2" >
5379
- <widget class="QListWidget" name="tvNCNotMembers" />
5380
+ <item row="1" column="2">
5381
+ <widget class="QListWidget" name="tvNCNotMembers"/>
5387
- <widget class="QWidget" name="page_14" >
5388
- <layout class="QGridLayout" name="gridLayout_5" >
5389
- <item row="0" column="0" >
5390
- <widget class="QLabel" name="label_24" >
5391
- <property name="text" >
5392
+ <widget class="QWidget" name="page_14">
5393
+ <layout class="QGridLayout" name="gridLayout_5">
5394
+ <item row="0" column="0">
5395
+ <widget class="QLabel" name="label_24">
5396
+ <property name="text">
5397
<string>Try to transfer the current settings</string>
5401
- <item row="1" column="0" >
5402
- <widget class="QRadioButton" name="rbtnChangePPDasIs" >
5403
- <property name="text" >
5404
+ <item row="1" column="0">
5405
+ <widget class="QRadioButton" name="rbtnChangePPDasIs">
5406
+ <property name="text">
5407
<string>Use the new PPD (Postscript Printer Description) as is.</string>
5411
- <item row="2" column="0" >
5412
- <widget class="QLabel" name="label_37" >
5413
- <property name="text" >
5414
- <string>This way all current option settings will be lost. The default settings of the new PPD will be used.</string>
5415
+ <item row="2" column="0">
5416
+ <widget class="QLabel" name="label_37">
5417
+ <property name="text">
5418
+ <string>This way all current option settings will be lost. The default settings of the new PPD will be used. </string>
5420
- <property name="wordWrap" >
5421
+ <property name="wordWrap">
5426
- <item row="3" column="0" >
5427
- <widget class="QRadioButton" name="rbtnChangePPDKeepSettings" >
5428
- <property name="text" >
5429
- <string>Try to copy the option settings over from the old PPD.</string>
5430
+ <item row="3" column="0">
5431
+ <widget class="QRadioButton" name="rbtnChangePPDKeepSettings">
5432
+ <property name="text">
5433
+ <string>Try to copy the option settings over from the old PPD. </string>
5437
- <item row="4" column="0" >
5438
- <widget class="QLabel" name="label_38" >
5439
- <property name="text" >
5440
+ <item row="4" column="0">
5441
+ <widget class="QLabel" name="label_38">
5442
+ <property name="text">
5443
<string>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.</string>
5445
- <property name="wordWrap" >
5446
+ <property name="wordWrap">
5451
- <item row="6" column="0" >
5452
- <spacer name="verticalSpacer_2" >
5453
- <property name="orientation" >
5454
+ <item row="6" column="0">
5455
+ <spacer name="verticalSpacer_2">
5456
+ <property name="orientation">
5457
<enum>Qt::Vertical</enum>
5459
- <property name="sizeHint" stdset="0" >
5460
+ <property name="sizeHint" stdset="0">
5463
<height>317</height>
5464
@@ -787,14 +857,14 @@
5468
- <item row="5" column="0" >
5469
- <layout class="QFormLayout" name="formLayout" />
5470
+ <item row="5" column="0">
5471
+ <layout class="QFormLayout" name="formLayout"/>
5475
- <widget class="QWidget" name="page_15" >
5476
- <widget class="QLabel" name="label_35" >
5477
- <property name="geometry" >
5478
+ <widget class="QWidget" name="page_15">
5479
+ <widget class="QLabel" name="label_35">
5480
+ <property name="geometry">
5484
@@ -802,14 +872,14 @@
5488
- <property name="text" >
5489
+ <property name="text">
5490
<string comment="KDE::DoNotExtract">TODO: Installed Options page</string>
5494
- <widget class="QWidget" name="page_16" >
5495
- <widget class="QLabel" name="label_36" >
5496
- <property name="geometry" >
5497
+ <widget class="QWidget" name="page_16">
5498
+ <widget class="QLabel" name="label_36">
5499
+ <property name="geometry">
5503
@@ -817,19 +887,19 @@
5507
- <property name="text" >
5508
+ <property name="text">
5509
<string comment="KDE::DoNotExtract">TODO: Downloadable Driver page</string>
5515
- <item row="1" column="0" >
5516
+ <item row="1" column="0">
5518
- <property name="orientation" >
5519
+ <property name="orientation">
5520
<enum>Qt::Horizontal</enum>
5522
- <property name="sizeHint" stdset="0" >
5523
+ <property name="sizeHint" stdset="0">
5527
@@ -837,30 +907,30 @@
5531
- <item row="1" column="1" >
5532
- <widget class="QPushButton" name="btnNPBack" >
5533
- <property name="text" >
5534
- <string>< Back</string>
5535
+ <item row="1" column="1">
5536
+ <widget class="QPushButton" name="btnNPBack">
5537
+ <property name="text">
5538
+ <string>Back</string>
5542
- <item row="1" column="2" >
5543
- <widget class="QPushButton" name="btnNPForward" >
5544
- <property name="text" >
5545
- <string>Forward ></string>
5546
+ <item row="1" column="2">
5547
+ <widget class="QPushButton" name="btnNPForward">
5548
+ <property name="text">
5549
+ <string>Forward</string>
5553
- <item row="1" column="3" >
5554
- <widget class="QPushButton" name="btnNPApply" >
5555
- <property name="text" >
5556
+ <item row="1" column="3">
5557
+ <widget class="QPushButton" name="btnNPApply">
5558
+ <property name="text">
5563
- <item row="1" column="4" >
5564
- <widget class="QPushButton" name="btnNPCancel" >
5565
- <property name="text" >
5566
+ <item row="1" column="4">
5567
+ <widget class="QPushButton" name="btnNPCancel">
5568
+ <property name="text">
5569
<string>Cancel</string>
5572
diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/options.py kdeadmin-4.2.2/system-config-printer-kde/options.py
5573
--- orig/kdeadmin-4.2.2/system-config-printer-kde/options.py 1970-01-01 01:00:00.000000000 +0100
5574
+++ kdeadmin-4.2.2/system-config-printer-kde/options.py 2009-04-09 22:56:08.000000000 +0100
5576
+# -*- coding: utf-8 -*-
5577
+## system-config-printer
5579
+#############################################################################
5581
+## Copyright 2007-2009 Canonical Ltd
5582
+## Copyright 2008-2009 Richard Birnie <arbyuk@googlemail.com>
5583
+## Author: Jonathan Riddell <jriddell@ubuntu.com>
5584
+## Richard Birnie <arbyuk@googlemail.com>
5586
+## Includes code from System Config Printer:
5587
+## Copyright (C) 2006, 2007, 2008 Red Hat, Inc.
5588
+## Copyright (C) 2006, 2007 Florian Festi <ffesti@redhat.com>
5589
+## Copyright (C) 2006, 2007, 2008 Tim Waugh <twaugh@redhat.com>
5591
+## This program is free software; you can redistribute it and/or
5592
+## modify it under the terms of the GNU General Public License as
5593
+## published by the Free Software Foundation; either version 2 of
5594
+## the License, or (at your option) any later version.
5596
+## This program is distributed in the hope that it will be useful,
5597
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
5598
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5599
+## GNU General Public License for more details.
5601
+## You should have received a copy of the GNU General Public License
5602
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
5604
+#############################################################################
5606
+from PyQt4.QtCore import *
5607
+from PyQt4.QtGui import *
5610
+These classes are used in the Job Options tab of the printer config dialogue
5613
+def OptionWidget(name, v, s, on_change):
5614
+ if isinstance(v, list):
5616
+ if isinstance(s, list):
5618
+ if not isinstance(vv, str): raise ValueError
5619
+ return OptionSelectMany(name, v, s, on_change)
5621
+ raise NotImplemented
5623
+ if (isinstance(s, int) or
5624
+ isinstance(s, float) or
5625
+ (isinstance(s, tuple) and
5627
+ ((isinstance(s[0], int) and isinstance(s[1], int)) or
5628
+ (isinstance(s[0], float) and isinstance(s[1], float))))):
5630
+ if (isinstance(s, int) or
5631
+ isinstance(s, tuple) and isinstance(s[0], int)):
5635
+ except ValueError:
5636
+ return OptionText(name, v, "", on_change)
5637
+ return OptionNumeric(name, v, s, on_change)
5638
+ elif isinstance(s, list):
5640
+ if not isinstance(sv, int):
5641
+ return OptionSelectOne(name, v, s, on_change)
5644
+ except ValueError:
5645
+ return OptionSelectOne(name, v, s, on_change)
5646
+ return OptionSelectOneNumber(name, v, s, on_change)
5647
+ elif isinstance(s, str):
5648
+ return OptionText(name, v, s, on_change)
5652
+# ---------------------------------------------------------------------------
5654
+class OptionInterface:
5655
+ def get_current_value(self):
5656
+ raise NotImplemented
5658
+ def is_changed(self):
5659
+ raise NotImplemented
5661
+class OptionAlwaysShown(OptionInterface):
5667
+ def __init__(self, name, ipp_type, system_default,
5668
+ widget, button, combobox_map = None, use_supported = False):
5670
+ self.widget = widget
5671
+ self.button = button
5672
+ if ipp_type == bool:
5673
+ def bool_type (x):
5674
+ if type (x) == str:
5675
+ if x.lower () in ("false", "no", "off"):
5677
+ # Even the empty string is true.
5680
+ ipp_type = bool_type
5681
+ self.ipp_type = ipp_type
5682
+ self.set_default (system_default)
5683
+ self.combobox_map = combobox_map
5684
+ if combobox_map != None and ipp_type == int:
5687
+ while i < self.widget.count():
5688
+ dict[combobox_map[i]] = self.widget.itemText(i)
5690
+ self.combobox_dict = dict
5691
+ self.use_supported = use_supported
5692
+ self.reinit (None)
5694
+ def set_default(self, system_default):
5695
+ # For the media option, the system default depends on the printer's
5696
+ # PageSize setting. This method allows the main module to tell us
5698
+ self.system_default = self.ipp_type (system_default)
5700
+ def reinit(self, original_value, supported=None):
5701
+ """Set the original value of the option and the supported choices.
5702
+ The special value None for original_value resets the option to the
5703
+ system default."""
5704
+ if (supported != None and
5705
+ self.use_supported):
5706
+ if (type(self.widget) == QComboBox and
5707
+ self.ipp_type == str):
5708
+ self.widget.clear()
5709
+ for each in supported:
5710
+ self.widget.addItem(each)
5711
+ elif (type(self.widget) == QComboBox and
5712
+ self.ipp_type == int and
5713
+ self.combobox_map != None):
5714
+ self.widget.clear()
5715
+ for each in supported:
5716
+ self.widget.addItem(self.combobox_dict[each])
5717
+ if original_value != None:
5718
+ self.original_value = self.ipp_type (original_value)
5719
+ self.set_widget_value (self.original_value)
5720
+ if original_value != self.get_widget_value():
5721
+ self.button.setEnabled(True)
5723
+ self.original_value = None
5724
+ self.set_widget_value (self.system_default)
5725
+ self.button.setEnabled(False)
5726
+ self.state = self.STATE_UNCHANGED
5728
+ def set_widget_value(self, ipp_value):
5729
+ t = type(self.widget)
5731
+ return self.widget.setValue(ipp_value)
5732
+ elif t == QComboBox:
5733
+ if self.ipp_type == str and self.combobox_map == None:
5734
+ index = self.widget.findText(ipp_value)
5736
+ self.widget.setCurrentIndex(index)
5739
+ if self.combobox_map:
5740
+ index = self.combobox_map.index (ipp_value)
5743
+ return self.widget.setCurrentIndex(index)
5744
+ elif t == QCheckBox:
5745
+ return self.widget.setChecked(ipp_value)
5747
+ raise NotImplemented
5749
+ def get_widget_value(self):
5750
+ t = type(self.widget)
5752
+ # Ideally we would use self.widget.get_value() here, but
5753
+ # it doesn't work if the value has been typed in and then
5754
+ # the Apply button immediately clicked. To handle this,
5755
+ # we use self.widget.get_text() and fall back to
5756
+ # get_value() if the result cannot be interpreted as the
5759
+ return self.ipp_type (self.widget.value ())
5760
+ except ValueError:
5761
+ # Can't convert result of get_text() to ipp_type.
5762
+ return self.ipp_type (self.widget.value ())
5763
+ elif t == QComboBox:
5764
+ if self.combobox_map:
5765
+ return self.combobox_map[self.widget.currentIndex()]
5766
+ if self.ipp_type == str:
5767
+ return self.widget.currentText()
5768
+ return self.ipp_type (unicode(self.widget.currentText()))
5769
+ elif t == QCheckBox:
5770
+ return self.ipp_type (self.widget.isChecked())
5772
+ raise NotImplemented
5774
+ def get_current_value(self):
5775
+ return self.get_widget_value ()
5777
+ def is_changed(self):
5778
+ if self.original_value != None:
5779
+ # There was a value set previously.
5780
+ if self.state == self.STATE_RESET:
5781
+ # It's been removed.
5783
+ if self.state == self.STATE_ADJUSTED:
5784
+ if self.get_current_value () != self.original_value:
5788
+ # The value is the same as before, and not reset.
5791
+ # There was no original value set.
5792
+ if self.state == self.STATE_ADJUSTED:
5793
+ # It's been adjusted.
5796
+ # It's been left alone, or possible adjusted and then reset.
5800
+ self.set_widget_value (self.system_default)
5801
+ self.state = self.STATE_RESET
5802
+ self.button.setEnabled(False)
5804
+ def changed(self):
5805
+ self.state = self.STATE_ADJUSTED
5806
+ self.button.setEnabled(True)
5808
+class OptionAlwaysShownSpecial(OptionAlwaysShown):
5809
+ def __init__(self, name, ipp_type, system_default,
5810
+ widget, button, combobox_map = None, use_supported = False,
5811
+ special_choice = "System default"):
5812
+ self.special_choice = special_choice
5813
+ self.special_choice_shown = False
5814
+ OptionAlwaysShown.__init__ (self, name, ipp_type, system_default,
5816
+ combobox_map=combobox_map,
5817
+ use_supported=use_supported)
5819
+ def show_special_choice (self):
5820
+ if self.special_choice_shown:
5823
+ self.special_choice_shown = True
5824
+ # Only works for ComboBox widgets
5825
+ self.widget.insertItem(0, self.special_choice)
5826
+ self.widget.setCurrentIndex(0)
5827
+ ##model = self.widget.get_model ()
5828
+ ##iter = model.insert (0)
5829
+ ##model.set_value (iter, 0, self.special_choice)
5830
+ ##self.widget.set_active_iter (model.get_iter_first ())
5832
+ def hide_special_choice (self):
5833
+ if not self.special_choice_shown:
5836
+ self.special_choice_shown = False
5837
+ # Only works for ComboBox widgets
5838
+ self.widget.removeItem(0)
5840
+ def reinit(self, original_value, supported=None):
5841
+ if original_value != None:
5842
+ self.hide_special_choice ()
5844
+ self.show_special_choice ()
5846
+ OptionAlwaysShown.reinit (self, original_value, supported=supported)
5849
+ self.show_special_choice ()
5850
+ OptionAlwaysShown.reset (self)
5852
+ def changed(self):
5853
+ OptionAlwaysShown.changed (self)
5854
+ if self.widget.currentIndex() > 0:
5855
+ self.hide_special_choice ()
5857
+class Option(OptionInterface):
5861
+ def __init__(self, name, value, supported, on_change):
5863
+ self.value = value
5864
+ self.supported = supported
5865
+ self.on_change = on_change
5866
+ self.is_new = False
5868
+ label = unicode(name)
5869
+ if not label.endswith (':'):
5871
+ self.label = QLabel(label)
5873
+ def get_current_value(self):
5874
+ raise NotImplemented
5876
+ def is_changed(self):
5877
+ return (self.is_new or
5878
+ str (self.get_current_value()) != str (self.value))
5880
+ def changed(self, widget, *args):
5881
+ self.on_change(self)
5883
+# ---------------------------------------------------------------------------
5885
+class OptionSelectOne(Option):
5887
+ def __init__(self, name, value, supported, on_change):
5888
+ Option.__init__(self, name, value, supported, on_change)
5890
+ self.selector = gtk.combo_box_new_text()
5894
+ for nr, choice in enumerate(supported):
5895
+ self.selector.append_text(str(choice))
5896
+ if str (value) == str (choice):
5898
+ if selected is not None:
5899
+ self.selector.set_active(selected)
5901
+ print "Unknown value for %s: %s" % (name, value)
5902
+ print "Choices:", supported
5903
+ self.selector.connect("changed", self.changed)
5905
+ def get_current_value(self):
5906
+ return self.selector.get_active_text()
5908
+# ---------------------------------------------------------------------------
5910
+class OptionSelectOneNumber(OptionSelectOne):
5912
+ def get_current_value(self):
5913
+ return int(self.selector.get_active_text())
5915
+# ---------------------------------------------------------------------------
5917
+class OptionSelectMany(Option):
5919
+ def __init__(self, name, value, supported, on_change):
5920
+ Option.__init__(self, name, value, supported, on_change)
5921
+ self.checkboxes = []
5924
+ for s in supported:
5925
+ checkbox = gtk.CheckButton(label=s)
5926
+ checkbox.set_active(s in value)
5927
+ vbox.add(checkbox)
5928
+ checkbox.connect("toggled", self.changed)
5929
+ self.checkboxes.append(checkbox)
5930
+ self.selector = vbox
5932
+ def get_current_value(self):
5933
+ return[s for s, chk in zip(self.supported, self.checkboxes)
5934
+ if chk.get_active()]
5936
+# ---------------------------------------------------------------------------
5938
+class OptionNumeric(Option):
5939
+ def __init__(self, name, value, supported, on_change):
5940
+ self.is_float = (isinstance(supported, float) or
5941
+ (isinstance(supported, tuple) and
5942
+ isinstance(supported[0], float)))
5948
+ if not isinstance(supported, tuple):
5949
+ supported = (0, supported)
5950
+ Option.__init__(self, name, value, supported, on_change)
5951
+ adj = gtk.Adjustment(value, supported[0], supported[1], 1.0, 5.0, 0.0)
5952
+ self.selector = gtk.SpinButton(adj, climb_rate=1.0, digits=digits)
5953
+ if not self.is_float:
5954
+ self.selector.set_numeric(True)
5955
+ self.selector.connect("changed", self.changed)
5957
+ def get_current_value(self):
5959
+ return self.selector.get_value()
5960
+ return self.selector.get_value_as_int()
5962
+# ---------------------------------------------------------------------------
5964
+class OptionText(Option):
5965
+ def __init__(self, name, value, supported, on_change):
5966
+ Option.__init__(self, name, value, supported, on_change)
5968
+ self.selector = QLineEdit()
5969
+ self.selector.setText(value)
5970
+ self.selector.connect(self.selector, SIGNAL("textChanged(QString)"), self.changed)
5972
+ def get_current_value(self):
5973
+ return self.selector.text()
5974
diff -urN orig/kdeadmin-4.2.2/system-config-printer-kde/optionwidgets.py kdeadmin-4.2.2/system-config-printer-kde/optionwidgets.py
5975
--- orig/kdeadmin-4.2.2/system-config-printer-kde/optionwidgets.py 1970-01-01 01:00:00.000000000 +0100
5976
+++ kdeadmin-4.2.2/system-config-printer-kde/optionwidgets.py 2009-04-09 22:56:08.000000000 +0100
5978
+# -*- coding: utf-8 -*-
5979
+## system-config-printer
5981
+#############################################################################
5983
+## Copyright 2007-2009 Canonical Ltd
5984
+## Copyright 2008-2009 Richard Birnie <arbyuk@googlemail.com>
5985
+## Author: Jonathan Riddell <jriddell@ubuntu.com>
5986
+## Richard Birnie <arbyuk@googlemail.com>
5988
+## Includes code from System Config Printer:
5989
+## Copyright (C) 2006, 2007, 2008 Red Hat, Inc.
5990
+## Copyright (C) 2006, 2007 Florian Festi <ffesti@redhat.com>
5991
+## Copyright (C) 2006, 2007, 2008 Tim Waugh <twaugh@redhat.com>
5993
+## This program is free software; you can redistribute it and/or
5994
+## modify it under the terms of the GNU General Public License as
5995
+## published by the Free Software Foundation; either version 2 of
5996
+## the License, or (at your option) any later version.
5998
+## This program is distributed in the hope that it will be useful,
5999
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
6000
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6001
+## GNU General Public License for more details.
6003
+## You should have received a copy of the GNU General Public License
6004
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
6006
+#############################################################################
6009
+from PyQt4.QtCore import *
6010
+from PyQt4.QtGui import *
6011
+from PyKDE4.kdecore import i18n
6014
+These classes are used to dynamically generate the UI on the Options tab of the printer config dialogue
6017
+def OptionWidget(option, ppd, gui, tab_label=None):
6018
+ """Factory function"""
6020
+ if (ui == cups.PPD_UI_BOOLEAN and
6021
+ len (option.choices) != 2):
6022
+ # This option is advertised as a Boolean but in fact has more
6023
+ # than two choices.
6024
+ print "Treating Boolean option %s as PickOne" % option.keyword
6025
+ ui = cups.PPD_UI_PICKONE
6027
+ if ui == cups.PPD_UI_BOOLEAN:
6028
+ return OptionBool(option, ppd, gui, tab_label=tab_label)
6030
+ elif ui == cups.PPD_UI_PICKONE:
6031
+ return OptionPickOne(option, ppd, gui, tab_label=tab_label)
6032
+ elif ui == cups.PPD_UI_PICKMANY:
6033
+ ##return OptionPickMany(option, ppd, gui, tab_label=tab_label)
6036
+# ---------------------------------------------------------------------------
6037
+class Option(QObject):
6039
+ def __init__(self, option, ppd, gui, tab_label=None):
6040
+ QObject.__init__(self)
6041
+ self.option = option
6044
+ self.enabled = True
6045
+ self.tab_label = tab_label
6047
+ ##vbox = gtk.VBox()
6049
+ #self.btnConflict = gtk.Button()
6050
+ #icon = gtk.image_new_from_stock(gtk.STOCK_DIALOG_WARNING,
6051
+ # gtk.ICON_SIZE_SMALL_TOOLBAR)
6052
+ #self.btnConflict.add(icon)
6053
+ #self.btnConflict.set_no_show_all(True) #avoid the button taking
6054
+ # over control again
6055
+ #vbox.add(self.btnConflict) # vbox reserves space while button
6056
+ #vbox.set_size_request(32, 28) # is hidden
6057
+ #self.conflictIcon = vbox
6059
+ #self.btnConflict.connect("clicked", self.on_btnConflict_clicked)
6062
+ self.constraints = [c for c in ppd.constraints
6063
+ if c.option1 == option.keyword]
6064
+ #for c in self.constraints:
6065
+ # if not c.choice1 or not c.choice2:
6066
+ # print c.option1, repr(c.choice1), c.option2, repr(c.choice2)
6067
+ self.conflicts = set()
6068
+ self.conflict_message = ""
6070
+ def enable(self, enabled=True):
6071
+ self.selector.setEnabled(enabled)
6072
+ self.enabled = enabled
6074
+ def disable(self):
6075
+ self.enable (False)
6077
+ def is_enabled(self):
6078
+ return self.enabled
6080
+ def get_current_value(self):
6081
+ raise NotImplemented
6083
+ def is_changed(self):
6084
+ return self.get_current_value()!= self.option.defchoice
6086
+ def writeback(self):
6088
+ self.ppd.markOption(self.option.keyword, self.get_current_value())
6090
+ def checkConflicts(self, update_others=True):
6091
+ value = self.get_current_value()
6092
+ for constraint in self.constraints:
6093
+ option2 = self.gui.options.get(constraint.option2, None)
6094
+ if option2 is None: continue
6096
+ if (constraint.choice1==value and
6097
+ option2.get_current_value() == constraint.choice2):
6099
+ self.conflicts.add(constraint)
6101
+ option2.checkConflicts(update_others=False)
6102
+ elif constraint in self.conflicts:
6104
+ self.conflicts.remove(constraint)
6105
+ option2.checkConflicts(update_others=False)
6108
+ tooltip = [unicode(i18n("Conflicts with:"))]
6109
+ for c in self.conflicts:
6110
+ option = self.gui.options.get(c.option2)
6111
+ tooltip.append(option.option.text)
6113
+ tooltip = "\n".join(tooltip)
6115
+ self.conflict_message = tooltip # XXX more verbose
6117
+ if self.conflicts:
6118
+ #FIXME: btnConflict not impemented yet
6119
+ #self.gui.btnConflict.setTooltip(tooltip + "OPTION-" + self.option.keyword)
6120
+ #self.btnConflict.show()
6123
+ #self.btnConflict.hide()
6126
+ self.gui.option_changed(self)
6127
+ return self.conflicts
6129
+ def on_change(self, index):
6130
+ self.checkConflicts()
6133
+ def on_btnConflict_clicked(self, button):
6134
+ self.dialog.set_markup(self.conflict_message)
6136
+ self.dialog.hide()
6138
+# ---------------------------------------------------------------------------
6142
+class OptionBool(Option):
6144
+ def __init__(self, option, ppd, gui, tab_label=None):
6145
+ self.selector = QCheckBox(option.text, gui)
6147
+ self.false = u"False" # hack to allow "None" instead of "False"
6148
+ self.true = u"True"
6149
+ for c in option.choices:
6150
+ if c["choice"] in ("None", "False", "Off"):
6151
+ self.false = c["choice"]
6152
+ if c["choice"] in ("True", "On"):
6153
+ self.true = c["choice"]
6154
+ self.selector.setChecked(option.defchoice == self.true)
6155
+ #self.selector.set_alignment(0.0, 0.5)
6156
+ self.connect(self.selector, SIGNAL("toggled(bool)"), self.on_change)
6157
+ Option.__init__(self, option, ppd, gui, tab_label=tab_label)
6159
+ def get_current_value(self):
6160
+ return (self.false, self.true)[self.selector.isChecked()]
6162
+# ---------------------------------------------------------------------------
6164
+class OptionPickOne(Option):
6165
+ widget_name = "OptionPickOne"
6167
+ def __init__(self, option, ppd, gui, tab_label=None):
6168
+ self.selector = QComboBox(gui)
6170
+ label = option.text
6171
+ if not label.endswith (':'):
6173
+ self.label = QLabel(label, gui)
6176
+ for nr, choice in enumerate(option.choices):
6177
+ self.selector.addItem(choice['text'])
6178
+ if option.defchoice == choice['choice']:
6179
+ selected = self.selector.count() - 1
6180
+ if selected is not None:
6181
+ self.selector.setCurrentIndex(selected)
6183
+ print option.text, "unknown value:", option.defchoice
6184
+ self.connect(self.selector, SIGNAL("currentIndexChanged(int)"), self.on_change)
6186
+ Option.__init__(self, option, ppd, gui, tab_label=tab_label)
6188
+ def get_current_value(self):
6189
+ return self.option.choices[self.selector.currentIndex()]['choice']
6191
+# ---------------------------------------------------------------------------
6193
+class OptionPickMany(OptionPickOne):
6194
+ widget_name = "OptionPickMany"
6196
+ def __init__(self, option, ppd, gui, tab_label=None):
6197
+ raise NotImplemented
6198
+ Option.__init__(self, option, ppd, gui, tab_label=tab_label)
6199
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
6200
--- orig/kdeadmin-4.2.2/system-config-printer-kde/smb-browse-dialog.ui 1970-01-01 01:00:00.000000000 +0100
6201
+++ kdeadmin-4.2.2/system-config-printer-kde/smb-browse-dialog.ui 2009-04-09 22:56:08.000000000 +0100
6203
+<ui version="4.0" >
6204
+ <class>SMBBrowseDialog</class>
6205
+ <widget class="QDialog" name="SMBBrowseDialog" >
6206
+ <property name="windowModality" >
6207
+ <enum>Qt::NonModal</enum>
6209
+ <property name="geometry" >
6213
+ <width>400</width>
6214
+ <height>300</height>
6217
+ <property name="font" >
6219
+ <weight>50</weight>
6220
+ <bold>false</bold>
6223
+ <property name="focusPolicy" >
6224
+ <enum>Qt::StrongFocus</enum>
6226
+ <property name="windowTitle" >
6227
+ <string>SMB Browser</string>
6229
+ <property name="modal" >
6232
+ <widget class="QWidget" name="layoutWidget" >
6233
+ <property name="geometry" >
6237
+ <width>361</width>
6238
+ <height>41</height>
6241
+ <layout class="QHBoxLayout" name="horizontalLayout" >
6243
+ <widget class="KPushButton" name="btnSMBBrowseRefresh" >
6244
+ <property name="text" >
6245
+ <string>Refresh</string>
6250
+ <spacer name="horizontalSpacer" >
6251
+ <property name="orientation" >
6252
+ <enum>Qt::Horizontal</enum>
6254
+ <property name="sizeHint" stdset="0" >
6257
+ <height>20</height>
6263
+ <widget class="KPushButton" name="btnSMBBrowseOk" >
6264
+ <property name="text" >
6265
+ <string>Ok</string>
6267
+ <property name="shortcut" >
6268
+ <string>Ctrl+O</string>
6273
+ <widget class="KPushButton" name="btnSMBBrowseCancel" >
6274
+ <property name="text" >
6275
+ <string>Cancel</string>
6281
+ <widget class="QTreeWidget" name="twSMBBrowser" >
6282
+ <property name="geometry" >
6286
+ <width>341</width>
6287
+ <height>221</height>
6290
+ <property name="sizePolicy" >
6291
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
6292
+ <horstretch>0</horstretch>
6293
+ <verstretch>0</verstretch>
6296
+ <property name="sortingEnabled" >
6299
+ <property name="allColumnsShowFocus" >
6302
+ <property name="columnCount" >
6303
+ <number>2</number>
6306
+ <property name="text" >
6307
+ <string>1</string>
6311
+ <property name="text" >
6312
+ <string>1</string>
6319
+ <class>KPushButton</class>
6320
+ <extends>QPushButton</extends>
6321
+ <header>kpushbutton.h</header>
6327
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
6328
--- orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.desktop 2009-03-26 14:43:48.000000000 +0000
6329
+++ kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.desktop 2009-04-09 22:56:08.000000000 +0100
6338
-Name[es]=Imprimiendo
6339
-Name[et]=Trükkimine
6340
-Name[fr]=Impression
6348
-Name[lt]=Spausdinimas
6355
-Name[pl]=Drukowanie
6357
Name[pt_BR]=Imprimindo
6365
Comment=Configure printers
6366
-Comment[ca]=Configura les impressores
6367
-Comment[cs]=Nastavení tisku
6368
-Comment[da]=Indstil printere
6369
-Comment[de]=Drucker einrichten
6370
Comment[el]=Ρύθμιση εκτυπωτών
6371
-Comment[es]=Configurar impresoras
6372
-Comment[et]=Printerite seadistamine
6373
-Comment[fr]=Configurer les imprimantes
6374
-Comment[ga]=Cumraigh printéirí
6375
Comment[gl]=Configuración das impresoras
6376
-Comment[hne]=प्रिंटर मन ल कान्फिगर करव
6377
-Comment[hu]=Nyomtatóbeállítás
6378
-Comment[is]=Stilla prentara
6379
-Comment[it]=Configura le stampanti
6380
-Comment[ja]=プリンタの設定
6381
-Comment[lt]=Konfigūruoti spausdintuvus
6382
Comment[lv]=Konfigurēt drukas ierīces
6383
-Comment[nb]=Sett opp skrivere
6384
Comment[nds]=Druckers instellen
6385
Comment[nl]=Printers instellen
6386
-Comment[nn]=Set opp skrivarar
6387
-Comment[pa]=ਪਰਿੰਟਿੰਗ ਸੰਰਚਨਾ
6388
-Comment[pl]=Konfiguracja drukarek
6389
Comment[pt]=Configurar as impressoras
6390
Comment[pt_BR]=Configurar impressoras
6391
-Comment[ro]=Configurează imprimantele
6392
Comment[ru]=Настройка принтеров
6393
Comment[sv]=Anpassa skrivare
6394
Comment[tr]=Yazıcıları yapılandır
6395
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
6396
--- orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.py 2008-12-21 20:20:45.000000000 +0000
6397
+++ kdeadmin-4.2.2/system-config-printer-kde/system-config-printer-kde.py 1970-01-01 01:00:00.000000000 +0100
6399
-#!/usr/bin/env python
6400
-# -*- coding: utf-8 -*-
6402
-#############################################################################
6404
-## Copyright (C) 2007 Canonical Ltd
6405
-## Author: Jonathan Riddell <jriddell@ubuntu.com>
6407
-## Includes code from System Config Printer
6408
-## Copyright (C) 2007 Tim Waugh <twaugh@redhat.com>
6409
-## Copyright (C) 2007 Red Hat, Inc.
6411
-## This program is free software; you can redistribute it and/or
6412
-## modify it under the terms of the GNU General Public License as
6413
-## published by the Free Software Foundation; either version 2 of
6414
-## the License, or (at your option) any later version.
6416
-## This program is distributed in the hope that it will be useful,
6417
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
6418
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6419
-## GNU General Public License for more details.
6421
-## You should have received a copy of the GNU General Public License
6422
-## along with this program. If not, see <http://www.gnu.org/licenses/>.
6424
-#############################################################################
6426
-MIN_REFRESH_INTERVAL = 1 # seconds
6429
-import sys, os, time, traceback, re, tempfile, httplib
6433
-#load modules from system-config-printer-common (debug, smburi), change path here if you have it installed elsewhere
6434
-SYSTEM_CONFIG_PRINTER_DIR = "/usr/share/system-config-printer"
6435
-if os.path.exists(SYSTEM_CONFIG_PRINTER_DIR + "/debug.py"):
6436
- sys.path.append(SYSTEM_CONFIG_PRINTER_DIR)
6438
-from PyQt4.QtCore import *
6439
-from PyQt4.QtGui import *
6440
-from PyQt4 import uic
6442
-from PyKDE4.kdecore import *
6443
-from PyKDE4.kdeui import *
6445
-#use _() to keep code the same as gnome system-config-printer
6447
- return unicode(i18n(string), "utf-8")
6449
-def translate(self, prop):
6450
- """reimplement method from uic to change it to use gettext"""
6451
- if prop.get("notr", None) == "true":
6452
- return self._cstring(prop)
6454
- if prop.text is None:
6456
- text = prop.text.encode("UTF-8")
6459
-uic.properties.Properties._string = translate
6462
-cups.require ("1.9.27")
6464
-# These come from system-config-printer
6466
-import cupshelpers #, options
6467
-from smburi import SMBURI
6468
-from debug import *
6471
-import dbus.mainloop.qt
6472
-import dbus.service
6474
-ellipsis = unichr(0x2026)
6477
- try_CUPS_SERVER_REMOTE_ANY = cups.CUPS_SERVER_REMOTE_ANY
6478
-except AttributeError:
6479
- # cups module was compiled with CUPS < 1.3
6480
- try_CUPS_SERVER_REMOTE_ANY = "_remote_any"
6482
-def validDeviceURI (uri):
6483
- """Returns True is the provided URI is valid."""
6484
- if uri.find (":/") > 0:
6488
-class GUI(QWidget):
6489
- """our main class is the main window"""
6491
- printer_states = { cups.IPP_PRINTER_IDLE: i18nc("Printer state", "Idle"),
6492
- cups.IPP_PRINTER_PROCESSING: i18nc("Printer state", "Processing"),
6493
- cups.IPP_PRINTER_BUSY: i18nc("Printer state", "Busy"),
6494
- cups.IPP_PRINTER_STOPPED: i18nc("Printer state", "Stopped") }
6496
- def __init__(self, start_printer = None, change_ppd = False):
6497
- QWidget.__init__(self)
6500
- self.language = locale.getlocale(locale.LC_MESSAGES)
6501
- self.encoding = locale.getlocale(locale.LC_CTYPE)
6503
- nonfatalException()
6504
- os.environ['LC_ALL'] = 'C'
6505
- locale.setlocale (locale.LC_ALL, "")
6506
- self.language = locale.getlocale(locale.LC_MESSAGES)
6507
- self.encoding = locale.getlocale(locale.LC_CTYPE)
6509
- self.printer = None
6510
- self.conflicts = set() # of options
6511
- self.connect_server = (self.printer and self.printer.getServer()) \
6512
- or cups.getServer()
6513
- self.connect_user = cups.getUser()
6514
- self.password = '' #FIXME not in Gnome version
6515
- self.passwd_retry = False #FIXME not in Gnome version
6516
- self.widget_data_setting = {} #FIXME not in Gnome version
6517
- #FIXMEcups.setPasswordCB(self.cupsPasswdCallback)
6518
- ##self.server_is_publishing = False #FIXME new in Gnome version
6520
- self.changed = set() # of options
6522
- self.servers = set((self.connect_server,))
6525
- self.cups = cups.Connection()
6526
- except RuntimeError:
6527
- #warn the user that cups is not running
6528
- message = i18n("CUPS is not currently running. CUPS is required for complete printing functionality. Please start CUPS then restart this application.")
6529
- answer = QMessageBox.warning(self, i18n("Print Server Not Running"), message, QMessageBox.Ok)
6530
- #still allow the app to start for those that really want that
6531
- if answer == QMessageBox.Ok:
6536
- if os.path.exists("system-config-printer.ui"):
6537
- APPDIR = QDir.currentPath()
6539
- file = KStandardDirs.locate("appdata", "system-config-printer.ui")
6540
- APPDIR = file.left(file.lastIndexOf("/"))
6542
- uic.loadUi(APPDIR + "/" + "system-config-printer.ui", self)
6545
- # New Printer Dialog
6546
- self.newPrinterGUI = np = NewPrinterGUI(self)
6547
- #np.NewPrinterWindow.set_transient_for(self.MainWindow)
6549
- self.setConnected()
6551
- self.connect(self.mainlist, SIGNAL("itemSelectionChanged()"), self.on_tvMainList_cursor_changed)
6552
- self.connect(self.mainlist, SIGNAL("currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)"), self.on_tvMainList_changed)
6553
- self.connect(self.chkServerBrowse, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
6554
- self.connect(self.chkServerShare, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
6555
- self.connect(self.chkServerShareAny, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
6556
- self.connect(self.chkServerRemoteAdmin, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
6557
- self.connect(self.chkServerAllowCancelAll, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
6558
- self.connect(self.chkServerLogDebug, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
6560
- self.connect(self.btnNewClass, SIGNAL("clicked()"), self.on_new_class_activate)
6561
- self.connect(self.btnNewPrinter, SIGNAL("clicked()"), self.on_new_printer_activate)
6563
- self.connect(self.entPDescription, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
6564
- self.connect(self.entPLocation, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
6565
- self.connect(self.entPDevice, SIGNAL("textEdited(const QString&)"), self.on_printer_changed)
6566
- self.connect(self.chkPEnabled, SIGNAL("stateChanged(int)"), self.on_printer_changed)
6567
- self.connect(self.chkPAccepting, SIGNAL("stateChanged(int)"), self.on_printer_changed)
6568
- self.connect(self.chkPShared, SIGNAL("stateChanged(int)"), self.on_printer_changed)
6569
- self.connect(self.cmbPErrorPolicy, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
6570
- self.connect(self.cmbPOperationPolicy, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
6571
- self.connect(self.cmbPStartBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
6572
- self.connect(self.cmbPEndBanner, SIGNAL("currentIndexChanged(int)"), self.on_printer_changed)
6573
- #self.connect(self.rbtnPAllow, SIGNAL("toggled(bool)"), self.on_printer_changed)
6576
- self.populateList(start_printer, change_ppd)
6577
- except cups.HTTPError, (s,):
6579
- self.setConnected()
6580
- self.populateList()
6581
- self.show_HTTP_Error(s)
6583
- self.mainlist.header().hide()
6585
- #hide some bits until implemented
6586
- self.btnNewPrinterNetwork.hide()
6587
- self.newPrinterNetworkLabel.hide()
6588
- self.btnNewPrinterSpecial.hide()
6589
- self.newPrinterSpecialLabel.hide()
6590
- self.btnNewPrinter.setText(i18n("New Printer"))
6591
- self.btnPrinterPropertiesApply.setIcon(KIcon("dialog-ok-apply"))
6592
- self.btnRevert.setIcon(KIcon("document-revert"))
6593
- self.newPrinterLabel.hide()
6594
- #(obsolete) only show settings until ready for the rest
6595
- #self.mainlist.hide()
6596
- self.mainlist.setCurrentItem(self.settingsItem)
6597
- #FIXME hide labels until implemented
6598
- self.lblPOptions.hide()
6599
- self.lblPInstallOptions.hide()
6601
- self.setWindowIcon(KIcon("printer"))
6603
- # now called dests_iconview_item_activated() in the Gnome version
6604
- def on_tvMainList_cursor_changed(self):
6606
- # The unapplied changes for this item have not been saved,
6607
- # and the user just pressed "Cancel".
6608
- #FIXME, should offer dialog prompting to save or cancel here
6610
- items = self.mainlist.selectedItems()
6611
- if len(items) < 1:
6614
- #FIXME only show settings until ready for the rest
6615
- #item = self.settingsItem
6616
- type = str(item.text(1))
6617
- name = str(item.text(0))
6618
- #name, type = self.getSelectedItem()
6619
- #model, self.mainListSelected = self.tvMainList.get_selection().get_selected()
6620
- #Save the values incase it gets deselected
6621
- self.mainListSelectedType = type
6622
- self.mainListSelectedName = name
6623
- item_selected = True
6625
- #self.ntbkMain.set_current_page(0)
6626
- self.ntbkMain.setCurrentIndex(0)
6627
- elif type == "Settings":
6628
- #self.ntbkMain.set_current_page(0)
6629
- self.ntbkMain.setCurrentIndex(1)
6631
- self.fillServerTab()
6633
- # No connection to CUPS. Make sure the Apply/Revert buttons
6634
- # are not sensitive.
6635
- self.setDataButtonState()
6636
- item_selected = False
6637
- elif type in ['Printer', 'Class']:
6639
- self.fillPrinterTab(name)
6640
- self.fillPrinterOptions()
6641
- self.setDataButtonState()
6642
- except RuntimeError:
6643
- # Perhaps cupsGetPPD2 failed for a browsed printer.
6644
- self.ntbkMain.setCurrentIndex(3)
6645
- #self.ntbkMain.set_current_page(2)
6648
- #self.ntbkMain.set_current_page(1)
6649
- self.ntbkMain.setCurrentIndex(2)
6650
- elif type == "None":
6651
- #self.ntbkMain.set_current_page(2)
6652
- self.ntbkMain.setCurrentIndex(3)
6653
- self.setDataButtonState()
6654
- item_selected = False
6656
- """FIXME, copy button
6657
- is_local = item_selected and not self.printers[name].discovered
6658
- for widget in [self.copy, self.btnCopy]:
6659
- widget.set_sensitive(item_selected)
6660
- for widget in [self.delete, self.btnDelete]:
6661
- widget.set_sensitive(is_local)
6664
- def printer_properties_response(self):
6665
- name, type = self.getSelectedItem()
6666
- if type in ("Printer", "Class"):
6667
- return self.save_printer(self.printer)
6668
- elif type == "Settings":
6669
- return self.save_serversettings()
6671
- def on_tvMainList_changed(self, new, old):
6672
- """about to change, offer to save"""
6674
- answer = QMessageBox.question(self, "Save Changes", "Do you want to save changes?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, QMessageBox.Save)
6675
- if answer == QMessageBox.Save:
6676
- self.printer_properties_response()
6677
- elif answer == QMessageBox.Discard:
6678
- self.changed = set() # avoid asking the user
6680
- def busy (self, win = None):
6684
- win.setCursor(Qt.WaitCursor)
6685
- QApplication.processEvents()
6687
- nonfatalException ()
6689
- def ready (self, win = None):
6693
- win.setCursor(Qt.ArrowCursor)
6694
- QApplication.processEvents()
6696
- nonfatalException ()
6698
- def setConnected(self):
6699
- connected = bool(self.cups)
6701
- host = cups.getServer()
6703
- if host[0] == '/':
6704
- host = 'localhost'
6705
- self.setWindowTitle(i18n("Printer configuration - %1", host))
6708
- status_msg = i18n("Connected to %1", host)
6710
- status_msg = i18n("Not connected")
6711
- #FIXME do we want a statusbar?
6712
- #self.statusbarMain.push(self.status_context_id, status_msg)
6714
- for widget in (#FIXMEself.btnNewPrinter, self.btnNewClass,
6715
- #self.new_printer, self.new_class,
6716
- self.chkServerBrowse, self.chkServerShare,
6717
- self.chkServerRemoteAdmin,
6718
- self.chkServerAllowCancelAll,
6719
- self.chkServerLogDebug):
6720
- widget.setEnabled(connected)
6722
- sharing = self.chkServerShare.isChecked ()
6723
- self.chkServerShareAny.setEnabled (sharing)
6726
- del self.server_settings
6730
- def populateList(self, start_printer = None, change_ppd = False):
6731
- #FIXMEold_name, old_type = self.getSelectedItem()
6735
- select_path = None
6740
- self.printers = cupshelpers.getPrinters(self.cups)
6742
- # Get default printer.
6744
- self.default_printer = self.cups.getDefault ()
6745
- except AttributeError: # getDefault appeared in pycups-1.9.31
6746
- # This fetches the list of printers and classes *again*,
6747
- # just to find out the default printer.
6748
- dests = self.cups.getDests ()
6749
- if dests.has_key ((None,None)):
6750
- self.default_printer = dests[(None,None)].name
6752
- self.default_printer = None
6753
- except cups.IPPError, (e, m):
6754
- self.show_IPP_Error(e, m)
6755
- self.printers = {}
6756
- self.default_printer = None
6758
- self.printers = {}
6759
- self.default_printer = None
6761
- local_printers = []
6762
- local_classes = []
6763
- remote_printers = []
6764
- remote_classes = []
6766
- for name, printer in self.printers.iteritems():
6767
- if printer.default:
6768
- self.default_printer = name
6769
- self.servers.add(printer.getServer())
6771
- if printer.remote:
6772
- if printer.is_class: remote_classes.append(name)
6773
- else: remote_printers.append(name)
6775
- if printer.is_class: local_classes.append(name)
6776
- else: local_printers.append(name)
6778
- local_printers.sort()
6779
- local_classes.sort()
6780
- remote_printers.sort()
6781
- remote_classes.sort()
6783
- if (old_name != "" and
6784
- (not old_name in local_printers) and
6785
- (not old_name in local_classes) and
6786
- (not old_name in remote_printers) and
6787
- (not old_name in remote_classes)):
6788
- # The previously selected printer no longer exists.
6791
- if (self.default_printer != None and
6792
- start_printer == None and
6794
- start_printer = self.default_printer
6796
- if not start_printer:
6797
- start_printer = old_name
6800
- "_printers" : True,
6801
- "_classes" : True,
6802
- "_remote_printers" : True,
6803
- "_remote_classes" : True,
6807
- # remove old printers/classes
6808
- iter = self.mainlist.get_iter_first()
6809
- iter = self.mainlist.iter_next(iter) # step over server settings
6811
- entry = self.mainlist.get_value(iter, 1)
6812
- path = self.mainlist.get_path(iter)
6813
- expanded[entry] = self.tvMainList.row_expanded(path)
6814
- more_entries = self.mainlist.remove(iter)
6815
- if not more_entries: break
6817
- self.mainlist.clear()
6818
- QTreeWidgetItem(self.mainlist, ["New Printer", 'New'])
6819
- self.settingsItem = QTreeWidgetItem(self.mainlist, ["Server Settings", 'Settings'])
6822
- for printers, text, name in (
6823
- (local_printers, i18n("Local Printers"), "_printers"),
6824
- (local_classes, i18n("Local Classes"), "_classes"),
6825
- (remote_printers, i18n("Remote Printers"), "_remote_printers"),
6826
- (remote_classes, i18n("Remote Classes"), "_remote_classes")):
6827
- if not printers: continue
6829
- #self.mainlist.addTopLevelItem(QTreeWidgetItem(self.mainlist, text))
6830
- rootTreeItem = QTreeWidgetItem(self.mainlist, [text, name])
6831
- #iter = self.mainlist.append(None, (text, name))
6832
- #path = self.mainlist.get_path(iter)
6834
- for printer_name in printers:
6835
- if start_printer == None:
6836
- start_printer = printer_name
6837
- treeItem = QTreeWidgetItem(rootTreeItem, [printer_name, "Printer"])
6838
- #p_iter = self.mainlist.append(iter, (printer_name, "Printer"))
6839
- if printer_name==start_printer:
6840
- treeItem.setSelected(True)
6841
- expanded[name] = True
6842
- if expanded[name]:
6843
- rootTreeItem.setExpanded(True)
6844
- #self.tvMainList.expand_row(path, False)
6845
- self.on_tvMainList_cursor_changed()
6846
- self.setDataButtonState()
6850
- self.on_btnChangePPD_clicked (self.btnChangePPD)
6854
- # Connect to Server
6856
- def on_printer_changed(self, text):
6857
- widget = self.sender()
6858
- if not widget: #method called as a method not a slot
6860
- if isinstance(widget, QCheckBox):
6861
- value = widget.isChecked()
6862
- elif isinstance(widget, QLineEdit):
6863
- value = unicode(widget.text())
6864
- elif isinstance(widget, QRadioButton):
6865
- value = widget.isChecked()
6866
- elif isinstance(widget, QComboBox):
6867
- value = unicode(widget.currentText())
6869
- raise ValueError, "Widget type not supported (yet)"
6873
- self.entPDescription : p.info,
6874
- self.entPLocation : p.location,
6875
- self.entPDevice : p.device_uri,
6876
- self.chkPEnabled : p.enabled,
6877
- self.chkPAccepting : not p.rejecting,
6878
- self.chkPShared : p.is_shared,
6879
- self.cmbPStartBanner : p.job_sheet_start,
6880
- self.cmbPEndBanner : p.job_sheet_end,
6881
- self.cmbPErrorPolicy : p.error_policy,
6882
- self.cmbPOperationPolicy : p.op_policy,
6883
- #self.rbtnPAllow: p.default_allow, #FIXME access control tab
6886
- old_value = old_values[widget]
6888
- if old_value == value:
6889
- self.changed.discard(widget)
6891
- self.changed.add(widget)
6892
- self.setDataButtonState()
6898
- # Server side options
6900
- # set buttons sensitivity
6901
- def setDataButtonState(self):
6902
- try: # Might not be a printer selected
6903
- possible = (self.ppd and
6904
- not bool (self.changed) and
6905
- self.printer.enabled and
6906
- not self.printer.rejecting)
6908
- self.btnPrintTestPage.setEnabled(possible)
6910
- commands = (self.printer.type & cups.CUPS_PRINTER_COMMANDS) != 0
6911
- self.btnSelfTest.setEnabled(commands and possible)
6912
- self.btnCleanHeads.setEnabled(commands and possible)
6914
- debugprint ("exception in setDataButtonState")
6917
- installablebold = False
6918
- optionsbold = False
6919
- if self.conflicts:
6920
- debugprint ("Conflicts detected")
6921
- self.btnConflict.show()
6922
- for option in self.conflicts:
6923
- if option.tab_label == self.lblPInstallOptions:
6924
- installablebold = True
6926
- optionsbold = True
6928
- self.btnConflict.hide()
6929
- installabletext = i18n("Installable Options")
6930
- optionstext = i18n("Printer Options")
6931
- if installablebold:
6932
- installabletext = i18nc("Conflicted entry", "<b>%1</b>", installabletext)
6934
- optionstext = i18nc("Conflicted entry", "<b>%1</b>", optionstext)
6935
- self.lblPInstallOptions.setText(installabletext)
6936
- self.lblPOptions.setText(optionstext)
6939
- store = self.tvPrinterProperties.get_model ()
6941
- for n in range (self.ntbkPrinter.get_n_pages ()):
6942
- page = self.ntbkPrinter.get_nth_page (n)
6943
- label = self.ntbkPrinter.get_tab_label (page)
6944
- if label == self.lblPInstallOptions:
6945
- iter = store.get_iter ((n,))
6946
- store.set_value (iter, 0, installabletext)
6947
- elif label == self.lblPOptions:
6948
- iter = store.get_iter ((n,))
6949
- store.set_value (iter, 0, optionstext)
6952
- self.btnPrinterPropertiesApply.setEnabled(len (self.changed) > 0)
6953
- self.btnRevert.setEnabled(len (self.changed) > 0)
6955
- def save_printer(self, printer, saveall=False):
6956
- class_deleted = False
6957
- name = printer.name
6960
- if not printer.is_class and self.ppd:
6961
- self.getPrinterSettings()
6962
- if self.ppd.nondefaultsMarked() or saveall:
6963
- self.passwd_retry = False # use cached Passwd
6964
- self.cups.addPrinter(name, ppd=self.ppd)
6967
- if printer.is_class:
6970
- # update member list
6971
- new_members = self.getCurrentClassMembers(self.tvClassMembers)
6972
- if not new_members:
6973
- dialog = gtk.MessageDialog(
6974
- flags=0, type=gtk.MESSAGE_WARNING,
6975
- buttons=gtk.BUTTONS_YES_NO,
6976
- message_format=_("This will delete this class!"))
6977
- dialog.format_secondary_text(_("Proceed anyway?"))
6978
- result = dialog.run()
6980
- if result==gtk.RESPONSE_NO:
6982
- class_deleted = True
6984
- # update member list
6985
- old_members = printer.class_members[:]
6987
- for member in new_members:
6988
- if member in old_members:
6989
- old_members.remove(member)
6991
- self.cups.addPrinterToClass(member, name)
6992
- for member in old_members:
6993
- self.cups.deletePrinterFromClass(member, name)
6996
- location = unicode(self.entPLocation.text())
6997
- info = unicode(self.entPDescription.text())
6998
- device_uri = unicode(self.entPDevice.text())
6999
- if device_uri.find (ellipsis) != -1:
7000
- # The URI is sanitized and not editable.
7001
- device_uri = printer.device_uri
7003
- enabled = self.chkPEnabled.isChecked()
7004
- accepting = self.chkPAccepting.isChecked()
7005
- shared = self.chkPShared.isChecked()
7007
- if info!=printer.info or saveall:
7008
- self.passwd_retry = False # use cached Passwd
7009
- self.cups.setPrinterInfo(name, info)
7010
- if location!=printer.location or saveall:
7011
- self.passwd_retry = False # use cached Passwd
7012
- self.cups.setPrinterLocation(name, location)
7013
- if (not printer.is_class and
7014
- (device_uri!=printer.device_uri or saveall)):
7015
- self.passwd_retry = False # use cached Passwd
7016
- self.cups.setPrinterDevice(name, device_uri)
7018
- if enabled != printer.enabled or saveall:
7019
- self.passwd_retry = False # use cached Passwd
7020
- self.printer.setEnabled(enabled)
7021
- if accepting == printer.rejecting or saveall:
7022
- self.passwd_retry = False # use cached Passwd
7023
- self.printer.setAccepting(accepting)
7024
- if shared != printer.is_shared or saveall:
7025
- self.passwd_retry = False # use cached Passwd
7026
- self.printer.setShared(shared)
7028
- job_sheet_start = unicode(self.cmbPStartBanner.currentText())
7029
- job_sheet_end = unicode(self.cmbPEndBanner.currentText())
7030
- error_policy = unicode(self.cmbPErrorPolicy.currentText())
7031
- op_policy = unicode(self.cmbPOperationPolicy.currentText())
7033
- if (job_sheet_start != printer.job_sheet_start or
7034
- job_sheet_end != printer.job_sheet_end) or saveall:
7035
- self.passwd_retry = False # use cached Passwd
7036
- printer.setJobSheets(job_sheet_start, job_sheet_end)
7037
- if error_policy != printer.error_policy or saveall:
7038
- self.passwd_retry = False # use cached Passwd
7039
- printer.setErrorPolicy(error_policy)
7040
- if op_policy != printer.op_policy or saveall:
7041
- self.passwd_retry = False # use cached Passwd
7042
- printer.setOperationPolicy(op_policy)
7044
- """FIXME TODO access
7045
- default_allow = self.rbtnPAllow.get_active()
7046
- except_users = self.getPUsers()
7048
- if (default_allow != printer.default_allow or
7049
- except_users != printer.except_users) or saveall:
7050
- self.passwd_retry = False # use cached Passwd
7051
- printer.setAccess(default_allow, except_users)
7053
- for option in printer.attributes:
7054
- if option not in self.server_side_options:
7055
- printer.unsetOption(option)
7056
- for option in self.server_side_options.itervalues():
7057
- if option.is_changed() or saveall:
7058
- printer.setOption(option.name, option.get_current_value())
7060
- except cups.IPPError, (e, s):
7061
- self.show_IPP_Error(e, s)
7063
- self.changed = set() # of options
7064
- if not self.__dict__.has_key ("server_settings"):
7065
- # We can authenticate with the server correctly at this point,
7066
- # but we have never fetched the server settings to see whether
7067
- # the server is publishing shared printers. Fetch the settings
7068
- # now so that we can update the "not published" label if necessary.
7070
- self.server_settings = self.cups.adminGetServerSettings()
7072
- nonfatalException()
7075
- self.populateList ()
7077
- # Update our copy of the printer's settings.
7078
- printers = cupshelpers.getPrinters (self.cups)
7079
- this_printer = { name: printers[name] }
7080
- self.printers.update (this_printer)
7084
- def getPrinterSettings(self):
7085
- #self.ppd.markDefaults()
7086
- for option in self.options.itervalues():
7087
- option.writeback()
7089
- @pyqtSignature("")
7090
- def on_btnPrintTestPage_clicked(self):
7091
- if self.test_button_cancels:
7092
- jobs = self.printer.testsQueued ()
7094
- debugprint ("Canceling job %s" % job)
7096
- self.cups.cancelJob (job)
7097
- except cups.IPPError, (e, msg):
7098
- self.show_IPP_Error(e, msg)
7099
- self.setTestButton (self.printer)
7102
- # if we have a page size specific custom test page, use it;
7103
- # otherwise use cups' default one
7104
- custom_testpage = None
7105
- opt = self.ppd.findOption ("PageSize")
7107
- custom_testpage = os.path.join(SYSTEM_CONFIG_PRINTER_DIR, 'testpage-%s.ps' % opt.defchoice.lower())
7109
- if custom_testpage and os.path.exists(custom_testpage):
7110
- debugprint ('Printing custom test page ' + custom_testpage)
7111
- job_id = self.cups.printTestPage(self.printer.name,
7112
- file=custom_testpage)
7114
- debugprint ('Printing default test page')
7115
- job_id = self.cups.printTestPage(self.printer.name)
7117
- self.setTestButton (self.printer)
7118
- QMessageBox.information(self, i18nc("Test page submitted", "Submitted"), i18n("Test page submitted as "
7119
- "job %d") % job_id)
7120
- except cups.IPPError, (e, msg):
7121
- if (e == cups.IPP_NOT_AUTHORIZED and
7122
- self.connect_server != 'localhost' and
7123
- self.connect_server[0] != '/'):
7124
- self.lblError.set_markup ('<span size="larger">'+
7125
- i18n("<b>Not possible</b>") + '</span>\n\n' +
7126
- i18n("The remote server did not accept "
7127
- "the print job, most likely "
7128
- "because the printer is not "
7130
- self.ErrorDialog.set_transient_for (self.MainWindow)
7131
- self.ErrorDialog.run ()
7132
- self.ErrorDialog.hide ()
7134
- self.show_IPP_Error(e, msg)
7136
- def maintenance_command (self, command):
7137
- (tmpfd, tmpfname) = tempfile.mkstemp ()
7138
- os.write (tmpfd, "#CUPS-COMMAND\n%s\n" % command)
7141
- format = "application/vnd.cups-command"
7142
- job_id = self.cups.printTestPage (self.printer.name,
7145
- user=self.connect_user)
7146
- self.lblInfo.set_markup ('<span size="larger">' +
7147
- i18nc("Maintenance command submitted", "<b>Submitted</b>") + '</span>\n\n' +
7148
- i18n("Maintenance command submitted as "
7149
- "job %d") % job_id)
7150
- self.InfoDialog.set_transient_for (self.MainWindow)
7151
- self.InfoDialog.run ()
7152
- self.InfoDialog.hide ()
7153
- except cups.IPPError, (e, msg):
7154
- if (e == cups.IPP_NOT_AUTHORIZED and
7155
- self.printer.name != 'localhost'):
7156
- self.lblError.set_markup ('<span size="larger">'+
7157
- i18n("<b>Not possible</b>") + '</span>\n\n' +
7158
- i18n("The remote server did not accept "
7159
- "the print job, most likely "
7160
- "because the printer is not "
7162
- self.ErrorDialog.set_transient_for (self.MainWindow)
7163
- self.ErrorDialog.run ()
7164
- self.ErrorDialog.hide ()
7166
- self.show_IPP_Error(e, msg)
7168
- @pyqtSignature("")
7169
- def on_btnSelfTest_clicked(self):
7170
- self.maintenance_command ("PrintSelfTestPage")
7172
- @pyqtSignature("")
7173
- def on_btnCleanHeads_clicked(self):
7174
- self.maintenance_command ("Clean all")
7176
- def fillComboBox(self, combobox, values, value):
7178
- for nr, val in enumerate(values):
7179
- combobox.addItem(val)
7181
- combobox.setCurrentIndex(nr)
7183
- def fillPrinterTab(self, name):
7184
- self.changed = set() # of options
7185
- self.options = {} # keyword -> Option object
7186
- self.conflicts = set() # of options
7188
- printer = self.printers[name]
7189
- self.printer = printer
7190
- printer.getAttributes ()
7192
- editable = not self.printer.discovered
7193
- editablePPD = not self.printer.remote
7196
- self.ppd = printer.getPPD()
7197
- except cups.IPPError, (e, m):
7198
- # Some IPP error other than IPP_NOT_FOUND.
7199
- self.show_IPP_Error(e, m)
7200
- # Treat it as a raw queue.
7202
- except RuntimeError:
7203
- # The underlying cupsGetPPD2() function returned NULL without
7204
- # setting an IPP error, so it'll be something like a failed
7206
- #FIXME show a dialogue
7207
- debugprint("Error!")
7209
- self.lblError.set_markup('<span size="larger">' +
7210
- _("<b>Error</b>") + '</span>\n\n' +
7211
- _("There was a problem connecting to "
7212
- "the CUPS server."))
7213
- self.ErrorDialog.set_transient_for(self.MainWindow)
7214
- self.ErrorDialog.run()
7215
- self.ErrorDialog.hide()
7219
- for widget in (self.entPDescription, self.entPLocation,
7221
- widget.setReadOnly(not editable)
7223
- for widget in (self.btnSelectDevice, self.btnChangePPD):
7225
- self.chkPEnabled, self.chkPAccepting, self.chkPShared,
7226
- self.cmbPStartBanner, self.cmbPEndBanner,
7227
- self.cmbPErrorPolicy, self.cmbPOperationPolicy,
7228
- self.rbtnPAllow, self.rbtnPDeny, self.tvPUsers,
7229
- self.entPUser, self.btnPAddUser, self.btnPDelUser):
7231
- widget.setEnabled(editable)
7233
- # Description page
7234
- self.entPDescription.setText(printer.info)
7235
- self.entPLocation.setText(printer.location)
7236
- #obsolete self.lblPMakeModel.setText(printer.make_and_model)
7237
- #obsolete self.lblPState.setText(printer.state_description)
7239
- uri = printer.device_uri
7240
- if uri.startswith("smb://"):
7241
- (group, host, share,
7242
- user, password) = SMBURI (uri=uri[6:]).separate ()
7245
- if len (user) or len (password):
7247
- uri += SMBURI (group=group, host=host, share=share).get_uri ()
7248
- self.entPDevice.setEnabled(False)
7250
- self.entPDevice.setEnabled(True)
7251
- self.entPDevice.setText(uri)
7252
- self.changed.discard(self.entPDevice)
7254
- # Hide make/model and Device URI for classes
7255
- for widget in (self.lblPMakeModel2, self.lblPMakeModel,
7256
- self.btnChangePPD, self.lblPDevice2,
7257
- self.entPDevice, self.btnSelectDevice):
7258
- if printer.is_class:
7265
- self.btnPMakeDefault.setEnabled(not printer.default)
7266
- if printer.default:
7267
- self.lblPDefault.setText(i18n("This is the default printer"))
7268
- elif self.default_printer:
7269
- self.lblPDefault.setText(self.default_printer)
7271
- self.lblPDefault.setText(i18n("No default printer set."))
7273
- self.setTestButton (printer)
7279
- self.chkPEnabled.setChecked(printer.enabled)
7280
- self.chkPAccepting.setChecked(not printer.rejecting)
7281
- self.chkPShared.setChecked(printer.is_shared)
7283
- if printer.is_shared:
7284
- flag = cups.CUPS_SERVER_SHARE_PRINTERS
7285
- publishing = int (self.server_settings[flag])
7287
- self.lblNotPublished.hide()
7289
- self.lblNotPublished.show()
7291
- self.lblNotPublished.hide()
7293
- self.lblNotPublished.hide()
7296
- self.cmbPStartBanner.setEnabled(editable)
7297
- self.cmbPEndBanner.setEnabled(editable)
7300
- self.cmbPErrorPolicy.setEnabled(editable)
7301
- self.cmbPOperationPolicy.setEnabled(editable)
7305
- self.rbtnPAllow.set_active(printer.default_allow)
7306
- self.rbtnPDeny.set_active(not printer.default_allow)
7307
- self.setPUsers(printer.except_users)
7309
- self.entPUser.set_text("")
7311
- # Server side options (Job options)
7312
- self.server_side_options = {}
7313
- for option in self.job_options_widgets.values ():
7314
- if option.name == "media" and self.ppd:
7315
- # Slightly special case because the 'system default'
7316
- # (i.e. what you get when you press Reset) depends
7317
- # on the printer's PageSize.
7318
- opt = self.ppd.findOption ("PageSize")
7320
- option.set_default (opt.defchoice)
7322
- option_editable = editable
7324
- value = self.printer.attributes[option.name]
7326
- option.reinit (None)
7329
- if self.printer.possible_attributes.has_key (option.name):
7330
- supported = self.printer.\
7331
- possible_attributes[option.name][1]
7332
- # Set the option widget.
7333
- # In CUPS 1.3.x the orientation-requested-default
7334
- # attribute may have the value None; this means there
7335
- # is no value set. This suits our needs here, as None
7336
- # resets the option to the system default and makes the
7337
- # Reset button insensitive.
7338
- option.reinit (value, supported=supported)
7340
- option.reinit (value)
7342
- self.server_side_options[option.name] = option
7344
- option_editable = False
7345
- self.lblError.set_markup ('<span ' +
7346
- 'size="larger">' +
7347
- _("<b>Error</b>") + '</span>\n\n' +
7348
- _("Option '%s' has value '%s' "
7349
- "and cannot be edited.") %
7350
- (option.name, value))
7351
- self.ErrorDialog.set_transient_for (self.MainWindow)
7352
- self.ErrorDialog.run()
7353
- self.ErrorDialog.hide()
7354
- option.widget.set_sensitive (option_editable)
7356
- option.button.set_sensitive (False)
7357
- self.other_job_options = []
7358
- self.draw_other_job_options (editable=editable)
7359
- for option in self.printer.attributes.keys ():
7360
- if self.server_side_options.has_key (option):
7363
- if self.printer.possible_attributes.has_key (option):
7364
- supported = self.printer.possible_attributes[option][1]
7365
- self.add_job_option (option, value=self.printer.attributes[option],
7366
- supported=supported, is_new=False,
7367
- editable=editable)
7368
- self.entNewJobOption.set_text ('')
7369
- self.entNewJobOption.set_sensitive (editable)
7370
- self.btnNewJobOption.set_sensitive (False)
7372
- if printer.is_class:
7373
- # remove InstallOptions tab
7374
- tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions)
7376
- self.ntbkPrinter.remove_page(tab_nr)
7377
- self.fillClassMembers(name, editable)
7380
- self.fillPrinterOptions(name, editablePPD)
7383
- self.changed = set() # of options
7384
- self.updatePrinterProperties ()
7385
- self.setDataButtonState()
7387
- def fillPrinterOptions(self):
7388
- return #FIXME TODO options tabs
7390
- #In Gnome is now on_delete_activate(self, UNUSED):
7391
- @pyqtSignature("")
7392
- def on_btnDelete_clicked(self):
7393
- name, type = self.getSelectedItem()
7397
- if type == "Printer":
7398
- message_format = i18n("Really delete printer %s?")
7400
- message_format = i18n("Really delete class %s?")
7402
- cancel = QMessageBox.question(self,"",
7403
- unicode(message_format) % name,
7404
- i18n("&Yes"), i18n("&No"),
7410
- self.cups.deletePrinter(name)
7411
- except cups.IPPError, (e, msg):
7412
- self.show_IPP_Error(e, msg)
7414
- self.changed = set()
7415
- self.populateList()
7416
- self.mainlist.setCurrentItem(self.mainlist.itemAt(0,0))
7418
- #in Gnome side is now set_default_printer (self, name):
7419
- @pyqtSignature("")
7420
- def on_btnPMakeDefault_clicked(self):
7422
- self.cups.setDefault(self.printer.name)
7423
- except cups.IPPError, (e, msg):
7424
- self.show_IPP_Error(e, msg)
7427
- # Also need to check system-wide lpoptions because that's how
7428
- # previous Fedora versions set the default (bug #217395).
7429
- (tmpfd, tmpfname) = tempfile.mkstemp ()
7432
- resource = "/admin/conf/lpoptions"
7433
- self.cups.getFile(resource, tmpfname)
7435
- except cups.HTTPError, (s,):
7437
- os.remove (tmpfname)
7441
- if s != cups.HTTP_NOT_FOUND:
7442
- self.show_HTTP_Error(s)
7446
- lines = file (tmpfname).readlines ()
7449
- for line in lines:
7450
- if line.startswith ("Default "):
7451
- # This is the system-wide default.
7452
- name = line.split (' ')[1]
7453
- if name != self.printer.name:
7454
- # Stop it from over-riding the server default.
7455
- lines[i] = "Dest " + line[8:]
7460
- file (tmpfname, 'w').writelines (lines)
7462
- self.cups.putFile (resource, tmpfname)
7463
- except cups.HTTPError, (s,):
7464
- os.remove (tmpfname)
7466
- self.show_HTTP_Error(s)
7469
- # Now reconnect because the server needs to reload.
7473
- os.remove (tmpfname)
7478
- self.populateList()
7479
- except cups.HTTPError, (s,):
7481
- self.setConnected()
7482
- self.populateList()
7483
- self.show_HTTP_Error(s)
7485
- ##########################################################################
7486
- ### Server settings
7487
- ##########################################################################
7489
- def fillServerTab(self):
7490
- self.changed = set()
7492
- self.server_settings = self.cups.adminGetServerSettings()
7493
- except cups.IPPError, (e, m):
7495
- self.show_IPP_Error(e, m)
7496
- self.tvMainList.get_selection().unselect_all()
7497
- self.on_tvMainList_cursor_changed(self.tvMainList)
7500
- for widget, setting in [
7501
- (self.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS),
7502
- (self.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS),
7503
- (self.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY),
7504
- (self.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN),
7505
- (self.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY),
7506
- (self.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]:
7507
- # widget.set_data("setting", setting)
7508
- self.widget_data_setting[widget] = setting
7509
- self.disconnect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
7510
- if self.server_settings.has_key(setting):
7511
- widget.setChecked(int(self.server_settings[setting]))
7512
- widget.setEnabled(True)
7514
- widget.setChecked(False)
7515
- widget.setEnabled(False)
7516
- self.connect(widget, SIGNAL("stateChanged(int)"), self.on_server_widget_changed)
7517
- self.setDataButtonState()
7518
- # Set sensitivity of 'Allow printing from the Internet'.
7519
- self.on_server_changed (self.chkServerShare) # (any will do here)
7521
- def on_server_widget_changed(self, value):
7522
- self.on_server_changed(self.sender())
7524
- def on_server_changed(self, widget):
7525
- #setting = widget.get_data("setting")
7526
- #print "widget_data_setting " + str(self.widget_data_setting)
7527
- #print "widget " + str(widget)
7528
- setting = self.widget_data_setting[widget]
7529
- if self.server_settings.has_key (setting):
7530
- if str(int(widget.isChecked())) == self.server_settings[setting]:
7531
- self.changed.discard(widget)
7533
- self.changed.add(widget)
7535
- sharing = self.chkServerShare.isChecked ()
7536
- self.chkServerShareAny.setEnabled (
7537
- sharing and self.server_settings.has_key(try_CUPS_SERVER_REMOTE_ANY))
7539
- self.setDataButtonState()
7541
- def save_serversettings(self):
7542
- setting_dict = self.server_settings.copy()
7543
- for widget, setting in [
7544
- (self.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS),
7545
- (self.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS),
7546
- (self.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY),
7547
- (self.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN),
7548
- (self.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY),
7549
- (self.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]:
7550
- if not self.server_settings.has_key(setting): continue
7551
- setting_dict[setting] = str(int(widget.isChecked()))
7553
- self.cups.adminSetServerSettings(setting_dict)
7554
- except cups.IPPError, (e, m):
7555
- self.show_IPP_Error(e, m)
7557
- except RuntimeError, s:
7558
- self.show_IPP_Error(None, s)
7560
- self.changed = set()
7561
- self.setDataButtonState()
7562
- time.sleep(1) # give the server a chance to process our request
7564
- # Now reconnect, in case the server needed to reload.
7567
- # Refresh the server settings in case they have changed in the
7570
- self.fillServerTab()
7572
- nonfatalException()
7574
- # ====================================================================
7575
- # == New Printer Dialog ==============================================
7576
- # ====================================================================
7579
- def on_new_printer_activate(self):
7581
- self.newPrinterGUI.init("printer")
7585
- def on_new_class_activate(self):
7586
- self.newPrinterGUI.init("class")
7588
- @pyqtSignature("")
7589
- def on_btnSelectDevice_clicked(self):
7590
- self.newPrinterGUI.init("device")
7592
- @pyqtSignature("")
7593
- def on_btnChangePPD_clicked(self):
7595
- self.newPrinterGUI.init("ppd")
7598
- def checkNPName(self, name):
7599
- if not name: return False
7600
- name = name.lower()
7601
- for printer in self.printers.values():
7602
- if not printer.discovered and printer.name.lower()==name:
7606
- def makeNameUnique(self, name):
7607
- """Make a suggested queue name valid and unique."""
7608
- name = name.replace (" ", "_")
7609
- name = name.replace ("/", "_")
7610
- name = name.replace ("#", "_")
7611
- if not self.checkNPName (name):
7613
- while not self.checkNPName (name + str (suffix)):
7617
- name += str (suffix)
7621
- ## Watcher interface helpers
7623
- @pyqtSignature("")
7624
- def on_btnRevert_clicked(self):
7625
- self.changed = set() # avoid asking the user
7626
- self.on_tvMainList_cursor_changed()
7628
- @pyqtSignature("")
7629
- def on_btnPrinterPropertiesApply_clicked(self):
7630
- err = self.printer_properties_response()
7632
- self.populateList()
7634
- nonfatalException()
7636
- def show_IPP_Error(self, exception, message):
7637
- if exception == cups.IPP_NOT_AUTHORIZED:
7638
- QMessageBox.critical(self, i18n('Not authorized'), i18n('The password may be incorrect.'))
7640
- QMessageBox.critical(self, i18n('CUPS server error'), i18n("There was an error during the CUPS "\
7641
- "operation: '%1'.", message))
7642
- def show_HTTP_Error(self, status):
7643
- if (status == cups.HTTP_UNAUTHORIZED or
7644
- status == cups.HTTP_FORBIDDEN):
7645
- QMessageBox.critical(self, i18n('Not authorized'),
7646
- i18n('The password may be incorrect, or the '
7647
- 'server may be configured to deny '
7648
- 'remote administration.'))
7650
- if status == cups.HTTP_BAD_REQUEST:
7651
- msg = i18nc("HTTP error", "Bad request")
7652
- elif status == cups.HTTP_NOT_FOUND:
7653
- msg = i18nc("HTTP error", "Not found")
7654
- elif status == cups.HTTP_REQUEST_TIMEOUT:
7655
- msg = i18nc("HTTP error", "Request timeout")
7656
- elif status == cups.HTTP_UPGRADE_REQUIRED:
7657
- msg = i18nc("HTTP error", "Upgrade required")
7658
- elif status == cups.HTTP_SERVER_ERROR:
7659
- msg = i18nc("HTTP error", "Server error")
7660
- elif status == -1:
7661
- msg = i18nc("HTTP error", "Not connected")
7663
- msg = i18nc("HTTP error", "status %1", status)
7665
- QMessageBox.critical(self, i18n('CUPS server error'), i18n("There was an HTTP error: %1.", msg))
7667
- def getSelectedItem(self):
7668
- return str(self.mainListSelectedName).decode ('utf-8'), str(self.mainListSelectedType)
7670
- items = self.mainlist.selectedItems()
7671
- if len(items) < 1:
7672
- return ("", 'None')
7674
- name = item.text(0)
7675
- type = item.text(1)
7676
- name = str(name).decode ('utf-8')
7677
- return name.strip(), type
7680
- def reconnect (self):
7681
- """Reconnect to CUPS after the server has reloaded."""
7682
- # libcups would handle the reconnection if we just told it to
7683
- # do something, for example fetching a list of classes.
7684
- # However, our local authentication certificate would be
7685
- # invalidated by a server restart, so it is better for us to
7686
- # handle the reconnection ourselves.
7690
- self.setConnected()
7692
- cups.setServer(self.connect_server)
7693
- cups.setUser(self.connect_user)
7695
- while attempt <= 5:
7697
- self.cups = cups.Connection ()
7699
- except RuntimeError:
7700
- # Connection failed.
7704
- self.setConnected()
7705
- self.passwd_retry = False
7707
- def updatePrinterProperties(self):
7708
- debugprint ("update printer properties")
7709
- printer = self.printer
7710
- self.lblPMakeModel.setText(printer.make_and_model)
7711
- state = self.printer_states.get (printer.state, i18nc("Printer state", "Unknown"))
7712
- reason = printer.other_attributes.get ('printer-state-message', '')
7713
- if len (reason) > 0:
7714
- state += ' - ' + reason
7715
- self.lblPState.setText(state)
7716
- if len (self.changed) == 0:
7717
- debugprint ("no changes yet: full printer properties update")
7719
- self.chkPEnabled.setEnabled(printer.enabled)
7720
- self.chkPAccepting.setEnabled(not printer.rejecting)
7721
- self.chkPShared.setEnabled(printer.is_shared)
7724
- self.fillComboBox(self.cmbPStartBanner,
7725
- printer.job_sheets_supported,
7726
- printer.job_sheet_start),
7727
- self.fillComboBox(self.cmbPEndBanner, printer.job_sheets_supported,
7728
- printer.job_sheet_end)
7731
- self.fillComboBox(self.cmbPErrorPolicy,
7732
- printer.error_policy_supported,
7733
- printer.error_policy)
7734
- self.fillComboBox(self.cmbPOperationPolicy,
7735
- printer.op_policy_supported,
7736
- printer.op_policy)
7740
- self.rbtnPAllow.set_active(printer.default_allow)
7741
- self.rbtnPDeny.set_active(not printer.default_allow)
7742
- self.setPUsers(printer.except_users)
7745
- def setTestButton (self, printer):
7746
- if printer.testsQueued ():
7747
- self.test_button_cancels = True
7748
- self.btnPrintTestPage.setText(i18n('Cancel Tests'))
7749
- self.btnPrintTestPage.setEnabled(True)
7751
- self.test_button_cancels = False
7752
- self.btnPrintTestPage.setText(i18n('Print Test Page'))
7753
- self.setDataButtonState()
7755
- def getCurrentClassMembers(self, listwidget):
7756
- count = listwidget.count()
7758
- for i in range(count):
7759
- result.append(listwidget.item(i).text())
7763
- def moveClassMembers(self, treeview_from, treeview_to):
7764
- rows = treeview_from.selectedItems()
7766
- treeview_from.takeItem(treeview_from.row(row))
7767
- treeview_to.addItem(row)
7769
- # Password handling
7772
- def cupsPasswdCallback(self, querystring):
7774
- if self.passwd_retry or len(self.password) == 0:
7775
- waiting = self.WaitWindow.get_property('visible')
7777
- self.WaitWindow.hide ()
7778
- self.lblPasswordPrompt.set_label (self.prompt_primary +
7780
- self.PasswordDialog.set_transient_for (self.MainWindow)
7781
- self.entPasswd.grab_focus ()
7783
- result = self.PasswordDialog.run()
7784
- self.PasswordDialog.hide()
7786
- self.WaitWindow.show ()
7787
- while gtk.events_pending ():
7788
- gtk.main_iteration ()
7789
- if result == gtk.RESPONSE_OK:
7790
- self.password = self.entPasswd.get_text()
7792
- self.password = ''
7793
- self.passwd_retry = False
7795
- self.passwd_retry = True
7796
- return self.password
7798
-class NewPrinterGUI(QDialog):
7800
- new_printer_device_tabs = {
7801
- "parallel" : 0, # empty tab
7816
- ntbkNewPrinterPages = {
7821
- "class-members" : 4,
7822
- "downloadable" : -1,
7825
- def __init__(self, mainapp):
7826
- QDialog.__init__(self, mainapp)
7827
- self.mainapp = mainapp
7828
- self.language = mainapp.language
7829
- self.dialog_mode = ""
7831
- self.WaitWindow = QMessageBox(self.mainapp)
7832
- self.WaitWindow.setStandardButtons(QMessageBox.NoButton)
7834
- if os.path.exists("system-config-printer.ui"):
7835
- APPDIR = QDir.currentPath()
7837
- file = KStandardDirs.locate("appdata", "system-config-printer.ui")
7838
- APPDIR = file.left(file.lastIndexOf("/"))
7840
- uic.loadUi(APPDIR + "/" + "new-printer.ui", self)
7842
- self.connect(self.tvNPDevices, SIGNAL("itemSelectionChanged()"), self.on_tvNPDevices_cursor_changed)
7843
- self.connect(self.tvNPMakes, SIGNAL("itemSelectionChanged()"), self.on_tvNPMakes_cursor_changed)
7844
- self.connect(self.tvNPModels, SIGNAL("itemSelectionChanged()"), self.on_tvNPModels_cursor_changed)
7845
- self.connect(self.entNPTDevice, SIGNAL("textEdited(const QString&)"), self.on_entNPTDevice_changed)
7846
-# self.connect(self.entNPTIPPHostname, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPHostname_changed)
7847
-# self.connect(self.entNPTIPPQueuename, SIGNAL("textEdited(const QString&)"), self.on_entNPTIPPQueuename_changed)
7848
- self.connect(self.entSMBURI, SIGNAL("textEdited(const QString&)"), self.on_entSMBURI_changed)
7849
- self.rbtnSMBAuthPrompt.setChecked(True)
7850
- self.on_rbtnSMBAuthSet_toggled(False)
7851
- self.connect(self.rbtnSMBAuthSet, SIGNAL("toggled(bool)"), self.on_rbtnSMBAuthSet_toggled)
7852
- self.rbtnNPFoomatic.setChecked(True)
7853
- self.connect(self.rbtnNPFoomatic, SIGNAL("toggled(bool)"), self.on_rbtnNPFoomatic_toggled)
7854
- self.connect(self.filechooserPPDButton, SIGNAL("clicked()"),self.on_filechooserPPDButton)
7855
- self.options = {} # keyword -> Option object
7856
- self.changed = set()
7857
- self.conflicts = set()
7860
- # Synchronisation objects.
7861
- self.ppds_lock = thread.allocate_lock()
7862
- self.devices_lock = thread.allocate_lock()
7863
- self.smb_lock = thread.allocate_lock()
7864
- self.ipp_lock = thread.allocate_lock()
7865
- self.drivers_lock = thread.allocate_lock()
7867
- #self.connect(self.btnNCAddMember, SIGNAL("clicked()"), self.slot_btnNCAddMember_clicked)
7868
- #self.connect(self.btnNCDelMember, SIGNAL("clicked()"), self.slot_btnNCDelMember_clicked)
7871
- # share with mainapp
7872
- self.WaitWindow = mainapp.WaitWindow
7873
- self.lblWait = mainapp.lblWait
7874
- self.busy = mainapp.busy
7875
- self.ready = mainapp.ready
7876
- self.show_IPP_Error = mainapp.show_IPP_Error
7877
- self.show_HTTP_Error = mainapp.show_HTTP_Error
7880
- # Optionally disable downloadable driver support.
7881
- if not config.DOWNLOADABLE_DRIVER_SUPPORT:
7882
- self.rbtnNPDownloadableDriverSearch.setEnabled(False)
7883
- self.downloadableDriverSearchFrame.hide()
7886
- # Set up OpenPrinting widgets.
7887
- self.openprinting = openprinting.OpenPrinting ()
7888
- self.openprinting_query_handle = None
7889
- combobox = self.cmbNPDownloadableDriverFoundPrinters
7890
- cell = gtk.CellRendererText()
7891
- combobox.pack_start (cell, True)
7892
- combobox.add_attribute(cell, 'text', 0)
7895
- self.smb_store = gtk.TreeStore (str, # host or share
7897
- gobject.TYPE_PYOBJECT, # domain dict
7898
- gobject.TYPE_PYOBJECT) # host dict
7899
- self.tvSMBBrowser.set_model (self.smb_store)
7900
- self.smb_store.set_sort_column_id (0, gtk.SORT_ASCENDING)
7902
- # SMB list columns
7903
- col = gtk.TreeViewColumn (_("Share"), gtk.CellRendererText (),
7905
- col.set_resizable (True)
7906
- col.set_sort_column_id (0)
7907
- self.tvSMBBrowser.append_column (col)
7909
- col = gtk.TreeViewColumn (_("Comment"), gtk.CellRendererText (),
7911
- self.tvSMBBrowser.append_column (col)
7912
- slct = self.tvSMBBrowser.get_selection ()
7913
- slct.set_select_function (self.smb_select_function)
7915
- self.SMBBrowseDialog.set_transient_for(self.NewPrinterWindow)
7918
- self.ipp_store = gtk.TreeStore (str, # queue
7920
- gobject.TYPE_PYOBJECT) # dict
7921
- self.tvIPPBrowser.set_model (self.ipp_store)
7922
- self.ipp_store.set_sort_column_id (0, gtk.SORT_ASCENDING)
7924
- # IPP list columns
7925
- col = gtk.TreeViewColumn (_("Queue"), gtk.CellRendererText (),
7927
- col.set_resizable (True)
7928
- col.set_sort_column_id (0)
7929
- self.tvIPPBrowser.append_column (col)
7931
- col = gtk.TreeViewColumn (_("Location"), gtk.CellRendererText (),
7933
- self.tvIPPBrowser.append_column (col)
7934
- self.IPPBrowseDialog.set_transient_for(self.NewPrinterWindow)
7936
- self.tvNPDriversTooltips = TreeViewTooltips(self.tvNPDrivers, self.NPDriversTooltips)
7938
- ppd_filter = gtk.FileFilter()
7939
- ppd_filter.set_name(_("PostScript Printer Description files (*.ppd, *.PPD, *.ppd.gz, *.PPD.gz, *.PPD.GZ)"))
7940
- ppd_filter.add_pattern("*.ppd")
7941
- ppd_filter.add_pattern("*.PPD")
7942
- ppd_filter.add_pattern("*.ppd.gz")
7943
- ppd_filter.add_pattern("*.PPD.gz")
7944
- ppd_filter.add_pattern("*.PPD.GZ")
7945
- self.filechooserPPD.add_filter(ppd_filter)
7947
- ppd_filter = gtk.FileFilter()
7948
- ppd_filter.set_name(_("All files (*)"))
7949
- ppd_filter.add_pattern("*")
7950
- self.filechooserPPD.add_filter(ppd_filter)
7952
- self.xml.signal_autoconnect(self)
7955
- #FIXME hide bits which are not yet implemented
7956
- self.btnSMBBrowse.hide()
7957
- self.btnSMBVerify.hide()
7958
- self.btnIPPFindQueue.hide()
7959
- self.btnIPPVerify.hide()
7960
- self.btnNPTLpdProbe.hide()
7962
- def option_changed(self, option):
7963
- if option.is_changed():
7964
- self.changed.add(option)
7966
- self.changed.discard(option)
7968
- if option.conflicts:
7969
- self.conflicts.add(option)
7971
- self.conflicts.discard(option)
7972
- self.setDataButtonState()
7976
- def setDataButtonState(self):
7977
- self.btnNPForward.setEnabled(not bool(self.conflicts))
7979
- def init(self, dialog_mode):
7980
- self.dialog_mode = dialog_mode
7981
- self.options = {} # keyword -> Option object
7982
- self.changed = set()
7983
- self.conflicts = set()
7986
- combobox = self.cmbNPDownloadableDriverFoundPrinters
7987
- combobox.set_model (gtk.ListStore (str, str))
7988
- self.entNPDownloadableDriverSearch.set_text ('')
7989
- button = self.btnNPDownloadableDriverSearch
7990
- label = button.get_children ()[0].get_children ()[0].get_children ()[1]
7991
- self.btnNPDownloadableDriverSearch_label = label
7992
- label.set_text (_("Search"))
7995
- if self.dialog_mode == "printer":
7996
- self.setWindowTitle(i18n("New Printer"))
7997
- # Start on devices page (1, not 0)
7998
- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"])
7999
- self.fillDeviceTab()
8000
- self.on_rbtnNPFoomatic_toggled()
8001
- # Start fetching information from CUPS in the background
8002
- self.new_printer_PPDs_loaded = False
8005
- elif self.dialog_mode == "class":
8006
- self.setWindowTitle(i18n("New Class"))
8007
- self.fillNewClassMembers()
8008
- # Start on name page
8009
- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["name"])
8010
- elif self.dialog_mode == "device":
8011
- self.setWindowTitle(i18n("Change Device URI"))
8012
- self.ntbkNewPrinter.setCurrentIndex(self.ntbkNewPrinterPages["device"])
8013
- self.queryDevices ()
8015
- self.fillDeviceTab(self.mainapp.printer.device_uri)
8016
- # Start fetching information from CUPS in the background
8017
- self.new_printer_PPDs_loaded = False
8019
- elif self.dialog_mode == "ppd":
8020
- self.setWindowTitle(i18n("Change Driver"))
8021
- self.ntbkNewPrinter.setCurrentIndex(2)
8022
- self.on_rbtnNPFoomatic_toggled()
8024
- self.auto_model = ""
8025
- ppd = self.mainapp.ppd
8027
- attr = ppd.findAttr("Manufacturer")
8029
- self.auto_make = attr.value
8031
- self.auto_make = ""
8032
- attr = ppd.findAttr("ModelName")
8033
- if not attr: attr = ppd.findAttr("ShortNickName")
8034
- if not attr: attr = ppd.findAttr("NickName")
8036
- if attr.value.startswith(self.auto_make):
8037
- self.auto_model = attr.value[len(self.auto_make):].strip ()
8040
- self.auto_model = attr.value.split(" ", 1)[1]
8041
- except IndexError:
8042
- self.auto_model = ""
8044
- self.auto_model = ""
8046
- # Special CUPS names for a raw queue.
8047
- self.auto_make = 'Raw'
8048
- self.auto_model = 'Queue'
8051
- self.fillMakeList()
8053
- if self.dialog_mode in ("printer", "class"):
8054
- self.entNPName.setText (self.mainapp.makeNameUnique(self.dialog_mode))
8055
- #FIXMEself.entNPName.grab_focus()
8056
- for widget in [self.entNPLocation,
8057
- self.entNPDescription]: #,
8058
- #self.entSMBURI, self.entSMBUsername,
8059
- #self.entSMBPassword, self.entNPTDirectJetHostname]:
8060
- widget.setText('')
8063
- p = os.popen ('/bin/hostname', 'r')
8064
- hostname = p.read ().strip ()
8066
- self.entNPLocation.setText(hostname)
8068
- nonfatalException ()
8070
- self.entNPTDirectJetPort.setText('9100')
8071
- self.setNPButtons()
8076
- def queryPPDs(self):
8077
- debugprint ("queryPPDs")
8078
- if not self.ppds_lock.acquire(0):
8079
- debugprint ("queryPPDs: in progress")
8081
- debugprint ("Lock acquired for PPDs thread")
8082
- # Start new thread
8083
- thread.start_new_thread (self.getPPDs_thread, (self.language[0],))
8084
- debugprint ("PPDs thread started")
8086
- def getPPDs_thread(self, language):
8088
- debugprint ("Connecting (PPDs)")
8089
- cups.setServer (self.mainapp.connect_server)
8090
- cups.setUser (self.mainapp.connect_user)
8091
- cups.setPasswordCB (self.mainapp.cupsPasswdCallback)
8092
- # cups.setEncryption (...)
8093
- c = cups.Connection ()
8094
- debugprint ("Fetching PPDs")
8095
- ppds_dict = c.getPPDs()
8096
- self.ppds_result = cupshelpers.ppds.PPDs(ppds_dict,
8097
- language=language)
8098
- debugprint ("Closing connection (PPDs)")
8100
- except cups.IPPError, (e, msg):
8101
- self.ppds_result = cups.IPPError (e, msg)
8103
- nonfatalException()
8104
- self.ppds_result = { }
8106
- debugprint ("Releasing PPDs lock")
8107
- self.ppds_lock.release ()
8109
- def fetchPPDs(self, parent=None):
8110
- debugprint ("fetchPPDs")
8114
- # Keep the UI refreshed while we wait for the devices to load.
8116
- while (self.ppds_lock.locked()):
8119
- self.WaitWindow.setText(i18n('<b>Searching</b>') + '<br /><br />' +
8120
- i18n('Searching for drivers'))
8121
- self.WaitWindow.show ()
8123
- QApplication.processEvents()
8128
- self.WaitWindow.hide ()
8130
- debugprint ("Got PPDs")
8131
- result = self.ppds_result # atomic operation
8132
- if isinstance (result, cups.IPPError):
8133
- # Propagate exception.
8137
- def loadPPDs(self, parent=None):
8141
- self.ppds = self.fetchPPDs (parent=parent)
8144
- def dropPPDs(self):
8152
- def fillNewClassMembers(self):
8153
- self.tvNCMembers.clear()
8154
- self.tvNCNotMembers.clear()
8155
- for printer in self.mainapp.printers.itervalues():
8156
- self.tvNCNotMembers.addItem(printer.name)
8158
- @pyqtSignature("")
8159
- def on_btnNCAddMember_clicked(self):
8160
- self.mainapp.moveClassMembers(self.tvNCNotMembers, self.tvNCMembers)
8161
- self.btnNPApply.setEnabled(
8162
- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
8164
- @pyqtSignature("")
8165
- def on_btnNCDelMember_clicked(self):
8166
- self.mainapp.moveClassMembers(self.tvNCMembers, self.tvNCNotMembers)
8167
- self.btnNPApply.setEnabled(
8168
- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
8170
- @pyqtSignature("")
8171
- def on_btnNPBack_clicked(self):
8172
- self.nextNPTab(-1)
8174
- @pyqtSignature("")
8175
- def on_btnNPForward_clicked(self):
8178
- def nextNPTab(self, step=1):
8179
- page_nr = self.ntbkNewPrinter.currentIndex()
8181
- if self.dialog_mode == "class":
8182
- #order = [0, 4, 5]
8183
- order = [self.ntbkNewPrinterPages["name"], self.ntbkNewPrinterPages["class-members"]]
8184
- elif self.dialog_mode == "printer":
8186
- if page_nr == 1: # Device (first page)
8187
- # Choose an appropriate name.
8190
- if self.device.id:
8191
- name = self.device.id_dict["MDL"]
8192
- name = self.mainapp.makeNameUnique (name)
8193
- self.entNPName.setText(name)
8195
- nonfatalException ()
8196
- self.auto_make, self.auto_model = None, None
8197
- self.device.uri = self.getDeviceURI()
8198
- if self.device.type in ("socket", "lpd", "ipp", "bluetooth"):
8199
- host = self.getNetworkPrinterMakeModel(self.device)
8202
- faxuri = self.get_hplip_uri_for_network_printer(host,
8206
- dialog = gtk.Dialog(self.device.info,
8207
- self.NewPrinterWindow,
8208
- gtk.DIALOG_MODAL |
8209
- gtk.DIALOG_DESTROY_WITH_PARENT,
8210
- (i18n("Printer"), 1,
8212
- label = gtk.Label(i18n("This printer supports both "
8213
- "printing and sending faxes. "
8214
- "Which functionality should be "
8215
- "used for this queue?"))
8216
- dialog.vbox.pack_start(label, True, True, 0)
8218
- queue_type = dialog.run()
8220
- if (queue_type == 2):
8221
- self.device.id_dict = \
8222
- self.get_hpfax_device_id(faxuri)
8223
- self.device.uri = faxuri
8224
- self.auto_make = self.device.id_dict["MFG"]
8225
- self.auto_model = self.device.id_dict["MDL"]
8226
- self.device.id = "MFG:" + self.auto_make + \
8227
- ";MDL:" + self.auto_model + \
8229
- self.device.id_dict["DES"] + ";"
8230
- uri = self.device.uri
8231
- if uri and uri.startswith ("smb://"):
8232
- uri = SMBURI (uri=uri[6:]).sanitize_uri ()
8234
- # Try to access the PPD, in this case our detected IPP
8235
- # printer is a queue on a remote CUPS server which is
8236
- # not automatically set up on our local CUPS server
8237
- # (for example DNS-SD broadcasted queue from Mac OS X)
8238
- self.remotecupsqueue = None
8239
- res = re.search ("ipp://(\S+(:\d+|))/printers/(\S+)", uri)
8241
- resg = res.groups()
8243
- conn = httplib.HTTPConnection(resg[0])
8244
- conn.request("GET", "/printers/%s.ppd" % resg[2])
8245
- resp = conn.getresponse()
8246
- if resp.status == 200: self.remotecupsqueue = resg[2]
8248
- debugprint("exception in getting remotecupsqueue")
8251
- # We also want to fetch the printer-info and
8252
- # printer-location attributes, to pre-fill those
8253
- # fields for this new queue.
8254
- oldserver = cups.getServer()
8255
- oldport = cups.getPort()
8257
- cups.setServer (resg[0])
8258
- if len (resg[1]) > 0:
8259
- cups.setPort (int (resg[1]))
8261
- cups.setPort (631)
8263
- c = cups.Connection ()
8264
- r = ['printer-info', 'printer-location']
8265
- attrs = c.getPrinterAttributes (uri=uri,
8266
- requested_attributes=r)
8267
- info = attrs.get ('printer-info', '')
8268
- location = attrs.get ('printer-location', '')
8269
- if len (info) > 0:
8270
- self.entNPDescription.setText(info)
8271
- if len (location) > 0:
8272
- self.entNPLocation.setText(location)
8274
- nonfatalException ()
8276
- cups.setServer (oldserver)
8277
- cups.setPort (oldport)
8279
- if (not self.remotecupsqueue and
8280
- not self.new_printer_PPDs_loaded):
8282
- self.loadPPDs(self)
8283
- except cups.IPPError, (e, msg):
8284
- #self.ready (self)
8285
- self.show_IPP_Error(e, msg)
8290
- self.new_printer_PPDs_loaded = True
8294
- if self.remotecupsqueue:
8295
- # We have a remote CUPS queue, let the client queue
8296
- # stay raw so that the driver on the server gets used
8298
- self.ppd = ppdname
8299
- name = self.remotecupsqueue
8300
- name = self.mainapp.makeNameUnique (name)
8301
- self.entNPName.setText(name)
8302
- elif self.device.id:
8303
- id_dict = self.device.id_dict
8304
- (status, ppdname) = self.ppds.\
8305
- getPPDNameFromDeviceID (id_dict["MFG"],
8311
- (status, ppdname) = self.ppds.\
8312
- getPPDNameFromDeviceID ("Generic",
8314
- "Generic Printer",
8318
- if ppdname and not self.remotecupsqueue:
8319
- ppddict = self.ppds.getInfoFromPPDName (ppdname)
8320
- make_model = ppddict['ppd-make-and-model']
8322
- cupshelpers.ppds.ppdMakeModelSplit (make_model)
8323
- self.auto_make = make
8324
- self.auto_model = model
8326
- nonfatalException ()
8327
- if not self.remotecupsqueue:
8328
- self.fillMakeList()
8329
- elif page_nr == 3: # Model has been selected
8330
- if not self.device.id:
8331
- # Choose an appropriate name when no Device ID
8332
- # is available, based on the model the user has
8335
- items = self.tvNPModels.selectedItems()
8336
- name = unicode(items[0].text())
8337
- name = self.mainapp.makeNameUnique (name)
8338
- self.entNPName.setText(name)
8340
- nonfatalException ()
8342
- ##self.ready (self.NewPrinterWindow)
8343
- if self.remotecupsqueue:
8345
- elif self.rbtnNPFoomatic.isChecked():
8346
- order = [1, 2, 3, 6, 0]
8347
- elif self.rbtnNPPPD.isChecked():
8348
- order = [1, 2, 6, 0]
8350
- # Downloadable driver
8351
- order = [1, 2, 7, 6, 0]
8352
- elif self.dialog_mode == "device":
8354
- elif self.dialog_mode == "ppd":
8355
- self.rbtnChangePPDasIs.setChecked(True)
8356
- if self.rbtnNPFoomatic.isChecked():
8357
- order = [2, 3, 5, 6]
8358
- elif self.rbtnNPPPD.isChecked():
8361
- # Downloadable driver
8362
- order = [2, 7, 5, 6]
8364
- next_page_nr = order[order.index(page_nr)+step]
8366
- # fill Installable Options tab
8367
- if next_page_nr == 6 and step > 0:
8368
- #TODO Prepare Installable Options screen.
8369
- self.ppd = self.getNPPPD()
8371
- if next_page_nr == 6:
8372
- # Prepare Installable Options screen.
8373
- if isinstance(self.ppd, cups.PPD):
8374
- self.fillNPInstallableOptions()
8376
- self.installable_options = None
8377
- # Put a label there explaining why the page is empty.
8380
- self.fillNPInstallableOptions()
8383
- # step over if empty and not in PPD mode
8384
- if self.dialog_mode != "ppd" and not self.installable_options:
8385
- next_page_nr = order[order.index(next_page_nr)+1]
8387
- next_page_nr = order[order.index(next_page_nr)+1]
8388
- self.installable_options = False
8389
- # Step over empty Installable Options tab
8390
- if next_page_nr == 6 and not self.installable_options and step<0:
8391
- next_page_nr = order[order.index(next_page_nr)-1]
8393
- if next_page_nr == 7: # About to show downloadable drivers
8394
- if self.drivers_lock.locked ():
8395
- # Still searching for drivers.
8396
- self.lblWait.set_markup ('<span size="larger">' +
8397
- i18n('<b>Searching</b>') + '</span>\n\n' +
8398
- i18n('Searching for drivers'))
8399
- self.WaitWindow.set_transient_for (self.NewPrinterWindow)
8400
- self.WaitWindow.show ()
8403
- # Keep the UI refreshed while we wait for the drivers
8404
- # query to complete.
8405
- while self.drivers_lock.locked ():
8406
- while gtk.events_pending ():
8407
- gtk.main_iteration ()
8410
- self.ready (self.NewPrinterWindow)
8411
- self.WaitWindow.hide ()
8413
- self.fillDownloadableDrivers()
8415
- self.ntbkNewPrinter.setCurrentIndex(next_page_nr)
8417
- self.setNPButtons()
8419
- def setNPButtons(self):
8420
- nr = self.ntbkNewPrinter.currentIndex()
8422
- if self.dialog_mode == "device":
8423
- self.btnNPBack.hide()
8424
- self.btnNPForward.hide()
8425
- self.btnNPApply.show()
8426
- uri = self.getDeviceURI ()
8427
- self.btnNPApply.setEnabled(validDeviceURI (uri))
8430
- if self.dialog_mode == "ppd":
8431
- if nr == 5: # Apply
8432
- if not self.installable_options:
8433
- # There are no installable options, so this is the
8435
- debugprint ("No installable options")
8436
- self.btnNPForward.hide ()
8437
- self.btnNPApply.show ()
8439
- self.btnNPForward.show ()
8440
- self.btnNPApply.hide ()
8443
- self.btnNPForward.hide()
8444
- self.btnNPApply.show()
8447
- self.btnNPForward.show()
8448
- self.btnNPApply.hide()
8450
- self.btnNPBack.hide()
8451
- self.btnNPForward.show()
8452
- downloadable_selected = False
8453
- if self.rbtnNPDownloadableDriverSearch.isChecked():
8454
- combobox = self.cmbNPDownloadableDriverFoundPrinters
8455
- iter = combobox.get_active_iter () #FIXME
8456
- if iter and combobox.get_model ().get_value (iter, 1):
8457
- downloadable_selected = True
8459
- self.btnNPForward.setEnabled(bool(
8460
- self.rbtnNPFoomatic.isChecked() or
8461
- not self.filechooserPPD.text().isEmpty() or
8462
- downloadable_selected))
8465
- self.btnNPBack.show()
8469
- if nr == 1: # Device
8472
- uri = self.getDeviceURI ()
8473
- valid = validDeviceURI (uri)
8476
- self.btnNPForward.setEnabled(valid)
8477
- self.btnNPBack.hide ()
8479
- self.btnNPBack.show()
8481
- self.btnNPForward.show()
8482
- self.btnNPApply.hide()
8484
- if nr == 0: # Name
8485
- self.btnNPBack.show()
8486
- if self.dialog_mode == "class":
8487
- self.btnNPForward.setEnabled(True)
8488
- if self.dialog_mode == "printer":
8489
- self.btnNPForward.hide()
8490
- self.btnNPApply.show()
8491
- self.btnNPApply.setEnabled(
8492
- self.mainapp.checkNPName(unicode(self.entNPName.text())))
8493
- if nr == 2: # Make/PPD file
8494
- downloadable_selected = False
8495
- if self.rbtnNPDownloadableDriverSearch.isChecked():
8496
- combobox = self.cmbNPDownloadableDriverFoundPrinters
8497
- iter = combobox.get_active_iter () #FIXME
8498
- if iter and combobox.get_model ().get_value (iter, 1):
8499
- downloadable_selected = True
8501
- self.btnNPForward.setEnabled(bool(
8502
- self.rbtnNPFoomatic.isChecked() or
8503
- not self.filechooserPPD.text().isEmpty() or
8504
- downloadable_selected))
8506
- if nr == 3: # Model/Driver
8507
- iter = self.tvNPDrivers.currentItem()
8508
- self.btnNPForward.setEnabled(bool(iter))
8509
- if nr == 4: # Class Members
8510
- self.btnNPForward.hide()
8511
- self.btnNPApply.show()
8512
- self.btnNPApply.setEnabled(self.tvNCMembers.count() > 0)
8513
- if nr == 7: # Downloadable drivers
8514
- if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1: #FIXME
8515
- accepted = self.rbtnNPDownloadLicenseYes.get_active ()
8517
- treeview = self.tvNPDownloadableDrivers
8518
- model, iter = treeview.get_selection ().get_selected ()
8519
- accepted = (iter != None)
8521
- self.btnNPForward.set_sensitive(accepted)
8523
- def on_filechooserPPDButton(self):
8524
- home = QDir.homePath()
8525
- fd = QFileDialog()
8526
- fd.setFileMode(fd.ExistingFile)
8527
- filename = fd.getOpenFileName(self, 'Open PPD file', home)
8528
- self.filechooserPPD.setText(filename)
8529
- self.btnNPForward.setEnabled(True)
8531
- def getDevices_thread(self):
8533
- debugprint ("Connecting (devices)")
8534
- cups.setServer (self.mainapp.connect_server)
8535
- #cups.setUser (self.mainapp.connect_user)
8536
- cups.setUser ("jr")
8537
- cups.setPasswordCB (self.mainapp.cupsPasswdCallback)
8538
- # cups.setEncryption (...)
8539
- c = cups.Connection ()
8540
- debugprint ("Fetching devices")
8541
- self.devices_result = cupshelpers.getDevices(c)
8542
- except cups.IPPError, (e, msg):
8543
- self.devices_result = cups.IPPError (e, msg)
8545
- debugprint ("Exception in getDevices_thread")
8546
- self.devices_result = {}
8549
- debugprint ("Closing connection (devices)")
8554
- debugprint ("Releasing devices lock")
8555
- self.devices_lock.release ()
8558
- def queryDevices(self):
8559
- if not self.devices_lock.acquire(0):
8560
- debugprint ("queryDevices: in progress")
8562
- debugprint ("Lock acquired for devices thread")
8563
- # Start new thread
8564
- thread.start_new_thread (self.getDevices_thread, ())
8565
- #self.getDevices_thread()
8566
- debugprint ("Devices thread started")
8568
- def fetchDevices(self, parent=None):
8569
- debugprint ("fetchDevices")
8570
- self.queryDevices ()
8573
- # Keep the UI refreshed while we wait for the devices to load.
8575
- while (self.devices_lock.locked()):
8578
- self.WaitWindow.setText (i18n('<b>Searching</b>') + '<br/><br/>' +
8579
- i18n('Searching for printers'))
8581
- # parent = self.mainapp.MainWindow
8582
- #self.WaitWindow.set_transient_for (parent)
8583
- #self.WaitWindow.show ()
8584
- self.WaitWindow.show()
8586
- QApplication.processEvents()
8591
- #self.WaitWindow.hide ()
8592
- self.WaitWindow.hide()
8594
- debugprint ("Got devices")
8595
- result = self.devices_result # atomic operation
8596
- if isinstance (result, cups.IPPError):
8597
- # Propagate exception.
8601
- def get_hpfax_device_id(self, faxuri):
8602
- os.environ["URI"] = faxuri
8603
- cmd = 'LC_ALL=C DISPLAY= hp-info -d "${URI}"'
8604
- debugprint (faxuri + ": " + cmd)
8606
- p = subprocess.Popen (cmd, shell=True,
8607
- stdin=file("/dev/null"),
8608
- stdout=subprocess.PIPE,
8609
- stderr=subprocess.PIPE)
8610
- (stdout, stderr) = p.communicate ()
8612
- # Problem executing command.
8615
- for line in stdout.split ("\n"):
8616
- if line.find ("fax-type") == -1:
8619
- res = re.search ("(\d+)", line)
8621
- resg = res.groups()
8623
- if faxtype >= 0: break
8626
- elif faxtype == 4:
8627
- return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax 2;DES:HP Fax 2;')
8629
- return cupshelpers.parseDeviceID ('MFG:HP;MDL:Fax;DES:HP Fax;')
8631
- def get_hplip_uri_for_network_printer(self, host, mode):
8632
- os.environ["HOST"] = host
8633
- if mode == "print": mod = "-c"
8634
- elif mode == "fax": mod = "-f"
8636
- cmd = 'hp-makeuri ' + mod + ' "${HOST}"'
8637
- debugprint (host + ": " + cmd)
8640
- p = subprocess.Popen (cmd, shell=True,
8641
- stdin=file("/dev/null"),
8642
- stdout=subprocess.PIPE,
8643
- stderr=subprocess.PIPE)
8644
- (stdout, stderr) = p.communicate ()
8646
- # Problem executing command.
8649
- uri = stdout.strip ()
8652
- def getNetworkPrinterMakeModel(self, device):
8653
- # Determine host name/IP
8655
- s = device.uri.find ("://")
8658
- e = device.uri[s:].find (":")
8659
- if e == -1: e = device.uri[s:].find ("/")
8660
- if e == -1: e = device.uri[s:].find ("?")
8661
- if e == -1: e = len (device.uri)
8662
- host = device.uri[s:s+e]
8663
- # Try to get make and model via SNMP
8665
- os.environ["HOST"] = host
8666
- cmd = '/usr/lib/cups/backend/snmp "${HOST}"'
8667
- debugprint (host + ": " + cmd)
8670
- p = subprocess.Popen (cmd, shell=True,
8671
- stdin=file("/dev/null"),
8672
- stdout=subprocess.PIPE,
8673
- stderr=subprocess.PIPE)
8674
- (stdout, stderr) = p.communicate ()
8676
- # Problem executing command.
8679
- if stdout != None:
8680
- mm = re.sub("^\s*\S+\s+\S+\s+\"", "", stdout)
8681
- mm = re.sub("\"\s+.*$", "", mm)
8682
- if mm and mm != "": device.make_and_model = mm
8683
- # Extract make and model and create a pseudo device ID, so
8684
- # that a PPD/driver can be assigned to the device
8685
- make_and_model = None
8686
- if len (device.make_and_model) > 7:
8687
- make_and_model = device.make_and_model
8688
- elif len (device.info) > 7:
8689
- make_and_model = device.info
8690
- make_and_model = re.sub("\s*(\(|\d+\.\d+\.\d+\.\d+).*$", "", make_and_model)
8691
- if make_and_model and not device.id:
8694
- (mk, md) = cupshelpers.ppds.ppdMakeModelSplit (make_and_model)
8695
- device.id = "MFG:" + mk + ";MDL:" + md + ";DES:" + mk + " " + md + ";"
8696
- device.id_dict = cupshelpers.parseDeviceID (device.id)
8697
- # Check whether the device is supported by HPLIP and replace
8698
- # its URI by an HPLIP URI
8700
- hplipuri = self.get_hplip_uri_for_network_printer(host, "print")
8702
- device.uri = hplipuri
8703
- s = hplipuri.find ("/usb/")
8704
- if s == -1: s = hplipuri.find ("/par/")
8705
- if s == -1: s = hplipuri.find ("/net/")
8708
- e = hplipuri[s:].find ("?")
8709
- if e == -1: e = len (hplipuri)
8710
- mdl = hplipuri[s:s+e].replace ("_", " ")
8711
- if mdl.startswith ("hp ") or mdl.startswith ("HP "):
8713
- device.make_and_model = "HP " + mdl
8714
- device.id = "MFG:HP;MDL:" + mdl + ";DES:HP " + mdl + ";"
8715
- device.id_dict = cupshelpers.parseDeviceID (device.id)
8716
- # Return the host name/IP for further actions
8719
- def fillDeviceTab(self, current_uri=None, query=True):
8722
- devices = self.fetchDevices()
8723
- except cups.IPPError, (e, msg):
8724
- self.show_IPP_Error(e, msg)
8727
- nonfatalException()
8731
- if devices.has_key (current_uri):
8732
- current = devices.pop(current_uri)
8734
- current = cupshelpers.Device (current_uri)
8735
- current.info = "Current device"
8737
- self.devices = devices.values()
8739
- for device in self.devices:
8740
- if device.type == "usb":
8741
- # Find USB URIs with corresponding HPLIP URIs and mark them
8742
- # for deleting, so that the user will only get the HPLIP
8743
- # URIs for full device support in the list
8745
- s = device.uri.find ("?serial=")
8748
- e = device.uri[s:].find ("?")
8749
- if e == -1: e = len (device.uri)
8750
- ser = device.uri[s:s+e]
8752
- s = device.uri[6:].find ("/")
8755
- e = device.uri[s:].find ("?")
8756
- if e == -1: e = len (device.uri)
8757
- mod = device.uri[s:s+e].lower ().replace ("%20", "_")
8758
- if mod.startswith ("hp_"):
8761
- for hpdevice in self.devices:
8764
- uri = hpdevice.uri
8765
- if not uri.startswith ("hp:"): continue
8767
- s = uri.find ("?serial=")
8770
- e = uri[s:].find ("?")
8771
- if e == -1: e = len (uri)
8772
- hpser = uri[s:s+e]
8773
- if hpser != ser: continue
8775
- if mod and not (ser and hpser):
8776
- s = uri.find ("/usb/")
8779
- e = uri[s:].find ("?")
8780
- if e == -1: e = len (uri)
8781
- hpmod = uri[s:s+e].lower ()
8782
- if hpmod.startswith ("hp_"):
8784
- if hpmod != mod: continue
8786
- if matchfound == 1: break
8787
- if matchfound == 1:
8788
- device.uri = "delete"
8789
- if device.type == "hal":
8790
- # Remove HAL USB URIs, for these printers there are already
8792
- if device.uri.startswith("hal:///org/freedesktop/Hal/devices/usb_device"):
8793
- device.uri = "delete"
8794
- if device.type == "socket":
8795
- # Remove default port to more easily find duplicate URIs
8796
- device.uri = device.uri.replace (":9100", "")
8798
- ## XXX This needs to be moved to *after* the device is
8799
- # selected. Looping through all the network printers like
8800
- # this is far too slow.
8801
- if False and device.type in ("socket", "lpd", "ipp", "bluetooth"):
8802
- host = self.getNetworkPrinterMakeModel(device)
8805
- faxuri = self.get_hplip_uri_for_network_printer(host,
8808
- self.devices.append(cupshelpers.Device(faxuri,
8809
- **{'device-class' : "direct",
8810
- 'device-info' : device.info + " HP Fax HPLIP",
8811
- 'device-device-make-and-model' : "HP Fax",
8812
- 'device-id' : "MFG:HP;MDL:Fax;DES:HP Fax;"}))
8813
- if device.uri.startswith ("hp:"):
8814
- device.type = "hp"
8815
- device.info += (" HPLIP")
8817
- nonfatalException ()
8818
- # Mark duplicate URIs for deletion
8819
- for i in range (len (self.devices)):
8820
- for j in range (len (self.devices)):
8821
- if i == j: continue
8822
- device1 = self.devices[i]
8823
- device2 = self.devices[j]
8824
- if device1.uri == "delete" or device2.uri == "delete":
8826
- if device1.uri == device2.uri:
8827
- # Keep the one with the longer (better) device ID
8828
- if (not device1.id):
8829
- device1.uri = "delete"
8830
- elif (not device2.id):
8831
- device2.uri = "delete"
8832
- elif (len (device1.id) < len (device2.id)):
8833
- device1.uri = "delete"
8835
- device2.uri = "delete"
8836
- self.devices = filter(lambda x: x.uri not in ("hp:/no_device_found",
8837
- "hpfax:/no_device_found",
8840
- "scsi", "http", "delete"),
8842
- self.devices.sort()
8844
- self.devices.append(cupshelpers.Device('',
8845
- **{'device-info' :i18nc("Other device", "Other")}))
8847
- current.info = i18nc("Current device", "%1 (Current)", current.info)
8848
- self.devices.insert(0, current)
8849
- self.device = current
8850
- self.tvNPDevices.clear()
8852
- for device in self.devices:
8853
- self.tvNPDevices.addItem(device.info)
8855
- #self.tvNPDevices.get_selection().select_path(0)
8856
- self.tvNPDevices.setCurrentRow(0)
8857
- self.on_tvNPDevices_cursor_changed()
8859
- def on_entNPTDevice_changed(self, entry):
8860
- self.setNPButtons()
8864
- def on_entSMBURI_changed (self, text):
8865
- uri = unicode(text)
8866
- (group, host, share, user, password) = SMBURI (uri=uri).separate ()
8868
- self.entSMBUsername.setText(user)
8870
- self.entSMBPassword.setText(password)
8871
- if user or password:
8872
- uri = SMBURI (group=group, host=host, share=share).get_uri ()
8873
- self.entSMBURI.setText(uri)
8874
- self.rbtnSMBAuthSet.setChecked(True)
8875
- elif unicode(self.entSMBUsername.text()) == '':
8876
- self.rbtnSMBAuthPrompt.setChecked(True)
8878
- self.btnSMBVerify.setEnabled(bool(uri))
8880
- def on_rbtnSMBAuthSet_toggled(self, ticked):
8881
- self.tblSMBAuth.setEnabled(ticked)
8883
- def on_entNPTIPPHostname_textChanged(self):
8884
- valid = len (self.entNPTIPPHostname.text ()) > 0
8885
- self.btnIPPFindQueue.setEnabled(valid)
8886
- self.update_IPP_URI_label ()
8889
- def update_IPP_URI_label(self):
8890
- hostname = unicode(self.entNPTIPPHostname.text())
8891
- queue = unicode(self.entNPTIPPQueuename.text())
8892
- valid = len (hostname) > 0 and queue != '/printers/'
8895
- uri = "ipp://%s%s" % (hostname, queue)
8896
- self.lblIPPURI.setText(uri)
8897
- self.lblIPPURI.show ()
8898
- self.entNPTIPPQueuename.show ()
8900
- self.lblIPPURI.hide ()
8902
- self.btnIPPVerify.setEnabled(valid)
8903
- self.setNPButtons ()
8905
- #FIXME this seems totally different from the Gnome one
8906
- @pyqtSignature("")
8907
- def on_btnIPPFindQueue_clicked(self):
8908
- self.IPPBrowseBox.clear()
8909
- host = str(self.entNPTIPPHostname.text())
8910
- cups.setServer (host)
8911
- printers = classes = {}
8913
- c = cups.Connection()
8914
- printers = c.getPrinters ()
8915
- classes = c.getClasses ()
8917
- except RuntimeError:
8919
- except cups.IPP_Error, (e, msg):
8922
- for printer, dict in printers.iteritems ():
8924
- self.IPPBrowseBox.addItem(printer)
8925
-# store.set_value (iter, 0, printer)
8926
-# store.set_value (iter, 1, dict.get ('printer-location', ''))
8927
-# store.set_value (iter, 2, dict)
8928
- for pclass, dict in classes.iteritems ():
8930
-# iter = store.append (None)
8931
-# store.set_value (iter, 0, pclass)
8932
-# store.set_value (iter, 1, dict.get ('printer-location', ''))
8933
-# store.set_value (iter, 2, dict)
8935
- if len (printers) + len (classes) == 0:
8936
- # Display 'No queues' dialog
8937
- QMessageBox.information(self, i18n("No queues"),i18n("There are no queues available."))
8939
- def on_tvNPDevices_cursor_changed(self):
8940
- device = self.devices[self.tvNPDevices.currentRow()]
8941
- self.device = device
8942
- self.lblNPDeviceDescription.setText('')
8943
- page = self.new_printer_device_tabs.get(device.type, 1)
8944
- self.ntbkNPType.setCurrentIndex(page)
8946
- type = device.type
8947
- url = device.uri.split(":", 1)[-1]
8949
- # This is the "no options" page, with just a label to describe
8950
- # the selected device.
8951
- if device.type == "parallel":
8952
- text = i18n("A printer connected to the parallel port.")
8953
- elif device.type == "usb":
8954
- text = i18n("A printer connected to a USB port.")
8955
- elif device.type == "hp":
8956
- text = i18n("HPLIP software driving a printer, "
8957
- "or the printer function of a multi-function device.")
8958
- elif device.type == "hpfax":
8959
- text = i18n("HPLIP software driving a fax machine, "
8960
- "or the fax function of a multi-function device.")
8961
- elif device.type == "hal":
8962
- text = i18n("Local printer detected by the "
8963
- "Hardware Abstraction Layer (HAL).")
8967
- self.lblNPDeviceDescription.setText(text)
8968
- elif device.type=="socket":
8969
- if device.uri.startswith ("socket"):
8970
- host = device.uri[9:]
8971
- i = host.find (":")
8973
- port = int (host[i + 1:])
8978
- self.entNPTDirectJetHostname.setText(host)
8979
- self.entNPTDirectJetPort.setText(str (port))
8980
- elif device.type=="serial":
8981
- if not device.is_class:
8982
- options = device.uri.split("?")[1]
8983
- options = options.split("+")
8985
- for option in options:
8986
- name, value = option.split("=")
8987
- option_dict[name] = value
8989
- for widget, name, optionvalues in (
8990
- (self.cmbNPTSerialBaud, "baud", None),
8991
- (self.cmbNPTSerialBits, "bits", None),
8992
- (self.cmbNPTSerialParity, "parity",
8993
- ["none", "odd", "even"]),
8994
- (self.cmbNPTSerialFlow, "flow",
8995
- ["none", "soft", "hard", "hard"])):
8996
- if option_dict.has_key(name): # option given in URI?
8997
- if optionvalues is None: # use text in widget
8998
- model = widget.get_model()
8999
- iter = model.get_iter_first()
9002
- value = model.get(iter,0)[0]
9003
- if value == option_dict[name]:
9004
- widget.set_active(nr)
9006
- iter = model.iter_next(iter)
9008
- else: # use optionvalues
9009
- nr = optionvalues.index(
9010
- option_dict[name])
9011
- widget.set_active(nr+1) # compensate "Default"
9013
- widget.set_active(0)
9015
- # XXX FILL TABS FOR VALID DEVICE URIs
9016
- elif device.type in ("ipp", "http"):
9017
- if (device.uri.startswith ("ipp:") or
9018
- device.uri.startswith ("http:")):
9019
- match = re.match ("(ipp|https?)://([^/]+)(.*)", device.uri)
9021
- server = match.group (2)
9022
- printer = match.group (3)
9027
- self.entNPTIPPHostname.setText(server)
9028
- self.entNPTIPPQueuename.setText(printer)
9029
- self.lblIPPURI.setText(device.uri)
9030
- self.lblIPPURI.show()
9031
- self.entNPTIPPQueuename.show()
9033
- self.entNPTIPPHostname.setText('')
9034
- self.entNPTIPPQueuename.setText('/printers/')
9035
- self.entNPTIPPQueuename.show()
9036
- self.lblIPPURI.hide()
9037
- elif device.type=="lpd":
9038
- if device.uri.startswith ("lpd"):
9039
- host = device.uri[6:]
9040
- i = host.find ("/")
9042
- printer = host[i + 1:]
9046
- self.cmbentNPTLpdHost.addItem(host)
9047
- self.cmbentNPTLpdQueue.addItem(printer)
9048
- elif device.uri == "lpd":
9050
- elif device.uri == "smb":
9051
- self.entSMBURI.setText('')
9052
- self.btnSMBVerify.setEnabled(False)
9053
- elif device.type == "smb":
9054
- self.entSMBUsername.setText('')
9055
- self.entSMBPassword.setText('')
9056
- self.entSMBURI.setText(device.uri[6:])
9057
- self.btnSMBVerify.setEnabled(True)
9059
- self.entNPTDevice.setText(device.uri)
9061
- self.setNPButtons()
9063
- def getDeviceURI(self):
9064
- type = self.device.type
9065
- if type == "socket": # DirectJet
9066
- host = unicode(self.entNPTDirectJetHostname.text())
9067
- port = unicode(self.entNPTDirectJetPort.text())
9068
- device = "socket://" + host
9070
- device = device + ':' + port
9071
- elif type in ("http", "ipp"): # IPP
9072
- if self.lblIPPURI.isVisible:
9073
- device = unicode(self.lblIPPURI.text())
9076
- elif type == "lpd": # LPD
9077
- host = unicode(self.cmbentNPTLpdHost.currentText())
9078
- printer = unicode(self.cmbentNPTLpdQueue.currentText())
9079
- device = "lpd://" + host
9081
- device = device + "/" + printer
9082
- elif type == "parallel": # Parallel
9083
- device = self.device.uri
9084
- elif type == "scsi": # SCSII
9086
- elif type == "serial": # Serial
9088
- for widget, name, optionvalues in (
9089
- (self.cmbNPTSerialBaud, "baud", None),
9090
- (self.cmbNPTSerialBits, "bits", None),
9091
- (self.cmbNPTSerialParity, "parity",
9092
- ("none", "odd", "even")),
9093
- (self.cmbNPTSerialFlow, "flow",
9094
- ("none", "soft", "hard", "hard"))):
9095
- nr = widget.get_active()
9097
- if optionvalues is not None:
9098
- option = optionvalues[nr-1]
9100
- option = widget.get_active_text()
9101
- options.append(name + "=" + option)
9102
- options = "+".join(options)
9103
- device = self.device.uri.split("?")[0] #"serial:/dev/ttyS%s"
9105
- device = device + "?" + options
9106
- elif type == "smb":
9107
- uri = unicode(self.entSMBURI.text())
9108
- (group, host, share, u, p) = SMBURI (uri=uri).separate ()
9111
- if self.rbtnSMBAuthSet.isChecked():
9112
- user = unicode(self.entSMBUsername.text())
9113
- password = unicode(self.entSMBPassword.text())
9114
- uri = SMBURI (group=group, host=host, share=share,
9115
- user=user, password=password).get_uri ()
9116
- device = "smb://" + uri
9117
- elif not self.device.is_class:
9118
- device = self.device.uri
9120
- device = str(self.entNPTDevice.text())
9124
- if nr == self.ntbkNewPrinterPages["device"]: # Device
9127
- uri = self.getDeviceURI ()
9128
- valid = validDeviceURI (uri)
9130
- debugprint("exception in getDeviceURI()")
9132
- self.btnNPForward.setEnabled(valid)
9133
- self.btnNPBack.hide ()
9135
- self.btnNPBack.show()
9137
- self.btnNPForward.show()
9138
- self.btnNPApply.hide()
9140
- if nr == self.ntbkNewPrinterPages["name"]: # Name
9141
- self.btnNPBack.show()
9142
- if self.dialog_mode == "printer":
9143
- self.btnNPForward.hide()
9144
- self.btnNPApply.show()
9145
- self.btnNPApply.setEnabled(
9146
- self.mainapp.checkNPName(self.entNPName.getText()))
9147
- if nr == self.ntbkNewPrinterPages["make"]: # Make/PPD file
9148
- downloadable_selected = False
9149
- if self.rbtnNPDownloadableDriverSearch.get_active ():
9150
- combobox = self.cmbNPDownloadableDriverFoundPrinters
9151
- iter = combobox.get_active_iter ()
9152
- if iter and combobox.get_model ().get_value (iter, 1):
9153
- downloadable_selected = True
9155
- self.btnNPForward.setEnabled(bool(
9156
- self.rbtnNPFoomatic.get_active() or
9157
- not self.filechooserPPD.text().isEmpty() or
9158
- downloadable_selected))
9159
- if nr == self.ntbkNewPrinterPages["model"]: # Model/Driver
9160
- model, iter = self.tvNPDrivers.get_selection().get_selected()
9161
- self.btnNPForward.set_sensitive(bool(iter))
9162
- if nr == self.ntbkNewPrinterPages["class-members"]: # Class Members
9163
- self.btnNPForward.hide()
9164
- self.btnNPApply.show()
9165
- self.btnNPApply.setEnabled(
9166
- bool(self.mainapp.getCurrentClassMembers(self.tvNCMembers)))
9167
- if nr == self.ntbkNewPrinterPages["downloadable"]: # Downloadable drivers
9168
- if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1:
9169
- accepted = self.rbtnNPDownloadLicenseYes.get_active ()
9173
- self.btnNPForward.set_sensitive(accepted)
9177
- def on_rbtnNPFoomatic_toggled(self):
9178
- rbtn1 = self.rbtnNPFoomatic.isChecked()
9179
- rbtn2 = self.rbtnNPPPD.isChecked()
9180
- rbtn3 = self.rbtnNPDownloadableDriverSearch.isChecked()
9181
- self.tvNPMakes.setEnabled(rbtn1)
9182
- self.filechooserPPD.setEnabled(rbtn2)
9185
- if not rbtn3 and self.openprinting_query_handle:
9186
- # Need to cancel a search in progress.
9187
- self.openprinting.cancelOperation (self.openprinting_query_handle)
9188
- self.openprinting_query_handle = None
9189
- self.btnNPDownloadableDriverSearch_label.setText(_("Search"))
9190
- # Clear printer list.
9191
- self.cmbNPDownloadableDriverFoundPrinters.clear()
9194
- for widget in [self.entNPDownloadableDriverSearch,
9195
- self.cmbNPDownloadableDriverFoundPrinters]:
9196
- widget.setEnabled(rbtn3)
9197
- self.btnNPDownloadableDriverSearch.\
9198
- setEnabled(rbtn3 and (self.openprinting_query_handle == None))
9200
- self.setNPButtons()
9202
- # PPD from foomatic
9204
- def fillMakeList(self):
9205
- makes = self.ppds.getMakes()
9206
- self.tvNPMakes.clear()
9209
- for make in makes:
9210
- self.tvNPMakes.addItem(make)
9212
- if make==self.auto_make:
9213
- self.tvNPMakes.setCurrentRow(index-1)
9216
- self.on_tvNPMakes_cursor_changed()
9218
- def on_tvNPMakes_cursor_changed(self):
9219
- items = self.tvNPMakes.selectedItems()
9220
- if len(items) > 0:
9221
- self.NPMake = unicode(items[0].text())
9222
- self.fillModelList()
9224
- def fillModelList(self):
9225
- models = self.ppds.getModels(self.NPMake)
9226
- self.tvNPModels.clear()
9230
- for pmodel in models:
9231
- self.tvNPModels.addItem(pmodel)
9232
- if self.NPMake==self.auto_make and pmodel==self.auto_model:
9233
- self.tvNPModels.setCurrentRow(index)
9237
- self.tvNPModels.setCurrentRow(0)
9238
- ##self.tvNPModels.columns_autosize()
9239
- self.on_tvNPModels_cursor_changed()
9241
- def fillDriverList(self, pmake, pmodel):
9242
- self.NPModel = pmodel
9243
- self.tvNPDrivers.clear()
9245
- ppds = self.ppds.getInfoFromModel(pmake, pmodel)
9247
- self.NPDrivers = self.ppds.orderPPDNamesByPreference(ppds.keys())
9248
- for i in range (len(self.NPDrivers)):
9249
- ppd = ppds[self.NPDrivers[i]]
9250
- driver = ppd["ppd-make-and-model"]
9251
- driver = driver.replace(" (recommended)", "")
9254
- lpostfix = " [%s]" % ppd["ppd-natural-language"]
9255
- driver += lpostfix
9260
- self.tvNPDrivers.addItem(i18nc("Recommended driver", "%1 (recommended)", driver))
9261
- self.tvNPDrivers.setCurrentRow(0)
9263
- self.tvNPDrivers.addItem(driver)
9264
- ##self.tvNPDrivers.columns_autosize()
9266
- def on_tvNPModels_cursor_changed(self):
9267
- items = self.tvNPModels.selectedItems()
9268
- if len(items) > 0:
9269
- pmodel = unicode(items[0].text())
9270
- self.fillDriverList(self.NPMake, pmodel)
9272
- def getNPPPD(self):
9274
- if self.rbtnNPFoomatic.isChecked():
9275
- #items = self.tvNPDrivers.selectedItems()
9276
- #nr = unicode(items[0])
9277
- nr = self.tvNPDrivers.currentRow()
9278
- ppd = self.NPDrivers[nr]
9279
- elif self.rbtnNPPPD.isChecked():
9280
- ppd = cups.PPD(unicode(self.filechooserPPD.text()))
9283
- # PPD of the driver downloaded from OpenPrinting XXX
9284
- treeview = self.tvNPDownloadableDrivers
9285
- model, iter = treeview.get_selection ().get_selected ()
9286
- driver = model.get_value (iter, 1)
9287
- if driver.has_key ('ppds'):
9288
- # Only need to download a PPD.
9289
- file_to_download = driver
9294
- except RuntimeError, e:
9295
- if self.rbtnNPFoomatic.isChecked():
9296
- # Foomatic database problem of some sort.
9297
- err_title = i18n('Database error')
9298
- model, iter = (self.tvNPDrivers.get_selection().
9300
- nr = model.get_path(iter)[0]
9301
- driver = self.NPDrivers[nr]
9302
- if driver.startswith ("gutenprint"):
9303
- # This printer references some XML that is not
9304
- # installed by default. Point the user at the
9305
- # package they need to install.
9306
- err = i18n("You will need to install the '%1' package "
9307
- "in order to use this driver.",
9308
- "gutenprint-foomatic")
9310
- err = i18n("The '%1' driver cannot be "
9311
- "used with printer '%2 %3'.", driver, self.NPMake, self.NPModel)
9312
- elif self.rbtnNPPPD.isChecked():
9313
- # This error came from trying to open the PPD file.
9314
- err_title = i18n('PPD error')
9315
- filename = self.filechooserPPD.text()
9316
- err = i18n('Failed to read PPD file. Possible reason '
9317
- 'follows:') + '\n'
9318
- os.environ["PPD"] = filename
9319
- # We want this to be in the current natural language,
9320
- # so we intentionally don't set LC_ALL=C here.
9321
- p = os.popen ('/usr/bin/cupstestppd -rvv "$PPD"', 'r')
9322
- output = p.readlines ()
9324
- err += reduce (lambda x, y: x + y, output)
9326
- # Failed to get PPD downloaded from OpenPrinting XXX
9327
- err_title = i18n('Downloadable drivers')
9328
- err_text = i18n("Support for downloadable "
9329
- "drivers is not yet completed.")
9331
- error_text = ('<span size="larger">' +
9332
- i18nc("Error title", "<b>%1</b>", err_title) + '</span>\n\n' + err)
9333
- QMessageBox.critical(self, err_title, error_text)
9336
- if isinstance(ppd, str) or isinstance(ppd, unicode):
9338
- if (ppd != "raw"):
9339
- f = self.mainapp.cups.getServerPPD(ppd)
9342
- except AttributeError:
9343
- nonfatalException()
9344
- debugprint ("pycups function getServerPPD not available: never mind")
9345
- except RuntimeError:
9346
- nonfatalException()
9347
- debugprint ("libcups from CUPS 1.3 not available: never mind")
9348
- except cups.IPPError:
9349
- nonfatalException()
9350
- debugprint ("CUPS 1.3 server not available: never mind")
9354
- # Create new Printer
9355
- @pyqtSignature("")
9356
- def on_btnNPApply_clicked(self):
9357
- if self.dialog_mode in ("class", "printer"):
9358
- name = unicode(self.entNPName.text())
9359
- location = unicode(self.entNPLocation.text())
9360
- info = unicode(self.entNPDescription.text())
9362
- name = self.mainapp.printer.name
9364
- #replace any whitespace in printer name with underscore otherwise
9365
- #CUPS throws an error
9366
- name = name.replace(" ", "_")
9368
- # Whether to check for missing drivers.
9373
- if self.dialog_mode=="class":
9374
- members = self.mainapp.getCurrentClassMembers(self.tvNCMembers)
9376
- for member in members:
9377
- self.passwd_retry = False # use cached Passwd
9378
- self.mainapp.cups.addPrinterToClass(str(member), name)
9379
- except cups.IPPError, (e, msg):
9380
- self.show_IPP_Error(e, msg)
9382
- elif self.dialog_mode=="printer":
9383
- self.device.uri = unicode(self.device.uri)
9385
- if self.device.uri:
9386
- uri = self.device.uri
9388
- uri = self.getDeviceURI()
9389
- if not self.ppd: # XXX needed?
9390
- # Go back to previous page to re-select driver.
9391
- self.nextNPTab(-1)
9394
- # write Installable Options to ppd
9395
- for option in self.options.itervalues():
9396
- option.writeback()
9399
- self.WaitWindow.setText(i18n('<b>Adding</b>') + '<br /><br />' +
9400
- i18n('Adding printer'))
9401
- #self.WaitWindow.set_transient_for (self.NewPrinterWindow)
9402
- self.WaitWindow.show ()
9403
- QApplication.processEvents()
9405
- self.passwd_retry = False # use cached Passwd
9406
- if isinstance(ppd, str) or isinstance(ppd, unicode):
9407
- self.mainapp.cups.addPrinter(name, ppdname=ppd,
9408
- device=uri, info=info, location=location)
9410
- elif ppd is None: # raw queue
9411
- self.mainapp.cups.addPrinter(name, device=uri,
9412
- info=info, location=location)
9414
- cupshelpers.setPPDPageSize(ppd, self.language[0])
9415
- self.mainapp.cups.addPrinter(name, ppd=ppd,
9416
- device=uri, info=info, location=location)
9419
- cupshelpers.activateNewPrinter (self.mainapp.cups, name)
9420
- except cups.IPPError, (e, msg):
9422
- self.WaitWindow.hide ()
9423
- self.show_IPP_Error(e, msg)
9426
- ##self.ready (self.NewPrinterWindow)
9427
- self.WaitWindow.hide ()
9428
- fatalException (1)
9429
- self.WaitWindow.hide ()
9430
- ##self.ready (self.NewPrinterWindow)
9432
- if self.dialog_mode in ("class", "printer"):
9434
- self.passwd_retry = False # use cached Passwd
9435
- self.mainapp.cups.setPrinterLocation(name, location)
9436
- self.passwd_retry = False # use cached Passwd
9437
- self.mainapp.cups.setPrinterInfo(name, info)
9438
- except cups.IPPError, (e, msg):
9439
- self.show_IPP_Error(e, msg)
9441
- elif self.dialog_mode == "device":
9443
- uri = self.getDeviceURI()
9444
- self.mainapp.cups.addPrinter(name, device=uri)
9445
- except cups.IPPError, (e, msg):
9446
- self.show_IPP_Error(e, msg)
9448
- elif self.dialog_mode == "ppd":
9450
- ppd = self.ppd = self.getNPPPD()
9452
- # Go back to previous page to re-select driver.
9453
- self.nextNPTab(-1)
9456
- # set ppd on server and retrieve it
9457
- # cups doesn't offer a way to just download a ppd ;(=
9459
- if isinstance(ppd, str) or isinstance(ppd, unicode):
9460
- if self.rbtnChangePPDasIs.isChecked():
9461
- # To use the PPD as-is we need to prevent CUPS copying
9462
- # the old options over. Do this by setting it to a
9463
- # raw queue (no PPD) first.
9465
- self.mainapp.cups.addPrinter(name, ppdname='raw')
9466
- except cups.IPPError, (e, msg):
9467
- self.show_IPP_Error(e, msg)
9469
- self.mainapp.cups.addPrinter(name, ppdname=ppd)
9470
- except cups.IPPError, (e, msg):
9471
- self.show_IPP_Error(e, msg)
9475
- filename = self.mainapp.cups.getPPD(name)
9476
- ppd = cups.PPD(filename)
9477
- os.unlink(filename)
9478
- except cups.IPPError, (e, msg):
9479
- if e == cups.IPP_NOT_FOUND:
9482
- self.show_IPP_Error(e, msg)
9485
- # We have an actual PPD to upload, not just a name.
9486
- if not self.rbtnChangePPDasIs.isChecked():
9487
- cupshelpers.copyPPDOptions(self.mainapp.ppd, ppd) # XXX
9489
- # write Installable Options to ppd
9490
- for option in self.options.itervalues():
9491
- option.writeback()
9492
- cupshelpers.setPPDPageSize(ppd, self.language[0])
9495
- self.mainapp.cups.addPrinter(name, ppd=ppd)
9496
- except cups.IPPError, (e, msg):
9497
- self.show_IPP_Error(e, msg)
9504
- self.mainapp.populateList(start_printer=name)
9507
- self.checkDriverExists (name, ppd=checkppd)
9509
- nonfatalException()
9511
- # Also check to see whether the media option has become
9512
- # invalid. This can happen if it had previously been
9513
- # explicitly set to a page size that is not offered with
9514
- # the new PPD (see bug #441836).
9517
- option = self.mainapp.server_side_options['media']
9518
- if option.get_current_value () == None:
9519
- debugprint ("Invalid media option: resetting")
9521
- self.mainapp.changed.add (option)
9522
- self.mainapp.save_printer (self.mainapp.printer)
9526
- print "exception in check to see whether the media option has become invalid"
9527
- nonfatalException()
9530
- def show_IPP_Error(self, exception, message):
9531
- if exception == cups.IPP_NOT_AUTHORIZED:
9532
- QMessageBox.critical(self, i18n('Not authorized'), i18n('The password may be incorrect.'))
9534
- QMessageBox.critical(self, i18n('CUPS server error'), i18n("There was an error during the CUPS "\
9535
- "operation: '%1'.", message))
9537
- def checkDriverExists(self, name, ppd=None):
9538
- """Check that the driver for an existing queue actually
9539
- exists, and prompt to install the appropriate package
9542
- ppd: cups.PPD object, if already created"""
9544
- # Is this queue on the local machine? If not, we can't check
9545
- # anything at all.
9546
- server = cups.getServer ()
9547
- if not (server == 'localhost' or server == '127.0.0.1' or
9548
- server == '::1' or server[0] == '/'):
9551
- # Fetch the PPD if we haven't already.
9554
- filename = self.mainapp.cups.getPPD(name)
9555
- except cups.IPPError, (e, msg):
9556
- if e == cups.IPP_NOT_FOUND:
9557
- # This is a raw queue. Nothing to check.
9560
- self.show_IPP_Error(e, msg)
9563
- ppd = cups.PPD(filename)
9564
- os.unlink(filename)
9566
- (pkgs, exes) = cupshelpers.missingPackagesAndExecutables (ppd)
9567
- if len (pkgs) > 0 or len (exes) > 0:
9568
- # We didn't find a necessary executable. Complain.
9569
- install = "/usr/bin/system-install-packages"
9570
- if len (pkgs) > 0 and os.access (install, os.X_OK):
9572
- install_text = ('<span weight="bold" size="larger">' +
9573
- i18n('Install driver') + '</span>\n\n' +
9574
- i18n("Printer '%1' requires the %2 package but "
9575
- "it is not currently installed.", name, pkg))
9576
- dialog = self.InstallDialog
9577
- self.lblInstall.set_markup(install_text)
9579
- error_text = ('<span weight="bold" size="larger">' +
9580
- i18n('Missing driver') + '</span>\n\n' +
9581
- i18n("Printer '%1' requires the '%2' program but "
9582
- "it is not currently installed. Please "
9583
- "install it before using this printer.", name, (exes + pkgs)[0]))
9584
- QMessageBox.error(self, "", error_text)
9587
- if pkg and response == gtk.RESPONSE_OK:
9588
- # Install the package.
9589
- def wait_child (sig, stack):
9590
- (pid, status) = os.wait ()
9592
- signal.signal (signal.SIGCHLD, wait_child)
9597
- os.execv (install, [install, pkg])
9602
- pass # should handle error
9606
- def on_entNPTIPPQueuename_textChanged(self, ent):
9607
- self.update_IPP_URI_label ()
9610
- def on_IPPBrowseBox_currentTextChanged(self, text):
9611
- self.update_IPP_URI_label()
9613
- #FIXME not in gnome?
9614
- @pyqtSignature("")
9615
- def on_btnNPCancel_clicked(self):
9617
-#end of class NewPrinterGUI
9619
-if __name__ == "__main__":
9620
- """start the application"""
9622
- appName = "system-config-printer-kde"
9623
- catalogue = "system-config-printer-kde"
9624
- programName = ki18n("System Config Printer KDE")
9626
- description = ki18n("Printer configuration tool")
9627
- license = KAboutData.License_GPL
9628
- copyright = ki18n("2007 Tim Waugh, Red Hat Inc, 2007-2008 Canonical Ltd")
9629
- text = KLocalizedString()
9630
- homePage = "https://launchpad.net/system-config-printer"
9633
- aboutData = KAboutData (appName, catalogue, programName, version, description,
9634
- license, copyright, text, homePage, bugEmail)
9636
- aboutData.addAuthor(ki18n("Jonathan Riddell"), ki18n("Author"))
9637
- aboutData.addAuthor(ki18n("Tim Waugh/Red Hat"), ki18n("System Config Printer Author"))
9639
- options = KCmdLineOptions()
9641
- KCmdLineArgs.init(sys.argv, aboutData)
9642
- KCmdLineArgs.addCmdLineOptions(options)
9644
- app = KApplication()
9645
- args = KCmdLineArgs.parsedArgs()
9648
- sys.exit(app.exec_())
9649
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
9650
--- orig/kdeadmin-4.2.2/system-config-printer-kde/system-config-printer.ui 2008-12-10 16:14:00.000000000 +0000
9651
+++ kdeadmin-4.2.2/system-config-printer-kde/system-config-printer.ui 2009-04-09 22:56:08.000000000 +0100
9653
-<ui version="4.0" >
9654
+<?xml version="1.0" encoding="UTF-8"?>
9657
- <widget class="QWidget" name="form" >
9658
- <property name="geometry" >
9659
+ <widget class="QWidget" name="form">
9660
+ <property name="geometry">
9664
- <width>878</width>
9665
- <height>444</height>
9666
+ <width>826</width>
9667
+ <height>509</height>
9670
- <property name="windowIcon" >
9671
+ <property name="windowIcon">
9673
<normaloff>../../../../.designer/backup/printer-128.png</normaloff>../../../../.designer/backup/printer-128.png</iconset>
9675
- <layout class="QGridLayout" name="gridLayout" >
9676
- <item rowspan="2" row="0" column="0" >
9677
- <widget class="QTreeWidget" name="mainlist" >
9678
- <property name="sizePolicy" >
9679
- <sizepolicy vsizetype="Expanding" hsizetype="Fixed" >
9680
+ <layout class="QGridLayout" name="gridLayout_4">
9681
+ <item row="0" column="0">
9682
+ <widget class="QTreeWidget" name="mainlist">
9683
+ <property name="sizePolicy">
9684
+ <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
9685
<horstretch>0</horstretch>
9686
<verstretch>0</verstretch>
9689
- <property name="rootIsDecorated" >
9690
+ <property name="rootIsDecorated">
9694
- <property name="text" >
9695
+ <property name="text">
9701
- <item row="0" column="1" colspan="3" >
9702
- <widget class="QStackedWidget" name="ntbkMain" >
9703
- <property name="currentIndex" >
9704
+ <item row="0" column="1">
9705
+ <widget class="QStackedWidget" name="ntbkMain">
9706
+ <property name="sizePolicy">
9707
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
9708
+ <horstretch>0</horstretch>
9709
+ <verstretch>0</verstretch>
9712
+ <property name="currentIndex">
9715
- <widget class="QWidget" name="page" >
9716
- <layout class="QGridLayout" >
9717
- <item row="0" column="0" >
9718
- <widget class="QLabel" name="label" >
9719
- <property name="text" >
9720
- <string>Add New Printer</string>
9724
- <item row="1" column="0" >
9725
- <widget class="QPushButton" name="btnNewPrinter" >
9726
- <property name="text" >
9727
- <string>New Local Printer</string>
9731
- <item row="1" column="1" >
9732
- <widget class="QLabel" name="newPrinterLabel" >
9733
- <property name="text" >
9734
- <string>New printer attached to this computer.</string>
9738
- <item row="2" column="0" >
9739
- <widget class="QPushButton" name="btnNewPrinterNetwork" >
9740
- <property name="text" >
9741
- <string>New Network Printer</string>
9745
- <item row="2" column="1" >
9746
- <widget class="QLabel" name="newPrinterNetworkLabel" >
9747
- <property name="text" >
9748
- <string>New remote printer</string>
9749
+ <widget class="QWidget" name="page">
9750
+ <layout class="QVBoxLayout" name="verticalLayout_4">
9752
+ <widget class="QLabel" name="label">
9753
+ <property name="sizePolicy">
9754
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
9755
+ <horstretch>0</horstretch>
9756
+ <verstretch>0</verstretch>
9761
- <item row="3" column="0" >
9762
- <widget class="QPushButton" name="btnNewPrinterSpecial" >
9763
- <property name="text" >
9764
- <string>New Special Printer</string>
9765
+ <property name="font">
9767
+ <weight>75</weight>
9773
- <item row="3" column="1" >
9774
- <widget class="QLabel" name="newPrinterSpecialLabel" >
9775
- <property name="text" >
9776
- <string comment="KDE::DoNotExtract" >TextLabel</string>
9780
- <item row="4" column="0" >
9781
- <widget class="QPushButton" name="btnNewClass" >
9782
- <property name="text" >
9783
- <string>New Printer Class</string>
9784
+ <property name="text">
9785
+ <string>Add New Printer</string>
9789
- <item row="4" column="1" >
9790
- <widget class="QLabel" name="label_5" >
9791
- <property name="text" >
9792
- <string>Add a new printer group.</string>
9796
+ <layout class="QGridLayout" name="gridLayout">
9797
+ <item row="0" column="0">
9798
+ <widget class="KPushButton" name="btnNewPrinter">
9799
+ <property name="text">
9800
+ <string>New Local Printer</string>
9804
+ <item row="0" column="1">
9805
+ <widget class="QLabel" name="newPrinterLabel">
9806
+ <property name="sizePolicy">
9807
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
9808
+ <horstretch>0</horstretch>
9809
+ <verstretch>0</verstretch>
9812
+ <property name="text">
9813
+ <string>Add a new printer which is directly connected to your
9818
+ <item row="1" column="0">
9819
+ <widget class="KPushButton" name="btnNewPrinterNetwork">
9820
+ <property name="text">
9821
+ <string>New Network Printer</string>
9825
+ <item row="1" column="1">
9826
+ <widget class="QLabel" name="newPrinterNetworkLabel">
9827
+ <property name="sizePolicy">
9828
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
9829
+ <horstretch>0</horstretch>
9830
+ <verstretch>0</verstretch>
9833
+ <property name="text">
9834
+ <string>Add a new printer which is connected to your home
9835
+network or on the Internet.</string>
9839
+ <item row="2" column="0">
9840
+ <widget class="KPushButton" name="btnNewPrinterSpecial">
9841
+ <property name="text">
9842
+ <string>New Special Printer</string>
9846
+ <item row="2" column="1">
9847
+ <widget class="QLabel" name="newPrinterSpecialLabel">
9848
+ <property name="sizePolicy">
9849
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
9850
+ <horstretch>0</horstretch>
9851
+ <verstretch>0</verstretch>
9854
+ <property name="text">
9855
+ <string>Add a new special printer such as a Fax or PDF by
9856
+specifying an executable command.</string>
9860
+ <item row="3" column="0">
9861
+ <widget class="KPushButton" name="btnNewClass">
9862
+ <property name="text">
9863
+ <string>New Printer Class</string>
9867
+ <item row="3" column="1">
9868
+ <widget class="QLabel" name="label_5">
9869
+ <property name="sizePolicy">
9870
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
9871
+ <horstretch>0</horstretch>
9872
+ <verstretch>0</verstretch>
9875
+ <property name="text">
9876
+ <string>Add a new printer class to specify a group of computers to
9883
- <item row="5" column="0" >
9885
- <property name="orientation" >
9887
+ <spacer name="verticalSpacer_4">
9888
+ <property name="orientation">
9889
<enum>Qt::Vertical</enum>
9891
- <property name="sizeHint" stdset="0" >
9892
+ <property name="sizeHint" stdset="0">
9895
- <height>40</height>
9896
+ <width>528</width>
9897
+ <height>317</height>
9904
- <widget class="QWidget" name="page_3" >
9905
- <layout class="QGridLayout" >
9906
- <item row="0" column="0" colspan="2" >
9907
- <layout class="QHBoxLayout" >
9908
+ <widget class="QWidget" name="page_3">
9909
+ <layout class="QGridLayout">
9910
+ <item row="0" column="0" colspan="2">
9911
+ <layout class="QHBoxLayout">
9913
- <widget class="QLabel" name="label_6" >
9914
- <property name="text" >
9915
+ <widget class="QLabel" name="label_6">
9916
+ <property name="text">
9917
<string>Basic Server Settings</string>
9922
- <widget class="QLabel" name="lblClassMembers" >
9923
- <property name="text" >
9924
+ <widget class="QLabel" name="lblClassMembers">
9925
+ <property name="text">
9931
- <widget class="QLabel" name="lblPInstallOptions" >
9932
- <property name="text" >
9933
+ <widget class="QLabel" name="lblPInstallOptions">
9934
+ <property name="text">
9940
- <widget class="QLabel" name="lblPOptions" >
9941
- <property name="text" >
9942
+ <widget class="QLabel" name="lblPOptions">
9943
+ <property name="text">
9950
- <item row="1" column="0" colspan="2" >
9951
- <widget class="QCheckBox" name="chkServerBrowse" >
9952
- <property name="text" >
9953
+ <item row="1" column="0" colspan="2">
9954
+ <widget class="QCheckBox" name="chkServerBrowse">
9955
+ <property name="text">
9956
<string>Show printers shared by other systems</string>
9960
- <item row="2" column="0" colspan="2" >
9961
- <widget class="QCheckBox" name="chkServerShare" >
9962
- <property name="text" >
9963
+ <item row="2" column="0" colspan="2">
9964
+ <widget class="QCheckBox" name="chkServerShare">
9965
+ <property name="text">
9966
<string>Share published printers connected to this system</string>
9970
- <item row="3" column="0" >
9971
+ <item row="3" column="0">
9973
- <property name="orientation" >
9974
+ <property name="orientation">
9975
<enum>Qt::Horizontal</enum>
9977
- <property name="sizeType" >
9978
+ <property name="sizeType">
9979
<enum>QSizePolicy::Fixed</enum>
9981
- <property name="sizeHint" stdset="0" >
9982
+ <property name="sizeHint" stdset="0">
9986
@@ -181,46 +232,46 @@
9990
- <item row="3" column="1" >
9991
- <widget class="QCheckBox" name="chkServerShareAny" >
9992
- <property name="sizePolicy" >
9993
- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
9994
+ <item row="3" column="1">
9995
+ <widget class="QCheckBox" name="chkServerShareAny">
9996
+ <property name="sizePolicy">
9997
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
9998
<horstretch>0</horstretch>
9999
<verstretch>0</verstretch>
10002
- <property name="text" >
10003
+ <property name="text">
10004
<string>Allow printing from the internet</string>
10008
- <item row="4" column="0" colspan="2" >
10009
- <widget class="QCheckBox" name="chkServerRemoteAdmin" >
10010
- <property name="text" >
10011
+ <item row="4" column="0" colspan="2">
10012
+ <widget class="QCheckBox" name="chkServerRemoteAdmin">
10013
+ <property name="text">
10014
<string>Allow remote administration</string>
10018
- <item row="5" column="0" colspan="2" >
10019
- <widget class="QCheckBox" name="chkServerAllowCancelAll" >
10020
- <property name="text" >
10021
+ <item row="5" column="0" colspan="2">
10022
+ <widget class="QCheckBox" name="chkServerAllowCancelAll">
10023
+ <property name="text">
10024
<string>Allow users to cancel any job (not just their own)</string>
10028
- <item row="6" column="0" colspan="2" >
10029
- <widget class="QCheckBox" name="chkServerLogDebug" >
10030
- <property name="text" >
10031
+ <item row="6" column="0" colspan="2">
10032
+ <widget class="QCheckBox" name="chkServerLogDebug">
10033
+ <property name="text">
10034
<string>Save debugging information for troubleshooting</string>
10038
- <item row="7" column="1" >
10039
+ <item row="7" column="1">
10041
- <property name="orientation" >
10042
+ <property name="orientation">
10043
<enum>Qt::Vertical</enum>
10045
- <property name="sizeHint" stdset="0" >
10046
+ <property name="sizeHint" stdset="0">
10049
<height>131</height>
10050
@@ -230,325 +281,1503 @@
10054
- <widget class="QWidget" name="page_2" >
10055
- <layout class="QGridLayout" >
10056
- <item row="0" column="0" >
10057
- <widget class="QTabWidget" name="tabWidget" >
10058
- <property name="sizePolicy" >
10059
- <sizepolicy vsizetype="Expanding" hsizetype="Minimum" >
10060
- <horstretch>1</horstretch>
10061
- <verstretch>0</verstretch>
10064
- <property name="currentIndex" >
10065
- <number>0</number>
10067
- <widget class="QWidget" name="settings" >
10068
- <attribute name="title" >
10069
- <string>Settings</string>
10071
- <layout class="QGridLayout" name="gridLayout_2" >
10072
- <item row="0" column="0" >
10073
- <widget class="QLabel" name="lblPDescription" >
10074
- <property name="text" >
10075
- <string>Description:</string>
10079
- <item row="0" column="1" colspan="5" >
10080
- <widget class="QLineEdit" name="entPDescription" />
10082
- <item row="1" column="0" >
10083
- <widget class="QLabel" name="lblPLocation" >
10084
- <property name="text" >
10085
- <string>Location:</string>
10089
- <item row="1" column="1" colspan="5" >
10090
- <widget class="QLineEdit" name="entPLocation" />
10092
- <item row="2" column="0" >
10093
- <widget class="QLabel" name="lblPDevice2" >
10094
- <property name="text" >
10095
- <string>Device URI:</string>
10099
- <item row="2" column="1" colspan="4" >
10100
- <widget class="QLineEdit" name="entPDevice" />
10102
- <item row="2" column="5" >
10103
- <widget class="QPushButton" name="btnSelectDevice" >
10104
- <property name="text" >
10105
- <string>Change</string>
10109
- <item row="3" column="0" colspan="2" >
10110
- <widget class="QLabel" name="lblPMakeModel2" >
10111
- <property name="text" >
10112
- <string>Make and Model:</string>
10116
- <item row="3" column="2" colspan="3" >
10117
- <widget class="QLabel" name="lblPMakeModel" >
10118
- <property name="text" >
10119
- <string>-</string>
10121
- <property name="wordWrap" >
10122
- <bool>true</bool>
10126
- <item row="3" column="5" >
10127
- <widget class="QPushButton" name="btnChangePPD" >
10128
- <property name="text" >
10129
- <string>Change</string>
10133
- <item row="4" column="0" colspan="2" >
10134
- <widget class="QLabel" name="lblPState2" >
10135
- <property name="text" >
10136
- <string>Printer State:</string>
10140
- <item row="4" column="2" colspan="4" >
10141
- <widget class="QLabel" name="lblPState" >
10142
- <property name="text" >
10143
- <string>-</string>
10147
- <item row="5" column="0" colspan="2" >
10148
- <widget class="QLabel" name="label_12" >
10149
- <property name="text" >
10150
- <string>Default Printer:</string>
10154
- <item row="5" column="2" colspan="3" >
10155
- <widget class="QLabel" name="lblPDefault" >
10156
- <property name="text" >
10157
- <string>-</string>
10161
- <item row="5" column="5" >
10162
- <widget class="QPushButton" name="btnPMakeDefault" >
10163
- <property name="text" >
10164
- <string>Make Default</string>
10168
- <item row="6" column="0" colspan="2" >
10169
- <widget class="QPushButton" name="btnDelete" >
10170
- <property name="text" >
10171
- <string>Remove Printer</string>
10172
+ <widget class="QWidget" name="page_2">
10173
+ <layout class="QGridLayout" name="gridLayout_3">
10174
+ <item row="0" column="0">
10175
+ <layout class="QVBoxLayout" name="verticalLayout">
10177
+ <layout class="QHBoxLayout" name="horizontalLayout">
10179
+ <widget class="QLabel" name="printerNameLabel">
10180
+ <property name="font">
10182
+ <weight>75</weight>
10183
+ <bold>true</bold>
10186
+ <property name="text">
10187
+ <string>My Printer</string>
10191
- <item row="6" column="2" colspan="4" >
10192
- <spacer name="horizontalSpacer" >
10193
- <property name="orientation" >
10195
+ <spacer name="horizontalSpacer_2">
10196
+ <property name="orientation">
10197
<enum>Qt::Horizontal</enum>
10199
- <property name="sizeHint" stdset="0" >
10200
+ <property name="sizeHint" stdset="0">
10202
- <width>432</width>
10203
+ <width>468</width>
10204
<height>20</height>
10209
- <item row="7" column="0" colspan="6" >
10210
- <spacer name="verticalSpacer" >
10211
- <property name="orientation" >
10212
- <enum>Qt::Vertical</enum>
10214
- <property name="sizeHint" stdset="0" >
10216
- <width>548</width>
10217
- <height>84</height>
10222
- <item row="8" column="0" colspan="3" >
10223
- <widget class="QPushButton" name="btnPrintTestPage" >
10224
- <property name="text" >
10225
- <string>Print Test Page</string>
10229
- <item row="8" column="3" >
10230
- <widget class="QPushButton" name="btnSelfTest" >
10231
- <property name="text" >
10232
- <string>Print Self-Test Page</string>
10236
- <item row="8" column="4" colspan="2" >
10237
- <widget class="QPushButton" name="btnCleanHeads" >
10238
- <property name="text" >
10239
- <string>Clean Print Heads</string>
10245
- <widget class="QWidget" name="policies" >
10246
- <attribute name="title" >
10247
- <string>Policies</string>
10249
- <layout class="QGridLayout" >
10250
- <item row="0" column="0" >
10251
- <widget class="QCheckBox" name="chkPEnabled" >
10252
- <property name="text" >
10253
- <string comment="Printer policy">Enabled</string>
10257
- <item rowspan="3" row="0" column="1" >
10258
- <widget class="QLabel" name="lblNotPublished" >
10259
- <property name="sizePolicy" >
10260
- <sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
10261
- <horstretch>0</horstretch>
10262
- <verstretch>0</verstretch>
10265
- <property name="text" >
10266
- <string comment="Printer policy">Not published
10267
-See server settings</string>
10271
- <item row="1" column="0" >
10272
- <widget class="QCheckBox" name="chkPAccepting" >
10273
- <property name="text" >
10274
- <string comment="Printer policy">Accepting Jobs</string>
10278
- <item row="2" column="0" >
10279
- <widget class="QCheckBox" name="chkPShared" >
10280
- <property name="text" >
10281
- <string comment="Printer policy">Shared</string>
10285
- <item row="3" column="0" >
10286
- <widget class="QLabel" name="label_8" >
10287
- <property name="sizePolicy" >
10288
- <sizepolicy vsizetype="Minimum" hsizetype="Minimum" >
10289
- <horstretch>0</horstretch>
10290
- <verstretch>0</verstretch>
10293
- <property name="text" >
10294
- <string>Error Policy</string>
10298
- <item row="3" column="1" >
10299
- <widget class="QComboBox" name="cmbPErrorPolicy" />
10301
- <item row="4" column="0" >
10302
- <widget class="QLabel" name="label_9" >
10303
- <property name="sizePolicy" >
10304
- <sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
10305
- <horstretch>0</horstretch>
10306
- <verstretch>0</verstretch>
10309
- <property name="text" >
10310
- <string>Operation Policy</string>
10314
- <item row="4" column="1" >
10315
- <widget class="QComboBox" name="cmbPOperationPolicy" />
10317
- <item row="5" column="0" >
10318
- <widget class="QLabel" name="label_10" >
10319
- <property name="sizePolicy" >
10320
- <sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
10321
- <horstretch>0</horstretch>
10322
- <verstretch>0</verstretch>
10325
- <property name="text" >
10326
- <string>Starting Banner</string>
10330
- <item row="5" column="1" >
10331
- <widget class="QComboBox" name="cmbPStartBanner" />
10333
- <item row="6" column="0" >
10334
- <widget class="QLabel" name="label_11" >
10335
- <property name="sizePolicy" >
10336
- <sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
10337
- <horstretch>0</horstretch>
10338
- <verstretch>0</verstretch>
10341
- <property name="text" >
10342
- <string>Ending Banner</string>
10346
- <item row="6" column="1" >
10347
- <widget class="QComboBox" name="cmbPEndBanner" />
10349
- <item row="7" column="0" colspan="2" >
10351
- <property name="orientation" >
10352
- <enum>Qt::Vertical</enum>
10354
- <property name="sizeHint" stdset="0" >
10356
- <width>521</width>
10357
- <height>20</height>
10367
+ <widget class="QTabWidget" name="ntbkPrinter">
10368
+ <property name="sizePolicy">
10369
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
10370
+ <horstretch>0</horstretch>
10371
+ <verstretch>0</verstretch>
10374
+ <property name="currentIndex">
10375
+ <number>0</number>
10377
+ <widget class="QWidget" name="settings">
10378
+ <attribute name="title">
10379
+ <string>Settings</string>
10381
+ <layout class="QVBoxLayout" name="verticalLayout_5">
10383
+ <widget class="QLabel" name="label_3">
10384
+ <property name="font">
10386
+ <weight>75</weight>
10387
+ <bold>true</bold>
10390
+ <property name="text">
10391
+ <string>Printer Description</string>
10396
+ <layout class="QGridLayout" name="gridLayout_8">
10397
+ <item row="0" column="0">
10398
+ <widget class="QLabel" name="lblPName">
10399
+ <property name="text">
10400
+ <string>Printer Name:</string>
10402
+ <property name="alignment">
10403
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
10407
+ <item row="0" column="1">
10408
+ <widget class="KLineEdit" name="entPName"/>
10410
+ <item row="1" column="0">
10411
+ <widget class="QLabel" name="lblPLocation">
10412
+ <property name="text">
10413
+ <string>Location:</string>
10415
+ <property name="alignment">
10416
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
10420
+ <item row="1" column="1">
10421
+ <widget class="KLineEdit" name="entPLocation"/>
10423
+ <item row="2" column="0">
10424
+ <widget class="QLabel" name="lblPDescription">
10425
+ <property name="text">
10426
+ <string>Printer Description:</string>
10428
+ <property name="alignment">
10429
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
10433
+ <item row="2" column="1">
10434
+ <widget class="KLineEdit" name="entPDescription"/>
10436
+ <item row="3" column="0">
10437
+ <widget class="QLabel" name="lblPDevice2">
10438
+ <property name="text">
10439
+ <string>Device Uri:</string>
10441
+ <property name="alignment">
10442
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
10446
+ <item row="3" column="1">
10447
+ <widget class="KLineEdit" name="entPDevice"/>
10452
+ <widget class="QCheckBox" name="chkPMakeDefault">
10453
+ <property name="enabled">
10454
+ <bool>true</bool>
10456
+ <property name="text">
10457
+ <string>Make Default (Current Default is Foo at Bar)</string>
10462
+ <widget class="Line" name="line">
10463
+ <property name="orientation">
10464
+ <enum>Qt::Horizontal</enum>
10469
+ <widget class="QLabel" name="label_7">
10470
+ <property name="font">
10472
+ <weight>75</weight>
10473
+ <bold>true</bold>
10476
+ <property name="text">
10477
+ <string>Driver Details</string>
10482
+ <layout class="QGridLayout" name="gridLayout_16">
10483
+ <item row="0" column="0">
10484
+ <widget class="QLabel" name="lblPMakeModel2">
10485
+ <property name="sizePolicy">
10486
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
10487
+ <horstretch>0</horstretch>
10488
+ <verstretch>0</verstretch>
10491
+ <property name="text">
10492
+ <string>Printer Model:</string>
10494
+ <property name="alignment">
10495
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
10499
+ <item row="0" column="1">
10500
+ <widget class="QLabel" name="lblPMakeModel">
10501
+ <property name="sizePolicy">
10502
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
10503
+ <horstretch>0</horstretch>
10504
+ <verstretch>0</verstretch>
10507
+ <property name="text">
10508
+ <string>-</string>
10510
+ <property name="wordWrap">
10511
+ <bool>true</bool>
10515
+ <item row="0" column="2">
10516
+ <widget class="KPushButton" name="btnChangePPD">
10517
+ <property name="text">
10518
+ <string>Change...</string>
10522
+ <item row="1" column="0">
10523
+ <widget class="QLabel" name="lblPType2">
10524
+ <property name="sizePolicy">
10525
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
10526
+ <horstretch>0</horstretch>
10527
+ <verstretch>0</verstretch>
10530
+ <property name="text">
10531
+ <string>Printer State:</string>
10533
+ <property name="alignment">
10534
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
10538
+ <item row="1" column="1" colspan="2">
10539
+ <widget class="QLabel" name="lblPState">
10540
+ <property name="sizePolicy">
10541
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
10542
+ <horstretch>0</horstretch>
10543
+ <verstretch>0</verstretch>
10546
+ <property name="text">
10547
+ <string>-</string>
10554
+ <widget class="Line" name="line_2">
10555
+ <property name="orientation">
10556
+ <enum>Qt::Horizontal</enum>
10561
+ <widget class="QLabel" name="label_12">
10562
+ <property name="font">
10564
+ <weight>75</weight>
10565
+ <bold>true</bold>
10568
+ <property name="text">
10569
+ <string>Printer Status</string>
10574
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
10576
+ <widget class="QCheckBox" name="chkPEnabled">
10577
+ <property name="text">
10578
+ <string>enable</string>
10583
+ <widget class="QCheckBox" name="chkPAccepting">
10584
+ <property name="text">
10585
+ <string>accepting</string>
10590
+ <widget class="QCheckBox" name="chkPShared">
10591
+ <property name="text">
10592
+ <string>sharing</string>
10597
+ <widget class="QLabel" name="lblNotPublished">
10598
+ <property name="text">
10599
+ <string>TextLabel</string>
10604
+ <spacer name="horizontalSpacer_10">
10605
+ <property name="orientation">
10606
+ <enum>Qt::Horizontal</enum>
10608
+ <property name="sizeHint" stdset="0">
10610
+ <width>40</width>
10611
+ <height>20</height>
10619
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
10621
+ <widget class="KPushButton" name="btnPrintTestPage">
10622
+ <property name="text">
10623
+ <string>Print Test Page</string>
10628
+ <widget class="KPushButton" name="btnSelfTest">
10629
+ <property name="text">
10630
+ <string>Print Self Test</string>
10635
+ <widget class="KPushButton" name="btnCleanHeads">
10636
+ <property name="text">
10637
+ <string>Clean Print Heads</string>
10642
+ <spacer name="horizontalSpacer_5">
10643
+ <property name="orientation">
10644
+ <enum>Qt::Horizontal</enum>
10646
+ <property name="sizeHint" stdset="0">
10648
+ <width>99</width>
10649
+ <height>17</height>
10657
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
10659
+ <widget class="KPushButton" name="btnDelete">
10660
+ <property name="text">
10661
+ <string>Remove Printer</string>
10666
+ <spacer name="horizontalSpacer_6">
10667
+ <property name="orientation">
10668
+ <enum>Qt::Horizontal</enum>
10670
+ <property name="sizeHint" stdset="0">
10672
+ <width>371</width>
10673
+ <height>17</height>
10682
+ <widget class="QWidget" name="policies">
10683
+ <attribute name="title">
10684
+ <string>Policies</string>
10686
+ <layout class="QVBoxLayout" name="verticalLayout_6">
10688
+ <widget class="QLabel" name="label_8">
10689
+ <property name="font">
10691
+ <weight>75</weight>
10692
+ <bold>true</bold>
10695
+ <property name="text">
10696
+ <string>Banner Settings</string>
10701
+ <layout class="QGridLayout" name="gridLayout_7">
10702
+ <item row="0" column="0">
10703
+ <widget class="QLabel" name="label_10">
10704
+ <property name="sizePolicy">
10705
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
10706
+ <horstretch>0</horstretch>
10707
+ <verstretch>0</verstretch>
10710
+ <property name="text">
10711
+ <string>Starting Banner:</string>
10713
+ <property name="alignment">
10714
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
10718
+ <item row="0" column="1">
10719
+ <widget class="KComboBox" name="cmbPStartBanner"/>
10721
+ <item row="0" column="2">
10722
+ <spacer name="horizontalSpacer">
10723
+ <property name="orientation">
10724
+ <enum>Qt::Horizontal</enum>
10726
+ <property name="sizeHint" stdset="0">
10728
+ <width>314</width>
10729
+ <height>13</height>
10734
+ <item row="1" column="0">
10735
+ <widget class="QLabel" name="label_11">
10736
+ <property name="sizePolicy">
10737
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
10738
+ <horstretch>0</horstretch>
10739
+ <verstretch>0</verstretch>
10742
+ <property name="text">
10743
+ <string>Ending Banner:</string>
10745
+ <property name="alignment">
10746
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
10750
+ <item row="1" column="1">
10751
+ <widget class="KComboBox" name="cmbPEndBanner"/>
10753
+ <item row="1" column="2">
10754
+ <spacer name="horizontalSpacer_3">
10755
+ <property name="orientation">
10756
+ <enum>Qt::Horizontal</enum>
10758
+ <property name="sizeHint" stdset="0">
10760
+ <width>314</width>
10761
+ <height>13</height>
10769
+ <widget class="Line" name="line_3">
10770
+ <property name="orientation">
10771
+ <enum>Qt::Horizontal</enum>
10776
+ <widget class="QLabel" name="label_9">
10777
+ <property name="font">
10779
+ <weight>75</weight>
10780
+ <bold>true</bold>
10783
+ <property name="text">
10784
+ <string>User and Group Permissions</string>
10789
+ <widget class="QRadioButton" name="rbtnPAllow">
10790
+ <property name="text">
10791
+ <string>Allow printing for everyone except these users.</string>
10796
+ <widget class="QRadioButton" name="rbtnPDeny">
10797
+ <property name="text">
10798
+ <string>Deny printing for everyone except these users</string>
10803
+ <widget class="QTreeWidget" name="tvPUsers">
10804
+ <property name="rootIsDecorated">
10805
+ <bool>false</bool>
10807
+ <property name="headerHidden">
10808
+ <bool>true</bool>
10811
+ <property name="text">
10812
+ <string>1</string>
10818
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
10820
+ <widget class="KPushButton" name="btnPAddUser">
10821
+ <property name="text">
10822
+ <string>Add</string>
10827
+ <widget class="KPushButton" name="btnPDelUser">
10828
+ <property name="text">
10829
+ <string>Remove</string>
10834
+ <spacer name="horizontalSpacer_4">
10835
+ <property name="orientation">
10836
+ <enum>Qt::Horizontal</enum>
10838
+ <property name="sizeHint" stdset="0">
10840
+ <width>354</width>
10841
+ <height>20</height>
10850
+ <widget class="QWidget" name="tab_3">
10851
+ <attribute name="title">
10852
+ <string>Members</string>
10854
+ <layout class="QGridLayout" name="gridLayout_15">
10855
+ <item row="0" column="0" colspan="3">
10856
+ <widget class="QLabel" name="label_47">
10857
+ <property name="text">
10858
+ <string>Add or Remove Members</string>
10862
+ <item row="1" column="0" rowspan="4">
10863
+ <widget class="QListWidget" name="tvClassMembers"/>
10865
+ <item row="1" column="1">
10866
+ <spacer name="verticalSpacer_2">
10867
+ <property name="orientation">
10868
+ <enum>Qt::Vertical</enum>
10870
+ <property name="sizeHint" stdset="0">
10872
+ <width>20</width>
10873
+ <height>125</height>
10878
+ <item row="1" column="2" rowspan="4">
10879
+ <widget class="QListWidget" name="tvClassNotMembers"/>
10881
+ <item row="2" column="1">
10882
+ <widget class="QPushButton" name="btnClassAddMember">
10883
+ <property name="text">
10888
+ <item row="3" column="1">
10889
+ <widget class="QPushButton" name="btnClassDelMember">
10890
+ <property name="text">
10895
+ <item row="4" column="1">
10896
+ <spacer name="verticalSpacer_3">
10897
+ <property name="orientation">
10898
+ <enum>Qt::Vertical</enum>
10900
+ <property name="sizeHint" stdset="0">
10902
+ <width>20</width>
10903
+ <height>358</height>
10910
+ <widget class="QWidget" name="tab_2">
10911
+ <attribute name="title">
10912
+ <string>Options</string>
10914
+ <layout class="QVBoxLayout" name="verticalLayout_3">
10916
+ <widget class="QWidget" name="optionsPageWidget" native="true">
10917
+ <layout class="QGridLayout" name="gridLayout_5">
10918
+ <item row="0" column="0">
10919
+ <layout class="QVBoxLayout" name="vbPOptions"/>
10925
+ <spacer name="verticalSpacer">
10926
+ <property name="orientation">
10927
+ <enum>Qt::Vertical</enum>
10929
+ <property name="sizeHint" stdset="0">
10931
+ <width>20</width>
10932
+ <height>531</height>
10939
+ <widget class="QWidget" name="joboptions">
10940
+ <attribute name="title">
10941
+ <string>Job Options</string>
10943
+ <layout class="QGridLayout" name="gridLayout_9">
10944
+ <item row="0" column="0">
10945
+ <widget class="QScrollArea" name="scrollArea">
10946
+ <property name="verticalScrollBarPolicy">
10947
+ <enum>Qt::ScrollBarAlwaysOn</enum>
10949
+ <property name="widgetResizable">
10950
+ <bool>true</bool>
10952
+ <widget class="QWidget" name="scrollAreaWidgetContents">
10953
+ <property name="geometry">
10957
+ <width>509</width>
10958
+ <height>1026</height>
10961
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
10963
+ <widget class="QWidget" name="optionsPageWidget2" native="true">
10964
+ <layout class="QVBoxLayout" name="verticalLayout_2">
10966
+ <widget class="QLabel" name="label136">
10967
+ <property name="text">
10968
+ <string>Specify the default job options for this printer. Jobs
10969
+arriving at this print server will have these options added
10970
+if they are not already set by the application.</string>
10975
+ <widget class="QLabel" name="label_13">
10976
+ <property name="text">
10977
+ <string><b>Common Options</b></string>
10982
+ <layout class="QGridLayout" name="gridLayout_11">
10983
+ <item row="0" column="0">
10984
+ <widget class="QLabel" name="label_14">
10985
+ <property name="text">
10986
+ <string>Copies</string>
10990
+ <item row="0" column="1">
10991
+ <widget class="QSpinBox" name="sbJOCopies"/>
10993
+ <item row="0" column="2">
10994
+ <widget class="QPushButton" name="btnJOResetCopies">
10995
+ <property name="text">
10996
+ <string>Reset</string>
11000
+ <item row="1" column="0">
11001
+ <widget class="QLabel" name="label_15">
11002
+ <property name="text">
11003
+ <string>Orientation</string>
11007
+ <item row="1" column="1">
11008
+ <widget class="QComboBox" name="cmbJOOrientationRequested">
11010
+ <property name="text">
11011
+ <string>Portrait (no rotation)</string>
11015
+ <property name="text">
11016
+ <string>Landscape (90°)</string>
11020
+ <property name="text">
11021
+ <string>Reverse landscape (270°)</string>
11025
+ <property name="text">
11026
+ <string>Reverse portrait (180°)</string>
11031
+ <item row="1" column="2">
11032
+ <widget class="QPushButton" name="btnJOResetOrientationRequested">
11033
+ <property name="text">
11034
+ <string>Reset</string>
11038
+ <item row="2" column="0" colspan="2">
11039
+ <widget class="QCheckBox" name="cbJOFitplot">
11040
+ <property name="text">
11041
+ <string>Scale to fit</string>
11045
+ <item row="2" column="2">
11046
+ <widget class="QPushButton" name="btnJOResetFitplot">
11047
+ <property name="text">
11048
+ <string>Reset</string>
11052
+ <item row="3" column="0">
11053
+ <widget class="QLabel" name="label_17">
11054
+ <property name="text">
11055
+ <string>Pages per slide</string>
11059
+ <item row="3" column="1">
11060
+ <widget class="QComboBox" name="cmbJONumberUp">
11062
+ <property name="text">
11063
+ <string>1</string>
11067
+ <property name="text">
11068
+ <string>2</string>
11072
+ <property name="text">
11073
+ <string>4</string>
11077
+ <property name="text">
11078
+ <string>6</string>
11082
+ <property name="text">
11083
+ <string>9</string>
11087
+ <property name="text">
11088
+ <string>16</string>
11093
+ <item row="3" column="2">
11094
+ <widget class="QPushButton" name="btnJOResetNumberUp">
11095
+ <property name="text">
11096
+ <string>Reset</string>
11100
+ <item row="4" column="0" colspan="2">
11101
+ <layout class="QGridLayout" name="gridLayout_2">
11102
+ <item row="0" column="0">
11103
+ <widget class="QLabel" name="label_37">
11104
+ <property name="text">
11105
+ <string>Pages per side layout:</string>
11109
+ <item row="0" column="1" colspan="2">
11110
+ <widget class="QComboBox" name="cmbJONumberUpLayout">
11112
+ <property name="text">
11113
+ <string>Left to right, top to bottom</string>
11117
+ <property name="text">
11118
+ <string>Left to right, bottom to top</string>
11122
+ <property name="text">
11123
+ <string>Right to left, top to bottom</string>
11128
+ <item row="0" column="3">
11129
+ <widget class="QPushButton" name="btnJOResetNumberUpLayout">
11130
+ <property name="text">
11131
+ <string>Reset</string>
11135
+ <item row="1" column="0">
11136
+ <widget class="QLabel" name="label_38">
11137
+ <property name="text">
11138
+ <string>Brightness:</string>
11142
+ <item row="1" column="1">
11143
+ <widget class="QSpinBox" name="sbJOBrightness"/>
11145
+ <item row="1" column="2">
11146
+ <widget class="QLabel" name="label_44">
11147
+ <property name="text">
11148
+ <string>%</string>
11152
+ <item row="1" column="3">
11153
+ <widget class="QPushButton" name="btnJOResetBrightness">
11154
+ <property name="text">
11155
+ <string>Reset</string>
11159
+ <item row="2" column="0">
11160
+ <widget class="QLabel" name="label_39">
11161
+ <property name="text">
11162
+ <string>Finishings:</string>
11166
+ <item row="2" column="1" colspan="2">
11167
+ <widget class="QComboBox" name="cmbJOFinishings">
11169
+ <property name="text">
11170
+ <string>None</string>
11174
+ <property name="text">
11175
+ <string>Staple</string>
11179
+ <property name="text">
11180
+ <string>Punch</string>
11184
+ <property name="text">
11185
+ <string>Cover</string>
11189
+ <property name="text">
11190
+ <string>Bind</string>
11194
+ <property name="text">
11195
+ <string>Saddle stitch</string>
11199
+ <property name="text">
11200
+ <string>Edge stitch</string>
11204
+ <property name="text">
11205
+ <string>Fold</string>
11209
+ <property name="text">
11210
+ <string>Trim</string>
11214
+ <property name="text">
11215
+ <string>Bale</string>
11219
+ <property name="text">
11220
+ <string>Booklet maker</string>
11224
+ <property name="text">
11225
+ <string>Job offset</string>
11229
+ <property name="text">
11230
+ <string>Staple (top left)</string>
11234
+ <property name="text">
11235
+ <string>Staple (bottom left)</string>
11239
+ <property name="text">
11240
+ <string>Staple (top right)</string>
11244
+ <property name="text">
11245
+ <string>Staple (bottom right)</string>
11249
+ <property name="text">
11250
+ <string>Edge stitch (left)</string>
11254
+ <property name="text">
11255
+ <string>Edge stitch (top)</string>
11259
+ <property name="text">
11260
+ <string>Edge stitch (right)</string>
11264
+ <property name="text">
11265
+ <string>Edge stitch (bottom)</string>
11269
+ <property name="text">
11270
+ <string>Staple dual (left)</string>
11274
+ <property name="text">
11275
+ <string>Staple dual (top)</string>
11279
+ <property name="text">
11280
+ <string>Staple dual (right)</string>
11284
+ <property name="text">
11285
+ <string>Staple dual (bottom)</string>
11289
+ <property name="text">
11290
+ <string>Bind (left)</string>
11294
+ <property name="text">
11295
+ <string>Bind (top)</string>
11299
+ <property name="text">
11300
+ <string>Bind (right)</string>
11304
+ <property name="text">
11305
+ <string>Bind (bottom)</string>
11310
+ <item row="2" column="3">
11311
+ <widget class="QPushButton" name="btnJOResetFinishings">
11312
+ <property name="text">
11313
+ <string>Reset</string>
11317
+ <item row="3" column="0">
11318
+ <widget class="QLabel" name="label_42">
11319
+ <property name="text">
11320
+ <string>Job priority:</string>
11324
+ <item row="3" column="1" colspan="2">
11325
+ <widget class="QSpinBox" name="sbJOJobPriority"/>
11327
+ <item row="3" column="3">
11328
+ <widget class="QPushButton" name="btnJOResetJobPriority">
11329
+ <property name="text">
11330
+ <string>Reset</string>
11334
+ <item row="4" column="0">
11335
+ <widget class="QLabel" name="label_40">
11336
+ <property name="text">
11337
+ <string>Media:</string>
11341
+ <item row="4" column="1" colspan="2">
11342
+ <widget class="QComboBox" name="cmbJOMedia"/>
11344
+ <item row="4" column="3">
11345
+ <widget class="QPushButton" name="btnJOResetMedia">
11346
+ <property name="text">
11347
+ <string>Reset</string>
11351
+ <item row="5" column="0">
11352
+ <widget class="QLabel" name="label_41">
11353
+ <property name="text">
11354
+ <string>Sides:</string>
11358
+ <item row="5" column="1" colspan="2">
11359
+ <widget class="QComboBox" name="cmbJOSides">
11361
+ <property name="text">
11362
+ <string>One-sided</string>
11366
+ <property name="text">
11367
+ <string>Two-sided (long edge)</string>
11371
+ <property name="text">
11372
+ <string>Two-sided (short edge)</string>
11377
+ <item row="5" column="3">
11378
+ <widget class="QPushButton" name="btnJOResetSides">
11379
+ <property name="text">
11380
+ <string>Reset</string>
11384
+ <item row="6" column="0">
11385
+ <widget class="QLabel" name="label_43">
11386
+ <property name="text">
11387
+ <string>Hold until:</string>
11391
+ <item row="6" column="1" colspan="2">
11392
+ <widget class="QComboBox" name="cmbJOHoldUntil"/>
11394
+ <item row="6" column="3">
11395
+ <widget class="QPushButton" name="btnJOResetHoldUntil">
11396
+ <property name="text">
11397
+ <string>Reset</string>
11406
+ <widget class="QLabel" name="label_16">
11407
+ <property name="text">
11408
+ <string><b>Image Options</b></string>
11413
+ <layout class="QGridLayout" name="gridLayout_6">
11414
+ <item row="0" column="0" colspan="4">
11415
+ <widget class="QCheckBox" name="cbJOMirror">
11416
+ <property name="text">
11417
+ <string>Mirror</string>
11421
+ <item row="0" column="4">
11422
+ <widget class="QPushButton" name="btnJOResetMirror">
11423
+ <property name="text">
11424
+ <string>Reset</string>
11428
+ <item row="1" column="0">
11429
+ <widget class="QLabel" name="label_18">
11430
+ <property name="text">
11431
+ <string>Scaling</string>
11435
+ <item row="1" column="1">
11436
+ <widget class="QSpinBox" name="sbJOScaling"/>
11438
+ <item row="1" column="2">
11439
+ <widget class="QLabel" name="label_30">
11440
+ <property name="text">
11441
+ <string>%</string>
11445
+ <item row="1" column="3" colspan="2">
11446
+ <widget class="QPushButton" name="btnJOResetScaling">
11447
+ <property name="text">
11448
+ <string>Reset</string>
11452
+ <item row="2" column="0" colspan="3">
11453
+ <layout class="QGridLayout" name="gridLayout_13">
11454
+ <item row="0" column="0">
11455
+ <widget class="QLabel" name="label_31">
11456
+ <property name="text">
11457
+ <string>Saturation</string>
11461
+ <item row="0" column="1">
11462
+ <widget class="QSpinBox" name="sbJOSaturation"/>
11464
+ <item row="0" column="2">
11465
+ <widget class="QLabel" name="label_34">
11466
+ <property name="text">
11467
+ <string>%</string>
11471
+ <item row="0" column="3">
11472
+ <widget class="QPushButton" name="btnJOResetSaturation">
11473
+ <property name="text">
11474
+ <string>Reset</string>
11478
+ <item row="1" column="0">
11479
+ <widget class="QLabel" name="label_32">
11480
+ <property name="text">
11481
+ <string>Hue adjustment</string>
11485
+ <item row="1" column="1">
11486
+ <widget class="QSpinBox" name="sbJOHue"/>
11488
+ <item row="1" column="2">
11489
+ <widget class="QLabel" name="label_35">
11490
+ <property name="text">
11491
+ <string>°</string>
11495
+ <item row="1" column="3">
11496
+ <widget class="QPushButton" name="btnJOResetHue">
11497
+ <property name="text">
11498
+ <string>Reset</string>
11502
+ <item row="2" column="0">
11503
+ <widget class="QLabel" name="label_33">
11504
+ <property name="text">
11505
+ <string>Gamme</string>
11509
+ <item row="2" column="1">
11510
+ <widget class="QSpinBox" name="sbJOGamma"/>
11512
+ <item row="2" column="3">
11513
+ <widget class="QPushButton" name="btnJOResetGamma">
11514
+ <property name="text">
11515
+ <string>Reset</string>
11521
+ <item row="2" column="3" colspan="2">
11522
+ <spacer name="horizontalSpacer_7">
11523
+ <property name="orientation">
11524
+ <enum>Qt::Horizontal</enum>
11526
+ <property name="sizeHint" stdset="0">
11528
+ <width>97</width>
11529
+ <height>94</height>
11537
+ <widget class="QLabel" name="label_19">
11538
+ <property name="text">
11539
+ <string><b>Text Options</b></string>
11544
+ <layout class="QGridLayout" name="gridLayout_10">
11545
+ <item row="0" column="0">
11546
+ <widget class="QLabel" name="label_20">
11547
+ <property name="text">
11548
+ <string>Character per inch:</string>
11550
+ <property name="textFormat">
11551
+ <enum>Qt::PlainText</enum>
11555
+ <item row="0" column="1">
11556
+ <widget class="QSpinBox" name="sbJOCpi"/>
11558
+ <item row="0" column="3">
11559
+ <widget class="QPushButton" name="btnJOResetCpi">
11560
+ <property name="text">
11561
+ <string>Reset</string>
11565
+ <item row="1" column="0">
11566
+ <widget class="QLabel" name="label_21">
11567
+ <property name="text">
11568
+ <string>Lines per inch</string>
11572
+ <item row="1" column="1">
11573
+ <widget class="QSpinBox" name="sbJOLpi"/>
11575
+ <item row="1" column="3">
11576
+ <widget class="QPushButton" name="btnJOResetLpi">
11577
+ <property name="text">
11578
+ <string>Reset</string>
11582
+ <item row="2" column="0">
11583
+ <widget class="QLabel" name="label_22">
11584
+ <property name="text">
11585
+ <string>Left margin</string>
11589
+ <item row="2" column="1">
11590
+ <widget class="QSpinBox" name="sbJOPageLeft"/>
11592
+ <item row="2" column="2">
11593
+ <widget class="QLabel" name="label_26">
11594
+ <property name="text">
11595
+ <string>Points</string>
11599
+ <item row="2" column="3">
11600
+ <widget class="QPushButton" name="btnJOResetPageLeft">
11601
+ <property name="text">
11602
+ <string>Reset</string>
11606
+ <item row="3" column="0">
11607
+ <widget class="QLabel" name="label_23">
11608
+ <property name="text">
11609
+ <string>Right margin</string>
11613
+ <item row="3" column="1">
11614
+ <widget class="QSpinBox" name="sbJOPageRight"/>
11616
+ <item row="3" column="2">
11617
+ <widget class="QLabel" name="label_27">
11618
+ <property name="text">
11619
+ <string>Points</string>
11623
+ <item row="3" column="3">
11624
+ <widget class="QPushButton" name="btnJOResetPageRight">
11625
+ <property name="text">
11626
+ <string>Reset</string>
11630
+ <item row="4" column="0">
11631
+ <widget class="QLabel" name="label_24">
11632
+ <property name="text">
11633
+ <string>Top margin</string>
11637
+ <item row="4" column="1">
11638
+ <widget class="QSpinBox" name="sbJOPageTop"/>
11640
+ <item row="4" column="2">
11641
+ <widget class="QLabel" name="label_28">
11642
+ <property name="text">
11643
+ <string>Points</string>
11647
+ <item row="4" column="3">
11648
+ <widget class="QPushButton" name="btnJOResetPageTop">
11649
+ <property name="text">
11650
+ <string>Reset</string>
11654
+ <item row="5" column="0">
11655
+ <widget class="QLabel" name="label_25">
11656
+ <property name="text">
11657
+ <string>Bottom margin</string>
11661
+ <item row="5" column="1">
11662
+ <widget class="QSpinBox" name="sbJOPageBottom"/>
11664
+ <item row="5" column="2">
11665
+ <widget class="QLabel" name="label_29">
11666
+ <property name="text">
11667
+ <string>Points</string>
11671
+ <item row="5" column="3">
11672
+ <widget class="QPushButton" name="btnJOResetPageBottom">
11673
+ <property name="text">
11674
+ <string>Reset</string>
11678
+ <item row="6" column="0" colspan="2">
11679
+ <layout class="QGridLayout" name="gridLayout_14">
11680
+ <item row="0" column="0" colspan="2">
11681
+ <widget class="QCheckBox" name="cbJOPrettyPrint">
11682
+ <property name="text">
11683
+ <string>Pretty print</string>
11687
+ <item row="0" column="2">
11688
+ <widget class="QPushButton" name="btnJOResetPrettyPrint">
11689
+ <property name="text">
11690
+ <string>Reset</string>
11694
+ <item row="1" column="0" colspan="2">
11695
+ <widget class="QCheckBox" name="cbJOWrap">
11696
+ <property name="text">
11697
+ <string>Word wrap</string>
11701
+ <item row="1" column="2">
11702
+ <widget class="QPushButton" name="btnJOResetWrap">
11703
+ <property name="text">
11704
+ <string>Reset</string>
11708
+ <item row="2" column="0">
11709
+ <widget class="QLabel" name="label_36">
11710
+ <property name="text">
11711
+ <string>Columns</string>
11715
+ <item row="2" column="1">
11716
+ <widget class="QSpinBox" name="sbJOColumns"/>
11718
+ <item row="2" column="2">
11719
+ <widget class="QPushButton" name="btnJOResetColumns">
11720
+ <property name="text">
11721
+ <string>Reset</string>
11730
+ <widget class="QLabel" name="label_45">
11731
+ <property name="text">
11737
+ <widget class="QWidget" name="tblJOOtherWidget" native="true">
11738
+ <layout class="QGridLayout" name="gridLayout_12">
11739
+ <item row="0" column="0">
11740
+ <layout class="QGridLayout" name="tblJOOther"/>
11746
+ <widget class="QLabel" name="label_46">
11747
+ <property name="text">
11748
+ <string>To add a new option, enter its name in the box below and click to add.</string>
11753
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
11755
+ <widget class="QLineEdit" name="entNewJobOption"/>
11758
+ <widget class="QPushButton" name="btnNewJobOption">
11759
+ <property name="text">
11760
+ <string>Add</string>
11765
+ <spacer name="horizontalSpacer_9">
11766
+ <property name="orientation">
11767
+ <enum>Qt::Horizontal</enum>
11769
+ <property name="sizeHint" stdset="0">
11771
+ <width>40</width>
11772
+ <height>20</height>
11783
+ <spacer name="horizontalSpacer_8">
11784
+ <property name="orientation">
11785
+ <enum>Qt::Horizontal</enum>
11787
+ <property name="sizeHint" stdset="0">
11789
+ <width>119</width>
11790
+ <height>1018</height>
11807
- <widget class="QWidget" name="page_4" />
11810
- <item row="1" column="1" >
11811
- <widget class="QPushButton" name="btnConflict" >
11812
- <property name="text" >
11817
- <item row="1" column="2" >
11818
- <widget class="QPushButton" name="btnPrinterPropertiesApply" >
11819
- <property name="text" >
11820
- <string>Apply</string>
11824
- <item row="1" column="3" >
11825
- <widget class="QPushButton" name="btnRevert" >
11826
- <property name="text" >
11827
- <string>Revert</string>
11829
+ <widget class="QWidget" name="page_4"/>
11836
+ <class>KComboBox</class>
11837
+ <extends>QComboBox</extends>
11838
+ <header>kcombobox.h</header>
11841
+ <class>KLineEdit</class>
11842
+ <extends>QLineEdit</extends>
11843
+ <header>klineedit.h</header>
11846
+ <class>KPushButton</class>
11847
+ <extends>QPushButton</extends>
11848
+ <header>kpushbutton.h</header>