#!/usr/bin/python   
# -*- coding: utf-8 -*-

# Copyright 2006 Canonical Ltd
# Author: Jonathan Riddell <jriddell@ubuntu.com>
#
#    This package is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.

import sys
import os
import os.path
import string
import urllib2

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from hwdb_client import ClientForm

import gettext
from gettext import gettext as _
import locale
localesApp="hwdb-client"
locale.setlocale(locale.LC_ALL, '')
gettext.bindtextdomain(localesApp)
gettext.textdomain(localesApp)

server = 'hwdb.ubuntu.com'
DATADIR = "/usr/share/hwdb-client/"
ARTDIR = "/usr/share/apps/hwdb-client-kde/pics/"
DISTRO = "Kubuntu"

class Collector(QWidget):
    """our central widget"""

    def __init__(self, backButton, forwardButton, cancelButton, parent = None):
        """set up the stacked widget with all the GUI items"""

        QWidget.__init__(self, parent)
        self.backButton = backButton
        self.forwardButton = forwardButton
        self.cancelButton = cancelButton
        
        self.backClicked = False

        self.output = []      # stores the users's answers
        self.comments = []    # stores the users's comments
        self.devdata = []     # stores detected hardware information
        self.step = 0
        self.xmlfile = DATADIR + "questions_en.xml"

        self.layout = QStackedLayout(self)

        txt = "<big><b>%s</b></big>\n" % unicode(_("Hardware Database Collection"), "UTF-8")
        txt += "<br />"
        txt += unicode(_("This is the %s hardware database collection tool.\n"
                     "It obtains data,\n"
                     "performs some tests, and asks you some\n"
                     "questions about your hardware.\n\n"), "UTF-8") % DISTRO
        txt += "<br /><br />"
        txt += "<b>%s</b>\n"%unicode(_("Improvement"), "UTF-8")
        txt += "<br />"
        txt += unicode(_("Developers use the collected data to improve hardware support.  By submitting "
                     "your hardware \n"
                     "information to the central %s database, you will "
                     "have \n"
                     "online access to your data in the future.  No personal "
                     "user information \n"
                     "will be collected or transmitted through this process unless you explicitly enter it."
                     "\n\n\t\t"), "UTF-8") % DISTRO
        txt += "<br /><br />"
        txt += unicode(_("Thank you for helping to improve %s."), "UTF-8") % DISTRO

        #First stack item is a text label used for various things
        textWidget = QWidget(self)
        textVBox = QVBoxLayout(textWidget)
        textVBox.addStretch()
        self.textLabel = QLabel(txt)
        self.textLabel.setWordWrap(True)
        textVBox.addWidget(self.textLabel)
        textVBox.addStretch()

        self.viewDataButton = QPushButton( unicode(_("View Data"), "UTF-8") )
        hbox = QHBoxLayout(textWidget)
        hbox.addStretch()
        hbox.addWidget(self.viewDataButton)
        hbox.addStretch()
        textVBox.addLayout(hbox)
        self.viewDataButton.hide()

        self.layout.addWidget(textWidget)   # index 0

        mainWidget = QWidget(self)
        mainLayout = QVBoxLayout(mainWidget)
        
        self.heading = heading(mainWidget)
        headingHBox = QHBoxLayout()
        headingHBox.addStretch()
        headingHBox.addWidget(self.heading)
        headingHBox.addStretch()
        mainLayout.addLayout(headingHBox)
        
        # the question layout with title, comment box and yes/no radios
        questionLayout = QHBoxLayout()
        self.questionLabel = QLabel(mainWidget)
        self.questionLabel.setWordWrap(True)
        self.questionLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        questionLayout.addWidget(self.questionLabel)
        
        self.retryButton = QPushButton(unicode(_("Test again"), "UTF-8"), mainWidget)
        self.retryButton.setIcon(QIcon("/usr/share/icons/crystalsvg/16x16/actions/reload.png"))
        self.connect(self.retryButton, SIGNAL("clicked()"), self.retry)
        questionLayout.addWidget(self.retryButton)
        mainLayout.addLayout(questionLayout)
        
        line = QFrame(mainWidget)
        line.setLineWidth(1)
        line.setFrameShape(QFrame.HLine)
        mainLayout.addWidget(line)
        
        answerLayout = QGridLayout()
        
        self.commentLabel = QLabel(unicode(_("Comments:"), "UTF-8"), mainWidget)
        answerLayout.addWidget(self.commentLabel, 0, 1)
        
        self.commentEdit = QTextEdit(mainWidget)
        self.commentEdit.resize(300, 100)
        self.connect(self.commentEdit, SIGNAL("textChanged()"), self.partialDeselected)
        answerLayout.addWidget(self.commentEdit, 1, 1)
        
        self.yesnobox = yesNoBox(mainWidget)
        self.yesnobox.move(100,100)
        self.yesnobox.resize(130,100)
        self.connect(self.yesnobox, SIGNAL("partialSelected()"), self.partialSelected)
        self.connect(self.yesnobox, SIGNAL("partialDeselected()"), self.partialDeselected)
        answerLayout.addWidget(self.yesnobox, 1, 0)
        
        mainLayout.addLayout(answerLayout)
        self.layout.addWidget(mainWidget)   # index 1
        
        # assemble widget has a progress bar to display progress of assembling data
        assembleWidget = QWidget(self)
        assembleVBox = QVBoxLayout(assembleWidget)
        assembleVBox.addStretch()
        self.assembleLabel = QLabel(assembleWidget)
        assembleVBox.addWidget(self.assembleLabel)
        self.assembleProgress = QProgressBar(assembleWidget)
        assembleVBox.addWidget(self.assembleProgress)
        assembleVBox.addStretch()
        self.layout.addWidget(assembleWidget)   # index 2
        
        #data has been sent, shows your computer's database ID and some buttons
        sentWidget = QWidget(self)
        sentVBox = QVBoxLayout(sentWidget)
        sentVBox.addStretch()
        thanksLabel = QLabel("<big>" + unicode(_("Your hardware data has been sent to our server.  Thank you for helping %s." + "</big>"), "UTF-8") % DISTRO, sentWidget)
        thanksLabel.setWordWrap(True)
        sentVBox.addWidget(thanksLabel)
        topHBox = QHBoxLayout()
        sentPic = QLabel(sentWidget)
        sentPic.setPixmap(QPixmap("/usr/share/icons/crystalsvg/22x22/apps/hwdb.png"))
        topHBox.addWidget(sentPic)
        self.sentIDLabel = QLabel(sentWidget)
        topHBox.addWidget(self.sentIDLabel)
        topHBox.addStretch()
        sentVBox.addLayout(topHBox)
        
        line = QFrame(sentWidget)
        line.setLineWidth(1)
        line.setFrameShape(QFrame.HLine)
        sentVBox.addWidget(line)

        self.sentText = QLabel(unicode(_("Attach this id to your bugreports or use it if you request online support."), "UTF-8"))
        self.sentText.setWordWrap(True)
        sentVBox.addWidget(self.sentText)
        
        buttonsHBox = QHBoxLayout()
        buttonsHBox.addStretch()
        copyButton = QPushButton(unicode(_("Copy to clipboard"), "UTF-8"))
        copyButton.setIcon(QIcon("/usr/share/icons/crystalsvg/16x16/actions/editcopy.png"))
        buttonsHBox.addWidget(copyButton)
        showRecordButton = QPushButton(unicode(_("Show online record"), "UTF-8"))
        showRecordButton.setIcon(QIcon("/usr/share/icons/hicolor/16x16/apps/konqueror.png"))
        self.connect(copyButton, SIGNAL("clicked()"), self.copyToClipboard)
        self.connect(showRecordButton, SIGNAL("clicked()"), self.showRecordOnline)
        buttonsHBox.addWidget(showRecordButton)
        buttonsHBox.addStretch()
        sentVBox.addLayout(buttonsHBox)
        sentVBox.addStretch()
        self.layout.addWidget(sentWidget)   # index 3
        
        #used for the audio test to show the animated GIF image
        movieWidget = QWidget(self)
        movieVBox = QVBoxLayout(movieWidget)
        movieVBox.addStretch()
        #self.movie = QMovie("speaker_shadow.gif")
        #movieVBox.addWidget(self.movie)
        movieVBox.addStretch()
        self.layout.addWidget(movieWidget)   # index 4
        
        #used for the network test, has three graphical labels for tick/crosses
        netTestWidget = QWidget(self)
        netTestVBox = QVBoxLayout(netTestWidget)
        self.netTestLabel = QLabel(netTestWidget)
        self.netTestLabel.setWordWrap(True)
        netTestVBox.addWidget(self.netTestLabel)
        netTestHBox = QHBoxLayout()
        self.netTestGraphic = [1, 2, 3]
        self.netTestGraphic[0] = QLabel(netTestWidget)
        self.netTestGraphic[1] = QLabel(netTestWidget)
        self.netTestGraphic[2] = QLabel(netTestWidget)
        pixmap = QPixmap(94, 111)
        pixmap.fill(QColor(255, 255, 255, 0))
        self.netTestGraphic[0].setPixmap(pixmap)
        self.netTestGraphic[1].setPixmap(pixmap)
        self.netTestGraphic[2].setPixmap(pixmap)
        netTestHBox.addWidget(self.netTestGraphic[0])
        netTestHBox.addWidget(self.netTestGraphic[1])
        netTestHBox.addWidget(self.netTestGraphic[2])
        netTestVBox.addLayout(netTestHBox)
        self.netTestResult = QLabel(netTestWidget)
        netTestVBox.addWidget(self.netTestResult)
        self.layout.addWidget(netTestWidget)   # index 5
        
        self.backgroundPixmap = QPixmap(ARTDIR + "canvas_bg.png")

        #check if data has already been sent, if so just show the sent widget, otherwise on with the questions
        hwdb_lock = ""
        home_path=os.environ["HOME"]	
        path = home_path+'/.hwdb'

        self.hwdb_lock = False
        if os.path.isfile(path):
            lock = open(path)
            self.hwdb_lock = lock.read()
        if self.hwdb_lock:
            self.dataSent(self.hwdb_lock)
        else:
            self.backButton.hide()
            self.layout.setCurrentIndex(0)  # intro text

    def sizeHint(self):
        return QSize(450, 300)

    def copyToClipboard(self):
        """for the Copy button on the sent widget"""
        clipboard = app.clipboard()
        clipboard.setText(self.hwdb_lock)

    def showRecordOnline(self):
        """for the Show button on the sent widget"""
        os.system("kfmclient exec http://hwdb.ubuntu.com/?xml=" + self.hwdb_lock)

    def partialSelected(self):
        """disable forward if no text and partial radio clicked"""
        if self.commentEdit.toPlainText().length() == 0: 
            self.forwardButton.setEnabled(False)

    def partialDeselected(self):
        """enable forward again"""
        self.forwardButton.setEnabled(True)

    def saveData(self):
        """save answers given by the user"""
        if self.backClicked == False:
            self.output.append(self.yesnobox.getCurrentButton())
            self.comments.append(unicode(self.commentEdit.toPlainText()))
        self.backClicked = False

    def forward(self):
        """forward button has been clicked, go to the next question"""
        elem = 0
        set = []

        self.forwardButton.setEnabled(False)
        self.forwardButton.setText(unicode(_("Next"), "UTF-8"))
        self.retryButton.hide()
        if self.layout.currentIndex() == 1:
            self.saveData()
            
        self.yesnobox.reset()
        self.commentEdit.clear()
        
        if self.step == 1:
            self.backButton.show()
        
        self.step = self.step + 1
        for line in open(self.xmlfile, 'r'):
            line = line.strip()
            if line.startswith('<advmark step="'+str(self.step)+'"'):
                elem = 1
                newline = line.rsplit("=", 1)
                showline = newline[1].strip('\">\n')
                set.append(showline+".png")
            if elem == 1:
                if line.startswith('<property name="title">'):
                    line = self.propstrip(line, 'title')
                    set.append(line.strip())
                if line.startswith('<property name="content">'):
                    line = self.propstrip(line, 'content')
                    set.append(unicode(_(line.strip()), "UTF-8"))
            if line.startswith("</advmark>"):
                elem = 0

        if len(set) >= 1:

            self.viewDataButton.hide()

            if set[1].startswith("Your E-mail"):
                self.commentLabel.setText(unicode(_("E-mail:"), "UTF-8"))
            else:
                self.commentLabel.setText(unicode(_("Comments:"), "UTF-8"))

            if set[1].startswith("Comments"):
                self.devdata.append('null')
                self.draw_commentwin(set)
            elif set[1].startswith("Video"):
                set[2] = set[2]+self.get_xorgdata()
                self.draw_yesno(set)
            elif set[1].startswith("Audio Test"):
                self.audioTest(set)
            elif set[1].startswith("Network"):
                self.networkTest(set)
            elif set[1].startswith("Assembling"):
                self.assemble(set)
            else:
                self.devdata.append('null')
                self.draw_yesno(set)
        else:  #reached the end of the questions
            self.sendData()

    def back(self):
        """back button has been clicked"""
        self.backClicked = True
        if self.step <= 0:
            self.backButton.hide()
        # network is really two steps, so back an extra step
        """
        if self.step == 5:
            self.step = self.step - 1
            self.output.pop()
            self.comments.pop()
        """
        if self.step == 5:
            self.retry()
        self.step = self.step - 2
        self.output.pop()
        self.comments.pop()
        self.forward()

    def propstrip(self, line, type):
        line = line.rstrip("</property>\n")
        line = line.lstrip('<property name="'+type+'">')
        return line.strip()

    def audioTest(self, set):
        """prepare the audio test"""
        self.retryButton.show()
        self.movie = QMovie(ARTDIR + "speaker_shadow.gif")
        self.movie.start()
        self.textLabel.setMovie(self.movie)
        devname = os.popen('cat /proc/asound/card0/id')
        for line in devname:
            self.devicename = line.strip()
            set[2] = unicode(_("Testing detected soundcard: "), "UTF-8") + self.devicename+"\n"+set[2]
            self.devdata.append(self.devicename)
        self.draw_yesno(set)
        self.doAudioTest()
        
    def doAudioTest(self):
        """play test sound"""
        self.backButton.setEnabled(False)
        self.forwardButton.setEnabled(False)
        self.movie.start()
        self.layout.setCurrentIndex(0)
        os.system("artsplay " + DATADIR + "sound.wav")
        QTimer.singleShot(3000, self.audioTestDone)
        
    def audioTestDone(self):
        """test finished, go to next question"""
        self.backButton.setEnabled(True)
        self.forwardButton.setEnabled(True)
        self.layout.setCurrentIndex(1)

    def networkTest(self, set):
        """prepare the network test"""
        self.netTestLabel.setText(set[2])
        route = self.getroute()
        if route:
            self.netdevice = route[len(route)-1].strip()
        else:
            self.netdevice = "none"
        set[2] = set[2]+unicode(_(" On interface: "), "UTF-8") + self.netdevice
        self.devdata.append(self.netdevice)
        self.draw_yesno(set)
        self.doNetworkTest()
        
    def doNetworkTest(self):
        """launch the network test"""
        self.backButton.setEnabled(False)
        self.forwardButton.setEnabled(False)
        self.layout.setCurrentIndex(5)
        self.netTestCounter = 0
        self.netTestFail = 0
        self.netTestSuccess = 0
        QTimer.singleShot(1000, self.netTest)
        
    def netTest(self):
        """ping gateway once and launch next test"""
        self.netTestGraphic[self.netTestCounter].setPixmap(QPixmap(ARTDIR + "yes.png"))
        route = self.getroute()
        if route:
            command = 'LC_ALL=C fping '+route[9]+' 2>/dev/null'
            for line in os.popen(command):
                fields = string.splitfields(line, 'is')
            status = fields[1].strip()
            if status.startswith('unreachable'):
                self.netTestGraphic[self.netTestCounter].setPixmap(QPixmap(ARTDIR + "no.png"))
                self.netTestFail = self.netTestFail + 1
            else:
                self.netTestGraphic[self.netTestCounter].setPixmap(QPixmap(ARTDIR + "yes.png"))
                self.netTestSuccess = self.netTestSuccess + 1
        else:
            self.netTestGraphic[self.netTestCounter].setPixmap(QPixmap(ARTDIR + "no.png"))
            self.netTestFail = self.netTestFail + 1
        self.netTestCounter = self.netTestCounter + 1
        os.system("artsplay " + DATADIR + "ping.wav")
        if self.netTestCounter == 3: #completed all three tests
            self.output.append(self.netTestFail)
            self.comments.append(self.netdevice+" failures: "+str(self.netTestFail))
            if self.netTestSuccess == 3:
                self.netTestResult.setText("<h1>" + unicode(_("Successful"), "UTF-8") + "</h1>")
            else:
                self.netTestResult.setText("<h1>" + unicode(_("Failed"), "UTF-8") + "<h1>")
            QTimer.singleShot(1000, self.forward)
        else:  # run next test
            QTimer.singleShot(1000, self.netTest)

    def retry(self):
        """user clicked retry button, re-do audio or network test"""
        if self.step == 1:  #audio
            self.doAudioTest()
        elif self.step == 5:  #network
            self.output.pop()
            self.comments.pop()
            self.step = 4
            self.netTestResult.setText("")
            pixmap = QPixmap(94, 111)
            pixmap.fill(QColor(255, 255, 255, 0))
            self.netTestGraphic[0].setPixmap(pixmap)
            self.netTestGraphic[1].setPixmap(pixmap)
            self.netTestGraphic[2].setPixmap(pixmap)
            if self.backClicked == False:
                self.doNetworkTest()
        else:
            print "error, unknown question in retry()"

    def getroute(self):
        route = False
        for line in os.popen('route -n'):
            if line.startswith('0.0.0.0'):
                route = string.splitfields(line, ' ')
        return route

    def get_xorgdata(self):
        ati_brain_damage = []
        command = 'xrandr -q|grep "*"'
        for item in os.popen('lsmod|grep fglrx'):
            ati_brain_damage.append(item)
        if len(ati_brain_damage):
            retval = unicode(_("\nDetected settings: impossible with fglrx"), "UTF-8")
        else:
            for line in os.popen(command):
                fields = string.splitfields(line, '  ')
                freq = fields[4].strip('+').strip('*')
                if freq == '\n' or freq == '':
                    freq = "N/A"
                retval = unicode(_("\nDetected settings: "), "UTF-8")+fields[1]+" @ "+freq+" Hz"
                self.devdata.append(fields[1].lstrip()+" @ "+fields[4].strip('*')+" Hz")
        return retval

    def draw_commentwin(self, set):
        """general comments question, hide the yes/no box"""
        self.yesnobox.hide()
        self.draw_yesno(set)

    def draw_yesno(self, set):
        """ask the question"""
        if set[1].startswith("Net"):
            self.retryButton.show()
        self.heading.setText(unicode(_(set[1]), "UTF-8"))
        self.heading.setImage(ARTDIR + set[0])

        self.layout.setCurrentIndex(1)

        #self.questionLabel.setText("<b>" + set[2] + "</b>")
        self.questionLabel.setText(_(set[2]))

        self.backButton.setEnabled(True)
        self.forwardButton.setEnabled(True)

    def assemble(self, set):
        """run hwdb-xml and collect output"""
        self.backButton.setEnabled(False)
        self.datapipe = []
        self.layout.setCurrentIndex(2)
        self.assembleLabel.setText(set[2])

        app.processEvents()

        for line in os.popen('/usr/bin/hwdb-xml -a'):
            self.datapipe.append(line)
            self.assembleProgress.setValue(self.assembleProgress.value() + 1)
            app.processEvents()
        
        self.datapipe.append("<!--<quadata>\n")
        i = 0
        for line in open(self.xmlfile, 'r'):
            self.assembleProgress.setValue(self.assembleProgress.value() + 1)
            line = line.strip()
            if line.startswith('<property name="title">'):
                line = self.propstrip(line, 'title')
                if not line.startswith("Assembling"):
                    line = line.rstrip()
                    self.datapipe.append("<question id=\""+line.lower()+"\">\n")
                    if not line.startswith("Comments") and not line.startswith("Your"):
                        self.datapipe.append(" <result>"+str(self.output[i])+"</result>\n")
                        self.datapipe.append(u"  <detected>"+self.devdata[i]+u"</detected>\n")
                    self.datapipe.append(u" <comment>"+self.comments[i]+u"</comment>\n")
                    self.datapipe.append("</question>\n")
                    i = i + 1
        self.datapipe.append("</quadata>\n-->\n")

        app.processEvents()

        self.datapipe.append("<!--<distroData>\n")

        for distro in [ "kubuntu", "ubuntu", "edubuntu", "xubuntu" ]:
             if os.path.exists("/var/lib/dpkg/info/" + distro + "-desktop.list"):
                 self.datapipe.append("  <installed>"+distro+"</installed>\n")

        self.datapipe.append("</distroData>\n-->\n")

        app.processEvents()

        self.viewDataButton.show()
        self.connect(self.viewDataButton, SIGNAL("clicked()"), self.viewDataClicked)
        self.layout.setCurrentIndex(0) #text label
        self.textLabel.setText(unicode(_("<h1>Your hardware data will now be uploaded.</h1>"), "UTF-8"))

        sendpipe = open('/tmp/hwdb_data.xml', 'w')

        for line in self.datapipe:
            app.processEvents()
            sendpipe.write(QString(line).toUtf8())
        sendpipe.close()
        self.forwardButton.setText(unicode(_("Send"), "UTF-8"))
        self.forwardButton.setEnabled(True)

    def viewDataClicked(self):
        print "viewDataClicked"
        dialogue = QDialog(self)
        vbox = QVBoxLayout(dialogue)
        dialogue.setLayout(vbox)

        textEdit = QTextEdit(dialogue)
        vbox.addWidget(textEdit)
        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok, Qt.Horizontal, dialogue)
        vbox.addWidget(buttonBox)
        self.connect(buttonBox, SIGNAL("accepted()"), dialogue.accept);

        data = open('/tmp/hwdb_data.xml', 'r')
        text = data.read()
        textEdit.setText(text)
        dialogue.resize(500, 400)
        dialogue.setWindowTitle(_("Raw Data"))
        dialogue.exec_()

    def sendData(self):
        """upload data (or save to a file on the desktop)"""
        self.layout.setCurrentIndex(0) #text label
        self.textLabel.setText(unicode(_("Connecting to server (timeout 30sec)."), "UTF-8"))
        app.processEvents()

        self.forwardButton.setEnabled(False)
        command = 'fping -a '+server+' 2>/dev/null'
        home_path=os.environ["HOME"]
        lock = open(home_path+'/.hwdb', 'w')
        md5sum = []
        ping = ''

        for line in os.popen(command):
            ping = line

        app.processEvents()
        for line in os.popen('md5sum /tmp/hwdb_data.xml'):
            md5sum = line.split(' ')
        os.system('mv /tmp/hwdb_data.xml /tmp/'+md5sum[0]+'.xml')
        os.system('bzip2 /tmp/'+md5sum[0]+'.xml')
        
        app.processEvents()
        if not ping:
            self.textLabel.setText(unicode(_("Can not connect to server, a copy of the data will get dropped\n to your desktop, please send it as mail\n attachment to hwdb@ubuntu.com"), "UTF-8"))
            app.processEvents()
            os.system('mv /tmp/'+md5sum[0]+'.xml.bz2 ~/Desktop/')
            self.dataSent(md5sum[0], False)
        else:
            request = urllib2.Request('http://'+server+'/upload/')
            response = urllib2.urlopen(request)
            forms = ClientForm.ParseResponse(response)
            form = forms[0]
            form.add_file(open('/tmp/'+md5sum[0]+'.xml.bz2'), 'text/xml', md5sum[0]+'.xml.bz2')
            response.close()
            request2 = form.click()
            response2 = urllib2.urlopen(request2)
            self.dataSent(md5sum[0], True)
        lock.write(md5sum[0])
        lock.close()
        os.system('rm -f /tmp/'+md5sum[0]+'.xml*')

    def dataSent(self, md5sum, sent = True):
        """show data sent widget"""
        if sent:
            self.textLabel.setText(unicode(_("Data has been sent..."), "UTF-8"))
        else:
            self.textLabel.setText(unicode(_("Can not connect to server, a copy of the data will get dropped\n to your desktop, please send it as mail\n attachment to hwdb@ubuntu.com"), "UTF-8"))
            self.sentText.setText("<p><b>" + unicode(_("Can not connect to server, a copy of the data will get dropped\n to your desktop, please send it as mail\n attachment to hwdb@ubuntu.com"), "UTF-8") + "</b></p><p>" + self.sentText.text())
        self.backButton.hide()
        self.forwardButton.setText(unicode(_("Run Again"), "UTF-8"))
        self.layout.setCurrentIndex(3)
        self.sentIDLabel.setText("<b>" + unicode(_("Submission id"), "UTF-8") + "</b><br /><div style='color:#639'>" + md5sum + "</div>")
        self.cancelButton.setText(unicode(_("Quit"), "UTF-8"))
        self.hwdb_lock = md5sum

