package GUI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
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.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.BevelBorder;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.plaf.metal.DefaultMetalTheme;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.OceanTheme;
import Core.Algorithm;
import Core.Configuration;
import Core.Schedule;
/**
* Gui is the class to construct the graphics user interface for whole application.
*
*/
public class Gui extends JFrame {
private static final long serialVersionUID = 1L;
/** The constant string that present the name of application. */
public static final String APP_NAME = "Class Scheduler";
private static final String macLnF = "com.sun.java.swing.plaf.mac.MacLookAndFeel";
private static final String metalLnF = "javax.swing.plaf.metal.MetalLookAndFeel";
private static final String motifLnF = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
private static final String windowsLnF = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
private static final String gtkLnF = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
private JFileChooser chooser;
/** The menu bar of application. */
private JMenuBar menuBar;
/** The tool bar of application. */
private JToolBar toolBar;
private TreePane treePanel;
private CalendarPane calendarPane;
private JMenuItem startItem;
private JButton startSolvingButton;
private JMenuItem stopItem;
private JButton stopSolvingButton;
private JMenuItem openFileItem;
private JButton openFileButton;
private JScrollPane umlScrollPane;
private JSplitPane splitPane;
/** The label added to update the status bar. */
private JLabel label;
private boolean _running;
private Schedule _schedule;
public Gui() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
initComponents();
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowOpened(WindowEvent e) {
}
}
);
Algorithm.GetInstance().GetObserver().SetWindow(this);
this.setTitle(APP_NAME);
}
/**
* Initializes all the components in the Gui class.
*/
private void initComponents() {
Image icon = this.getToolkit().createImage("icon\\app.png");
this.setIconImage(icon);
calendarPane = new CalendarPane();
calendarPane.setSize(calendarPane.getWidth(), calendarPane.getHeight());
calendarPane.setPreferredSize(new Dimension(calendarPane.getWidth(), calendarPane.getHeight()));
calendarPane.setBackground(Color.WHITE);
calendarPane.setAutoscrolls(true);
treePanel = new TreePane(calendarPane);
umlScrollPane = new JScrollPane(calendarPane,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, treePanel, umlScrollPane);
splitPane.setResizeWeight(0.04);
label = new JLabel();
label.setText("Press F1 for help");
getContentPane().add(label, BorderLayout.PAGE_END);
getContentPane().add(splitPane, BorderLayout.CENTER);
initBar();
this.setSize(JFrame.MAXIMIZED_HORIZ, JFrame.MAXIMIZED_VERT);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(835, 760);
this.setVisible(true);
}
/**
* Quits the application with showing a confirm dialog.
*/
private void quitApp() {
String title = "Exit - " + APP_NAME;
String message = new String("Do you want to quit?");
int option = JOptionPane.YES_NO_OPTION;
int messageType = JOptionPane.INFORMATION_MESSAGE;
option = JOptionPane.showConfirmDialog(null, message, title, option, messageType, new ImageIcon("icon\\app.png"));
if(option == JOptionPane.YES_OPTION)
System.exit(0);
}
/**
* Initializes menu bar and the tool bar.
* It will initializes all menu item and button in the tool bar and add
* action listener to them either handle these action.
*/
private void initBar() {
menuBar = new JMenuBar();
menuBar.setBorder(new BevelBorder(BevelBorder.RAISED));
toolBar = new JToolBar();
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic('f');
menuBar.add(fileMenu);
JMenu viewMenu = new JMenu("View");
viewMenu.setMnemonic('v');
menuBar.add(viewMenu);
JMenu helpMenu = new JMenu("Help");
helpMenu.setMnemonic('h');
menuBar.add(helpMenu);
JMenu lnfMenu = new JMenu("Look And Feel");
lnfMenu.setMnemonic('l');
final JMenu themeMenu = new JMenu("Metal Theme");
themeMenu.setMnemonic('t');
themeMenu.setEnabled(false);
KeyStroke startSolvingKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_MASK);
startItem = new JMenuItem("Start Solving", new ImageIcon("icon\\startItem.png"));
startItem.setAccelerator(startSolvingKeyStroke);
startItem.setMnemonic('t');
startItem.setEnabled(false);
startSolvingButton = new JButton(new ImageIcon("icon\\start.png"));
startSolvingButton.setToolTipText("Start Solving");
startSolvingButton.setEnabled(false);
KeyStroke stopSolvingKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_MASK);
stopItem = new JMenuItem("Stop Solving", new ImageIcon("icon\\stopItem.png"));
stopItem.setAccelerator(stopSolvingKeyStroke);
stopItem.setMnemonic('v');
stopItem.setEnabled(false);
stopSolvingButton = new JButton(new ImageIcon("icon\\stop.png"));
stopSolvingButton.setToolTipText("Stop Solving");
stopSolvingButton.setEnabled(false);
KeyStroke openFileKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK);
openFileItem = new JMenuItem("Open File", new ImageIcon("icon\\openItem.png"));
openFileItem.setAccelerator(openFileKeyStroke);
openFileItem.setMnemonic('o');
openFileButton = new JButton(new ImageIcon("icon\\openconfig.png"));
openFileButton.setToolTipText("Open Config File");
JMenuItem saveItem = new JMenuItem("Save", new ImageIcon("icon\\saveItem.png"));
KeyStroke saveKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK);
saveItem.setAccelerator(saveKeyStroke);
saveItem.setMnemonic('s');
JButton saveButton = new JButton(new ImageIcon("icon\\save.png"));
saveButton.setToolTipText("Save as image");
Icon exitIcon = new ImageIcon("icon\\exit.jpg");
JMenuItem exitItem = new JMenuItem("Exit", exitIcon);
KeyStroke exitKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.ALT_MASK);
exitItem.setAccelerator(exitKeyStroke);
exitItem.setMnemonic('e');
JMenuItem helpItem = new JMenuItem("Help", new ImageIcon("icon/helpItem.png"));
helpItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
helpItem.setMnemonic('h');
JButton helpButton = new JButton(new ImageIcon("icon/help.png"));
helpButton.setToolTipText("Help content");
final JCheckBoxMenuItem viewToolBarItem = new JCheckBoxMenuItem("ToolBar", true);
viewToolBarItem.setMnemonic('t');
JMenuItem macItem = new JMenuItem("Mac");
macItem.setMnemonic('M');
macItem.setEnabled(isAvailableLnF(macLnF));
JMenuItem metalItem = new JMenuItem("Metal");
metalItem.setMnemonic('e');
metalItem.setEnabled(isAvailableLnF(metalLnF));
JMenuItem motifItem = new JMenuItem("Motif");
motifItem.setMnemonic('o');
motifItem.setEnabled(isAvailableLnF(motifLnF));
JMenuItem windowsItem = new JMenuItem("Windows");
windowsItem.setMnemonic('w');
windowsItem.setEnabled(isAvailableLnF(windowsLnF));
JMenuItem gtkItem = new JMenuItem("GTK");
gtkItem.setMnemonic('g');
gtkItem.setEnabled(isAvailableLnF(gtkLnF));
JMenuItem oceanItem = new JMenuItem("Ocean");
oceanItem.setMnemonic('o');
JMenuItem defaultItem = new JMenuItem("Default");
defaultItem.setMnemonic('m');
ActionListener eventListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
new MyThread().start();
openFileItem.setEnabled(false);
openFileButton.setEnabled(false);
startSolvingButton.setEnabled(false);
startItem.setEnabled(false);
stopSolvingButton.setEnabled(true);
stopItem.setEnabled(true);
}
};
startSolvingButton.addActionListener(eventListener);
startItem.addActionListener(eventListener);
eventListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Algorithm.GetInstance().Stop();
openFileItem.setEnabled(true);
openFileButton.setEnabled(true);
startItem.setEnabled(true);
startSolvingButton.setEnabled(true);
stopItem.setEnabled(false);
stopSolvingButton.setEnabled(false);
}
};
stopSolvingButton.addActionListener(eventListener);
stopItem.addActionListener(eventListener);
eventListener = new ActionListener () {
public void actionPerformed(ActionEvent openFileEvent) {
label.setText("Opening Config File");
getContentPane().add(label, BorderLayout.PAGE_END);
openActionPerformed(openFileEvent);
}
};
openFileItem.addActionListener(eventListener);
openFileButton.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent saveAction) {
label.setText("Saving file");
getContentPane().add(label, BorderLayout.PAGE_END);
saveActionPerformed(saveAction);
}
};
saveItem.addActionListener(eventListener);
saveButton.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent exitAction) {
quitApp();
}
};
exitItem.addActionListener(eventListener);
//xu ly su kien help
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent helpEvent) {
String helpMessage = new String("Class Scheduler version 1.0\n\nLegend:\n" +
"R: Room overlapping\n" +
"S: Seats Requirement\n" +
"L: Computer Lab Requirement\n" +
"P: Professor Overlapping\n" +
"G: Student Group Overlapping\n\n" +
"Green color indicates that requirement is satisfied.\n" +
"Red color indicates that requirement is not satisfied.\n\n" +
"Hatched area indicates overlapping of classes at same time and place."
);
String title = "Help - " + APP_NAME;
int messageType = JOptionPane.INFORMATION_MESSAGE;
JOptionPane.showMessageDialog(null, helpMessage, title, messageType,
new ImageIcon("icon\\help.gif"));
}
};
helpItem.addActionListener(eventListener);
helpButton.addActionListener(eventListener);
eventListener = new ActionListener() {
@SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent e) {
if(viewToolBarItem.getState())
Gui.this.add(toolBar);
else
Gui.this.remove(toolBar);
Gui.this.repaint();
}
};
viewToolBarItem.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
createLookAndFeel(macLnF);
themeMenu.setEnabled(false);
}
};
macItem.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
createLookAndFeel(metalLnF);
themeMenu.setEnabled(true);
}
};
metalItem.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
createLookAndFeel(motifLnF);
themeMenu.setEnabled(false);
}
};
motifItem.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
createLookAndFeel(windowsLnF);
themeMenu.setEnabled(false);
}
};
windowsItem.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
createLookAndFeel(gtkLnF);
}
};
gtkItem.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
MetalLookAndFeel.setCurrentTheme(new OceanTheme());
try {
UIManager.setLookAndFeel(metalLnF);
} catch(Exception exception) {}
javax.swing.SwingUtilities.updateComponentTreeUI(Gui.this);
}
};
oceanItem.addActionListener(eventListener);
eventListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme());
try {
UIManager.setLookAndFeel(metalLnF);
}
catch (Exception exp) {}
javax.swing.SwingUtilities.updateComponentTreeUI(Gui.this);
}
};
defaultItem.addActionListener(eventListener);
fileMenu.add(openFileItem);
fileMenu.addSeparator();
fileMenu.add(startItem);
fileMenu.add(stopItem);
fileMenu.addSeparator();
fileMenu.add(saveItem);
fileMenu.addSeparator();
fileMenu.add(exitItem);
lnfMenu.add(macItem);
lnfMenu.add(metalItem);
lnfMenu.add(motifItem);
lnfMenu.add(windowsItem);
lnfMenu.add(gtkItem);
themeMenu.add(oceanItem);
themeMenu.add(defaultItem);
viewMenu.add(viewToolBarItem);
viewMenu.addSeparator();
viewMenu.add(lnfMenu);
viewMenu.add(themeMenu);
helpMenu.add(helpItem);
helpMenu.addSeparator();
setJMenuBar(menuBar);
toolBar.add(openFileButton);
toolBar.addSeparator();
toolBar.add(startSolvingButton);
toolBar.add(stopSolvingButton);
toolBar.addSeparator();
toolBar.add(saveButton);
toolBar.addSeparator();
toolBar.add(helpButton);
toolBar.addSeparator();
this.add(toolBar, BorderLayout.PAGE_START);
}
/**
* Determines whether a look and feel is supported or not
* @param lnf the look and feel need to check
* @return true if look and feel is available
*/
private boolean isAvailableLnF(String lnf) {
try {
Class lnfClass = Class.forName(lnf);
LookAndFeel newLAF = (LookAndFeel)(lnfClass.newInstance());
return newLAF.isSupportedLookAndFeel();
} catch(Exception e) {
return false;
}
}
private void openActionPerformed(ActionEvent e) {
chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setCurrentDirectory(new File("").getAbsoluteFile());
FileNameExtensionFilter filter = new FileNameExtensionFilter("cfg files", "cfg");
chooser.setFileFilter(filter);
int code = chooser.showOpenDialog(this);
if (code == JFileChooser.APPROVE_OPTION)
{
File selectedFile = chooser.getSelectedFile();
openFile(selectedFile);
}
else {
label.setText("Load file cancelled");
}
}
/**
* Opens a config file for processing.
*/
public void openFile(File selectedFile) {
try {
Configuration.GetInstance().ParseFile(selectedFile.getAbsolutePath());
treePanel.refreshTree();
label.setText("File " + selectedFile.getName() + " loaded");
startItem.setEnabled(true);
startSolvingButton.setEnabled(true);
} catch (Exception e) {
label.setText("Failed load file");
startItem.setEnabled(false);
startSolvingButton.setEnabled(false);
stopItem.setEnabled(false);
stopSolvingButton.setEnabled(false);
}
}
/**
* Saves draw panel to an image in jpg format.
* It uses a jpg filter then show an dialog for user to choose a path and then save
* current draw panel to an image.
* @param e save action event to be handled.
*/
public void saveActionPerformed(ActionEvent e) {
chooser = new JFileChooser();
FileFilter jpgFilter = new SimpleFilter("jpg", "Image Files(*.jpg)");
chooser.addChoosableFileFilter(jpgFilter);
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
int option = chooser.showSaveDialog(this);
if(option == JFileChooser.APPROVE_OPTION)
save(chooser.getSelectedFile());
label.setText("File saved");
getContentPane().add(label, BorderLayout.PAGE_END);
}
/**
* Writes all draw panel to RGB image in jpg format.
* @param f File used to save the image.
*/
public void save(File f) {
try {
BufferedImage img = new BufferedImage(699, 862, BufferedImage.TYPE_INT_RGB);
Graphics image = img.getGraphics();
calendarPane.paint(image);
ImageIO.write(img, "jpg", f);
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* Set a given look and feel if available
* @param lnf the look and feel that want to set
*/
private void createLookAndFeel(String lnf) {
try {
UIManager.setLookAndFeel(lnf);
} catch(Exception exception) {}
javax.swing.SwingUtilities.updateComponentTreeUI(this);
}
class MyThread extends Thread
{
@Override
public void run()
{
Algorithm.GetInstance().Start();
}
};
public void SetSchedule(Schedule schedule)
{
synchronized(this)
{
_schedule = schedule.MakeCopy(false);
String fit = String.format( "Fitness: %f, Generation: %d", _schedule.GetFitness(),
Algorithm.GetInstance().GetCurrentGeneration());
label.setText(fit);
calendarPane.SetSchedule(_schedule);
}
}
public void SetNewState(Algorithm.AlgorithmState state) {
_running = false;
switch(state) {
case AS_CRITERIA_STOPPED:
case AS_USER_STOPED:
openFileItem.setEnabled(true);
openFileButton.setEnabled(true);
startItem.setEnabled(true);
startSolvingButton.setEnabled(true);
stopItem.setEnabled(false);
stopSolvingButton.setEnabled(false);
break;
case AS_RUNNING:
calendarPane.resizePanel();
_running = true;
break;
}
}
}