Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When printing from MUL, calculate BV from C3/Tag #1462

Merged
merged 6 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added megameklab/data/images/widgets/moveBottom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added megameklab/data/images/widgets/moveDown.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added megameklab/data/images/widgets/moveTop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added megameklab/data/images/widgets/moveUp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ ConfigurationDialog.chkShowCondensedTables.text=Print Mech hit location and clus
ConfigurationDialog.chkShowCondensedTables.tooltip=Include hit location and cluster hits tables in the space where the fluff image normally goes.
ConfigurationDialog.chkShowQuirks.text=Print design quirks
ConfigurationDialog.chkShowQuirks.tooltip=Displays featured design quirks
ConfigurationDialog.chkShowPilotData.text=Include pilot data when printing from a MUL
ConfigurationDialog.chkShowPilotData.text=Include pilot and force data when printing from a MUL
ConfigurationDialog.chkShowPilotData.tooltip=When using a MUL file for batch printing, unchecking this option ignores the generated crew information.
ConfigurationDialog.chkShowEraIcon.text=Print era icon
ConfigurationDialog.chkShowEraIcon.tooltip=Includes the icon associated with the era the unit was constructed.
Expand Down
15 changes: 1 addition & 14 deletions megameklab/src/megameklab/ui/MenuBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import megamek.common.annotations.Nullable;
import megamek.common.loaders.BLKFile;
import megamek.common.templates.TROView;
import megamek.common.util.ImageUtil;
import megameklab.MMLConstants;
import megameklab.ui.dialog.MMLFileChooser;
import megameklab.ui.dialog.MegaMekLabUnitSelectorDialog;
Expand Down Expand Up @@ -394,15 +393,9 @@ private JMenu createPDFUnitExportMenu() {
final JMenuItem miExportUnitsFromMULFileToPDF = new JMenuItem(resources.getString("FromMUL.text"));
miExportUnitsFromMULFileToPDF.setName("miExportUnitsFromMULFileToPDF");
miExportUnitsFromMULFileToPDF.setMnemonic(KeyEvent.VK_M);
miExportUnitsFromMULFileToPDF.addActionListener(evt -> UnitPrintManager.exportMUL(owner.getFrame(), false));
miExportUnitsFromMULFileToPDF.addActionListener(evt -> UnitPrintManager.printMUL(owner.getFrame(), true));
pdfUnitExportMenu.add(miExportUnitsFromMULFileToPDF);

final JMenuItem miExportUnitsFromMULFileToSinglePDFPages = new JMenuItem(resources.getString("FromMULSingle.text"));
miExportUnitsFromMULFileToSinglePDFPages.setName("miExportUnitsFromMULFileToSinglePDFPages");
miExportUnitsFromMULFileToSinglePDFPages.setMnemonic(KeyEvent.VK_L);
miExportUnitsFromMULFileToSinglePDFPages.addActionListener(evt -> UnitPrintManager.exportMUL(owner.getFrame(), true));
pdfUnitExportMenu.add(miExportUnitsFromMULFileToSinglePDFPages);

return pdfUnitExportMenu;
}

Expand Down Expand Up @@ -509,12 +502,6 @@ private JMenu createPrintMenu() {
miPrintUnitsFromMULFile.addActionListener(evt -> UnitPrintManager.printMUL(owner.getFrame(), false));
printMenu.add(miPrintUnitsFromMULFile);

final JMenuItem miPrintUnitsFromMULFileToSinglePages = new JMenuItem(resources.getString("FromMULSingle.text"));
miPrintUnitsFromMULFileToSinglePages.setName("miPrintUnitsFromMULFileToSinglePages");
miPrintUnitsFromMULFileToSinglePages.setMnemonic(KeyEvent.VK_L);
miPrintUnitsFromMULFileToSinglePages.addActionListener(evt -> UnitPrintManager.printMUL(owner.getFrame(), true));
printMenu.add(miPrintUnitsFromMULFileToSinglePages);

return printMenu;
}

