Пример #1
0
def show_survey():
    # If run for the first time, open a browser tab with a survey
    settings = QSettings()
    show_survey = settings.value("startup/show-survey", True, type=bool)
    if show_survey:
        question = QMessageBox(
            QMessageBox.Question, 'Orange Survey',
            'We would like to know more about how our software is used.\n\n'
            'Would you care to fill our short 1-minute survey?',
            QMessageBox.Yes | QMessageBox.No)
        question.setDefaultButton(QMessageBox.Yes)
        later = question.addButton('Ask again later', QMessageBox.NoRole)
        question.setEscapeButton(later)

        def handle_response(result):
            if result == QMessageBox.Yes:
                success = QDesktopServices.openUrl(
                    QUrl("https://orange.biolab.si/survey/short.html"))
                settings.setValue("startup/show-survey", not success)
            else:
                settings.setValue("startup/show-survey",
                                  result != QMessageBox.No)

        question.finished.connect(handle_response)
        question.show()
        return question
def compare_versions(latest):
    current = current_version()
    version = pkg_resources.parse_version
    if version(latest) <= version(current):
        return
    question = QMessageBox(QMessageBox.Information,
                           UPDATE_AVAILABLE_TITLE,
                           UPDATE_AVAILABLE_MESSAGE.format(
                               current_version=current, latest_version=latest),
                           textFormat=Qt.RichText)
    ok = question.addButton('Download Now', question.AcceptRole)
    question.setDefaultButton(ok)
    question.addButton('Remind Later', question.RejectRole)
    question.finished.connect(lambda: question.clickedButton() == ok and
                              QDesktopServices.openUrl(QUrl(DOWNLOAD_URL)))
    question.show()
Пример #3
0
def show_survey():
    # If run for the first time, open a browser tab with a survey
    settings = QSettings()
    show_survey = settings.value("startup/show-survey", True, type=bool)
    if show_survey:
        question = QMessageBox(
            QMessageBox.Question,
            'Orange Survey',
            'We would like to know more about how our software is used.\n\n'
            'Would you care to fill our short 1-minute survey?',
            QMessageBox.Yes | QMessageBox.No)
        question.setDefaultButton(QMessageBox.Yes)
        later = question.addButton('Ask again later', QMessageBox.NoRole)
        question.setEscapeButton(later)

        def handle_response(result):
            if result == QMessageBox.Yes:
                success = QDesktopServices.openUrl(
                    QUrl("https://orange.biolab.si/survey/short.html"))
                settings.setValue("startup/show-survey", not success)
            else:
                settings.setValue("startup/show-survey", result != QMessageBox.No)

        question.finished.connect(handle_response)
        question.show()
        return question
Пример #4
0
def track_user_stats():

    reply = get_usage_track_conf()

    if reply == 'ask later':

        m = QMessageBox(
            QMessageBox.Question,
            "User tracking",
            "Do you give us permission to track which country you are from and how many times you use this application? " \
            "This will contribute to the support of this software.",
            QMessageBox.Yes | QMessageBox.No | QMessageBox.NoRole
        )
        ask_later_btn = m.addButton("Ask me later", QMessageBox.NoRole)
        m.setEscapeButton(ask_later_btn)
        reply = m.exec_()

        if reply == QMessageBox.No:
            set_usage_track_conf('no-track')

        elif reply == QMessageBox.Yes:
            set_usage_track_conf('track')
            reply = 'track'

        elif reply == QMessageBox.NoButton:
            set_usage_track_conf('ask later')

    if reply == 'track':
        register_access()
def track_user_stats():

    reply = get_usage_track_conf()

    if reply=='ask later':

        m = QMessageBox(
            QMessageBox.Question,
            "User tracking",
            "Do you give us permission to track which country you are from and how many times you use this application? " \
            "This will contribute to the support of this software.",
            QMessageBox.Yes | QMessageBox.No | QMessageBox.NoRole
        )
        ask_later_btn = m.addButton("Ask me later", QMessageBox.NoRole)
        m.setEscapeButton(ask_later_btn)
        reply = m.exec_()

        if reply == QMessageBox.No:
            set_usage_track_conf('no-track')

        elif reply == QMessageBox.Yes:
            set_usage_track_conf('track')
            reply = 'track'

        elif reply == QMessageBox.NoButton:
            set_usage_track_conf('ask later')

    if reply=='track':
        register_access()
