Carregar ficheiros para "/"
This commit is contained in:
44
README.md
Normal file
44
README.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Analisador ASCII de Ficheiros ECU
|
||||
|
||||
Esta é uma aplicação Python standalone para analisar ficheiros binários (com foco em ficheiros de ECU automóvel) e extrair padrões ASCII relevantes.
|
||||
|
||||
## Funcionalidades
|
||||
|
||||
- Interface gráfica simples para seleção de ficheiros.
|
||||
- Procura por diversos padrões de texto, incluindo:
|
||||
- Famílias de ECU (MEDC, EDC, MDG, MD1)
|
||||
- Números de Software
|
||||
- VIN (Número de Identificação do Veículo)
|
||||
- Códigos de 3+ letras
|
||||
- Sequências longas de números
|
||||
- Possíveis Códigos PIN
|
||||
- Números de Peça Bosch
|
||||
- Endereços de Email
|
||||
- URLs
|
||||
- Apresentação dos resultados numa janela dedicada, com contagem de ocorrências.
|
||||
- Barra de progresso durante a análise.
|
||||
|
||||
## Como Executar
|
||||
|
||||
1. Certifique-se de que tem Python 3 instalado.
|
||||
2. Guarde o ficheiro `ecu_ascii_analyzer.py`.
|
||||
3. Execute o script a partir da linha de comandos:
|
||||
```bash
|
||||
python ecu_ascii_analyzer.py
|
||||
```
|
||||
4. Use o botão "Procurar..." para selecionar um ficheiro.
|
||||
5. Clique em "Analisar Ficheiro" para iniciar a análise.
|
||||
|
||||
## Padrões Procurados
|
||||
|
||||
A aplicação procura pelos seguintes padrões (ignorando maiúsculas/minúsculas):
|
||||
|
||||
- **Ecu Family**: `\b(MEDC|EDC|MDG|MD1)\b`
|
||||
- **Possible Software Number**: `\b\d{9,11}\b`
|
||||
- **VIN (Vehicle Identification Number)**: `\b[A-HJ-NPR-Z0-9]{17}\b`
|
||||
- **Potential Codes (3+ letters)**: `\b[A-Z]{3,}\b`
|
||||
- **Long Numbers (5+ digits)**: `\b\d{5,}\b`
|
||||
- **Possible Pin Code (4 Alphanum)**: `\b[A-Z0-9]{4}\b`
|
||||
- **Bosch Part Number**: `\b0\s?2[68]\d[\s\d]{6,7}\b`
|
||||
- **Email Address**: `[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`
|
||||
- **URL**: `https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&//=]*)`
|
||||
514
ecu_ascii_analyzer.py
Normal file
514
ecu_ascii_analyzer.py
Normal file
@ -0,0 +1,514 @@
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog, scrolledtext, ttk, messagebox
|
||||
import re
|
||||
import os
|
||||
from collections import Counter
|
||||
|
||||
# Importações dos novos módulos de padrões
|
||||
from patterns.common_patterns import PATTERNS_COMMON, INITIAL_ANALYSIS_PATTERNS_KEYS
|
||||
from patterns.landrover_jaguar_patterns import PATTERNS_LANDROVER_JAGUAR
|
||||
from patterns.vag_patterns import PATTERNS_VAG
|
||||
from patterns.bmw_patterns import PATTERNS_BMW # Importar PATTERNS_BMW
|
||||
from Data.vag_ecu_group_handler import load_vag_ecu_list
|
||||
from Data.jlr_ecu_group_handler import load_jlr_ecu_list
|
||||
from Data.bmw_ecu_group_handler import load_bmw_ecu_list # Nova importação para BMW
|
||||
# No futuro, adicionar importações para outros módulos de marca aqui:
|
||||
# from patterns.bmw_patterns import PATTERNS_BMW
|
||||
# etc.
|
||||
|
||||
# --- Constantes Globais ---
|
||||
BRAND_NAMES = ['VAG', 'LandRover/Jaguar', 'BMW', 'Mercedes', 'Renault/Dacia', 'Peugeot/Citroen', 'Opel', 'Fiat/Lancia/Alfa', 'Ford']
|
||||
|
||||
# Variáveis globais para armazenar referências a widgets e estado
|
||||
global_root_window = None
|
||||
global_file_path_var = None
|
||||
global_results_text_widget = None
|
||||
global_brand_buttons_frame = None
|
||||
global_category_buttons_frame = None
|
||||
global_ascii_text = None # Armazena o conteúdo ASCII do ficheiro lido
|
||||
global_progress_bar = None
|
||||
global_progress_label = None
|
||||
|
||||
# Função para ler o ficheiro em modo binário e tentar decodificar para ASCII
|
||||
def read_file_content(file_path):
|
||||
try:
|
||||
with open(file_path, 'rb') as f:
|
||||
binary_content = f.read()
|
||||
# Tenta decodificar como ASCII, ignorando erros ou substituindo caracteres problemáticos
|
||||
ascii_content = binary_content.decode('ascii', errors='replace')
|
||||
return ascii_content
|
||||
except FileNotFoundError:
|
||||
print(f"Erro: Ficheiro não encontrado em {file_path}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Erro ao ler ou decodificar o ficheiro {file_path}: {e}")
|
||||
return None
|
||||
|
||||
# Função principal de análise de padrões ASCII a partir de uma string de conteúdo
|
||||
def analyze_ascii_patterns_from_file(file_content, current_patterns_to_search, progress_callback=None, target_pattern_name=None):
|
||||
results = {}
|
||||
search_dict = {}
|
||||
if target_pattern_name:
|
||||
if target_pattern_name in current_patterns_to_search:
|
||||
search_dict = {target_pattern_name: current_patterns_to_search[target_pattern_name]}
|
||||
else:
|
||||
print(f"Aviso: Padrão alvo '{target_pattern_name}' não encontrado no dicionário de pesquisa fornecido.")
|
||||
return {target_pattern_name: {}}
|
||||
else:
|
||||
search_dict = current_patterns_to_search
|
||||
|
||||
for pattern_name, regex_pattern in search_dict.items():
|
||||
try:
|
||||
flags = 0
|
||||
# A flag re.IGNORECASE para 'Ecu Family' foi removida para restaurar o comportamento anterior.
|
||||
# Se a insensibilidade a maiúsculas/minúsculas for necessária para os KEYWORDS,
|
||||
# isso deve ser tratado diretamente no regex em common_patterns.py.
|
||||
|
||||
if pattern_name == 'Possible PIN':
|
||||
pin_candidates_matches = re.finditer(r'\b([A-Z0-9]{4,8})\b', file_content)
|
||||
uppercase_block_counts = Counter()
|
||||
found_items_for_pin = {}
|
||||
for match_obj in pin_candidates_matches:
|
||||
block_match = match_obj.group(1)
|
||||
if block_match.isalnum() and block_match == block_match.upper():
|
||||
uppercase_block_counts[block_match] += 1
|
||||
|
||||
for block, count in uppercase_block_counts.items():
|
||||
if 2 <= count <= 3:
|
||||
found_items_for_pin[block] = count
|
||||
results[pattern_name] = found_items_for_pin
|
||||
else:
|
||||
matches = re.finditer(regex_pattern, file_content, flags)
|
||||
found_items = {}
|
||||
for match_obj in matches:
|
||||
item = match_obj.group(1) if match_obj.groups() else match_obj.group(0)
|
||||
if item:
|
||||
cleaned_item = ''.join(char for char in item if char.isprintable()).strip()
|
||||
if cleaned_item:
|
||||
found_items[cleaned_item] = found_items.get(cleaned_item, 0) + 1
|
||||
results[pattern_name] = found_items
|
||||
except re.error as e:
|
||||
print(f"Erro de regex para o padrão '{pattern_name}' com regex '{regex_pattern}': {e}")
|
||||
results[pattern_name] = {"ERRO DE REGEX": 1}
|
||||
except Exception as e:
|
||||
print(f"Erro inesperado ao processar o padrão '{pattern_name}': {e}")
|
||||
results[pattern_name] = {"ERRO INESPERADO": 1}
|
||||
return results
|
||||
|
||||
# Função para lidar com a seleção de ficheiro e realizar a análise inicial
|
||||
def handle_file_selection_and_initial_analysis(file_path_var):
|
||||
file_path = filedialog.askopenfilename(
|
||||
title="Selecionar ficheiro ECU",
|
||||
filetypes=(("Binary files", "*.bin"), ("All files", "*.*"))
|
||||
)
|
||||
if not file_path:
|
||||
return
|
||||
|
||||
file_path_var.set(os.path.basename(file_path))
|
||||
global global_ascii_text
|
||||
global_ascii_text = read_file_content(file_path)
|
||||
|
||||
if global_ascii_text is None:
|
||||
tk.messagebox.showerror("Erro de Leitura", f"Não foi possível ler ou decodificar o ficheiro: {file_path}", parent=global_root_window)
|
||||
clear_ui_state()
|
||||
return
|
||||
|
||||
if global_results_text_widget:
|
||||
global_results_text_widget.config(state=tk.NORMAL)
|
||||
global_results_text_widget.delete(1.0, tk.END)
|
||||
global_results_text_widget.config(state=tk.DISABLED)
|
||||
|
||||
for widget in global_brand_buttons_frame.winfo_children():
|
||||
widget.destroy()
|
||||
for widget in global_category_buttons_frame.winfo_children():
|
||||
widget.destroy()
|
||||
|
||||
initial_patterns_dict = {key: PATTERNS_COMMON[key] for key in INITIAL_ANALYSIS_PATTERNS_KEYS if key in PATTERNS_COMMON}
|
||||
|
||||
if not initial_patterns_dict:
|
||||
tk.messagebox.showwarning("Configuração", "Nenhum padrão de análise inicial definido ou encontrado em common_patterns.py.", parent=global_root_window)
|
||||
create_brand_buttons()
|
||||
return
|
||||
|
||||
analysis_output = analyze_ascii_patterns_from_file(global_ascii_text, initial_patterns_dict)
|
||||
|
||||
display_initial_results(analysis_output, global_results_text_widget, global_root_window)
|
||||
create_brand_buttons()
|
||||
global_progress_label.config(text="Análise inicial concluída. Selecione uma marca.")
|
||||
global_progress_bar['value'] = 100
|
||||
global_root_window.update_idletasks()
|
||||
|
||||
# Nova função para exibir os resultados iniciais combinados
|
||||
def display_initial_results(initial_results_map, results_text_widget, root_window):
|
||||
results_text_widget.config(state=tk.NORMAL)
|
||||
results_text_widget.delete(1.0, tk.END)
|
||||
results_text_widget.insert(tk.END, "--- Análise Inicial Rápida ---\n")
|
||||
found_any_overall = False
|
||||
|
||||
for pattern_name in INITIAL_ANALYSIS_PATTERNS_KEYS:
|
||||
results_text_widget.insert(tk.END, f" --- {pattern_name} ---\n")
|
||||
matches_for_pattern = initial_results_map.get(pattern_name)
|
||||
|
||||
if matches_for_pattern:
|
||||
found_any_overall = True
|
||||
for item, count in matches_for_pattern.items():
|
||||
results_text_widget.insert(tk.END, f" {item}\n") # Removida a contagem de ocorrências
|
||||
else:
|
||||
results_text_widget.insert(tk.END, " Nenhum resultado encontrado para este padrão.\n")
|
||||
|
||||
if not found_any_overall:
|
||||
results_text_widget.insert(tk.END, " Nenhum dos padrões de análise rápida encontrou correspondências no ficheiro.\n")
|
||||
|
||||
results_text_widget.insert(tk.END, "\n--- Fim da Análise Inicial Rápida ---\n")
|
||||
|
||||
# Adicionar nova secção para Grupos (VAG, JLR, etc.)
|
||||
results_text_widget.insert(tk.END, "\n---- Centralina Usada nestes Marcas----\n")
|
||||
vag_ecu_list = load_vag_ecu_list()
|
||||
jlr_ecu_list = load_jlr_ecu_list()
|
||||
bmw_ecu_list = load_bmw_ecu_list()
|
||||
|
||||
found_in_vag_group = False
|
||||
found_in_jlr_group = False
|
||||
found_in_bmw_group = False
|
||||
any_group_found = False
|
||||
|
||||
ecu_families_found = set() # Para armazenar as famílias de ECU encontradas na análise inicial
|
||||
if initial_results_map and 'Ecu Family' in initial_results_map:
|
||||
for ecu_family, count in initial_results_map['Ecu Family'].items():
|
||||
ecu_families_found.add(ecu_family)
|
||||
|
||||
if ecu_families_found:
|
||||
for ecu_family in ecu_families_found:
|
||||
if ecu_family in vag_ecu_list:
|
||||
found_in_vag_group = True
|
||||
if ecu_family in jlr_ecu_list:
|
||||
found_in_jlr_group = True
|
||||
if ecu_family in bmw_ecu_list:
|
||||
found_in_bmw_group = True
|
||||
|
||||
if found_in_vag_group:
|
||||
results_text_widget.insert(tk.END, " - Grupo VAG\n")
|
||||
any_group_found = True
|
||||
if found_in_jlr_group:
|
||||
results_text_widget.insert(tk.END, " - Grupo Jaguar LandRover\n")
|
||||
any_group_found = True
|
||||
if found_in_bmw_group:
|
||||
results_text_widget.insert(tk.END, " - Grupo BMW\n")
|
||||
any_group_found = True
|
||||
|
||||
if not any_group_found:
|
||||
results_text_widget.insert(tk.END, " - Nenhum grupo correspondente encontrado.\n")
|
||||
else:
|
||||
results_text_widget.insert(tk.END, " Nenhuma família de ECU encontrada na análise para verificar grupos.\n")
|
||||
|
||||
results_text_widget.config(state=tk.DISABLED)
|
||||
if root_window: root_window.update_idletasks()
|
||||
|
||||
# Função a ser chamada pelo clique de um botão de categoria (sub-análise)
|
||||
def run_single_analysis(pattern_name_key, ascii_content, results_widget, root, progress_bar, progress_label_widget, brand_context=None):
|
||||
if not ascii_content:
|
||||
tk.messagebox.showwarning("Aviso", "Conteúdo do ficheiro não está carregado.", parent=root)
|
||||
return
|
||||
|
||||
progress_label_widget.config(text=f"A analisar para: {pattern_name_key}...")
|
||||
progress_bar['value'] = 0
|
||||
root.update_idletasks()
|
||||
|
||||
regex_to_use = None
|
||||
if brand_context == 'VAG' and pattern_name_key in PATTERNS_VAG:
|
||||
regex_to_use = PATTERNS_VAG[pattern_name_key]
|
||||
elif brand_context == 'LandRover/Jaguar' and pattern_name_key in PATTERNS_LANDROVER_JAGUAR:
|
||||
regex_to_use = PATTERNS_LANDROVER_JAGUAR[pattern_name_key]
|
||||
elif brand_context == 'BMW' and pattern_name_key in PATTERNS_BMW:
|
||||
regex_to_use = PATTERNS_BMW[pattern_name_key]
|
||||
# Adicionar elif para outras marcas aqui
|
||||
|
||||
if regex_to_use is None and pattern_name_key in PATTERNS_COMMON:
|
||||
regex_to_use = PATTERNS_COMMON[pattern_name_key]
|
||||
|
||||
if not regex_to_use:
|
||||
tk.messagebox.showerror("Erro de Configuração", f"Padrão '{pattern_name_key}' não encontrado para o contexto '{brand_context or 'Comum'}'.", parent=root)
|
||||
progress_label_widget.config(text=f"Erro: Padrão '{pattern_name_key}' não configurado.")
|
||||
return
|
||||
|
||||
single_pattern_dict_to_search = {pattern_name_key: regex_to_use}
|
||||
analysis_result = analyze_ascii_patterns_from_file(ascii_content, single_pattern_dict_to_search, target_pattern_name=pattern_name_key)
|
||||
|
||||
progress_bar['value'] = 50
|
||||
root.update_idletasks()
|
||||
|
||||
results_widget.config(state=tk.NORMAL)
|
||||
results_widget.delete(1.0, tk.END)
|
||||
matches_dict = analysis_result.get(pattern_name_key, {})
|
||||
|
||||
if matches_dict:
|
||||
results_widget.insert(tk.END, f"Resultados para '{pattern_name_key}':\n")
|
||||
for item, count in matches_dict.items():
|
||||
results_widget.insert(tk.END, f" - {item} (Ocorrências: {count})\n")
|
||||
else:
|
||||
results_widget.insert(tk.END, f"Nenhum resultado encontrado para '{pattern_name_key}'.\n")
|
||||
|
||||
results_widget.config(state=tk.DISABLED)
|
||||
progress_bar['value'] = 100
|
||||
progress_label_widget.config(text=f"Análise para '{pattern_name_key}' concluída.")
|
||||
root.update_idletasks()
|
||||
|
||||
def run_vag_sw_analysis(ascii_content, results_widget, root, progress_bar, progress_label_widget):
|
||||
if not ascii_content:
|
||||
messagebox.showwarning("Aviso", "Nenhum ficheiro carregado ou conteúdo ASCII não disponível.")
|
||||
return
|
||||
|
||||
# Check if required patterns are defined
|
||||
missing_patterns = []
|
||||
if 'PATTERNS_COMMON' not in globals() or not isinstance(PATTERNS_COMMON, dict) or \
|
||||
'Possible Software Number' not in PATTERNS_COMMON:
|
||||
missing_patterns.append("'Possible Software Number' de PATTERNS_COMMON")
|
||||
if 'PATTERNS_VAG' not in globals() or not isinstance(PATTERNS_VAG, dict) or \
|
||||
'VAG 10SW' not in PATTERNS_VAG:
|
||||
missing_patterns.append("'VAG 10SW' de PATTERNS_VAG")
|
||||
|
||||
if missing_patterns:
|
||||
messagebox.showerror("Erro de Configuração", f"Padrões não encontrados ou mal configurados: {', '.join(missing_patterns)}.")
|
||||
return
|
||||
|
||||
progress_label_widget.config(text="A analisar VAG SW...")
|
||||
progress_bar['value'] = 0
|
||||
if root: root.update_idletasks()
|
||||
|
||||
patterns_for_vag_sw = {
|
||||
'Possible Software Number': PATTERNS_COMMON['Possible Software Number'],
|
||||
'VAG 10SW': PATTERNS_VAG['VAG 10SW']
|
||||
}
|
||||
|
||||
all_results_map = {}
|
||||
total_patterns_to_analyze = len(patterns_for_vag_sw)
|
||||
|
||||
for i, (name, pattern_regex) in enumerate(patterns_for_vag_sw.items()):
|
||||
progress_val = int(((i + 0.5) / total_patterns_to_analyze) * 100)
|
||||
progress_bar['value'] = progress_val
|
||||
progress_label_widget.config(text=f"A analisar VAG SW: {name} ({progress_val}%)")
|
||||
if root: root.update_idletasks()
|
||||
|
||||
current_search_dict = {name: pattern_regex}
|
||||
# Pass progress_callback=None as analyze_ascii_patterns_from_file might not use it for single pattern
|
||||
analysis_results = analyze_ascii_patterns_from_file(ascii_content, current_search_dict, progress_callback=None, target_pattern_name=name)
|
||||
|
||||
if name in analysis_results and analysis_results[name]:
|
||||
all_results_map[name] = analysis_results[name]
|
||||
|
||||
results_widget.config(state=tk.NORMAL)
|
||||
results_widget.delete('1.0', tk.END)
|
||||
|
||||
results_widget.insert(tk.END, "--- Análise VAG SW ---\n")
|
||||
displayed_sw_numbers = set()
|
||||
found_any_sw = False
|
||||
|
||||
# Processar 'Possible Software Number' primeiro
|
||||
pattern_order = ['Possible Software Number', 'VAG 10SW']
|
||||
|
||||
for pattern_title in pattern_order:
|
||||
if pattern_title in all_results_map and all_results_map[pattern_title]:
|
||||
items_found = all_results_map[pattern_title]
|
||||
# Filtrar itens já exibidos, especialmente para 'VAG 10SW'
|
||||
unique_items_to_display = []
|
||||
if items_found:
|
||||
sorted_items = sorted(items_found.items(), key=lambda x: x[1], reverse=True)
|
||||
for item, count in sorted_items:
|
||||
if item not in displayed_sw_numbers:
|
||||
unique_items_to_display.append(item)
|
||||
displayed_sw_numbers.add(item)
|
||||
|
||||
if unique_items_to_display:
|
||||
found_any_sw = True
|
||||
results_widget.insert(tk.END, f" --- {pattern_title} ---\n")
|
||||
for item_text in unique_items_to_display:
|
||||
results_widget.insert(tk.END, f" {item_text}\n")
|
||||
elif pattern_title == 'Possible Software Number' and not found_any_sw: # Se PSN não achou nada, e é a primeira vez
|
||||
results_widget.insert(tk.END, f" --- {pattern_title} ---\n Nenhum resultado encontrado.\n")
|
||||
|
||||
if not found_any_sw:
|
||||
results_widget.insert(tk.END, " Nenhum número de software VAG encontrado.\n")
|
||||
|
||||
results_widget.insert(tk.END, "\n--- Fim da Análise VAG SW ---\n")
|
||||
|
||||
results_widget.config(state=tk.DISABLED)
|
||||
progress_label_widget.config(text="Análise VAG SW concluída.")
|
||||
progress_bar['value'] = 100
|
||||
if root: root.update_idletasks()
|
||||
|
||||
# Função para limpar o estado da UI
|
||||
def clear_ui_state():
|
||||
if global_file_path_var: global_file_path_var.set("Nenhum ficheiro selecionado")
|
||||
if global_results_text_widget:
|
||||
global_results_text_widget.config(state=tk.NORMAL)
|
||||
global_results_text_widget.delete(1.0, tk.END)
|
||||
global_results_text_widget.insert(tk.END, "Por favor, selecione um ficheiro para análise.")
|
||||
global_results_text_widget.config(state=tk.DISABLED)
|
||||
for frame in [global_brand_buttons_frame, global_category_buttons_frame]:
|
||||
if frame:
|
||||
for widget in frame.winfo_children():
|
||||
widget.destroy()
|
||||
if global_progress_label: global_progress_label.config(text="Pronto para iniciar.")
|
||||
if global_progress_bar: global_progress_bar['value'] = 0
|
||||
# Limpar o texto ASCII global para a próxima análise
|
||||
global global_ascii_text
|
||||
global_ascii_text = None
|
||||
if global_root_window: global_root_window.update_idletasks()
|
||||
|
||||
# Função para criar os botões das marcas
|
||||
def create_brand_buttons():
|
||||
for widget in global_brand_buttons_frame.winfo_children():
|
||||
widget.destroy()
|
||||
for brand_name in BRAND_NAMES:
|
||||
button = ttk.Button(global_brand_buttons_frame, text=brand_name,
|
||||
command=lambda b_name=brand_name: show_brand_analysis_options(b_name))
|
||||
button.pack(side=tk.LEFT, padx=2, pady=2, fill=tk.X, expand=True)
|
||||
if global_root_window: global_root_window.update_idletasks()
|
||||
|
||||
# Função para mostrar opções de análise baseadas na marca
|
||||
def show_brand_analysis_options(brand_name):
|
||||
if not global_ascii_text:
|
||||
tk.messagebox.showwarning("Aviso", "Conteúdo do ficheiro não está carregado.", parent=global_root_window)
|
||||
return
|
||||
|
||||
for widget in global_category_buttons_frame.winfo_children():
|
||||
widget.destroy()
|
||||
|
||||
patterns_to_show_for_brand_keys = []
|
||||
for p_name in PATTERNS_COMMON.keys():
|
||||
# Exclui 'Possible PIN' especificamente para a marca VAG ou BMW
|
||||
if (brand_name == 'VAG' and p_name == 'Possible PIN') or \
|
||||
(brand_name == 'BMW' and p_name == 'Possible PIN'):
|
||||
continue
|
||||
if p_name not in INITIAL_ANALYSIS_PATTERNS_KEYS:
|
||||
patterns_to_show_for_brand_keys.append(p_name)
|
||||
|
||||
brand_specific_patterns_for_this_brand_keys = []
|
||||
if brand_name == 'VAG':
|
||||
brand_specific_patterns_for_this_brand_keys = list(PATTERNS_VAG.keys())
|
||||
elif brand_name == 'LandRover/Jaguar':
|
||||
brand_specific_patterns_for_this_brand_keys = list(PATTERNS_LANDROVER_JAGUAR.keys())
|
||||
elif brand_name == 'BMW':
|
||||
brand_specific_patterns_for_this_brand_keys = list(PATTERNS_BMW.keys())
|
||||
# Adicionar elif para outras marcas aqui
|
||||
|
||||
combined_keys = patterns_to_show_for_brand_keys + brand_specific_patterns_for_this_brand_keys
|
||||
patterns_to_show_for_brand_keys = sorted(list(set(combined_keys)))
|
||||
|
||||
global_progress_label.config(text=f"Marca: {brand_name}. Selecione um tipo de análise.")
|
||||
global_progress_bar['value'] = 0
|
||||
|
||||
if not patterns_to_show_for_brand_keys:
|
||||
label_no_patterns = ttk.Label(global_category_buttons_frame, text=f"Nenhum padrão de análise definido para a marca {brand_name}.")
|
||||
label_no_patterns.pack(pady=10)
|
||||
global_root_window.update_idletasks()
|
||||
return
|
||||
|
||||
for pattern_name_key in patterns_to_show_for_brand_keys:
|
||||
button_text = pattern_name_key
|
||||
current_command = None
|
||||
|
||||
if brand_name == 'VAG':
|
||||
if pattern_name_key == 'Bosch SW': # Esta é a chave original que queremos substituir por 'VAG SW'
|
||||
button_text = 'VAG SW'
|
||||
current_command = lambda: run_vag_sw_analysis( # run_vag_sw_analysis agora só faz 10SW
|
||||
global_ascii_text,
|
||||
global_results_text_widget,
|
||||
global_root_window,
|
||||
global_progress_bar,
|
||||
global_progress_label
|
||||
)
|
||||
elif pattern_name_key == 'VAG 10SW': # Esta chave vem de PATTERNS_VAG.keys(), não queremos um botão para ela.
|
||||
continue # Pula a criação de um botão dedicado 'VAG 10SW'
|
||||
elif pattern_name_key == 'VAG Specific PartNumbers':
|
||||
# Para este, queremos um botão que chame run_single_analysis como normal
|
||||
button_text = 'VAG Specific PartNumbers'
|
||||
current_command = lambda p_name=pattern_name_key: run_single_analysis(
|
||||
p_name,
|
||||
global_ascii_text,
|
||||
global_results_text_widget,
|
||||
global_root_window,
|
||||
global_progress_bar,
|
||||
global_progress_label,
|
||||
brand_context=brand_name
|
||||
)
|
||||
else:
|
||||
# Para outros padrões comuns ou específicos de VAG que não são os acima
|
||||
current_command = lambda p_name=pattern_name_key: run_single_analysis(
|
||||
p_name,
|
||||
global_ascii_text,
|
||||
global_results_text_widget,
|
||||
global_root_window,
|
||||
global_progress_bar,
|
||||
global_progress_label,
|
||||
brand_context=brand_name
|
||||
)
|
||||
else: # Para marcas que não são VAG
|
||||
current_command = lambda p_name=pattern_name_key: run_single_analysis(
|
||||
p_name,
|
||||
global_ascii_text,
|
||||
global_results_text_widget,
|
||||
global_root_window,
|
||||
global_progress_bar,
|
||||
global_progress_label,
|
||||
brand_context=brand_name
|
||||
)
|
||||
|
||||
if current_command: # Só cria o botão se um comando foi definido
|
||||
button = ttk.Button(global_category_buttons_frame, text=button_text, command=current_command)
|
||||
button.pack(side=tk.LEFT, padx=2, pady=2, fill=tk.X, expand=True)
|
||||
if global_root_window: global_root_window.update_idletasks()
|
||||
|
||||
# Função principal para criar a janela e os widgets
|
||||
def create_main_window():
|
||||
global global_root_window, global_file_path_var, global_results_text_widget
|
||||
global global_brand_buttons_frame, global_category_buttons_frame, global_progress_bar, global_progress_label
|
||||
|
||||
root = tk.Tk()
|
||||
root.title("Analisador ASCII de Ficheiros ECU - Refatorado")
|
||||
global_root_window = root
|
||||
|
||||
style = ttk.Style(root)
|
||||
try:
|
||||
style.theme_use('clam') # 'clam' é uma boa opção multiplataforma
|
||||
except tk.TclError:
|
||||
# Fallback para um tema padrão se 'clam' não estiver disponível
|
||||
# Isto pode acontecer em algumas instalações mínimas de Tk
|
||||
print("Tema 'clam' não encontrado, usando tema padrão do Tk.")
|
||||
pass # Usa o tema padrão do sistema
|
||||
|
||||
file_path_var = tk.StringVar()
|
||||
global_file_path_var = file_path_var
|
||||
file_label = ttk.Label(root, textvariable=file_path_var)
|
||||
file_label.pack(pady=5, padx=10, fill=tk.X)
|
||||
|
||||
select_button = ttk.Button(root, text="Selecionar Ficheiro e Iniciar Análise",
|
||||
command=lambda: handle_file_selection_and_initial_analysis(file_path_var))
|
||||
select_button.pack(pady=5, padx=10, fill=tk.X) # pady ajustado para consistência
|
||||
|
||||
progress_frame = ttk.Frame(root)
|
||||
progress_frame.pack(pady=5, padx=10, fill=tk.X)
|
||||
progress_label = ttk.Label(progress_frame, text="Pronto para iniciar.")
|
||||
progress_label.pack(side=tk.LEFT, padx=5)
|
||||
progress_bar = ttk.Progressbar(progress_frame, orient='horizontal', mode='determinate', length=200)
|
||||
progress_bar.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
global_progress_bar = progress_bar
|
||||
global_progress_label = progress_label
|
||||
|
||||
brand_buttons_frame = ttk.Frame(root)
|
||||
brand_buttons_frame.pack(pady=5, padx=10, fill=tk.X)
|
||||
global_brand_buttons_frame = brand_buttons_frame
|
||||
|
||||
category_buttons_frame = ttk.Frame(root)
|
||||
category_buttons_frame.pack(pady=5, padx=10, fill=tk.X)
|
||||
global_category_buttons_frame = category_buttons_frame
|
||||
|
||||
results_text_widget = scrolledtext.ScrolledText(root, wrap=tk.WORD, width=100, height=20, state=tk.DISABLED)
|
||||
results_text_widget.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
|
||||
global_results_text_widget = results_text_widget
|
||||
|
||||
clear_ui_state() # Limpa a UI antes de iniciar
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
create_main_window()
|
||||
8
requirements.txt
Normal file
8
requirements.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# Esta aplicação usa principalmente módulos built-in do Python.
|
||||
# Tkinter (para a GUI) faz parte da instalação standard do Python.
|
||||
# Nenhuma dependência externa é estritamente necessária para a funcionalidade base.
|
||||
|
||||
# Se quiser executar num ambiente virtual, pode criar um e ativá-lo.
|
||||
# python -m venv venv
|
||||
# venv\Scripts\activate (Windows)
|
||||
# source venv/bin/activate (Linux/macOS)
|
||||
Reference in New Issue
Block a user