diff --git a/lib/CreoMigrateGui.py b/lib/CreoMigrateGui.py index 7e9c261..55800bf 100644 --- a/lib/CreoMigrateGui.py +++ b/lib/CreoMigrateGui.py @@ -1,354 +1,121 @@ import tkinter as tk -from tkinter import ttk -from controller import Controller +from gui import App from caditem import CadItem -#from tkinter import messagebox -#import logging +from controller import Controller, GuiLogic +from manage_configs import Configs +import argparse +import os + +demo_data = """ +{ + "parent_children_mapping": { + "400102130": [ "400102142" ], + "400102167": [ "821116004" ], + "400102168": [ "821116001" ], + "400102195": [ "822066075", "822066216", "822066154", "822066101", + "822064090", "822066196", "400102129", "822066217", "822066160", + "822066215", "913041045", "913011009", "911011057", "822064035", + "925011006", "911091041", "913051040", "911021112", "911021166", + "825006003", "912041005", "911011014", "911011009", "911021144", + "911021001", "913011016", "929055170", "913011010", "911021035", + "829416065", "712000151", "712000100" ], + "400102196": [ "400102125", "400102126", "400102130", "400102161", + "400102163", "400102165", "400102166", "400102167", "400102168", + "400102190", "400102195", "400102198", "400102246", "400102247", + "400102267", "400102272", "400102274", "400102275", "400102277", + "400102278", "400102282", "400102284", "400102417", "720002003", + "721001034", "821114025", "822064091", "822066085", "822996075", + "829416061", "829516004", "911021113", "911021181", "911021259", + "911091054", "911091096", "911091097", "911251013", "912011009", + "919050006", "924031058", "924031081" ], + "400102235": [ "400102236", "400102237", "400102238", "400102239", + "400102268", "911021143", "911021054", "911021055" ], + "400102236": [ "MA0000006" ], + "400102267": [ "400102235", "829416159", "829416077", "829416079", + "911021260", "911021147", "911251014" ], + "400102282": [ "822066026", "822066089", "919010052" ], + "821114025": [ "911081007", "821116053" ], + "821116004": [ "822026004" ], + "822064035": [ "822066065" ], + "822064091": [ "822066212", "822064093", "822066220", "822066200", + "912011010", "911021156", "822066201", "911071027", "913011109", + "911011070", "913011001", "710005021", "919010055", "720000008", "720000007" ], + "822064093": [ "822066204", "822066205", "822066206", "822066207", "822066208" ], + "822066075": [ "822066157", "822066162", "911261023" ], + "822066160": [ "MA0000004" ], + "822066162": [ "822064013" ], + "822066196": [ "MA0000008" ], + "822066220": [ "924031033" ], + "829416159": [ "829416089" ] + }, + "red_ids": [ "400102274", "400102275", "400102190", "400102198", "400102161", + "400102277", "400102163", "400102278", "400102282", "400102284", + "400102195", "MA0000008", "MA0000004", "929055170", "400102267", + "400102235", "400102236", "MA0000006", "400102237", "400102238", + "400102239", "400102268", "829416159", "924031058", "924031081", + "822064091", "822066199", "822066200" ], + "gui_data": { + "asm_id": "400102196", + "teilenummer": "400102142", + "pdm_kategorie_neu": "Einzelteil", + "neuaufbau": "False", + "lebenszyklus_status_neu": "Serie", + "aus_halbzeug_neu": "True", + "zusatzinfos_text_neu": "Dies sind neue Zusatzinfos" + }, + "data": {} +} +""" + +class Environment: + + def __init__(self): + self.lib_dir = os.environ.get('CREMIG_LIB') + self.data_dir = os.environ.get('CREMIG_DATA') + self.out_dir = os.environ.get('CREMIG_WORK') + self.cfg_dir = os.environ.get('CREMIG_CFG') + self.ruledesigner_csv_filename = os.environ.get('RD_DATABASE_NAME') + +def build_gui(model, configs): + root = tk.Tk() + app = App(root, configs) + + controller = Controller(model, app) + logic = GuiLogic(configs) + controller.add_logic(logic) + + # um ohne Observer pattern auch Rückmeldungen geben zu können + app.set_controller(controller) + model.set_controller(controller) + + # Daten des Modells in der Oberfläche darstellen + controller.refresh_gui() + + app.mainloop() -#logger = logging.getLogger(__name__) -class TreeView(): - def __init__(self, frame, nrow=0): - # a treeview - # hier Anzahl der sichtbaren Zeilen des Baums angeben: - self.tree = ttk.Treeview(frame, height=40) - # TODO hier anstatt root die Statistik rein schreiben. - self.tree.heading('#0', text='root', anchor=tk.W) - self.tree.grid(row=nrow, column=0, sticky=tk.NSEW) +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Das Programm ermöglicht einw graphisch unterstützte Migration eines Teiles oder Assemblies von Creo nach SolidEdge. Erzeugt eine korrekte Impfdatei.', prog='CreoMigrateGui') + parser.add_argument('-n', '--number', action='store', help='Eingabe der SIVAS-Teilenummer, für die der Migrationsstatus angezeigt werden soll', metavar="id") + parser.add_argument('-d', '--demo', action='store_true', help='arbeitet ohne Server. Lädt Testdaten ein um nur eine Oberfläche darzustellen') - # add a scrollbar - scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=self.tree.yview) - self.tree.configure(yscroll=scrollbar.set) - scrollbar.grid(row=nrow, column=1, sticky='ns') + args = parser.parse_args() - #self.tree.bind('<>', self.item_selected) # Einfachklick - self.tree.bind('', self.item_selected) # Doppelklick: + environment = Environment() + output_dir = environment.out_dir + configs = Configs(environment.cfg_dir) - def set_controller(self, controller): - self.controller = controller + model = CadItem() + if args.demo: + model.from_json(demo_data) + build_gui(model, configs) - def refresh(self, parent_children_mapping, red_ids): - self.clear() - self.create(parent_children_mapping, red_ids) + elif args.number: + id = args.number + path = os.path.join(output_dir, id + '.json') + if os.path.exist(path): + model.load(demo_data) + build_gui(model, configs) + else: + parser.print_help() - def clear(self): - for c in self.tree.get_children(): - self.tree.delete(c) - - def create(self, parent_children_mapping, red_ids): - # adding data of first column after root - pool = set() - for parent,children in parent_children_mapping.items(): - if parent not in pool: - self.tree.insert('', tk.END, text=parent, iid=parent, open=True) - pool.add(parent) - cn = children - # sortiere die Zahlen im Baum immer aufsteigend - cn.sort(reverse=True) - for child_id in cn: - if child_id not in pool: - pool.add(child_id) - if child_id not in red_ids: rowtags = ('good') - else: rowtags = ('missing') - self.tree.insert('', tk.END, text=child_id, iid=child_id, tags=rowtags, open=True) - #self.tree.move(child_id, parent, 0) - - # einmal über alles gehen und alle keys an die richtige Stelle schieben - for parent,children in parent_children_mapping.items(): - for child_id in children: - self.tree.move(child_id, parent, 0) - - # https://www.askpython.com/python-modules/tkinter/tkinter-colors - #self.tree.tag_configure('good', background='LawnGreen') - self.tree.tag_configure('good', background='white') - self.tree.tag_configure('missing', background='red') - - def data_from_model(self): - parent_children_mapping = self.controller.get_parent_children() - red_ids = self.controller.get_red_ids() - self.refresh(parent_children_mapping, red_ids) - - def item_selected(self, event): - """callback of TK if an item in the tree has been selected - """ - cid = self.tree.selection()[0] - # trage die neue ID ins Modell ein - self.controller.set_gui_data('teilenummer', cid) - self.controller.refresh_gui() - - -class AllFrames(): - """ enthält alle gleichen Methoden für die Widgets in der rechte Spalte - """ - def __init__(self, nrow=0): - self.set_start_rwo(nrow) - self._controller = None - - def get_rows(self): - return self.rownum - - def set_start_rwo(self, nrow): - if nrow < 0: - raise Exception("this row can not be set") - self.rownum = nrow - - def set_controller(self, controller): - self._controller = controller - def get_controller(self): - return self._controller - - def callback(self, key): - controller = self.get_controller() - if controller: - controller.callback(key) - - - def data_to_model(self, controller): - data = self.get_data() - controller.set_gui_dict(data) - - def data_to_model(self, controller, key, value): - controller.set_gui_data(key, value) - -class LeftFrameAsm(AllFrames): - def __init__(self, frame, nrow=0): - AllFrames.__init__(self, nrow) - self.frame = frame - self.build_widgets() - - def build_widgets(self): - frame = self.frame - self.rownum = AllFrames.get_rows(self) - col_left = 0 - # Baugruppennummer - asm_label = ttk.Label(frame, text="Baugruppennummer:" ) - asm_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.rownum += 1 - self.asm_number = tk.StringVar() - asm_entry = ttk.Entry(frame, textvariable=self.asm_number, width=9) - asm_entry.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.rownum += 1 - - def get_data(self): - return { - "asm_id": self.asm_number.get(), - } - - def data_from_model(self): - data = self.get_controller().get_all_gui_data() - if 'asm_id' in data: - self.asm_number.set(data["asm_id"]) - -class RightFrameLabels(AllFrames): - def __init__(self, frame, nrow=0): - AllFrames.__init__(self, nrow) - self.frame = frame - self.build_widgets() - - def build_widgets(self): - frame = self.frame - self.rownum = AllFrames.get_rows(self) - col_left = 0 - # Feld, SIVAS-Werte, Überschriebene Werte - feld_label = ttk.Label(frame, text="Feld" ) - feld_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - Sivas_label = ttk.Label(frame, text="SIVAS-Werte" ) - Sivas_label.grid(column=col_left+1, row=self.rownum, sticky=tk.W, padx=5, pady=5) - transwritten_label = ttk.Label(frame, text="Überschriebene Werte" ) - transwritten_label.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5) - - feld_label.configure(font=("Helvetica", 16)) - Sivas_label.configure(font=("Helvetica",16)) - transwritten_label.configure(font=("Helvetica",16)) - self.rownum += 1 - - separator = ttk.Separator(frame, orient='horizontal') - separator.grid(column=col_left, columnspan=3, row=self.rownum, sticky=tk.EW, padx=5, pady=5) - self.rownum += 1 - - # Teilenummer - teilenummer_label = ttk.Label(frame, text="Teilenummer:") - teilenummer_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.teilenummer_text = tk.StringVar() - teilenummer_entry = ttk.Entry(frame, textvariable=self.teilenummer_text) - teilenummer_entry.grid(column=col_left+1, row=self.rownum, sticky=tk.W, padx=5, pady=5) - teilenummer_entry.bind('<>', lambda event:self.callback("teilenummer")) - self.rownum += 1 - separator2 = ttk.Separator(frame, orient='horizontal') - separator2.grid(column=col_left, columnspan=3, row=self.rownum, sticky=tk.EW, padx=5, pady=5) - self.rownum += 1 - - - def get_data(self): - return { - "teilennummer": self.teilenummer_text.get(), - } - - def data_from_model(self): - data = self.get_controller().get_all_gui_data() - if 'teilenummer' in data: - self.teilenummer_text.set(data["teilenummer"]) - - -class RightFramePDM(AllFrames): - def __init__(self, frame, nrow=0): - AllFrames.__init__(self, nrow) - self.frame = frame - self.build_widgets() - - def build_widgets(self): - frame = self.frame - self.rownum = AllFrames.get_rows(self) - col_left = 0 - # pdmkategorie - pdmkategorie_label = ttk.Label(frame, text="PDM-Kategorie:" ) - pdmkategorie_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.pdm_category = tk.StringVar() - pdmkategorie_combo = ttk.Combobox(frame, textvariable=self.pdm_category) - pdmkategorie_combo['values'] = ["Baugruppe", "Einzelteil", "Kaufteil", "NichtSivas", "Normteil", "Schweissbaugruppe"] - pdmkategorie_combo['state'] = 'readonly' - pdmkategorie_combo.bind('<>', lambda event:self.callback('pdm_kategorie_neu')) - pdmkategorie_combo.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.rownum += 1 - - # Neuaufbau - neuaufbau_label = ttk.Label(frame, text="Neuaufbau:") - neuaufbau_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - - self.neuaufbau = None - neuaufbau_checkbutton = ttk.Checkbutton(frame, - text='ja', - variable=self.neuaufbau, - command=lambda: self.callback("neuaufbau"), - onvalue=True, - offvalue=False) - neuaufbau_checkbutton.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.rownum += 1 - - # Lebenszyklusstatus - lebenszyklusstatus_label = ttk.Label(frame, text="Lebenszyklusstatus:") - lebenszyklusstatus_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.lebenszyklus_status_neu = tk.StringVar() - lebenszyklusstatus_combo = ttk.Combobox(frame, textvariable=self.lebenszyklus_status_neu) - lebenszyklusstatus_combo['values'] = ["Serie", "Prototyp"] - lebenszyklusstatus_combo['state'] = 'readonly' - lebenszyklusstatus_combo.bind('<>', lambda event:self.callback('lebenszyklus_status_neu')) - lebenszyklusstatus_combo.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.rownum += 1 - - # aus Halbzeug - halbzeug_label = ttk.Label(frame, text="aus Halbzeug:") - halbzeug_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.aus_halbzeug_neu = None - aushalbzeug_checkbuttonr = ttk.Checkbutton(frame, - text='neu', - variable=self.aus_halbzeug_neu, - command=lambda: self.callback("aus_halbzeug_neu"), - onvalue=True, - offvalue=False) - aushalbzeug_checkbuttonr.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.rownum += 1 - - # Zusatzinformationen - zusatzinfos_label = ttk.Label(frame, text="Zusatzinformationen:") - zusatzinfos_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.zusatzinfos_text = tk.StringVar() - zusatzinfos_entry = ttk.Entry(frame, textvariable=self.zusatzinfos_text) - zusatzinfos_entry.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5) - self.rownum += 1 - - def get_data(self): - return { - "pdm_kategorie_neu": self.pdm_category.get(), - "neuaufbau": self.neuaufbau, - "lebenszyklus_status_neu": self.lebenszyklus_status_neu.get(), - "aus_halbzeug_neu": self.aus_halbzeug_neu, - "zusatzinfos_txt_neu": self.zusatzinfos_text.get(), - } - - def data_from_model(self): - data = self.get_controller().get_all_gui_data() - if 'pdm_kategorie_neu' in data: - self.pdm_category.set(data["pdm_kategorie_neu"]) - if 'neuaufbau' in data: - self.neuaufbau = data["neuaufbau"] - if 'lebenszyklus_status_neu' in data: - self.lebenszyklus_status_neu.set(data["lebenszyklus_status_neu"]) - if 'aus_halbzeug_neu' in data: - self.aus_halbzeug_neu= data["aus_halbzeug_neu"] - if 'zusatzinfos_text_neu' in data: - self.zusatzinfos_text.set(data["zusatzinfos_text_neu"]) - - - -class App(): - def __init__(self, root): - """Standardgui mit Baum zur Anwahl der Teile des Assemblies""" - - self.root = root - - # configure the grid - # die erste Spalte mit Baum sollte unbeweglich bleiben bei Vergräßerung des Fensters. - # self.root.columnconfigure(0, weight=2) - self.root.columnconfigure(1, weight=1) - #self.root.geometry('800x800') - - # Create left and right frames - left_frame = ttk.Frame(self.root, width=200, height=800) - left_frame.grid(row=0, column=0, padx=10, pady=5) - - right_frame = ttk.Frame(self.root, width=650, height=800) - right_frame.grid(row=0, column=1, padx=10, pady=5) - - style = ttk.Style(self.root) - style.theme_use('classic') - - self.lf1 = LeftFrameAsm(left_frame, 0) - nrows = self.lf1.get_rows() - self.lf2 = TreeView(left_frame, nrows) - - self.rf0 = RightFrameLabels(right_frame, 0) - nrows = self.rf0.get_rows() - self.rf1 = RightFramePDM(right_frame, nrows) - nrows = self.rf1.get_rows() - #self.rf2 = RightFramePDM(right_frame, nrows) - # TODO usw. - - def data_from_model(self): - """ methode zum auslesen aller Daten der Oberfläche aus dem Modell - """ - self.lf1.data_from_model() - self.lf2.data_from_model() - - self.rf0.data_from_model() - self.rf1.data_from_model() - - def set_controller(self, controller): - # merken des Handels auf den Controller in jedem widget - self._controller = controller - - self.lf1.set_controller(controller) - self.lf2.set_controller(controller) - self.rf0.set_controller(controller) - self.rf1.set_controller(controller) - - def mainloop(self): - self.root.mainloop() - - -if __name__ == "__main__": - - """ using the Model-View-Controller (MVC) Pattern - - The MODEL is responsible for managing the data of the application. It - receives user input from the CONTROLLER - - The VIEW renders presentation of the model in a particular format. - - The CONTROLLER responds to the user input and performs interactions on the - data model objects. The CONTROLLER receives the input, optionally validates - it and then passes the input to the model. - - - <--fills gui -- --manipulates--> - --user input-> <--give model data-- - - - """