Пример #6
0
 def compare_versions(latest):
     if LooseVersion(latest) <= LooseVersion(current):
         return
     question = QMessageBox(
         QMessageBox.Information,
         'Orange Update Available',
         'A newer version of Orange is available.<br><br>'
         '<b>Current version:</b> {}<br>'
         '<b>Latest version:</b> {}'.format(current, latest),
         textFormat=Qt.RichText)
     ok = question.addButton('Download Now', question.AcceptRole)
     question.setDefaultButton(ok)
     question.addButton('Remind Later', question.RejectRole)
     question.finished.connect(
         lambda: question.clickedButton() == ok and QDesktopServices.
         openUrl(QUrl("https://orange.biolab.si/download/")))
     question.show()
Пример #7
0
 def compare_versions(latest):
     version = pkg_resources.parse_version
     if version(latest) <= version(current):
         return
     question = QMessageBox(
         QMessageBox.Information,
         'Orange Update Available',
         'A newer version of Orange is available.<br><br>'
         '<b>Current version:</b> {}<br>'
         '<b>Latest version:</b> {}'.format(current, latest),
         textFormat=Qt.RichText)
     ok = question.addButton('Download Now', question.AcceptRole)
     question.setDefaultButton(ok)
     question.addButton('Remind Later', question.RejectRole)
     question.finished.connect(
         lambda:
         question.clickedButton() == ok and
         QDesktopServices.openUrl(QUrl("https://orange.biolab.si/download/")))
     question.show()
Пример #8
0
 def compare_versions(latest):
     version = pkg_resources.parse_version
     if version(latest) <= version(current):
         return
     question = QMessageBox(
         QMessageBox.Information,
         "Orange Update Available",
         "A newer version of Orange is available.<br><br>"
         "<b>Current version:</b> {}<br>"
         "<b>Latest version:</b> {}".format(current, latest),
         textFormat=Qt.RichText,
     )
     ok = question.addButton("Download Now", question.AcceptRole)
     question.setDefaultButton(ok)
     question.addButton("Remind Later", question.RejectRole)
     question.finished.connect(
         lambda: question.clickedButton() == ok and QDesktopServices.
         openUrl(QUrl("https://orange.biolab.si/download/")))
     question.show()
Пример #9
0
    def fix_expressions(self):
        dlg = QMessageBox(
            QMessageBox.Question, "Fix Expressions",
            "This widget's behaviour has changed. Values of categorical "
            "variables are now inserted as their textual representations "
            "(strings); previously they appeared as integer numbers, with an "
            "attribute '.value' that contained the text.\n\n"
            "The widget currently runs in compatibility mode. After "
            "expressions are updated, manually check for their correctness.")
        dlg.addButton("Update", QMessageBox.ApplyRole)
        dlg.addButton("Cancel", QMessageBox.RejectRole)
        if dlg.exec() == QMessageBox.RejectRole:
            return

        def fixer(mo):
            var = domain[mo.group(2)]
            if mo.group(3) == ".value":  # uses string; remove `.value`
                return "".join(mo.group(1, 2, 4))
            # Uses ints: get them by indexing
            return mo.group(1) + "{" + \
                ", ".join(f"'{val}': {i}"
                          for i, val in enumerate(var.values)) + \
                f"}}[{var.name}]" + mo.group(4)

        domain = self.data.domain
        disc_vars = "|".join(f"{var.name}"
                             for var in chain(domain.variables, domain.metas)
                             if var.is_discrete)
        expr = re.compile(r"(^|\W)(" + disc_vars + r")(\.value)?(\W|$)")
        self.descriptors[:] = [
            descriptor._replace(
                expression=expr.sub(fixer, descriptor.expression))
            for descriptor in self.descriptors
        ]

        self.expressions_with_values = False
        self.fix_button.hide()
        index = self.currentIndex
        self.featuremodel[:] = list(self.descriptors)
        self.setCurrentIndex(index)
        self.apply()
Пример #10
0
def fix_extension(ext, format, suggested_ext, suggested_format):
    dlg = QMessageBox(
        QMessageBox.Warning, "Mismatching extension",
        "Extension '{}' does not match the chosen file format, {}.\n\n"
        "Would you like to fix this?".format(ext, format))
    role = QMessageBox.AcceptRole
    change_ext = \
        suggested_ext and \
        dlg.addButton("Change extension to " + suggested_ext, role)
    change_format =\
        suggested_format and \
        dlg.addButton("Save as " + suggested_format, role)
    cancel = dlg.addButton("Back", role)
    dlg.setEscapeButton(cancel)
    dlg.exec()
    if dlg.clickedButton() == cancel:
        return fix_extension.CANCEL
    elif dlg.clickedButton() == change_ext:
        return fix_extension.CHANGE_EXT
    elif dlg.clickedButton() == change_format:
        return fix_extension.CHANGE_FORMAT