class heading(QWidget):
    """the question titles, with background image, icon and text"""
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        self.text = ""
        self.background = QPixmap(ARTDIR + "header_bg.png")
        self.image = QPixmap()

    def setText(self, text):
        self.text = text

    def setImage(self, imageName):
        self.image = QPixmap(imageName)
        self.update()

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        painter.drawPixmap(0, 0, self.background)
        painter.drawPixmap(0, 0, self.image)
        painter.setFont( QFont("Sans Serif", 20 ))
        painter.drawText(50, 25, self.text)
        painter.end()

    def minimumSizeHint(self):
        return QSize(410, 50)

    def sizeHint(self):
        return QSize(410, 50)


class yesNoBox(QWidget):
    """the yes/no/partial radio buttons, with arrows at the side"""
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)

        self.yesButton = QRadioButton(unicode(_("Yes"), "UTF-8"), self)
        partialButton = QRadioButton(unicode(_("Partial"), "UTF-8"), self)
        noButton = QRadioButton(unicode(_("No"), "UTF-8"), self)
        neutralButton = QRadioButton(unicode(_("N/A"), "UTF-8"), self)

        self.yesButton.setToolTip(unicode(_("The device was automatically detected and is functioning properly"), "UTF-8"))
        partialButton.setToolTip(unicode(_("The device is functioning, but not fully, or it required manual configuration (please explain in comment)"), "UTF-8"))
        noButton.setToolTip(unicode(_("The device is not functioning at all"), "UTF-8"))
        neutralButton.setToolTip(unicode(_("The device is not available"), "UTF-8"))

        self.buttonGroup = QButtonGroup(self)
        self.buttonGroup.addButton(self.yesButton)
        self.buttonGroup.addButton(partialButton)
        self.buttonGroup.addButton(noButton)
        self.buttonGroup.addButton(neutralButton)
        self.buttonGroup.setId(self.yesButton, 0)
        self.buttonGroup.setId(partialButton, 1)
        self.buttonGroup.setId(noButton, 2)
        self.buttonGroup.setId(neutralButton, 3)

        self.connect(self.yesButton, SIGNAL("toggled(bool)"), self.yesClicked)
        self.connect(partialButton, SIGNAL("toggled(bool)"), self.partialClicked)
        self.connect(noButton, SIGNAL("toggled(bool)"), self.noClicked)
        self.connect(neutralButton, SIGNAL("toggled(bool)"), self.neutralClicked)

        layout = QGridLayout(self)
        layout.addWidget(self.yesButton, 0, 1)
        layout.addWidget(partialButton, 1, 1)
        layout.addWidget(noButton, 2, 1)
        layout.addWidget(neutralButton, 3, 1)

        self.label = QLabel(self)
        layout.addWidget(self.label, 0, 0, 4, 1)
        layout.setSpacing(0)

        self.yesButton.setChecked(True)
        
        self.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed))

    def reset(self):
        self.yesButton.setChecked(True)

    def yesClicked(self, toggled):
        if toggled:
            self.label.setPixmap(QPixmap(ARTDIR + "true.png"))

    def partialClicked(self, toggled):
        if toggled:
            self.label.setPixmap(QPixmap(ARTDIR + "partial.png"))
            self.emit(SIGNAL("partialSelected()"))
        else:
            self.emit(SIGNAL("partialDeselected()"))

    def noClicked(self, toggled):
        if toggled:
            self.label.setPixmap(QPixmap(ARTDIR + "false.png"))

    def neutralClicked(self, toggled):
        if toggled:
            self.label.setPixmap(QPixmap(ARTDIR + "neutral.png"))

    def getCurrentButton(self):
        return self.buttonGroup.checkedId()

