class DownloadWindow(QDialog): def __init__(self, parent: Optional[QWidget] = None, url: str = '') -> None: super().__init__(parent, ) if parent: self.setWindowTitle('Download Mod') else: self.setWindowTitle(getTitleString('Download Mod')) self.setAttribute(Qt.WA_DeleteOnClose) mainLayout = QVBoxLayout(self) mainLayout.setContentsMargins(5, 5, 5, 5) self.signals = DownloadWindowEvents(self) # URL input gbUrl = QGroupBox('Mod URL') gbUrlLayout = QVBoxLayout() gbUrl.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.url = QLineEdit() self.url.setPlaceholderText( 'https://www.nexusmods.com/witcher3/mods/...') self.url.setText(url) self.url.textChanged.connect(lambda: self.validateUrl(self.url.text())) gbUrlLayout.addWidget(self.url) self.urlInfo = QLabel('🌐') self.urlInfo.setContentsMargins(4, 4, 4, 4) self.urlInfo.setMinimumHeight(36) self.urlInfo.setWordWrap(True) gbUrlLayout.addWidget(self.urlInfo) gbUrl.setLayout(gbUrlLayout) mainLayout.addWidget(gbUrl) # File selection gbFiles = QGroupBox('Mod Files') gbFilesLayout = QVBoxLayout() gbFiles.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.files = QTableWidget(0, 4) self.files.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.files.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.files.setContextMenuPolicy(Qt.CustomContextMenu) self.files.setSelectionMode(QAbstractItemView.ExtendedSelection) self.files.setSelectionBehavior(QAbstractItemView.SelectRows) self.files.setWordWrap(False) self.files.setSortingEnabled(True) self.files.setFocusPolicy(Qt.StrongFocus) self.files.verticalHeader().hide() self.files.setSortingEnabled(True) self.files.sortByColumn(2, Qt.DescendingOrder) self.files.verticalHeader().setVisible(False) self.files.verticalHeader().setDefaultSectionSize(25) self.files.horizontalHeader().setHighlightSections(False) self.files.horizontalHeader().setStretchLastSection(True) self.files.setHorizontalHeaderLabels( ['File Name', 'Version', 'Upload Date', 'Description']) self.files.setEditTriggers(QAbstractItemView.NoEditTriggers) self.files.verticalScrollBar().valueChanged.connect( lambda: self.files.clearFocus()) self.files.itemSelectionChanged.connect(lambda: self.validateFiles()) self.files.setDisabled(True) self.files.setStyleSheet(''' QTableView { gridline-color: rgba(255,255,255,1); } QTableView::item { padding: 5px; margin: 1px 0; } QTableView::item:!selected:hover { background-color: rgb(217, 235, 249); padding: 0; } ''') gbFilesLayout.addWidget(self.files) _mouseMoveEvent = self.files.mouseMoveEvent self.files.hoverIndexRow = -1 def mouseMoveEvent(event: QMouseEvent) -> None: self.files.hoverIndexRow = self.files.indexAt(event.pos()).row() _mouseMoveEvent(event) self.files.mouseMoveEvent = mouseMoveEvent # type: ignore self.files.setItemDelegate(ModListItemDelegate(self.files)) self.files.setMouseTracking(True) gbFiles.setLayout(gbFilesLayout) mainLayout.addWidget(gbFiles) # Actions actionsLayout = QHBoxLayout() actionsLayout.setAlignment(Qt.AlignRight) self.download = QPushButton('Download', self) self.download.clicked.connect(lambda: self.downloadEvent()) self.download.setAutoDefault(True) self.download.setDefault(True) self.download.setDisabled(True) actionsLayout.addWidget(self.download) cancel = QPushButton('Cancel', self) cancel.clicked.connect(self.cancelEvent) actionsLayout.addWidget(cancel) mainLayout.addLayout(actionsLayout) # Setup self.setMinimumSize(QSize(420, 420)) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.resize(QSize(720, 420)) self.finished.connect( lambda: self.validateUrl.cancel()) # type: ignore self.finished.connect( lambda: self.downloadEvent.cancel()) # type: ignore self.modId = 0 self.validateUrl(self.url.text()) def cancelEvent(self) -> None: self.close() @debounce(200, cancel_running=True) async def validateUrl(self, url: str) -> bool: self.download.setDisabled(True) self.files.setDisabled(True) self.files.clearSelection() self.files.clearFocus() self.files.clearContents() self.files.setRowCount(0) self.files.setSortingEnabled(False) self.url.setStyleSheet('') self.modId = 0 if not url: self.urlInfo.setText(''' <font color="#888">Please enter a valid mod url.</font> ''') return False modId = getModId(url) if not modId: self.files.setDisabled(True) self.url.setStyleSheet(''' *{ border: 1px solid #B22222; padding: 1px 0px; } ''') self.urlInfo.setText(''' <font color="#888">Please enter a valid mod url.</font> ''') return False self.urlInfo.setText('🌐') try: filesResponse = await getModFiles(modId) except (RequestError, ResponseError, Exception) as e: self.url.setStyleSheet(''' *{ border: 1px solid #B22222; padding: 1px 0px; } ''') self.urlInfo.setText(f''' <font color="#888">Could not get mod files: {e}.</font> ''') return False try: files = filesResponse['files'] if not len(files): self.urlInfo.setText(f''' <font color="#888">Mod "{modId}" has no files!</font> ''') return False self.files.setRowCount(len(files)) for i in range(len(files)): file = files[i] fileid = int(file['file_id']) name = str(file['name']) version = str(file['version']) _uploadtime = dateparser.parse(file['uploaded_time']) uploadtime = _uploadtime.astimezone(tz=None).strftime( '%Y-%m-%d %H:%M:%S') if _uploadtime else '?' description = html.unescape(str(file['description'])) nameItem = QTableWidgetItem(name) nameItem.setToolTip(name) nameItem.setData(Qt.UserRole, fileid) self.files.setItem(i, 0, nameItem) versionItem = QTableWidgetItem(version) versionItem.setToolTip(version) self.files.setItem(i, 1, versionItem) uploadtimeItem = QTableWidgetItem(uploadtime) uploadtimeItem.setToolTip(uploadtime) self.files.setItem(i, 2, uploadtimeItem) descriptionItem = QTableWidgetItem(description) descriptionItem.setToolTip(description) self.files.setItem(i, 3, descriptionItem) except KeyError as e: logger.exception( f'Could not find key "{str(e)}" in mod files response') self.urlInfo.setText(f''' <font color="#888">Could not find key "{str(e)}" in mod files response.</font> ''') return False self.urlInfo.setText(f''' <font color="#888">Found {len(files)} available files.</font> ''') self.files.resizeColumnsToContents() self.files.setDisabled(False) self.files.setSortingEnabled(True) self.modId = modId return True def validateFiles(self) -> bool: selection = self.files.selectionModel().selectedRows() if len(selection) > 0: self.download.setText(f'Download {len(selection)} mods') self.download.setDisabled(False) return True return False @debounce(25, cancel_running=True) async def downloadEvent(self) -> None: self.download.setDisabled(True) self.url.setDisabled(True) selection = self.files.selectionModel().selectedRows() files = [ self.files.item(index.row(), 0).data(Qt.UserRole) for index in selection ] self.files.setDisabled(True) try: urls = await asyncio.gather( *[getModFileUrls(self.modId, file) for file in files], loop=asyncio.get_running_loop()) except (RequestError, ResponseError, Exception) as e: self.url.setStyleSheet(''' *{ border: 1px solid #B22222; padding: 1px 0px; } ''') self.urlInfo.setText(f''' <font color="#888">Could not download mod files: {e}.</font> ''') return try: self.signals.download.emit([url[0]['URI'] for url in urls]) except KeyError as e: logger.exception( f'Could not find key "{str(e)}" in file download response') self.urlInfo.setText(f''' <font color="#888">Could not find key "{str(e)}" in file download response.</font> ''') return self.close()
class Buscador(QWidget): status_signal = Signal(str) def __init__(self): self.db = ClientesDB() QWidget.__init__(self) Font = QFont() Font.setBold(True) # Labels em Negrito # Entry: self.entry_nome = QLineEdit() self.entry_nome.setText("Nome para Busca") # Botões self.button_busca = QPushButton("&Busca") self.button_busca.clicked.connect(self.buscar) self.button_busca.setShortcut("Ctrl+B") self.button_limpar = QPushButton("Limpar") self.button_limpar.clicked.connect(self.limpar) self.button_limpar.setShortcut("ESC") # Tabela self.clientes = 0 self.tabela_clientes = QTableWidget() self.tabela_clientes.setColumnCount(4) self.tabela_clientes.setHorizontalHeaderLabels([ "Nome", "Número", "CPF", "Endereço", ]) self.tabela_clientes.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.tabela_clientes.horizontalHeader().setStretchLastSection(True) self.tabela_clientes.resizeColumnsToContents() self.tabela_clientes.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tabela_clientes.itemDoubleClicked.connect(self.info_cliente) #Leiaute: self.layout = QVBoxLayout() self.layout_busca = QHBoxLayout() self.layout_busca.addWidget(self.entry_nome) self.layout_busca.addWidget(self.button_busca) self.layout.addLayout(self.layout_busca) self.layout.addWidget(self.tabela_clientes) self.setLayout(self.layout) @Slot() def buscar(self): nome_buscado = self.entry_nome.text() data = self.db.busca(nome_buscado) self.limpar() self.status_signal.emit("Feito") for cliente in data: nome = QTableWidgetItem(cliente['nome']) numero = QTableWidgetItem(cliente['numero']) cpf = QTableWidgetItem(cliente['cpf']) endereco = QTableWidgetItem(cliente['endereco']) nome.setTextAlignment(Qt.AlignCenter) numero.setTextAlignment(Qt.AlignCenter) cpf.setTextAlignment(Qt.AlignCenter) endereco.setTextAlignment(Qt.AlignCenter) self.tabela_clientes.insertRow(self.clientes) self.tabela_clientes.setItem(self.clientes, 0, nome) self.tabela_clientes.setItem(self.clientes, 1, numero) self.tabela_clientes.setItem(self.clientes, 2, cpf) self.tabela_clientes.setItem(self.clientes, 3, endereco) self.clientes += 1 @Slot() def limpar(self): self.tabela_clientes.clearContents() self.tabela_clientes.setRowCount(0) self.clientes = 0 @Slot() def info_cliente(self): pass
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)