class SetPolicyWidget(QWidget):

    Sg_view_changed = Signal()

    def __init__(self, model: SettingsModel, parent=None):
        super(SetPolicyWidget, self).__init__(parent)

        self._model = model

        self.setAccessibleName("InfoBox")

        self.titolo = QLabel("Politica di gestione conflitti")
        self.titolo.setAccessibleName('Title2')

        self.sottotitolo = QLabel("Cambia come vengono gestiti conflitti")
        self.sottotitolo.setAccessibleName('Sottotitolo')

        self.spaceLabel = QLabel(" ")

        self.client = QRadioButton(
            "Client: le modifiche in locale sovrascrivono quelle presenti nel server"
        )
        self.manual = QRadioButton(
            "Manuale: verranno salvati entrambi i file, sarà l'utente a decidere cosa mantenere"
        )
        self.Sl_model_changed()

        layout = QVBoxLayout()
        layout.addWidget(self.titolo)
        layout.addWidget(self.sottotitolo)
        layout.addWidget(self.spaceLabel)
        sub_layout = QVBoxLayout()
        sub_layout.addWidget(self.client)
        sub_layout.addWidget(self.manual)

        layout.addLayout(sub_layout)
        self.setLayout(layout)

        self.client.clicked.connect(self.Sl_client_checked)
        self.manual.clicked.connect(self.Sl_manual_checked)

    @Slot()
    def Sl_client_checked(self):
        if self.client.isChecked():
            self.Sg_view_changed.emit()

    @Slot()
    def Sl_manual_checked(self):
        if self.manual.isChecked():
            self.Sg_view_changed.emit()

    @Slot()
    def Sl_model_changed(self):
        if self._model.get_policy() == Policy.Manual:
            self.client.setChecked(False)
            self.manual.setChecked(True)
        else:
            self.client.setChecked(True)
            self.manual.setChecked(False)
Esempio n. 2
0
class ReferenceDialog(QDialog):
    def __init__(self, parent):
        super().__init__(parent)
        self.setWindowTitle("Set reference")
        vbox = QVBoxLayout(self)
        grid = QGridLayout()
        self.average = QRadioButton("Average")
        self.channels = QRadioButton("Channel(s):")
        self.average.toggled.connect(self.toggle)
        self.channellist = QLineEdit()
        self.channellist.setEnabled(False)
        self.average.setChecked(True)
        grid.addWidget(self.average, 0, 0)
        grid.addWidget(self.channels, 1, 0)
        grid.addWidget(self.channellist, 1, 1)
        vbox.addLayout(grid)
        buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        vbox.addWidget(buttonbox)
        buttonbox.accepted.connect(self.accept)
        buttonbox.rejected.connect(self.reject)
        vbox.setSizeConstraint(QVBoxLayout.SetFixedSize)

    def toggle(self):
        if self.average.isChecked():
            self.channellist.setEnabled(False)
        else:
            self.channellist.setEnabled(True)
