diff --git a/forms.py b/forms.py index dcb61fa..91788d3 100644 --- a/forms.py +++ b/forms.py @@ -186,7 +186,7 @@ class MainFrame(wx.Frame): menubar.Append(menu, '&Run') menu = wx.Menu() - menu.Append(ID_SHOW_RESULT, 'Show numbers\tF7') + menu.Append(ID_SHOW_RESULT, 'Show report\tF7') menu.AppendSeparator() menu.Append(ID_SHOW_PLOT, 'Show plot\tF8') menu.Append(ID_ADD_PLOT, 'Add plot') @@ -228,7 +228,7 @@ class MainFrame(wx.Frame): tb1.SetToolBitmapSize(wx.Size(16, 16)) tb1.AddSimpleTool(ID_ADD_MODEL_SELECTED, "model-new", wx.Bitmap('share/model-add.png'), - 'Add spacification to selected model') + 'Add specification to selected model') tb1.AddSimpleTool(ID_DUPLICATE_MODEL, "model-dup", wx.Bitmap('share/model-dup.png'), 'Duplicate selected model') tb1.AddSimpleTool(ID_DUPLICATE_TREE, "model-dup-tree", wx.Bitmap('share/model-dup-tree.png'), diff --git a/opal.py b/opal.py index b51c039..cdac4a6 100644 --- a/opal.py +++ b/opal.py @@ -13,14 +13,19 @@ import server import task + import wx -import wx.propgrid as wxpg -import wx.lib.plot as wxplot import forms +wxpg = forms.wxpg +wxplot = forms.wxplot +from wx.lib.embeddedimage import PyEmbeddedImage + import time import threading import re -from wx.lib.embeddedimage import PyEmbeddedImage +import json +import zlib +from pprint import pprint class ModelData: def __init__(self, server, model, parent_data = None): @@ -38,9 +43,9 @@ class ModelData: self.res = None -LINE_CURVE = 1 -LINE_MARKER = 2 -LINE_HISTOGRAM = 3 +LINE_CURVE = 1 +LINE_MARKER = 2 +LINE_HISTOGRAM = 3 class LineData: """ @@ -63,6 +68,10 @@ class LineData: self.colour = colour # цвет: если не задан выбирается из списка self.style = style # стиль: если не задан, еспользуется по умолчанию + def GetModelTitle(self): + container, item = self.ums_ptr + return container.GetItemText(item) + def GetTitle(self): # если есть указатель на компонент с графиками, # извлекаем оттуда название @@ -98,6 +107,7 @@ class MainFrame(forms.MainFrame): def __init__(self): forms.MainFrame.__init__(self, None) + self.model = None self.name_id = 1 s = server.LocalServer() @@ -129,6 +139,10 @@ class MainFrame(forms.MainFrame): self.Bind(wx.EVT_MENU, self.OnNewProject, id = forms.ID_NEW) + self.Bind(wx.EVT_MENU, self.OnOpenProject, + id = forms.ID_OPEN) + self.Bind(wx.EVT_MENU, self.OnSaveProject, + id = forms.ID_SAVE) self.Bind(wx.EVT_MENU, self.OnTest, id = forms.ID_TEST) @@ -283,7 +297,7 @@ class MainFrame(forms.MainFrame): """ def DoItem(item, model): sp.SetPyData(item, model) - for spec in model.GetSpecs(): + for label, spec in model.GetSpecs().iteritems(): child = sp.AppendItem(item, spec.GetTitle()) DoItem(child, spec) @@ -294,7 +308,7 @@ class MainFrame(forms.MainFrame): sp.ExpandAll() sp.SortChildren(root) - def NewProject(self, model): + def NewProject(self, model, create_default = True): """ Начать новый проект: 0. Очичтить все компоненты @@ -307,6 +321,8 @@ class MainFrame(forms.MainFrame): self.m_params.Clear() self.m_quick_result.Clear() self.m_plots.DeleteAllItems() + # фиксируем выбранную модель + self.model = model # Строим спецификации self.BuildSpecs(model) # Очищаем окно пользовательских моделей @@ -314,7 +330,8 @@ class MainFrame(forms.MainFrame): um = self.m_user_models um.DeleteAllItems() um.AddRoot('root') - self.AddModelToRoot(model) + if create_default: + self.AddModelToRoot(model) # Создаем корневой элемент для окна с графиками self.m_plots.AddRoot('root') @@ -329,8 +346,123 @@ class MainFrame(forms.MainFrame): model = f.GetSelectedModel() if model: self.NewProject(model) + self.do_nothing = False + def OnOpenProject(self, event): + + def WalkModels(source, root, models, model_def = None): + + for key, value in source.iteritems(): + label = value['model'] + if label not in models: + raise KeyError, 'no "{}"'.format(label) + data = ModelData(self.server, models[label], model_def) + data.mdef.params = value['data'] + if 'result' in value: + data.res = task.ResultData(value['result']) + # тут надо проверить все добавленные параметры + + item = um.AppendItem(root, key) + um.SetPyData(item, data) + model_items[key] = item + WalkModels(value['um'], item, models[label].GetSpecs(), data) + + try: + infile = 'data.opl' + data = {} + with open(infile, 'rb') as f: + data = json.loads(zlib.decompress(f.read())) + + pprint(data) + + tid = data['tid'] + model_label = data['model'] + model = self.server.CheckModel(tid, model_label) + if not model: + raise ValueError + + self.NewProject(model, False) + + um = self.m_user_models + model_items = {} + root = um.GetRootItem() + WalkModels(data['um'], root, {model.GetLabel(): model}) + + # except KeyError, e: + # wx.MessageBox("Can't parse saved file!", 'Error!') + # except ValueError, e: + # wx.MessageBox("Can't parse saved file!", 'Error!') + except Exception, e: + print 'Oops', type(e), e + + + def OnSaveProject(self, event): + + def WalkModels(item, dest): + if item != um.GetRootItem(): + data = um.GetPyData(item) + title = um.GetItemText(item) + mdef = data.mdef + dest[title] = { + 'model': mdef.DD.GetLabel(), + 'data': mdef.params, + 'um': {} + } + if data.res: + dest[title]['result'] = data.res.DumpData() + dest = dest[title]['um'] + + child, _ = um.GetFirstChild(item) + while child.IsOk(): + WalkModels(child, dest) + child = um.GetNextSibling(child) + + def WalkPlots(root, dest): + # по всеи элементам первого уровня + item1, _ = self.m_plots.GetFirstChild(root) + while item1.IsOk(): + # по всем элементам второго уровня + item2, _ = self.m_plots.GetFirstChild(item1) + lines = [] + while item2.IsOk(): + line = self.m_plots.GetPyData(item2) + data = { + 'title': self.m_plots.GetItemText(item2), + 'colx': line.columns[0], + 'coly': line.columns[1], + 'model': line.GetModelTitle(), + 'type': line.type, + } + lines.append(data) + item2 = self.m_plots.GetNextSibling(item2) + title = self.m_plots.GetItemText(item1) + dest.append([title, lines]) + item1 = self.m_plots.GetNextSibling(item1) + + + wx.BeginBusyCursor() + + data = {} + + data['tid'] = self.model.GetTaskId() + data['model'] = self.model.GetLabel() + + um = self.m_user_models + data['um'] = {} + WalkModels(um.GetRootItem(), data['um']) + + data['plots'] = [] + WalkPlots(self.m_plots.GetRootItem(), data['plots']) + + # pprint(data) + dump = json.dumps(data, indent = 2) + with open('data.opl', 'wb') as f: + f.write(zlib.compress(dump, 9)) + # f.write(dump) + + wx.EndBusyCursor() + # Функции непосредственной работы с моделями: # создание, изменение, дублирование и прочее @@ -502,7 +634,6 @@ class MainFrame(forms.MainFrame): # то все субмодели должны быть пересчитаны Walk(item) - def OnTest(self, event): def Walk(item): @@ -955,6 +1086,9 @@ class ThisApp(wx.App): # Запуск приложения #----------------------------------------------------------------------------- -if __name__ == "__main__": +def main(): app = ThisApp(redirect = False) - app.MainLoop() \ No newline at end of file + app.MainLoop() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/opal.pyw b/opal.pyw new file mode 100644 index 0000000..d2d8926 --- /dev/null +++ b/opal.pyw @@ -0,0 +1,2 @@ +from opal import main +main() \ No newline at end of file diff --git a/server.py b/server.py index a16f73b..025c550 100644 --- a/server.py +++ b/server.py @@ -17,6 +17,7 @@ import time import datetime import threading import subprocess +import hashlib import task @@ -47,8 +48,6 @@ class LocalServer: self.queue_lock = threading.Lock() # init actions - - self.log = open('log.txt', 'w') self.WriteToLog('local server initialized') def Close(self): @@ -61,7 +60,7 @@ class LocalServer: def WriteToLog(self, msg): tm = str(datetime.datetime.now()) msg = tm + ' ' + msg - self.log.write(msg + '\n') + # self.log.write(msg + '\n') print msg def TestTaskData(self, data): @@ -86,13 +85,14 @@ class LocalServer: self.TestTaskData(data) # вычисляем псевдоуникальный идентификатор модели - tid = hash(data['meta']) + tid = hashlib.md5(data['meta']).hexdigest() # сохраняем описание задачи self.tasks_meta[tid] = { 'title': data.get('title', ''), 'author': data.get('author', ''), 'meta': data['meta'], - 'exec': line + 'exec': line, + 'models': [] } # выделяем описания моделей @@ -101,6 +101,7 @@ class LocalServer: model_descr = task.DataDescription(None, label, data, tid) # добавляем в список описаний self.models.append(model_descr) + self.tasks_meta[tid]['models'].append(model_descr) self.WriteToLog('Task from "{}" asked'.format(line)) except IOError, e: @@ -116,6 +117,13 @@ class LocalServer: def GetTaskMeta(self, tid): return self.tasks_meta.get(tid) + def CheckModel(self, tid, model_label): + models = self.tasks_meta[tid]['models'] + for model in models: + if model_label == model.GetLabel(): + return model + return None + #-------------------------------------------------------------------------- def CreateJob(self): diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fdabf37 --- /dev/null +++ b/setup.py @@ -0,0 +1,18 @@ +from distutils.core import setup +import py2exe + + +excludes = ['_gtkagg', '_tkagg', 'bsddb', 'curses', 'email', 'pywin.debugger', + 'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl', + 'Tkconstants', 'Tkinter'] +setup( + name = 'Opal', + windows = ['opal.pyw'], + options = { "py2exe": { + "compressed": 2, + "optimize": 2, + "bundle_files": 1, + "excludes": excludes, + } }, + zipfile = None, +) \ No newline at end of file diff --git a/task.py b/task.py index 109fa03..0d7e820 100644 --- a/task.py +++ b/task.py @@ -42,6 +42,17 @@ class Parameter: def Test(self, value): return True + def DumpData(self): + """ + Возвращает данные в стандартных контейнерах + + READ ONLY!!! + """ + return self.data + + def LoadData(self, data): + self.data = data + class Value(Parameter): def __init__(self, label, value): if isinstance(value, dict): @@ -70,6 +81,13 @@ class Column(Parameter): except: pass + def DumpData(self): + return [ + self.GetLabel(), + self.GetType(), + self.GetTitle(), + ] + #------------------------------------------------------------------------------- class DataDescription: @@ -86,10 +104,12 @@ class DataDescription: par = Parameter(label, self.pdata[label]) self.pdata[label] = par - self.specs = [] # рекурсивное создание описаний спецификаций - for label, data in self.data.get('spec', {}).iteritems(): - self.specs.append(DataDescription(self, label, data, self.tid)) + self.specs = { label: DataDescription(self, label, data, self.tid) + for label, data in self.data.get('spec', {}).iteritems() } + + # for label, data in self.data.get('spec', {}).iteritems(): + # self.specs.append(DataDescription(self, label, data, self.tid)) def GetLabel(self): return self.label @@ -115,6 +135,9 @@ class DataDescription: def GetImage(self): return self.data.get('img') + def GetTaskId(self): + return self.tid + def __getitem__(self, label): return self.pdata.get(label) @@ -158,16 +181,7 @@ class DataDefinition: class ResultData: def __init__(self, data): - self.data = {} - for key, value in data.get('data', {}).iteritems(): - self.data[key] = Value(key, value) - - table = data.get('table', []) - self.head = {} - self.table = [] - if table: - self.head = [ Column(item) for item in table[0] ] - self.table = table[1:] + self.LoadData(data) def GetColumns(self): return self.head @@ -187,3 +201,28 @@ class ResultData: def Zip(self, col1, col2): return [ (row[col1], row[col2]) for row in self.rows ] + + def DumpData(self): + data = {} + if self.data: + data['data'] = { key: self.data[key].DumpData() + for key in self.data } + + if self.head: + head = [ col.DumpData() for col in self.columns ] + body = self.table + data['table'] = [head] + body + return data + + def LoadData(self, data): + self.data = {} + for key, value in data.get('data', {}).iteritems(): + self.data[key] = Value(key, value) + + table = data.get('table', []) + self.head = [] + self.table = [] + if table: + self.head = [ Column(item) for item in table[0] ] + self.table = table[1:] + diff --git a/tasks/testt.json b/tasks/testt.json index f427e4d..ff9a0ee 100644 --- a/tasks/testt.json +++ b/tasks/testt.json @@ -33,7 +33,7 @@ "n": { "type": "int", - "default": 100, + "default": 10, "title": "Steps", "comment": "Number of steps for algorithm" } diff --git a/tasks/testt.py b/tasks/testt.py index f1cbecb..f979c64 100644 --- a/tasks/testt.py +++ b/tasks/testt.py @@ -52,7 +52,7 @@ def serie(n, d, h, l = 0): y = sin_taylor(l, d) yield (l, y) l += h - time.sleep(0.01) + # time.sleep(0.002) def main():