예제 #1
0
파일: main.py 프로젝트: fashni/IndoseCT
  def _load_files(self, fnames):
    # if self.ctx.isImage:
    self.on_close_image()
    self.statusBar().showMessage('Loading Images')
    n = len(fnames)
    progress = QProgressDialog(f"Loading {n} images...", "Cancel", 0, n, self)
    progress.setWindowModality(Qt.WindowModal)
    progress.setMinimumDuration(1000) # operation shorter than 1 sec will not open progress dialog
    files = []
    for idx, filename in enumerate(fnames):
      dcm = get_dicom(filename)
      files.append(dcm)
      progress.setValue(idx)
      if progress.wasCanceled():
        break
    progress.setValue(n)

    if not files:
      progress.cancel()
      if self.fsource=='dir':
        QMessageBox.information(None, "Info", "No DICOM files in the selected directory.")
      elif self.fsource=='sample':
        QMessageBox.information(None, "Info", "No DICOM files in sample directory.")
      elif self.fsource=='files':
        QMessageBox.warning(None, "Info", "The specified file is not a valid DICOM file.")
      return

    self.ctx.isImage = True
    self.ctx.dicoms, dc = self.filter_invalid(files)
    if dc>0:
      f = 'files' if dc>1 else 'file'
      QMessageBox.warning(None, "Unsupported format", f"Cannot load {dc} {f}.")

    self.ctx.total_img = len(self.ctx.dicoms)
    self.total_lbl.setText(str(self.ctx.total_img))
    self.ctx.current_img = 1
    self.update_image()
    self.ctx.app_data.emit_img_loaded(True)

    self.go_to_slice_sb.setValue(self.ctx.current_img)
    self.go_to_slice_sb.setMinimum(self.ctx.current_img)
    self.go_to_slice_sb.setMaximum(self.ctx.total_img)

    self.get_patient_info()
    phantom_id = int(not self.patient_info['protocol'].upper() in ['HEAD', 'HEADNECK', 'NECK']) if self.patient_info['protocol'] is not None else 1
    self.phantom_cb.setCurrentIndex(phantom_id)
    self.on_phantom_update(phantom_id)
    self.info_panel.setInfo(self.patient_info)
    self.dcmtree_btn.setEnabled(True)
    self.close_img_btn.setEnabled(True)
    self.windowing_cb.setEnabled(True)
    self.sort_btn.setEnabled(True)
    self.adjust_slices()
def showbarprocess(content):
    num = int(100000)
    progress = QProgressDialog()
    progress.setWindowTitle("Processing ...")
    progress.setLabelText(content)
    progress.setCancelButton(None)  ##不显示cancel button
    #progress.setCancelButtonText("")
    progress.setMinimumDuration(5)
    progress.setWindowModality(Qt.WindowModal)
    progress.setRange(0, num)
    for i in range(num):
        progress.setValue(i)

    else:
        progress.setValue(num)

    progress.cancel()
예제 #3
0
    def _start(self, type_file, sleep_time, new_file, output_file):
        progress = QProgressDialog(NAME_PROGRESS_BAR,
                                   "",
                                   0,
                                   100,
                                   parent=self.window)
        progress.setWindowModality(Qt.WindowModal)
        progress.setCancelButton(None)
        progress.setWindowFlags(progress.windowFlags()
                                & ~Qt.WindowCloseButtonHint)
        progress.setMinimumDuration(0)

        thread = Thread(self.window, type_file, new_file, output_file)
        thread.start()

        while not thread.isFinished() or progress.value() != 99:
            loop = QEventLoop()
            QTimer.singleShot(sleep_time if not thread.isFinished() else 100,
                              loop.quit)
            loop.exec_()
            if progress.value() == 99:
                continue
            progress.setValue(progress.value() + 1)
        progress.cancel()
예제 #4
0
class ProgressCallbackWidget(ClientCallback):
    def __init__(self, parent):
        ClientCallback.__init__(self)

        self._parent = parent
        self._block = False

        self._label_text = ''
        self._title_text = ''
        self._updated_text = ''
        self._finished_text = ''
        self._cancellable = True

        self.status_progress = QProgressDialog(self._parent, Qt.Dialog)

        self.set_range(0, 1)

    def __del__(self):
        self.status_progress.close()
        del self.status_progress

    def set_block(self, block):
        self._block = block

    def set_title_text(self, title_text):
        self._title_text = title_text

    def set_label_text(self, label_text):
        self._label_text = label_text

    def set_updated_text(self, updated_text):
        self._updated_text = updated_text

    def set_finished_text(self, finished_label):
        self._finished_text = finished_label

    def set_cancellable(self, cancellable):
        if not self._cancellable and cancellable:
            log.warning(
                'ProgressCallbackWidget.set_cancellable({cancellable}): invalid operation'
                .format(cancellable=cancellable))
        if cancellable:
            if not self._cancellable:
                self.status_progress.setCancelButton(QPushButton(_('Cancel')))
        else:
            self.status_progress.setCancelButton(None)
        self._cancellable = cancellable

    def on_show(self):
        # FIXME: status_progress may be None if on_update is called BEFORE show..
        # FIXME: rename to start..
        self.status_progress.reset()

        self.set_block(self._block)
        self.set_cancellable(self._cancellable)

        self.status_progress.setWindowTitle(self._title_text)
        self.status_progress.setLabelText(self._label_text)

        minimum, maximum = self.get_range()

        self.status_progress.setMinimum(minimum)
        self.status_progress.setMaximum(maximum)

        self.status_progress.show()
        if self._block:
            self._parent.setCursor(Qt.WaitCursor)

    def on_update(self, value, *args, **kwargs):
        self.status_progress.setValue(value)
        if self._updated_text:
            # FIXME: let the caller format the strings
            updatedMsg = self._updated_text.format(*args)
            self.status_progress.setLabelText(updatedMsg)
        QCoreApplication.processEvents()

    def on_finish(self, *args, **kwargs):
        # FIXME: let the caller format the strings
        finishedMsg = self._finished_text.format(*args)
        self.status_progress.setLabelText(finishedMsg)
        self.status_progress.done(0)
        if self._block:
            self._parent.setCursor(
                Qt.ArrowCursor
            )  # FIXME: restoreCursor? setCursor only in this class!!
        QCoreApplication.processEvents()

    def on_rangeChange(self, minimum, maximum):
        self.status_progress.setMinimum(minimum)
        self.status_progress.setMaximum(maximum)
        QCoreApplication.processEvents()

    def on_cancel(self):
        self.status_progress.cancel()
        if self._block:
            self._parent.setCursor(Qt.ArrowCursor)
        QCoreApplication.processEvents()

    def canceled(self):
        return self.status_progress.wasCanceled()
