Changed Report to a message tree, recursively formatted
This commit is contained in:
parent
aa11d54396
commit
c5dc2669cf
3 changed files with 129 additions and 99 deletions
|
@ -27,7 +27,6 @@ import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import net.vhati.modmanager.core.Report;
|
import net.vhati.modmanager.core.Report;
|
||||||
import net.vhati.modmanager.core.Report.ReportFormatter;
|
|
||||||
import net.vhati.modmanager.core.Report.ReportMessage;
|
import net.vhati.modmanager.core.Report.ReportMessage;
|
||||||
|
|
||||||
import ar.com.hjg.pngj.PngReader;
|
import ar.com.hjg.pngj.PngReader;
|
||||||
|
@ -199,10 +198,8 @@ public class ModUtilities {
|
||||||
* Checks a mod file for common problems.
|
* Checks a mod file for common problems.
|
||||||
*
|
*
|
||||||
* @param modFile an *.ftl file to check
|
* @param modFile an *.ftl file to check
|
||||||
* @param formatter custom message decoration/indention, or null
|
|
||||||
*/
|
*/
|
||||||
public static Report validateModFile( File modFile, ReportFormatter formatter ) {
|
public static Report validateModFile( File modFile ) {
|
||||||
if ( formatter == null ) formatter = new ReportFormatter();
|
|
||||||
|
|
||||||
List<ReportMessage> messages = new ArrayList<ReportMessage>();
|
List<ReportMessage> messages = new ArrayList<ReportMessage>();
|
||||||
List<ReportMessage> pendingMsgs = new ArrayList<ReportMessage>();
|
List<ReportMessage> pendingMsgs = new ArrayList<ReportMessage>();
|
||||||
|
@ -392,16 +389,22 @@ public class ModUtilities {
|
||||||
if ( isXML ) {
|
if ( isXML ) {
|
||||||
if ( isXMLAppend ) seenAppend = true;
|
if ( isXMLAppend ) seenAppend = true;
|
||||||
|
|
||||||
Report xmlReport = validateModXML( decodeResult.text, formatter );
|
Report xmlReport = validateModXML( decodeResult.text );
|
||||||
|
|
||||||
|
if ( xmlReport.messages.size() > 0 ) {
|
||||||
|
List<ReportMessage> condensedList = new ArrayList<ReportMessage>();
|
||||||
|
ReportMessage prevMessage = null;
|
||||||
|
for ( ReportMessage message : xmlReport.messages ) {
|
||||||
|
if ( !message.equals(prevMessage) ) {
|
||||||
|
condensedList.add( message );
|
||||||
|
prevMessage = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( xmlReport.text.length() > 0 ) {
|
|
||||||
pendingMsgs.add( new ReportMessage(
|
pendingMsgs.add( new ReportMessage(
|
||||||
ReportMessage.WARNING_SUBSECTION,
|
ReportMessage.WARNING_SUBSECTION,
|
||||||
"XML Syntax Issues:"
|
"XML Syntax Issues:",
|
||||||
) );
|
condensedList
|
||||||
pendingMsgs.add( new ReportMessage(
|
|
||||||
ReportMessage.NESTED_BLOCK,
|
|
||||||
xmlReport.text
|
|
||||||
) );
|
) );
|
||||||
}
|
}
|
||||||
if ( xmlReport.outcome == false )
|
if ( xmlReport.outcome == false )
|
||||||
|
@ -457,9 +460,7 @@ public class ModUtilities {
|
||||||
String.format( "%s:", modFile.getName() )
|
String.format( "%s:", modFile.getName() )
|
||||||
) );
|
) );
|
||||||
|
|
||||||
StringBuilder resultBuf = new StringBuilder();
|
return new Report( messages, modValid );
|
||||||
formatter.format( messages, resultBuf );
|
|
||||||
return new Report( resultBuf, modValid );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -473,10 +474,8 @@ public class ModUtilities {
|
||||||
* first typo it sees. :/
|
* first typo it sees. :/
|
||||||
*
|
*
|
||||||
* @param text unparsed xml
|
* @param text unparsed xml
|
||||||
* @param formatter custom message decoration/indention, or null
|
|
||||||
*/
|
*/
|
||||||
public static Report validateModXML( String text, ReportFormatter formatter ) {
|
public static Report validateModXML( String text ) {
|
||||||
if ( formatter == null ) formatter = new ReportFormatter();
|
|
||||||
|
|
||||||
List<ReportMessage> messages = new ArrayList<ReportMessage>();
|
List<ReportMessage> messages = new ArrayList<ReportMessage>();
|
||||||
boolean xmlValid = true;
|
boolean xmlValid = true;
|
||||||
|
@ -711,17 +710,7 @@ public class ModUtilities {
|
||||||
xmlValid = false;
|
xmlValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder resultBuf = new StringBuilder();
|
return new Report( messages, xmlValid );
|
||||||
|
|
||||||
ReportMessage prevMessage = null;
|
|
||||||
for ( ReportMessage message : messages ) {
|
|
||||||
if ( message.equals(prevMessage) ) continue;
|
|
||||||
|
|
||||||
formatter.format( message, resultBuf );
|
|
||||||
prevMessage = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Report( resultBuf, xmlValid );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,37 +1,35 @@
|
||||||
package net.vhati.modmanager.core;
|
package net.vhati.modmanager.core;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A human-readable block of text, with a boolean outcome.
|
* A list of messages, with a boolean outcome.
|
||||||
*/
|
*/
|
||||||
public class Report {
|
public class Report {
|
||||||
public final CharSequence text;
|
public final List<ReportMessage> messages;
|
||||||
public final boolean outcome;
|
public final boolean outcome;
|
||||||
|
|
||||||
public Report( CharSequence text, boolean outcome ) {
|
public Report( List<ReportMessage> messages, boolean outcome ) {
|
||||||
this.text = text;
|
|
||||||
this.outcome = outcome;
|
this.outcome = outcome;
|
||||||
|
|
||||||
|
List<ReportMessage> tmpList = new ArrayList<ReportMessage>( messages );
|
||||||
|
this.messages = Collections.unmodifiableList( tmpList );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats ReportMessages to include in buffered reports.
|
* Formats ReportMessages.
|
||||||
*
|
*
|
||||||
* Symbols are prepended to indicate type.
|
* Symbols are prepended to indicate type.
|
||||||
*
|
*
|
||||||
* Methods can accept a formatter as an argument,
|
* Nested messages are indented.
|
||||||
* internally accumulate messages, format them,
|
|
||||||
* and return an Appendable CharSequence.
|
|
||||||
*
|
|
||||||
* To nest reports, that buffer can be intented
|
|
||||||
* and appended to another buffer; or it can be
|
|
||||||
* wrapped in a NESTED_BLOCK message of its own.
|
|
||||||
*
|
*
|
||||||
* The Appendable interface claims to throw
|
* The Appendable interface claims to throw
|
||||||
* IOException, but StringBuffer and StringBuilder
|
* IOException, but StringBuffer and StringBuilder
|
||||||
|
@ -55,31 +53,56 @@ public class Report {
|
||||||
case ReportMessage.SUBSECTION: return "> ";
|
case ReportMessage.SUBSECTION: return "> ";
|
||||||
case ReportMessage.WARNING_SUBSECTION: return "~ ";
|
case ReportMessage.WARNING_SUBSECTION: return "~ ";
|
||||||
case ReportMessage.ERROR_SUBSECTION: return "! ";
|
case ReportMessage.ERROR_SUBSECTION: return "! ";
|
||||||
case ReportMessage.NESTED_BLOCK: return "";
|
|
||||||
default: return getIndent();
|
default: return getIndent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void format( List<ReportMessage> messages, Appendable buf ) throws IOException {
|
/**
|
||||||
for ( ReportMessage message : messages )
|
* Returns the given CharSequence, or a new one decorated for the type.
|
||||||
format( message, buf );
|
*/
|
||||||
|
public CharSequence getDecoratedText( int messageType, CharSequence text ) {
|
||||||
|
// Sections get underlined.
|
||||||
|
if ( messageType == ReportMessage.SECTION ) {
|
||||||
|
StringBuilder buf = new StringBuilder( text.length()*2+1 );
|
||||||
|
buf.append( text ).append( "\n" );
|
||||||
|
|
||||||
|
buf.append( getPrefix( messageType ).replaceAll( "\\S", " " ) );
|
||||||
|
for ( int i=0; i < text.length(); i++ )
|
||||||
|
buf.append( "-" );
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void format( ReportMessage message, Appendable buf ) throws IOException {
|
/**
|
||||||
if ( message.type == ReportMessage.NESTED_BLOCK ) {
|
* Formats a list of messages.
|
||||||
// Already formatted this once, indent it instead.
|
*
|
||||||
|
* Leading newlines in the first message will be omitted.
|
||||||
// Skip leading newlines
|
*/
|
||||||
int start = 0;
|
public void format( List<ReportMessage> messages, Appendable buf, int indentCount ) throws IOException {
|
||||||
while ( start < message.text.length() && message.text.charAt(start) == '\n' )
|
for ( int i=0; i < messages.size(); i++ ) {
|
||||||
start++;
|
ReportMessage message = messages.get( i );
|
||||||
if ( start > 0 )
|
if ( i == 0 ) {
|
||||||
indent( message.text.subSequence( start, message.text.length() ), buf );
|
// Skip leading newlines in first message.
|
||||||
else
|
int start = 0;
|
||||||
indent( message.text, buf );
|
while ( start < message.text.length() && message.text.charAt(start) == '\n' )
|
||||||
return;
|
start++;
|
||||||
|
if ( start > 0 ) {
|
||||||
|
// Create a substitute message without them.
|
||||||
|
CharSequence newText = message.text.subSequence( start, message.text.length() );
|
||||||
|
message = new ReportMessage( message.type, newText, message.nestedMessages );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format( message, buf, indentCount );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indents and decorates a message, then formats any nested messages.
|
||||||
|
*/
|
||||||
|
public void format( ReportMessage message, Appendable buf, int indentCount ) throws IOException {
|
||||||
// Subsections get an extra linebreak above them.
|
// Subsections get an extra linebreak above them.
|
||||||
switch ( message.type ) {
|
switch ( message.type ) {
|
||||||
case ReportMessage.SUBSECTION:
|
case ReportMessage.SUBSECTION:
|
||||||
|
@ -90,69 +113,61 @@ public class Report {
|
||||||
// Not a subsection.
|
// Not a subsection.
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.append( getPrefix( message.type ) );
|
CharSequence seq = getDecoratedText( message.type, message.text );
|
||||||
buf.append( message.text );
|
|
||||||
buf.append( "\n" );
|
|
||||||
|
|
||||||
// Sections get underlined.
|
// Indent the first line.
|
||||||
if ( message.type == ReportMessage.SECTION ) {
|
for ( int i=0; i < indentCount; i++ )
|
||||||
buf.append( getIndent() );
|
buf.append( getIndent() );
|
||||||
for ( int i=0; i < message.text.length(); i++ )
|
buf.append( getPrefix( message.type ) );
|
||||||
buf.append( "-" );
|
|
||||||
buf.append( "\n" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void indent( CharSequence src, Appendable dst ) throws IOException {
|
// Indent multi-line message text.
|
||||||
Matcher m = breakPtn.matcher( src );
|
Matcher m = breakPtn.matcher( seq );
|
||||||
int lastEnd = 0;
|
int lastEnd = 0;
|
||||||
while ( m.find() ) {
|
while ( m.find() ) {
|
||||||
if ( m.start() - lastEnd > 0 )
|
if ( m.start() - lastEnd > 0 )
|
||||||
dst.append( src.subSequence( lastEnd, m.start() ) );
|
buf.append( seq.subSequence( lastEnd, m.start() ) );
|
||||||
|
|
||||||
if ( m.group(1).length() > 0 ) // Didn't match beginning (^).
|
if ( m.group(1).length() > 0 ) {
|
||||||
dst.append( "\n" );
|
// At \n, instead of 0-length beginning (^).
|
||||||
dst.append( getIndent() );
|
buf.append( "\n" );
|
||||||
|
for ( int i=0; i < indentCount; i++ ) {
|
||||||
|
buf.append( getIndent() );
|
||||||
|
}
|
||||||
|
}
|
||||||
lastEnd = m.end();
|
lastEnd = m.end();
|
||||||
}
|
}
|
||||||
int srcLen = src.length();
|
int srcLen = seq.length();
|
||||||
if ( lastEnd < srcLen )
|
if ( lastEnd < srcLen )
|
||||||
dst.append( src.subSequence( lastEnd, srcLen ) );
|
buf.append( seq.subSequence( lastEnd, srcLen ) );
|
||||||
|
|
||||||
|
buf.append( "\n" );
|
||||||
|
|
||||||
|
if ( message.nestedMessages != null ) {
|
||||||
|
format( message.nestedMessages, buf, indentCount+1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exception-swallowing wrapper. */
|
/** Exception-swallowing wrapper. */
|
||||||
public void format( List<ReportMessage> messages, StringBuffer buf ) {
|
public void format( List<ReportMessage> messages, StringBuffer buf, int indentCount ) {
|
||||||
try { format( messages, (Appendable)buf ); }
|
try { format( messages, (Appendable)buf, indentCount ); }
|
||||||
catch( IOException e ) {}
|
catch( IOException e ) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exception-swallowing wrapper. */
|
/** Exception-swallowing wrapper. */
|
||||||
public void format( List<ReportMessage> messages, StringBuilder buf ) {
|
public void format( List<ReportMessage> messages, StringBuilder buf, int indentCount ) {
|
||||||
try { format( messages, (Appendable)buf ); }
|
try { format( messages, (Appendable)buf, indentCount ); }
|
||||||
catch( IOException e ) {}
|
catch( IOException e ) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exception-swallowing wrapper. */
|
/** Exception-swallowing wrapper. */
|
||||||
public void format( ReportMessage message, StringBuffer buf ) {
|
public void format( ReportMessage message, StringBuffer buf, int indentCount ) {
|
||||||
try { format( message, (Appendable)buf ); }
|
try { format( message, (Appendable)buf, indentCount ); }
|
||||||
catch( IOException e ) {}
|
catch( IOException e ) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exception-swallowing wrapper. */
|
/** Exception-swallowing wrapper. */
|
||||||
public void format( ReportMessage message, StringBuilder buf ) {
|
public void format( ReportMessage message, StringBuilder buf, int indentCount ) {
|
||||||
try { format( message, (Appendable)buf ); }
|
try { format( message, (Appendable)buf, indentCount ); }
|
||||||
catch( IOException e ) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Exception-swallowing wrapper. */
|
|
||||||
public void indent( CharSequence src, StringBuffer dst ) {
|
|
||||||
try { indent( src, (Appendable)dst ); }
|
|
||||||
catch( IOException e ) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Exception-swallowing wrapper. */
|
|
||||||
public void indent( CharSequence src, StringBuilder dst ) {
|
|
||||||
try { indent( src, (Appendable)dst ); }
|
|
||||||
catch( IOException e ) {}
|
catch( IOException e ) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,14 +189,20 @@ public class Report {
|
||||||
public static final int SUBSECTION = 5;
|
public static final int SUBSECTION = 5;
|
||||||
public static final int WARNING_SUBSECTION = 6;
|
public static final int WARNING_SUBSECTION = 6;
|
||||||
public static final int ERROR_SUBSECTION = 7;
|
public static final int ERROR_SUBSECTION = 7;
|
||||||
public static final int NESTED_BLOCK = 8;
|
|
||||||
|
|
||||||
public final int type;
|
public final int type;
|
||||||
public final CharSequence text;
|
public final CharSequence text;
|
||||||
|
public final List<ReportMessage> nestedMessages;
|
||||||
|
|
||||||
public ReportMessage( int type, CharSequence text ) {
|
public ReportMessage( int type, CharSequence text ) {
|
||||||
|
this( type, text, new ArrayList() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReportMessage( int type, CharSequence text, List<ReportMessage> nestedMessages ) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
List<ReportMessage> tmpList = new ArrayList<ReportMessage>( nestedMessages );
|
||||||
|
this.nestedMessages = Collections.unmodifiableList( tmpList );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -190,16 +211,33 @@ public class Report {
|
||||||
if ( o == this ) return true;
|
if ( o == this ) return true;
|
||||||
if ( o instanceof ReportMessage == false ) return false;
|
if ( o instanceof ReportMessage == false ) return false;
|
||||||
ReportMessage other = (ReportMessage)o;
|
ReportMessage other = (ReportMessage)o;
|
||||||
return ( this.type == other.type && this.text.equals(other.text) );
|
if ( this.type != other.type ) return false;
|
||||||
|
if ( this.text.equals(other.text) ) return false;
|
||||||
|
|
||||||
|
if ( this.nestedMessages == null ) {
|
||||||
|
if ( other.nestedMessages != null )
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if ( !this.nestedMessages.equals( other.nestedMessages ) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = 236;
|
int result = 236;
|
||||||
int salt = 778;
|
int salt = 778;
|
||||||
|
int nullCode = 99;
|
||||||
|
|
||||||
result = salt * result + this.type;
|
result = salt * result + this.type;
|
||||||
result = salt * result + text.hashCode();
|
result = salt * result + text.hashCode();
|
||||||
|
|
||||||
|
if ( this.nestedMessages != null )
|
||||||
|
result = salt * result + this.nestedMessages.hashCode();
|
||||||
|
else
|
||||||
|
result = salt * result + nullCode;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ import net.vhati.modmanager.core.ModPatchThread;
|
||||||
import net.vhati.modmanager.core.ModPatchThread.BackedUpDat;
|
import net.vhati.modmanager.core.ModPatchThread.BackedUpDat;
|
||||||
import net.vhati.modmanager.core.ModUtilities;
|
import net.vhati.modmanager.core.ModUtilities;
|
||||||
import net.vhati.modmanager.core.Report;
|
import net.vhati.modmanager.core.Report;
|
||||||
|
import net.vhati.modmanager.core.Report.ReportFormatter;
|
||||||
import net.vhati.modmanager.json.GrognakCatalogFetcher;
|
import net.vhati.modmanager.json.GrognakCatalogFetcher;
|
||||||
import net.vhati.modmanager.json.JacksonGrognakCatalogReader;
|
import net.vhati.modmanager.json.JacksonGrognakCatalogReader;
|
||||||
import net.vhati.modmanager.ui.ChecklistTableModel;
|
import net.vhati.modmanager.ui.ChecklistTableModel;
|
||||||
|
@ -556,8 +557,10 @@ public class ManagerFrame extends JFrame implements ActionListener, HashObserver
|
||||||
if ( !localModsTableModel.isSelected(i) ) continue;
|
if ( !localModsTableModel.isSelected(i) ) continue;
|
||||||
|
|
||||||
ModFileInfo modFileInfo = localModsTableModel.getItem( i );
|
ModFileInfo modFileInfo = localModsTableModel.getItem( i );
|
||||||
Report validateReport = ModUtilities.validateModFile( modFileInfo.getFile(), null );
|
Report validateReport = ModUtilities.validateModFile( modFileInfo.getFile() );
|
||||||
resultBuf.append( validateReport.text );
|
|
||||||
|
ReportFormatter formatter = new ReportFormatter();
|
||||||
|
formatter.format( validateReport.messages, resultBuf, 0 );
|
||||||
resultBuf.append( "\n" );
|
resultBuf.append( "\n" );
|
||||||
|
|
||||||
if ( validateReport.outcome == false ) anyInvalid = true;
|
if ( validateReport.outcome == false ) anyInvalid = true;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue