Skip to content

Commit

Permalink
Changed name from gui to app
Browse files Browse the repository at this point in the history
  • Loading branch information
jslane-h committed Jul 20, 2023
1 parent f1c2520 commit d34b7ab
Show file tree
Hide file tree
Showing 16 changed files with 2,386 additions and 1 deletion.
63 changes: 63 additions & 0 deletions src/app/advanced_popup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from PyQt6.QtWidgets import QLabel, QLineEdit, QVBoxLayout, QPushButton, QDialog, QTextEdit, QMessageBox
from PyQt6.QtGui import QFontMetricsF
import json
import re

class AdvancedPopup(QDialog):
def __init__(self, rect=None, edit=False):
super().__init__()

form_layout = QVBoxLayout()
state_label = QLabel('State:')

if edit:
self.setWindowTitle('Edit State')
else:
self.setWindowTitle('Add State')

self.state_input = QTextEdit()
if rect:
self.state_input.setText(rect.get_state_string())

font = self.state_input.font()
fontMetrics = QFontMetricsF(font)
spaceWidth = fontMetrics.horizontalAdvance(' ')
self.state_input.setTabStopDistance(spaceWidth * 4)

self.save_button = QPushButton('Save')
self.save_button.clicked.connect(self.check_state)

form_layout.addWidget(state_label)
form_layout.addWidget(self.state_input, 3)
form_layout.addWidget(self.save_button)

self.setLayout(form_layout)

def get_state(self):
state_text = self.state_input.toPlainText()

try:
state_json = json.loads(state_text)
except json.decoder.JSONDecodeError:
state_json = {}
title = [key for key in state_json.keys()][0]

state_dict = state_json[title]
state_dict['Title'] = title
return state_dict

def check_state(self):
state = self.get_state()
state_type = state['Type']

def error_popup(text):
error_msg = QMessageBox()
error_msg.setIcon(QMessageBox.Icon.Critical)
error_msg.setWindowTitle('Error in State')
error_msg.setText(text)
error_msg.exec()

if state_type not in ['Choice', 'MethodCall']:
error_popup('Invalid type')
elif state_type == 'Choice' and 'Choices' not in state.keys():
error_popup('Choice type, but no Choices key')
243 changes: 243 additions & 0 deletions src/app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton, QHBoxLayout, QListWidget, QFrame, QDialog, QLabel, QToolBar, QMenu, QFileDialog
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QAction
from import_form import ImportForm
from meta_form import MetaForm
from workflow_diagram import WorkflowDiagram
from rect_connect import CustomItem
import json


with open('dependencies.json') as file:
data = json.load(file)

form = {}

class GUI(QMainWindow):
def __init__(self, setting):
"""QMainWindow to contain MetaForm, ImportForm, and Workflow Diagram.
Args:
setting: (optional)
"""
super().__init__()
self.initialize_ui(setting)

def initialize_ui(self, setting):
self.setWindowTitle('ConStrain')

self.meta_form = MetaForm()
self.import_form = ImportForm()
self.states_form = WorkflowDiagram(setting)

self.column_list = QListWidget()
self.column_list.addItems(['Meta', 'Imports', 'State'])
self.column_list.currentItemChanged.connect(self.display_form)

self.column_frame = QFrame()
self.column_frame.setFrameStyle(QFrame.Shape.NoFrame)
self.column_frame.setMaximumWidth(100)
column_layout = QVBoxLayout()
column_layout.addWidget(self.column_list)
self.column_frame.setLayout(column_layout)

middle_layout = QHBoxLayout()
middle_layout.addWidget(self.column_frame)
middle_layout.addWidget(self.meta_form)
middle_layout.addWidget(self.import_form)
middle_layout.addWidget(self.states_form)

self.validate_button = QPushButton('Validate')
self.validate_button.setFixedSize(100, 20)
self.validate_button.clicked.connect(self.validate_form)

self.submit_button = QPushButton('Submit')
self.submit_button.setEnabled(False)
self.submit_button.setFixedSize(100, 20)
self.submit_button.clicked.connect(self.submit_form)

buttons = QHBoxLayout()
buttons.addWidget(self.validate_button)
buttons.addWidget(self.submit_button)
buttons.setAlignment(Qt.AlignmentFlag.AlignHCenter)

main_layout = QVBoxLayout()
main_layout.addLayout(middle_layout)
main_layout.addLayout(buttons)

central_widget = QWidget()
central_widget.setLayout(main_layout)
self.setCentralWidget(central_widget)

self.initialize_toolbar()

def initialize_toolbar(self):
toolbar = QToolBar()
self.addToolBar(toolbar)

file_menu = QMenu('File', self)

import_action = QAction('Import', self)
import_action.triggered.connect(self.importFile)
file_menu.addAction(import_action)

export_action = QAction('Export', self)
export_action.triggered.connect(self.exportFile)
file_menu.addAction(export_action)

toolbar.addAction(file_menu.menuAction())

def exportFile(self):

fp, _ = QFileDialog.getSaveFileName(self, 'Save JSON File', '', 'JSON Files (*.json);;All Files (*)')

