예제 #1
0
class FirstRunDialog(BaseDialog):
    def __init__(self, parent=None):
        BaseDialog.__init__(self, parent)
        self.setWindowTitle(_("First Run Dialog"))

        self.top_label = WarningLabel("FirstRun")

        self.wizard_widget = QtGui.QStackedWidget()

        page0 = PageZero(self)
        self.page1 = PageOne(self)
        self.page2 = PageTwo(self)
        self.page3 = PageThree(self)
        self.page4 = PageFour(self)
        self.page5 = PageFive(self)
        page6 = PageSix(self)
        self.page7 = PageSeven(self)
        # accept_page = AcceptPage(self)

        self.wizard_widget.addWidget(page0)
        self.wizard_widget.addWidget(self.page1)
        self.wizard_widget.addWidget(self.page2)
        self.wizard_widget.addWidget(self.page3)
        self.wizard_widget.addWidget(self.page4)
        self.wizard_widget.addWidget(self.page5)
        self.wizard_widget.addWidget(page6)
        self.wizard_widget.addWidget(self.page7)
        # self.wizard_widget.addWidget(accept_page)

        self.insertWidget(self.top_label)
        self.insertWidget(self.wizard_widget)

        self.next_but = self.button_box.addButton(_("Next"),
                                                  self.button_box.ActionRole)
        self.back_but = self.button_box.addButton(_("Back"),
                                                  self.button_box.ActionRole)

        self.apply_but.hide()
        self.back_but.hide()
        self.cancel_but.setText(_("Quit OpenMolar"))

        self.set_labels()

    def sizeHint(self):
        return QtCore.QSize(400, 400)

    def wait(self, waiting=True):
        if waiting:
            QtGui.QApplication.instance().setOverrideCursor(
                QtCore.Qt.WaitCursor)
        else:
            QtGui.QApplication.instance().restoreOverrideCursor()

    def set_labels(self):
        self.top_label.setText(self.current_page.header_text)
        self.cancel_but.setVisible(self.current_index == 0)
        self.back_but.setVisible(self.current_index != 0)

        if self.current_index == 5:
            self.next_but.setText(_("Create Database Now!"))
        elif self.current_index == 7:
            self.next_but.setText(_("Write Config File and Proceed"))
        else:
            self.next_but.setText(_("Next"))

    def next(self):
        '''
        0 = intro
        1 = application password
        2 = host and port
        3 = database option (create new or use existing)
        4 = database details (dbname, user and password)
        5 = enter privileged user
        6 = create database
        7 = test connection, write config and exit.
        '''
        i = self.wizard_widget.currentIndex()
        if not self.current_page.is_completed:
            QtGui.QMessageBox.warning(self, _("error"),
                                      self.current_page.error_message)
            new_i = i
        elif i == 4 and not self.page3.create_new:
            new_i = i + 3
        elif i == 7:
            self.finish()
            return
        else:
            new_i = i + 1
        self.wizard_widget.setCurrentIndex(new_i)
        self.set_labels()

    def back(self):
        i = self.wizard_widget.currentIndex()
        if i == 0:
            new_i = 0
        elif i == 7:  # shouldn't happen?
            new_i = 0  # don't create a database by hitting "back"
        else:
            new_i = i - 1
        self.wizard_widget.setCurrentIndex(new_i)
        self.set_labels()

    def database_exists_already(self):
        self.wizard_widget.setCurrentIndex(4)
        self.set_labels()

    def finish(self):
        dom = minidom.parseString(XML_TEMPLATE)
        #-- hash the password and save it
        PSWORD = hashlib.md5(
            hashlib.sha1(str("diqug_ADD_SALT_3i2some" +
                             self.sys_password)).hexdigest()).hexdigest()
        dom.getElementsByTagName(
            "system_password")[0].firstChild.replaceWholeText(PSWORD)
        #-- server settings
        xmlnode = dom.getElementsByTagName("server")[0]
        #-- host
        xmlnode.getElementsByTagName(
            "location")[0].firstChild.replaceWholeText(self.host)
        #--port
        xmlnode.getElementsByTagName("port")[0].firstChild.replaceWholeText(
            str(self.port))
        #-- database settings
        xmlnode = dom.getElementsByTagName("database")[0]
        #--user
        xmlnode.getElementsByTagName("user")[0].firstChild.replaceWholeText(
            self.db_user)
        #--password
        xmlnode.getElementsByTagName(
            "password")[0].firstChild.replaceWholeText(
                base64.b64encode(self.db_pass))
        #--db name
        xmlnode.getElementsByTagName("dbname")[0].firstChild.replaceWholeText(
            self.db_name)

        settings_dir = os.path.dirname(localsettings.global_cflocation)
        successful_save = False
        try:
            if not os.path.exists(settings_dir):
                LOGGER.info("creating settings directory '%s'", settings_dir)
                os.mkdir(settings_dir)
            LOGGER.info('writing settings to %s',
                        localsettings.global_cflocation)
            f = open(localsettings.global_cflocation, "w")
            f.write(dom.toxml())
            f.close()
            localsettings.cflocation = localsettings.global_cflocation
            successful_save = True
        except OSError:
            pass
        except IOError:
            pass

        if not successful_save:
            message = (
                "unable to write to '%s' "
                "we need root privileges for that\n"
                "will resort to putting settings into a local file '%s'")
            LOGGER.warning(message, settings_dir, localsettings.cflocation)
            settings_dir = os.path.dirname(localsettings.cflocation)
            if not os.path.exists(settings_dir):
                os.mkdir(settings_dir)
            LOGGER.info("putting a local settings file in '%s'", settings_dir)
            f = open(localsettings.cflocation, "w")
            f.write(dom.toxml())
            f.close()
            localsettings.cflocation = localsettings.cflocation

        conf_text = "[login]\nPASSWORD=\nUSER1=\nUSER2="
        if self.page3.create_new:
            conf_text = conf_text.replace("USER1=", "USER1=USER")
        f = open(localsettings.LOGIN_CONF, "w")
        f.write(conf_text)
        f.close()

        self.accept()

    def _clicked(self, but):
        '''
        "private" function called when button box is clicked
        '''
        if but == self.next_but:
            self.next()
        elif but == self.back_but:
            self.back()
        else:
            BaseDialog._clicked(self, but)

    @property
    def current_index(self):
        return self.wizard_widget.currentIndex()

    @property
    def current_page(self):
        return self.wizard_widget.currentWidget()

    @property
    def sys_password(self):
        return str(self.page1.line_edit1.text().toAscii())

    @property
    def host(self):
        return str(self.page2.line_edit1.text().toAscii())

    @property
    def port(self):
        return int(str(self.page2.line_edit2.text().toAscii()))

    @property
    def db_name(self):
        return str(self.page4.line_edit1.text().toAscii())

    @property
    def db_user(self):
        return str(self.page4.line_edit2.text().toAscii())

    @property
    def db_pass(self):
        return str(self.page4.line_edit3.text().toAscii())

    @property
    def privileged_user(self):
        return str(self.page5.line_edit1.text().toAscii())

    @property
    def privileged_user_pass(self):
        return str(self.page5.line_edit2.text().toAscii())
