Tizen 2.1 base
[platform/upstream/hplip.git] / ui4 / plugindialog.py
1 # -*- coding: utf-8 -*-
2 #
3 # (c) Copyright 2001-2009 Hewlett-Packard Development Company, L.P.
4 #
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.
9 #
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.
14 #
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
18 #
19 # Authors: Don Welch
20 #
21
22
23 # Local
24 from base.g import *
25 from base import device, utils
26 from prnt import cups
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
38
39 # Qt
40 from PyQt4.QtCore import *
41 from PyQt4.QtGui import *
42
43 # Ui
44 from plugindialog_base import Ui_Dialog
45
46
47 PAGE_SOURCE = 0
48 # PAGE_LICENSE = 1 # part of plug-in itself, this is a placeholder
49 PAGE_MAX = 1
50
51
52
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
59         self.result = False
60         self.core = CoreInstall()
61         self.core.set_plugin_version()
62         self.setupUi(self)
63
64         self.user_settings = UserSettings()
65         self.user_settings.load()
66         self.user_settings.debug()
67
68         self.initUi()
69
70         QTimer.singleShot(0, self.showSourcePage)
71
72
73     def isPluginInstalled(self):
74         return self.core.check_for_plugin()
75
76
77     def initUi(self):
78         # connect signals/slots
79         self.connect(self.CancelButton, SIGNAL("clicked()"), self.CancelButton_clicked)
80         self.connect(self.NextButton, SIGNAL("clicked()"), self.NextButton_clicked)
81
82         # Application icon
83         self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
84
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,
102         }
103
104     #
105     # SOURCE PAGE
106     #
107     def showSourcePage(self):
108         reason_text = self.plugin_reason_text()
109
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)
114
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))
117
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)
123
124         self.BrowseToolButton.setIcon(QIcon(load_pixmap('folder_open', '16x16')))
125
126         self.displayPage(PAGE_SOURCE)
127
128
129     def DownloadRadioButton_toggled(self, b):
130         if b:
131             self.PathLineEdit.setEnabled(False)
132             self.BrowseToolButton.setEnabled(False)
133             self.NextButton.setEnabled(True)
134             try:
135                 self.PathLineEdit.setStyleSheet("")
136             except AttributeError:
137                 pass
138             self.plugin_path = None
139
140
141     def CopyRadioButton_toggled(self, b):
142         if b:
143             self.PathLineEdit.setEnabled(True)
144             self.BrowseToolButton.setEnabled(True)
145             self.plugin_path = unicode(self.PathLineEdit.text())
146             self.setPathIndicators()
147
148
149     def SkipRadioButton_toggled(self, b):
150         if b:
151             self.PathLineEdit.setEnabled(False)
152             self.BrowseToolButton.setEnabled(False)
153             self.NextButton.setEnabled(True)
154             try:
155                 self.PathLineEdit.setStyleSheet("")
156             except AttributeError:
157                 pass
158             self.plugin_path = None
159
160
161     def PathLineEdit_textChanged(self, t):
162         self.plugin_path = unicode(t)
163         self.setPathIndicators()
164
165
166     def setPathIndicators(self):
167         ok = True
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))
170             ok = False
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))
173             ok = False
174
175         if not ok:
176             try:
177                 self.PathLineEdit.setStyleSheet("background-color: yellow; ")
178             except AttributeError:
179                 pass
180             self.NextButton.setEnabled(False)
181         else:
182             try:
183                 self.PathLineEdit.setStyleSheet("")
184             except AttributeError:
185                 pass
186             self.NextButton.setEnabled(True)
187             self.PathLineEdit.setToolTip(QString(""))
188
189
190     def BrowseToolButton_clicked(self):
191         t = unicode(self.PathLineEdit.text())
192
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)")))
198
199         if path:
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()
205
206         self.setPathIndicators()
207
208     #
209     # Misc
210     #
211
212     def displayPage(self, page):
213         self.updateStepText(page)
214         self.StackedWidget.setCurrentIndex(page)
215
216
217     def CancelButton_clicked(self):
218         self.close()
219
220
221     def NextButton_clicked(self):
222         if self.SkipRadioButton.isChecked():
223             log.debug("Skipping plug-in installation.")
224             self.close()
225             return
226
227         beginWaitCursor()
228         try:
229
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()
233
234                 if plugin_conf_url.startswith('file://'):
235                     pass
236                 else:
237                     log.info("Checking for network connection...")
238                     ok = self.core.check_network_connection()
239
240                     if not ok:
241                         log.error("Network connection not detected.")
242                         endWaitCursor()
243                         FailureUI(self, self.__tr("Network connection not detected."))
244                         self.close()
245                         return
246
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)
250
251                 log.debug("path=%s, size=%d, checksum=%s, timestamp=%f, ok=%s" %
252                         (self.plugin_path, size, checksum, timestamp, ok))
253
254                 if not self.plugin_path.startswith('http://') and not self.plugin_path.startswith('file://'):
255                     self.plugin_path = 'file://' + self.plugin_path
256
257             else: # path
258                 if not self.plugin_path.startswith('http://'):
259                     self.plugin_path = 'file://' + self.plugin_path
260
261                 size, checksum, timestamp = 0, '', 0
262
263             if self.plugin_path.startswith('file://'):
264                 pass
265             else:
266                 log.info("Checking for network connection...")
267                 ok = self.core.check_network_connection()
268
269                 if not ok:
270                     log.error("Network connection not detected.")
271                     endWaitCursor()
272                     FailureUI(self, self.__tr("Network connection not detected."))
273                     self.close()
274                     return
275
276             log.info("Downloading plug-in from: %s" % self.plugin_path)
277
278             status, ret = self.core.download_plugin(self.plugin_path, size, checksum, timestamp,
279                 self.plugin_download_callback)
280
281             if status in (PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS, PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND):
282                 endWaitCursor()
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:
286
287                     self.core.delete_plugin()
288                     self.close()
289                     return
290
291             elif status != PLUGIN_INSTALL_ERROR_NONE:
292
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))
295
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))
298
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.")
301
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>")
304
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>")
307
308                 self.core.delete_plugin()
309                 endWaitCursor()
310                 FailureUI(self, desc)
311                 self.close()
312                 return
313
314             if not self.core.run_plugin(GUI_MODE, self.plugin_install_callback):
315                 self.core.delete_plugin()
316                 endWaitCursor()
317                 FailureUI(self, self.__tr("Plug-in install failed."))
318                 self.close()
319                 return
320
321             cups_devices = device.getSupportedCUPSDevices(['hp'])
322             for dev in cups_devices:
323                 mq = device.queryModelByURI(dev)
324
325                 if mq.get('fw-download', False):
326                     # Download firmware if needed
327                     log.info(log.bold("\nDownloading firmware to device %s..." % dev))
328                     try:
329                         d = None
330                         try:
331                             d = device.Device(dev)
332                         except Error:
333                             log.error("Error opening device.")
334                             endWaitCursor()
335                             FailureUI(self, self.__tr("<b>Firmware download to device failed.</b><p>%1</p>").arg(dev))
336                             continue
337
338                         if d.downloadFirmware():
339                             log.info("Firmware download successful.\n")
340                         else:
341                             endWaitCursor()
342                             FailureUI(self, self.__tr("<b>Firmware download to device failed.</b><p>%1</p>").arg(dev))
343
344                     finally:
345                         if d is not None:
346                             d.close()
347         finally:
348             endWaitCursor()
349
350         self.core.delete_plugin()
351         SuccessUI(self, self.__tr("<b>Plug-in installation successful.</b>"))
352         self.result = True
353         self.close()
354
355
356     def plugin_download_callback(self, c, s, t):
357         pass
358
359
360     def plugin_install_callback(self, s):
361         print s
362
363
364     def updateStepText(self, p):
365         self.StepText.setText(self.__tr("Step %1 of %2").arg(p+1).arg(PAGE_MAX+1))
366
367
368     def plugin_reason_text(self):
369         try:
370             return self.PLUGIN_REASON_TEXT[self.plugin_reason]
371         except KeyError:
372             return None
373
374
375     def __tr(self,s,c = None):
376         return qApp.translate("PluginDialog",s,c)
377
378