if fp:
try:
workflow = self.get_workflow()
with open(fp, 'w', encoding='utf-8') as f:
json.dump(self.create_json(workflow), f, indent=4)
except Exception:
print('error')

def importFile(self):
file_dialog = QFileDialog()
file_dialog.setWindowTitle('Select a JSON File')
file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
file_dialog.setNameFilter('JSON files (*.json)')
if file_dialog.exec() == QFileDialog.DialogCode.Accepted:
file_path = file_dialog.selectedFiles()[0]
with open(file_path, 'r') as f:
workflow = json.load(f)
if isinstance(workflow, dict):
self.meta_form.read_import(workflow.get('workflow_name'), workflow.get('meta'))
self.import_form.read_import(workflow.get('imports'))
self.states_form.read_import(workflow.get('states'))
self.get_workflow()
else:
print('error')




def display_form(self, current_item):
if current_item.text() == self.column_list.item(0).text():
self.meta_form.show()
self.import_form.hide()
self.states_form.hide()
elif current_item.text() == self.column_list.item(1).text():
self.meta_form.hide()
self.import_form.show()
self.states_form.hide()
else:
self.meta_form.hide()
self.import_form.hide()
self.states_form.show()

def create_json(self, workflow):
data = {'workflow_name': self.meta_form.get_workflow_name(), 'meta': self.meta_form.get_meta(),
'imports': self.import_form.get_imports(), 'states': {}}
for item in workflow:
copy_item = dict(item)
title = copy_item.pop('Title')
data['states'][title] = copy_item
json_data = data
return json_data

def submit_form(self):
self.submit_button.setEnabled(False)

def get_workflow(self):
items = [item for item in self.states_form.scene.items() if isinstance(item, CustomItem)]
roots = []
for i in items:
parent = True
for j in items:
if i in j.children:
parent = False
break
if parent:
roots.append(i)

visited = set()
paths = []

def dfs_helper(item, path):
path.append(item)
visited.add(item)

if item not in items or not item.children:
item.setBrush('red')
item.state['End'] = 'True'
paths.append(path[:])
else:
item.setBrush()

for child in item.children:
if child not in visited:
dfs_helper(child, path)

path.pop()
visited.remove(item)

for root in roots:
root.state['Start'] = 'True'
self.states_form.view.arrange_tree(root, 0, 0, 150)
if root not in visited:
dfs_helper(root, [])
root.setBrush('green')

workflow_path = []
visited = set()
for path in paths:
for node in path:
if node not in visited:
workflow_path.append(node.state)
visited.add(node)
return workflow_path

def validate_form(self, data):
workflow_path = self.get_workflow()
json_data = self.create_json(workflow_path)
valid = True
if valid:
self.submit_button.setEnabled(True)

class UserSetting(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle('ConStrain')
query = QLabel('Advanced or basic user settings?')
self.advanced_button = QPushButton('Advanced')
self.advanced_button.clicked.connect(self.showAdvanced)
self.basic_button = QPushButton('Basic')
self.basic_button.clicked.connect(self.showBasic)

form_layout = QVBoxLayout()
button_layout = QHBoxLayout()

button_layout.addWidget(self.advanced_button)
button_layout.addWidget(self.basic_button)

form_layout.addWidget(query)
form_layout.addLayout(button_layout)

self.setLayout(form_layout)

def showBasic(self):
self.close()
self.gui = GUI('basic')
self.gui.show()

def showAdvanced(self):
self.close()
self.gui = GUI('advanced')
self.gui.show()


app = QApplication(sys.argv)

window = UserSetting()
window.show()

sys.exit(app.exec())
58 changes: 58 additions & 0 deletions src/app/app.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# -*- mode: python ; coding: utf-8 -*-


block_cipher = None


a = Analysis(
['app.py'],
pathex=[],
binaries=[],
datas=[
('advanced_popup.py', '.'),
('import_form.py', '.'),
('meta_form.py', '.'),
('popup_window.py', '.'),
('rect_connect.py', '.'),
('workflow_diagram.py', '.'),
('dependencies.json', '.')
],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='app',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='app',
)
11 changes: 11 additions & 0 deletions src/app/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"workflow_name": "",
"meta": {
"author": "",
"date": "01/01/2000",
"version": "",
"description": ""
},
"imports": [],
"states": {}
}
1 change: 1 addition & 0 deletions src/app/data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"{\n \"workflow_name\": \"\",\n \"meta\": {\n \"author\": \"\",\n \"date\": \"01/01/2000\",\n \"version\": \"\",\n \"description\": \"\"\n },\n \"imports\": [],\n \"states\": {\n \"Load data\": {\n \"Type\": \"MethodCall\",\n \"MethodCall\": \"DataProcessing\",\n \"Parameters\": {\n \"data_path\": \"./tests/api/data/data_eplus.csv\",\n \"data_source\": \"EnergyPlus\"\n },\n \"Payloads\": {\n \"data\": \"$.data\",\n \"data_processing_obj\": \"$\"\n },\n \"Next\": \"Slice data\",\n \"Start\": \"True\"\n }\n }\n}"
Loading

0 comments on commit d34b7ab

Please sign in to comment.