class CheckVersionDialog(ExtendableDialog, Options):
    '''
    A dialog which informs the user of any updates to the openmolar application
    There are 2 ways of calling this dialog.
    exec_() = show the dialog before polling the wesbite for releases
    background_exec() = only show the result if there is a new version.
    '''
    result = None
    _new_version = None
    _next_check_date = None
    polling = False

    def __init__(self, parent=None):
        LOGGER.debug("initiating CheckVersionDialog")
        ExtendableDialog.__init__(self, parent)
        self.data_fetcher = DataFetcher(parent)
        self.config = MyConfigParser()

    def add_widgets(self):
        self.header_label = WarningLabel(
            _("Checking for updates.... please wait."))
        self.result_label = QtWidgets.QLabel("")
        self.result_label.setAlignment(QtCore.Qt.AlignCenter)
        self.result_label.setOpenExternalLinks(True)

        self.insertWidget(self.header_label)
        self.insertWidget(self.result_label)

        self.cancel_but.hide()
        self.apply_but.setText(_("OK"))
        self.enableApply()

        self.options_widget = OptionsWidget(self)
        self.options_widget.set_chosen_option(self.config.update_option)
        self.set_advanced_but_text(_("Options"))
        self.add_advanced_widget(self.options_widget)

    def show_result(self):
        LOGGER.debug("CheckVersionDialog show result")
        self.result = self.data_fetcher.result()
        if self.result is None:
            self.result_label.setText(
                "%s<br /><a href='%s'>%s</a>" % (_("Unable to connect to"),
                                                 INFORMATION_URL,
                                                 INFORMATION_URL))
            return
        if self.update_available:
            header_text = _("A newer version of OpenMolar is available")
            self.header_label.label.setStyleSheet("color: red")
        else:
            header_text = _("You are running the latest version - thankyou")

        self.header_label.setText(header_text)
        self.result_label.setText(MESSAGE % (self.new_version))

    def lookup_due(self):
        '''
        check the config file for user preferences on update check
        '''
        LOGGER.debug("checking user preferences for application update check")
        if self.config.update_option == self.NEVER:
            return False
        if self.config.update_option == self.MONTHLY:
            delta = timedelta(days=30)
        elif self.config.update_option == self.WEEKLY:
            delta = timedelta(days=7)
        elif self.config.update_option == self.DAILY:
            delta = timedelta(days=1)
        else:
            delta = timedelta(days=0)
        if self.config.last_check_date + delta > date.today():
            LOGGER.debug("update check not due yet")
            return False
        return True

    def hit_website(self):
        if not self.polling:
            LOGGER.info("polling website for latest release")
            self.polling = True
            self.data_fetcher.get_webdata()

    @property
    def update_available(self):
        '''
        a boolean to lookup whether a new version is available.
        '''
        LOGGER.debug("getting property update_available")
        try:
            if self.new_version[0] > localsettings.VERSION:
                LOGGER.info("There is a newer version available upstream")
                return True
            else:
                LOGGER.info("You are running the latest version - thankyou")
                return False
        except:
            LOGGER.exception("unknown error getting update available "
                             "perhaps the website returned garbage???")
            return False

    @property
    def new_version(self):
        if self._new_version is None:
            scp = configparser.ConfigParser()
            scp.read_string(self.result)
            version, release_date, message = "", None, ""
            try:
                try:
                    version = scp.get("RELEASE", "VERSION")
                except configparser.NoOptionError:
                    pass
                try:
                    release_date_string = scp.get("RELEASE", "DATE")
                    m = re.match(r"(\d+),(\d+),(\d+)", release_date_string)
                    if m:
                        release_date = date(int(m.groups()[0]),
                                            int(m.groups()[1]),
                                            int(m.groups()[2]))
                        self.checked_today = True
                    else:
                        LOGGER.warning("release date not in form 2016,03,09")
                except configparser.NoOptionError:
                    pass
                except ValueError:  # this will fire if a bad date is passed.
                    logging.exception("error parsing date field")
                try:
                    message = scp.get("RELEASE", "MESSAGE")
                except configparser.NoOptionError:
                    pass
            except configparser.NoSectionError:
                LOGGER.warning("unable to parse result of version checking")
            except configparser.MissingSectionHeaderError:
                pass
            self._new_version = (version,
                                 localsettings.formatDate(release_date),
                                 message.replace("\n", "<br />"))
        return self._new_version

    def background_exec(self):
        if self.lookup_due():
            self.data_fetcher.finished_signal.connect(self.exec_)
            self.hit_website()

    def exec_(self):
        LOGGER.debug("exec_ called by %s", self.sender())
        self.add_widgets()
        if self.sender() == self.data_fetcher:
            self.show_result()
            # lookup has been performed discreetly, only bother the user if
            # there is an update available
            if not self.update_available:
                return False
        else:
            self.data_fetcher.finished_signal.connect(self.show_result)
            QtCore.QTimer.singleShot(5000, self.hit_website)
        if ExtendableDialog.exec_(self):
            self.config.user_chosen_option = self.options_widget.chosen_option
            self.config.checked_today = self.checked_today
            self.config.write_config()
