/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/*
* TileEditor.java
*
* Created on Mar 21, 2012, 12:14:42 PM
*/
package org.pepsoft.worldpainter;
import org.pepsoft.worldpainter.biomeschemes.CustomBiomeManager;
import org.pepsoft.worldpainter.history.HistoryEntry;
import org.pepsoft.worldpainter.layers.Layer;
import javax.swing.*;
import javax.swing.text.html.HTMLDocument;
import java.awt.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import static org.pepsoft.worldpainter.Constants.TILE_SIZE;
/**
*
* @author pepijn
*/
public class TileEditor extends WorldPainterDialog implements TileSelector.Listener {
/** Creates new form TileEditor */
public TileEditor(java.awt.Frame parent, Dimension dimension, ColourScheme colourScheme, BiomeScheme biomeScheme, CustomBiomeManager customBiomeManager, Collection<Layer> hiddenLayers, boolean contourLines, int contourSeparation, TileRenderer.LightOrigin lightOrigin) {
super(parent);
this.dimension = dimension;
initComponents();
// Fix the incredibly ugly default font of the JTextPane
Font font = UIManager.getFont("Label.font");
String bodyRule = "body { font-family: " + font.getFamily() + "; font-size: " + font.getSize() + "pt; }";
((HTMLDocument) jTextPane1.getDocument()).getStyleSheet().addRule(bodyRule);
tileSelector1.setColourScheme(colourScheme);
tileSelector1.setBiomeScheme(biomeScheme);
tileSelector1.setHiddenLayers(hiddenLayers);
tileSelector1.setContourLines(contourLines);
tileSelector1.setContourSeparation(contourSeparation);
tileSelector1.setLightOrigin(lightOrigin);
tileSelector1.setDimension(dimension);
tileSelector1.setCustomBiomeManager(customBiomeManager);
tileSelector1.addListener(this);
getRootPane().setDefaultButton(buttonClose);
setLocationRelativeTo(parent);
}
// TileSelector.Listener
@Override
public void selectionChanged(TileSelector tileSelector, Set<Point> newSelection) {
setControlStates();
}
private void setControlStates() {
Set<Point> selectedTiles = tileSelector1.getSelectedTiles();
boolean allowAddTiles, allowRemoveTiles;
if (selectedTiles.isEmpty()) {
allowAddTiles = allowRemoveTiles = false;
} else {
allowAddTiles = false;
allowRemoveTiles = false;
for (Point selectedTile: selectedTiles) {
if (dimension.getTile(selectedTile) != null) {
allowRemoveTiles = true;
} else {
allowAddTiles = true;
}
}
}
buttonAddTiles.setEnabled(allowAddTiles);
buttonRemoveTiles.setEnabled(allowRemoveTiles);
}
private void addTiles() {
Set<Point> selectedTiles = tileSelector1.getSelectedTiles();
Set<Point> tilesToAdd = new HashSet<>();
int newLowestTileX = dimension.getLowestX(), newHighestTileX = dimension.getHighestX();
int newLowestTileY = dimension.getLowestY(), newHighestTileY = dimension.getHighestY();
for (Point selectedTile: selectedTiles) {
if (dimension.getTile(selectedTile) == null) {
tilesToAdd.add(selectedTile);
if (selectedTile.x < newLowestTileX) {
newLowestTileX = selectedTile.x;
}
if (selectedTile.x > newHighestTileX) {
newHighestTileX = selectedTile.x;
}
if (selectedTile.y < newLowestTileY) {
newLowestTileY = selectedTile.y;
}
if (selectedTile.y > newHighestTileY) {
newHighestTileY = selectedTile.y;
}
}
}
if (tilesToAdd.isEmpty()) {
return;
}
// Try to guestimate whether there is enough memory to add the selected
// number of tiles, and if not, ask the user whether they want to
// continue at their own risk
Runtime runtime = Runtime.getRuntime();
runtime.gc();
long maxMemory = runtime.maxMemory();
long freeMemory = runtime.freeMemory();
long totalMemory = runtime.totalMemory();
long memoryInUse = totalMemory - freeMemory;
long availableMemory = maxMemory - memoryInUse;
// Allow room for export
availableMemory -= 250000000L;
// Convert to KB
availableMemory /= 1024;
// Guestimate data and image size
long totalEstimatedDataSize = tilesToAdd.size() * NewWorldDialog.ESTIMATED_TILE_DATA_SIZE;
long totalEstimatedImageSize = (newHighestTileX - newLowestTileX + 1L) * TILE_SIZE * (newHighestTileY - newLowestTileY + 1) * TILE_SIZE * 4 / 1024;
long currentImageSize = (dimension.getHighestX() - dimension.getLowestX() + 1L) * TILE_SIZE * (dimension.getHighestY() - dimension.getLowestY() + 1) * TILE_SIZE * 4 / 1024;
long totalEstimatedSize = totalEstimatedDataSize + totalEstimatedImageSize - currentImageSize;
if (totalEstimatedSize > availableMemory) {
if (JOptionPane.showConfirmDialog(this, "There may not be enough memory to add " + tilesToAdd.size() + " tiles!\nIt may fail, or cause errors later on.\nPlease consider adding fewer tiles, or installing more memory.\nDo you want to continue?", "Too Many Tiles", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION) {
return;
}
} else {
if (JOptionPane.showConfirmDialog(this, "Do you want to add " + tilesToAdd.size() + " new tiles?\nNote that this cannot be undone!", "Confirm Adding Tiles", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
return;
}
}
dimension.setEventsInhibited(true);
dimension.clearUndo();
try {
for (Point newTileCoords: tilesToAdd) {
Tile newTile = dimension.getTileFactory().createTile(newTileCoords.x, newTileCoords.y);
dimension.addTile(newTile);
}
} finally {
dimension.setEventsInhibited(false);
}
dimension.armSavePoint();
World2 world = dimension.getWorld();
if (world != null) {
world.addHistoryEntry(HistoryEntry.WORLD_TILES_ADDED, dimension.getName(), tilesToAdd.size());
}
tileSelector1.clearSelection();
tileSelector1.refresh();
setControlStates();
}
private void removeTiles() {
Set<Point> selectedTiles = tileSelector1.getSelectedTiles();
Set<Point> tilesToRemove = selectedTiles.stream().filter(selectedTile -> dimension.getTile(selectedTile) != null).collect(Collectors.toSet());
if (tilesToRemove.isEmpty()) {
return;
}
if (tilesToRemove.size() == dimension.getTileCount()) {
JOptionPane.showMessageDialog(this, "<html>You cannot remove <em>all</em> tiles from the dimension!</html>", "All Tiles Selected", JOptionPane.ERROR_MESSAGE);
return;
}
if (JOptionPane.showConfirmDialog(this, "Do you want to remove " + tilesToRemove.size() + " tiles?\nNote that this cannot be undone!", "Confirm Removing Tiles", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
dimension.setEventsInhibited(true);
dimension.clearUndo();
try {
tilesToRemove.forEach(dimension::removeTile);
} finally {
dimension.setEventsInhibited(false);
}
dimension.armSavePoint();
World2 world = dimension.getWorld();
if (world != null) {
world.addHistoryEntry(HistoryEntry.WORLD_TILES_REMOVED, dimension.getName(), tilesToRemove.size());
}
tileSelector1.clearSelection();
tileSelector1.refresh();
setControlStates();
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
buttonClose = new javax.swing.JButton();
buttonAddTiles = new javax.swing.JButton();
buttonRemoveTiles = new javax.swing.JButton();
tileSelector1 = new org.pepsoft.worldpainter.TileSelector();
jTextPane1 = new javax.swing.JTextPane();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("WorldPainter - Add or Remove Tiles");
buttonClose.setText("Close");
buttonClose.addActionListener(this::buttonCloseActionPerformed);
buttonAddTiles.setText("Add tiles");
buttonAddTiles.setEnabled(false);
buttonAddTiles.addActionListener(this::buttonAddTilesActionPerformed);
buttonRemoveTiles.setText("Remove tiles");
buttonRemoveTiles.setEnabled(false);
buttonRemoveTiles.addActionListener(this::buttonRemoveTilesActionPerformed);
tileSelector1.setAllowNonExistentTileSelection(true);
jTextPane1.setEditable(false);
jTextPane1.setContentType("text/html"); // NOI18N
jTextPane1.setText("WorldPainter works in tiles of 128 by 128 blocks. On this screen you can add or remove tiles.<br><br>Select tiles to the right using the left mouse button, move the map with the middle or right buttons, then select an action below:<br><br><b>Note:</b> this will remove all undo information!");
jTextPane1.setOpaque(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(buttonClose)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jTextPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 146, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(buttonAddTiles)
.addComponent(buttonRemoveTiles))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tileSelector1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(tileSelector1, javax.swing.GroupLayout.DEFAULT_SIZE, 451, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(buttonClose))
.addGroup(layout.createSequentialGroup()
.addComponent(jTextPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(buttonAddTiles)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(buttonRemoveTiles)))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void buttonCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCloseActionPerformed
cancel();
}//GEN-LAST:event_buttonCloseActionPerformed
private void buttonAddTilesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonAddTilesActionPerformed
addTiles();
}//GEN-LAST:event_buttonAddTilesActionPerformed
private void buttonRemoveTilesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRemoveTilesActionPerformed
removeTiles();
}//GEN-LAST:event_buttonRemoveTilesActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton buttonAddTiles;
private javax.swing.JButton buttonClose;
private javax.swing.JButton buttonRemoveTiles;
private javax.swing.JTextPane jTextPane1;
private org.pepsoft.worldpainter.TileSelector tileSelector1;
// End of variables declaration//GEN-END:variables
private final Dimension dimension;
private static final long serialVersionUID = 1L;
}