package net.vhati.modmanager.ui;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.event.MouseEvent;
import java.net.URI;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.event.MouseInputAdapter;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import net.vhati.modmanager.ui.Statusbar;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ModInfoArea extends JScrollPane {
private static final Logger log = LogManager.getLogger(ModInfoArea.class);
private static final String STYLE_REGULAR = "regular";
private static final String STYLE_HYPERLINK = "hyperlink";
private static final String STYLE_TITLE = "title";
private static final String ATTR_HYPERLINK_TARGET = "hyperlink-target";
public static Color COLOR_HYPER = Color.BLUE;
public static final StyleContext DEFAULT_STYLES = ModInfoArea.getDefaultStyleContext();
private Statusbar statusbar = null;
private JTextPane textPane;
private StyledDocument doc;
private boolean browseWorks;
public ModInfoArea() {
this( DEFAULT_STYLES );
}
public ModInfoArea( StyleContext styleContext ) {
super();
textPane = new JTextPane();
textPane.setEditable( false );
doc = new DefaultStyledDocument(styleContext);
textPane.setStyledDocument(doc);
Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
if ( desktop != null && desktop.isSupported(Desktop.Action.BROWSE) ) {
browseWorks = true;
}
MouseInputAdapter hyperlinkListener = new MouseInputAdapter() {
private Cursor defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
private Cursor linkCursor = new Cursor(Cursor.HAND_CURSOR);
private boolean wasOverLink = false;
@Override
public void mouseClicked( MouseEvent e ) {
AttributeSet tmpAttr = doc.getCharacterElement( textPane.viewToModel(e.getPoint()) ).getAttributes();
Object targetObj = tmpAttr.getAttribute( ATTR_HYPERLINK_TARGET );
if ( targetObj != null ) {
Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
if ( desktop != null && desktop.isSupported(Desktop.Action.BROWSE) ) {
try {
desktop.browse( new URI(targetObj.toString()) );
}
catch ( Exception f ) {
log.error( "Error browsing clicked url: "+ targetObj.toString(), f );
}
}
}
}
@Override
public void mouseMoved( MouseEvent e ) {
AttributeSet tmpAttr = doc.getCharacterElement( textPane.viewToModel(e.getPoint()) ).getAttributes();
Object targetObj = tmpAttr.getAttribute( ATTR_HYPERLINK_TARGET );
if ( targetObj != null ) {
textPane.setCursor( linkCursor );
if ( statusbar != null )
statusbar.setStatusText( targetObj.toString() );
wasOverLink = true;
}
else {
if ( wasOverLink ) {
textPane.setCursor( defaultCursor );
if ( statusbar != null )
statusbar.setStatusText( "" );
}
wasOverLink = false;
}
}
};
textPane.addMouseListener( hyperlinkListener );
textPane.addMouseMotionListener( hyperlinkListener );
textPane.addMouseListener( new ClipboardMenuMouseListener() );
this.setViewportView( textPane );
}
public void setDescription( String title, String body ) {
setDescription( title, null, null, null, body );
}
public void setDescription( String title, String author, String version, String url, String body ) {
Style regularStyle = doc.getStyle( STYLE_REGULAR );
try {
doc.remove( 0, doc.getLength() );
doc.insertString( doc.getLength(), title +"\n", doc.getStyle( STYLE_TITLE ) );
boolean first = true;
if ( author != null ) {
doc.insertString( doc.getLength(), String.format("%sby %s", (first ? "" : " "), author), regularStyle );
first = false;
}
if ( version != null ) {
doc.insertString( doc.getLength(), String.format("%s(version %s)", (first ? "" : " "), version), regularStyle );
first = false;
}
if ( !first ) {
doc.insertString( doc.getLength(), "\n", regularStyle );
}
if ( url != null ) {
doc.insertString( doc.getLength(), "Website: ", regularStyle );
if ( browseWorks && url.matches("^(?:https?|ftp)://.*") ) {
SimpleAttributeSet tmpAttr = new SimpleAttributeSet( doc.getStyle( STYLE_HYPERLINK ) );
tmpAttr.addAttribute( ATTR_HYPERLINK_TARGET, url );
doc.insertString( doc.getLength(), "Link", tmpAttr );
} else {
doc.insertString( doc.getLength(), url, regularStyle );
}
doc.insertString( doc.getLength(), "\n", regularStyle );
}
doc.insertString( doc.getLength(), "\n", regularStyle );
if ( body != null ) {
doc.insertString( doc.getLength(), body, regularStyle );
}
}
catch ( BadLocationException e) {
log.error( "Error filling info text area.", e );
}
textPane.setCaretPosition(0);
}
public void setCaretPosition( int n ) {
textPane.setCaretPosition( n );
}
public void clear() {
try {
doc.remove( 0, doc.getLength() );
}
catch ( BadLocationException e) {
log.error( "Error clearing info text area.", e );
}
}
public void appendTitleText( String s ) throws BadLocationException {
doc.insertString( doc.getLength(), s, doc.getStyle( STYLE_TITLE ) );
}
public void appendRegularText( String s ) throws BadLocationException {
doc.insertString( doc.getLength(), s, doc.getStyle( STYLE_REGULAR ) );
}
public void appendLinkText( String linkURL, String linkTitle ) throws BadLocationException {
if ( browseWorks && linkURL.matches("^(?:https?|ftp)://.*") ) {
SimpleAttributeSet tmpAttr = new SimpleAttributeSet( doc.getStyle( STYLE_HYPERLINK ) );
tmpAttr.addAttribute( ATTR_HYPERLINK_TARGET, linkURL );
doc.insertString( doc.getLength(), linkTitle, tmpAttr );
} else {
doc.insertString( doc.getLength(), linkURL, doc.getStyle( STYLE_REGULAR ) );
}
}
/**
* Sets a component with a statusbar to be set during mouse events.
*/
public void setStatusbar( Statusbar comp ) {
this.statusbar = comp;
}
private static StyleContext getDefaultStyleContext() {
StyleContext result = new StyleContext();
Style defaultStyle = StyleContext.getDefaultStyleContext().getStyle( StyleContext.DEFAULT_STYLE );
Style baseStyle = result.addStyle("base", defaultStyle);
Style regularStyle = result.addStyle( STYLE_REGULAR, baseStyle );
StyleConstants.setFontFamily( regularStyle, "Monospaced" );
StyleConstants.setFontSize( regularStyle, 12 );
Style hyperStyle = result.addStyle( STYLE_HYPERLINK, regularStyle );
StyleConstants.setForeground( hyperStyle, COLOR_HYPER );
StyleConstants.setUnderline( hyperStyle, true );
Style titleStyle = result.addStyle( STYLE_TITLE, baseStyle );
StyleConstants.setFontFamily( titleStyle, "SansSerif" );
StyleConstants.setFontSize( titleStyle, 24 );
StyleConstants.setBold( titleStyle, true );
return result;
}
}