class Window(QWidget):
    """our top level widget with image at the top, Collector main widget in centre and buttons at the bottom.  It has an image as the background."""
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)

        self.setWindowTitle(unicode(_("Hardware Database Collection"), "UTF-8"))
        self.background = QLabel(self)
        self.bgPixmap = QPixmap(ARTDIR + "canvas_bg.png")
        self.background.setPixmap(self.bgPixmap)
        self.background.show()
        
        self.setBackgroundRole(QPalette.Base)
        self.setAutoFillBackground(True)

        layout = QVBoxLayout(self)
        layout.setSpacing(0)
        layout.setMargin(0)
        
        header = QLabel(self)
        header.setPixmap(QPixmap(ARTDIR + "hwdb_head.png"))
        header.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        header.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed))
        headerHBox = QHBoxLayout()
        headerHBox.addStretch()
        headerHBox.addWidget(header)
        headerHBox.addStretch()

        line = QFrame(self)
        line.setLineWidth(1)
        line.setFrameShape(QFrame.HLine)

        bottomWidget = QWidget(self)
        bottomLayout = QHBoxLayout(bottomWidget)
        bottomLayout.addStretch()
        backButton = QPushButton(unicode(_("Back"), "UTF-8"))
        bottomLayout.addWidget(backButton)
        forwardButton = QPushButton(unicode(_("Next"), "UTF-8"))
        bottomLayout.addWidget(forwardButton)
        cancelButton = QPushButton(unicode(_("Cancel"), "UTF-8"))
        bottomLayout.addWidget(cancelButton)
        backButton.setIcon(QIcon("/usr/share/icons/crystalsvg/16x16/actions/back.png"))
        forwardButton.setIcon(QIcon("/usr/share/icons/crystalsvg/16x16/actions/forward.png"))
        cancelButton.setIcon(QIcon("/usr/share/icons/crystalsvg/22x22/actions/button_cancel.png"))
        
        widget = Collector(backButton, forwardButton, cancelButton, self)
        widget.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum))
        
        layout.addLayout(headerHBox)
        layout.addWidget(line)
        layout.addWidget(widget)
        layout.addWidget(bottomWidget)
        
        self.connect(forwardButton, SIGNAL("clicked()"), widget.forward)
        self.connect(backButton, SIGNAL("clicked()"), widget.back)
        self.connect(cancelButton, SIGNAL("clicked()"), app.quit)

    def resizeEvent(self, event):
        """background in bottom right corner"""
        self.background.move(self.width() - self.bgPixmap.width(), self.height() - self.bgPixmap.height())

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setWindowIcon(QIcon("/usr/share/icons/crystalsvg/22x22/apps/hwdb.png"))
    window = Window()
    window.show()
    sys.exit(app.exec_())
