Skip to content

Commit 7a7458e

Browse files
committed
working widget
1 parent d3fbbb6 commit 7a7458e

File tree

6 files changed

+329
-14
lines changed

6 files changed

+329
-14
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
"""Dialogs for editing custom files."""
2+
3+
import logging
4+
from pathlib import Path
5+
6+
from PyQt6 import Qsci, QtWidgets
7+
from RATapi.utils.enums import Languages
8+
from RATapi.wrappers import start_matlab
9+
10+
11+
def edit_file(filename: str, language: Languages, parent: QtWidgets.QWidget):
12+
"""Edit a file in the file editor.
13+
14+
Parameters
15+
----------
16+
filename : str
17+
The name of the file to edit.
18+
language : Languages
19+
The language for dialog highlighting.
20+
parent : QtWidgets.QWidget
21+
The parent of this widget.
22+
23+
"""
24+
file = Path(filename)
25+
if not file.is_file():
26+
logger = logging.getLogger("rascal_log")
27+
logger.error("Attempted to edit a custom file which does not exist!")
28+
return
29+
30+
dialog = CustomFileEditorDialog(file, language, parent)
31+
dialog.exec()
32+
33+
34+
def edit_file_matlab(filename: str):
35+
"""Open a file in MATLAB."""
36+
loader = start_matlab()
37+
38+
if loader is None:
39+
logger = logging.getLogger("rascal_log")
40+
logger.error("Attempted to edit a file in MATLAB engine, but `matlabengine` is not available.")
41+
return
42+
43+
engine = loader.result()
44+
engine.edit(str(filename))
45+
46+
47+
class CustomFileEditorDialog(QtWidgets.QDialog):
48+
"""Dialog for editing custom files.
49+
50+
Parameters
51+
----------
52+
file : pathlib.Path
53+
The file to edit.
54+
language : Languages
55+
The language for dialog highlighting.
56+
parent : QtWidgets.QWidget
57+
The parent of this widget.
58+
59+
"""
60+
61+
def __init__(self, file, language, parent):
62+
super().__init__(parent)
63+
64+
self.setMinimumWidth(600)
65+
self.setMinimumHeight(400)
66+
67+
self.file = file
68+
69+
self.editor = Qsci.QsciScintilla()
70+
match language:
71+
case Languages.Python:
72+
self.editor.setLexer(Qsci.QsciLexerPython(self.editor))
73+
case Languages.Matlab:
74+
self.editor.setLexer(Qsci.QsciLexerMatlab(self.editor))
75+
case _:
76+
self.editor.setLexer(None)
77+
78+
self.editor.setText(self.file.read_text())
79+
80+
save_button = QtWidgets.QPushButton("Save", self)
81+
save_button.clicked.connect(self.save_file)
82+
cancel_button = QtWidgets.QPushButton("Cancel", self)
83+
cancel_button.clicked.connect(self.reject)
84+
85+
button_layout = QtWidgets.QHBoxLayout()
86+
button_layout.addWidget(save_button)
87+
button_layout.addWidget(cancel_button)
88+
89+
layout = QtWidgets.QVBoxLayout()
90+
layout.addWidget(self.editor)
91+
layout.addLayout(button_layout)
92+
93+
self.setLayout(layout)
94+
self.setWindowTitle(f"Edit {str(file)}")
95+
96+
def save_file(self):
97+
"""Save and close the file."""
98+
self.file.write_text(self.editor.text())
99+
self.accept()

rascal2/widgets/delegates.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,41 @@ def setModelData(self, editor, model, index):
3434
model.setData(index, data, QtCore.Qt.ItemDataRole.EditRole)
3535

3636

37+
class CustomFileFunctionDelegate(QtWidgets.QStyledItemDelegate):
38+
"""Item delegate for choosing the function from a custom file."""
39+
40+
def __init__(self, parent):
41+
super().__init__(parent)
42+
self.widget = parent
43+
44+
def createEditor(self, parent, option, index):
45+
func_names = self.widget.model.func_names[
46+
index.siblingAtColumn(index.column() - 1).data(QtCore.Qt.ItemDataRole.DisplayRole)
47+
]
48+
# we define the methods set_data and get_date
49+
# so that setEditorData and setModelData don't need
50+
# to know what kind of widget the editor is
51+
if func_names is None:
52+
editor = QtWidgets.QLineEdit(parent)
53+
editor.set_data = editor.setText
54+
editor.get_data = editor.text
55+
else:
56+
editor = QtWidgets.QComboBox(parent)
57+
editor.addItems(func_names)
58+
editor.set_data = editor.setCurrentText
59+
editor.get_data = editor.currentText
60+
61+
return editor
62+
63+
def setEditorData(self, editor: QtWidgets.QWidget, index):
64+
data = index.data(QtCore.Qt.ItemDataRole.DisplayRole)
65+
editor.set_data(data)
66+
67+
def setModelData(self, editor, model, index):
68+
data = editor.get_data()
69+
model.setData(index, data, QtCore.Qt.ItemDataRole.EditRole)
70+
71+
3772
class ValueSpinBoxDelegate(QtWidgets.QStyledItemDelegate):
3873
"""Item delegate for parameter values between a dynamic min and max.
3974

rascal2/widgets/inputs.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from enum import Enum
44
from math import floor, log10
5+
from pathlib import Path
56
from typing import Callable
67

78
from pydantic.fields import FieldInfo
@@ -29,6 +30,7 @@ def get_validated_input(field_info: FieldInfo, parent=None) -> QtWidgets.QWidget
2930
int: IntInputWidget,
3031
float: FloatInputWidget,
3132
Enum: EnumInputWidget,
33+
Path: PathInputWidget,
3234
}
3335

3436
for input_type, widget in class_widgets.items():
@@ -160,6 +162,25 @@ def create_editor(self, field_info: FieldInfo) -> QtWidgets.QWidget:
160162
return editor
161163

162164

165+
class PathInputWidget(BaseInputWidget):
166+
"""Input widget for paths."""
167+
168+
edit_signal = "pressed"
169+
170+
def create_editor(self, field_info: FieldInfo) -> QtWidgets.QWidget:
171+
file_dialog = QtWidgets.QFileDialog(parent=self)
172+
173+
def open_file():
174+
file = file_dialog.getOpenFileName()[0]
175+
if file:
176+
browse_button.setText(file)
177+
178+
browse_button = QtWidgets.QPushButton("Browse...", self)
179+
browse_button.clicked.connect(lambda: open_file())
180+
181+
return browse_button
182+
183+
163184
class AdaptiveDoubleSpinBox(QtWidgets.QDoubleSpinBox):
164185
"""A double spinbox which adapts to given numbers of decimals."""
165186

0 commit comments

Comments
 (0)