예제 #3
0
class FirstRunDialog(BaseDialog):

    def __init__(self, parent=None):
        BaseDialog.__init__(self, parent)
        self.setWindowTitle(_("First Run Dialog"))

        self.top_label = WarningLabel("FirstRun")

        self.wizard_widget = QtWidgets.QStackedWidget()

        page0 = PageZero(self)
        self.page1 = PageOne(self)
        self.page2 = PageTwo(self)
        self.page3 = PageThree(self)
        self.page4 = PageFour(self)
        self.page5 = PageFive(self)
        page6 = PageSix(self)
        self.page7 = PageSeven(self)
        # accept_page = AcceptPage(self)

        self.wizard_widget.addWidget(page0)
        self.wizard_widget.addWidget(self.page1)
        self.wizard_widget.addWidget(self.page2)
        self.wizard_widget.addWidget(self.page3)
        self.wizard_widget.addWidget(self.page4)
        self.wizard_widget.addWidget(self.page5)
        self.wizard_widget.addWidget(page6)
        self.wizard_widget.addWidget(self.page7)
        # self.wizard_widget.addWidget(accept_page)

        self.insertWidget(self.top_label)
        self.insertWidget(self.wizard_widget)

        self.next_but = self.button_box.addButton(
            _("Next"), self.button_box.ActionRole)
        self.back_but = self.button_box.addButton(
            _("Back"), self.button_box.ActionRole)

        self.apply_but.hide()
        self.back_but.hide()
        self.cancel_but.setText(_("Quit OpenMolar"))

        self.set_labels()

    def sizeHint(self):
        return QtCore.QSize(400, 400)

    def wait(self, waiting=True):
        if waiting:
            QtWidgets.QApplication.instance().setOverrideCursor(
                QtCore.Qt.WaitCursor)
        else:
            QtWidgets.QApplication.instance().restoreOverrideCursor()

    def set_labels(self):
        self.top_label.setText(self.current_page.header_text)
        self.cancel_but.setVisible(self.current_index == 0)
        self.back_but.setVisible(self.current_index != 0)

        if self.current_index == 5:
            self.next_but.setText(_("Create Database Now!"))
        elif self.current_index == 7:
            self.next_but.setText(_("Write Config File and Proceed"))
        else:
            self.next_but.setText(_("Next"))

    def __next__(self):
        '''
        0 = intro
        1 = application password
        2 = host and port
        3 = database option (create new or use existing)
        4 = database details (dbname, user and password)
        5 = enter privileged user
        6 = create database
        7 = test connection, write config and exit.
        '''
        i = self.wizard_widget.currentIndex()
        if not self.current_page.is_completed:
            QtWidgets.QMessageBox.warning(self,
                                          _("error"),
                                          self.current_page.error_message)
            new_i = i
        elif i == 4 and not self.page3.create_new:
            new_i = i + 3
        elif i == 7:
            self.finish()
            return
        else:
            new_i = i + 1
        self.wizard_widget.setCurrentIndex(new_i)
        self.set_labels()

    def back(self):
        i = self.wizard_widget.currentIndex()
        if i == 0:
            new_i = 0
        elif i == 7:  # shouldn't happen?
            new_i = 0  # don't create a database by hitting "back"
        else:
            new_i = i - 1
        self.wizard_widget.setCurrentIndex(new_i)
        self.set_labels()

    def database_exists_already(self):
        self.wizard_widget.setCurrentIndex(4)
        self.set_labels()

    def finish(self):
        dom = minidom.parseString(XML_TEMPLATE)
        #  hash the password (twice) and save it
        sha1 = hashlib.sha1(("diqug_ADD_SALT_3i2some%s" %
                             self.sys_password).encode("utf8")).hexdigest()
        PSWORD = hashlib.md5(sha1.encode("utf8")).hexdigest()
        dom.getElementsByTagName(
            "system_password")[0].firstChild.replaceWholeText(PSWORD)
        #  server settings
        xmlnode = dom.getElementsByTagName("server")[0]
        #  host
        xmlnode.getElementsByTagName(
            "location")[0].firstChild.replaceWholeText(self.host)
        # port
        xmlnode.getElementsByTagName(
            "port")[0].firstChild.replaceWholeText(str(self.port))
        #  database settings
        xmlnode = dom.getElementsByTagName("database")[0]
        # user
        xmlnode.getElementsByTagName(
            "user")[0].firstChild.replaceWholeText(self.db_user)
        # password
        xmlnode.getElementsByTagName(
            "password")[0].firstChild.replaceWholeText(
            base64.b64encode(self.db_pass.encode("utf8")).decode("utf8"))
        # db name
        xmlnode.getElementsByTagName(
            "dbname")[0].firstChild.replaceWholeText(self.db_name)

        settings_dir = os.path.dirname(localsettings.global_cflocation)
        successful_save = False
        try:
            if not os.path.exists(settings_dir):
                LOGGER.info("creating settings directory '%s'", settings_dir)
                os.mkdir(settings_dir)
            LOGGER.info(
                'writing settings to %s', localsettings.global_cflocation)
            f = open(localsettings.global_cflocation, "w")
            f.write(dom.toxml())
            f.close()
            localsettings.cflocation = localsettings.global_cflocation
            successful_save = True
        except OSError:
            pass
        except IOError:
            pass

        if not successful_save:
            message = (
                "unable to write to '%s' "
                "we need root privileges for that\n"
                "will resort to putting settings into a local file '%s'")
            LOGGER.warning(message, settings_dir, localsettings.cflocation)
            settings_dir = os.path.dirname(localsettings.cflocation)
            if not os.path.exists(settings_dir):
                os.mkdir(settings_dir)
            LOGGER.info("putting a local settings file in '%s'", settings_dir)
            f = open(localsettings.cflocation, "w")
            f.write(dom.toxml())
            f.close()
            localsettings.cflocation = localsettings.cflocation

        conf_text = "[login]\nPASSWORD=\nUSER1=\nUSER2="
        if self.page3.create_new:
            conf_text = conf_text.replace("USER1=", "USER1=USER")
        f = open(localsettings.LOGIN_CONF, "w")
        f.write(conf_text)
        f.close()

        self.accept()

    def _clicked(self, but):
        '''
        "private" function called when button box is clicked
        '''
        if but == self.next_but:
            next(self)
        elif but == self.back_but:
            self.back()
        else:
            BaseDialog._clicked(self, but)

    @property
    def current_index(self):
        return self.wizard_widget.currentIndex()

    @property
    def current_page(self):
        return self.wizard_widget.currentWidget()

    @property
    def sys_password(self):
        return str(self.page1.line_edit1.text())

    @property
    def host(self):
        return str(self.page2.line_edit1.text())

    @property
    def port(self):
        return int(str(self.page2.line_edit2.text()))

    @property
    def db_name(self):
        return str(self.page4.line_edit1.text())

    @property
    def db_user(self):
        return str(self.page4.line_edit2.text())

    @property
    def db_pass(self):
        return str(self.page4.line_edit3.text())

    @property
    def privileged_user(self):
        return str(self.page5.line_edit1.text())

    @property
    def privileged_user_pass(self):
        return str(self.page5.line_edit2.text())
