package main;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.io.File;
import javax.swing.JOptionPane;
import tikzmodel.TikzFigure;
import tikzparser.*;
import gui.*;
/**
* Each instance of the MieZ class manages exactly one TikZ picture.
* It also provides routines to store the picture in the file it was
* read from.
*
* @author Florian Noack
*/
public final class MieZ implements DocumentWindowListener, Debug, MouseListener, MouseMotionListener {
////////////////////////////////
// CONSTANTS
////////////////////////////////
/**
* Frametitle
*/
static final String TITLE = "MieZ - A TikZ image manipulation tool";
/**
* Version
*/
static final String VERSION = "0.1";
/**
* Exit question
*/
static final String QUESTION_EXIT = "Do you really want to quit?";
/**
* Save question
*/
static final String QUESTION_SAVE = "Do you want to save your changes before exiting?";
////////////////////////////////
// STATICS
////////////////////////////////
/**
* Working directory of this process.
*/
public static String WORKING_DIRECTORY;
/**
* Stores the number of currently created instances
*/
private static int instanceCount;
/**
* File Manager for Tikz pictures
*/
private static TikzFileManager manager;
/**
* Static constructor.
*/
static {
instanceCount = 0;
manager = TikzFileManager.createManager();
}
////////////////////////////////
// DYNAMICS
////////////////////////////////
/**
* Main window of the MieZ program.
*/
private DocumentWindow gui;
/**
* Currently opened TikzPicture for this instance.
*/
private SyntaxTikzPicture pic;
/**
* Currently openen TikzFile in this instance.
*/
private TikzFile file;
/**
* Current manipulation's active screen figure.
*/
private Figure activeFigure;
/**
* Determines whether the document has changed.
*/
private boolean hasChanged;
/**
* Constructs a new document controller given a specified picture.
*
* @param picture
* Picture that can be processed by this controller. If <i>picture</i> is null,
* the document window will be empty.
*/
private MieZ(SyntaxTikzPicture pic) {
// Sets object variables
hasChanged = false;
// New instance was created
instanceCount++;
// Initialize GUI
gui = new DocumentWindow(TITLE, this);
gui.getEditorPanel().getDrawPanel().addMouseListener(this);
gui.getEditorPanel().getDrawPanel().addMouseMotionListener(this);
gui.setVisible(true);
openPicture(pic);
}
/**
* Closes the program window.
*/
@Override
public void onCloseWindow() {
if(hasChanged) {
switch(JOptionPane.showConfirmDialog(gui, QUESTION_SAVE)) {
case JOptionPane.YES_OPTION:
onSave();
case JOptionPane.NO_OPTION:
closeWindow();
}
} else {
// Close empty windows without asking
if(file == null) {
closeWindow();
} else {
switch(JOptionPane.showConfirmDialog(gui, QUESTION_EXIT)) {
case JOptionPane.YES_OPTION:
closeWindow();
}
}
}
}
/**
* Closes the currently processed document.
*/
private void closeWindow() {
gui.setVisible(false);
gui.dispose();
instanceCount--;
if(instanceCount == 0) {
System.exit(0);
}
}
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if("New".equals(cmd)) {
onNew();
} else if("Open".equals(cmd)) {
onOpen();
} else if("Save".equals(cmd)) {
onSave();
} else if("Exit".equals(cmd)) {
onCloseWindow();
}
}
/**
* Invoked when a new picture is going to be created. (Menu item: File -> New)
*/
private void onNew() {
/*
* Not in the prototype version.
*/
}
@Override
public void onOpen() {
/*
* Open file chooser dialog
*/
File f = gui.showOpenFileDialog();
if(f != null) { // Can f==null happen anyway?
TikzFile file = manager.requestFile(f.getAbsolutePath());
this.file = file;
switch(file.getPictures().length) {
case 0:
JOptionPane.showMessageDialog(
gui,
"The selected file doesn't contain any decodable TikZ pictures.",
"No TikZ pictures found",
JOptionPane.WARNING_MESSAGE
);
break;
case 1:
openPicture(file.getPictures()[0]);
setChanged(true);
break;
default:
openPicture(gui.choosePicture(file));
setChanged(true);
}
}
}
/**
* Saves recent changes in the current document.
*/
@Override
public void onSave() {
//if(hasChanged) {
file.save();
setChanged(false);
//}
}
/**
* Sets the document's state.
*/
private void setChanged(boolean changeStatus) {
hasChanged = changeStatus;
gui.showStateChanged(changeStatus);
}
/**
* Opens a new picture in the current window or in a new one
* if the current window is already processing a picture.
*
* @param newPic
* new picture to be opened
*/
private void openPicture(SyntaxTikzPicture newPic) {
if(newPic != null) {
if(this.pic == null) {
this.pic = newPic;
gui.setPicture(newPic);
} else {
new MieZ(newPic);
}
}
}
private Point2D convertToTeX(MouseEvent me) {
// transform that shifts points 10 right and 20 up
//Graphics2D g2 = (Graphics2D) gui.getEditorPanel().getDrawPanel().getGraphics();
AffineTransform transformer = gui.getEditorPanel().getDrawPanel().getTransform();
Point2D.Double mousePositionUC = new Point2D.Double();
// create transform to undo the translation.
try {
// manually untransform points as above with reverse.transform( before, after ),
transformer.inverseTransform( me.getPoint(), mousePositionUC );
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
return mousePositionUC;
}
///////////////////////////////////
// Mouse(Motion)Listener implementation
///////////////////////////////////
@Override
public void mouseDragged(MouseEvent e) {
if(activeFigure != null) {
TikzFigure fig = activeFigure.getTikzFigure();
Point2D p = convertToTeX(e);
fig.moveTo(p.getX(), p.getY());
activeFigure.updateShape();
gui.repaint();
}
}
@Override
public void mouseMoved(MouseEvent e) {}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
for(Figure f : gui.getEditorPanel().getDrawPanel().getFigures()) {
boolean selected = false;
Point2D p = convertToTeX(e);
if(!selected && f.getShape().intersects(p.getX()-3, p.getY()-3,6,6)) {
activeFigure = f;
onHit(f);
selected = true;
} else {
onMiss(f);
}
}
}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
///////////////////////////////////
// FigureListener implementation
///////////////////////////////////
public void onHit(Figure f) {
f.setSelected(true);
gui.repaint();
}
public void onMiss(Figure f) {
f.setSelected(false);
gui.repaint();
}
/**
* Starts the program.
*/
public static void main(String[] args) {
WORKING_DIRECTORY = System.getProperty("user.dir");
new MieZ(null);
}
}