Пример #11
0
def fix_extension(ext, format, suggested_ext, suggested_format):
    dlg = QMessageBox(
        QMessageBox.Warning,
        "Mismatching extension",
        "Extension '{}' does not match the chosen file format, {}.\n\n"
        "Would you like to fix this?".format(ext, format))
    role = QMessageBox.AcceptRole
    change_ext = \
        suggested_ext and \
        dlg.addButton("Change extension to " + suggested_ext, role)
    change_format =\
        suggested_format and \
        dlg.addButton("Save as " + suggested_format, role)
    cancel = dlg.addButton("Back", role)
    dlg.setEscapeButton(cancel)
    dlg.exec()
    if dlg.clickedButton() == cancel:
        return fix_extension.CANCEL
    elif dlg.clickedButton() == change_ext:
        return fix_extension.CHANGE_EXT
    elif dlg.clickedButton() == change_format:
        return fix_extension.CHANGE_FORMAT
Пример #12
0
def user_stats_question():

    title = "User tracking"
    msg = "Do you give us permission to track what country you are from and how many times you use this application? (We will not track your IP)"

    btns = QMessageBox.Yes | QMessageBox.No | QMessageBox.NoRole

    m = QMessageBox(QMessageBox.Question, title, msg, btns)
    ask_later_button = m.addButton("Ask me later", QMessageBox.NoRole)
    m.setEscapeButton(ask_later_button)

    reply = m.exec_()

    if reply == QMessageBox.No:
        return 'no'
    elif reply == QMessageBox.Yes:
        return 'yes'
    elif reply == QMessageBox.NoButton:
        return 'ask later'