예제 #4
0
class EditTreatmentDialog(ExtendableDialog):

    def __init__(self, serialno, courseno, parent=None):
        ExtendableDialog.__init__(self, parent, remove_stretch=True)
        self.setWindowTitle(_("Edit Treatment Dialog"))

        self.serialno = serialno
        self.courseno = courseno

        self._treatment_course = None
        self.widgets = {}
        self.orig_values = {}

        frame = QtWidgets.QFrame()
        form_layout = QtWidgets.QFormLayout(frame)

        self.header_label = WarningLabel("")

        tooth_atts = []

        for att in treatment_course.CURRTRT_ROOT_ATTS:
            widg = UpperCaseLineEdit()
            self.widgets[att] = widg
            if re.match("[ul][lr][1-8]", att):
                tooth_atts.append(att)
            else:
                form_layout.addRow(att, widg)
        for att in sorted(tooth_atts):
            form_layout.addRow(att.upper(), self.widgets[att])

        scroll_area = QtWidgets.QScrollArea()
        scroll_area.setWidget(frame)
        scroll_area.setWidgetResizable(True)

        self.insertWidget(self.header_label)
        self.insertWidget(scroll_area)

        self.add_advanced_widget(QtWidgets.QLabel(_("No Advanced Options")))
        QtCore.QTimer.singleShot(100, self.load_values)

    @property
    def treatment_course(self):
        if self._treatment_course is None:
            self._treatment_course = treatment_course.TreatmentCourse(
                self.serialno, self.courseno)
        return self._treatment_course

    def load_values(self):
        mb = QtWidgets.QMessageBox(self)
        mb.setWindowTitle(_("Option"))
        mb.setIcon(mb.Question)
        mb.setStandardButtons(mb.Yes | mb.No)
        mb.setText("%s<hr /><em>%s</em>" % (
            _("Edit Completed items?"),
            _("Choosing 'NO' will offer edit of planned items")))
        self.rejected.connect(mb.accept)  # for Unittests
        mb.exec_()

        if mb.result() == mb.No:
            self.header_label.setText(_("Planned Items"))
            suffix = "pl"
        else:
            self.header_label.setText(_("Completed Items"))
            suffix = "cmp"
        for att in treatment_course.CURRTRT_ROOT_ATTS:
            val = self.treatment_course.__dict__[att + suffix]
            widg = self.widgets[att]
            self.orig_values[att] = val
            widg.setText(val)
            widg.editingFinished.connect(self.check_appliable)

    def new_value(self, att):
        return str(self.widgets[att].text()).strip(" ") + " "

    def check_appliable(self):
        for att in treatment_course.CURRTRT_ROOT_ATTS:
            if self.new_value(att) != self.orig_values[att]:
                self.enableApply()
                return
        self.enableApply(False)

    def sizeHint(self):
        return QtCore.QSize(350, 600)

    def update_db(self):
        changes = ""
        values = []
        for att in treatment_course.CURRTRT_ROOT_ATTS:
            if self.new_value(att) != self.orig_values[att]:
                changes += "%s%s=%%s ," % (att, self.suffix)
                values.append(self.new_value(att))

        treatment_course.update_course(
            changes.rstrip(","),
            values,
            self.serialno,
            self.courseno)
