package net.certware.argument.sfp.review.wizard; import net.certware.argument.sfp.review.Activator; import net.certware.argument.sfp.review.preferences.PreferenceConstants; import net.certware.argument.sfp.semiFormalProof.Entailment; import net.certware.argument.sfp.semiFormalProof.Proof; import net.certware.argument.sfp.semiFormalProof.SemiFormalProofFactory; import net.certware.argument.sfp.semiFormalProof.Statement; import net.certware.argument.sfp.semiFormalProof.ValidationKind; import net.certware.argument.sfp.util.ProofUtil; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.IFormPart; import org.eclipse.ui.forms.widgets.FormText; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.forms.widgets.TableWrapData; import org.eclipse.ui.forms.widgets.TableWrapLayout; /** * A generic statement details page. * Most logic contained here. Sub-classes add help context. * @author mrb * @since 1.0.3 */ public abstract class ReviewDetailPage extends GenericDetailPage { /** details client */ private Composite premisesClient = null; /** buttons client */ private Composite buttonsClient = null; /** author text */ private Text authorText; /** time stamp text */ private Text timeStampText; /** buttons layout section */ private Section buttonsSection; /** proof valid button */ private Button validButton; /** proof invalid button */ private Button invalidButton; /** proof unknown button */ private Button unknownButton; /** client for inference statements */ private Composite inferenceClient; /** section for inference client */ private Section inferenceSection; /** section for justifications client */ private Section premisesSection; /** section for entailments */ private Section entailmentsSection; /** client for entailment section */ private Composite entailmentsClient; /** section for deduction */ private Section deductionSection; /** client for deduction section */ private Composite deductionClient; /** whether to show premise validity */ private boolean showPremiseValidity = true; /** preference change listener */ private ReviewPropertyChangeListener reviewPropertyChangeListener; /** * Constructor saves the contributions for name search. * @param proof proof to display */ public ReviewDetailPage(Proof proof,TreeViewer viewer, ReviewValidatePage validate, ReviewSetupPage setup) { super(proof,viewer,validate,setup); // TODO add an insert line command to the editor, inserting numbered line and renumbering those following? // TODO fix the save resource on finish } /** * Creates the initial page structure before values available. * @param parent details page of scrolled block */ public void createContents(Composite parent) { // put a table wrap layout onto the scrolled block area for the details pages TableWrapLayout layout = new TableWrapLayout(); layout.topMargin = 5; layout.leftMargin = 5; layout.rightMargin = 5; layout.bottomMargin = 5; layout.numColumns = 1; parent.setLayout(layout); toolkit = mform.getToolkit(); // instructions area Section instructionsSection = toolkit.createSection(parent, Section.DESCRIPTION | Section.TITLE_BAR); instructionsSection.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.FILL_GRAB)); instructionsSection.setText("Statement Validation"); instructionsSection.setDescription("Evaluate the statement's validity according to its logical elements below:"); toolkit.createCompositeSeparator(instructionsSection); Composite instructionsClient = toolkit.createComposite(instructionsSection); TableWrapLayout vcl = new TableWrapLayout(); vcl.numColumns = 1; instructionsClient.setLayout( vcl ); instructionsSection.setClient(instructionsClient); // premises area premisesSection = toolkit.createSection(parent, Section.DESCRIPTION | Section.TITLE_BAR); premisesSection.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.FILL_GRAB)); premisesSection.setText("Premises"); premisesSection.setDescription(""); premisesClient = toolkit.createComposite(premisesSection); TableWrapLayout pcl = new TableWrapLayout(); pcl.numColumns = 3; premisesClient.setLayout( pcl ); premisesSection.setClient(premisesClient); // inference area inferenceSection = toolkit.createSection(parent, Section.DESCRIPTION | Section.TITLE_BAR); inferenceSection.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.FILL_GRAB)); inferenceSection.setText("Inference"); inferenceSection.setDescription(""); inferenceClient = toolkit.createComposite(inferenceSection); TableWrapLayout icl = new TableWrapLayout(); icl.numColumns = 3; inferenceClient.setLayout( icl ); inferenceSection.setClient(inferenceClient); // entailment area entailmentsSection = toolkit.createSection(parent, Section.DESCRIPTION | Section.TITLE_BAR); entailmentsSection.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.FILL_GRAB)); entailmentsSection.setText("Entailments"); entailmentsSection.setDescription(""); entailmentsClient = toolkit.createComposite(entailmentsSection); TableWrapLayout ecl = new TableWrapLayout(); ecl.numColumns = 3; entailmentsClient.setLayout( ecl ); entailmentsSection.setClient(entailmentsClient); // deduction area deductionSection = toolkit.createSection(parent, Section.DESCRIPTION | Section.TITLE_BAR); deductionSection.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.FILL_GRAB)); deductionSection.setText("Deduction"); deductionSection.setDescription(""); deductionClient = toolkit.createComposite(deductionSection); TableWrapLayout dcl = new TableWrapLayout(); dcl.numColumns = 3; deductionClient.setLayout( dcl ); deductionSection.setClient(deductionClient); // buttons area buttonsSection = toolkit.createSection(parent, Section.DESCRIPTION | Section.TITLE_BAR ); // Section.NO_TITLE ); buttonsSection.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.FILL_GRAB )); buttonsSection.setText("Validation"); buttonsSection.setDescription(""); buttonsClient = toolkit.createComposite(buttonsSection); TableWrapLayout bcl = new TableWrapLayout(); bcl.makeColumnsEqualWidth = false; bcl.numColumns = 1; buttonsClient.setLayout(bcl); buttonsSection.setClient(buttonsClient); // populate the sections with latest selections populatePremises(); populateInference(); populateEntailments(); populateDeduction(); populateButtons(); parent.setSize(300, 100); // listen to preference changes reviewPropertyChangeListener = new ReviewPropertyChangeListener(); Activator.getDefault().getPreferenceStore().addPropertyChangeListener(reviewPropertyChangeListener); Boolean b = Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.P_SHOW_PREMISE_VALIDITY); if ( b != null ) setPremiseValidity(b.booleanValue()); } /** * Dispose of resources and listeners. */ @Override public void dispose() { if ( reviewPropertyChangeListener != null ) { Activator.getDefault().getPreferenceStore().removePropertyChangeListener(reviewPropertyChangeListener); } super.dispose(); } /** * Update the validation element of the selected statement. * Adds validation kind, author, and time stamp to the validation entry. * Creates the validation element if it is missing. * @param kind validation kind */ public void updateValidation( ValidationKind kind ) { if ( statement != null ) { if ( statement.getValidation() == null ) { statement.setValidation( SemiFormalProofFactory.eINSTANCE.createValidation() ); } // update the model statement.getValidation().setState( kind ); statement.getValidation().setAuthor( addQuotes( setupPage.getAuthor()) ); statement.getValidation().setTimeStamp( addQuotes( setupPage.getTimeStamp()) ); // update the details page to show the new author and time stamp authorText.setText( removeQuotes( setupPage.getAuthor() ) ); timeStampText.setText( removeQuotes( setupPage.getTimeStamp() ) ); // refresh labels on master and details pages update(); viewer.refresh(); } } /** * Get the author stored in the statement's validation record. * @return statement validation author */ public String getOriginalAuthor() { if ( statement != null && statement.getValidation() != null ) { return statement.getValidation().getAuthor(); } return ""; } /** * Get the time stamp stored in the statement's validation record. * @return statement validation time stamp */ public String getOriginalTimeStamp() { if ( statement != null && statement.getValidation() != null ) { return statement.getValidation().getTimeStamp(); } return ""; } /** * Populate the premise rows. */ private void populatePremises() { // show only the selected statement's justifications if ( statement != null ) { // find statement justifications, returned as list EList<Statement> premises = ProofUtil.getStatementPremises(proof, statement); if ( premises.size() > 0 ) { populateHeader(premisesClient); // show justifiers for ( Statement s : premises ) { displayStatementLine(premisesClient,s); } } // update section description switch( premises.size() ) { case 0: premisesSection.setDescription("No premises given."); premisesSection.setExpanded(false); break; case 1: premisesSection.setDescription("Inference Premise:"); premisesSection.setExpanded(true); break; default: premisesSection.setDescription("Inference Premises:"); premisesSection.setExpanded(true); break; } } else { //premisesSection.setDescription(""); clearClient(premisesClient); premisesSection.setExpanded(false); } } /** * Populate the entailment rows. */ private void populateEntailments() { // show only the selected statement's entailments if ( statement != null ) { // find statement entailments, returned as list EList<Entailment> entailments = ProofUtil.getStatementEntailments(statement); if ( entailments.size() > 0 ) { populateHeader(entailmentsClient); // show entailments boolean firstPass = true; for ( Entailment e : entailments ) { // separator if ( firstPass == false ) { populateHeader(entailmentsClient); } // entailment heads EList<String> heads = ProofUtil.getHeadList(e); for ( String head : heads ) { Statement es = ProofUtil.findStatement(proof, head); if ( es != null ) { displayStatementLine(entailmentsClient, es); } } // entailment tail Statement ts = ProofUtil.findStatement(proof, e.getTail()); displayEntailmentLine(entailmentsClient,ts,heads.size()>1); firstPass = false; } } // update section description switch( entailments.size() ) { case 0: clearClient(entailmentsClient); entailmentsSection.setExpanded(false); break; case 1: entailmentsSection.setDescription("Deduction entailment:"); entailmentsSection.setExpanded(true); break; default: entailmentsSection.setDescription("Deduction entailments:"); entailmentsSection.setExpanded(true); break; } } else { clearClient(entailmentsClient); entailmentsSection.setExpanded(false); } } /** * Populate the inference row. */ private void populateInference() { if ( statement != null ) { EList<Statement> premises = ProofUtil.getStatementPremises(proof, statement); EList<Entailment> entailments = ProofUtil.getStatementEntailments(statement); if ( premises.isEmpty() ) { if ( entailments.isEmpty() == false ) { inferenceSection.setDescription("Deduction:"); } else if ( ProofUtil.statementIsEpsilon(statement)) { inferenceSection.setDescription("Empty set"); } else if ( ProofUtil.statementIsHypothesis(statement)) { inferenceSection.setDescription("Hypothesis:"); } else { inferenceSection.setDescription("Definition:"); } } else { inferenceSection.setDescription("Inference given the above premises:"); } populateHeader(inferenceClient); displayStatementLine(inferenceClient,statement); inferenceSection.setExpanded(true); } else { inferenceSection.setExpanded(false); } } /** * Populate the deduction row. */ private void populateDeduction() { if ( statement != null ) { EList<Entailment> entailments = ProofUtil.getStatementEntailments(statement); if ( entailments.isEmpty() ) { clearClient(deductionClient); deductionSection.setExpanded(false); } else { deductionSection.setDescription("Deduction given the above entailments:"); deductionSection.setExpanded(true); } populateHeader(deductionClient); displayStatementLine(deductionClient,statement); } else { deductionSection.setExpanded(false); } } /** * Create the buttons row and validation reference row on their form clients. * Adds button listeners to update validation and button enabled states. */ private void populateButtons() { // buttons composite row Composite buttonsComposite = toolkit.createComposite(buttonsClient); TableWrapLayout buttonsCompositeLayout = new TableWrapLayout(); buttonsCompositeLayout.makeColumnsEqualWidth = true; buttonsCompositeLayout.numColumns = 3; buttonsComposite.setLayout(buttonsCompositeLayout); // author composite row Composite authorComposite = toolkit.createComposite(buttonsClient); TableWrapLayout authorCompositeLayout = new TableWrapLayout(); authorCompositeLayout.makeColumnsEqualWidth = false; authorCompositeLayout.numColumns = 4; authorComposite.setLayout(authorCompositeLayout); // buttons on the buttons client validButton = toolkit.createButton(buttonsComposite, getItemValidLabel(), SWT.PUSH); validButton.setLayoutData(new TableWrapData(TableWrapData.LEFT,TableWrapData.TOP)); validButton.setImage( imageRegistry.get( Activator.REVIEW_VALID_IMAGE )); validButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { updateValidation(ValidationKind.VALID); updateButtons(); } }); invalidButton = toolkit.createButton(buttonsComposite, getItemInvalidLabel(), SWT.PUSH); invalidButton.setLayoutData(new TableWrapData(TableWrapData.LEFT,TableWrapData.TOP)); invalidButton.setImage( imageRegistry.get( Activator.REVIEW_INVALID_IMAGE )); invalidButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { updateValidation(ValidationKind.INVALID); updateButtons(); } }); unknownButton = toolkit.createButton(buttonsComposite, getItemUnknownLabel(), SWT.PUSH); unknownButton.setLayoutData(new TableWrapData(TableWrapData.LEFT,TableWrapData.TOP)); unknownButton.setImage( imageRegistry.get( Activator.REVIEW_UNKNOWN_IMAGE )); unknownButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { updateValidation(ValidationKind.UNKNOWN); updateButtons(); } }); // add labels made from validation setup fields toolkit.createLabel(authorComposite,"Previous Author"); authorText = toolkit.createText(authorComposite,removeQuotes(getOriginalAuthor())); authorText.setEditable(false); toolkit.createLabel(authorComposite,"Time Stamp"); timeStampText = toolkit.createText(authorComposite, removeQuotes(getOriginalTimeStamp())); timeStampText.setEditable(false); // update description if ( statement != null ) { buttonsSection.setDescription("Validate the statement:"); } // set enabled states based on statement selection updateButtons(); } /** * Update the enable states of the buttons based on validation kind. * Adds the validation object if not present in statement. */ private void updateButtons() { if ( statement == null ) return; if ( statement.getValidation() == null ) { statement.setValidation( SemiFormalProofFactory.eINSTANCE.createValidation() ); } if ( statement.getValidation().getState() == ValidationKind.INVALID ) { invalidButton.setEnabled(false); validButton.setEnabled(true); unknownButton.setEnabled(true); } if ( statement.getValidation().getState() == ValidationKind.VALID ) { invalidButton.setEnabled(true); validButton.setEnabled(false); unknownButton.setEnabled(true); } if ( statement.getValidation().getState() == ValidationKind.UNKNOWN ) { invalidButton.setEnabled(true); validButton.setEnabled(true); unknownButton.setEnabled(false); } // if any predecessors invalid, disable the valid button if ( ProofUtil.justificationsValid(proof,statement) == false ) { validButton.setEnabled(false); } markDirty(); validatePage.setPageComplete(true); } /** * Create the widgets for an entailment line. * @param client client on which to add children * @param s statement to display * @param plural whether there is more than one head item */ private void displayEntailmentLine(Composite client, Statement s, boolean plural) { // first row, show entailment signal Label c1 = toolkit.createLabel(client,""); c1.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.TOP)); c1.setImage( imageRegistry.get( Activator.REVIEW_ENTAILMENT_IMAGE ) ); Label c2 = toolkit.createLabel(client, plural ? "Imply" : "Implies"); c2.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.TOP)); Label c3 = toolkit.createLabel(client,""); c3.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.TOP)); // next row, display the statement content displayStatementLine(client,s); } /** * Create the widgets for a statement line. * @param client client on which to add children * @param s statement to display */ private void displayStatementLine(Composite client, Statement s) { Label idValue = toolkit.createLabel(client,s.getId()); idValue.setFont(normalFont); idValue.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.TOP)); if ( this.showPremiseValidity ) { idValue.setImage( getImageForStatement(s) ); } else { idValue.setImage(null); idValue.setText(" "); //$NON-NLS-1$ } idValue.setToolTipText( s.getId() ); FormText bodyValue = toolkit.createFormText(client, false); bodyValue.setWhitespaceNormalized(true); bodyValue.setText( removeQuotes(s.getStatement()) , false, false); bodyValue.setFont(normalFont); bodyValue.setLayoutData(new TableWrapData(TableWrapData.FILL, TableWrapData.TOP)); bodyValue.setToolTipText( s.getId() + ' ' + s.getStatement() ); Label commentValue = toolkit.createLabel(client, ProofUtil.getStatementComment(s)); commentValue.setFont(normalFont); commentValue.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.TOP)); commentValue.setToolTipText( commentValue.getText() ); } /** * Refreshes the page with new selection data. */ protected void update() { if ( proof == null ) return; // clear previous data clearClient(premisesClient); clearClient(inferenceClient); clearClient(entailmentsClient); clearClient(deductionClient); clearClient(buttonsClient); // reload the clients // populateHeader(); populatePremises(); populateInference(); populateEntailments(); populateDeduction(); populateButtons(); // layout clients premisesSection.getParent().layout(true); premisesClient.getParent().layout(true, true); inferenceSection.getParent().layout(true, true); inferenceClient.getParent().layout(true, true); entailmentsSection.getParent().layout(true); entailmentsClient.getParent().layout(true,true); deductionSection.getParent().layout(true); deductionClient.getParent().layout(true,true); buttonsSection.getParent().layout(true); buttonsClient.getParent().layout(true, true); // layout form mform.reflow(true); setHelpContext(inferenceClient); // TODO is this right? } /** * Sets the help context ID. * @param c control for help system reference */ // abstract void setHelpContext(Control c); /** * Sets the form input object to the given value. * Expects an Example object. * @return always returns false */ public boolean setFormInput(Object input) { statement = (Statement)input; return false; } /** * Sets the object to display as a result of master selection. * Listener mapped to objects of the statement type. * Uses the first selected item. Calls <code>update()</code>. */ public void selectionChanged(IFormPart part, ISelection selection) { IStructuredSelection ssel = (IStructuredSelection)selection; if ( ssel == null || ssel.getFirstElement() == null ) return; // check selection type if ( ssel.getFirstElement() instanceof Proof ) { proof = (Proof)ssel.getFirstElement(); } else if ( ssel.getFirstElement() instanceof Statement) { statement = (Statement)ssel.getFirstElement(); proof = (Proof) EcoreUtil.getRootContainer(statement); } update(); } /** * Sets the premise validity flag for review page. * @param value new value */ private void setPremiseValidity(boolean value) { this.showPremiseValidity = value; } /** * Preference change listener. */ class ReviewPropertyChangeListener implements IPropertyChangeListener { /** * Captures changes and refreshes display if necessary. */ @Override public void propertyChange(PropertyChangeEvent event) { boolean needUpdate = false; if ( event.getProperty().equals(PreferenceConstants.P_SHOW_PREMISE_VALIDITY )) { Boolean v = (Boolean)event.getNewValue(); if ( showPremiseValidity != v.booleanValue() ) { setPremiseValidity(v.booleanValue()); needUpdate = true; } } // refresh once for all preference changes if ( needUpdate ) update(); } } }