def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) # Create the name manager instance and move it to another thread. # This will cause all the slots to be run in that other thread # instead of our GUI thread. self.name_manager = NameManager() self.name_manager_thread = QThread() self.name_manager.moveToThread(self.name_manager_thread) self.name_manager_thread.start() # Create our network manager self.network_manager = NetworkManager() # When the name manager emits it's full name list, we want to # repopulate our list. self.name_manager.names_signal.connect(self.populate_list) # When the restore list button is clicked, let the name manager # know we need all the names in long term storage self.restore_list_button.clicked.connect(self.name_manager.get_all_names) self.add_name_signal.connect(self.name_manager.store_name) self.add_name_signal.connect(self.cache_name) self.submit_button.clicked.connect(self.say_hello) self.clear_list_button.clicked.connect(self.clear_list)
def parse_model(self, m): # Dict used to translate from arg position to anchor position anchor_codes = ['w', 'e', 'n', 's'] nm = NameManager.Instance() # nodes = {1: 'label1', 2: 'label2', ...} # edges = [(1, 2, 'e'), ...] nodes = {} edges = [] predicates = m.split() for n, p in enumerate(predicates): parts = p.split('(') atom = parts[0] terms = parts[1] if len(parts) > 1 else [] nodes[n] = atom if terms: terms = [t.strip(' )') for t in terms.split(',')] atom_anchors = nm.get(atom).hook_points term_anchors = [a for i, a in enumerate(anchor_codes) if atom_anchors[i]] assert len(terms) == len(term_anchors) for i, t in enumerate(terms): nodes[t] = t edges.append((n, t, term_anchors[i])) return nodes, edges
def on_release(self): if self.parent is None: return if self.state == 'down': asp.AtomWidget.active_atom = NameManager.Instance().get(self.text) self.parent.update_atom_editor(self.text) self.parent.set_item('atom') else: asp.AtomWidget.active_atom = None self.parent.update_atom_editor('')
class GlobalContainer(box.BoxLayout): graph_list = prop.ListProperty([]) active_graph = prop.ObjectProperty(None) name_manager = NameManager.Instance() show_sidepanel = prop.BooleanProperty(True) modestr = prop.StringProperty('insert') itemstr = prop.StringProperty('atom') modes = {'insert': asp.Mode.INSERT, 'select': asp.Mode.SELECT} items = { 'atom': asp.Item.ATOM, 'ellipse': asp.Item.ELLIPSE, 'rectangle': asp.Item.SQUARE } def __init__(self, **kwargs): super(GlobalContainer, self).__init__(**kwargs) self._keyboard = None self.request_keyboard() self.working_dir = './' self.tutorial = None self.popup_stack = [] window.Window.bind(on_resize=self.on_resize) if DEBUG: self.tracker = ClassTracker() self.tracker.track_object(MenuButton) self.all_objects = muppy.get_objects() def request_keyboard(self): self._keyboard = window.Window.request_keyboard( self._keyboard_release, self) self._keyboard.bind(on_key_down=self._on_keyboard_down) def _keyboard_catch(self): self._keyboard.bind(on_key_down=self._on_keyboard_down) def _keyboard_release(self): self._keyboard.unbind(on_key_down=self._on_keyboard_down) #self._keyboard = None def _on_keyboard_down(self, keyboard, keycode, text, modifiers): if keycode[1] == 'escape': base.stopTouchApp() elif keycode[1] == 'd': self.set_mode('insert') elif keycode[1] == 's': self.set_mode('select') elif keycode[1] == 'w': self.set_item('atom') elif keycode[1] == 'e': self.set_item('ellipse') elif keycode[1] == 'r': self.set_item('rectangle') elif keycode[1] == 'p': self.active_graph.show_tree(0) elif keycode[1] == 'o': self.view_symbolic_formula() elif keycode[1] == 'n': self.show_gringo_query() elif keycode[1] == 'g': self.show_save() elif keycode[1] == 'l': self.show_load() elif keycode[1] == 'y': print self.name_manager.get_all() print asp.Line.get_all_lines() elif keycode[1] == 't': self.toggle_sidepanel() elif keycode[1] == 'tab': if not self.show_sidepanel: self.toggle_sidepanel() self.ids.atom_input.focus = True elif keycode[1] == '.': if DEBUG: rb = refbrowser.InteractiveBrowser(self) rb.main() # self.all_objects = muppy.get_objects() # sum1 = summary.summarize(self.all_objects) # summary.print_(sum1) # self.tracker.create_snapshot() # self.tracker.stats.print_summary() return True def _focus_name_list(self, value): if value and (asp.AtomWidget.active_atom is not None): previous_name = asp.AtomWidget.active_atom.name for button in self.ids.name_list.children: if (button.text == previous_name) and (button.state != 'down'): button.trigger_action() elif value: if self.ids.name_list.children: self.ids.name_list.children[-1].trigger_action() else: for button in self.ids.name_list.children: if button.state == 'down': button.trigger_action() def on_resize(self, window, width, height): if self.show_sidepanel: self.ids.sidepanel.width = self.width * .15 self.active_graph.size = self.ids.stencilview.size def toggle_sidepanel(self): self.show_sidepanel = not self.show_sidepanel if self.show_sidepanel: width = self.width * .15 else: width = 0 anim.Animation(width=width, d=.15, t='out_quart').start(self.ids.sidepanel) if not self.show_sidepanel: self.ids.sidepanel.focus = False # Also release keyboard #self.update_sourcecode() def update_atom_editor(self, name): editor = self.ids.atom_editor if name == '': editor.disabled = True else: if editor.disabled: editor.disabled = False atom = self.name_manager.get(name) editor.update(atom) def update_atom(self, name, new_name='', new_hook_points=[], is_constant=False): atom = self.name_manager.get(name) if new_name <> '': atom.name = new_name if len(new_hook_points) == 4: atom.hook_points = new_hook_points # print id(atom.hook_points) atom.is_constant = is_constant def register_atom(self, name, hooks=[False, False, False, False], is_constant=False): if name == '': return children = self.ids.name_list.children new_button = None name_to_insert = name i = len(children) - 1 # If the name doesn't exist, register atom if self.name_manager.get(name) is None: self.name_manager.register(name, asp.Atom(name, hooks, is_constant)) # print id(self.name_manager.get(name).hook_points) # Insert in name_list sorted by name while i >= 0: if children[i].text < name_to_insert: #print children[i].text, '<', name_to_insert pass elif children[i].text == name_to_insert: # Already exists if children[i].state != 'down': children[i].trigger_action() return elif children[i].text > name_to_insert: #print children[i].text, '>', name_to_insert temp = children[i].text children[i].text = name_to_insert name_to_insert = temp if new_button == None: new_button = children[i] i -= 1 self.ids.name_list.add_widget(AtomSelectionButton(text=name_to_insert)) if new_button == None: new_button = children[0] if new_button.state == 'down': asp.AtomWidget.active_atom = self.name_manager.get(name) self.update_atom_editor(name) self.set_item('atom') else: new_button.trigger_action() def rename_atom(self, new_name): old_name = '' for button in self.ids.name_list.children: if button.state == 'down': old_name = button.text selected_button = button if (old_name != '') and (new_name != ''): try: atom = self.name_manager.get(old_name) exists = self.name_manager.get(new_name) assert atom is not None assert exists is None except AssertionError: #self.show_error('Name already exists.') print 'Name already exists.' return selected_button.text = new_name atom.name = new_name self.name_manager.unregister(old_name) self.name_manager.register(new_name, atom) self.update_atom_editor(new_name) def delete_atom(self): for button in self.ids.name_list.children: if button.state == 'down': self.name_manager.unregister(button.text) self.active_graph.delete_atom(button.text) asp.AtomWidget.active_atom = None self.ids.name_list.remove_widget(button) self.update_atom_editor('') def clear_atoms(self): self.ids.name_list.clear_widgets() self.name_manager.clear() self.update_atom_editor('') asp.AtomWidget.active_atom = None def new_graph(self): # TODO: Migrate to tab system asp.Line.clear_lines() self.clear_atoms() if self.active_graph is None: g = asp.RootWidget() self.graph_list.append(g) self.active_graph = g self.ids.stencilview.add_widget(g) else: self.active_graph.delete_tree() def close_graph(self): if self.active_graph is not None: asp.Line.clear_lines() self.active_graph.delete_tree() self.active_graph.delete_root() self.clear_atoms() self.graph_list.pop() self.active_graph = None def set_mode(self, mode): try: prev_mode = self.active_graph.mode new_mode = self.modes[mode] if new_mode == asp.Mode.INSERT: self.active_graph.show_hooks() else: if prev_mode == asp.Mode.INSERT: self.active_graph.hide_hooks() self.active_graph.mode = new_mode self.modestr = mode except KeyError as err: print 'ERROR: Invalid mode {0} requested.'.format(str(err)) def set_item(self, item): try: self.active_graph.item = self.items[item] self.itemstr = item except KeyError as err: print 'ERROR: Invalid item {0} requested.'.format(str(err)) except AttributeError: pass if item == 'atom': self._focus_name_list(True) else: self._focus_name_list(False) def push_popup(self, popup): self.popup_stack.append(popup) popup.open() def dismiss_popup(self): popup = self.popup_stack.pop() popup.dismiss() def show_rename_atom(self): content = TextInputDialog(caption="Enter new name", validate_callback=self.rename_atom, cancel=self.dismiss_popup) p = CustomPopup(self, title="Rename atom", content=content, size_hint=(0.4, 0.25)) self.push_popup(p) def show_load(self): content = LoadDialog(load=self.load, cancel=self.dismiss_popup) content.ids.filechooser.path = self.working_dir p = CustomPopup(self, title="Load file", content=content, size_hint=(0.9, 0.9)) self.push_popup(p) def show_save(self): content = SaveDialog(save=self.save, cancel=self.dismiss_popup) content.ids.filechooser.path = self.working_dir p = CustomPopup(self, title="Save file", content=content, size_hint=(0.9, 0.9)) self.push_popup(p) def show_export(self): content = ExportDialog(export=self.export, cancel=self.dismiss_popup) content.ids.filechooser.path = self.working_dir p = CustomPopup(self, title="Export file", content=content, size_hint=(0.9, 0.9)) self.push_popup(p) def show_gringo_query(self): caption = "Enter desired predicates separated by commas" content = TextInputDialog(caption=caption, validate_callback=self.gringo_query, dismiss_on_validate=False, focus=False, cancel=self.dismiss_popup) p = CustomPopup(self, title="Output predicates", content=content, size_hint=(0.4, 0.25)) self.push_popup(p) def show_stable_models(self, solver): models = solver.get_models() content = None if len(models) == 0: content = ErrorDialog('Unsatisfiable', cancel=self.dismiss_popup) else: solver.generate_graph(models[0]) content = StableModelDialog(solver, cancel=self.dismiss_popup) content.ids.img.reload() p = CustomPopup(self, catch_keyboard=False, title="Stable Models", content=content, size_hint=(0.9, 0.9)) self.push_popup(p) def show_error(self, err_str): content = ErrorDialog(err_str, cancel=self.dismiss_popup) p = CustomPopup(self, catch_keyboard=False, title="Error", content=content, size_hint=(0.4, 0.3)) self.push_popup(p) def show_about(self): content = AboutDialog(cancel=self.dismiss_popup) p = CustomPopup(self, catch_keyboard=False, title="About " + __title__, content=content, size_hint=(0.5, 0.5)) self.push_popup(p) def load(self, path, filename): self.close_graph() self.working_dir = path try: f = os.path.join(path, filename[0]) # Temporal line storage. Its contents are arranged as follows: # { line_id: (graph, hook_list) , ... } lines = {} with open(f, 'r') as stream: for line in stream: if line.startswith(NameParser.TOKENS['name']): name, hooks, is_constant = NameParser.parse_name(line) self.register_atom(name, hooks, is_constant) if line.startswith(NameParser.TOKENS['line']): line_id, graph = NameParser.parse_line(line) lines[line_id] = (graph, [None] * len(graph)) new_graph = lang.Builder.load_file(f) self.ids.stencilview.add_widget(new_graph) self.active_graph = new_graph #self.graph_list.pop() self.graph_list.append(new_graph) for w in self.active_graph.walk(restrict=True): if isinstance(w, asp.AtomWidget): w._deferred_init() for i in w.get_line_info(): line_id = i[0] hook_index = i[1] lines[line_id][1][hook_index] = i[2] elif isinstance(w, asp.NexusWidget): for i in w.line_info: line_id = i[0] hook_index = i[1] lines[line_id][1][hook_index] = w for line, info in lines.iteritems(): print line, info asp.Line.build_from_graph(info[0], info[1]) self.set_mode(self.modestr) self.set_item(self.itemstr) self.dismiss_popup() except (KeyboardInterrupt, SystemExit): raise except: self.dismiss_popup() self.close_graph() self.new_graph() self.show_error('Corrupted file.') def save(self, path, filename): self.working_dir = path with open(os.path.join(path, filename), 'w') as stream: stream.write('#:kivy 1.0.9\n\n') for (name, atom) in self.name_manager.get_all(): stream.write( NameParser.get_name_str(name, atom.hook_points, atom.is_constant)) for line in asp.Line.get_all_lines(): stream.write( NameParser.get_line_str(line.line_id, line.get_full_graph())) stream.write('\n') stream.write(self.active_graph.get_tree(0)) self.dismiss_popup() def export(self, path, filename): _, ext = os.path.splitext(filename) if ext == '.png': self.active_graph.export_to_png(os.path.join(path, filename)) elif ext == '.lp': rpn = self.active_graph.get_formula_RPN() constants = self.active_graph.get_constants() solver = eg_solver.Solver() solver.set_formula(rpn, constants) rules = solver.generate_asp_rules() with open(os.path.join(path, filename), 'w') as stream: for r in rules: stream.write(r) stream.write('\n') else: error_str = 'File extension not supported.' print error_str self.show_error(error_str) return self.dismiss_popup() def highlight_variables(self): self.active_graph.highlight_variables() def view_symbolic_formula(self): print self.active_graph.get_formula() def gringo_query(self, show_predicates): def generate_show_statements(predicates): pred_list = predicates.split(',') pred_list = map(lambda s: s.strip(), pred_list) n_args = (lambda name: self.name_manager.get(name).hook_points. count(True)) pred_list = [p + '/' + str(n_args(p)) for p in pred_list] show_list = ['#show {0}.'.format(p) for p in pred_list] return show_list self.dismiss_popup() rpn = self.active_graph.get_formula_RPN() rpn = norm.LIT.TRUE if rpn == '' else rpn constants = self.active_graph.get_constants() print 80 * '-' print 'RPN formula:\n', rpn solver = eg_solver.Solver() result = '' try: show_statements = [] if show_predicates: try: show_statements = generate_show_statements(show_predicates) except Exception: pass solver.set_formula(rpn, constants) result = solver.solve(show=show_statements) except norm.MalformedFormulaError: self.show_error('Malformed formula.') return except RuntimeError, e: print e self.show_error(str(e)) return self.show_stable_models(solver)
class MainWindow(QMainWindow, Ui_MainWindow): add_name_signal = Signal(unicode) def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) # Create the name manager instance and move it to another thread. # This will cause all the slots to be run in that other thread # instead of our GUI thread. self.name_manager = NameManager() self.name_manager_thread = QThread() self.name_manager.moveToThread(self.name_manager_thread) self.name_manager_thread.start() # Create our network manager self.network_manager = NetworkManager() # When the name manager emits it's full name list, we want to # repopulate our list. self.name_manager.names_signal.connect(self.populate_list) # When the restore list button is clicked, let the name manager # know we need all the names in long term storage self.restore_list_button.clicked.connect(self.name_manager.get_all_names) self.add_name_signal.connect(self.name_manager.store_name) self.add_name_signal.connect(self.cache_name) self.submit_button.clicked.connect(self.say_hello) self.clear_list_button.clicked.connect(self.clear_list) def clean_up(self): """ You can't rely on __del__ properly closing down all your threads. So use a clean_up method that will be called manually. :return: """ if hasattr(self, 'network_manager_thread'): self.network_manager.api.end_connection() self.network_manager.api.join() self.network_manager_thread.quit() self.name_manager_thread.quit() def start_api(self, ip, port): """ Connect to an external API service which will send us names :param ip: IP address of server :param port: Port of service :return: """ self.network_manager_thread = QThread() self.network_manager.moveToThread(self.network_manager_thread) self.network_manager.message_signal.connect(self.handle_message) self.network_manager_thread.start() self.network_manager.connect_signal.emit(ip, port) @Slot() def handle_message(self, message): """ Handle incoming names from the API. We simply want to follow the established procedure to add a new name. So we just emit on that signal. :param message: String name :return: """ self.add_name_signal.emit(message) @Slot() def say_hello(self): self.add_name_signal.emit(self.name_text.text()) self.hello_label.setText(u"{} {}".format(GREETING, self.name_text.text())) self.name_text.setText('') @Slot() def cache_name(self, name): self.names_list.addItem(name) @Slot() def clear_list(self): self.names_list.clear() @Slot() def populate_list(self, names): """ Clears and repopulates the list with the given list :param names: List of names :return: """ self.clear_list() for name in names: self.names_list.addItem(name)