class Importador(QWidget):
    """GUI class for the BGG -> Ludopedia importer"""
    enable_editables = Signal(bool)
    alternative_chosen = Signal(object)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.thread = QThread()
        self.worker = None
        grid_layout = QGridLayout(self)
        login_group_box = self.create_login_group()
        data_group_box = self.create_data_group()
        self.enable_editables.connect(login_group_box.setEnabled)
        self.enable_editables.connect(data_group_box.setEnabled)
        self.import_button = QPushButton('Importar', self)
        self.import_button.setEnabled(False)
        self.enable_editables.connect(self.import_button.setEnabled)
        self.import_button.clicked.connect(self.enable_editables)
        self.import_button.clicked.connect(self.load_data)
        self.bgg_user_line_edit.textChanged.connect(self.enable_import)
        self.ludo_mail_line_edit.textChanged.connect(self.enable_import)
        self.ludo_pass_line_edit.textChanged.connect(self.enable_import)
        grid_layout.addWidget(login_group_box, 1, 1, 1, 2)
        grid_layout.addWidget(data_group_box, 2, 1, 1, 2)
        grid_layout.addWidget(self.import_button, 8, 2)
        self.log_widget = QTextEdit(self)
        self.log_widget.setReadOnly(True)
        grid_layout.addWidget(self.log_widget, 9, 1, 30, 2)

    def create_qlineedit(self, text):
        """Creates a label with the given text and an accompanying line edit"""
        line_edit = QLineEdit(self)
        line_edit_label = QLabel(text, line_edit)
        line_edit_label.setBuddy(line_edit)
        return (line_edit, line_edit_label)

    def create_login_group(self):
        """Create labels and line edits for providing BGG and ludopedia login information"""
        (self.bgg_user_line_edit,
         bgg_user_label) = self.create_qlineedit('Usuario BoardGameGeek:')
        (self.ludo_mail_line_edit,
         ludo_mail_label) = self.create_qlineedit('E-mail Ludopedia:')
        (self.ludo_pass_line_edit,
         ludo_pass_label) = self.create_qlineedit('Senha Ludopedia:')
        self.ludo_pass_line_edit.setEchoMode(QLineEdit.PasswordEchoOnEdit)
        group_box = QGroupBox('Login')
        grid_layout = QGridLayout(group_box)
        grid_layout.addWidget(bgg_user_label, 1, 1)
        grid_layout.addWidget(self.bgg_user_line_edit, 1, 2)
        grid_layout.addWidget(ludo_mail_label, 2, 1)
        grid_layout.addWidget(self.ludo_mail_line_edit, 2, 2)
        grid_layout.addWidget(ludo_pass_label, 3, 1)
        grid_layout.addWidget(self.ludo_pass_line_edit, 3, 2)
        group_box.setLayout(grid_layout)
        return group_box

    def create_data_group(self):
        """Creates group for holding specific choice data selection"""
        button_group = QButtonGroup(self)
        button_group.setExclusive(True)
        colecao_radio_button = QRadioButton('Coleção')
        self.partidas_radio_button = QRadioButton('Partidas')
        colecao_radio_button.setChecked(True)
        button_group.addButton(colecao_radio_button)
        button_group.addButton(self.partidas_radio_button)
        (self.min_date_picker,
         min_date_label) = create_date_picker('À Partir de:', self)
        (self.max_date_picker,
         max_date_label) = create_date_picker('Até:', self)
        self.min_date_picker.dateChanged.connect(
            self.max_date_picker.setMinimumDate)
        colecao_radio_button.toggled.connect(self.min_date_picker.setDisabled)
        colecao_radio_button.toggled.connect(self.max_date_picker.setDisabled)
        self.map_users_button = QPushButton(
            'Ver mapa de usuarios BGG -> Ludopedia', self)
        self.map_users_button.setEnabled(False)
        self.map_users_button.clicked.connect(self.user_map)
        colecao_radio_button.toggled.connect(self.map_users_button.setDisabled)
        group_box = QGroupBox('Dados')
        grid_layout = QGridLayout(group_box)
        grid_layout.addWidget(colecao_radio_button, 1, 1)
        grid_layout.addWidget(self.partidas_radio_button, 1, 2)
        grid_layout.addWidget(min_date_label, 2, 1)
        grid_layout.addWidget(self.min_date_picker, 2, 2)
        grid_layout.addWidget(max_date_label, 3, 1)
        grid_layout.addWidget(self.max_date_picker, 3, 2)
        grid_layout.addWidget(self.map_users_button, 4, 1, 1, 2)
        group_box.setLayout(grid_layout)
        return group_box

    def enable_import(self):
        """Slot to toggle state of the import button"""
        self.import_button.setDisabled(not self.bgg_user_line_edit.text()
                                       or not self.ludo_mail_line_edit.text()
                                       or not self.ludo_pass_line_edit.text())

    def log_text(self, message_type, text):
        """Logs the given text to the QPlainTextWidget"""
        current_time = QTime.currentTime().toString()
        if message_type == MessageType.ERROR:
            self.log_widget.insertHtml(
                f'[{current_time}] {ERROR_HTML}{text}<br>')
        elif message_type == MessageType.GENERIC:
            self.log_widget.insertHtml(f'[{current_time}] {text}<br>')
        elif message_type == MessageType.DEBUG and ENABLE_DEBUG:
            self.log_widget.insertHtml(
                f'[{current_time}] {DEBUG_HTML}{text}<br>')

        self.log_widget.moveCursor(QTextCursor.End)
        if ENABLE_DEBUG:
            print(text)

    def disconnect_thread(self):
        """Disconnect the started signal from the thread"""
        self.thread.started.disconnect()

    def configure_thread(self, worker):
        """Does basic thread startup and cleanup configuration"""
        worker.finished.connect(self.thread.quit)
        worker.moveToThread(self.thread)
        self.thread.started.connect(worker.run)
        worker.message.connect(self.log_text)
        worker.finished.connect(self.disconnect_thread)
        worker.exit_on_error.connect(self.thread.quit)
        worker.exit_on_error.connect(lambda: self.enable_editables.emit(True))

    def load_data(self):
        """Load data from bgg"""
        try:
            (session, ludo_user_id) = self.login_ludopedia()
            bgg_user = self.bgg_user_line_edit.text()

            if self.partidas_radio_button.isChecked():
                current_date = format_qdate(QDate.currentDate())
                min_date = parse_date(
                    format_qdate(self.min_date_picker.date()), current_date)
                max_date = parse_date(
                    format_qdate(self.max_date_picker.date()), min_date)
                self.worker = BGGPlayFetcher(bgg_user, min_date, max_date)
                self.configure_thread(self.worker)
                self.worker.finished.connect(lambda plays: self.post_plays(
                    session, plays, bgg_user, ludo_user_id))
            else:
                self.worker = BGGColectionFetcher(bgg_user)
                self.configure_thread(self.worker)
                self.worker.finished.connect(
                    lambda bgg_collection: self.import_collection(
                        session, bgg_collection))
            self.thread.start()
        except InputError:
            self.enable_editables.emit(True)

    def show_play_table(self, plays):
        """Shows a table with all the plays to be imported, allowing user to select some to skip"""
        tree_model = PlayTableModel(plays)
        table_widget = QTableView()
        table_widget.setModel(tree_model)
        table_widget.verticalHeader().setVisible(False)
        table_view_header = table_widget.horizontalHeader()
        table_view_header.setStretchLastSection(True)
        for column in range(tree_model.columnCount()):
            column_size = tree_model.data(tree_model.index(0, column),
                                          PlayTableModel.SIZE_ROLE)
            table_view_header.resizeSection(column, column_size)
        table_widget_dialog = QDialog(self)
        table_widget_dialog.setModal(True)
        grid_layout = QGridLayout(table_widget_dialog)
        grid_layout.addWidget(table_widget, 1, 1)
        table_widget_dialog.resize(800, 600)
        table_widget_dialog.exec_()
        skipped_plays = tree_model.get_skipped_plays()
        return [play for play in plays if play.id not in skipped_plays]

    def post_plays(self, session, plays, bgg_user, ludo_user_id):
        """Receives plays from the Play Fetched thread and start the Ludopedia Logger"""
        user_map = self.get_bgg_to_ludo_users()
        if bgg_user not in user_map:
            user_map[bgg_user] = ludo_user_id

        selected_plays = self.show_play_table(plays)

        self.worker = LudopediaPlayLogger(session, selected_plays, bgg_user,
                                          user_map)
        self.worker.request_search.connect(
            self.request_search_and_show_alternatives,
            Qt.BlockingQueuedConnection)
        self.worker.request_alternative.connect(self.request_alternative,
                                                Qt.BlockingQueuedConnection)
        self.alternative_chosen.connect(self.worker.receive_alternative,
                                        Qt.DirectConnection)
        self.configure_thread(self.worker)
        self.worker.finished.connect(lambda: self.enable_editables.emit(True))
        self.thread.start()

    def user_map(self):
        """Slot to show user map from bgg to ludopedia"""
        user_map_dialog = QDialog(self)
        user_map_dialog.setModal(True)
        bgg_to_ludo = self.get_bgg_to_ludo_users()
        user_list = [f'{key} -> {value}' for key, value in bgg_to_ludo.items()]
        list_widget = QListWidget(user_map_dialog)
        list_widget.addItems(user_list)
        list_widget.setResizeMode(QListView.Adjust)
        list_widget.sortItems()
        grid_layout = QGridLayout(user_map_dialog)
        grid_layout.addWidget(list_widget, 1, 1)
        user_map_dialog.resize(400, 400)
        user_map_dialog.show()

    def login_ludopedia(self):
        """Logins into Ludopedia manually and returns the session and user_id"""
        self.log_text(MessageType.GENERIC, 'Obtendo dados do Ludopedia')
        payload = {
            'email': self.ludo_mail_line_edit.text(),
            'pass': self.ludo_pass_line_edit.text()
        }

        session = requests.Session()
        session_request = session.post(LUDOPEDIA_LOGIN_URL, data=payload)

        if 'senha incorretos' in session_request.text:
            self.log_text(
                MessageType.ERROR,
                'Não foi possível logar na Ludopedia com as informações fornecidas'
            )
            raise InputError

        user_re = re.search(r'id_usuario=(\d+)', session_request.text)
        user_id = user_re.group(1) if user_re else None

        return (session, user_id)

    def import_collection(self, session, collection):
        """Imports a given collection into Ludopedia"""
        self.worker = LudopediaCollectionLogger(session, collection)
        self.configure_thread(self.worker)
        self.worker.finished.connect(lambda: self.enable_editables.emit(True))
        self.thread.start()

    def show_alternatives_dialog(self, bgg_play, data):
        """Show alternative games to use as the game to log a play"""
        alternatives_dialog = QInputDialog(self)
        alternatives_list = [
            f'{item["nm_jogo"]} ({item["ano_publicacao"]})' for item in data
        ]
        alternatives_dialog.setComboBoxItems(alternatives_list)
        alternatives_dialog.setOption(QInputDialog.UseListViewForComboBoxItems)
        game_str = f'{bgg_play.game_name} ({bgg_play.year_published})'
        alternatives_dialog.setLabelText(
            f'Escolha uma alternativa para o jogo "{game_str}"')
        if alternatives_dialog.exec_():
            selected_index = alternatives_list.index(
                alternatives_dialog.textValue())
            return data[selected_index]
        return None

    def request_search_and_show_alternatives(self, session, bgg_play):
        """Request a new string to use for game search and then show results to be picked"""
        new_search_dialog = QInputDialog(self)
        game_str = f'{bgg_play.game_name} ({bgg_play.year_published})'
        new_search_dialog.setLabelText(
            f'Jogo "{game_str}" não encontrado\nBuscar por:')
        new_search_dialog.setInputMode(QInputDialog.TextInput)
        if new_search_dialog.exec_():
            data = search_ludopedia_games(session,
                                          new_search_dialog.textValue())
            data = self.show_alternatives_dialog(bgg_play, data)
            self.alternative_chosen.emit(data)

    def request_alternative(self, bgg_play, data):
        """Request an alternative from user and emit choice"""
        alternative = self.show_alternatives_dialog(bgg_play, data)
        self.alternative_chosen.emit(alternative)

    def get_bgg_to_ludo_users(self):
        """Reads usuarios.txt file to map a bgg user to its corresponding ludopedia one"""
        try:
            parser = ConfigParser()
            with open("usuarios.txt") as lines:
                lines = chain(("[top]", ), lines)
                parser.read_file(lines)
                bgg_to_ludo_user = dict(parser['top'])
                bgg_to_ludo_user_id = dict()
                for bgg_user, ludo_user in bgg_to_ludo_user.items():
                    if is_invalid_bgg_user(bgg_user):
                        self.log_text(
                            MessageType.ERROR,
                            f'Usuário do BGG "{bgg_user}" inválido'
                            f' no mapa de usuários')
                        continue

                    if ludo_user.isdigit():
                        bgg_to_ludo_user_id[bgg_user] = ludo_user
                        self.log_text(
                            MessageType.DEBUG,
                            f'Usuário do BGG "{bgg_user}" já mapeado'
                            f' ao id ludopedia: {ludo_user}')
                    else:
                        ludo_user_id = get_ludo_user_id(ludo_user)
                        if ludo_user_id:
                            self.log_text(MessageType.DEBUG,
                                          f'{ludo_user_id} para {ludo_user}')
                            bgg_to_ludo_user_id[bgg_user] = ludo_user_id
                        else:
                            self.log_text(
                                MessageType.ERROR,
                                f'Falha ao buscar id de usuario da'
                                f' ludopedia para "{ludo_user}"')
                return bgg_to_ludo_user_id
        except FileNotFoundError:
            self.log_error(
                MessageType.ERROR,
                'Não foi possível encontrar o arquivo "usuarios.txt')
            return {}