예제 #5
0
class ProcessCombine(QObject):
    """
    Scans through the gpx files and initialize the GpxToFeature tool to import
    to create the features and finally combine the features as a single layer.
    """
    progress = pyqtSignal(str)

    def __init__(self, parent):
        """
        Initializes the processCombine
        :param parent: The parent of QObject
        :type parent: QWidget
        """
        QObject.__init__(self, parent)
        self._parent = parent
        self.init_progress_dialog()
        self.layer_fields = None
        global ID_NUMBER
        ID_NUMBER = 0
        global STOP_IMPORT
        STOP_IMPORT = False
        self.number_of_gpx_files = 0

    def init_progress_dialog(self):
        """
        Initializes the progress dialog.
        """
        self.progress_dlg = QProgressDialog(self._parent)
        self.progress_dlg.resize(340, self.progress_dlg.height())
        title = QApplication.translate('ProcessCombine', 'Importing...')
        self.progress_dlg.setWindowTitle(title)
        label = QLabel()
        label.setWordWrap(True)
        label.setMinimumHeight(17)
        self.progress_dlg.setMinimumWidth(500)
        self.progress_dlg.setMaximumWidth(500)
        self.progress_dlg.setLabel(label)
        self.progress_dlg.setValue(0)
        self.progress_dlg.canceled.connect(self.on_stop_importing)
        self.progress_dlg.open()

    @staticmethod
    def on_stop_importing():
        """
        A slot raised to stops the importing process. This happens when the
        progress dialog cancel button is clicked.
        """
        global STOP_IMPORT
        STOP_IMPORT = True

    def on_update_progress(self, progress):
        """
        A slot raised used to update the progress by emitting progress message
        from GpxToFeature signal called progress.
        :param progress: The progress message.
        :type progress: String
        """
        self.progress.emit(progress)

    def gpx_to_feature_list(self, parm_store):
        """
        Gets QgsFeature list by supplying gpx files.
        :param parm_store: The parameter store object
        :type parm_store: Class
        """
        feature_list = []
        for dir_path, sub_dirs, files in os.walk(parm_store.input_path):

            QApplication.processEvents()
            if STOP_IMPORT:
                return None
            # Exclude sub-folders if user have chosen not to scan sub-folders
            if not parm_store.scan_sub_folders:
                if dir_path != parm_store.input_path:
                    continue

            gpx_files = glob.glob('{0}/{1}*{2}.gpx'.format(
                dir_path,
                parm_store.file_name_prefix,
                parm_store.file_name_suffix
            ))
            gpx_count = len(gpx_files)
            if gpx_count == 0:
                continue
            self.number_of_gpx_files += gpx_count
            self.progress_dlg.setRange(0, len(gpx_files))

            for i, gpx_file in enumerate(gpx_files):
                QApplication.processEvents()
                if STOP_IMPORT:
                    return None
                gpx_path = os.path.join(dir_path, gpx_file)
                parent_path = os.path.dirname(parm_store.input_path)
                relative_path = os.path.relpath(gpx_path, parent_path)
                scanning = QApplication.translate('ProcessCombine',
                                                  'Scanning')

                text = '{} {}'.format(scanning, relative_path)

                self.progress_dlg.setLabelText(text)

                gpx_to_layer = GpxToFeature(parm_store)
                gpx_to_layer.progress.connect(self.on_update_progress)
                gpx_to_layer.init_gpx_import(gpx_path)
                if not STOP_IMPORT:
                    self.progress_dlg.setValue(i)
                # fet layer fields once
                if len(gpx_to_layer.final_features) > 0:
                    if self.layer_fields is None:
                        self.layer_fields = gpx_to_layer.layer_fields
                    feature_list.extend(gpx_to_layer.final_features)

        return feature_list

    def combine_features(self, parm_store):
        """
        Combines all features under one layer.
        :param parm_store: The parameter store object
        :type parm_store: Class
        :return:
        :rtype:
        """
        final_layer = QgsVectorLayer(
            "{0}?crs=epsg:{1}&field=id:integer&index=yes".format(
                parm_store.geometry_type, parm_store.gpx_projection
            ),
            parm_store.layer_name,
            "memory"
        )

        feature_list = self.gpx_to_feature_list(parm_store)

        if self.layer_fields is None:
            self.progress_dlg.blockSignals(True)
            self.progress_dlg.close()
            self.progress_dlg.blockSignals(False)
            return 0
        if STOP_IMPORT:
            return
        provider = final_layer.dataProvider()

        final_layer.startEditing()
        provider.addAttributes(self.layer_fields)
        final_layer.updateFields()
        provider.addFeatures(feature_list)
        final_layer.commitChanges()

        final_layer.updateExtents()
        QgsProject.instance().addMapLayer(final_layer)
        return len(feature_list)

    def finish_import(self, parm_store):
        """
        Finishes the import process.
        :param parm_store: The parameter store object
        :type parm_store: Class
        :return: None if the process is aborted or number_features is None
        :rtype: NoneType
        """

        number_of_features = self.combine_features(parm_store)
        if STOP_IMPORT:
            abort_text = QApplication.translate(
                'ProcessCombine',
                '<html><b>The importing process is aborted!</b></html>'
            )
            self.progress.emit(abort_text)
            return
        if number_of_features is None:
            return
        if number_of_features < 1:
            end_text = QApplication.translate(
                'ProcessCombine',
                '<html><b>Sorry, no valid GPX features found '
                'in the folder!</b</html>'
            )
            self.progress.emit(end_text)
            self.progress_dlg.cancel()
            return

        self.copy_gpx_files(VALID_GPX_FILES, parm_store.valid_gpx_folder)
        self.copy_gpx_files(INVALID_GPX_FILES, parm_store.invalid_gpx_folder)

        self.progress_dlg.cancel()
        a = QApplication.translate('ProcessCombine',
                                   '<html><b>Successfully imported')
        c = QApplication.translate('ProcessCombine', 'features from')
        d = QApplication.translate('ProcessCombine', 'gpx files!<br>')
        e = QApplication.translate('ProcessCombine',
                                   'You can view the result in')
        g = QApplication.translate('ProcessCombine', 'layer.</b</html>')
        end_text = '{} {} {} {} {} {} {} {}'.format(
            a, number_of_features, c, self.number_of_gpx_files, d, e,
            parm_store.layer_name, g
        )
        self.progress.emit(end_text)

    @staticmethod
    def copy_gpx_files(source_files, destination_folder):
        """
        Copies gpx files from a source folder to a destination folder.
        :param source_files: The source folder
        :type source_files: String
        :param destination_folder: The destination folder
        :type destination_folder: String
        """
        for gpx_path in source_files:
            gpx_file = os.path.basename(gpx_path)
            destination = os.path.join(destination_folder, gpx_file)
            QApplication.processEvents()
            shutil.copyfile(gpx_path, destination)
