/**
* ORIPA - Origami Pattern Editor
* Copyright (C) 2005-2009 Jun Mitani http://mitani.cs.tsukuba.ac.jp/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package oripa.view.main;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Observable;
import java.util.Observer;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import oripa.Config;
import oripa.ORIPA;
import oripa.bind.ButtonFactory;
import oripa.bind.PaintActionButtonFactory;
import oripa.doc.Doc;
import oripa.doc.exporter.ExporterXML;
import oripa.file.FileChooser;
import oripa.file.FileChooserFactory;
import oripa.file.FileFilterEx;
import oripa.file.FileHistory;
import oripa.file.FileVersionError;
import oripa.file.FilterDB;
import oripa.file.ImageResourceLoader;
import oripa.file.SavingAction;
import oripa.fold.OrigamiModel;
import oripa.fold.OrigamiModelFactory;
import oripa.paint.core.PaintConfig;
import oripa.paint.core.PaintContext;
import oripa.paint.creasepattern.CreasePattern;
import oripa.paint.creasepattern.Painter;
import oripa.paint.util.DeleteSelectedLines;
import oripa.resource.Constants;
import oripa.resource.ResourceHolder;
import oripa.resource.ResourceKey;
import oripa.resource.StringID;
import oripa.viewsetting.main.MainFrameSettingDB;
import oripa.viewsetting.main.MainScreenSettingDB;
public class MainFrame extends JFrame implements ActionListener,
ComponentListener, WindowListener, Observer {
/**
*
*/
private static final long serialVersionUID = 272369294032419950L;
private MainFrameSettingDB setting = MainFrameSettingDB.getInstance();
private MainScreenSettingDB screenSetting = MainScreenSettingDB.getInstance();
private PaintContext mouseContext = PaintContext.getInstance();
PainterScreen mainScreen;
private JMenu menuFile = new JMenu(
ORIPA.res.getString(StringID.Main.FILE_ID));
private JMenu menuEdit = new JMenu(ORIPA.res.getString("Edit"));
private JMenu menuHelp = new JMenu(ORIPA.res.getString("Help"));
private JMenuItem menuItemClear = new JMenuItem(ORIPA.res.getString("New"));
private JMenuItem menuItemOpen = new JMenuItem(ORIPA.res.getString("Open"));
private JMenuItem menuItemSave = new JMenuItem(ORIPA.res.getString("Save"));
private JMenuItem menuItemSaveAs = new JMenuItem(
ORIPA.res.getString("SaveAs"));
private JMenuItem menuItemSaveAsImage = new JMenuItem(
ORIPA.res.getString("SaveAsImage"));
private JMenuItem menuItemExportDXF = new JMenuItem("Export DXF");
private JMenuItem menuItemExportOBJ = new JMenuItem("Export OBJ");
private JMenuItem menuItemExportCP = new JMenuItem("Export CP");
private JMenuItem menuItemExportSVG = new JMenuItem("Export SVG");
// -----------------------------------------------------------------------------------------------------------
// Create paint button
ButtonFactory buttonFactory = new PaintActionButtonFactory();
/**
* For changing outline
*/
private JMenuItem menuItemChangeOutline = (JMenuItem) buttonFactory.create(
this, JMenuItem.class, StringID.EDIT_CONTOUR_ID);
/**
* For selecting all lines
*/
private JMenuItem menuItemSelectAll = (JMenuItem) buttonFactory.create(
this, JMenuItem.class, StringID.SELECT_ALL_LINE_ID);
/**
* For starting copy-and-paste
*/
private JMenuItem menuItemCopyAndPaste = (JMenuItem) buttonFactory.create(
this, JMenuItem.class, StringID.COPY_PASTE_ID);
/**
* For starting cut-and-paste
*/
private JMenuItem menuItemCutAndPaste = (JMenuItem) buttonFactory.create(
this, JMenuItem.class, StringID.CUT_PASTE_ID);
// -----------------------------------------------------------------------------------------------------------
private ResourceHolder resourceHolder = ResourceHolder.getInstance();
private JMenuItem menuItemProperty = new JMenuItem(
resourceHolder.getString(ResourceKey.LABEL,
StringID.Main.PROPERTY_ID));
private JMenuItem menuItemExit = new JMenuItem(resourceHolder.getString(
ResourceKey.LABEL, StringID.Main.EXIT_ID));
private JMenuItem menuItemUndo = new JMenuItem(ORIPA.res.getString("Undo"));
private JMenuItem menuItemAbout = new JMenuItem(
ORIPA.res.getString("About"));
private JMenuItem menuItemRepeatCopy = new JMenuItem("Array Copy");
private JMenuItem menuItemCircleCopy = new JMenuItem("Circle Copy");
private JMenuItem menuItemUnSelectAll = new JMenuItem("UnSelect All");
private JMenuItem menuItemDeleteSelectedLines = new JMenuItem(
"Delete Selected Lines");
private JMenuItem[] MRUFilesMenuItem = new JMenuItem[Config.MRUFILE_NUM];
private RepeatCopyDialog arrayCopyDialog;
private CircleCopyDialog circleCopyDialog;
public static JLabel hintLabel = new JLabel();
public UIPanel uiPanel;
private FileHistory fileHistory = new FileHistory(Config.MRUFILE_NUM);
private FilterDB filterDB = FilterDB.getInstance();
private FileFilterEx[] fileFilters = new FileFilterEx[] {
filterDB.getFilter("opx"), filterDB.getFilter("pict") };
public MainFrame() {
setting.addObserver(this);
// addKeyListener(this);
menuItemCopyAndPaste.setText(resourceHolder.getString(
ResourceKey.LABEL, StringID.COPY_PASTE_ID));
menuItemCutAndPaste.setText(resourceHolder.getString(
ResourceKey.LABEL, StringID.CUT_PASTE_ID));
// menuItemChangeOutline.setText(ORIPA.res.getString(StringID.Menu.CONTOUR_ID));
mainScreen = new PainterScreen();
addWindowListener(this);
uiPanel = new UIPanel(mainScreen);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(uiPanel, BorderLayout.WEST);
getContentPane().add(mainScreen, BorderLayout.CENTER);
getContentPane().add(hintLabel, BorderLayout.SOUTH);
ImageResourceLoader imgLoader = new ImageResourceLoader();
this.setIconImage(imgLoader.loadAsIcon("icon/oripa.gif", getClass())
.getImage());
menuItemOpen.addActionListener(this);
menuItemOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
ActionEvent.CTRL_MASK));
menuItemSave.addActionListener(this);
menuItemSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
ActionEvent.CTRL_MASK));
menuItemSaveAs.addActionListener(this);
menuItemSaveAsImage.addActionListener(this);
menuItemExit.addActionListener(this);
// menuItemExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
// ActionEvent.CTRL_MASK));
menuItemUndo.addActionListener(this);
menuItemUndo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z,
ActionEvent.CTRL_MASK));
menuItemClear.addActionListener(this);
menuItemClear.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
ActionEvent.CTRL_MASK));
menuItemAbout.addActionListener(this);
menuItemExportDXF.addActionListener(this);
menuItemExportOBJ.addActionListener(this);
menuItemExportCP.addActionListener(this);
menuItemExportSVG.addActionListener(this);
menuItemProperty.addActionListener(this);
menuItemChangeOutline.addActionListener(this);
menuItemRepeatCopy.addActionListener(this);
menuItemCircleCopy.addActionListener(this);
menuItemSelectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
ActionEvent.CTRL_MASK));
menuItemUnSelectAll.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_ESCAPE, 0));
menuItemUnSelectAll
.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
CreasePattern creasePattern = ORIPA.doc.getCreasePattern();
Painter painter = new Painter();
painter.resetSelectedOriLines(creasePattern);
mouseContext.clear(false);
mainScreen.repaint();
}
});
menuItemDeleteSelectedLines
.addActionListener(new DeleteSelectedLines());
menuItemDeleteSelectedLines.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_DELETE, 0));
menuItemCopyAndPaste.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_C, ActionEvent.CTRL_MASK));
menuItemCutAndPaste.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_X, ActionEvent.CTRL_MASK));
for (int i = 0; i < Config.MRUFILE_NUM; i++) {
MRUFilesMenuItem[i] = new JMenuItem();
MRUFilesMenuItem[i].addActionListener(this);
}
loadIniFile();
// Building the menu bar
JMenuBar menuBar = new JMenuBar();
buildMenuFile();
menuEdit.add(menuItemCopyAndPaste);
menuEdit.add(menuItemCutAndPaste);
menuEdit.add(menuItemRepeatCopy);
menuEdit.add(menuItemCircleCopy);
menuEdit.add(menuItemSelectAll);
menuEdit.add(menuItemUnSelectAll);
menuEdit.add(menuItemDeleteSelectedLines);
menuEdit.add(menuItemUndo);
menuEdit.add(menuItemChangeOutline);
menuHelp.add(menuItemAbout);
menuBar.add(menuFile);
menuBar.add(menuEdit);
menuBar.add(menuHelp);
setJMenuBar(menuBar);
addSavingActions();
}
private void addSavingActions() {
filterDB.getFilter("pict").setSavingAction(new SavingAction() {
@Override
public boolean save(String path) {
try {
savePictureFile(mainScreen.getCreasePatternImage(), path);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
return true;
}
});
filterDB.getFilter("opx").setSavingAction(new SavingAction() {
@Override
public boolean save(String path) {
try {
saveOpxFile(path);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
return true;
}
});
}
private void saveOpxFile(String filePath) {
ExporterXML exporter = new ExporterXML();
exporter.export(ORIPA.doc, filePath);
ORIPA.doc.setDataFilePath(filePath);
updateMenu(filePath);
ORIPA.doc.clearChanged();
}
private void savePictureFile(Image cpImage, String filePath)
throws IOException {
BufferedImage image = new BufferedImage(cpImage.getWidth(this),
cpImage.getHeight(this), BufferedImage.TYPE_INT_RGB);
image.getGraphics().drawImage(cpImage, 0, 0, this);
File file = new File(filePath);
ImageIO.write(image, filePath.substring(filePath.lastIndexOf(".") + 1),
file);
}
public void initialize() {
arrayCopyDialog = new RepeatCopyDialog(this);
circleCopyDialog = new CircleCopyDialog(this);
}
@Override
public void actionPerformed(ActionEvent e) {
Doc document = ORIPA.doc;
CreasePattern creasePattern = document.getCreasePattern();
// Check the last opened files
for (int i = 0; i < Config.MRUFILE_NUM; i++) {
if (e.getSource() == MRUFilesMenuItem[i]) {
try {
String filePath = MRUFilesMenuItem[i].getText();
openFile(filePath);
updateTitleText();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this, e.toString(),
ORIPA.res.getString("Error_FileLoadFailed"),
JOptionPane.ERROR_MESSAGE);
}
mainScreen.repaint();
return;
}
}
//TODO Refactor the long, long if-else sequences!
// String lastPath = fileHistory.getLastPath();
String lastDirectory = fileHistory.getLastDirectory();
if (e.getSource() == menuItemOpen) {
openFile(null);
mainScreen.repaint();
updateTitleText();
} else if (e.getSource() == menuItemSave
&& !ORIPA.doc.getDataFilePath().equals("")) {
saveOpxFile(ORIPA.doc.getDataFilePath());
} else if (e.getSource() == menuItemSaveAs
|| e.getSource() == menuItemSave) {
String path = saveFile(lastDirectory, ORIPA.doc.getDataFileName(),
fileFilters);
updateMenu(path);
updateTitleText();
} else if (e.getSource() == menuItemSaveAsImage) {
saveFile(lastDirectory, ORIPA.doc.getDataFileName(),
new FileFilterEx[] { filterDB.getFilter("pict") });
} else if (e.getSource() == menuItemExportDXF) {
exportFile("dxf");
} else if (e.getSource() == menuItemExportOBJ) {
exportFile("obj");
} else if (e.getSource() == menuItemExportCP) {
exportFile("cp");
} else if (e.getSource() == menuItemExportSVG) {
exportFile("svg");
} else if (e.getSource() == menuItemChangeOutline) {
// Globals.preEditMode = Globals.editMode;
// Globals.editMode = Constants.EditMode.EDIT_OUTLINE;
// Globals.setMouseAction(new EditOutlineAction());
} else if (e.getSource() == menuItemExit) {
saveIniFile();
System.exit(0);
} else if (e.getSource() == menuItemUndo) {
if (PaintConfig.getMouseAction() != null) {
PaintConfig.getMouseAction().undo(mouseContext);
} else {
ORIPA.doc.loadUndoInfo();
}
mainScreen.repaint();
} else if (e.getSource() == menuItemClear) {
ORIPA.doc = new Doc(Constants.DEFAULT_PAPER_SIZE);
ORIPA.modelFrame.repaint();
ORIPA.modelFrame.setVisible(false);
ORIPA.renderFrame.setVisible(false);
screenSetting.setGridVisible(true);
screenSetting.notifyObservers();
// ORIPA.mainFrame.uiPanel.dispGridCheckBox.setSelected(true);
updateTitleText();
} else if (e.getSource() == menuItemAbout) {
JOptionPane.showMessageDialog(this, ORIPA.infoString,
ORIPA.res.getString("Title"),
JOptionPane.INFORMATION_MESSAGE);
} else if (e.getSource() == menuItemProperty) {
PropertyDialog dialog = new PropertyDialog(this);
dialog.setValue();
Rectangle rec = getBounds();
dialog.setLocation(
(int) (rec.getCenterX() - dialog.getWidth() / 2),
(int) (rec.getCenterY() - dialog.getHeight() / 2));
dialog.setModal(true);
dialog.setVisible(true);
} else if (e.getSource() == menuItemRepeatCopy) {
Painter painter = new Painter();
if (painter.countSelectedLines(creasePattern) == 0) {
JOptionPane.showMessageDialog(this, "Select target lines",
"ArrayCopy", JOptionPane.WARNING_MESSAGE);
} else {
arrayCopyDialog.setVisible(true);
}
} else if (e.getSource() == menuItemCircleCopy) {
Painter painter = new Painter();
if (painter.countSelectedLines(creasePattern) == 0) {
JOptionPane.showMessageDialog(this, "Select target lines",
"ArrayCopy", JOptionPane.WARNING_MESSAGE);
} else {
circleCopyDialog.setVisible(true);
}
}
}
public void updateTitleText() {
String fileName;
if ((ORIPA.doc.getDataFilePath()).equals("")) {
fileName = ORIPA.res.getString("DefaultFileName");
} else {
fileName = ORIPA.doc.getDataFileName();
}
setTitle(fileName + " - " + ORIPA.TITLE);
}
private String saveFile(String directory, String fileName,
FileFilterEx[] filters) {
File givenFile = new File(directory, fileName);
return saveFile(givenFile.getPath(), filters);
}
private String saveFile(String homePath, FileFilterEx[] filters) {
FileChooserFactory chooserFactory = new FileChooserFactory();
FileChooser chooser = chooserFactory.createChooser(homePath, filters);
String path = chooser.saveFile(this);
if (path != null) {
// if(path.endsWith(".opx")){
// ORIPA.doc.setDataFilePath(path);
// ORIPA.doc.clearChanged();
//
// updateMenu(path);
// }
} else {
path = homePath;
}
return path;
}
public void exportFile(String ext) {
Doc document = ORIPA.doc;
CreasePattern creasePattern = document.getCreasePattern();
OrigamiModel origamiModel = document.getOrigamiModel();
boolean hasModel = origamiModel.hasModel();
OrigamiModelFactory modelFactory = new OrigamiModelFactory();
origamiModel = modelFactory.buildOrigami(creasePattern, document.getPaperSize(), true);
document.setOrigamiModel(origamiModel);
if ("obj".equals(ext) == false) {
} else if (!hasModel && !origamiModel.isProbablyFoldable()) {
JOptionPane.showConfirmDialog(null,
"Warning: Building a set of polygons from crease pattern "
+ "was failed.", "Warning",
JOptionPane.OK_OPTION, JOptionPane.WARNING_MESSAGE);
}
saveFile(null, new FileFilterEx[] { filterDB.getFilter(ext) });
}
private void buildMenuFile() {
menuFile.removeAll();
menuFile.add(menuItemClear);
menuFile.add(menuItemOpen);
menuFile.add(menuItemSave);
menuFile.add(menuItemSaveAs);
menuFile.add(menuItemSaveAsImage);
menuFile.add(menuItemExportDXF);
menuFile.add(menuItemExportOBJ);
menuFile.add(menuItemExportCP);
menuFile.add(menuItemExportSVG);
menuFile.addSeparator();
menuFile.add(menuItemProperty);
menuFile.addSeparator();
int i = 0;
for (String path : fileHistory.getHistory()) {
MRUFilesMenuItem[i].setText(path);
menuFile.add(MRUFilesMenuItem[i]);
i++;
}
while (i < MRUFilesMenuItem.length) {
MRUFilesMenuItem[i].setText("");
i++;
}
menuFile.addSeparator();
menuFile.add(menuItemExit);
}
public void updateMenu(String filePath) {
if (filterDB.getLoadableFilterOf(filePath) == null) {
return;
}
fileHistory.useFile(filePath);
buildMenuFile();
}
/**
* if filePath is null, this method opens a dialog to select the target.
* otherwise, it tries to read data from the path.
*
* @param filePath
*/
private void openFile(String filePath) {
ORIPA.modelFrame.setVisible(false);
ORIPA.renderFrame.setVisible(false);
screenSetting.setGridVisible(false);
screenSetting.notifyObservers();
// ORIPA.mainFrame.uiPanel.dispGridCheckBox.setSelected(false);
String path = null;
if (filePath != null) {
path = loadFile(filePath);
} else {
FileChooserFactory factory = new FileChooserFactory();
FileChooser fileChooser = factory.createChooser(fileHistory
.getLastPath(), FilterDB.getInstance().getLoadables());
fileChooser.setFileFilter(FilterDB.getInstance().getFilter("opx"));
path = fileChooser.loadFile(this);
}
if (path == null) {
path = ORIPA.doc.getDataFilePath();
} else {
updateMenu(path);
}
}
/**
* Do not call directly. Please use openFile().
*
* @param filePath
* @return
*/
private String loadFile(String filePath) {
FileFilterEx[] filters = FilterDB.getInstance().getLoadables();
File file = new File(filePath);
// find appropriate loader
boolean loaded = false;
for (FileFilterEx filter : filters) {
if (!filter.accept(file)){
continue;
}
if (file.isDirectory()) {
continue;
}
try {
loaded = filter.getLoadingAction().load(filePath);
} catch (FileVersionError e) {
JOptionPane.showMessageDialog(
this,
"This file is compatible with a new version. "
+ "Please obtain the latest version of ORIPA",
"Failed to load the file",
JOptionPane.ERROR_MESSAGE);
}
break;
}
if (!loaded) {
return null;
}
return filePath;
}
private void saveIniFile() {
fileHistory.saveToFile(ORIPA.iniFilePath);
}
private void loadIniFile() {
fileHistory.loadFromFile(ORIPA.iniFilePath);
}
@Override
public void componentResized(ComponentEvent arg0) {
}
@Override
public void componentMoved(ComponentEvent arg0) {
}
@Override
public void componentShown(ComponentEvent arg0) {
}
@Override
public void componentHidden(ComponentEvent arg0) {
}
@Override
public void windowOpened(WindowEvent arg0) {
}
@Override
public void windowClosing(WindowEvent arg0) {
if (ORIPA.doc.isChanged()) {
// TODO: confirm saving edited opx
int selected = JOptionPane
.showConfirmDialog(
this,
"The crease pattern has been modified. Would you like to save?",
"Comfirm to save", JOptionPane.YES_NO_OPTION);
if (selected == JOptionPane.YES_OPTION) {
String path = saveFile(fileHistory.getLastDirectory(),
ORIPA.doc.getDataFileName(), fileFilters);
if (path == null) {
}
}
}
saveIniFile();
}
@Override
public void windowClosed(WindowEvent arg0) {
}
@Override
public void windowIconified(WindowEvent arg0) {
}
@Override
public void windowDeiconified(WindowEvent arg0) {
}
@Override
public void windowActivated(WindowEvent arg0) {
}
@Override
public void windowDeactivated(WindowEvent arg0) {
}
// @Override
// public void keyTyped(KeyEvent e) {
// if(e.isControlDown()){
// screenUpdater.updateScreen();
// }
// }
//
// @Override
// public void keyPressed(KeyEvent e) {
// if(e.isControlDown()){
// screenUpdater.updateScreen();
// }
// }
//
// @Override
// public void keyReleased(KeyEvent e) {
// if(e.isControlDown()){
// screenUpdater.updateScreen();
// }
//
// }
@Override
public void update(Observable o, Object arg) {
if (o.toString() == setting.getName()) {
hintLabel.setText(" " + setting.getHint());
hintLabel.repaint();
}
}
}