Example #1
0
    def delete_selected_files(self):
        button = QMessageBox.question(
            get_main_window(), 'Delete Files',
            'Irreversibly deleting selected files and directories.',
            QMessageBox.Ok, QMessageBox.Cancel)

        if not self.is_alive() or button != QMessageBox.Ok:
            return

        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) == 0:
            return

        script_instance_ref = [None]

        def progress_canceled():
            script_instance = script_instance_ref[0]

            if script_instance == None:
                return

            self.script_manager.abort_script(script_instance)

        progress = ExpandingProgressDialog(self)
        progress.set_progress_text_visible(False)
        progress.setModal(True)
        progress.setWindowTitle('Delete Files')
        progress.setLabelText('Collecting files and directories to delete')
        progress.setRange(0, 0)
        progress.canceled.connect(progress_canceled)
        progress.show()

        files_to_delete = []
        dirs_to_delete = []
        all_done = False

        while not all_done:
            all_done = True

            for selected_name_item in list(selected_name_items):
                item_done = False
                parent = selected_name_item.parent()

                while not item_done and parent != None:
                    if parent in selected_name_items:
                        selected_name_items.remove(selected_name_item)
                        item_done = True
                    else:
                        parent = parent.parent()

                if item_done:
                    all_done = False
                    break

        for selected_name_item in selected_name_items:
            path = get_full_item_path(selected_name_item)
            item_type = selected_name_item.data(USER_ROLE_ITEM_TYPE)

            if item_type == ITEM_TYPE_DIRECTORY:
                dirs_to_delete.append(posixpath.join(self.bin_directory, path))
            else:
                files_to_delete.append(posixpath.join(self.bin_directory,
                                                      path))

        message = 'Deleting '

        if len(files_to_delete) == 1:
            message += '1 file '
        elif len(files_to_delete) > 1:
            message += '{0} files '.format(len(files_to_delete))

        if len(dirs_to_delete) == 1:
            if len(files_to_delete) > 0:
                message += 'and '

            message += '1 directory'
        elif len(dirs_to_delete) > 1:
            if len(files_to_delete) > 0:
                message += 'and '

            message += '{0} directories'.format(len(dirs_to_delete))

        progress.setLabelText(message)

        def cb_delete(result):
            script_instance = script_instance_ref[0]

            if script_instance != None:
                aborted = script_instance.abort
            else:
                aborted = False

            script_instance_ref[0] = None

            progress.cancel()
            self.refresh_files()

            if aborted:
                QMessageBox.information(get_main_window(), 'Delete Files',
                                        'Delete operation was aborted.')
                return

            report_script_result(
                result, 'Delete Files Error',
                'Could not delete selected files/directories:')

        script_instance_ref[0] = self.script_manager.execute_script(
            'delete',
            cb_delete,
            [json.dumps(files_to_delete),
             json.dumps(dirs_to_delete)],
            execute_as_user=True)
Example #2
0
            def get_main_classes():
                script_instance_ref = [None]

                def progress_canceled():
                    script_instance = script_instance_ref[0]

                    if script_instance == None:
                        return

                    self.wizard().script_manager.abort_script(script_instance)

                progress = ExpandingProgressDialog(self.wizard())
                progress.set_progress_text_visible(False)
                progress.setWindowTitle('Edit Program')
                progress.setLabelText('Collecting Java main classes')
                progress.setModal(True)
                progress.setRange(0, 0)
                progress.canceled.connect(progress_canceled)
                progress.show()

                def cb_java_main_classes(result):
                    script_instance = script_instance_ref[0]

                    if script_instance != None:
                        aborted = script_instance.abort
                    else:
                        aborted = False

                    script_instance_ref[0] = None

                    def done():
                        progress.cancel()
                        self.combo_main_class.setEnabled(True)
                        self.completeChanged.emit()

                    if aborted:
                        done()
                        return

                    okay, message = check_script_result(result,
                                                        decode_stderr=True)

                    if not okay:
                        self.label_main_class_error.setText(
                            '<b>Error:</b> ' + html.escape(message))
                        self.label_main_class_error.setVisible(True)
                        done()
                        return

                    def expand_async(data):
                        try:
                            main_classes = json.loads(
                                zlib.decompress(
                                    memoryview(data)).decode('utf-8'))

                            if not isinstance(main_classes, dict):
                                main_classes = {}
                        except:
                            main_classes = {}

                        return main_classes

                    def cb_expand_success(main_classes):
                        self.combo_main_class.clear()

                        for cls in sorted(main_classes.keys()):
                            self.combo_main_class.addItem(
                                cls, main_classes[cls])

                        self.combo_main_class_checker.set_current_text(
                            program.cast_custom_option_value(
                                'java.main_class', str, ''))
                        done()

                    def cb_expand_error():
                        self.label_main_class_error.setText(
                            '<b>Error:</b> Internal async error')
                        self.label_main_class_error.setVisible(True)
                        done()

                    async_call(expand_async, result.stdout, cb_expand_success,
                               cb_expand_error)

                script_instance_ref[0] = self.wizard(
                ).script_manager.execute_script('java_main_classes',
                                                cb_java_main_classes,
                                                [self.bin_directory],
                                                max_length=1024 * 1024,
                                                decode_output_as_utf8=False)