Expand Down
178 changes: 172 additions & 6 deletions megameklab/src/megameklab/ui/dialog/PrintQueueDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import megamek.client.ui.baseComponents.MMButton;
import megamek.client.ui.swing.UnitLoadingDialog;
import megamek.common.BTObject;
import megamek.common.Configuration;
import megamek.common.Entity;
import megamek.common.MechFileParser;
import megameklab.printing.PageBreak;
Expand All @@ -30,14 +31,18 @@
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

import static java.util.stream.Collectors.toList;

Expand All @@ -48,22 +53,47 @@
* @author Simon (Juliez)
*/
public class PrintQueueDialog extends AbstractMMLButtonDialog {

private final boolean printToPdf;
private final JButton addFromFileButton = new JButton("Add From File");
private final JButton addFromCacheButton = new JButton("Add From Cache");
private final JButton addPageBreakButton = new JButton("Add Page Break");
private final JButton removeButton = new JButton("Remove Selected");

private final JButton moveTopButton = new JButton(icon("moveTop.png"));
private final JButton moveUpButton = new JButton(icon("moveUp.png"));
private final JButton moveDownButton = new JButton(icon("moveDown.png"));
private final JButton moveBottomButton = new JButton(icon("moveBottom.png"));

private final JCheckBox oneUnitPerSheetCheck = new JCheckBox("Print each unit to a separate page");
private final JFrame parent;
private final List<BTObject> units = new ArrayList<>();
private final JList<String> queuedUnitList = new JList<>();

public PrintQueueDialog(JFrame parent, boolean printToPdf) {
private final boolean fromMul;

public PrintQueueDialog(JFrame parent, boolean printToPdf, List<? extends BTObject> units, boolean fromMul) {
super(parent, true, "PrintQueueDialog", "PrintQueueDialog.windowName.text");
this.parent = parent;
this.printToPdf = printToPdf;
this.fromMul = fromMul;
initialize();
if (units != null) {
this.units.addAll(units);
refresh();
}
}

public PrintQueueDialog(JFrame parent, boolean printToPdf) {
this(parent, printToPdf, null, false);
}

private static ImageIcon icon(String name) {
var path = Configuration.widgetsDir().toPath().resolve(name);
try {
return new ImageIcon(path.toUri().toURL());
} catch (MalformedURLException e) {
return null;
}
}

@Override
Expand All @@ -77,26 +107,51 @@ protected Container createCenterPane() {
removeButton.addActionListener(e -> removeSelectedUnits());
removeButton.setEnabled(false);
removeButton.setMnemonic(KeyEvent.VK_R);

moveTopButton.addActionListener(e -> moveTop());
moveTopButton.setMnemonic(KeyEvent.VK_PAGE_UP);
moveTopButton.setEnabled(false);
moveBottomButton.addActionListener(e -> moveBottom());
moveBottomButton.setMnemonic(KeyEvent.VK_PAGE_DOWN);
moveBottomButton.setEnabled(false);
moveUpButton.addActionListener(e -> moveUp());
moveUpButton.setMnemonic(KeyEvent.VK_UP);
moveUpButton.setEnabled(false);
moveDownButton.addActionListener(e -> moveDown());
moveDownButton.setMnemonic(KeyEvent.VK_DOWN);
moveDownButton.setEnabled(false);

oneUnitPerSheetCheck.setAlignmentX(JComponent.CENTER_ALIGNMENT);
oneUnitPerSheetCheck.setToolTipText("When unchecked, the record sheets for some unit types may be printed on the same page. " +
"Note that the result may depend on whether reference tables are printed. This can be changed in the Settings.");
queuedUnitList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
queuedUnitList.addListSelectionListener(e -> removeButton.setEnabled(!queuedUnitList.isSelectionEmpty()));
queuedUnitList.addListSelectionListener(new OnSelectionChanged());
queuedUnitList.setVisibleRowCount(15);

JPanel buttonPanel = new FixedXYPanel(new GridLayout(4, 1));
buttonPanel.add(addFromCacheButton);
buttonPanel.add(addFromFileButton);
if (!fromMul) {
buttonPanel.add(addFromCacheButton);
buttonPanel.add(addFromFileButton);
}
buttonPanel.add(addPageBreakButton);
buttonPanel.add(removeButton);
buttonPanel.setAlignmentY(JComponent.TOP_ALIGNMENT);

JPanel moveButtonPanel = new FixedXYPanel(new GridLayout(4, 1));
moveButtonPanel.add(moveTopButton);
moveButtonPanel.add(moveUpButton);
moveButtonPanel.add(moveDownButton);
moveButtonPanel.add(moveBottomButton);
moveButtonPanel.setAlignmentY(JComponent.TOP_ALIGNMENT);

JScrollPane queuedUnitListScrollPane = new JScrollPane(queuedUnitList);
queuedUnitListScrollPane.setAlignmentY(JComponent.TOP_ALIGNMENT);
queuedUnitListScrollPane.setBorder(new TitledBorder("Selected Units:"));

Box centerPanel = Box.createHorizontalBox();
centerPanel.add(buttonPanel);
centerPanel.add(Box.createHorizontalStrut(30));
centerPanel.add(moveButtonPanel);
centerPanel.add(queuedUnitListScrollPane);
centerPanel.setBorder(new EmptyBorder(20, 30, 20, 30));

Expand All @@ -122,7 +177,14 @@ protected JPanel createButtonPanel() {

private void refresh() {
List<String> nameList = units.stream()
.map(unit -> ' ' + unit.generalName() + ' ' + unit.specificName())
.map(unit -> {
String title = String.format(" %s %s", unit.generalName(), unit.specificName());
if (fromMul && unit instanceof Entity) {
var crew = ((Entity) unit).getCrew();
title += String.format(" {%s %d/%d}", crew.getName(), crew.getGunnery(), crew.getPiloting());
}
return title;
})
.collect(toList());

var replacementModel = new DefaultListModel<String>();
Expand Down Expand Up @@ -215,6 +277,110 @@ private void removeSelectedUnits() {
refresh();
}

private void moveTop() {
List<BTObject> newListTop = new ArrayList<>();
List<BTObject> newListBottom = new ArrayList<>();
boolean state = false;
for (int i = 0; i < units.size(); i++) {
if (i == topSelectedIndex()) {
state = true;
} else if (i > bottomSelectedIndex()) {
state = false;
}
(state ? newListTop : newListBottom).add(units.get(i));
}
units.clear();
units.addAll(newListTop);
units.addAll(newListBottom);
refresh();
queuedUnitList.setSelectedIndices(IntStream.range(0, newListTop.size()).toArray());
}

private void moveBottom() {
List<BTObject> newListBottom = new ArrayList<>();
List<BTObject> newListTop = new ArrayList<>();
boolean state = false;
for (int i = 0; i < units.size(); i++) {
if (i == topSelectedIndex()) {
state = true;
} else if (i > bottomSelectedIndex()) {
state = false;
}
(state ? newListBottom : newListTop).add(units.get(i));
}
units.clear();
units.addAll(newListTop);
units.addAll(newListBottom);
refresh();
queuedUnitList.setSelectedIndices(IntStream.range(newListTop.size(), newListTop.size() + newListBottom.size()).toArray());
}

private void moveUp() {
var unit = units.remove(topSelectedIndex() - 1);
units.add(bottomSelectedIndex(), unit);
var indices = queuedUnitList.getSelectedIndices();
refresh();
queuedUnitList.setSelectedIndices(Arrays.stream(indices).map(i -> i - 1).toArray());
}

private void moveDown() {
var unit = units.remove(bottomSelectedIndex() + 1);
units.add(topSelectedIndex(), unit);
var indices = queuedUnitList.getSelectedIndices();
refresh();
queuedUnitList.setSelectedIndices(Arrays.stream(indices).map(i -> i + 1).toArray());
}

private int topSelectedIndex() {
return queuedUnitList.getSelectedIndex();
}

private int bottomSelectedIndex() {
var indices = queuedUnitList.getSelectedIndices();
return indices[indices.length - 1];
}

private class OnSelectionChanged implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent e) {
removeButton.setEnabled(!queuedUnitList.isSelectionEmpty());

if (!isSelectionContiguous()) {
moveTopButton.setEnabled(false);
moveUpButton.setEnabled(false);
moveDownButton.setEnabled(false);
moveBottomButton.setEnabled(false);
} else {
if (topSelectedIndex() == 0) {
moveTopButton.setEnabled(false);
moveUpButton.setEnabled(false);
} else {
moveTopButton.setEnabled(true);
moveUpButton.setEnabled(true);
}
if (bottomSelectedIndex() == units.size() - 1) {
moveBottomButton.setEnabled(false);
moveDownButton.setEnabled(false);
} else {
moveBottomButton.setEnabled(true);
moveDownButton.setEnabled(true);
}
}
}

private boolean isSelectionContiguous() {
// getSelectedIndices is guaranteed to return the indices in ascending order
var indices = queuedUnitList.getSelectedIndices();
if (indices.length == 0) {
return false;
}

var start = indices[0];
var end = indices[indices.length - 1];
return end - start == indices.length - 1;
}
}

// TODO: Move to UIUtil
public static class FixedXYPanel extends JPanel {

Expand Down
44 changes: 11 additions & 33 deletions megameklab/src/megameklab/util/UnitPrintManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@

import megamek.client.ui.swing.UnitLoadingDialog;
import megamek.common.*;
import megamek.common.util.C3Util;
import megameklab.printing.*;
import megameklab.ui.dialog.MegaMekLabUnitSelectorDialog;
import org.apache.commons.io.FilenameUtils;
import megameklab.ui.dialog.PrintQueueDialog;
import org.apache.logging.log4j.LogManager;

import javax.print.attribute.HashPrintRequestAttributeSet;
Expand Down Expand Up @@ -50,7 +51,7 @@ public static void exportEntity(Entity entity, JFrame parent) {
}
}

public static void printMUL(Frame parent, boolean singlePrint) {
public static void printMUL(JFrame parent, boolean printToPdf) {
JFileChooser f = new JFileChooser(System.getProperty("user.dir"));
f.setLocation(parent.getLocation().x + 150, parent.getLocation().y + 100);
f.setDialogTitle("Print From MUL");
Expand All @@ -75,39 +76,16 @@ public static void printMUL(Frame parent, boolean singlePrint) {
return;
}

printAllUnits(loadedUnits, singlePrint);
}

public static void exportMUL(Frame parent, boolean singlePrint) {
JFileChooser f = new JFileChooser(System.getProperty("user.dir"));
f.setLocation(parent.getLocation().x + 150, parent.getLocation().y + 100);
f.setDialogTitle("Export from MUL");
f.setMultiSelectionEnabled(false);

FileNameExtensionFilter filter = new FileNameExtensionFilter("Mul Files", "mul");

// Add a filter for mul files
f.setFileFilter(filter);

int returnVal = f.showOpenDialog(parent);
if ((returnVal != JFileChooser.APPROVE_OPTION) || (f.getSelectedFile() == null)) {
// I want a file, y'know!
return;
}
File mulFile = f.getSelectedFile();
final Vector<Entity> loadedUnits;
try {
loadedUnits = new MULParser(mulFile, null).getEntities();
loadedUnits.trimToSize();
} catch (Exception ex) {
LogManager.getLogger().error("", ex);
return;
// Dummy player and game allow bonus BV from C3 and TAG to be calculated
Game g = new Game();
Player p = new Player(1, "Nobody");
for (Entity e : loadedUnits) {
e.setOwner(p);
g.addEntity(e);
C3Util.wireC3(g, e);
}

File exportFile = getExportFile(parent, FilenameUtils.removeExtension(mulFile.getPath()) + ".pdf");
if (exportFile != null) {
exportUnits(loadedUnits, exportFile, singlePrint);
}
new PrintQueueDialog(parent, printToPdf, loadedUnits, true).setVisible(true);
}

public static File getExportFile(Frame parent) {
Expand Down
Loading