mirror of
https://github.com/nixietab/picodulce.git
synced 2025-04-10 10:28:56 +01:00
Compare commits
4 Commits
f4b0b39090
...
27c75d1ef2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
27c75d1ef2 | ||
![]() |
18692c3abc | ||
![]() |
c4f662235e | ||
![]() |
bf30a6ecd6 |
@ -40,7 +40,7 @@
|
|||||||
- **Custom Theme Support**: Create and apply personalized themes with ease. A dedicated repository and guide are [available to help you get started.](https://github.com/nixietab/picodulce-themes)
|
- **Custom Theme Support**: Create and apply personalized themes with ease. A dedicated repository and guide are [available to help you get started.](https://github.com/nixietab/picodulce-themes)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
If you are on windows you may be more interested in a [installer](https://github.com/nixietab/2hsu/releases/download/release/2hsu.exe)
|
If you are on windows you may be more interested in a [installer](https://github.com/nixietab/picodulce/releases/latest)
|
||||||
|
|
||||||
### 1. Clone the repository
|
### 1. Clone the repository
|
||||||
|
|
||||||
|
160
picodulce.py
160
picodulce.py
@ -9,7 +9,7 @@ import requests
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from PyQt5.QtWidgets import QApplication, QComboBox, QWidget, QVBoxLayout, QListWidget, QPushButton, QMessageBox, QDialog, QHBoxLayout, QLabel, QLineEdit, QCheckBox, QTabWidget, QFrame, QSpacerItem, QSizePolicy, QMainWindow, QGridLayout, QTextEdit, QListWidget, QListWidgetItem
|
from PyQt5.QtWidgets import QApplication, QComboBox, QWidget, QInputDialog, QVBoxLayout, QListWidget, QPushButton, QMessageBox, QDialog, QHBoxLayout, QLabel, QLineEdit, QCheckBox, QTabWidget, QFrame, QSpacerItem, QSizePolicy, QMainWindow, QGridLayout, QTextEdit, QListWidget, QListWidgetItem, QMenu
|
||||||
from PyQt5.QtGui import QFont, QIcon, QColor, QPalette, QMovie, QPixmap, QDesktopServices, QBrush
|
from PyQt5.QtGui import QFont, QIcon, QColor, QPalette, QMovie, QPixmap, QDesktopServices, QBrush
|
||||||
from PyQt5.QtCore import Qt, QObject, pyqtSignal, QThread, QUrl, QMetaObject, Q_ARG, QByteArray, QSize
|
from PyQt5.QtCore import Qt, QObject, pyqtSignal, QThread, QUrl, QMetaObject, Q_ARG, QByteArray, QSize
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -22,10 +22,8 @@ class PicomcVersionSelector(QWidget):
|
|||||||
self.open_dialogs = []
|
self.open_dialogs = []
|
||||||
self.check_config_file()
|
self.check_config_file()
|
||||||
self.themes_integrity()
|
self.themes_integrity()
|
||||||
# Specify the path to the themes directory
|
|
||||||
themes_folder = "themes"
|
themes_folder = "themes"
|
||||||
|
|
||||||
# Default theme file name (can be changed)
|
|
||||||
theme_file = self.config.get("Theme", "Dark.json")
|
theme_file = self.config.get("Theme", "Dark.json")
|
||||||
|
|
||||||
# Ensure the theme file exists in the themes directory
|
# Ensure the theme file exists in the themes directory
|
||||||
@ -1257,11 +1255,12 @@ class ModLoaderAndVersionMenu(QDialog):
|
|||||||
# Add content to "Instances" tab
|
# Add content to "Instances" tab
|
||||||
self.setup_instances_tab(instances_tab)
|
self.setup_instances_tab(instances_tab)
|
||||||
|
|
||||||
|
|
||||||
def setup_instances_tab(self, instances_tab):
|
def setup_instances_tab(self, instances_tab):
|
||||||
layout = QVBoxLayout(instances_tab)
|
layout = QVBoxLayout(instances_tab)
|
||||||
|
|
||||||
# Create title label
|
# Create title label
|
||||||
title_label = QLabel('Current Instance:')
|
title_label = QLabel('Manage Minecraft Instances')
|
||||||
title_label.setFont(QFont("Arial", 14))
|
title_label.setFont(QFont("Arial", 14))
|
||||||
layout.addWidget(title_label)
|
layout.addWidget(title_label)
|
||||||
|
|
||||||
@ -1282,20 +1281,6 @@ class ModLoaderAndVersionMenu(QDialog):
|
|||||||
create_instance_button.clicked.connect(self.create_instance)
|
create_instance_button.clicked.connect(self.create_instance)
|
||||||
layout.addWidget(create_instance_button)
|
layout.addWidget(create_instance_button)
|
||||||
|
|
||||||
# Create input field and button to rename an instance
|
|
||||||
self.rename_instance_input = QLineEdit()
|
|
||||||
self.rename_instance_input.setPlaceholderText("Enter new instance name")
|
|
||||||
layout.addWidget(self.rename_instance_input)
|
|
||||||
|
|
||||||
rename_instance_button = QPushButton("Rename Instance")
|
|
||||||
rename_instance_button.clicked.connect(self.rename_instance)
|
|
||||||
layout.addWidget(rename_instance_button)
|
|
||||||
|
|
||||||
# Create button to delete an instance
|
|
||||||
delete_instance_button = QPushButton("Delete Instance")
|
|
||||||
delete_instance_button.clicked.connect(self.delete_instance)
|
|
||||||
layout.addWidget(delete_instance_button)
|
|
||||||
|
|
||||||
# Fetch and display the current instances
|
# Fetch and display the current instances
|
||||||
self.load_instances()
|
self.load_instances()
|
||||||
|
|
||||||
@ -1334,20 +1319,7 @@ class ModLoaderAndVersionMenu(QDialog):
|
|||||||
else:
|
else:
|
||||||
QMessageBox.warning(self, "Invalid Input", "Please enter a valid instance name.")
|
QMessageBox.warning(self, "Invalid Input", "Please enter a valid instance name.")
|
||||||
|
|
||||||
def rename_instance(self):
|
def rename_instance(self, old_instance_name, new_instance_name):
|
||||||
selected_item = self.instances_list_widget.currentItem()
|
|
||||||
|
|
||||||
if not selected_item:
|
|
||||||
QMessageBox.warning(self, "No Selection", "Please select an instance to rename.")
|
|
||||||
return
|
|
||||||
|
|
||||||
old_instance_name = selected_item.text()
|
|
||||||
new_instance_name = self.rename_instance_input.text().strip()
|
|
||||||
|
|
||||||
if not new_instance_name:
|
|
||||||
QMessageBox.warning(self, "Invalid Input", "Please enter a valid new instance name.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if old_instance_name == "default":
|
if old_instance_name == "default":
|
||||||
QMessageBox.warning(self, "Cannot Rename Instance", "You cannot rename the 'default' instance.")
|
QMessageBox.warning(self, "Cannot Rename Instance", "You cannot rename the 'default' instance.")
|
||||||
return
|
return
|
||||||
@ -1379,48 +1351,36 @@ class ModLoaderAndVersionMenu(QDialog):
|
|||||||
logging.error("Error renaming instance: %s", e.stderr)
|
logging.error("Error renaming instance: %s", e.stderr)
|
||||||
QMessageBox.critical(self, "Error", f"Failed to rename instance: {e.stderr}")
|
QMessageBox.critical(self, "Error", f"Failed to rename instance: {e.stderr}")
|
||||||
|
|
||||||
|
def delete_instance(self, instance_name):
|
||||||
|
if instance_name == "default":
|
||||||
|
QMessageBox.warning(self, "Cannot Delete Instance", "You cannot delete the 'default' instance.")
|
||||||
|
return
|
||||||
|
|
||||||
|
confirm_delete = QMessageBox.question(
|
||||||
|
self, "Confirm Deletion", f"Are you sure you want to delete the instance '{instance_name}'?",
|
||||||
|
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
|
||||||
|
)
|
||||||
|
|
||||||
|
if confirm_delete == QMessageBox.Yes:
|
||||||
|
try:
|
||||||
|
# Run the "picomc instance delete" command
|
||||||
|
process = subprocess.Popen(['picomc', 'instance', 'delete', instance_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||||
|
output, error = process.communicate()
|
||||||
|
|
||||||
def delete_instance(self):
|
if process.returncode != 0:
|
||||||
# Get the selected instance name
|
raise subprocess.CalledProcessError(process.returncode, process.args, error)
|
||||||
selected_instance = self.instances_list_widget.currentItem()
|
|
||||||
|
|
||||||
if selected_instance:
|
# Notify the user that the instance was deleted
|
||||||
instance_name = selected_instance.text()
|
QMessageBox.information(self, "Instance Deleted", f"Instance '{instance_name}' has been deleted successfully.")
|
||||||
|
|
||||||
# Prevent deletion of the "default" instance
|
# Reload the instances list
|
||||||
if instance_name == "default":
|
self.load_instances()
|
||||||
QMessageBox.warning(self, "Cannot Delete Instance", "You cannot delete the 'default' instance.")
|
|
||||||
return
|
|
||||||
|
|
||||||
confirm_delete = QMessageBox.question(
|
except FileNotFoundError:
|
||||||
self, "Confirm Deletion", f"Are you sure you want to delete the instance '{instance_name}'?",
|
logging.error("'picomc' command not found. Please make sure it's installed and in your PATH.")
|
||||||
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
|
except subprocess.CalledProcessError as e:
|
||||||
)
|
logging.error("Error deleting instance: %s", e.stderr)
|
||||||
|
QMessageBox.critical(self, "Error", f"Failed to delete instance: {e.stderr}")
|
||||||
if confirm_delete == QMessageBox.Yes:
|
|
||||||
try:
|
|
||||||
# Run the "picomc instance delete" command
|
|
||||||
process = subprocess.Popen(['picomc', 'instance', 'delete', instance_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
||||||
output, error = process.communicate()
|
|
||||||
|
|
||||||
if process.returncode != 0:
|
|
||||||
raise subprocess.CalledProcessError(process.returncode, process.args, error)
|
|
||||||
|
|
||||||
# Notify the user that the instance was deleted
|
|
||||||
QMessageBox.information(self, "Instance Deleted", f"Instance '{instance_name}' has been deleted successfully.")
|
|
||||||
|
|
||||||
# Reload the instances list
|
|
||||||
self.load_instances()
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
|
||||||
logging.error("'picomc' command not found. Please make sure it's installed and in your PATH.")
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
logging.error("Error deleting instance: %s", e.stderr)
|
|
||||||
QMessageBox.critical(self, "Error", f"Failed to delete instance: {e.stderr}")
|
|
||||||
else:
|
|
||||||
QMessageBox.warning(self, "No Selection", "Please select an instance to delete.")
|
|
||||||
|
|
||||||
def load_instances(self):
|
def load_instances(self):
|
||||||
try:
|
try:
|
||||||
@ -1432,37 +1392,74 @@ class ModLoaderAndVersionMenu(QDialog):
|
|||||||
# Parse the output and add each instance to the list widget
|
# Parse the output and add each instance to the list widget
|
||||||
instances = output.splitlines()
|
instances = output.splitlines()
|
||||||
self.instances_list_widget.clear() # Clear the previous list
|
self.instances_list_widget.clear() # Clear the previous list
|
||||||
self.instances_list_widget.addItems(instances)
|
for instance in instances:
|
||||||
|
item = QListWidgetItem()
|
||||||
|
self.instances_list_widget.addItem(item)
|
||||||
|
self.add_instance_buttons(item, instance)
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logging.error("'picomc' command not found. Please make sure it's installed and in your PATH.")
|
logging.error("'picomc' command not found. Please make sure it's installed and in your PATH.")
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
logging.error("Error fetching instances: %s", e.stderr)
|
logging.error("Error fetching instances: %s", e.stderr)
|
||||||
|
|
||||||
def on_instance_selected(self, item):
|
def add_instance_buttons(self, list_item, instance_name):
|
||||||
# Get the selected instance name
|
widget = QWidget()
|
||||||
selected_instance = item.text()
|
layout = QHBoxLayout(widget)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
label = QLabel(instance_name)
|
||||||
|
rename_button = QPushButton("Rename")
|
||||||
|
delete_button = QPushButton("Delete")
|
||||||
|
|
||||||
|
# Stylize the buttons
|
||||||
|
button_style = """
|
||||||
|
QPushButton {
|
||||||
|
padding: 2px 5px;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
rename_button.setStyleSheet(button_style)
|
||||||
|
delete_button.setStyleSheet(button_style)
|
||||||
|
|
||||||
|
layout.addWidget(label)
|
||||||
|
layout.addStretch()
|
||||||
|
layout.addWidget(rename_button)
|
||||||
|
layout.addWidget(delete_button)
|
||||||
|
|
||||||
|
widget.setLayout(layout)
|
||||||
|
list_item.setSizeHint(widget.sizeHint())
|
||||||
|
self.instances_list_widget.setItemWidget(list_item, widget)
|
||||||
|
|
||||||
|
# Connect button signals
|
||||||
|
rename_button.clicked.connect(lambda: self.prompt_rename_instance(instance_name))
|
||||||
|
delete_button.clicked.connect(lambda: self.delete_instance(instance_name))
|
||||||
|
|
||||||
|
def prompt_rename_instance(self, old_instance_name):
|
||||||
|
new_instance_name, ok = QInputDialog.getText(
|
||||||
|
self, "Rename Instance",
|
||||||
|
f"Enter new name for instance '{old_instance_name}':"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ok and new_instance_name:
|
||||||
|
self.rename_instance(old_instance_name, new_instance_name)
|
||||||
|
|
||||||
|
def on_instance_selected(self, item):
|
||||||
|
widget = self.instances_list_widget.itemWidget(item)
|
||||||
|
instance_name = widget.findChild(QLabel).text()
|
||||||
|
|
||||||
# Path to the config.json file
|
|
||||||
config_file = 'config.json'
|
config_file = 'config.json'
|
||||||
|
|
||||||
# Check if the config file exists
|
|
||||||
if os.path.exists(config_file):
|
if os.path.exists(config_file):
|
||||||
try:
|
try:
|
||||||
# Load the current config.json file
|
|
||||||
with open(config_file, 'r') as file:
|
with open(config_file, 'r') as file:
|
||||||
config_data = json.load(file)
|
config_data = json.load(file)
|
||||||
|
|
||||||
# Update the "Instance" value with the selected instance name
|
config_data['Instance'] = instance_name
|
||||||
config_data['Instance'] = selected_instance
|
|
||||||
|
|
||||||
# Save the updated config back to the file
|
|
||||||
with open(config_file, 'w') as file:
|
with open(config_file, 'w') as file:
|
||||||
json.dump(config_data, file, indent=4)
|
json.dump(config_data, file, indent=4)
|
||||||
|
|
||||||
logging.info(f"Config updated: Instance set to {selected_instance}")
|
logging.info(f"Config updated: Instance set to {instance_name}")
|
||||||
|
|
||||||
# Update the label with the new instance
|
|
||||||
self.update_instance_label()
|
self.update_instance_label()
|
||||||
|
|
||||||
except (json.JSONDecodeError, FileNotFoundError) as e:
|
except (json.JSONDecodeError, FileNotFoundError) as e:
|
||||||
@ -1475,11 +1472,9 @@ class ModLoaderAndVersionMenu(QDialog):
|
|||||||
|
|
||||||
if os.path.exists(config_file):
|
if os.path.exists(config_file):
|
||||||
try:
|
try:
|
||||||
# Load the config file
|
|
||||||
with open(config_file, 'r') as file:
|
with open(config_file, 'r') as file:
|
||||||
config_data = json.load(file)
|
config_data = json.load(file)
|
||||||
|
|
||||||
# Get the current instance from the config and update the label
|
|
||||||
current_instance = config_data.get('Instance', 'Not set')
|
current_instance = config_data.get('Instance', 'Not set')
|
||||||
self.current_instance_label.setText(f'Current instance: {current_instance}')
|
self.current_instance_label.setText(f'Current instance: {current_instance}')
|
||||||
|
|
||||||
@ -1488,6 +1483,7 @@ class ModLoaderAndVersionMenu(QDialog):
|
|||||||
else:
|
else:
|
||||||
self.current_instance_label.setText('Current instance: Not set')
|
self.current_instance_label.setText('Current instance: Not set')
|
||||||
|
|
||||||
|
|
||||||
def setup_install_mod_loader_tab(self, install_mod_tab):
|
def setup_install_mod_loader_tab(self, install_mod_tab):
|
||||||
layout = QVBoxLayout(install_mod_tab)
|
layout = QVBoxLayout(install_mod_tab)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "0.11.4",
|
"version": "0.11.5",
|
||||||
"links": [
|
"links": [
|
||||||
"https://raw.githubusercontent.com/nixietab/picodulce/main/version.json",
|
"https://raw.githubusercontent.com/nixietab/picodulce/main/version.json",
|
||||||
"https://raw.githubusercontent.com/nixietab/picodulce/main/picodulce.py",
|
"https://raw.githubusercontent.com/nixietab/picodulce/main/picodulce.py",
|
||||||
|
Loading…
Reference in New Issue
Block a user