/*
* Copyright (C) 2007-2011 IsmAvatar <IsmAvatar@gmail.com>
*
* This file is part of LateralGM.
* LateralGM is free software and comes with ABSOLUTELY NO WARRANTY.
* See LICENSE for details.
*/
package org.lateralgm.main;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileView;
import javax.swing.tree.TreeNode;
import org.lateralgm.components.CustomFileChooser;
import org.lateralgm.components.ErrorDialog;
import org.lateralgm.components.GmMenuBar;
import org.lateralgm.components.CustomFileChooser.FilterSet;
import org.lateralgm.components.impl.CustomFileFilter;
import org.lateralgm.components.impl.ResNode;
import org.lateralgm.file.GmFile;
import org.lateralgm.file.GmFileReader;
import org.lateralgm.file.GmFileWriter;
import org.lateralgm.file.GmFormatException;
import org.lateralgm.file.ResourceList;
import org.lateralgm.messages.Messages;
import org.lateralgm.resources.Resource;
public class FileChooser
{
List<FileReader> readers = new ArrayList<FileReader>();
CustomFileChooser fc = new CustomFileChooser("/org/lateralgm","LAST_FILE_DIR"); //$NON-NLS-1$ //$NON-NLS-2$
FilterSet openFs = new FilterSet();
FilterUnion openAllFilter = new FilterUnion();
FilterSet saveFs = new FilterSet();
public static List<FileView> fileViews = new ArrayList<FileView>();
public static interface FileReader
{
public FileFilter getGroupFilter();
public FileFilter[] getFilters();
public boolean canRead(File f);
public GmFile readFile(File f, ResNode root) throws GmFormatException;
}
public static interface FileWriter
{
}
public void addReader(FileReader fr)
{
readers.add(fr);
openFs.add(fr.getGroupFilter());
for (FileFilter ff : fr.getFilters())
openFs.add(ff);
openAllFilter.add(fr.getGroupFilter());
if (readers.size() == 2) openFs.add(0,openAllFilter);
}
public FileChooser()
{
fc.setFileView(new FileViewUnion());
addReader(new GmReader());
String exts[] = { ".gm81",".gmk",".gm6" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
saveFs.addFilter("FileChooser.FORMAT_WRITERS_GM",exts); //$NON-NLS-1$
saveFs.addFilter("FileChooser.FORMAT_GM81",exts[0]); //$NON-NLS-1$
saveFs.addFilter("FileChooser.FORMAT_GMK",exts[1]); //$NON-NLS-1$
saveFs.addFilter("FileChooser.FORMAT_GM6",exts[2]); //$NON-NLS-1$
}
private class FileViewUnion extends FileView
{
public String getName(File f)
{
for (FileView fv : fileViews)
{
String val = fv.getName(f);
if (val != null) return val;
}
return super.getName(f);
}
public String getDescription(File f)
{
for (FileView fv : fileViews)
{
String val = fv.getDescription(f);
if (val != null) return val;
}
return super.getDescription(f);
}
public String getTypeDescription(File f)
{
for (FileView fv : fileViews)
{
String val = fv.getTypeDescription(f);
if (val != null) return val;
}
return super.getTypeDescription(f);
}
public Icon getIcon(File f)
{
for (FileView fv : fileViews)
{
Icon val = fv.getIcon(f);
if (val != null) return val;
}
return super.getIcon(f);
}
public Boolean isTraversable(File f)
{
for (FileView fv : fileViews)
{
Boolean val = fv.isTraversable(f);
if (val != null) return val;
}
return super.isTraversable(f);
}
}
private class FilterUnion extends FileFilter
{
List<FileFilter> filters = new ArrayList<FileFilter>();
public FilterUnion(FileFilter...filters)
{
add(filters);
}
public void add(FileFilter...filters)
{
for (FileFilter ff : filters)
this.filters.add(ff);
}
@Override
public boolean accept(File f)
{
for (FileFilter ff : filters)
if (ff.accept(f)) return true;
return false;
}
@Override
public String getDescription()
{
return Messages.getString("FileChooser.ALL_SUPPORTED"); //$NON-NLS-1$
}
}
protected class GmReader implements FileReader
{
CustomFileFilter[] filters;
CustomFileFilter groupFilter;
GmReader()
{
String[] exts = { ".gm81",".gmk",".gm6",".gmd" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
String[] descs = { "GM81","GMK","GM6","GMD" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
groupFilter = new CustomFileFilter(Messages.getString("FileChooser.FORMAT_READERS_GM"),exts); //$NON-NLS-1$
filters = new CustomFileFilter[exts.length];
for (int i = 0; i < exts.length; i++)
filters[i] = new CustomFileFilter(
Messages.getString("FileChooser.FORMAT_" + descs[i]),exts[i]); //$NON-NLS-1$
}
public FileFilter getGroupFilter()
{
return groupFilter;
}
public FileFilter[] getFilters()
{
return filters;
}
public boolean canRead(File f)
{
return groupFilter.accept(f);
}
public GmFile readFile(File f, ResNode root) throws GmFormatException
{
return GmFileReader.readGmFile(f,root);
}
}
private void setTitleFile(String titleFile)
{
LGM.frame.setTitle(Messages.format("LGM.TITLE",titleFile)); //$NON-NLS-1$
}
public void newFile()
{
setTitleFile(Messages.getString("LGM.NEWGAME")); //$NON-NLS-1$
LGM.newRoot();
LGM.currentFile = new GmFile();
LGM.populateTree();
fc.setSelectedFile(new File(new String()));
LGM.reload(true);
}
public void openNewFile()
{
fc.setFilterSet(openFs);
fc.setAccessory(null);
if (fc.showOpenDialog(LGM.frame) != CustomFileChooser.APPROVE_OPTION) return;
File f = fc.getSelectedFile();
if (f == null) return;
openFile(f);
}
/** Note that passing in null will cause an open dialog to display */
public void openFile(File file)
{
if (file == null)
{
openNewFile();
return;
}
if (!file.exists()) return;
FileReader reader = findReader(file);
if (reader == null)
{
String title = Messages.getString("FileChooser.UNRECOGNIZED_TITLE"); //$NON-NLS-1$
String message = Messages.format("FileChooser.UNRECOGNIZED",file.getName()); //$NON-NLS-1$
JOptionPane.showMessageDialog(LGM.frame,message,title,JOptionPane.WARNING_MESSAGE);
return;
}
try
{
LGM.currentFile = reader.readFile(file,LGM.newRoot());
}
catch (GmFormatException ex)
{
new ErrorDialog(LGM.frame,Messages.getString("FileChooser.ERROR_LOAD_TITLE"), //$NON-NLS-1$
Messages.getString("FileChooser.ERROR_LOAD"),Messages.format("FileChooser.DEBUG_INFO", //$NON-NLS-1$ //$NON-NLS-2$
ex.getClass().getName(),ex.getMessage(),ex.stackAsString())).setVisible(true);
LGM.currentFile = ex.file;
LGM.populateTree();
rebuildTree();
}
setTitleFile(file.getName());
PrefsStore.addRecentFile(file.getPath());
((GmMenuBar) LGM.frame.getJMenuBar()).updateRecentFiles();
LGM.reload(true);
}
private FileReader findReader(File file)
{
for (FileReader fr : readers)
if (fr.canRead(file)) return fr;
return null;
}
private void rebuildTree()
{
for (int i = 0; i < LGM.root.getChildCount(); i++)
{
TreeNode n = LGM.root.getChildAt(i);
if (!(n instanceof ResNode)) continue;
ResNode rn = (ResNode) n;
if (rn.status != ResNode.STATUS_PRIMARY) continue;
ResourceList<?> rl = LGM.currentFile.getList(rn.kind);
for (Resource<?,?> r : rl)
rn.add(new ResNode(r.getName(),ResNode.STATUS_SECONDARY,r.getKind(),r.reference));
}
}
public boolean saveFile()
{
if (LGM.currentFile.filename == null) return saveNewFile();
LGM.commitAll();
String ext = getVersionExtension(LGM.currentFile.fileVersion);
if (!LGM.currentFile.filename.endsWith(ext))
{
int result = JOptionPane.showConfirmDialog(LGM.frame,Messages.format(
"FileChooser.CONFIRM_EXTENSION",ext,LGM.currentFile.fileVersion), //$NON-NLS-1$
LGM.currentFile.filename,JOptionPane.YES_NO_CANCEL_OPTION);
if (result == JOptionPane.CANCEL_OPTION) return false;
if (result == JOptionPane.NO_OPTION) return saveNewFile();
//if result == yes then continue
}
attemptBackup();
try
{
writeFile(LGM.currentFile,LGM.root);
return true;
}
catch (IOException e)
{
e.printStackTrace();
JOptionPane.showMessageDialog(LGM.frame,Messages.format("FileChooser.ERROR_SAVE", //$NON-NLS-1$
LGM.currentFile.filename,e.getClass().getName(),e.getMessage()),
Messages.getString("FileChooser.ERROR_SAVE_TITLE"),JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
return false;
}
}
public boolean saveNewFile()
{
fc.setFilterSet(saveFs);
fc.setAccessory(makeVersionRadio());
String filename = LGM.currentFile.filename;
fc.setSelectedFile(filename == null ? null : new File(filename));
while (true) //repeatedly display dialog until a valid response is given
{
if (fc.showSaveDialog(LGM.frame) != JFileChooser.APPROVE_OPTION) return false;
filename = fc.getSelectedFile().getPath();
if (forceExt.isSelected())
{
String ext = getVersionExtension(LGM.currentFile.fileVersion);
if (!filename.endsWith(ext)) filename += ext;
}
int result = JOptionPane.YES_OPTION;
if (new File(filename).exists())
result = JOptionPane.showConfirmDialog(
LGM.frame,
Messages.format("FileChooser.CONFIRM_REPLACE",filename), //$NON-NLS-1$
Messages.getString("FileChooser.CONFIRM_REPLACE_TITLE"),JOptionPane.YES_NO_CANCEL_OPTION, //$NON-NLS-1$
JOptionPane.WARNING_MESSAGE);
if (result == JOptionPane.YES_OPTION)
{
LGM.currentFile.filename = filename;
LGM.frame.setTitle(Messages.format("LGM.TITLE",new File(filename).getName())); //$NON-NLS-1$
if (!saveFile()) return false;
PrefsStore.addRecentFile(filename);
((GmMenuBar) LGM.frame.getJMenuBar()).updateRecentFiles();
return true;
}
if (result == JOptionPane.CANCEL_OPTION) return false;
}
}
//Backups
public static boolean attemptBackup()
{
if (pushBackups(LGM.currentFile.filename)) return true;
int result = JOptionPane.showOptionDialog(LGM.frame,Messages.format("FileChooser.ERROR_BACKUP", //$NON-NLS-1$
LGM.currentFile.filename),Messages.getString("FileChooser.ERROR_BACKUP_TITLE"), //$NON-NLS-1$
JOptionPane.YES_NO_OPTION,JOptionPane.ERROR_MESSAGE,null,null,null);
return result == JOptionPane.YES_OPTION;
}
private static boolean pushBackups(String fn)
{
int nb = PrefsStore.getNumberOfBackups();
if (nb <= 0 || !new File(fn).exists()) return true;
String bn;
if (fn.endsWith(".gm6") || fn.endsWith(".gmk"))
bn = fn.substring(0,fn.length() - 4);
else if (fn.endsWith(".gm81"))
bn = fn.substring(0,fn.length() - 5);
else
bn = fn;
block:
{
String ff = "%s.gb%d";
int i;
for (i = 1; i <= nb; i++)
{
String f = String.format(ff,bn,i);
if (!new File(f).exists()) break;
}
if (i > nb)
{
i = nb;
if (!new File(String.format(ff,bn,i)).delete()) break block;
}
for (i--; i >= 0; i--)
{
File f = new File(i > 0 ? String.format(ff,bn,i) : fn);
if (!f.renameTo(new File(String.format(ff,bn,i + 1)))) break block;
}
return true;
}
return false;
}
//Version Radio
public static String getVersionExtension(int version)
{
switch (version)
{
case 530:
return ".gmd";
case 600:
return ".gm6";
case 701:
case 800:
return ".gmk";
case 810:
return ".gm81";
default:
throw new IllegalArgumentException(Integer.toString(version));
}
}
JCheckBox forceExt = new JCheckBox(Messages.getString("FileChooser.FORCE_EXT"),true); //$NON-NLS-1$
public JPanel makeVersionRadio()
{
final int versions[] = { 810,800,701,600 };
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p,BoxLayout.PAGE_AXIS));
ButtonGroup bg = new ButtonGroup();
for (final int v : versions)
{
//XXX: Externalize the version string?
JRadioButton b = new JRadioButton(Integer.toString(v),LGM.currentFile.fileVersion == v);
bg.add(b);
p.add(b);
b.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
LGM.currentFile.fileVersion = v;
}
});
}
p.add(forceExt);
return p;
}
//TODO: Remove
void writeFile(GmFile f, ResNode root) throws IOException
{
GmFileWriter.writeGmFile(f,root);
}
}