/* Copyright (c) 2008-2010, developers of the Ascension Log Visualizer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ package com.googlecode.logVisualizer.gui; import java.util.HashSet; import java.util.Set; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTree; import javax.swing.ScrollPaneConstants; import javax.swing.WindowConstants; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeSelectionModel; import org.jfree.ui.RefineryUtilities; import com.googlecode.logVisualizer.logData.Item; import com.googlecode.logVisualizer.logData.LogDataHolder; import com.googlecode.logVisualizer.logData.MPGain; import com.googlecode.logVisualizer.logData.Skill; import com.googlecode.logVisualizer.logData.consumables.Consumable; import com.googlecode.logVisualizer.logData.turn.AbstractTurn; import com.googlecode.logVisualizer.logData.turn.SingleTurn; import com.googlecode.logVisualizer.logData.turn.TurnInterval; import com.googlecode.logVisualizer.logData.turn.turnAction.EquipmentChange; import com.googlecode.logVisualizer.parser.UsefulPatterns; import com.googlecode.logVisualizer.util.textualLogs.TextLogCreator; import com.googlecode.logVisualizer.util.textualLogs.TextLogCreator.TextualLogVersion; /** * A useful and mostly self-contained class that can be used to view a more * detailed report of an ascension log. */ final class DetailedLogViewer extends JFrame { /** * */ private static final long serialVersionUID = -1426856289964754334L; private final JEditorPane editorPane = new JEditorPane(); private final String htmlLog; /** * Constructs and opens a frame with a more detailed view of the given * ascension log. */ DetailedLogViewer(final LogDataHolder logData) { super("DetailedLogViewer"); this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); if (logData == null) { throw new NullPointerException( "The log data holder must not be null."); } this.htmlLog = TextLogCreator.getTextualLog(logData, TextualLogVersion.HTML_LOG); final JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); this.editorPane.setEditable(false); this.editorPane.setContentType("text/html"); splitter.setLeftComponent(new JScrollPane(this .createTurnRundownTree(logData))); splitter.setRightComponent(new JScrollPane(this.editorPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED)); splitter.setDividerLocation(300); this.setContentPane(splitter); this.setSize(800, 600); RefineryUtilities.centerFrameOnScreen(this); this.setVisible(true); } /** * Creates the turn rundown tree menu to navigate between all turns. */ private JTree createTurnRundownTree(final LogDataHolder logData) { final DefaultMutableTreeNode root = new DefaultMutableTreeNode( logData.getLogName()); for (final TurnInterval ti : logData.getTurnsSpent()) { final DefaultMutableTreeNode tiRoot = new DefaultMutableTreeNode( new TurnIntervalContainer(ti)); for (final SingleTurn st : ti.getTurns()) { tiRoot.add(new DefaultMutableTreeNode(new SingleTurnContainer( st))); } root.add(tiRoot); } final JTree tree = new JTree(root); tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION); tree.addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(final TreeSelectionEvent e) { final DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree .getLastSelectedPathComponent(); if (node != null) { final Object nodeContents = node.getUserObject(); if (nodeContents instanceof TurnContainer) { DetailedLogViewer.this.editorPane.setText(DetailedLogViewer .createInformationString((TurnContainer) nodeContents)); } else { DetailedLogViewer.this.editorPane .setText(DetailedLogViewer.this.htmlLog); } DetailedLogViewer.this.editorPane.setCaretPosition(0); } } }); tree.setSelectionInterval(0, 0); return tree; } static String createInformationString(final TurnContainer tc) { return tc.getTurnObject() instanceof TurnInterval ? DetailedLogViewer .createTurnIntervalInfoString((TurnInterval) tc.getTurnObject()) : DetailedLogViewer.createSingleTurnInfoString((SingleTurn) tc .getTurnObject()); } private static String createTurnIntervalInfoString(final TurnInterval ti) { final StringBuilder str = new StringBuilder(2000); str.append("<html>"); // Caption str.append("<h1>"); str.append(UsefulPatterns.SQUARE_BRACKET_OPEN); if (ti.getTotalTurns() > 1) { str.append(ti.getStartTurn() + 1); str.append(UsefulPatterns.MINUS); } str.append(ti.getEndTurn()); str.append(UsefulPatterns.SQUARE_BRACKET_CLOSE); str.append(UsefulPatterns.WHITE_SPACE); str.append(ti.getAreaName()); str.append("</h1><p>"); // General data str.append("<h2>"); str.append("General Data"); str.append("</h2><br>"); str.append("Meat gained inside encounters: " + ti.getEncounterMeatGain() + "<br>"); str.append("Meat gained outside encounters: " + ti.getOtherMeatGain() + "<br>"); str.append("Meat spent: " + ti.getMeatSpent() + "<br>"); str.append("Stat gains: " + ti.getStatGain() + "<br>"); str.append("Stat gains (including consumables): " + ti.getTotalStatGain() + "<br>"); str.append("Free runaways: " + ti.getFreeRunaways() + "<br>"); int mpCosts = 0; for (final Skill s : ti.getSkillsCast()) { mpCosts += s.getMpCost(); } str.append("MP spent: " + mpCosts + "<br>"); final Set<String> usedFamiliars = new HashSet<>(); for (final SingleTurn st : ti.getTurns()) { usedFamiliars.add(st.getUsedFamiliar().getFamiliarName()); } str.append("Used familiars: "); for (final String s : usedFamiliars) { str.append(s + ", "); } str.replace(str.length() - 2, str.length(), ""); str.append("<br>"); str.append("Number of encounters: " + ti.getTotalTurns() + "<br>"); str.append("Number of dropped items: " + ti.getDroppedItems().size() + "<br>"); str.append("Number of consumables used: " + ti.getConsumablesUsed().size() + "<br>"); str.append("Number of skills cast: " + ti.getSkillsCast().size()); str.append("<p>"); // Encounter list str.append("<h2>"); str.append("Encounters"); str.append("</h2><br>"); for (final SingleTurn st : ti.getTurns()) { str.append(UsefulPatterns.SQUARE_BRACKET_OPEN); str.append(st.getTurnNumber()); str.append(UsefulPatterns.SQUARE_BRACKET_CLOSE); str.append(UsefulPatterns.WHITE_SPACE); str.append(st.getEncounterName()); str.append("<br>"); } str.append("<p>"); str.append(DetailedLogViewer.createDetailedTurnInfoString(ti)); str.append("</html>"); return str.toString(); } private static String createSingleTurnInfoString(final SingleTurn st) { final StringBuilder str = new StringBuilder(1000); str.append("<html>"); // Caption str.append("<h1>"); str.append(UsefulPatterns.SQUARE_BRACKET_OPEN); str.append(st.getTurnNumber()); str.append(UsefulPatterns.SQUARE_BRACKET_CLOSE); str.append(UsefulPatterns.WHITE_SPACE); str.append(st.getEncounterName()); str.append("</h1><p>"); // General data str.append("<h2>"); str.append("General Data"); str.append("</h2><br>"); str.append("Meat gained inside the encounter: " + st.getEncounterMeatGain() + "<br>"); str.append("Meat gained outside the encounter: " + st.getOtherMeatGain() + "<br>"); str.append("Meat spent: " + st.getMeatSpent() + "<br>"); str.append("Stat gains: " + st.getStatGain() + "<br>"); str.append("Stat gains (including consumables): " + st.getTotalStatGain() + "<br>"); int mpCosts = 0; for (final Skill s : st.getSkillsCast()) { mpCosts += s.getMpCost(); } str.append("MP spent: " + mpCosts + "<br>"); str.append("Familiar: " + st.getUsedFamiliar().getFamiliarName() + "<br>"); str.append("Number of dropped items: " + st.getDroppedItems().size() + "<br>"); str.append("Number of consumables used: " + st.getConsumablesUsed().size() + "<br>"); str.append("Number of skills cast: " + st.getSkillsCast().size()); str.append("<p>"); // Equipment str.append("<h2>"); str.append("Equipment"); str.append("</h2><br>"); final EquipmentChange equip = st.getUsedEquipment(); str.append("Hat: " + equip.getHat() + "<br>"); str.append("Weapon: " + equip.getWeapon() + "<br>"); str.append("Offhand: " + equip.getOffhand() + "<br>"); str.append("Shirt: " + equip.getShirt() + "<br>"); str.append("Pants: " + equip.getPants() + "<br>"); str.append("Acc1: " + equip.getAcc1() + "<br>"); str.append("Acc2: " + equip.getAcc2() + "<br>"); str.append("Acc2: " + equip.getAcc3() + "<br>"); str.append("Familiar equip: " + equip.getFamEquip()); str.append("<p>"); str.append(DetailedLogViewer.createDetailedTurnInfoString(st)); str.append("</html>"); return str.toString(); } private static String createDetailedTurnInfoString(final AbstractTurn t) { final StringBuilder str = new StringBuilder(1000); // Dropped items str.append("<h2>"); str.append("Dropped Items"); str.append("</h2><br>"); for (final Item i : t.getDroppedItems()) { str.append(i + "<br>"); } str.append("<p>"); // Consumables used str.append("<h2>"); str.append("Consumables Used"); str.append("</h2><br>"); for (final Consumable c : t.getConsumablesUsed()) { str.append(c + "<br>"); } str.append("<p>"); // Skills cast str.append("<h2>"); str.append("Skills Cast"); str.append("</h2><br>"); for (final Skill s : t.getSkillsCast()) { str.append(s.getAmount()); str.append(UsefulPatterns.WHITE_SPACE); str.append(s.getName()); str.append(UsefulPatterns.WHITE_SPACE); str.append(UsefulPatterns.ROUND_BRACKET_OPEN); str.append(s.getMpCost()); str.append(UsefulPatterns.WHITE_SPACE); str.append("MP"); str.append(UsefulPatterns.ROUND_BRACKET_CLOSE); str.append("<br>"); } str.append("<p>"); // MP summary final MPGain mpGains = t.getMPGain(); str.append("<h2>"); str.append("MP Gains"); str.append("</h2><br>"); str.append("Total mp gained: " + mpGains.getTotalMPGains() + "<br><br>"); str.append("Inside Encounters: " + mpGains.getEncounterMPGain() + "<br>"); str.append("Starfish Familiars: " + mpGains.getStarfishMPGain() + "<br>"); str.append("Resting: " + mpGains.getRestingMPGain() + "<br>"); str.append("Outside Encounters: " + mpGains.getOutOfEncounterMPGain() + "<br>"); str.append("Consumables: " + mpGains.getConsumableMPGain() + "<br>"); str.append("<p>"); return str.toString(); } private static interface TurnContainer { AbstractTurn getTurnObject(); } private static class TurnIntervalContainer implements TurnContainer { private final TurnInterval ti; TurnIntervalContainer(final TurnInterval ti) { this.ti = ti; } @Override public AbstractTurn getTurnObject() { return this.ti; } @Override public String toString() { final StringBuilder str = new StringBuilder(50); str.append(UsefulPatterns.SQUARE_BRACKET_OPEN); if (this.ti.getTotalTurns() > 1) { str.append(this.ti.getStartTurn() + 1); str.append(UsefulPatterns.MINUS); } str.append(this.ti.getEndTurn()); str.append(UsefulPatterns.SQUARE_BRACKET_CLOSE); str.append(UsefulPatterns.WHITE_SPACE); str.append(this.ti.getAreaName()); return str.toString(); } } private static class SingleTurnContainer implements TurnContainer { private final SingleTurn st; SingleTurnContainer(final SingleTurn st) { this.st = st; } @Override public AbstractTurn getTurnObject() { return this.st; } @Override public String toString() { final StringBuilder str = new StringBuilder(40); str.append(UsefulPatterns.SQUARE_BRACKET_OPEN); str.append(this.st.getTurnNumber()); str.append(UsefulPatterns.SQUARE_BRACKET_CLOSE); str.append(UsefulPatterns.WHITE_SPACE); str.append(this.st.getEncounterName()); return str.toString(); } } }