Esempio n. 4
0
class Maker(QWidget):
    def __init__(self, parent=None):
        super(Maker, self).__init__(parent)

        self.setWindowTitle("Project Maker")

        self.userFilepath = QLineEdit()
        self.userFilepath.setPlaceholderText("Your filepath here...")
        self.projName = QLineEdit()
        self.projName.setPlaceholderText("Your project name here...")
        self.makeButton = QPushButton("Create Project")
        self.fileSearchButton = QPushButton("...")
        self.fileSearchButton.setToolTip(
            "Search for a directory for your project")

        self.goProj = QRadioButton("Go Project")
        self.goProj.setToolTip("You will still need a go.mod file")
        self.pyProj = QRadioButton("Python Project")
        self.versionControlFiles = QCheckBox(
            "Create README.md and .gitignore?")
        self.versionControlFiles.setToolTip(
            "Creates the files used in online version control, such as Github")
        self.pyProj.setChecked(True)
        self.versionControlFiles.setChecked(True)

        projSelect = QGroupBox("Project Selection")
        projectOptions = QVBoxLayout()
        projectOptions.addWidget(self.pyProj)
        projectOptions.addWidget(self.goProj)
        projectOptions.addWidget(self.versionControlFiles)
        projectOptions.stretch(1)
        projSelect.setLayout(projectOptions)

        searchLayout = QHBoxLayout()
        searchLayout.addWidget(self.userFilepath)
        searchLayout.addWidget(self.fileSearchButton)
        searchLayout.stretch(1)

        layout = QVBoxLayout()
        layout.addLayout(searchLayout)
        layout.addWidget(self.projName)
        layout.addWidget(self.makeButton)
        layout.addWidget(self.fileSearchButton)
        layout.addWidget(projSelect)
        self.setLayout(layout)

        self.makeButton.clicked.connect(self.createFiles)
        self.fileSearchButton.clicked.connect(self.onClickFileSearch)

    @Slot()
    def onClickFileSearch(self):
        fileSearch = QFileDialog.getExistingDirectory(self,
                                                      "Select a Directory...",
                                                      "C:/Users")
        self.userFilepath.setText(fileSearch)

    @Slot()
    def createFiles(self):
        p = Path(f"{self.userFilepath.text()}/{self.projName.text()}")
        try:
            p.mkdir()
        except FileExistsError as exc:
            msgbox = QMessageBox()
            msgbox.setText(f"{exc}")
            msgbox.exec()
        else:
            os.chdir(f"{self.userFilepath.text()}\\{self.projName.text()}")
            if self.pyProj.isChecked():
                fileType = "py"
            elif self.goProj.isChecked():
                fileType = "go"
            with open(f"{self.projName.text()}.{fileType}", "w") as f:
                f.write(f"# Created on {date.today()}")
            if self.versionControlFiles.isChecked():
                open("README.md", "a").close()
                open(".gitignore", "a").close()
