1 # -*- coding: utf-8 -*-
3 # (c) Copyright 2001-2009 Hewlett-Packard Development Company, L.P.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 from base import device, utils
27 from base.codes import *
28 from ui_utils import *
29 from installer.core_install import CoreInstall
30 from installer.core_install import PLUGIN_INSTALL_ERROR_NONE, \
31 PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, \
32 PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, \
33 PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD, \
34 PLUGIN_INSTALL_ERROR_PLUGIN_FILE_CHECKSUM_ERROR, \
35 PLUGIN_INSTALL_ERROR_NO_NETWORK, \
36 PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR, \
37 PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS
40 from PyQt4.QtCore import *
41 from PyQt4.QtGui import *
44 from plugindialog_base import Ui_Dialog
48 # PAGE_LICENSE = 1 # part of plug-in itself, this is a placeholder
53 class PluginDialog(QDialog, Ui_Dialog):
54 def __init__(self, parent, install_mode=PLUGIN_NONE, plugin_reason=PLUGIN_REASON_NONE):
55 QDialog.__init__(self, parent)
56 self.install_mode = install_mode
57 self.plugin_reason = plugin_reason
58 self.plugin_path = None
60 self.core = CoreInstall()
61 self.core.set_plugin_version()
64 self.user_settings = UserSettings()
65 self.user_settings.load()
66 self.user_settings.debug()
70 QTimer.singleShot(0, self.showSourcePage)
73 def isPluginInstalled(self):
74 return self.core.check_for_plugin()
78 # connect signals/slots
79 self.connect(self.CancelButton, SIGNAL("clicked()"), self.CancelButton_clicked)
80 self.connect(self.NextButton, SIGNAL("clicked()"), self.NextButton_clicked)
83 self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
85 self.PLUGIN_REASON_TEXT = {
86 PLUGIN_REASON_NONE: None,
87 PLUGIN_REASON_PRINTING_SUPPORT: self.__tr("This plugin will enable printing support."),
88 PLUGIN_REASON_FASTER_PRINTING: self.__tr("This plugin will enhance print speed."),
89 PLUGIN_REASON_BETTER_PRINTING_PQ: self.__tr("This plugin will enhance print quality."),
90 PLUGIN_REASON_PRINTING_FEATURES: self.__tr("This plugin will add printing features."),
91 PLUGIN_REASON_RESERVED_10: None,
92 PLUGIN_REASON_RESERVED_20: None,
93 PLUGIN_REASON_SCANNING_SUPPORT: self.__tr("This plugin will enable scanning support."),
94 PLUGIN_REASON_FASTER_SCANNING: self.__tr("This plugin will enhance scanning speed."),
95 PLUGIN_REASON_BETTER_SCANNING_IQ: self.__tr("This plugin will enhance scanning image quality."),
96 PLUGIN_REASON_RESERVED_200: None,
97 PLUGIN_REASON_RESERVED_400: None,
98 PLUGIN_REASON_FAXING_SUPPORT: self.__tr("This plugin will enable faxing support."),
99 PLUGIN_REASON_FAX_FEATURES: self.__tr("This plugin will enhnace faxing features."),
100 PLUGIN_REASON_RESERVED_20000: None,
101 PLUGIN_REASON_RESERVED_40000: None,
107 def showSourcePage(self):
108 reason_text = self.plugin_reason_text()
110 if reason_text is not None:
111 if self.install_mode == PLUGIN_REQUIRED:
112 self.TitleLabel.setText(self.__tr("An additional driver plug-in is required to operate this printer. You may download the plug-in directly from an HP authorized server (recommended), or, if you already have a copy of the file, you can specify a path to the file (advanced). <br><br>%1").arg(reason_text))
113 self.SkipRadioButton.setEnabled(False)
115 elif self.install_mode == PLUGIN_OPTIONAL:
116 self.TitleLabel.setText(self.__tr("An optional driver plug-in is available to enhance the operation of this printer. You may download the plug-in directly from an HP authorized server (recommended), skip this installation (not recommended), or, if you already have a copy of the file, you can specify a path to the file (advanced).<br><br>%1").arg(reason_text))
118 self.connect(self.DownloadRadioButton, SIGNAL("toggled(bool)"), self.DownloadRadioButton_toggled)
119 self.connect(self.CopyRadioButton, SIGNAL("toggled(bool)"), self.CopyRadioButton_toggled)
120 self.connect(self.SkipRadioButton, SIGNAL("toggled(bool)"), self.SkipRadioButton_toggled)
121 self.connect(self.PathLineEdit, SIGNAL("textChanged(const QString &)"), self.PathLineEdit_textChanged)
122 self.connect(self.BrowseToolButton, SIGNAL("clicked()"), self.BrowseToolButton_clicked)
124 self.BrowseToolButton.setIcon(QIcon(load_pixmap('folder_open', '16x16')))
126 self.displayPage(PAGE_SOURCE)
129 def DownloadRadioButton_toggled(self, b):
131 self.PathLineEdit.setEnabled(False)
132 self.BrowseToolButton.setEnabled(False)
133 self.NextButton.setEnabled(True)
135 self.PathLineEdit.setStyleSheet("")
136 except AttributeError:
138 self.plugin_path = None
141 def CopyRadioButton_toggled(self, b):
143 self.PathLineEdit.setEnabled(True)
144 self.BrowseToolButton.setEnabled(True)
145 self.plugin_path = unicode(self.PathLineEdit.text())
146 self.setPathIndicators()
149 def SkipRadioButton_toggled(self, b):
151 self.PathLineEdit.setEnabled(False)
152 self.BrowseToolButton.setEnabled(False)
153 self.NextButton.setEnabled(True)
155 self.PathLineEdit.setStyleSheet("")
156 except AttributeError:
158 self.plugin_path = None
161 def PathLineEdit_textChanged(self, t):
162 self.plugin_path = unicode(t)
163 self.setPathIndicators()
166 def setPathIndicators(self):
168 if not self.plugin_path or (self.plugin_path and os.path.isdir(self.plugin_path)):
169 self.PathLineEdit.setToolTip(self.__tr("You must specify a path to the '%1' file.").arg(self.core.plugin_name))
171 elif os.path.basename(self.plugin_path) != self.core.plugin_name:
172 self.PathLineEdit.setToolTip(self.__tr("The plugin filename must be '%1'.").arg(self.core.plugin_name))
177 self.PathLineEdit.setStyleSheet("background-color: yellow; ")
178 except AttributeError:
180 self.NextButton.setEnabled(False)
183 self.PathLineEdit.setStyleSheet("")
184 except AttributeError:
186 self.NextButton.setEnabled(True)
187 self.PathLineEdit.setToolTip(QString(""))
190 def BrowseToolButton_clicked(self):
191 t = unicode(self.PathLineEdit.text())
193 if not os.path.exists(t):
194 path = unicode(QFileDialog.getOpenFileName(self, self.__tr("Select Plug-in File"),
195 #user_conf.workingDirectory(),
196 self.user_settings.working_dir,
197 self.__tr("Plugin Files (*.run)")))
200 self.plugin_path = path
201 self.PathLineEdit.setText(self.plugin_path)
202 #user_conf.setWorkingDirectory(self.plugin_path)
203 self.user_settings.working_dir = self.plugin_path
204 self.user_settings.save()
206 self.setPathIndicators()
212 def displayPage(self, page):
213 self.updateStepText(page)
214 self.StackedWidget.setCurrentIndex(page)
217 def CancelButton_clicked(self):
221 def NextButton_clicked(self):
222 if self.SkipRadioButton.isChecked():
223 log.debug("Skipping plug-in installation.")
230 if self.plugin_path is None: # download
231 # read plugin.conf (local or on sf.net) to get plugin_path (http://)
232 plugin_conf_url = self.core.get_plugin_conf_url()
234 if plugin_conf_url.startswith('file://'):
237 log.info("Checking for network connection...")
238 ok = self.core.check_network_connection()
241 log.error("Network connection not detected.")
243 FailureUI(self, self.__tr("Network connection not detected."))
247 log.info("Downloading configuration file from: %s" % plugin_conf_url)
248 self.plugin_path, size, checksum, timestamp, ok = self.core.get_plugin_info(plugin_conf_url,
249 self.plugin_download_callback)
251 log.debug("path=%s, size=%d, checksum=%s, timestamp=%f, ok=%s" %
252 (self.plugin_path, size, checksum, timestamp, ok))
254 if not self.plugin_path.startswith('http://') and not self.plugin_path.startswith('file://'):
255 self.plugin_path = 'file://' + self.plugin_path
258 if not self.plugin_path.startswith('http://'):
259 self.plugin_path = 'file://' + self.plugin_path
261 size, checksum, timestamp = 0, '', 0
263 if self.plugin_path.startswith('file://'):
266 log.info("Checking for network connection...")
267 ok = self.core.check_network_connection()
270 log.error("Network connection not detected.")
272 FailureUI(self, self.__tr("Network connection not detected."))
276 log.info("Downloading plug-in from: %s" % self.plugin_path)
278 status, ret = self.core.download_plugin(self.plugin_path, size, checksum, timestamp,
279 self.plugin_download_callback)
281 if status in (PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS, PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND):
283 if QMessageBox.question(self, self.__tr("Digital signature download failed"),
284 self.__tr("<b>The download of the digital signature file failed.</b><p>Without this file, it is not possible to authenticate and validate the plug-in prior to installation.</p>Do you still want to install the plug-in?"),
285 QMessageBox.Yes | QMessageBox.No) != QMessageBox.Yes:
287 self.core.delete_plugin()
291 elif status != PLUGIN_INSTALL_ERROR_NONE:
293 if status == PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND:
294 desc = self.__tr("<b>ERROR: Plug-in file not found (server returned 404 or similar error).</b><p>Error code: %1</p>").arg(str(ret))
296 elif status == PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD:
297 desc = self.__tr("<b>ERROR: Plug-in file does not match its digital signature.</b><p>File may have been corrupted or altered.</p><p>Error code: %1</p>").arg(str(ret))
299 elif status == PLUGIN_INSTALL_ERROR_PLUGIN_FILE_CHECKSUM_ERROR:
300 desc = self.__tr("<b>ERROR: Plug-in file does not match its checksum. File may have been corrupted or altered.")
302 elif status == PLUGIN_INSTALL_ERROR_NO_NETWORK:
303 desc = self.__tr("<b>ERROR: Unable to connect to network to download the plug-in.</b><p>Please check your network connection and try again.</p>")
305 elif status == PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR:
306 desc = self.__tr("<b>ERROR: Unable to create the plug-in directory.</b><p>Please check your permissions and try again.</p>")
308 self.core.delete_plugin()
310 FailureUI(self, desc)
314 if not self.core.run_plugin(GUI_MODE, self.plugin_install_callback):
315 self.core.delete_plugin()
317 FailureUI(self, self.__tr("Plug-in install failed."))
321 cups_devices = device.getSupportedCUPSDevices(['hp'])
322 for dev in cups_devices:
323 mq = device.queryModelByURI(dev)
325 if mq.get('fw-download', False):
326 # Download firmware if needed
327 log.info(log.bold("\nDownloading firmware to device %s..." % dev))
331 d = device.Device(dev)
333 log.error("Error opening device.")
335 FailureUI(self, self.__tr("<b>Firmware download to device failed.</b><p>%1</p>").arg(dev))
338 if d.downloadFirmware():
339 log.info("Firmware download successful.\n")
342 FailureUI(self, self.__tr("<b>Firmware download to device failed.</b><p>%1</p>").arg(dev))
350 self.core.delete_plugin()
351 SuccessUI(self, self.__tr("<b>Plug-in installation successful.</b>"))
356 def plugin_download_callback(self, c, s, t):
360 def plugin_install_callback(self, s):
364 def updateStepText(self, p):
365 self.StepText.setText(self.__tr("Step %1 of %2").arg(p+1).arg(PAGE_MAX+1))
368 def plugin_reason_text(self):
370 return self.PLUGIN_REASON_TEXT[self.plugin_reason]
375 def __tr(self,s,c = None):
376 return qApp.translate("PluginDialog",s,c)