Example #1
0
    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)
Example #2
0
    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
Example #3
0
    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('')
Example #4
0
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)
Example #5
0
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)