Esempio n. 5
0
class MainWindow(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self)
        # Variaveis
        self.separador = ";" # Separador padrao de colunas em um arquivo txt ou csv
        self.selected = np.array([1, 24, 48, 96]).astype('timedelta64[h]') # selecionados ao iniciar o programa, modificavel.
        self.fileformat =  '' # Reservado para o formato do arquivo a ser aberto. Pode ser .xlsx ou .odf. ou .csv e assim vai.

        # facilita o acesso a variavel.
        self.timedeltastr = ("1 Hora","2 Horas", "3 Horas", "4 Horas","12 Horas",
         "24 Horas", "48 Horas", "72 horas", "96 horas", "30 Dias")
        self.timedeltas = np.array([1, 2, 3, 4, 12, 24, 48, 72, 96, 24*30]).astype('timedelta64[h]')
        self.linktimedelta = dict([(self.timedeltas[x], self.timedeltastr[x]) for x in range(len(self.timedeltastr))])

        self.datastring = ["DD/MM/AAAA",'AAAA/MM/DD', "AAAA-MM-DD", "DD-MM-AAAA"]
        self.dataformat = ["%d/%m/%Y", "%Y/%m/%d", "%Y-%m-%d", "%d-%m-%Y"]
        self.linkdata = dict([(self.datastring[x], self.dataformat[x]) for x in range(len(self.dataformat))])

        self.timestring = ["hh:mm", "hh:mm:ss", "hh:mm:ss.ms"]
        self.timeformat = ["%H:%M", "%H:%M:%S", "%H:%M:%S.%f"]
        self.linktime = dict([(self.timestring[x], self.timeformat[x]) for x in range(len(self.timeformat))])

        #Janela Principal
        widget = QWidget()
        self.setCentralWidget(widget)

        # Inicializa os Widgets
        self.folder = QLineEdit("Salvar Como...")
        self.path = QLineEdit("Abrir arquivo...")
        #
        buttonOpen = QPushButton('Abrir')
        buttonSave = QPushButton("Destino")
        Processar = QPushButton('Executar')
        Ajuda = QPushButton('Informações')
        #
        groupBox2 = QGroupBox("Delimitador")
        self.delimitador1 = QRadioButton("Ponto-Vírgula")
        self.delimitador2 = QRadioButton("Vírgula")
        self.delimitador3 = QRadioButton("Ponto")
        self.delimitador4 = QRadioButton("Tabulação")
        #
        checkGroup = QGroupBox("Mais opções")
        text3 = QPushButton("Configurações")
        text2 = QLabel("Formato da Data")
        text1 = QLabel("Formato da Hora")
        self.FormatoTime = QComboBox()
        self.FormatoTime.addItems(self.timestring)
        self.FormatoData = QComboBox()
        self.FormatoData.addItems(self.datastring)
        #
        text = QLabel("Por favor, selecione na tabela abaixo as colunas a utilizar:")
        self.ignore = QRadioButton("Possui Cabeçalho") # True se estiver selecionado, False caso nao
        #
        self.Tabela = QTableWidget(15,15)
        self.startTable()

        # Layouts
        MainLayout = QVBoxLayout()

        Gridlayout = QGridLayout()
        Gridlayout.addWidget(self.path, 0, 0)
        Gridlayout.addWidget(self.folder, 1, 0)
        Gridlayout.addWidget(buttonOpen, 0, 1)
        Gridlayout.addWidget(buttonSave, 1, 1)
        Gridlayout.addWidget(Processar, 0, 3)
        Gridlayout.addWidget(Ajuda, 1, 3)
        Gridlayout.setColumnStretch(0, 2)
        Gridlayout.setColumnStretch(3, 1)
        Gridlayout.setColumnMinimumWidth(2, 20)

        SecondLayout = QHBoxLayout()
        SecondLayout.addWidget(groupBox2)
        SecondLayout.addSpacing(40)
        SecondLayout.addWidget(checkGroup)
        #
        SepLayout = QVBoxLayout()
        SepLayout.addWidget(self.delimitador1)
        SepLayout.addWidget(self.delimitador2)
        SepLayout.addWidget(self.delimitador3)
        SepLayout.addWidget(self.delimitador4)
        #
        OptionsLayout = QVBoxLayout()
        OptionsLayout.addWidget(text3)
        OptionsLayout.addWidget(text2)
        OptionsLayout.addWidget(self.FormatoData)
        OptionsLayout.addWidget(text1)
        OptionsLayout.addWidget(self.FormatoTime)

        ThirdLayout = QVBoxLayout()
        ThirdLayout.addWidget(self.ignore)
        ThirdLayout.addWidget(text)

        MainLayout.addLayout(Gridlayout)
        MainLayout.addLayout(SecondLayout)
        MainLayout.addLayout(ThirdLayout)
        MainLayout.addWidget(self.Tabela)

        # Coloca o Layout principal na Janela
        widget.setLayout(MainLayout)

        # Comandos dos Widgets e edicoes.
        groupBox2.setLayout(SepLayout)
        self.delimitador1.setChecked(True)
        self.folder.setReadOnly(True)
        self.path.setReadOnly(True)
        checkGroup.setLayout(OptionsLayout)

        buttonOpen.clicked.connect(self.searchFile)
        buttonSave.clicked.connect(self.getNewFile)
        self.delimitador1.clicked.connect(self.updateDelimiter)
        self.delimitador2.clicked.connect(self.updateDelimiter)
        self.delimitador3.clicked.connect(self.updateDelimiter)
        self.delimitador4.clicked.connect(self.updateDelimiter)
        Ajuda.clicked.connect(self.help)
        Processar.clicked.connect(self.taskStart)
        text3.clicked.connect(self.openSubWindow)

        # Propriedades da janela principal
        height = 480
        width = 640
        myappid = 'GePlu.release1_0.0' # arbitrary string
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
        self.setWindowIcon(QIcon(r'images\icon6.ico'))
        self.setFixedSize(width, height)
        self.setWindowTitle("GePlu")

    def openSubWindow(self):

        dialog = MyDialog(self)
        dialog.show()
        dialog.exec_()

    def taskStart(self):
        ''' Inicia a execucao do programa, se houver algum erro durante o processo
        notifica o usuario e deixa a funcao imediatamente'''
        if self.folder.isModified() and self.path.isModified(): # o usuario entrou com os enderecos?
            start = time.time()

            # Conhece do que se trata cada coluna na tabela e armazena essa informacao.
            header = {}
            for col in range(15):
                header[self.Tabela.cellWidget(0, col).currentText()] = col

            boolean = 0 if self.ignore.isChecked() else None

            # Le o arquivo e retorna um dataframe de strings
            df_master = utils.read_file(self, header = boolean)
            df_master = dt.data_filter(self, df_master, header)
            df_master = dt.convert_dtype(self, df_master)

            # Computa os acumulados para cada intervalo de tempo (key).
            for key in self.selected:
                array = dt.compute(df_master.index.to_numpy(), df_master['Observado'].to_numpy(), key)
                df_master[self.linktimedelta[key]] = pd.Series(array, df_master.index)

            # salva o arquivo final.
            utils.save_file(self, df_master)

            # Fim do processo
            end = time.time()
            # Notifica o usuario
            QMessageBox.information(self, "Notificação", "Tarefa realizada com sucesso!\nTempo de execução: {} s.".format(round(end-start, 2)))
            # Reseta a tabela e os endereço do arquivo aberto e onde salvar, na janela principal.
            self.resetProgram()

        else:
            QMessageBox.warning(self, "Notificação", "Houve um erro no arquivo ou diretório especificado.\nPor favor, selecione um caminho válido.")


    def help(self):
        x = 'Caso tenha alguma dúvida, abra o documento em PDF presente\nna pasta do programa ou entre em contato.\n\nGeplu\n1.0.0'
        msgBox = QMessageBox.information(self, "Informação", x)

    def resetProgram(self):
        self.Tabela.clearContents()
        self.startTable()
        self.folder.setText("Salvar Como...")
        self.path.setText("Selecionar o arquivo...")
        self.folder.setModified(False)
        self.folder.setModified(False)

    def updateDelimiter(self):
        separadores = {"Ponto-Vírgula": ';', "Vírgula":",", "Ponto":".", "Tabulação":"\t"}
        for x in [self.delimitador1, self.delimitador3, self.delimitador2, self.delimitador4]:
            if x.isChecked():
                self.separador = separadores[x.text()]
                break

        if self.path.isModified():
            self.updateTable()

    def startTable(self):
        for col in range(self.Tabela.columnCount()):
            combo = QComboBox()
            combo.addItems(["Selecionar","Data & Hora","Prec. Observada","Data","Hora","Nível do Rio"])
            self.Tabela.setCellWidget(0, col, combo)

    def updateTable(self):
        # Guarda a primeira linha
        n_col = self.Tabela.columnCount()
        textos = [0]*n_col
        for col in range(n_col): textos[col] = self.Tabela.cellWidget(0, col).currentText()

        self.Tabela.clearContents()
        self.startTable()

        for col in range(n_col): self.Tabela.cellWidget(0, col).setCurrentText(textos[col])

        # Mostra na tabela as primeiras 14 linhas do arquivo que o usuario deseja abrir/utilizar.
        data_df = utils.read_file(self, 14).to_numpy()
        for row in range(data_df.shape[0]):
            for col in range(data_df.shape[1]):
                self.Tabela.setItem(row+1, col, QTableWidgetItem(data_df[row][col]))


    def searchFile(self):
        address, x = QFileDialog.getOpenFileName(self, "Selecione um arquivo",
            filter = "Text files (*.txt *.csv *.xlsx)"
            )
        if len(address) > 0:
            self.path.setText(address)
            self.path.setModified(True)
            self.fileformat = address[address.index('.'):]
            self.updateTable()

    def getNewFile(self):
        address, x = QFileDialog.getSaveFileName(self, "Salvar como",
            filter = "Text files (*.csv);; Text files (*.txt);; Planilha do Microsoft Excel (*.xlsx)"
            )
        if len(address) > 0:
            self.folder.setText(address)
            self.folder.setModified(True)