Пример #13
0
def main(argv=None):
    if argv is None:
        argv = sys.argv

    usage = "usage: %prog [options] [workflow_file]"
    parser = optparse.OptionParser(usage=usage)

    parser.add_option("--no-discovery",
                      action="store_true",
                      help="Don't run widget discovery "
                      "(use full cache instead)")
    parser.add_option("--force-discovery",
                      action="store_true",
                      help="Force full widget discovery "
                      "(invalidate cache)")
    parser.add_option("--clear-widget-settings",
                      action="store_true",
                      help="Remove stored widget setting")
    parser.add_option("--no-welcome",
                      action="store_true",
                      help="Don't show welcome dialog.")
    parser.add_option("--no-splash",
                      action="store_true",
                      help="Don't show splash screen.")
    parser.add_option("-l",
                      "--log-level",
                      help="Logging level (0, 1, 2, 3, 4)",
                      type="int",
                      default=1)
    parser.add_option("--style",
                      help="QStyle to use",
                      type="str",
                      default=None)
    parser.add_option("--stylesheet",
                      help="Application level CSS style sheet to use",
                      type="str",
                      default="orange.qss")
    parser.add_option("--qt",
                      help="Additional arguments for QApplication",
                      type="str",
                      default=None)

    (options, args) = parser.parse_args(argv[1:])

    levels = [
        logging.CRITICAL, logging.ERROR, logging.WARN, logging.INFO,
        logging.DEBUG
    ]

    # Fix streams before configuring logging (otherwise it will store
    # and write to the old file descriptors)
    fix_win_pythonw_std_stream()

    # Try to fix fonts on OSX Mavericks
    fix_osx_10_9_private_font()

    # File handler should always be at least INFO level so we need
    # the application root level to be at least at INFO.
    root_level = min(levels[options.log_level], logging.INFO)
    rootlogger = logging.getLogger(canvas.__name__)
    rootlogger.setLevel(root_level)

    # Initialize SQL query and execution time logger (in SqlTable)
    sql_level = min(levels[options.log_level], logging.INFO)
    make_sql_logger(sql_level)

    # Standard output stream handler at the requested level
    stream_hander = logging.StreamHandler()
    stream_hander.setLevel(level=levels[options.log_level])
    rootlogger.addHandler(stream_hander)

    log.info("Starting 'Orange Canvas' application.")

    qt_argv = argv[:1]

    if options.style is not None:
        qt_argv += ["-style", options.style]

    if options.qt is not None:
        qt_argv += shlex.split(options.qt)

    qt_argv += args

    log.debug("Starting CanvasApplicaiton with argv = %r.", qt_argv)
    app = CanvasApplication(qt_argv)

    # NOTE: config.init() must be called after the QApplication constructor
    config.init()

    clear_settings_flag = os.path.join(config.widget_settings_dir(),
                                       "DELETE_ON_START")

    if options.clear_widget_settings or \
            os.path.isfile(clear_settings_flag):
        log.info("Clearing widget settings")
        shutil.rmtree(config.widget_settings_dir(), ignore_errors=True)

    file_handler = logging.FileHandler(filename=os.path.join(
        config.log_dir(), "canvas.log"),
                                       mode="w")

    file_handler.setLevel(root_level)
    rootlogger.addHandler(file_handler)

    # intercept any QFileOpenEvent requests until the main window is
    # fully initialized.
    # NOTE: The QApplication must have the executable ($0) and filename
    # arguments passed in argv otherwise the FileOpen events are
    # triggered for them (this is done by Cocoa, but QApplicaiton filters
    # them out if passed in argv)

    open_requests = []

    def onrequest(url):
        log.info("Received an file open request %s", url)
        open_requests.append(url)

    app.fileOpenRequest.connect(onrequest)

    settings = QSettings()

    stylesheet = options.stylesheet
    stylesheet_string = None

    if stylesheet != "none":
        if os.path.isfile(stylesheet):
            stylesheet_string = open(stylesheet, "rb").read()
        else:
            if not os.path.splitext(stylesheet)[1]:
                # no extension
                stylesheet = os.path.extsep.join([stylesheet, "qss"])

            pkg_name = canvas.__name__
            resource = "styles/" + stylesheet

            if pkg_resources.resource_exists(pkg_name, resource):
                stylesheet_string = \
                    pkg_resources.resource_string(pkg_name, resource).decode()

                base = pkg_resources.resource_filename(pkg_name, "styles")

                pattern = re.compile(
                    r"^\s@([a-zA-Z0-9_]+?)\s*:\s*([a-zA-Z0-9_/]+?);\s*$",
                    flags=re.MULTILINE)

                matches = pattern.findall(stylesheet_string)

                for prefix, search_path in matches:
                    QDir.addSearchPath(prefix, os.path.join(base, search_path))
                    log.info("Adding search path %r for prefix, %r",
                             search_path, prefix)

                stylesheet_string = pattern.sub("", stylesheet_string)

            else:
                log.info("%r style sheet not found.", stylesheet)

    # Add the default canvas_icons search path
    dirpath = os.path.abspath(os.path.dirname(canvas.__file__))
    QDir.addSearchPath("canvas_icons", os.path.join(dirpath, "icons"))

    canvas_window = CanvasMainWindow()
    canvas_window.setWindowIcon(config.application_icon())

    if stylesheet_string is not None:
        canvas_window.setStyleSheet(stylesheet_string)

    if not options.force_discovery:
        reg_cache = cache.registry_cache()
    else:
        reg_cache = None

    widget_discovery = qt.QtWidgetDiscovery(cached_descriptions=reg_cache)

    widget_registry = qt.QtWidgetRegistry()

    widget_discovery.found_category.connect(widget_registry.register_category)
    widget_discovery.found_widget.connect(widget_registry.register_widget)

    want_splash = \
        settings.value("startup/show-splash-screen", True, type=bool) and \
        not options.no_splash

    if want_splash:
        pm, rect = config.splash_screen()
        splash_screen = SplashScreen(pixmap=pm, textRect=rect)
        splash_screen.setFont(QFont("Helvetica", 12))
        color = QColor("#FFD39F")

        def show_message(message):
            splash_screen.showMessage(message, color=color)

        widget_discovery.discovery_start.connect(splash_screen.show)
        widget_discovery.discovery_process.connect(show_message)
        widget_discovery.discovery_finished.connect(splash_screen.hide)

    log.info("Running widget discovery process.")

    cache_filename = os.path.join(cache_dir(), "widget-registry.pck")
    if options.no_discovery:
        widget_registry = pickle.load(open(cache_filename, "rb"))
        widget_registry = qt.QtWidgetRegistry(widget_registry)
    else:
        widget_discovery.run(config.widgets_entry_points())
        # Store cached descriptions
        cache.save_registry_cache(widget_discovery.cached_descriptions)
        pickle.dump(WidgetRegistry(widget_registry),
                    open(cache_filename, "wb"))
    set_global_registry(widget_registry)
    canvas_window.set_widget_registry(widget_registry)
    canvas_window.show()
    canvas_window.raise_()

    want_welcome = \
        settings.value("startup/show-welcome-screen", True, type=bool) \
        and not options.no_welcome

    # Process events to make sure the canvas_window layout has
    # a chance to activate (the welcome dialog is modal and will
    # block the event queue, plus we need a chance to receive open file
    # signals when running without a splash screen)
    app.processEvents()

    app.fileOpenRequest.connect(canvas_window.open_scheme_file)

    if want_welcome and not args and not open_requests:
        canvas_window.welcome_dialog()

    elif args:
        log.info("Loading a scheme from the command line argument %r", args[0])
        canvas_window.load_scheme(args[0])
    elif open_requests:
        log.info("Loading a scheme from an `QFileOpenEvent` for %r",
                 open_requests[-1])
        canvas_window.load_scheme(open_requests[-1].toLocalFile())

    # If run for the first time, open a browser tab with a survey
    show_survey = settings.value("startup/show-survey", True, type=bool)
    if show_survey:
        question = QMessageBox(
            QMessageBox.Question, 'Orange Survey',
            'We would like to know more about how our software is used.\n\n'
            'Would you care to fill our short 1-minute survey?',
            QMessageBox.Yes | QMessageBox.No)
        question.setDefaultButton(QMessageBox.Yes)
        later = question.addButton('Ask again later', QMessageBox.NoRole)
        question.setEscapeButton(later)

        def handle_response(result):
            if result == QMessageBox.Yes:
                success = QDesktopServices.openUrl(
                    QUrl("http://orange.biolab.si/survey/short.html"))
                settings.setValue("startup/show-survey", not success)
            else:
                settings.setValue("startup/show-survey",
                                  result != QMessageBox.No)

        question.finished.connect(handle_response)
        question.show()

    # Tee stdout and stderr into Output dock
    log_view = canvas_window.log_view()

    stdout = TextStream()
    stdout.stream.connect(log_view.write)
    if sys.stdout:
        stdout.stream.connect(sys.stdout.write)
        stdout.flushed.connect(sys.stdout.flush)

    stderr = TextStream()
    error_writer = log_view.formated(color=Qt.red)
    stderr.stream.connect(error_writer.write)
    if sys.stderr:
        stderr.stream.connect(sys.stderr.write)
        stderr.flushed.connect(sys.stderr.flush)

    log.info("Entering main event loop.")
    try:
        with patch('sys.excepthook',
                   ExceptHook(stream=stderr, canvas=canvas_window,
                              handledException=handle_exception)),\
             patch('sys.stderr', stderr),\
             patch('sys.stdout', stdout):
            status = app.exec_()
    except BaseException:
        log.error("Error in main event loop.", exc_info=True)

    canvas_window.deleteLater()
    app.processEvents()
    app.flush()
    del canvas_window

    # Collect any cycles before deleting the QApplication instance
    gc.collect()

    del app
    return status