Example #3
0
    def import_archive(self):
        source_path = self.edit_archive.text()

        if len(source_path) == 0:
            return

        script_instance_ref = [None]

        def progress_canceled():
            chunked_uploader = self.chunked_uploader

            if chunked_uploader != None:
                chunked_uploader.canceled = True

            script_instance = script_instance_ref[0]

            if script_instance != None:
                self.script_manager.abort_script(script_instance)

        self.progress = ExpandingProgressDialog(self)
        self.progress.set_progress_text_visible(False)
        self.progress.setModal(True)
        self.progress.setWindowTitle('Import Archive')
        self.progress.setLabelText('Step 1 of 4: Creating import directory')
        self.progress.setRange(0, 0)
        self.progress.setAutoClose(False)
        self.progress.canceled.connect(progress_canceled)
        self.progress.show()

        selected_identifiers = []

        for selected_item in self.tree_programs.selectedItems():
            selected_identifiers.append(selected_item.text(1))

        import_directory_ref = [None]

        def extract_archive():
            def cb_import_extract(result):
                script_instance = script_instance_ref[0]

                if script_instance != None:
                    aborted = script_instance.abort
                else:
                    aborted = False

                script_instance_ref[0] = None

                if aborted:
                    return

                if not report_script_result(
                        result,
                        'Import Error',
                        'Could not extract archive',
                        before_message_box=self.progress.close):
                    return

                def cb_restart_reboot_shutdown(result):
                    self.progress.close()

                    report_script_result(
                        result, 'Import Error',
                        'Could not reboot RED Brick to finish program import')

                # step 4/4: reboot
                self.progress.setLabelText('Step 4 of 4: Rebooting RED Brick')
                self.progress.setRange(0, 0)

                self.script_manager.execute_script(
                    'restart_reboot_shutdown_systemd',
                    cb_restart_reboot_shutdown, ['1'])

                def close_progress():
                    # use a closure to capture self and ansure that it's safe
                    # to call this even if the tab was official destroyed already
                    self.progress.close()

                QTimer.singleShot(1500, close_progress)

            # step 3/4: extract uploaded archive
            self.progress.setLabelText('Step 3 of 4: Extracting archive')
            self.progress.setRange(0, 0)

            script_instance_ref[0] = self.script_manager.execute_script(
                'import_extract', cb_import_extract,
                [import_directory_ref[0]] + selected_identifiers)

        def cb_import_directory(result):
            script_instance = script_instance_ref[0]

            if script_instance != None:
                aborted = script_instance.abort
            else:
                aborted = False

            script_instance_ref[0] = None

            if aborted:
                return

            if not report_script_result(
                    result,
                    'Import Error',
                    'Could not create import directory',
                    before_message_box=self.progress.close):
                return

            # step 2/4: upload archive to temporary import directory
            import_directory_ref[0] = result.stdout.strip()
            target_path = posixpath.join(import_directory_ref[0],
                                         'archive.tfrba')
            self.chunked_uploader = ChunkedUploader(self, extract_archive)

            if not self.chunked_uploader.prepare(source_path):
                return

            try:
                target_file = REDFile(self.session).open(
                    target_path, REDFile.FLAG_WRITE_ONLY | REDFile.FLAG_CREATE
                    | REDFile.FLAG_NON_BLOCKING | REDFile.FLAG_EXCLUSIVE,
                    0o644, 1000, 1000)  # FIXME: async_call
            except (Error, REDError) as e:
                QMessageBox.information(
                    get_main_window(), 'Import Error',
                    'Could not open target file {0}: {1}'.format(
                        target_path, e))
                return

            self.progress.setLabelText('Step 2 of 4: Uploading archive')
            self.progress.set_progress_text_visible(True)
            self.chunked_uploader.start(target_path, target_file)

        # step 1/4: create temporary import directory
        script_instance_ref[0] = self.script_manager.execute_script(
            'import_directory', cb_import_directory, execute_as_user=True)