예제 #6
0
class SearchPanel(QWidget):
    """ SearchPanel
    """

    onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest')

    def __init__(self, parent=None, show_progress_dlg=False):
        super(SearchPanel, self).__init__(parent=parent)
        self._app_window = parent

        if self._app_window.dwarf is None:
            print('SearchPanel created before Dwarf exists')
            return

        self._app_window.dwarf.onMemoryScanResult.connect(
            self._on_search_result)

        self._ranges_model = None
        self._result_model = None

        self._blocking_search = show_progress_dlg
        self.progress = None
        self._pattern_length = 0

        self._search_results = []

        self.setContentsMargins(0, 0, 0, 0)

        main_wrap = QVBoxLayout()
        main_wrap.setContentsMargins(1, 1, 1, 1)

        wrapping_wdgt = QWidget()
        wrapping_wdgt.setContentsMargins(10, 10, 10, 10)
        v_box = QVBoxLayout(wrapping_wdgt)
        v_box.setContentsMargins(0, 0, 0, 0)
        self.input = QLineEdit()
        self.input.setPlaceholderText(
            'search for a sequence of bytes in hex format: deadbeef123456aabbccddeeff...'
        )
        v_box.addWidget(self.input)

        self.check_all_btn = QPushButton('check all')
        self.check_all_btn.clicked.connect(self._on_click_check_all)
        self.uncheck_all_btn = QPushButton('uncheck all')
        self.uncheck_all_btn.clicked.connect(self._on_click_uncheck_all)
        self.search_btn = QPushButton('search')
        self.search_btn.clicked.connect(self._on_click_search)

        h_box = QHBoxLayout()
        h_box.addWidget(self.check_all_btn)
        h_box.addWidget(self.uncheck_all_btn)
        h_box.addWidget(self.search_btn)
        v_box.addLayout(h_box)

        main_wrap.addWidget(wrapping_wdgt)

        self.ranges = DwarfListView(self)
        self.ranges.clicked.connect(self._on_show_results)
        self.results = DwarfListView(self)
        self.results.setVisible(False)

        h_box = QHBoxLayout()
        h_box.setContentsMargins(0, 0, 0, 0)
        h_box.addWidget(self.ranges)
        h_box.addWidget(self.results)
        main_wrap.addLayout(h_box)

        main_wrap.setSpacing(0)

        self.setLayout(main_wrap)

        self._setup_models()

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def _setup_models(self):
        self._ranges_model = QStandardItemModel(0, 7)

        # just replicate ranges panel model
        self._ranges_model.setHeaderData(
            0, Qt.Horizontal, 'x'
        )  # TODO: replace with checkbox in header - remove checkall btns
        self._ranges_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._ranges_model.setHeaderData(1, Qt.Horizontal, 'Address')
        self._ranges_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._ranges_model.setHeaderData(2, Qt.Horizontal, 'Size')
        self._ranges_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._ranges_model.setHeaderData(3, Qt.Horizontal, 'Protection')
        self._ranges_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._ranges_model.setHeaderData(4, Qt.Horizontal, 'FileOffset')
        self._ranges_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._ranges_model.setHeaderData(5, Qt.Horizontal, 'FileSize')
        self._ranges_model.setHeaderData(5, Qt.Horizontal, Qt.AlignCenter,
                                         Qt.TextAlignmentRole)
        self._ranges_model.setHeaderData(6, Qt.Horizontal, 'FilePath')

        self.ranges.setModel(self._ranges_model)
        self.ranges.header().setSectionResizeMode(0,
                                                  QHeaderView.ResizeToContents)
        self.ranges.header().setSectionResizeMode(1,
                                                  QHeaderView.ResizeToContents)
        self.ranges.header().setSectionResizeMode(2,
                                                  QHeaderView.ResizeToContents)
        self.ranges.header().setSectionResizeMode(3,
                                                  QHeaderView.ResizeToContents)
        self.ranges.header().setSectionResizeMode(4,
                                                  QHeaderView.ResizeToContents)
        self.ranges.header().setSectionResizeMode(5,
                                                  QHeaderView.ResizeToContents)

        self.ranges.doubleClicked.connect(self._on_range_dblclick)

        # setup results model
        self._result_model = QStandardItemModel(0, 1)
        self._result_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self.results.setModel(self._result_model)
        self.results.doubleClicked.connect(self._on_dblclicked)

    def set_ranges(self, ranges):
        """ Fills Rangelist with Data
        """
        self.ranges.header().setSectionResizeMode(0, QHeaderView.Fixed)
        if isinstance(ranges, list):
            self._ranges_model.removeRows(0, self._ranges_model.rowCount())
            for range_entry in ranges:
                if 'protection' in range_entry and isinstance(
                        range_entry['protection'], str):
                    if 'r' not in range_entry['protection']:
                        # skip not readable range
                        continue

                else:
                    continue
                # create items to add
                str_frmt = ''
                if self.ranges._uppercase_hex:
                    str_frmt = '0x{0:X}'
                else:
                    str_frmt = '0x{0:x}'

                addr = QStandardItem()
                addr.setTextAlignment(Qt.AlignCenter)
                addr.setText(str_frmt.format(int(range_entry['base'], 16)))

                size = QStandardItem()
                size.setTextAlignment(Qt.AlignRight)
                size.setText("{0:,d}".format(int(range_entry['size'])))

                protection = QStandardItem()
                protection.setTextAlignment(Qt.AlignCenter)
                protection.setText(range_entry['protection'])

                file_path = None
                file_addr = None
                file_size = None

                if len(range_entry) > 3:
                    if range_entry['file']['path']:
                        file_path = QStandardItem()
                        file_path.setText(range_entry['file']['path'])

                    if range_entry['file']['offset']:
                        file_addr = QStandardItem()
                        file_addr.setTextAlignment(Qt.AlignCenter)
                        file_addr.setText(
                            str_frmt.format(range_entry['file']['offset']))

                    if range_entry['file']['size']:
                        file_size = QStandardItem()
                        file_size.setTextAlignment(Qt.AlignRight)
                        file_size.setText("{0:,d}".format(
                            int(range_entry['file']['size'])))

                checkbox = QStandardItem()
                checkbox.setCheckable(True)

                self._ranges_model.appendRow([
                    checkbox, addr, size, protection, file_addr, file_size,
                    file_path
                ])

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_range_dblclick(self, model_index):
        item = self._ranges_model.itemFromIndex(model_index)
        if item:
            if self._ranges_model.item(model_index.row(),
                                       0).checkState() != Qt.Checked:
                self._ranges_model.item(model_index.row(),
                                        0).setCheckState(Qt.Checked)
            else:
                self._ranges_model.item(model_index.row(),
                                        0).setCheckState(Qt.Unchecked)

    def _on_click_check_all(self):
        for i in range(self._ranges_model.rowCount()):
            self._ranges_model.item(i, 0).setCheckState(Qt.Checked)

    def _on_click_uncheck_all(self):
        for i in range(self._ranges_model.rowCount()):
            self._ranges_model.item(i, 0).setCheckState(Qt.Unchecked)

    def _on_dblclicked(self, model_index):
        item = self._result_model.itemFromIndex(model_index)
        if item:
            self.onShowMemoryRequest.emit(
                self._result_model.item(model_index.row(), 0).text())

    def _on_click_search(self):
        pattern = self.input.text()
        if pattern == '':
            return 1

        # check if we already provide a hex string as input
        try:
            test = pattern.replace(' ', '')
            int(test, 16)
            pattern = test
        except ValueError:
            # search for string
            pattern = binascii.hexlify(pattern.encode('utf8')).decode('utf8')

        ranges = []
        self._search_results = []
        for i in range(self._ranges_model.rowCount()):
            item = self._ranges_model.item(i, 0)
            if item.checkState() == Qt.Checked:
                addr = self._ranges_model.item(i, 1)
                size = self._ranges_model.item(i, 2)
                ranges.append([addr.text(), size.text()])

        if len(ranges) == 0:
            return 1

        if self._blocking_search:
            self.progress = QProgressDialog()
            self.progress.setFixedSize(300, 50)
            self.progress.setAutoFillBackground(True)
            self.progress.setWindowModality(Qt.WindowModal)
            self.progress.setWindowTitle('Please wait')
            self.progress.setLabelText('searching...')
            self.progress.setSizeGripEnabled(False)
            self.progress.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            self.progress.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
            self.progress.setWindowFlag(Qt.WindowCloseButtonHint, False)
            self.progress.setModal(True)
            self.progress.setCancelButton(None)
            self.progress.setRange(0, 0)
            self.progress.setMinimumDuration(0)
            self.progress.forceShow()

        self._app_window.show_progress('searching...')
        self.input.setEnabled(False)
        self.search_btn.setEnabled(False)
        self.check_all_btn.setEnabled(False)
        self.uncheck_all_btn.setEnabled(False)

        self._pattern_length = len(pattern) * .5

        search_thread = SearchThread(self._app_window.dwarf, self)
        search_thread.onCmdCompleted.connect(self._on_search_complete)
        search_thread.onError.connect(self._on_search_error)
        search_thread.pattern = pattern
        search_thread.ranges = ranges
        search_thread.start()

    def _on_search_result(self, data):
        self._search_results.append(data)

    def _on_search_complete(self):
        self.input.setEnabled(True)
        self.search_btn.setEnabled(True)
        self.check_all_btn.setEnabled(True)
        self.uncheck_all_btn.setEnabled(True)
        self._app_window.hide_progress()
        if self._blocking_search:
            self.progress.cancel()

        self._ranges_model.removeColumns(4, 3)
        self._ranges_model.setHeaderData(3, Qt.Horizontal, 'Search Results')
        self._ranges_model.setHeaderData(3, Qt.Horizontal, None,
                                         Qt.TextAlignmentRole)

        results_count = 0
        is_selected = False
        for i in range(self._ranges_model.rowCount()):
            item = self._ranges_model.item(i, 0)
            if item.checkState() == Qt.Checked:
                item.setCheckState(Qt.Unchecked)
                if not is_selected:
                    is_selected = True
                    self.ranges.setCurrentIndex(self._ranges_model.index(i, 0))
            else:
                self._search_results.insert(i, None)
                self._ranges_model.item(i, 3).setText('')
                self._ranges_model.item(i, 3).setTextAlignment(Qt.AlignLeft)
                continue

            if len(self._search_results[i]):
                results_count += len(self._search_results[i])
                self._ranges_model.item(i, 3).setText('Matches: {0}'.format(
                    len(self._search_results[i])))
                self._ranges_model.item(i, 3).setTextAlignment(Qt.AlignLeft)
            else:
                self._ranges_model.item(i, 3).setText('')
                self._ranges_model.item(i, 3).setTextAlignment(Qt.AlignLeft)

        self._app_window.set_status_text(
            'Search complete: {0} matches'.format(results_count))
        if results_count:
            for i in self._search_results:
                if i and len(i):
                    self.results.setVisible(True)
                    for result in i:
                        self._result_model.appendRow(
                            QStandardItem(result['address']))

                    break

    def _on_search_error(self, msg):
        utils.show_message_box(msg)

    def _on_show_results(self):
        if self._search_results:
            self.results.clear()
            if self._app_window.memory_panel:
                self._app_window.memory_panel.remove_highlights('search')
            selected_index = self.ranges.selectionModel().currentIndex().row()
            if selected_index is not None:
                item_txt = self._ranges_model.item(selected_index, 3).text()
                if item_txt == '':
                    return

                for result in self._search_results[selected_index]:
                    self._result_model.appendRow(
                        QStandardItem(result['address']))

                    # TODO: fix hexview highlights performance
                    """
class DownloadProgress(QObject):
    """
    Dialog which is shown during download and parsing of the data. Displays the progress of the task
    of downloading and parsing. Creates a worker thread to do the actual download process in the background.
    """
    finishedSignal = pyqtSignal(OrderedDict, dict, name="processFinished")

    def __init__(self, parent):
        super(DownloadProgress, self).__init__(parent)
        self.parent = parent
        self.progressDialog = None
        self.worker = None
        self.thread = None

    def begin_download(self, request_params, request_function):
        self.progressDialog = QProgressDialog(self.parent, Qt.WindowSystemMenuHint | Qt.WindowTitleHint)
        self.progressDialog.setWindowTitle(Messages.downloading_weatherdata())
        self.progressDialog.setAutoClose(False)
        self.progressDialog.setCancelButton(None)
        self.progressDialog.setLabelText(Messages.downloading_weatherdata())
        self.progressDialog.open()
        self.progressDialog.setValue(0)

        self.request_params = request_params
        self.worker = DownloadWorker(request_params, request_function)
        self.worker.threadUpdateSignal.connect(self._update_progress_bar)
        self.worker.threadExceptionSignal.connect(self._loading_failed)
        self.worker.threadResultsSignal.connect(self._process_finished)
        self.worker.threadChangeTaskSignal.connect(self._change_progress_dialog)

        self.thread = QThread()
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.download_data)
        self.thread.start()

    @pyqtSlot(int, int, name="progressUpdate")
    def _update_progress_bar(self, i, max_value):
        self.progressDialog.setRange(0, max_value)
        self.progressDialog.setValue(i)

    @pyqtSlot(object, name="exceptionInProcess")
    def _loading_failed(self, error):
        self.progressDialog.cancel()

        try:
            raise error
        except RequestException as e:
            if e.error_code == 400:
                # command to ask data probably invalid or there is a problem with current station
                self.parent.show_error_alerts(Messages.weatherstation_error() + str(e))
            else:
                self.parent.show_error_alerts(Messages.unknown_error() + str(e))
        except InvalidApikeyException:
                # apikey is invalid
                self.parent.show_error_alerts(Messages.request_failed_error())
        except NoDataException:
            self.parent.show_error_alerts(Messages.date_not_found_error())
        except QueryLimitException as e:
            self.parent.show_error_alerts(Messages.query_limit_error().format(e.wait_time))
        except Exception as e:
            self.parent.show_error_alerts(Messages.unknown_error() + str(e))

    @pyqtSlot(str, name="progressChange")
    def _change_progress_dialog(self, header):
        """
        When the "topic" of the progress bar changes from download to parsing for example.
        :param header:
        :return:
        """
        self.progressDialog.setLabelText(header)
        self.progressDialog.setValue(0)

    @pyqtSlot(list, name="results")
    def _process_finished(self, result):
        self.result = result
        self.progressDialog.close()
        self.finishedSignal.emit(self.result, self.request_params)
class MWindow(QMainWindow):
    def __init__(self):
        super(MWindow, self).__init__()

        #gecko driver çalışması için yolda olması gerekiyor.
        if not os.getcwd() in sys.path:
            sys.path.append(os.getcwd())

        uic.loadUi("ui/anasayfa.ui", self)
        self.setFixedSize(700, 620)

        self.labelHata.setText("")

        self.btnFormuTemizle.clicked.connect(self.formuTemizle)
        self.btnSorgula.clicked.connect(self.hesSorgula)

        self.btnKayitEkle.clicked.connect(lambda: self.ekleGuncelle("ekle"))
        self.btnGuncelle.clicked.connect(self.btnGuncelleClicked)

        self.btnSil.clicked.connect(self.sil)
        self.btnHepsiniSil.clicked.connect(self.veritabaniniTemizle)
        self.btnYardim.clicked.connect(self.yardim)

        self.sinifIslemleri()
        self.btnSinifSorgula.clicked.connect(self.btnSinifSorgulaClicked)

        self.dosyaSecButton.clicked.connect(self.dosyaSec)
        self.dizinSecButton.clicked.connect(self.dizinSec)
        self.topluKaydetButton.clicked.connect(self.topluKaydet)

        self.btnSinifSil.clicked.connect(self.sinifSilClicked)

        self.resim.setPixmap(QPixmap(PHOTO_PLACEHOLDER))
        self.show()

        #Bu gizli butonlar thread içinden arayüzde yapılacak değişiklikler için eklendi.
        #Doğru yol olmayabilir ama işe yarıyor :)
        self.animasyonKapatButon = QPushButton(self)
        self.animasyonKapatButon.clicked.connect(
            self.yukleniyorAnimasyonuKapat)
        self.animasyonKapatButon.hide()
        self.tabloGonderButton = QPushButton(self)
        self.tabloGonderButton.clicked.connect(self.tabloIsle)
        self.tabloGonderButton.hide()
        self.hataMesajiButton = QPushButton(self)
        self.hataMesajiButton.clicked.connect(self.hataMesaji)
        self.hataMesajiButton.hide()
        self.btnSinifIslemleri = QPushButton(self)
        self.btnSinifIslemleri.clicked.connect(self.sinifIslemleri)
        self.btnSinifIslemleri.hide()

        self.mesaj = ""
        self.timer = QTimer(self)

    def hataMesaji(self):
        self.timer.stop()
        mesaj = self.mesaj
        self.labelHata.setText(mesaj)

        self.timer.timeout.connect(self.hataMesajiKapat)
        self.timer.start(5000)

    def hataMesajiKapat(self):
        self.labelHata.setText("")
        self.timer.stop()

    def veritabaniniTemizle(self):

        qm = QMessageBox(self)
        mesaj = "Tüm bilgiler silinecek. Onaylıyor musunuz?"
        ret = qm.warning(self, 'Hepsini Sil', mesaj, qm.Yes | qm.No)

        if ret == qm.Yes:
            vt.DB.veritabanisil()

            self.formuTemizle()
            self.sinifIslemleri()
            self.mesaj = "Tüm veriler silindi."
            self.hataMesaji()

    def yukleniyorAnimasyonuBaslat(self, parent=None):
        self.dialogMessage = "İşlem devam ediyor..."

        if parent == None:
            self.pb = QProgressDialog(self)
        else:
            self.pb = QProgressDialog(parent)

        pb = self.pb
        pb.setLabelText(self.dialogMessage)
        pb.setStyleSheet("color:blue;background-color:orange;")
        pb.setWindowFlag(Qt.FramelessWindowHint)
        pb.setCancelButton(None)
        pb.setRange(0, 0)
        pb.setMinimumDuration(0)
        pb.show()

    def yukleniyorAnimasyonuKapat(self):
        self.pb.cancel()

    def ogrenciGoster(self, ogrenci):
        if len(ogrenci) == 0:
            return

        self.tcNo.setText(ogrenci[TC_NO_INDEX])
        self.ad.setText(ogrenci[AD_INDEX])
        self.soyad.setText(ogrenci[SOYAD_INDEX])
        self.okulNo.setText(str(ogrenci[OKUL_NO_INDEX]))
        self.sinif.setText(ogrenci[SINIF_INDEX])
        self.resim.setPixmap(ogrenci[RESIM_INDEX])
        self.hesKodu.setText(ogrenci[HES_KODU_INDEX])
        #self.durum.setText(str(ogrenci[DURUM_INDEX]))

    def hesSorgula(self):
        self.labelHata.setText("")
        ogrenci = []

        #*Tc noya göre veritabanı sorgulamasında birden fazla sonuç gelebilir.
        self.tekHesSorguSonucu = []
        hes_kodu = ""
        hesKoduKayitli = True

        if self.okulNo.text() != "":
            no = self.okulNo.text()
            self.formuTemizle()

            if not no.isnumeric():
                self.mesaj = "Geçerli okul numarası girmelisiniz!"
                self.hataMesajiButton.click()
                return

            ogrenci = vt.DB.okul_no_ile(int(no))
            if len(ogrenci) == 0:
                self.mesaj = "Bu numara kayıtlı değil."
                self.hataMesajiButton.click()
                return

            self.ogrenciGoster(ogrenci)
            hes_kodu = ogrenci[HES_KODU_INDEX]

        elif self.tcNo.text() != "":
            ogrenci = vt.DB.tc_no_ile(self.tcNo.text())
            self.formuTemizle()

            if len(ogrenci) == 0:
                self.mesaj = "Bu TC no kayıtlı değil."
                self.hataMesajiButton.click()
                return

            self.ogrenciGoster(ogrenci)
            hes_kodu = ogrenci[HES_KODU_INDEX]

        elif self.hesKodu.text() != "":
            ogrenci = vt.DB.hes_kodu_ile(self.hesKodu.text())

            if len(ogrenci) == 0:
                hes_kodu = self.hesKodu.text()
                hesKoduKayitli = False
            else:
                self.formuTemizle()
                self.ogrenciGoster(ogrenci)
                hes_kodu = ogrenci[HES_KODU_INDEX]

        else:
            self.mesaj = "Okul no, TC no veya HES kodu girmelisiniz!"
            self.hataMesajiButton.click()
            return

        if self.kullaniciAdi.text() != "" and self.sifre.text() != "":
            #Girilen bilgiye göre öğrenci kayıtlıysa gösterildi. Hes kodu sorgulanacak.
            self.yukleniyorAnimasyonuBaslat()

            #Firefox yeni bir threadde açılmalı yoksa arayüzü kilitliyor.
            self.mThread = Thread(target=self.eDevlettenSorgula,
                                  args=(hes_kodu, hesKoduKayitli))
            self.mThread.start()

        else:
            #*Kullanıcı adı veya şifresi boş
            self.mesaj = "e-Devlet kullanıcı adı ve şifresini girmelisiniz."
            self.hataMesajiButton.click()
            return

    def formuTemizle(self):
        self.okulNo.setText("")
        self.ad.setText("")
        self.soyad.setText("")
        self.sinif.setText("")
        self.tcNo.setText("")
        self.hesKodu.setText("")
        self.durum.setText("")
        self.resim.setPixmap(QPixmap(PHOTO_PLACEHOLDER))

    def yardim(self):
        yardim = QDialog(self)
        uic.loadUi("ui/yardim.ui", yardim)
        yardim.setFixedSize(610, 450)
        yardim.exec_()

    def btnGuncelleClicked(self):
        if self.kullaniciAdi.text() == "" or self.sifre.text() == "":
            self.mesaj = "E-Devlet bilgilerini girmeden güncelleme yapılamaz!"
            self.hataMesajiButton.click()
            return

        tmp_no = self.okulNo.text()
        ogrenci = []
        if tmp_no != "" and tmp_no.isnumeric():
            ogrenci = vt.DB.okul_no_ile(tmp_no)

        if len(ogrenci) == 0:

            self.mesaj = "Bu numaraya sahip öğrenci yok!"
            self.hataMesajiButton.click()
        else:
            self.ogrenciGoster(ogrenci)
            self.ekleGuncelle("güncelle")

    def ekleGuncelle(self, eylem):
        if eylem == "ekle":
            if self.kullaniciAdi.text() == "" or self.sifre.text() == "":
                self.mesaj = "E-Devlet bilgilerini girmeden kayıt ekleme yapılamaz!"
                self.hataMesajiButton.click()
                return

        self.eklenenResim = ""

        self.ekleGuncellePencere = QDialog(self)
        uic.loadUi("ui/ekleGuncelle.ui", self.ekleGuncellePencere)

        self.ekleGuncellePencere.setFixedSize(450, 280)
        self.ekleGuncellePencere.hata.hide()

        if eylem == "ekle":
            self.ekleGuncellePencere.setWindowTitle("Ekle")
            self.ekleGuncellePencere.widgetKaydet.setText("Kaydet")

        elif eylem == "güncelle":
            self.ekleGuncellePencere.setWindowTitle("Güncelle")
            self.ekleGuncellePencere.widgetKaydet.setText("Güncelle")

            self.ekleGuncellePencere.widgetOkulNo.setText(self.okulNo.text())
            self.ekleGuncellePencere.widgetOkulNo.setEnabled(False)

            self.ekleGuncellePencere.widgetAdi.setText(self.ad.text())
            self.ekleGuncellePencere.widgetAdi.setEnabled(False)

            self.ekleGuncellePencere.widgetSoyadi.setText(self.soyad.text())
            self.ekleGuncellePencere.widgetSoyadi.setEnabled(False)

            self.ekleGuncellePencere.widgetSinifi.setText(self.sinif.text())
            self.ekleGuncellePencere.widgetTcKimlikNo.setText(self.tcNo.text())
            self.ekleGuncellePencere.widgetTcKimlikNo.setEnabled(False)

            self.ekleGuncellePencere.widgetHesKodu.setText(self.hesKodu.text())

            res = self.resim.pixmap()
            if res:
                self.ekleGuncellePencere.widgetResim.setPixmap(res)

        self.ekleGuncellePencere.widgetIptal.clicked.connect(
            self.ekleGuncellePencere.destroy)
        self.ekleGuncellePencere.widgetKaydet.clicked.connect(self.kaydet)
        self.ekleGuncellePencere.widgetResimEkle.clicked.connect(
            self.resimEkle)

        self.ekleGuncellePencere.exec_()

    def resimEkle(self):

        resimAdi, _ = QFileDialog.getOpenFileName(self.ekleGuncellePencere,
                                                  "Resim seç...", "C:\\")
        try:
            if resimAdi != "":
                mResim = QPixmap(resimAdi)
                self.ekleGuncellePencere.widgetResim.setPixmap(mResim)
                self.eklenenResim = resimAdi

        except:
            return

    def kaydet(self):
        self.ekleGuncellePencere.hata.hide()

        kimlikNo = self.ekleGuncellePencere.widgetTcKimlikNo.text()
        hesKodu = self.ekleGuncellePencere.widgetHesKodu.text()
        ad = self.ekleGuncellePencere.widgetAdi.text()
        soyad = self.ekleGuncellePencere.widgetSoyadi.text()
        sinif = self.ekleGuncellePencere.widgetSinifi.text()
        okulNo = self.ekleGuncellePencere.widgetOkulNo.text()

        ogrenci = [
            kimlikNo, ad, soyad, okulNo, sinif, self.eklenenResim, hesKodu, "1"
        ]

        if self.ekleGuncellePencere.widgetKaydet.text() == "Kaydet":
            #*Bilgilerde eksiklik varsa durdurulacak.
            bilgilerTam = hesKodu != "" and kimlikNo != "" and ad != "" and self.eklenenResim != "" and soyad != "" and sinif != "" and okulNo != ""

            if not bilgilerTam:
                self.ekleGuncellePencere.hata.show()
                self.ekleGuncellePencere.hata.setText("Bilgiler eksik!")
                return

            #Öğrenci zaten kayıtlı mı kontrol ediliyor.
            numaraKayitli = vt.DB.okul_no_ile(ogrenci[OKUL_NO_INDEX])
            tcNoKayitli = vt.DB.tc_no_ile(ogrenci[TC_NO_INDEX])
            hesKayitli = vt.DB.hes_kodu_ile(ogrenci[HES_KODU_INDEX])

            if len(numaraKayitli) > 0 or len(tcNoKayitli) > 0 or len(
                    hesKayitli) > 0:
                self.ekleGuncellePencere.hata.show()
                self.ekleGuncellePencere.hata.setText(
                    "Öğrenci zaten kayıtlı. Düzenlemek için Güncelle bölümünü kullanın."
                )
                return

            try:
                self.yukleniyorAnimasyonuBaslat()
                th = Thread(target=self.eDevlettenGrupGuncelleSayfasiAc,
                            args=(E_DEVLET_GRUP_ADI, True, ogrenci))
                th.start()
            except:
                self.animasyonKapatButon.click()
                self.ekleGuncellePencere.hata.show()
                self.ekleGuncellePencere.hata.setText(
                    "Öğrenci zaten kayıtlı. Düzenlemek için Güncelle bölümünü kullanın."
                )

        #Güncelleme sayfasındayız.
        else:
            bilgilerTam = hesKodu != "" and sinif != ""

            if not bilgilerTam:
                self.ekleGuncellePencere.hata.show()
                self.ekleGuncellePencere.hata.setText("Bilgiler eksik!")
                return

            #Hes kodu değişmedi, sadece veritabanına yazılacak.
            if self.hesKodu.text() == hesKodu:

                if self.eklenenResim != "":
                    vt.DB.toplu_kayit_ekle([ogrenci])
                else:
                    vt.DB.veriguncelle(okulNo, sinif, hesKodu)

                self.sinif.setText(sinif)

            #Hes değişti. E-devletten hes kodu eklenecek. Eklenirse veritabanına kaydedilecek.
            else:
                if self.eklenenResim != "":
                    self.yukleniyorAnimasyonuBaslat()
                    th = Thread(target=self.eDevlettenGrupGuncelleSayfasiAc,
                                args=(E_DEVLET_GRUP_ADI, True, ogrenci))
                    th.start()
                #Yeni resim eklenmediyse eski öğrenci güncellenecek.
                else:
                    self.yukleniyorAnimasyonuBaslat()
                    th = Thread(target=self.eDevlettenGrupGuncelleSayfasiAc,
                                args=(E_DEVLET_GRUP_ADI, True, ogrenci, True))
                    th.start()

        self.ekleGuncellePencere.close()

    def grubaHesEkle(self, hes, browserAc=True):
        if browserAc:
            if not self.eDevletGirisiYap():
                self.mesaj = "E-Devlet girişi yapılamadı!"
                self.hataMesajiButton.click()
                return

        br = self.br

        self.elemanYuklenmesiniBekle(id="hesKodu")

        br.find_element_by_id("hesKodu").clear()
        br.find_element_by_id("hesKodu").send_keys(hes)
        br.find_element_by_name("btn").click()
        self.elemanYuklenmesiniBekle(sinif="actionButton")

        if len(br.find_elements_by_class_name("confirmContainer")) > 0:
            return True
        else:
            return False

    #Öğrenci sil
    def sil(self):

        okulNo = self.okulNo.text()
        if okulNo != "" and okulNo.isnumeric():

            ogrenci = vt.DB.okul_no_ile(int(okulNo))
            if len(ogrenci) > 0:
                self.ogrenciGoster(ogrenci)

                qm = QMessageBox(self)
                ret = qm.question(self, 'Sil', "Öğrenci silisin mi?",
                                  qm.Yes | qm.No)
                if ret == qm.Yes:
                    vt.DB.kayitsil(int(okulNo))
                    self.mesaj = "Öğrenci silindi."
                    self.hataMesajiButton.click()
                    self.formuTemizle()

            else:
                self.mesaj = "Kayıt yok!"
                self.hataMesajiButton.click()

        else:
            self.mesaj = "Sileceğiniz öğrencinin numarasını girmediniz!"
            self.hataMesajiButton.click()

    def sonucGeldimi(self):

        try:
            br = self.br
            tc_sonu = br.find_elements_by_class_name(
                "compact")[0].find_elements_by_tag_name("dd")[1].get_attribute(
                    "innerText")
            ad_soyad = br.find_elements_by_class_name(
                "compact")[0].find_elements_by_tag_name("dd")[0].get_attribute(
                    "innerText")
            durum = br.find_elements_by_class_name(
                "compact")[0].find_elements_by_tag_name("dd")[3].get_attribute(
                    "innerText")
            return (tc_sonu, ad_soyad, durum)

        except:
            return (False, False, False)

    def eDevletGirisiYap(self,
                         tcKimlik="",
                         sifre="",
                         gizliPencere=TARAYICIYI_GIZLE):
        try:
            if tcKimlik == "" and sifre == "":
                tcKimlik = self.kullaniciAdi.text()
                sifre = self.sifre.text()

            if tcKimlik == "" or sifre == "":
                return False

            url = "https://giris.turkiye.gov.tr/Giris/"

            #*E-devlete grup ekleneceği zaman gizliPencere=False olmalı, excel doyası yüklenmiyor yoksa.
            if gizliPencere:
                options = Options()
                options.add_argument('--headless')
                self.br = Firefox(executable_path="geckodriver",
                                  options=options)
            else:
                self.br = Firefox(executable_path="geckodriver")

            br = self.br
            br.get(url)

            br.find_element_by_id("tridField").send_keys(tcKimlik)
            br.find_element_by_id("egpField").send_keys(sifre)
            br.find_elements_by_class_name("submitButton")[0].click()

            self.elemanYuklenmesiniBekle(sinif="userMenuButton")

            if len(br.find_elements_by_class_name("userMenuButton")) > 0:
                return True
            else:
                return False
        except:
            return False

    def eDevletCikisYap(self):
        self.br.find_elements_by_class_name("userMenuButton")[0].click()
        self.br.find_elements_by_class_name("logout")[0].click()
        self.br.close()

    def eDevlettenSorgula(self, hesKodu, hesKoduKayitli=True):

        if self.eDevletGirisiYap():
            self.pb.setLabelText("E-Devlet girişi yapıldı...")
        else:
            self.yukleniyorAnimasyonuKapat()
            self.mesaj = "E-Devlet girişi başarısız!"
            self.hataMesajiButton.click()
            return

        br = self.br
        url1 = "https://www.turkiye.gov.tr/saglik-bakanligi-hes-kodu-sorgulama"
        sayac = 0
        br.get(url1)

        try:

            br.find_element_by_id("hes_kodu").send_keys(hesKodu)
            br.find_elements_by_class_name("submitButton")[0].click()
            self.pb.setLabelText("Sorgulanıyor...")

            while (True):
                tc_sonu, ad_soyad, durum = self.sonucGeldimi()
                #Hes kodu geçersiz uyarısı kontrol ediliyor.
                if len(br.find_elements_by_class_name("warningContainer")) > 0:
                    tc_sonu, ad_soyad, durum = (False, False, False)
                    break

                if tc_sonu or sayac > TIMEOUT:
                    break
                sayac += 1
                time.sleep(1)

            #* Burada edevletten sonuç gelmiş ve tc_sonu, hes ve durum değişkenlerine aktarılmış oluyor.
            #*Sonuç gelmemişse bu değişkenlere False değeri veriliyor.

            self.eDevletCikisYap()
            self.yukleniyorAnimasyonuKapat()

            if tc_sonu:
                if not hesKoduKayitli:
                    son_uc = tc_sonu[-3:]
                    ad = " ".join(ad_soyad.split(" ")[:-1])
                    soyad = ad_soyad.split(" ")[-1]

                    ogrenciListe = vt.DB.tc_sonu_ile(son_uc, ad[:2], soyad[:2])

                    #Öğrenci veritabanında yoksa.
                    if len(ogrenciListe) == 0:
                        self.durum.setText(durum)
                        self.tcNo.setText(tc_sonu)

                        soyad = ad_soyad.split(" ")[-1]
                        self.soyad.setText(soyad)
                        ad = " ".join(ad_soyad.split(" ")[:-1])

                        self.ad.setText(ad)

                    elif len(ogrenciListe) == 1:
                        self.ogrenciGoster(ogrenciListe[0])
                        self.mesaj = "Olası eşleşme"
                        self.hataMesajiButton.click()
                    else:
                        # Bir okul için çok düşük bir ihtimal bu. Sadece uyarıyla geçeceğim.
                        self.ogrenciGoster(ogrenciListe[0])
                        self.tekHesSorguSonucu = ogrenciListe
                        self.mesaj = "Olası eşleşmeler"
                        self.hataMesajiButton.click()

                else:
                    #Hes kodu kayıtlı, öğrenci zaten gösterildi. Durum yazılacak.
                    self.durum.setText(durum)

            else:
                self.mesaj = "Hatalı hes kodu!"
                self.hataMesajiButton.click()

        except:
            br.close()
            self.yukleniyorAnimasyonuKapat()
            self.mesaj = "Beklenmeyen bir hata oluştu!"
            self.hataMesajiButton.click()

    #True döndürürse grup kaydedilmiş ve hes kodlarını kaydedilmiştir.
    def grupOlustur(self,
                    grupAdi,
                    tamDosyaYolu,
                    ogrenciler,
                    aciklama="",
                    varolanGrubaEkle=False):

        try:

            if not varolanGrubaEkle:
                if not self.eDevletGirisiYap():
                    self.mesaj = "E-Devlet girişi yapılamadı."
                    self.hataMesajiButton.click()
                    return False

                self.pb.setLabelText("E-Devlet girişi yapıldı...")

                br = self.br
                url = "https://www.turkiye.gov.tr/saglik-bakanligi-toplu-hes-kodu-sorgulama?yeni=grup"
                br.get(url)

                br.find_element_by_id("grupAdi").clear()
                br.find_element_by_id("grupAdi").send_keys(grupAdi)
                br.find_element_by_id("grupAciklama").send_keys(aciklama)
                br.find_elements_by_class_name("submitButton")[0].click()

                if not self.elemanYuklenmesiniBekle(id="hesKodu"):
                    return False

                self.pb.setLabelText("Grup oluşturuldu...")

            else:
                self.eDevlettenGrupGuncelleSayfasiAc(E_DEVLET_GRUP_ADI,
                                                     browser=True)
                self.elemanYuklenmesiniBekle(
                    linkText="Hes Kodlarını Excelden Yükle")
                br = self.br

            br.find_element_by_link_text(
                "Hes Kodlarını Excelden Yükle").click()
            self.elemanYuklenmesiniBekle(sinif="filedropzone")

            br.find_elements_by_class_name("filedropzone")[0].click()
            subprocess.call(["cscript.exe", "deneme.vbs", tamDosyaYolu])

            time.sleep(4)

            br.find_element_by_name("btn").click()

            if self.elemanYuklenmesiniBekle(sinif="list-right"):
                if len(br.find_elements_by_class_name("confirmContainer")) > 0:

                    self.pb.setLabelText("Hes listesi kaydedildi...")
                    vt.DB.toplu_kayit_ekle(ogrenciler)
                    br.close()
                    self.btnSinifIslemleri.click()
                    self.animasyonKapatButon.click()
                    self.mesaj = "Liste kaydedildi."
                    self.hataMesajiButton.click()
                    return True
                else:
                    self.animasyonKapatButon.click()
                    self.mesaj = "Hata: Liste e-devlete kaydedilemedi!"
                    self.hataMesajiButton.click()
                    return False
            else:
                self.mesaj = "Hata: Liste e-devlete kaydedilemedi!"
                self.hataMesajiButton.click()
                self.animasyonKapatButon.click()
                return False

        except:
            self.mesaj = "Hata: Liste e-devlete kaydedilemedi!"
            self.hataMesajiButton.click()
            self.animasyonKapatButon.click()
            return False

    def eDevlettenGrupGuncelleSayfasiAc(self,
                                        grupAdi,
                                        browser=True,
                                        ogrenci=[],
                                        ogrenciGuncellenecek=False):

        try:
            if browser:
                if not self.eDevletGirisiYap():
                    return

                self.pb.setLabelText("E-Devlet girişi yapıldı...")

            br = self.br
            url = "https://www.turkiye.gov.tr/saglik-bakanligi-toplu-hes-kodu-sorgulama"
            br.get(url)
            self.elemanYuklenmesiniBekle(id="resultTable")

            listeler = br.find_elements_by_link_text("Güncelle")
            if len(listeler) == 0:
                return
            elif len(listeler) == 1:
                br.find_element_by_link_text("Güncelle").click()

            else:
                tumSutunlar = br.find_elements_by_tag_name("td")
                gruplar = [
                    i.text for i in tumSutunlar
                    if tumSutunlar.index(i) % 4 == 0
                ]
                grupIndex = gruplar.index(grupAdi)
                br.find_elements_by_link_text("Güncelle")[grupIndex].click()

            self.pb.setLabelText("Güncelleme sayfası açıldı...")

            #*İlgili grup güncellenmeye hazır.
            self.elemanYuklenmesiniBekle(sinif="actionButton")
            br.find_elements_by_class_name("actionButton")[1].click()

            self.elemanYuklenmesiniBekle(sinif="actionButton")

            if len(ogrenci) > 0:
                if self.grubaHesEkle(ogrenci[HES_KODU_INDEX], browserAc=False):

                    self.pb.setLabelText("Hes kaydedildi...")

                    if ogrenciGuncellenecek:
                        vt.DB.veriguncelle(ogrenci[OKUL_NO_INDEX],
                                           ogrenci[SINIF_INDEX],
                                           ogrenci[HES_KODU_INDEX])
                    else:
                        vt.DB.toplu_kayit_ekle([ogrenci])

                    self.sinif.setText(ogrenci[SINIF_INDEX])
                    self.hesKodu.setText(ogrenci[HES_KODU_INDEX])
                    self.mesaj = "Öğrenci kaydedildi."
                    self.hataMesajiButton.click()
                    self.animasyonKapatButon.click()
                    br.close()

                else:
                    self.mesaj = "Girilen HES kodu geçersiz!"
                    self.hataMesajiButton.click()
                    self.animasyonKapatButon.click()
                    br.close()

        except:
            self.mesaj = "Beklenmeyen bir hata oluştu!"
            self.hataMesajiButton.click()
            self.animasyonKapatButon.click()
            self.br.close()

    def eDevletHesSil(self, hes, browserAc=True):
        try:
            if browserAc:
                self.eDevlettenGrupGuncelleSayfasiAc(E_DEVLET_GRUP_ADI)

            br = self.br

            #*İlk satır tablo başlıkları
            satirlar = br.find_elements_by_tag_name("tr")
            if len(satirlar) > 1:
                satir = satirlar[1]

                #*Satırların class hidden durumları değiştiriliyor.Yoksa 1. sayfadan sonrakiler görünmüyor.
                br.execute_script("arguments[0].setAttribute('class', '')",
                                  satir)

                sutunListesi = br.find_elements_by_tag_name("td")
                tumHesler = [
                    i.text for i in sutunListesi
                    if sutunListesi.index(i) % 2 == 0
                ]

                br.find_elements_by_link_text("Sil")[tumHesler.index(
                    hes)].click()
                self.elemanYuklenmesiniBekle(sinif="actionButton")

                if len(br.find_elements_by_class_name("confirmContainer")) > 0:
                    return True
                else:
                    return False

        except:
            return False

    def edevlettenHepsiniSil(self):

        try:

            if not self.eDevletGirisiYap():
                return

            br = self.br
            url = "https://www.turkiye.gov.tr/saglik-bakanligi-toplu-hes-kodu-sorgulama"
            br.get(url)
            self.elemanYuklenmesiniBekle(id="resultTable")

            while (len(br.find_elements_by_link_text("Sil")) > 0):

                br.find_element_by_link_text("Sil").click()
                self.elemanYuklenmesiniBekle(sinif="radioButton")

                br.find_element_by_class_name("radioButton").click()
                br.find_element_by_class_name("actionButton").click()

                self.elemanYuklenmesiniBekle(sinif="contentToolbar")
                br.find_element_by_partial_link_text("Grup Listesi").click()

                self.elemanYuklenmesiniBekle(id="resultTable")

        except:
            self.br.close()
            self.mesaj = "Gruplar e-devletten silinemedi!"
            self.hataMesajiButton.click()
            self.animasyonKapatButon.click()

    def elemanYuklenmesiniBekle(self, id="", sinif="", linkText=""):
        br = self.br
        timeout = TIMEOUT

        if id != "":

            while len(br.find_elements_by_id(id)) == 0 and timeout > 0:
                time.sleep(1)
                timeout -= 1
            if timeout == 0:
                return False
            else:
                return True

        elif sinif != "":
            while len(br.find_elements_by_class_name(
                    sinif)) == 0 and timeout > 0:
                time.sleep(1)
                timeout -= 1
            if timeout == 0:
                return False
            else:
                return True

        elif linkText != "":
            while len(br.find_elements_by_link_text(
                    linkText)) == 0 and timeout > 0:
                time.sleep(1)
                timeout -= 1
            if timeout == 0:
                return False
            else:
                return True

    def sinifIslemleri(self):
        self.comboboxSinifSec.clear()
        siniflar = []
        tmp_siniflar = vt.DB.sinif_isimleri()

        #[(sınıf,),(sınıf,),(sınıf,)] şeklinde geliyor veritabanından.
        for i in tmp_siniflar:
            siniflar.append(*i)

        #*Veritabanından çekilen sınıflar comboboxa aktarılıyor.
        self.comboboxSinifSec.addItems(siniflar)

        tablo = self.sorguSonucuTableWidget
        #*Resim, ad soyad, tc ve açıklama olacak şekilde 4 sütun.
        tablo.setColumnCount(4)
        tablo.setRowCount(1)

        item1 = QTableWidgetItem("Resim")
        item1.setTextAlignment(Qt.AlignCenter)
        item1.setBackground(QColor("#616161"))
        item1.setForeground(QColor("#ffffff"))
        tablo.setItem(0, 0, item1)
        item2 = QTableWidgetItem("Öğrenci")
        item2.setTextAlignment(Qt.AlignCenter)
        item2.setBackground(QColor("#616161"))
        item2.setForeground(QColor("#ffffff"))
        tablo.setItem(0, 1, item2)
        item3 = QTableWidgetItem("Okul No")
        item3.setTextAlignment(Qt.AlignCenter)
        item3.setBackground(QColor("#616161"))
        item3.setForeground(QColor("#ffffff"))
        tablo.setItem(0, 2, item3)
        item4 = QTableWidgetItem("Açıklama")
        item4.setTextAlignment(Qt.AlignCenter)
        item4.setBackground(QColor("#616161"))
        item4.setForeground(QColor("#ffffff"))
        tablo.setItem(0, 3, item4)
        tablo.verticalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        tablo.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        tablo.horizontalHeader().hide()
        tablo.verticalHeader().hide()

    def btnSinifSorgulaClicked(self):

        self.formuTemizle()

        if self.comboboxSinifSec.currentText() == "":
            self.mesaj = "Sorgulanacak sınıf yok!"
            self.hataMesaji()
            return

        if self.kullaniciAdi.text() != "" and self.sifre.text() != "":
            self.sorguSonucuLabel.setText("")
            self.yukleniyorAnimasyonuBaslat()
            th = Thread(target=self.sinifSorgula)
            th.start()

        else:
            self.mesaj = "E-Devlet kullanıcı adı ve şifrenizi girmelisiniz!"
            self.hataMesaji()

    def sinifSorgula(self):

        self.tabloyaGonderilenOgrenciler = []
        self.tabloyaGonderilenSorunlar = []

        sinif = self.comboboxSinifSec.currentText()

        if not self.eDevletGirisiYap():
            self.yukleniyorAnimasyonuKapat()
            self.br.close()
            self.mesaj = "E-Devlet girişi yapılamadı!"
            self.hataMesajiButton.click()
            return

        br = self.br
        br.get(
            "https://www.turkiye.gov.tr/saglik-bakanligi-toplu-hes-kodu-sorgulama"
        )
        self.elemanYuklenmesiniBekle(linkText="Yeni Grup Oluştur")

        url = "https://www.turkiye.gov.tr/saglik-bakanligi-toplu-hes-kodu-sorgulama?i=s&s=0"
        br.get(url)
        self.elemanYuklenmesiniBekle(sinif="compact")

        gecersizler = br.find_elements_by_css_selector(
            "table[summary='Geçersiz HES Kodu Listesi (Süresi dolmuş, Silinmiş)']"
        )
        pozitifler = br.find_elements_by_css_selector(
            "table[summary='Riskli HES Kodu Listesi (Pozitif, Temaslı)']")

        if len(gecersizler) != 0 or len(pozitifler) != 0:
            #Tüm satırlar görünür hale getiriliyor.
            for eleman in br.find_elements_by_tag_name("tr"):
                br.execute_script("arguments[0].setAttribute('class','')",
                                  eleman)

            ogrenciler = []
            hesler = []
            sorunlar = []
            if len(pozitifler) > 0:
                self.sorguSonucuLabel.setText("Sorun var!")
                #hes_kodu, tc_no, açıklama
                tumBilgiler = [
                    i.text
                    for i in pozitifler[0].find_elements_by_tag_name("td")
                ]
                #*Bunlar edevletten gelecek sonuçlar.
                tmp_hesler = [
                    i for i in tumBilgiler if tumBilgiler.index(i) % 3 == 0
                ]
                tmp_sorunlar = [
                    i for i in tumBilgiler if tumBilgiler.index(i) % 3 == 2
                ]
                #*Sınıf sorgulandığı için hesler zaten veritabanında kayıtlı.
                #Bu sorguda sorun çıkarsa döngü ile veritabanından sorgulanabilir.

                tmp_ogrenciler = vt.DB.hes_kodu_listesi_ile(hesler)
                if len(tmp_ogrenciler) > 0:
                    for ogrenci in tmp_ogrenciler:
                        if ogrenci[SINIF_INDEX] == sinif:
                            ind = tmp_ogrenciler.index(ogrenci)
                            ogrenciler.append(ogrenci)
                            hesler.append(tmp_hesler[ind])
                            sorunlar.append(tmp_sorunlar[ind])

            if len(gecersizler) > 0:
                self.sorguSonucuLabel.setText("Sorun var!")
                tumBilgiler = [
                    i.text
                    for i in gecersizler[0].find_elements_by_tag_name("td")
                ]

                tmp_hesler = [
                    i for i in tumBilgiler if tumBilgiler.index(i) % 3 == 0
                ]
                tmp_sorunlar = [
                    i for i in tumBilgiler if tumBilgiler.index(i) % 3 == 1
                ]
                #*Sınıf sorgulandığı için hesler zaten veritabanında kayıtlı.
                #Bu sorguda sorun çıkarsa döngü ile veritabanından sorgulanabilir.
                tmpOgrenciler = vt.DB.hes_kodu_listesi_ile(tmp_hesler)

                if len(tmpOgrenciler) > 0:
                    for ogrenci in tmpOgrenciler:
                        if ogrenci[SINIF_INDEX] == sinif:
                            ind = tmpOgrenciler.index(ogrenci)
                            ogrenciler.append(ogrenci)
                            hesler.append(tmp_hesler[ind])
                            sorunlar.append(tmp_sorunlar[ind])

            self.tabloyaGonderilenOgrenciler = ogrenciler
            self.tabloyaGonderilenSorunlar = sorunlar

        else:
            self.sorguSonucuLabel.setText("Sorun yok.")

        self.tabloGonderButton.click()
        self.animasyonKapatButon.click()
        br.close()

    def tabloIsle(self):

        if len(self.tabloyaGonderilenOgrenciler) > 0:
            self.sorguSonucuLabel.setStyleSheet("QLabel{background-color:red}")

            ogrenciler = self.tabloyaGonderilenOgrenciler
            sorunlar = self.tabloyaGonderilenSorunlar

            tablo = self.sorguSonucuTableWidget
            tablo.setRowCount(len(ogrenciler) + 1)

            for ogrenci in ogrenciler:
                sira = ogrenciler.index(ogrenci) + 1
                fotoLabel = QLabel()
                resim = ogrenci[RESIM_INDEX].scaled(45, 50, Qt.KeepAspectRatio)
                fotoLabel.setPixmap(resim)

                tablo.setCellWidget(sira, 0, fotoLabel)
                tablo.setItem(
                    sira, 1,
                    QTableWidgetItem(ogrenci[AD_INDEX] + " " +
                                     ogrenci[SOYAD_INDEX]))
                tablo.setItem(sira, 2,
                              QTableWidgetItem(str(ogrenci[OKUL_NO_INDEX])))
                tablo.setItem(sira, 3, QTableWidgetItem(sorunlar[sira - 1]))

                #* Tablo biçimlendirmeleri
                tablo.horizontalHeader().setSectionResizeMode(
                    0, QHeaderView.ResizeToContents)
                tablo.horizontalHeader().setSectionResizeMode(
                    1, QHeaderView.Stretch)
                tablo.horizontalHeader().setSectionResizeMode(
                    2, QHeaderView.Stretch)
                tablo.horizontalHeader().setSectionResizeMode(
                    3, QHeaderView.Stretch)
                tablo.verticalHeader().setSectionResizeMode(
                    QHeaderView.ResizeToContents)

        else:
            self.sorguSonucuLabel.setStyleSheet(
                "QLabel{background-color:green}")
            self.sorguSonucuLabel.setText("Sorun yok")

    def dosyaSec(self):
        dosyaAdi, _ = QFileDialog.getOpenFileName(
            self, 'Dosya seç', '', "Excel files (*.xls *.xlsx)")
        if dosyaAdi:
            self.dosyaYoluLineEdit.setText(dosyaAdi)

    def dizinSec(self):
        fotoDizin = str(QFileDialog.getExistingDirectory(self, "Dizin seç"))
        if fotoDizin:
            self.fotoYoluLineEdit.setText(fotoDizin)

    def topluKaydet(self):

        if self.kullaniciAdi.text() == "" or self.sifre.text() == "":
            self.mesaj = "E-Devlet kullanıcı adı ve şifrenizi girelisiniz."
            self.hataMesajiButton.click()
            return

        if os.path.exists(self.dosyaYoluLineEdit.text()) and os.path.exists(
                self.fotoYoluLineEdit.text()):
            #Excelden veriler alınıyor.
            ogrenciler = self.exceldenVeriAl()
            #Veritabanına kaydediliyor.

            hesListesi = [ogrenci[HES_KODU_INDEX] for ogrenci in ogrenciler]

            self.hesExcelDosyalasiniKaydet(hesListesi)

            #Tek grup oluşturuldu. Başarılı olursa veritabanına kaydedilecek.
            #Grup yoksa oluşturulacak varsa üstüne hes kodları eklenecek.
            self.yukleniyorAnimasyonuBaslat()

            yol = os.getcwd() + os.sep + OLUSTURULAN_EXCEL_DOSYASI_ADI
            if len(vt.DB.sinif_isimleri()) == 0:
                th = Thread(target=self.grupOlustur,
                            args=(E_DEVLET_GRUP_ADI, yol, ogrenciler))
                th.start()
            else:
                th = Thread(target=self.grupOlustur,
                            args=(E_DEVLET_GRUP_ADI, yol, ogrenciler, "",
                                  True))
                th.start()

        else:
            self.mesaj = "Excel dosyasını ve fotoğraf dizinini seçmelisiniz!"
            self.hataMesajiButton.click()

    def exceldenVeriAl(self):
        dosyaYolu = self.dosyaYoluLineEdit.text()
        indexler = {
            "ad": 1,
            "soyad": 2,
            "tc_no": 3,
            "hes": 5,
            "okul_no": 0,
            "sinif": 4
        }

        wb = load_workbook(dosyaYolu, read_only=True)
        ws = wb.active

        fotoYol = self.fotoYoluLineEdit.text()
        dosyaIsimleri = os.listdir(fotoYol)
        dosyaTamIsimleri = [
            i for i in dosyaIsimleri
            if i.endswith(".jpg") or i.endswith(".png")
        ]

        veriler = ws.values

        ogrenciler = []
        sayac = -1
        for satir in veriler:
            #Excelde ilk satır başlık satırı.
            sayac += 1
            if sayac == 0:
                continue

            ogrenci = []
            tmp = [*satir]

            tc = tmp[indexler["tc_no"]]
            if tc == None:
                break
            ogrenci.append(str(tc))

            ad = tmp[indexler["ad"]]
            ogrenci.append(ad)

            soyad = tmp[indexler["soyad"]]
            ogrenci.append(soyad)

            numara = tmp[indexler["okul_no"]]
            ogrenci.append(numara)

            numaraString = str(numara)

            sinif = tmp[indexler["sinif"]]
            ogrenci.append(sinif)

            if numaraString + ".jpg" in dosyaTamIsimleri:
                resim = fotoYol + "/" + numaraString + ".jpg"
            elif numaraString + ".png" in dosyaIsimleri:
                resim = fotoYol + "/" + numaraString + ".png"
            else:
                resim = ""

            ogrenci.append(resim)
            hes = tmp[indexler["hes"]]
            ogrenci.append(hes)
            ogrenci.append(1)
            ogrenciler.append(ogrenci)

        wb.close()

        return ogrenciler

    def hesExcelDosyalasiniKaydet(self, hesListesi):

        try:
            wb = xlsxwriter.Workbook(OLUSTURULAN_EXCEL_DOSYASI_ADI)
            ws = wb.add_worksheet()
            ws.write(0, 0, "HES KODU")

            yazilacak_satir = 1
            for hes in hesListesi:
                ws.write(yazilacak_satir, 0, hes)
                yazilacak_satir += 1

            wb.close()
            return True

        except:
            return False

    def sinifSilClicked(self):

        if self.comboboxSinifSec.currentText() == "":
            self.mesaj = "Silinecek sınıf yok!"
            self.hataMesaji()
            return

        qm = QMessageBox(self)
        mesaj = f"{self.comboboxSinifSec.currentText()} silinecek. Onaylıyor musunuz?"
        ret = qm.warning(self, 'Sınıf Sil', mesaj, qm.Yes | qm.No)

        if ret == qm.Yes:
            vt.DB.sinif_sil(self.comboboxSinifSec.currentText())
            self.btnSinifIslemleri.click()
            self.mesaj = "Sınıf silindi."
            self.hataMesajiButton.click()