|
|
|
@ -1,7 +1,8 @@ |
|
|
|
import sys |
|
|
|
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QLineEdit, |
|
|
|
QLabel, QCheckBox, QPushButton, QFormLayout, QListWidgetItem, QSplitter, QTreeWidget, |
|
|
|
QTreeWidgetItem, QDialog, QDialogButtonBox, QComboBox, QMessageBox, QSpinBox, QMenu) |
|
|
|
QTreeWidgetItem, QDialog, QDialogButtonBox, QComboBox, QMessageBox, QSpinBox, QMenu, QTabWidget, |
|
|
|
QTextEdit) |
|
|
|
from PyQt6.QtCore import Qt, QSize |
|
|
|
from PyQt6.QtGui import QPixmap, QFontMetrics, QColor, QAction |
|
|
|
import sqlite3 |
|
|
|
@ -12,54 +13,10 @@ import os |
|
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
|
|
|
|
|
|
# Now try to import |
|
|
|
from pokemon_db_ui import PokemonUI |
|
|
|
from DataGatherers.update_location_information import process_pokemon_for_location_data |
|
|
|
from DataGatherers.cache_manager import CacheManager |
|
|
|
|
|
|
|
class EvolutionEditDialog(QDialog): |
|
|
|
def __init__(self, parent=None, from_pfic=None, to_pfic=None, method=None): |
|
|
|
super().__init__(parent) |
|
|
|
self.setWindowTitle("Edit Evolution") |
|
|
|
self.setModal(True) |
|
|
|
|
|
|
|
layout = QVBoxLayout(self) |
|
|
|
|
|
|
|
self.from_combo = QComboBox() |
|
|
|
self.to_combo = QComboBox() |
|
|
|
self.method_edit = QLineEdit(method) |
|
|
|
|
|
|
|
layout.addWidget(QLabel("From Pokémon:")) |
|
|
|
layout.addWidget(self.from_combo) |
|
|
|
layout.addWidget(QLabel("To Pokémon:")) |
|
|
|
layout.addWidget(self.to_combo) |
|
|
|
layout.addWidget(QLabel("Evolution Method:")) |
|
|
|
layout.addWidget(self.method_edit) |
|
|
|
|
|
|
|
self.button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) |
|
|
|
self.button_box.accepted.connect(self.accept) |
|
|
|
self.button_box.rejected.connect(self.reject) |
|
|
|
layout.addWidget(self.button_box) |
|
|
|
|
|
|
|
self.delete_button = QPushButton("Delete Evolution") |
|
|
|
self.delete_button.clicked.connect(self.delete_evolution) |
|
|
|
layout.addWidget(self.delete_button) |
|
|
|
|
|
|
|
self.populate_combos(from_pfic, to_pfic) |
|
|
|
|
|
|
|
def populate_combos(self, from_pfic, to_pfic): |
|
|
|
cursor = self.parent().cursor |
|
|
|
cursor.execute('SELECT PFIC, name, form_name FROM pokemon_forms ORDER BY name, form_name') |
|
|
|
for pfic, name, form_name in cursor.fetchall(): |
|
|
|
display_name = f"{name} ({form_name})" if form_name else name |
|
|
|
self.from_combo.addItem(display_name, pfic) |
|
|
|
self.to_combo.addItem(display_name, pfic) |
|
|
|
|
|
|
|
if from_pfic: |
|
|
|
self.from_combo.setCurrentIndex(self.from_combo.findData(from_pfic)) |
|
|
|
if to_pfic: |
|
|
|
self.to_combo.setCurrentIndex(self.to_combo.findData(to_pfic)) |
|
|
|
|
|
|
|
def delete_evolution(self): |
|
|
|
self.done(2) # Use a custom return code for delete action |
|
|
|
from event_system import event_system |
|
|
|
|
|
|
|
def parse_pfic(pfic): |
|
|
|
parts = pfic.split('-') |
|
|
|
@ -71,14 +28,21 @@ class DBEditor(QMainWindow): |
|
|
|
self.setWindowTitle("Pokémon Database Editor") |
|
|
|
self.setGeometry(100, 100, 1000, 600) |
|
|
|
|
|
|
|
self.conn = sqlite3.connect(':memory:') # Use in-memory database for runtime |
|
|
|
event_system.add_listener('get_pokemon_data', self.load_pokemon_details) |
|
|
|
event_system.add_listener('save_changes', self.save_changes) |
|
|
|
event_system.add_listener('add_new_encounter', self.add_new_encounter) |
|
|
|
event_system.add_listener('get_pokemon_list', self.send_pokemon_list) |
|
|
|
event_system.add_listener('get_home_storable', self.get_home_storable) |
|
|
|
event_system.add_listener('get_evolution_chain', self.get_evolution_chain) |
|
|
|
event_system.add_listener('get_evolution_parent', self.get_evolution_parent) |
|
|
|
|
|
|
|
self.conn = sqlite3.connect(':memory:', check_same_thread=False) # Use in-memory database for runtime |
|
|
|
self.cursor = self.conn.cursor() |
|
|
|
self.init_database() |
|
|
|
self.patches = self.load_and_apply_patches() |
|
|
|
|
|
|
|
self.encounter_cache = {} # Add this line |
|
|
|
self.init_ui() |
|
|
|
#self.load_pokemon_list() # Make sure this is called after init_ui |
|
|
|
|
|
|
|
def init_database(self): |
|
|
|
# Create or open the file-based database |
|
|
|
@ -369,124 +333,26 @@ class DBEditor(QMainWindow): |
|
|
|
with open('patches.json', 'w') as f: |
|
|
|
json.dump(self.patches, f) |
|
|
|
|
|
|
|
def init_ui(self): |
|
|
|
central_widget = QWidget() |
|
|
|
self.setCentralWidget(central_widget) |
|
|
|
main_layout = QHBoxLayout(central_widget) |
|
|
|
|
|
|
|
# Left side: Search and List |
|
|
|
left_layout = QVBoxLayout() |
|
|
|
search_layout = QHBoxLayout() |
|
|
|
self.search_bar = QLineEdit() |
|
|
|
self.search_bar.setPlaceholderText("Search Pokémon...") |
|
|
|
self.search_bar.textChanged.connect(self.filter_pokemon_list) |
|
|
|
search_layout.addWidget(self.search_bar) |
|
|
|
|
|
|
|
left_layout.addLayout(search_layout) |
|
|
|
|
|
|
|
self.pokemon_list = QListWidget() |
|
|
|
self.pokemon_list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) |
|
|
|
self.pokemon_list.customContextMenuRequested.connect(self.show_pokemon_context_menu) |
|
|
|
self.pokemon_list.currentItemChanged.connect(self.load_pokemon_details) |
|
|
|
left_layout.addWidget(self.pokemon_list) |
|
|
|
|
|
|
|
# Move the checkbox here, after the pokemon_list |
|
|
|
self.highlight_no_encounters = QCheckBox("Highlight Pokémon without encounters") |
|
|
|
self.highlight_no_encounters.stateChanged.connect(self.toggle_highlight_mode) |
|
|
|
left_layout.addWidget(self.highlight_no_encounters) |
|
|
|
|
|
|
|
# Add the new checkbox for filtering Home-storable Pokémon |
|
|
|
self.filter_home_storable = QCheckBox("Show only Home-storable Pokémon") |
|
|
|
self.filter_home_storable.stateChanged.connect(self.filter_pokemon_list) |
|
|
|
left_layout.addWidget(self.filter_home_storable) |
|
|
|
|
|
|
|
# Right side: Edit panel |
|
|
|
right_layout = QHBoxLayout() |
|
|
|
|
|
|
|
# Left side of right panel: Text information |
|
|
|
text_layout = QVBoxLayout() |
|
|
|
self.edit_form = QFormLayout() |
|
|
|
self.name_label = QLabel() |
|
|
|
self.form_name_label = QLabel() |
|
|
|
self.national_dex_label = QLabel() |
|
|
|
self.generation_label = QLabel() |
|
|
|
self.home_checkbox = QCheckBox("Available in Home") |
|
|
|
self.is_baby_form_checkbox = QCheckBox("Is Baby Form") |
|
|
|
def load_pokemon_details(self, pfic): |
|
|
|
self.cursor.execute(''' |
|
|
|
SELECT pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home |
|
|
|
FROM pokemon_forms pf |
|
|
|
LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC |
|
|
|
WHERE pf.PFIC = ? |
|
|
|
''', (pfic,)) |
|
|
|
|
|
|
|
self.edit_form.addRow("Name:", self.name_label) |
|
|
|
self.edit_form.addRow("Form:", self.form_name_label) |
|
|
|
self.edit_form.addRow("National Dex:", self.national_dex_label) |
|
|
|
self.edit_form.addRow("Generation:", self.generation_label) |
|
|
|
self.edit_form.addRow(self.home_checkbox) |
|
|
|
self.edit_form.addRow(self.is_baby_form_checkbox) |
|
|
|
|
|
|
|
text_layout.addLayout(self.edit_form) |
|
|
|
|
|
|
|
# Evolution chain tree |
|
|
|
self.evolution_tree = QTreeWidget() |
|
|
|
self.evolution_tree.setHeaderLabels(["Pokémon", "Evolution Method"]) |
|
|
|
self.evolution_tree.setColumnWidth(0, 200) |
|
|
|
text_layout.addWidget(self.evolution_tree) |
|
|
|
|
|
|
|
# Add Locations tree |
|
|
|
self.locations_tree = QTreeWidget() |
|
|
|
self.locations_tree.setHeaderLabels(["Game/Location", "Details"]) |
|
|
|
self.locations_tree.setColumnWidth(0, 200) |
|
|
|
self.locations_tree.itemDoubleClicked.connect(self.edit_encounter) |
|
|
|
text_layout.addWidget(QLabel("Locations:")) |
|
|
|
text_layout.addWidget(self.locations_tree) |
|
|
|
|
|
|
|
# Add New Encounter button |
|
|
|
self.add_encounter_button = QPushButton("Add New Encounter") |
|
|
|
self.add_encounter_button.clicked.connect(self.add_new_encounter) |
|
|
|
text_layout.addWidget(self.add_encounter_button) |
|
|
|
|
|
|
|
# Move buttons to the bottom |
|
|
|
text_layout.addStretch(1) |
|
|
|
|
|
|
|
self.save_button = QPushButton("Save Changes") |
|
|
|
self.save_button.clicked.connect(self.save_changes) |
|
|
|
text_layout.addWidget(self.save_button) |
|
|
|
|
|
|
|
self.export_button = QPushButton("Export Database") |
|
|
|
self.export_button.clicked.connect(self.export_database) |
|
|
|
text_layout.addWidget(self.export_button) |
|
|
|
|
|
|
|
# Add New Evolution button |
|
|
|
self.add_evolution_button = QPushButton("Add New Evolution") |
|
|
|
self.add_evolution_button.clicked.connect(self.add_new_evolution) |
|
|
|
text_layout.addWidget(self.add_evolution_button) |
|
|
|
|
|
|
|
# Right side of right panel: Image |
|
|
|
image_layout = QVBoxLayout() |
|
|
|
self.image_label = QLabel() |
|
|
|
self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter) |
|
|
|
self.image_label.setFixedSize(200, 200) |
|
|
|
image_layout.addWidget(self.image_label) |
|
|
|
image_layout.addStretch(1) |
|
|
|
|
|
|
|
right_layout.addLayout(text_layout) |
|
|
|
right_layout.addLayout(image_layout) |
|
|
|
|
|
|
|
main_layout.addLayout(left_layout, 1) |
|
|
|
main_layout.addLayout(right_layout, 1) |
|
|
|
|
|
|
|
self.load_pokemon_list() |
|
|
|
|
|
|
|
def adjust_list_width(self): |
|
|
|
max_width = 0 |
|
|
|
font_metrics = QFontMetrics(self.pokemon_list.font()) |
|
|
|
for i in range(self.pokemon_list.count()): |
|
|
|
item_width = font_metrics.horizontalAdvance(self.pokemon_list.item(i).text()) |
|
|
|
max_width = max(max_width, item_width) |
|
|
|
|
|
|
|
# Add some padding to the width |
|
|
|
list_width = max_width + 50 |
|
|
|
self.pokemon_list.setFixedWidth(list_width) |
|
|
|
self.search_bar.setFixedWidth(list_width) |
|
|
|
|
|
|
|
def load_pokemon_list(self): |
|
|
|
self.pokemon_list.clear() |
|
|
|
return self.cursor.fetchone() |
|
|
|
|
|
|
|
def save_changes(self, data): |
|
|
|
# Your existing code to save changes |
|
|
|
pass |
|
|
|
|
|
|
|
def add_new_encounter(self, data): |
|
|
|
# Your existing code to add a new encounter |
|
|
|
pass |
|
|
|
|
|
|
|
def send_pokemon_list(self, callback): |
|
|
|
# Fetch pokemon list from database |
|
|
|
self.cursor.execute(''' |
|
|
|
SELECT pf.PFIC, pf.name, pf.form_name, pf.national_dex |
|
|
|
FROM pokemon_forms pf |
|
|
|
@ -495,82 +361,23 @@ class DBEditor(QMainWindow): |
|
|
|
|
|
|
|
# Sort the pokemon_data based on PFIC |
|
|
|
pokemon_data.sort(key=lambda x: parse_pfic(x[0])) |
|
|
|
callback(pokemon_data) |
|
|
|
|
|
|
|
for pfic, name, form_name, national_dex in pokemon_data: |
|
|
|
display_name = f"{national_dex:04d} - {name}" |
|
|
|
if form_name: |
|
|
|
display_name += f" ({form_name})" |
|
|
|
item = QListWidgetItem(display_name) |
|
|
|
item.setData(Qt.ItemDataRole.UserRole, pfic) |
|
|
|
self.pokemon_list.addItem(item) |
|
|
|
|
|
|
|
self.update_encounter_cache() |
|
|
|
self.update_pokemon_list_highlights() |
|
|
|
self.adjust_list_width() |
|
|
|
self.filter_pokemon_list() |
|
|
|
|
|
|
|
def filter_pokemon_list(self): |
|
|
|
search_text = self.search_bar.text().lower() |
|
|
|
show_only_home_storable = self.filter_home_storable.isChecked() |
|
|
|
|
|
|
|
for i in range(self.pokemon_list.count()): |
|
|
|
item = self.pokemon_list.item(i) |
|
|
|
pfic = item.data(Qt.ItemDataRole.UserRole) |
|
|
|
|
|
|
|
# Check if the item matches the search text |
|
|
|
text_match = search_text in item.text().lower() |
|
|
|
|
|
|
|
# Check if the item is storable in Home (if the filter is active) |
|
|
|
home_storable = True |
|
|
|
if show_only_home_storable: |
|
|
|
self.cursor.execute('SELECT storable_in_home FROM pokemon_storage WHERE PFIC = ?', (pfic,)) |
|
|
|
result = self.cursor.fetchone() |
|
|
|
home_storable = result[0] if result else False |
|
|
|
|
|
|
|
# Show the item only if it matches both filters |
|
|
|
item.setHidden(not (text_match and home_storable)) |
|
|
|
|
|
|
|
self.update_pokemon_list_highlights() |
|
|
|
|
|
|
|
def load_pokemon_details(self, current, previous): |
|
|
|
if not current: |
|
|
|
return |
|
|
|
|
|
|
|
pfic = current.data(Qt.ItemDataRole.UserRole) |
|
|
|
self.cursor.execute(''' |
|
|
|
SELECT pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home, pf.is_baby_form |
|
|
|
FROM pokemon_forms pf |
|
|
|
LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC |
|
|
|
WHERE pf.PFIC = ? |
|
|
|
''', (pfic,)) |
|
|
|
pokemon_data = self.cursor.fetchone() |
|
|
|
|
|
|
|
if pokemon_data: |
|
|
|
name, form_name, national_dex, generation, storable_in_home, is_baby_form = pokemon_data |
|
|
|
self.name_label.setText(name) |
|
|
|
self.form_name_label.setText(form_name if form_name else "") |
|
|
|
self.national_dex_label.setText(str(national_dex)) |
|
|
|
self.generation_label.setText(str(generation)) |
|
|
|
self.home_checkbox.setChecked(bool(storable_in_home)) |
|
|
|
self.is_baby_form_checkbox.setChecked(bool(is_baby_form)) |
|
|
|
self.home_checkbox.stateChanged.connect(self.update_home_storable) |
|
|
|
|
|
|
|
# Load and display the image |
|
|
|
image_path = f"images-new/{pfic}.png" |
|
|
|
if os.path.exists(image_path): |
|
|
|
pixmap = QPixmap(image_path) |
|
|
|
self.image_label.setPixmap(pixmap.scaled(200, 200, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) |
|
|
|
else: |
|
|
|
self.image_label.setText("Image not found") |
|
|
|
|
|
|
|
# Load and display evolution chain |
|
|
|
self.load_evolution_chain(pfic) |
|
|
|
def init_ui(self): |
|
|
|
# Create a central widget for the main window |
|
|
|
central_widget = QWidget() |
|
|
|
self.setCentralWidget(central_widget) |
|
|
|
main_layout = QVBoxLayout(central_widget) |
|
|
|
|
|
|
|
# Load and display encounter locations |
|
|
|
self.load_encounter_locations(pfic) |
|
|
|
# Create the PokemonUI as a child widget |
|
|
|
self.pokemon_ui = PokemonUI(self) |
|
|
|
main_layout.addWidget(self.pokemon_ui) |
|
|
|
|
|
|
|
self.current_pfic = pfic |
|
|
|
self.add_evolution_button.setEnabled(True) # Enable the button when a Pokémon is selected |
|
|
|
def get_home_storable(self, pfic): |
|
|
|
self.cursor.execute('SELECT storable_in_home FROM pokemon_storage WHERE PFIC = ?', (pfic,)) |
|
|
|
result = self.cursor.fetchone() |
|
|
|
home_storable = result[0] if result else False |
|
|
|
return home_storable |
|
|
|
|
|
|
|
def update_home_storable(self): |
|
|
|
if hasattr(self, 'current_pfic'): |
|
|
|
@ -584,55 +391,55 @@ class DBEditor(QMainWindow): |
|
|
|
if not parent: |
|
|
|
return # Don't edit the root item |
|
|
|
|
|
|
|
from_pfic = parent.data(0, Qt.ItemDataRole.UserRole) |
|
|
|
to_pfic = item.data(0, Qt.ItemDataRole.UserRole) |
|
|
|
method = item.text(1) |
|
|
|
#from_pfic = parent.data(0, Qt.ItemDataRole.UserRole) |
|
|
|
#to_pfic = item.data(0, Qt.ItemDataRole.UserRole) |
|
|
|
#method = item.text(1) |
|
|
|
|
|
|
|
dialog = EvolutionEditDialog(self, from_pfic, to_pfic, method) |
|
|
|
result = dialog.exec() |
|
|
|
#dialog = EvolutionEditDialog(self, from_pfic, to_pfic, method) |
|
|
|
#result = dialog.exec() |
|
|
|
|
|
|
|
if result == QDialog.DialogCode.Accepted: |
|
|
|
new_from_pfic = dialog.from_combo.currentData() |
|
|
|
new_to_pfic = dialog.to_combo.currentData() |
|
|
|
new_method = dialog.method_edit.text() |
|
|
|
#if result == QDialog.DialogCode.Accepted: |
|
|
|
# new_from_pfic = dialog.from_combo.currentData() |
|
|
|
# new_to_pfic = dialog.to_combo.currentData() |
|
|
|
# new_method = dialog.method_edit.text() |
|
|
|
|
|
|
|
# Update the in-memory database |
|
|
|
self.cursor.execute(''' |
|
|
|
UPDATE evolution_chains |
|
|
|
SET from_pfic = ?, to_pfic = ?, method = ? |
|
|
|
WHERE from_pfic = ? AND to_pfic = ? |
|
|
|
''', (new_from_pfic, new_to_pfic, new_method, from_pfic, to_pfic)) |
|
|
|
|
|
|
|
# Create or update the patch |
|
|
|
patch_key = f"evolution_{from_pfic}_{to_pfic}" |
|
|
|
self.patches[patch_key] = { |
|
|
|
'action': 'update', |
|
|
|
'new_from_pfic': new_from_pfic, |
|
|
|
'new_to_pfic': new_to_pfic, |
|
|
|
'new_method': new_method |
|
|
|
} |
|
|
|
self.save_patches() |
|
|
|
# self.cursor.execute(''' |
|
|
|
# UPDATE evolution_chains |
|
|
|
# SET from_pfic = ?, to_pfic = ?, method = ? |
|
|
|
# WHERE from_pfic = ? AND to_pfic = ? |
|
|
|
# ''', (new_from_pfic, new_to_pfic, new_method, from_pfic, to_pfic)) |
|
|
|
|
|
|
|
# # Create or update the patch |
|
|
|
# patch_key = f"evolution_{from_pfic}_{to_pfic}" |
|
|
|
# self.patches[patch_key] = { |
|
|
|
# 'action': 'update', |
|
|
|
# 'new_from_pfic': new_from_pfic, |
|
|
|
# 'new_to_pfic': new_to_pfic, |
|
|
|
# 'new_method': new_method |
|
|
|
# } |
|
|
|
# self.save_patches() |
|
|
|
|
|
|
|
# Refresh the evolution chain display |
|
|
|
self.load_evolution_chain(self.current_pfic) |
|
|
|
|
|
|
|
elif result == 2: # Delete action |
|
|
|
confirm = QMessageBox.question(self, "Confirm Deletion", "Are you sure you want to delete this evolution?", |
|
|
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) |
|
|
|
if confirm == QMessageBox.StandardButton.Yes: |
|
|
|
# Delete from the in-memory database |
|
|
|
self.cursor.execute(''' |
|
|
|
DELETE FROM evolution_chains |
|
|
|
WHERE from_pfic = ? AND to_pfic = ? |
|
|
|
''', (from_pfic, to_pfic)) |
|
|
|
# self.load_evolution_chain(self.current_pfic) |
|
|
|
|
|
|
|
#elif result == 2: # Delete action |
|
|
|
# confirm = QMessageBox.question(self, "Confirm Deletion", "Are you sure you want to delete this evolution?", |
|
|
|
# QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) |
|
|
|
# if confirm == QMessageBox.StandardButton.Yes: |
|
|
|
# # Delete from the in-memory database |
|
|
|
# self.cursor.execute(''' |
|
|
|
# DELETE FROM evolution_chains |
|
|
|
# WHERE from_pfic = ? AND to_pfic = ? |
|
|
|
# ''', (from_pfic, to_pfic)) |
|
|
|
|
|
|
|
# Create a delete patch |
|
|
|
patch_key = f"evolution_{from_pfic}_{to_pfic}" |
|
|
|
self.patches[patch_key] = {'action': 'delete'} |
|
|
|
self.save_patches() |
|
|
|
# patch_key = f"evolution_{from_pfic}_{to_pfic}" |
|
|
|
# self.patches[patch_key] = {'action': 'delete'} |
|
|
|
# self.save_patches() |
|
|
|
|
|
|
|
# Refresh the evolution chain display |
|
|
|
self.load_evolution_chain(self.current_pfic) |
|
|
|
# self.load_evolution_chain(self.current_pfic) |
|
|
|
|
|
|
|
def get_evolution_chain(self, pfic): |
|
|
|
def follow_chain(start_pfic, visited=None): |
|
|
|
@ -670,100 +477,15 @@ class DBEditor(QMainWindow): |
|
|
|
return chain |
|
|
|
|
|
|
|
return follow_chain(pfic) |
|
|
|
|
|
|
|
def load_evolution_chain(self, pfic): |
|
|
|
self.evolution_tree.clear() |
|
|
|
evolution_chain = self.get_evolution_chain(pfic) |
|
|
|
|
|
|
|
# Create a dictionary to store tree items |
|
|
|
tree_items = {} |
|
|
|
|
|
|
|
# First pass: create all tree items |
|
|
|
for current_pfic, name, form_name, method in evolution_chain: |
|
|
|
display_name = f"{name} ({form_name})" if form_name else name |
|
|
|
item = QTreeWidgetItem([display_name, method if method else ""]) |
|
|
|
item.setData(0, Qt.ItemDataRole.UserRole, current_pfic) |
|
|
|
tree_items[current_pfic] = item |
|
|
|
|
|
|
|
if current_pfic == pfic: |
|
|
|
item.setBackground(0, QColor(255, 255, 0, 100)) # Highlight selected Pokémon |
|
|
|
|
|
|
|
# Second pass: build the tree structure |
|
|
|
root = None |
|
|
|
for current_pfic, name, form_name, method in evolution_chain: |
|
|
|
item = tree_items[current_pfic] |
|
|
|
|
|
|
|
# Find the parent of this item |
|
|
|
self.cursor.execute('SELECT from_pfic FROM evolution_chains WHERE to_pfic = ?', (current_pfic,)) |
|
|
|
parent_pfic = self.cursor.fetchone() |
|
|
|
|
|
|
|
if parent_pfic: |
|
|
|
parent_item = tree_items.get(parent_pfic[0]) |
|
|
|
if parent_item: |
|
|
|
parent_item.addChild(item) |
|
|
|
elif not root: |
|
|
|
root = item |
|
|
|
self.evolution_tree.addTopLevelItem(root) |
|
|
|
|
|
|
|
# Expand the entire tree |
|
|
|
self.evolution_tree.expandAll() |
|
|
|
|
|
|
|
# Scroll to and select the current Pokémon |
|
|
|
current_item = tree_items[pfic] |
|
|
|
self.evolution_tree.scrollToItem(current_item) |
|
|
|
self.evolution_tree.setCurrentItem(current_item) |
|
|
|
|
|
|
|
# Connect double-click signal |
|
|
|
self.evolution_tree.itemDoubleClicked.connect(self.edit_evolution) |
|
|
|
|
|
|
|
def save_changes(self): |
|
|
|
if hasattr(self, 'current_pfic'): |
|
|
|
storable_in_home = self.home_checkbox.isChecked() |
|
|
|
self.patches[self.current_pfic] = {'storable_in_home': storable_in_home} |
|
|
|
|
|
|
|
with open('patches.json', 'w') as f: |
|
|
|
json.dump(self.patches, f) |
|
|
|
|
|
|
|
def export_database(self): |
|
|
|
export_conn = sqlite3.connect('pokemon_forms_production.db') |
|
|
|
self.conn.backup(export_conn) |
|
|
|
export_conn.close() |
|
|
|
|
|
|
|
def get_evolution_parent(self, pfic): |
|
|
|
self.cursor.execute('SELECT from_pfic FROM evolution_chains WHERE to_pfic = ?', (pfic,)) |
|
|
|
return self.cursor.fetchone() |
|
|
|
|
|
|
|
def closeEvent(self, event): |
|
|
|
self.conn.close() |
|
|
|
event.accept() |
|
|
|
|
|
|
|
def add_new_evolution(self): |
|
|
|
if not hasattr(self, 'current_pfic'): |
|
|
|
return |
|
|
|
|
|
|
|
dialog = EvolutionEditDialog(self, self.current_pfic, None, "") |
|
|
|
result = dialog.exec() |
|
|
|
|
|
|
|
if result == QDialog.DialogCode.Accepted: |
|
|
|
new_from_pfic = dialog.from_combo.currentData() |
|
|
|
new_to_pfic = dialog.to_combo.currentData() |
|
|
|
new_method = dialog.method_edit.text() |
|
|
|
|
|
|
|
# Update the in-memory database |
|
|
|
self.cursor.execute(''' |
|
|
|
INSERT INTO evolution_chains (from_pfic, to_pfic, method) |
|
|
|
VALUES (?, ?, ?) |
|
|
|
''', (new_from_pfic, new_to_pfic, new_method)) |
|
|
|
|
|
|
|
# Create a new patch |
|
|
|
patch_key = f"evolution_{new_from_pfic}_{new_to_pfic}" |
|
|
|
self.patches[patch_key] = { |
|
|
|
'action': 'add', |
|
|
|
'from_pfic': new_from_pfic, |
|
|
|
'to_pfic': new_to_pfic, |
|
|
|
'method': new_method |
|
|
|
} |
|
|
|
self.save_patches() |
|
|
|
|
|
|
|
# Refresh the evolution chain display |
|
|
|
self.load_evolution_chain(self.current_pfic) |
|
|
|
|
|
|
|
def load_encounter_locations(self, pfic): |
|
|
|
self.locations_tree.clear() |
|
|
|
self.cursor.execute(''' |
|
|
|
@ -817,185 +539,6 @@ class DBEditor(QMainWindow): |
|
|
|
# After updating the locations tree |
|
|
|
self.update_pokemon_list_highlights() |
|
|
|
|
|
|
|
def edit_encounter(self, item, column): |
|
|
|
if item.parent() is None: # This is a game item, not a location item |
|
|
|
return |
|
|
|
|
|
|
|
game = item.parent().text(0) |
|
|
|
location = item.text(0) |
|
|
|
|
|
|
|
dialog = QDialog(self) |
|
|
|
dialog.setWindowTitle("Edit Encounter") |
|
|
|
layout = QFormLayout(dialog) |
|
|
|
|
|
|
|
game_edit = QLineEdit(game) |
|
|
|
location_edit = QLineEdit(location) |
|
|
|
day_edit = QLineEdit() |
|
|
|
time_edit = QLineEdit() |
|
|
|
dual_slot_edit = QLineEdit() |
|
|
|
static_encounter_check = QCheckBox("Static Encounter") |
|
|
|
static_encounter_count_edit = QSpinBox() |
|
|
|
extra_text_edit = QLineEdit() |
|
|
|
stars_edit = QLineEdit() |
|
|
|
fishing_check = QCheckBox("Fishing") |
|
|
|
rods_edit = QLineEdit() |
|
|
|
|
|
|
|
layout.addRow("Game:", game_edit) |
|
|
|
layout.addRow("Location:", location_edit) |
|
|
|
layout.addRow("Day:", day_edit) |
|
|
|
layout.addRow("Time:", time_edit) |
|
|
|
layout.addRow("Dual Slot:", dual_slot_edit) |
|
|
|
layout.addRow("Static Encounter:", static_encounter_check) |
|
|
|
layout.addRow("Static Encounter Count:", static_encounter_count_edit) |
|
|
|
layout.addRow("Extra Text:", extra_text_edit) |
|
|
|
layout.addRow("Stars:", stars_edit) |
|
|
|
layout.addRow("Fishing:", fishing_check) |
|
|
|
layout.addRow("Rods:", rods_edit) |
|
|
|
|
|
|
|
exclusive_group_combo = QComboBox() |
|
|
|
exclusive_group_combo.addItem("None", None) |
|
|
|
self.cursor.execute('SELECT id, group_name FROM exclusive_encounter_groups') |
|
|
|
for group_id, group_name in self.cursor.fetchall(): |
|
|
|
exclusive_group_combo.addItem(group_name, group_id) |
|
|
|
|
|
|
|
layout.addRow("Exclusive Group:", exclusive_group_combo) |
|
|
|
|
|
|
|
# Fetch current values |
|
|
|
self.cursor.execute(''' |
|
|
|
SELECT day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods, exclusive_group_id |
|
|
|
FROM encounters |
|
|
|
WHERE pfic = ? AND game = ? AND location = ? |
|
|
|
''', (self.current_pfic, game, location)) |
|
|
|
current_values = self.cursor.fetchone() |
|
|
|
|
|
|
|
if current_values: |
|
|
|
day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods, exclusive_group_id = current_values |
|
|
|
day_edit.setText(day or "") |
|
|
|
time_edit.setText(time or "") |
|
|
|
dual_slot_edit.setText(dual_slot or "") |
|
|
|
static_encounter_check.setChecked(bool(static_encounter)) |
|
|
|
static_encounter_count_edit.setValue(static_encounter_count or 0) |
|
|
|
extra_text_edit.setText(extra_text or "") |
|
|
|
stars_edit.setText(stars or "") |
|
|
|
fishing_check.setChecked(bool(fishing)) |
|
|
|
rods_edit.setText(rods or "") |
|
|
|
index = exclusive_group_combo.findData(exclusive_group_id) |
|
|
|
if index >= 0: |
|
|
|
exclusive_group_combo.setCurrentIndex(index) |
|
|
|
|
|
|
|
buttons = QDialogButtonBox( |
|
|
|
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, |
|
|
|
Qt.Orientation.Horizontal, dialog) |
|
|
|
buttons.accepted.connect(dialog.accept) |
|
|
|
buttons.rejected.connect(dialog.reject) |
|
|
|
layout.addRow(buttons) |
|
|
|
|
|
|
|
if dialog.exec() == QDialog.DialogCode.Accepted: |
|
|
|
new_game = game_edit.text() |
|
|
|
new_location = location_edit.text() |
|
|
|
new_day = day_edit.text() or None |
|
|
|
new_time = time_edit.text() or None |
|
|
|
new_dual_slot = dual_slot_edit.text() or None |
|
|
|
new_static_encounter = static_encounter_check.isChecked() |
|
|
|
new_static_encounter_count = static_encounter_count_edit.value() |
|
|
|
new_extra_text = extra_text_edit.text() or None |
|
|
|
new_stars = stars_edit.text() or None |
|
|
|
new_fishing = fishing_check.isChecked() |
|
|
|
new_rods = rods_edit.text() or None |
|
|
|
new_exclusive_group_id = exclusive_group_combo.currentData() |
|
|
|
|
|
|
|
# Update the database |
|
|
|
self.cursor.execute(''' |
|
|
|
UPDATE encounters |
|
|
|
SET game = ?, location = ?, day = ?, time = ?, dual_slot = ?, |
|
|
|
static_encounter = ?, static_encounter_count = ?, extra_text = ?, |
|
|
|
stars = ?, fishing = ?, rods = ?, exclusive_group_id = ? |
|
|
|
WHERE pfic = ? AND game = ? AND location = ? |
|
|
|
''', (new_game, new_location, new_day, new_time, new_dual_slot, |
|
|
|
new_static_encounter, new_static_encounter_count, new_extra_text, |
|
|
|
new_stars, new_fishing, new_rods, new_exclusive_group_id, |
|
|
|
self.current_pfic, game, location)) |
|
|
|
self.conn.commit() |
|
|
|
|
|
|
|
# Update the cache if all encounters for this Pokémon were deleted |
|
|
|
if not self.check_pokemon_has_encounters(self.current_pfic): |
|
|
|
self.encounter_cache[self.current_pfic] = False |
|
|
|
|
|
|
|
# Refresh the locations tree |
|
|
|
self.load_encounter_locations(self.current_pfic) |
|
|
|
|
|
|
|
def add_new_encounter(self): |
|
|
|
dialog = QDialog(self) |
|
|
|
dialog.setWindowTitle("Add New Encounter") |
|
|
|
layout = QFormLayout(dialog) |
|
|
|
|
|
|
|
game_edit = QLineEdit() |
|
|
|
location_edit = QLineEdit() |
|
|
|
day_edit = QLineEdit() |
|
|
|
time_edit = QLineEdit() |
|
|
|
dual_slot_edit = QLineEdit() |
|
|
|
static_encounter_check = QCheckBox("Static Encounter") |
|
|
|
static_encounter_count_edit = QSpinBox() |
|
|
|
extra_text_edit = QLineEdit() |
|
|
|
stars_edit = QLineEdit() |
|
|
|
fishing_check = QCheckBox("Fishing") |
|
|
|
rods_edit = QLineEdit() |
|
|
|
|
|
|
|
layout.addRow("Game:", game_edit) |
|
|
|
layout.addRow("Location:", location_edit) |
|
|
|
layout.addRow("Day:", day_edit) |
|
|
|
layout.addRow("Time:", time_edit) |
|
|
|
layout.addRow("Dual Slot:", dual_slot_edit) |
|
|
|
layout.addRow("Static Encounter:", static_encounter_check) |
|
|
|
layout.addRow("Static Encounter Count:", static_encounter_count_edit) |
|
|
|
layout.addRow("Extra Text:", extra_text_edit) |
|
|
|
layout.addRow("Stars:", stars_edit) |
|
|
|
layout.addRow("Fishing:", fishing_check) |
|
|
|
layout.addRow("Rods:", rods_edit) |
|
|
|
|
|
|
|
exclusive_group_combo = QComboBox() |
|
|
|
exclusive_group_combo.addItem("None", None) |
|
|
|
self.cursor.execute('SELECT id, group_name FROM exclusive_encounter_groups') |
|
|
|
for group_id, group_name in self.cursor.fetchall(): |
|
|
|
exclusive_group_combo.addItem(group_name, group_id) |
|
|
|
|
|
|
|
layout.addRow("Exclusive Group:", exclusive_group_combo) |
|
|
|
|
|
|
|
buttons = QDialogButtonBox( |
|
|
|
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, |
|
|
|
Qt.Orientation.Horizontal, dialog) |
|
|
|
buttons.accepted.connect(dialog.accept) |
|
|
|
buttons.rejected.connect(dialog.reject) |
|
|
|
layout.addRow(buttons) |
|
|
|
|
|
|
|
if dialog.exec() == QDialog.DialogCode.Accepted: |
|
|
|
game = game_edit.text() |
|
|
|
location = location_edit.text() |
|
|
|
day = day_edit.text() or None |
|
|
|
time = time_edit.text() or None |
|
|
|
dual_slot = dual_slot_edit.text() or None |
|
|
|
static_encounter = static_encounter_check.isChecked() |
|
|
|
static_encounter_count = static_encounter_count_edit.value() |
|
|
|
extra_text = extra_text_edit.text() or None |
|
|
|
stars = stars_edit.text() or None |
|
|
|
fishing = fishing_check.isChecked() |
|
|
|
rods = rods_edit.text() or None |
|
|
|
exclusive_group_id = exclusive_group_combo.currentData() |
|
|
|
|
|
|
|
# Insert new encounter into the database |
|
|
|
self.cursor.execute(''' |
|
|
|
INSERT INTO encounters |
|
|
|
(pfic, game, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods, exclusive_group_id) |
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) |
|
|
|
''', (self.current_pfic, game, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods, exclusive_group_id)) |
|
|
|
self.conn.commit() |
|
|
|
|
|
|
|
# Update the cache |
|
|
|
self.encounter_cache[self.current_pfic] = True |
|
|
|
|
|
|
|
# Refresh the locations tree |
|
|
|
self.load_encounter_locations(self.current_pfic) |
|
|
|
|
|
|
|
# Add this as a class attribute in the DBEditor class |
|
|
|
game_generations = { |
|
|
|
"Red": 1, "Blue": 1, "Yellow": 1, |
|
|
|
@ -1011,24 +554,6 @@ class DBEditor(QMainWindow): |
|
|
|
"Pokémon Go": 0, "Pokémon Home": 0 |
|
|
|
} |
|
|
|
|
|
|
|
def toggle_highlight_mode(self): |
|
|
|
self.update_pokemon_list_highlights() |
|
|
|
|
|
|
|
def update_pokemon_list_highlights(self): |
|
|
|
highlight_mode = self.highlight_no_encounters.isChecked() |
|
|
|
for i in range(self.pokemon_list.count()): |
|
|
|
item = self.pokemon_list.item(i) |
|
|
|
pfic = item.data(Qt.ItemDataRole.UserRole) |
|
|
|
|
|
|
|
if highlight_mode: |
|
|
|
has_encounters = self.encounter_cache.get(pfic, False) |
|
|
|
if not has_encounters: |
|
|
|
item.setData(Qt.ItemDataRole.BackgroundRole, QColor(255, 200, 200)) # Light red background |
|
|
|
else: |
|
|
|
item.setData(Qt.ItemDataRole.BackgroundRole, None) # White background |
|
|
|
else: |
|
|
|
item.setData(Qt.ItemDataRole.BackgroundRole, None) # White background |
|
|
|
|
|
|
|
def update_encounter_cache(self): |
|
|
|
self.cursor.execute(''' |
|
|
|
SELECT DISTINCT pfic |
|
|
|
@ -1036,10 +561,10 @@ class DBEditor(QMainWindow): |
|
|
|
''') |
|
|
|
pokemon_with_encounters = set(row[0] for row in self.cursor.fetchall()) |
|
|
|
|
|
|
|
for i in range(self.pokemon_list.count()): |
|
|
|
item = self.pokemon_list.item(i) |
|
|
|
pfic = item.data(Qt.ItemDataRole.UserRole) |
|
|
|
self.encounter_cache[pfic] = pfic in pokemon_with_encounters |
|
|
|
#for i in range(self.pokemon_list.count()): |
|
|
|
# item = self.pokemon_list.item(i) |
|
|
|
# pfic = item.data(Qt.ItemDataRole.UserRole) |
|
|
|
# self.encounter_cache[pfic] = pfic in pokemon_with_encounters |
|
|
|
|
|
|
|
def check_pokemon_has_encounters(self, pfic): |
|
|
|
return self.encounter_cache.get(pfic, False) |
|
|
|
@ -1180,6 +705,50 @@ class DBEditor(QMainWindow): |
|
|
|
|
|
|
|
print(f"Refreshed encounters for {name} {form if form else ''}") |
|
|
|
|
|
|
|
def gather_pokemon_forms(self): |
|
|
|
self.progress_text.clear() # Clear previous progress text |
|
|
|
self.progress_text.append("Starting to gather Pokémon forms...") |
|
|
|
# Implement the logic to gather Pokémon forms |
|
|
|
# Update progress as you go, for example: |
|
|
|
self.progress_text.append("Processed 100 Pokémon...") |
|
|
|
self.progress_text.append("Processed 200 Pokémon...") |
|
|
|
# ... |
|
|
|
self.progress_text.append("Finished gathering Pokémon forms.") |
|
|
|
|
|
|
|
def gather_home_storage_info(self): |
|
|
|
self.progress_text.clear() |
|
|
|
self.progress_text.append("Starting to gather Home storage information...") |
|
|
|
# Implement the logic |
|
|
|
# ... |
|
|
|
|
|
|
|
def gather_evolution_info(self): |
|
|
|
self.progress_text.clear() |
|
|
|
self.progress_text.append("Starting to gather evolution information...") |
|
|
|
# Implement the logic |
|
|
|
# ... |
|
|
|
|
|
|
|
def gather_encounter_info(self): |
|
|
|
self.progress_text.clear() |
|
|
|
self.progress_text.append("Starting to gather encounter information...") |
|
|
|
# Implement the logic |
|
|
|
# ... |
|
|
|
|
|
|
|
def reinitialize_database(self): |
|
|
|
reply = QMessageBox.question(self, 'Confirm Action', |
|
|
|
'Are you sure you want to clear and reinitialize the database? This action cannot be undone.', |
|
|
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No) |
|
|
|
if reply == QMessageBox.StandardButton.Yes: |
|
|
|
self.progress_text.clear() |
|
|
|
self.progress_text.append("Starting database reinitialization...") |
|
|
|
# Implement the logic to clear and reinitialize the database |
|
|
|
self.conn.close() |
|
|
|
os.remove('pokemon_forms.db') # Remove the existing database file |
|
|
|
self.conn = sqlite3.connect('pokemon_forms.db') |
|
|
|
self.cursor = self.conn.cursor() |
|
|
|
self.init_database() # Reinitialize the database structure |
|
|
|
self.progress_text.append("Database reinitialized successfully.") |
|
|
|
QMessageBox.information(self, 'Database Reinitialized', 'The database has been cleared and reinitialized.') |
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
app = QApplication(sys.argv) |
|
|
|
editor = DBEditor() |
|
|
|
|