Example #4
0
    def initializePage(self):
        self.set_formatted_sub_title(
            'Specify how the {language} program [{name}] should be executed.')

        self.update_combo_version('java', self.combo_version)

        self.combo_start_mode.setCurrentIndex(
            Constants.DEFAULT_JAVA_START_MODE)
        self.combo_jar_file_selector.reset()
        self.class_path_list_editor.reset()
        self.check_show_class_path.setChecked(False)
        self.check_show_advanced_options.setChecked(False)
        self.combo_working_directory_selector.reset()
        self.option_list_editor.reset()

        # if a program exists then this page is used in an edit wizard
        program = self.wizard().program

        if program != None:
            self.bin_directory = posixpath.join(program.root_directory, 'bin')
        else:
            identifier = self.get_field('identifier')
            self.bin_directory = posixpath.join('/', 'home', 'tf', 'programs',
                                                identifier, 'bin')

        # collect class path entries
        self.class_path_candidates = ['.']

        for filename in sorted(self.wizard().available_files):
            directroy = posixpath.split(filename)[0]

            if len(directroy
                   ) > 0 and directroy not in self.class_path_candidates:
                self.class_path_candidates.append(directroy)

            if filename.endswith('.class') or filename.endswith('.properties'):
                if program == None:
                    self.class_path_list_editor.add_item(directroy)
            elif filename.endswith('.jar'):
                self.class_path_candidates.append(filename)

                if program == None:
                    self.class_path_list_editor.add_item(filename)

        self.class_path_list_editor.add_item(
            '/usr/tinkerforge/bindings/java/Tinkerforge.jar')
        self.class_path_candidates.append(
            '/usr/tinkerforge/bindings/java/Tinkerforge.jar')

        self.combo_main_class.clear()
        self.combo_main_class.clearEditText()

        # collect main classes
        if program != None:
            self.combo_main_class.setEnabled(False)

            def get_main_classes():
                script_instance_ref = [None]

                def progress_canceled():
                    script_instance = script_instance_ref[0]

                    if script_instance == None:
                        return

                    self.wizard().script_manager.abort_script(script_instance)

                progress = ExpandingProgressDialog(self.wizard())
                progress.set_progress_text_visible(False)
                progress.setWindowTitle('Edit Program')
                progress.setLabelText('Collecting Java main classes')
                progress.setModal(True)
                progress.setRange(0, 0)
                progress.canceled.connect(progress_canceled)
                progress.show()

                def cb_java_main_classes(result):
                    script_instance = script_instance_ref[0]

                    if script_instance != None:
                        aborted = script_instance.abort
                    else:
                        aborted = False

                    script_instance_ref[0] = None

                    def done():
                        progress.cancel()
                        self.combo_main_class.setEnabled(True)
                        self.completeChanged.emit()

                    if aborted:
                        done()
                        return

                    okay, message = check_script_result(result,
                                                        decode_stderr=True)

                    if not okay:
                        self.label_main_class_error.setText(
                            '<b>Error:</b> ' + html.escape(message))
                        self.label_main_class_error.setVisible(True)
                        done()
                        return

                    def expand_async(data):
                        try:
                            main_classes = json.loads(
                                zlib.decompress(
                                    memoryview(data)).decode('utf-8'))

                            if not isinstance(main_classes, dict):
                                main_classes = {}
                        except:
                            main_classes = {}

                        return main_classes

                    def cb_expand_success(main_classes):
                        self.combo_main_class.clear()

                        for cls in sorted(main_classes.keys()):
                            self.combo_main_class.addItem(
                                cls, main_classes[cls])

                        self.combo_main_class_checker.set_current_text(
                            program.cast_custom_option_value(
                                'java.main_class', str, ''))
                        done()

                    def cb_expand_error():
                        self.label_main_class_error.setText(
                            '<b>Error:</b> Internal async error')
                        self.label_main_class_error.setVisible(True)
                        done()

                    async_call(expand_async, result.stdout, cb_expand_success,
                               cb_expand_error)

                script_instance_ref[0] = self.wizard(
                ).script_manager.execute_script('java_main_classes',
                                                cb_java_main_classes,
                                                [self.bin_directory],
                                                max_length=1024 * 1024,
                                                decode_output_as_utf8=False)

            # need to decouple this with a timer, otherwise it's executed at
            # a time where the progress bar cannot properly enter model state
            # to block the parent widget
            QTimer.singleShot(0, get_main_classes)
        elif self.wizard().hasVisitedPage(Constants.PAGE_FILES):
            uploads = self.wizard().page(Constants.PAGE_FILES).get_uploads()

            if len(uploads) > 0:
                abort_ref = [False]

                def progress_canceled():
                    abort_ref[0] = True

                progress = ExpandingProgressDialog(self)
                progress.set_progress_text_visible(False)
                progress.setWindowTitle('New Program')
                progress.setLabelText('Collecting Java main classes')
                progress.setModal(True)
                progress.setRange(0, 0)
                progress.canceled.connect(progress_canceled)
                progress.show()

                def cb_main_classes(main_classes):
                    for main_class in main_classes:
                        self.combo_main_class.addItem(main_class)

                    if self.combo_main_class.count() > 1:
                        self.combo_main_class.clearEditText()

                    progress.cancel()

                    self.combo_main_class.setEnabled(True)
                    self.completeChanged.emit()

                def cb_main_classes_error():
                    self.label_main_class_error.setText(
                        '<b>Error:</b> Internal async error')
                    self.label_main_class_error.setVisible(True)

                    progress.cancel()

                    self.combo_main_class.clearEditText()
                    self.combo_main_class.setEnabled(True)
                    self.completeChanged.emit()

                def get_main_classes_async(uploads):
                    return sorted(
                        get_main_classes_from_class_or_jar(uploads, abort_ref))

                self.combo_main_class.setEnabled(False)

                async_call(get_main_classes_async, uploads, cb_main_classes,
                           cb_main_classes_error)

        # if a program exists then this page is used in an edit wizard
        if program != None:
            # start mode
            start_mode_api_name = program.cast_custom_option_value(
                'java.start_mode', str, '<unknown>')
            start_mode = Constants.get_java_start_mode(start_mode_api_name)

            self.combo_start_mode.setCurrentIndex(start_mode)

            # main class
            self.combo_main_class_checker.set_current_text(
                program.cast_custom_option_value('java.main_class', str, ''))

            # jar file
            self.combo_jar_file_selector.set_current_text(
                program.cast_custom_option_value('java.jar_file', str, ''))

            # class path
            self.class_path_list_editor.clear()

            for class_path_entry in program.cast_custom_option_value_list(
                    'java.class_path', str, []):
                self.class_path_list_editor.add_item(class_path_entry)

            # working directory
            self.combo_working_directory_selector.set_current_text(
                program.working_directory)

            # options
            self.option_list_editor.clear()

            for option in program.cast_custom_option_value_list(
                    'java.options', str, []):
                self.option_list_editor.add_item(option)

        self.update_ui_state()