예제 #5
0
class CheckVersionDialog(ExtendableDialog, Options):
    '''
    A dialog which informs the user of any updates to the openmolar application
    There are 2 ways of calling this dialog.
    exec_() = show the dialog before polling the wesbite for releases
    background_exec() = only show the result if there is a new version.
    '''
    result = None
    _new_version = None
    _next_check_date = None
    polling = False

    def __init__(self, parent=None):
        LOGGER.debug("initiating CheckVersionDialog")
        ExtendableDialog.__init__(self, parent)
        self.data_fetcher = DataFetcher(parent)
        self.config = MyConfigParser()

    def add_widgets(self):
        self.header_label = WarningLabel(
            _("Checking for updates.... please wait."))
        self.result_label = QtWidgets.QLabel("")
        self.result_label.setAlignment(QtCore.Qt.AlignCenter)
        self.result_label.setOpenExternalLinks(True)

        self.insertWidget(self.header_label)
        self.insertWidget(self.result_label)

        self.cancel_but.hide()
        self.apply_but.setText(_("OK"))
        self.enableApply()

        self.options_widget = OptionsWidget(self)
        self.options_widget.set_chosen_option(self.config.update_option)
        self.set_advanced_but_text(_("Options"))
        self.add_advanced_widget(self.options_widget)

    def show_result(self):
        LOGGER.debug("CheckVersionDialog show result")
        self.result = self.data_fetcher.result()
        if self.result is None:
            self.result_label.setText(
                "%s<br /><a href='%s'>%s</a>" %
                (_("Unable to connect to"), INFORMATION_URL, INFORMATION_URL))
            return
        if self.update_available:
            header_text = _("A newer version of OpenMolar is available")
            self.header_label.label.setStyleSheet("color: red")
        else:
            header_text = _("You are running the latest version - thankyou")

        self.header_label.setText(header_text)
        self.result_label.setText(MESSAGE % (self.new_version))

    def lookup_due(self):
        '''
        check the config file for user preferences on update check
        '''
        LOGGER.debug("checking user preferences for application update check")
        if self.config.update_option == self.NEVER:
            return False
        if self.config.update_option == self.MONTHLY:
            delta = timedelta(days=30)
        elif self.config.update_option == self.WEEKLY:
            delta = timedelta(days=7)
        elif self.config.update_option == self.DAILY:
            delta = timedelta(days=1)
        else:
            delta = timedelta(days=0)
        if self.config.last_check_date + delta > date.today():
            LOGGER.debug("update check not due yet")
            return False
        return True

    def hit_website(self):
        if not self.polling:
            LOGGER.info("polling website for latest release")
            self.polling = True
            self.data_fetcher.get_webdata()

    @property
    def update_available(self):
        '''
        a boolean to lookup whether a new version is available.
        '''
        LOGGER.debug("getting property update_available")
        try:
            if self.new_version[0] > localsettings.VERSION:
                LOGGER.info("There is a newer version available upstream")
                return True
            else:
                LOGGER.info("You are running the latest version - thankyou")
                return False
        except:
            LOGGER.exception("unknown error getting update available "
                             "perhaps the website returned garbage???")
            return False

    @property
    def new_version(self):
        if self._new_version is None:
            scp = configparser.ConfigParser()
            scp.read_string(self.result)
            version, release_date, message = "", None, ""
            try:
                try:
                    version = scp.get("RELEASE", "VERSION")
                except configparser.NoOptionError:
                    pass
                try:
                    release_date_string = scp.get("RELEASE", "DATE")
                    m = re.match(r"(\d+),(\d+),(\d+)", release_date_string)
                    if m:
                        release_date = date(int(m.groups()[0]),
                                            int(m.groups()[1]),
                                            int(m.groups()[2]))
                        self.checked_today = True
                    else:
                        LOGGER.warning("release date not in form 2016,03,09")
                except configparser.NoOptionError:
                    pass
                except ValueError:  # this will fire if a bad date is passed.
                    logging.exception("error parsing date field")
                try:
                    message = scp.get("RELEASE", "MESSAGE")
                except configparser.NoOptionError:
                    pass
            except configparser.NoSectionError:
                LOGGER.warning("unable to parse result of version checking")
            except configparser.MissingSectionHeaderError:
                pass
            self._new_version = (version,
                                 localsettings.formatDate(release_date),
                                 message.replace("\n", "<br />"))
        return self._new_version

    def background_exec(self):
        if self.lookup_due():
            self.data_fetcher.finished_signal.connect(self.exec_)
            self.hit_website()

    def exec_(self):
        LOGGER.debug("exec_ called by %s", self.sender())
        self.add_widgets()
        if self.sender() == self.data_fetcher:
            self.show_result()
            # lookup has been performed discreetly, only bother the user if
            # there is an update available
            if not self.update_available:
                return False
        else:
            self.data_fetcher.finished_signal.connect(self.show_result)
            QtCore.QTimer.singleShot(5000, self.hit_website)
        if ExtendableDialog.exec_(self):
            self.config.user_chosen_option = self.options_widget.chosen_option
            self.config.checked_today = self.checked_today
            self.config.write_config()