All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jsoar.debugger.PartialMatchesView Maven / Gradle / Ivy

/*
 * Copyright (c) 2008  Dave Ray 
 *
 * Created on Oct 23, 2008
 */
package org.jsoar.debugger;

import java.awt.BorderLayout;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;

import org.jsoar.debugger.selection.SelectionListener;
import org.jsoar.debugger.selection.SelectionManager;
import org.jsoar.debugger.syntax.Highlighter;
import org.jsoar.kernel.Production;
import org.jsoar.kernel.ProductionManager;
import org.jsoar.kernel.rete.PartialMatches;
import org.jsoar.kernel.rete.PartialMatches.Entry;
import org.jsoar.runtime.CompletionHandler;
import org.jsoar.runtime.ThreadedAgent;
import org.jsoar.util.adaptables.Adaptables;

/**
 * @author ray
 */
public class PartialMatchesView extends AbstractAdaptableView implements SelectionListener, Refreshable
{
    private final ThreadedAgent agent;
    private final SelectionManager selectionManager;
    private final Highlighter highlighter;
    private JTextPane textArea = new JTextPane();

    public PartialMatchesView(JSoarDebugger debugger)
    {
        super("partialmatches", "Partial Matches");

        this.highlighter = Highlighter.getInstance(debugger);
        this.agent = debugger.getAgent();
        this.selectionManager = debugger.getSelectionManager();
        
        JPanel p = new JPanel(new BorderLayout());
        this.textArea.setEditable(false);
        this.textArea.setContentType("text/html");

        p.add(new JScrollPane(textArea), BorderLayout.CENTER);
        
        getContentPane().add(p);

        this.selectionManager.addListener(this);
        selectionChanged(selectionManager);
    }

    /* (non-Javadoc)
     * @see org.jsoar.debugger.selection.SelectionListener#selectionChanged(org.jsoar.debugger.selection.SelectionManager)
     */
    @Override
    public void selectionChanged(SelectionManager manager)
    {
        getMatchOutput(new ArrayList(manager.getSelection()));
    }
    
    /* (non-Javadoc)
     * @see org.jsoar.debugger.Refreshable#refresh(boolean)
     */
    @Override
    public void refresh(boolean afterInitSoar)
    {
        getMatchOutput(new ArrayList(selectionManager.getSelection()));
    }

    /* (non-Javadoc)
     * @see org.jsoar.debugger.AbstractAdaptableView#getShortcutKey()
     */
    @Override
    public String getShortcutKey()
    {
        return "ctrl M";
    }

    private void getMatchOutput(final List selection)
    {
        Color background = highlighter.getPatterns().getBackground();
        Callable matchCall = () -> safeGetMatchOutput(selection, background);
        CompletionHandler finish = result ->
        {
            if(result != null && result.length() != 0)
            {
                textArea.setText(result);
                textArea.setCaretPosition(0);
            }
        };
        agent.execute(matchCall, SwingCompletionHandler.newInstance(finish));
    }
    
    private Production getProduction(ProductionManager pm, Object o)
    {
        Production p = Adaptables.adapt(o, Production.class);
        if(p != null)
        {
            return p;
        }
        
        return pm.getProduction(o.toString());
    }
    
    private String safeGetMatchOutput(List selection, Color background)
    {
        final StringBuilder b = new StringBuilder();
        b.append("");
        b.append("");
        int count = 0;
        for(Object o : selection)
        {
            final Production p = getProduction(agent.getProductions(), o);
            if(p != null)
            {
                b.append("

" + escape(p.getName()) + "

"); final PartialMatches pm = p.getPartialMatches(); final List entries = pm.getEntries(); if(entries.size() > 0) { formatEntries(b, entries, 0); b.append("
"); final Entry lastEntry = entries.get(entries.size() - 1); final int total = lastEntry.matches; b.append(String.format("%d complete match%s.", total > 0 ? "green" : "red", total, total != 1 ? "es" : "")); } else { b.append("No match info available
"); } count++; } b.append("
"); } b.append(""); return count != 0 ? b.toString() : null; } private String escape(String s) { return s.replace("&", "&").replace("<", "<"); } private void spaces(StringBuilder b, int level) { for(int i = 0; i < level; i++) { b.append("  "); } } private void formatPositiveEntry(StringBuilder b, Entry e, Entry previous) { printEntryLeader(b, e, previous); b.append(""); b.append("" + e.matches + " "); b.append(escape(String.format("%s", e.condition))); b.append(""); } private void formatNegativeEntry(final StringBuilder b, Entry e, int level, Entry previous) { printEntryLeader(b, e, previous); // how about ¬ ?? b.append("-{
"); formatEntries(b, e.negatedSubConditions, level+1); spaces(b, level); b.append("   "); b.append(String.format("} %d", e.matches > 0 ? "green" : "red", e.matches)); } private void printEntryLeader(StringBuilder b, Entry e, Entry previous) { final boolean firstNonMatch = e.matches == 0 && (previous == null || previous.matches > 0); if(firstNonMatch) { b.append("" + escape(">> ") + ""); } else { b.append("   "); } } private void formatEntries(final StringBuilder b, final List entries, int level) { b.append(""); Entry previous = null; int processed = 0; for(Entry e : entries) { spaces(b, level); if(e.negatedSubConditions == null) { formatPositiveEntry(b, e, previous); } else { formatNegativeEntry(b, e, level, previous); } b.append("
"); previous = e; processed++; // Only print up to the first non-match. // TODO: make this configurable if(e.matches == 0) { break; } } if(processed != entries.size()) { final int remaining = entries.size() - processed; b.append(String.format("   ... %d more condition%s ...
", remaining, (remaining != 1 ? "s": ""))); } b.append("
"); } }