Example #5
0
    def export_archive(self):
        #FIXME: fromTime_t is obsolete: https://doc.qt.io/qt-5/qdatetime-obsolete.html#toTime_t
        timestamp   = QDateTime.fromTime_t(int(time.time())).toString('yyyyMMdd-HHmmss')
        target_path = os.path.join(self.last_directory, 'red-brick-export-{0}.tfrba'.format(timestamp))
        target_path = get_save_file_name(get_main_window(), 'Save Archive', target_path, 'Tinkerforge RED-Brick Archive(*.tfrba)')

        if len(target_path) == 0:
            return

        self.last_directory = os.path.split(target_path)[0]
        script_instance_ref = [None]

        def progress_canceled():
            script_instance = script_instance_ref[0]

            if script_instance != None:
                self.script_manager.abort_script(script_instance)

            chunked_downloader = self.chunked_downloader

            if chunked_downloader != None:
                chunked_downloader.canceled = True

        self.progress = ExpandingProgressDialog(self)
        self.progress.set_progress_text_visible(False)
        self.progress.setModal(True)
        self.progress.setWindowTitle('Export Archive')
        self.progress.setLabelText('Step 1 of 2: Archiving selected programs')
        self.progress.setRange(0, 0)
        self.progress.setAutoClose(False)
        self.progress.canceled.connect(progress_canceled)
        self.progress.show()

        selected_identifiers = []

        for selected_item in self.tree_programs.selectedItems():
            selected_identifiers.append(selected_item.text(1))

        def cb_export(result):
            script_instance = script_instance_ref[0]

            if script_instance != None:
                aborted = script_instance.abort
            else:
                aborted = False

            script_instance_ref[0] = None

            if aborted:
                return

            if not report_script_result(result, 'Export Error', 'Could not archive selected programs',
                                        before_message_box=self.progress.close):
                return

            # step 2/2: download created archive
            source_path             = posixpath.join(result.stdout.strip(), 'archive.tfrba')
            self.chunked_downloader = ChunkedDownloader(self)

            if not self.chunked_downloader.prepare(source_path):
                return

            self.progress.setLabelText('Step 2 of 2: Downloading archive')
            self.progress.set_progress_text_visible(True)
            self.chunked_downloader.start(target_path)

        # step 1/2: run export script to create archive
        script_instance_ref[0] = self.script_manager.execute_script('export', cb_export, selected_identifiers)