Пример #14
0
    def get_table(self):
        if self.tablecombo.currentIndex() <= 0:
            if self.database_desc:
                self.database_desc["Table"] = "(None)"
            self.data_desc_table = None
            return

        if self.tablecombo.currentIndex() < self.tablecombo.count() - 1:
            self.table = self.tablemodel[self.tablecombo.currentIndex()]
            self.database_desc["Table"] = self.table
            if "Query" in self.database_desc:
                del self.database_desc["Query"]
        else:
            self.sql = self.table = self.sqltext.toPlainText()
            if self.materialize:
                import psycopg2
                if not self.materialize_table_name:
                    self.Error.connection(
                        "Specify a table name to materialize the query")
                    return
                try:
                    with self.backend.execute_sql_query(
                            "DROP TABLE IF EXISTS " +
                            self.materialize_table_name):
                        pass
                    with self.backend.execute_sql_query(
                            "CREATE TABLE " + self.materialize_table_name +
                            " AS " + self.table):
                        pass
                    with self.backend.execute_sql_query(
                            "ANALYZE " + self.materialize_table_name):
                        pass
                    self.table = self.materialize_table_name
                except (psycopg2.ProgrammingError, BackendError) as ex:
                    self.Error.connection(str(ex))
                    return

        try:
            table = SqlTable(dict(host=self.host,
                                  port=self.port,
                                  database=self.database,
                                  user=self.username,
                                  password=self.password),
                             self.table,
                             backend=type(self.backend),
                             inspect_values=False)
        except BackendError as ex:
            self.Error.connection(str(ex))
            return

        self.Error.connection.clear()

        sample = False
        if table.approx_len() > LARGE_TABLE and self.guess_values:
            confirm = QMessageBox(self)
            confirm.setIcon(QMessageBox.Warning)
            confirm.setText("Attribute discovery might take "
                            "a long time on large tables.\n"
                            "Do you want to auto discover attributes?")
            confirm.addButton("Yes", QMessageBox.YesRole)
            no_button = confirm.addButton("No", QMessageBox.NoRole)
            sample_button = confirm.addButton("Yes, on a sample",
                                              QMessageBox.YesRole)
            confirm.exec()
            if confirm.clickedButton() == no_button:
                self.guess_values = False
            elif confirm.clickedButton() == sample_button:
                sample = True

        self.Information.clear()
        if self.guess_values:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            if sample:
                s = table.sample_time(1)
                domain = s.get_domain(inspect_values=True)
                self.Information.data_sampled()
            else:
                domain = table.get_domain(inspect_values=True)
            QApplication.restoreOverrideCursor()
            table.domain = domain

        if self.download:
            if table.approx_len() > MAX_DL_LIMIT:
                QMessageBox.warning(
                    self, 'Warning', "Data is too big to download.\n"
                    "Consider using the Data Sampler widget to download "
                    "a sample instead.")
                self.download = False
            elif table.approx_len() > AUTO_DL_LIMIT:
                confirm = QMessageBox.question(
                    self, 'Question', "Data appears to be big. Do you really "
                    "want to download it to local memory?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if confirm == QMessageBox.No:
                    self.download = False
        if self.download:
            table.download_data(MAX_DL_LIMIT)
            table = Table(table)

        return table
Пример #15
0
    def get_table(self):
        curIdx = self.tablecombo.currentIndex()
        if curIdx <= 0:
            if self.database_desc:
                self.database_desc["Table"] = "(None)"
            self.data_desc_table = None
            return

        if self.tablecombo.itemText(curIdx) != "Custom SQL":
            self.table = self.tables[self.tablecombo.currentIndex()]
            self.database_desc["Table"] = self.table
            if "Query" in self.database_desc:
                del self.database_desc["Query"]
            what = self.table
        else:
            what = self.sql = self.sqltext.toPlainText()
            self.table = "Custom SQL"
            if self.materialize:
                import psycopg2
                if not self.materialize_table_name:
                    self.Error.connection(
                        "Specify a table name to materialize the query")
                    return
                try:
                    with self.backend.execute_sql_query("DROP TABLE IF EXISTS " +
                                                        self.materialize_table_name):
                        pass
                    with self.backend.execute_sql_query("CREATE TABLE " +
                                                        self.materialize_table_name +
                                                        " AS " + self.sql):
                        pass
                    with self.backend.execute_sql_query("ANALYZE " + self.materialize_table_name):
                        pass
                except (psycopg2.ProgrammingError, BackendError) as ex:
                    self.Error.connection(str(ex))
                    return

        try:
            table = SqlTable(dict(host=self.host,
                                  port=self.port,
                                  database=self.database,
                                  user=self.username,
                                  password=self.password),
                             what,
                             backend=type(self.backend),
                             inspect_values=False)
        except BackendError as ex:
            self.Error.connection(str(ex))
            return

        self.Error.connection.clear()

        sample = False

        if table.approx_len() > LARGE_TABLE and self.guess_values:
            confirm = QMessageBox(self)
            confirm.setIcon(QMessageBox.Warning)
            confirm.setText("Attribute discovery might take "
                            "a long time on large tables.\n"
                            "Do you want to auto discover attributes?")
            confirm.addButton("Yes", QMessageBox.YesRole)
            no_button = confirm.addButton("No", QMessageBox.NoRole)
            sample_button = confirm.addButton("Yes, on a sample",
                                              QMessageBox.YesRole)
            confirm.exec()
            if confirm.clickedButton() == no_button:
                self.guess_values = False
            elif confirm.clickedButton() == sample_button:
                sample = True

        self.Information.clear()
        if self.guess_values:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            if sample:
                s = table.sample_time(1)
                domain = s.get_domain(inspect_values=True)
                self.Information.data_sampled()
            else:
                domain = table.get_domain(inspect_values=True)
            QApplication.restoreOverrideCursor()
            table.domain = domain

        if self.download:
            if table.approx_len() > MAX_DL_LIMIT:
                QMessageBox.warning(
                    self, 'Warning', "Data is too big to download.\n"
                    "Consider using the Data Sampler widget to download "
                    "a sample instead.")
                self.download = False
            elif table.approx_len() > AUTO_DL_LIMIT:
                confirm = QMessageBox.question(
                    self, 'Question', "Data appears to be big. Do you really "
                                      "want to download it to local memory?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if confirm == QMessageBox.No:
                    self.download = False
        if self.download:
            table.download_data(MAX_DL_LIMIT)
            table = Table(table)

        return table
Пример #16
0
def main(argv=None):
    if argv is None:
        argv = sys.argv

    usage = "usage: %prog [options] [workflow_file]"
    parser = optparse.OptionParser(usage=usage)

    parser.add_option("--no-discovery",
                      action="store_true",
                      help="Don't run widget discovery "
                           "(use full cache instead)")
    parser.add_option("--force-discovery",
                      action="store_true",
                      help="Force full widget discovery "
                           "(invalidate cache)")
    parser.add_option("--clear-widget-settings",
                      action="store_true",
                      help="Remove stored widget setting")
    parser.add_option("--no-welcome",
                      action="store_true",
                      help="Don't show welcome dialog.")
    parser.add_option("--no-splash",
                      action="store_true",
                      help="Don't show splash screen.")
    parser.add_option("-l", "--log-level",
                      help="Logging level (0, 1, 2, 3, 4)",
                      type="int", default=1)
    parser.add_option("--style",
                      help="QStyle to use",
                      type="str", default=None)
    parser.add_option("--stylesheet",
                      help="Application level CSS style sheet to use",
                      type="str", default="orange.qss")
    parser.add_option("--qt",
                      help="Additional arguments for QApplication",
                      type="str", default=None)

    (options, args) = parser.parse_args(argv[1:])

    levels = [logging.CRITICAL,
              logging.ERROR,
              logging.WARN,
              logging.INFO,
              logging.DEBUG]

    # Fix streams before configuring logging (otherwise it will store
    # and write to the old file descriptors)
    fix_win_pythonw_std_stream()

    # Try to fix fonts on OSX Mavericks
    fix_osx_10_9_private_font()

    # File handler should always be at least INFO level so we need
    # the application root level to be at least at INFO.
    root_level = min(levels[options.log_level], logging.INFO)
    rootlogger = logging.getLogger(canvas.__name__)
    rootlogger.setLevel(root_level)

    # Initialize SQL query and execution time logger (in SqlTable)
    sql_level = min(levels[options.log_level], logging.INFO)
    make_sql_logger(sql_level)

    # Standard output stream handler at the requested level
    stream_hander = logging.StreamHandler()
    stream_hander.setLevel(level=levels[options.log_level])
    rootlogger.addHandler(stream_hander)

    log.info("Starting 'Orange Canvas' application.")

    qt_argv = argv[:1]

    if options.style is not None:
        qt_argv += ["-style", options.style]

    if options.qt is not None:
        qt_argv += shlex.split(options.qt)

    qt_argv += args

    log.debug("Starting CanvasApplicaiton with argv = %r.", qt_argv)
    app = CanvasApplication(qt_argv)

    # NOTE: config.init() must be called after the QApplication constructor
    config.init()

    clear_settings_flag = os.path.join(
        config.widget_settings_dir(), "DELETE_ON_START")

    if options.clear_widget_settings or \
            os.path.isfile(clear_settings_flag):
        log.info("Clearing widget settings")
        shutil.rmtree(
            config.widget_settings_dir(),
            ignore_errors=True)

    file_handler = logging.FileHandler(
        filename=os.path.join(config.log_dir(), "canvas.log"),
        mode="w"
    )

    file_handler.setLevel(root_level)
    rootlogger.addHandler(file_handler)

    # intercept any QFileOpenEvent requests until the main window is
    # fully initialized.
    # NOTE: The QApplication must have the executable ($0) and filename
    # arguments passed in argv otherwise the FileOpen events are
    # triggered for them (this is done by Cocoa, but QApplicaiton filters
    # them out if passed in argv)

    open_requests = []

    def onrequest(url):
        log.info("Received an file open request %s", url)
        open_requests.append(url)

    app.fileOpenRequest.connect(onrequest)

    settings = QSettings()

    stylesheet = options.stylesheet
    stylesheet_string = None

    if stylesheet != "none":
        if os.path.isfile(stylesheet):
            stylesheet_string = open(stylesheet, "rb").read()
        else:
            if not os.path.splitext(stylesheet)[1]:
                # no extension
                stylesheet = os.path.extsep.join([stylesheet, "qss"])

            pkg_name = canvas.__name__
            resource = "styles/" + stylesheet

            if pkg_resources.resource_exists(pkg_name, resource):
                stylesheet_string = \
                    pkg_resources.resource_string(pkg_name, resource).decode()

                base = pkg_resources.resource_filename(pkg_name, "styles")

                pattern = re.compile(
                    r"^\s@([a-zA-Z0-9_]+?)\s*:\s*([a-zA-Z0-9_/]+?);\s*$",
                    flags=re.MULTILINE
                )

                matches = pattern.findall(stylesheet_string)

                for prefix, search_path in matches:
                    QDir.addSearchPath(prefix, os.path.join(base, search_path))
                    log.info("Adding search path %r for prefix, %r",
                             search_path, prefix)

                stylesheet_string = pattern.sub("", stylesheet_string)

            else:
                log.info("%r style sheet not found.", stylesheet)

    # Add the default canvas_icons search path
    dirpath = os.path.abspath(os.path.dirname(canvas.__file__))
    QDir.addSearchPath("canvas_icons", os.path.join(dirpath, "icons"))

    canvas_window = CanvasMainWindow()
    canvas_window.setWindowIcon(config.application_icon())

    if stylesheet_string is not None:
        canvas_window.setStyleSheet(stylesheet_string)

    if not options.force_discovery:
        reg_cache = cache.registry_cache()
    else:
        reg_cache = None

    widget_discovery = qt.QtWidgetDiscovery(cached_descriptions=reg_cache)

    widget_registry = qt.QtWidgetRegistry()

    widget_discovery.found_category.connect(
        widget_registry.register_category
    )
    widget_discovery.found_widget.connect(
        widget_registry.register_widget
    )

    want_splash = \
        settings.value("startup/show-splash-screen", True, type=bool) and \
        not options.no_splash

    if want_splash:
        pm, rect = config.splash_screen()
        splash_screen = SplashScreen(pixmap=pm, textRect=rect)
        splash_screen.setFont(QFont("Helvetica", 12))
        color = QColor("#FFD39F")

        def show_message(message):
            splash_screen.showMessage(message, color=color)

        widget_discovery.discovery_start.connect(splash_screen.show)
        widget_discovery.discovery_process.connect(show_message)
        widget_discovery.discovery_finished.connect(splash_screen.hide)

    log.info("Running widget discovery process.")

    cache_filename = os.path.join(cache_dir(), "widget-registry.pck")
    if options.no_discovery:
        widget_registry = pickle.load(open(cache_filename, "rb"))
        widget_registry = qt.QtWidgetRegistry(widget_registry)
    else:
        widget_discovery.run(config.widgets_entry_points())
        # Store cached descriptions
        cache.save_registry_cache(widget_discovery.cached_descriptions)
        pickle.dump(WidgetRegistry(widget_registry),
                     open(cache_filename, "wb"))
    set_global_registry(widget_registry)
    canvas_window.set_widget_registry(widget_registry)
    canvas_window.show()
    canvas_window.raise_()

    want_welcome = \
        settings.value("startup/show-welcome-screen", True, type=bool) \
        and not options.no_welcome

    # Process events to make sure the canvas_window layout has
    # a chance to activate (the welcome dialog is modal and will
    # block the event queue, plus we need a chance to receive open file
    # signals when running without a splash screen)
    app.processEvents()

    app.fileOpenRequest.connect(canvas_window.open_scheme_file)

    if want_welcome and not args and not open_requests:
        canvas_window.welcome_dialog()

    elif args:
        log.info("Loading a scheme from the command line argument %r",
                 args[0])
        canvas_window.load_scheme(args[0])
    elif open_requests:
        log.info("Loading a scheme from an `QFileOpenEvent` for %r",
                 open_requests[-1])
        canvas_window.load_scheme(open_requests[-1].toLocalFile())

    # If run for the first time, open a browser tab with a survey
    show_survey = settings.value("startup/show-survey", True, type=bool)
    if show_survey:
        question = QMessageBox(
            QMessageBox.Question,
            'Orange Survey',
            'We would like to know more about how our software is used.\n\n'
            'Would you care to fill our short 1-minute survey?',
            QMessageBox.Yes | QMessageBox.No)
        question.setDefaultButton(QMessageBox.Yes)
        later = question.addButton('Ask again later', QMessageBox.NoRole)
        question.setEscapeButton(later)

        def handle_response(result):
            if result == QMessageBox.Yes:
                success = QDesktopServices.openUrl(
                    QUrl("http://orange.biolab.si/survey/short.html"));
                settings.setValue("startup/show-survey", not success)
            else:
                settings.setValue("startup/show-survey", result != QMessageBox.No)

        question.finished.connect(handle_response)
        question.show()

    # Tee stdout and stderr into Output dock
    log_view = canvas_window.log_view()

    stdout = TextStream()
    stdout.stream.connect(log_view.write)
    if sys.stdout:
        stdout.stream.connect(sys.stdout.write)
        stdout.flushed.connect(sys.stdout.flush)

    stderr = TextStream()
    error_writer = log_view.formated(color=Qt.red)
    stderr.stream.connect(error_writer.write)
    if sys.stderr:
        stderr.stream.connect(sys.stderr.write)
        stderr.flushed.connect(sys.stderr.flush)

    log.info("Entering main event loop.")
    try:
        with patch('sys.excepthook',
                   ExceptHook(stream=stderr, canvas=canvas_window,
                              handledException=handle_exception)),\
             patch('sys.stderr', stderr),\
             patch('sys.stdout', stdout):
            status = app.exec_()
    except BaseException:
        log.error("Error in main event loop.", exc_info=True)

    canvas_window.deleteLater()
    app.processEvents()
    app.flush()
    del canvas_window

    # Collect any cycles before deleting the QApplication instance
    gc.collect()

    del app
    return status