/*
* Copyright (C) 2010-2012 Klaus Reimer <k@ailis.de>
* See LICENSE.TXT for licensing information.
*/
package de.ailis.xadrian.frames;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.MenuElement;
import javax.swing.SwingConstants;
import javax.swing.TransferHandler;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import de.ailis.xadrian.actions.AboutAction;
import de.ailis.xadrian.actions.AddFactoryAction;
import de.ailis.xadrian.actions.ChangePricesAction;
import de.ailis.xadrian.actions.ChangeSectorAction;
import de.ailis.xadrian.actions.ChangeSunsAction;
import de.ailis.xadrian.actions.CloseAction;
import de.ailis.xadrian.actions.CloseAllAction;
import de.ailis.xadrian.actions.CopyAction;
import de.ailis.xadrian.actions.DonateAction;
import de.ailis.xadrian.actions.ExitAction;
import de.ailis.xadrian.actions.ExportASCIIAction;
import de.ailis.xadrian.actions.ExportTemplateCodeAction;
import de.ailis.xadrian.actions.ForumAction;
import de.ailis.xadrian.actions.GithubAction;
import de.ailis.xadrian.actions.GooglePlusAction;
import de.ailis.xadrian.actions.HomepageAction;
import de.ailis.xadrian.actions.ImportTemplateCodeAction;
import de.ailis.xadrian.actions.NewAction;
import de.ailis.xadrian.actions.OpenAction;
import de.ailis.xadrian.actions.PreferencesAction;
import de.ailis.xadrian.actions.PrintAction;
import de.ailis.xadrian.actions.SaveAction;
import de.ailis.xadrian.actions.SaveAllAction;
import de.ailis.xadrian.actions.SaveAsAction;
import de.ailis.xadrian.actions.SelectAllAction;
import de.ailis.xadrian.actions.ToggleBaseComplexAction;
import de.ailis.xadrian.actions.TwitterAction;
import de.ailis.xadrian.components.ComplexEditor;
import de.ailis.xadrian.components.SocialPane;
import de.ailis.xadrian.data.Complex;
import de.ailis.xadrian.data.Game;
import de.ailis.xadrian.data.Sector;
import de.ailis.xadrian.data.factories.GameFactory;
import de.ailis.xadrian.dialogs.AboutDialog;
import de.ailis.xadrian.dialogs.OpenComplexDialog;
import de.ailis.xadrian.dialogs.PreferencesDialog;
import de.ailis.xadrian.dialogs.SelectGameDialog;
import de.ailis.xadrian.interfaces.ClipboardProvider;
import de.ailis.xadrian.interfaces.ComplexProvider;
import de.ailis.xadrian.interfaces.GameProvider;
import de.ailis.xadrian.interfaces.SectorProvider;
import de.ailis.xadrian.listeners.ClipboardStateListener;
import de.ailis.xadrian.listeners.EditorStateListener;
import de.ailis.xadrian.listeners.MainStateListener;
import de.ailis.xadrian.listeners.StateListener;
import de.ailis.xadrian.resources.Images;
import de.ailis.xadrian.support.ComplexTransferHandler;
import de.ailis.xadrian.support.Config;
import de.ailis.xadrian.support.I18N;
import de.ailis.xadrian.support.ModalDialog.Result;
import de.ailis.xadrian.utils.FileUtils;
/**
* The main frame.
*
* @author Klaus Reimer (k@ailis.de)
*/
public class MainFrame extends JFrame implements EditorStateListener,
ChangeListener, ClipboardProvider, ClipboardStateListener,
ComplexProvider, SectorProvider, StateListener, GameProvider
{
/** Serial version UID */
private static final long serialVersionUID = 7989554637240491666L;
/** The logger. */
private static final Log LOG = LogFactory.getLog(MainFrame.class);
/** The event listener list */
private final EventListenerList listenerList = new EventListenerList();
/** The "exit" action */
private final Action exitAction = new ExitAction(this);
/** The "new" action */
private final Action newAction = new NewAction(this);
/** The "open" action */
private final Action openAction = new OpenAction(this);
/** The "close" action */
private final Action closeAction = new CloseAction(this);
/** The "close all" action */
private final Action closeAllAction = new CloseAllAction(this);
/** The "save" action */
private final Action saveAction = new SaveAction(this);
/** The "save as" action */
private final Action saveAsAction = new SaveAsAction(this);
/** The "Export ASCIIe" action */
private final Action exportASCIIAction =
new ExportASCIIAction(this);
/** The "Export Template Code" action */
private final Action exportTemplateCodeAction =
new ExportTemplateCodeAction(this);
/** The "Import Template Code" action */
private final Action importTemplateCodeAction =
new ImportTemplateCodeAction(this);
/** The "save all" action */
private final Action saveAllAction = new SaveAllAction(this);
/** The "print" action */
private final Action printAction = new PrintAction(this);
/** The "about" action */
private final Action aboutAction = new AboutAction(this);
/** The "donate" action */
private final Action donateAction = new DonateAction();
/** The "homepage" action */
private final Action homepageAction = new HomepageAction();
/** The "forum" action */
private final Action forumAction = new ForumAction();
/** The "googlePlus" action */
private final Action googlePlusAction = new GooglePlusAction();
/** The "twitter" action */
private final Action twitterAction = new TwitterAction();
/** The "github" action */
private final Action githubAction = new GithubAction();
/** The "preferences" action */
private final Action preferencesAction = new PreferencesAction(this);
/** The "addFactory" action */
private final Action addFactoryAction = new AddFactoryAction(this);
/** The "changeSuns" action */
private final Action changeSunsAction = new ChangeSunsAction(this);
/** The "changeSector" action */
private final Action changeSectorAction = new ChangeSectorAction(this,
this, "complex");
/** The "changePrices" action */
private final Action changePricesAction = new ChangePricesAction(this);
/** The "select all" action */
private final Action selectAllAction = new SelectAllAction(this);
/** The "toggleBaseComplex" action */
private final Action toggleBaseComplexAction =
new ToggleBaseComplexAction(this);
/** The tabbed pane. */
private JTabbedPane tabs;
/** The welcome panel. */
private JPanel welcomePanel;
/** The status bar. */
private JLabel statusBar;
/** The transfer handler for dropping complex files into Xadrian. */
private final TransferHandler transferHandler = new ComplexTransferHandler(this);
/** The unprocessed files specified on the command line. */
private static List<File> unprocessedFiles = new ArrayList<File>();
/** The singleton instance . */
private static MainFrame instance;
/**
* Constructor
*/
public MainFrame()
{
setTitle(I18N.getString("title"));
setName("mainFrame");
setIconImages(Images.LOGOS);
setPreferredSize(new Dimension(960, 700));
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(final WindowEvent e)
{
exit();
}
});
createStatusBar();
createMenuBar();
createToolBar();
createContent();
setTransferHandler(this.transferHandler);
pack();
Config.restoreWindowState(this);
this.tabs.requestFocus();
}
/**
* Creates the menu.
*/
private void createMenuBar()
{
// Create the menu bar
final JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
// Create the 'File' menu
final JMenu fileMenu = I18N.createMenu(menuBar, "file");
fileMenu.add(this.newAction);
fileMenu.add(this.openAction);
fileMenu.addSeparator();
fileMenu.add(this.closeAction);
fileMenu.add(this.closeAllAction);
fileMenu.addSeparator();
fileMenu.add(this.saveAction);
fileMenu.add(this.saveAsAction);
fileMenu.add(this.saveAllAction);
fileMenu.addSeparator();
fileMenu.add(this.printAction);
fileMenu.addSeparator();
final JMenu exportMenu = I18N.createMenu(fileMenu, "export");
exportMenu.add(this.exportASCIIAction);
exportMenu.add(this.exportTemplateCodeAction);
final JMenu importMenu = I18N.createMenu(fileMenu, "import");
importMenu.add(this.importTemplateCodeAction);
fileMenu.addSeparator();
fileMenu.add(this.exitAction);
// Create the 'Edit' menu
final JMenu editMenu = I18N.createMenu(menuBar, "edit");
editMenu.add(new CopyAction(this));
editMenu.add(this.selectAllAction);
editMenu.addSeparator();
editMenu.add(this.preferencesAction);
// Create the 'Complex' menu
final JMenu complexMenu = I18N.createMenu(menuBar, "complex");
complexMenu.add(this.addFactoryAction);
complexMenu.add(this.changeSectorAction);
complexMenu.add(this.changeSunsAction);
complexMenu.add(this.changePricesAction);
complexMenu.add(new JCheckBoxMenuItem(this.toggleBaseComplexAction));
// Create the 'Help' menu
final JMenu helpMenu = I18N.createMenu(menuBar, "help");
helpMenu.add(this.donateAction);
helpMenu.addSeparator();
helpMenu.add(this.homepageAction);
helpMenu.add(this.forumAction);
helpMenu.add(this.twitterAction);
helpMenu.add(this.googlePlusAction);
helpMenu.add(this.githubAction);
helpMenu.addSeparator();
helpMenu.add(this.aboutAction);
installStatusHandler(menuBar);
}
/**
* Creates the tool bar.
*/
private void createToolBar()
{
final JToolBar toolBar = new JToolBar(SwingConstants.HORIZONTAL);
toolBar.setFloatable(false);
toolBar.setRollover(true);
toolBar.add(this.exitAction);
toolBar.addSeparator();
toolBar.add(this.newAction);
toolBar.add(this.openAction);
toolBar.add(this.closeAction);
toolBar.add(this.saveAction);
toolBar.add(this.printAction);
toolBar.addSeparator();
toolBar.add(this.addFactoryAction);
toolBar.add(this.changeSectorAction);
toolBar.add(this.changeSunsAction);
toolBar.add(this.changePricesAction);
final JToggleButton btn =
new JToggleButton(this.toggleBaseComplexAction);
btn.setHideActionText(true);
toolBar.add(btn);
add(toolBar, BorderLayout.NORTH);
installStatusHandler(toolBar);
}
/**
* Creates the content.
*/
private void createContent()
{
this.tabs = new JTabbedPane();
this.tabs.setPreferredSize(new Dimension(640, 480));
this.tabs.addChangeListener(this);
this.tabs.setTransferHandler(this.transferHandler);
final JPanel welcomePanel = this.welcomePanel = new JPanel();
welcomePanel.setTransferHandler(this.transferHandler);
welcomePanel.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
welcomePanel.setPreferredSize(new Dimension(640, 480));
final JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridBagLayout());
c.anchor = GridBagConstraints.CENTER;
welcomePanel.add(buttonPanel, c);
final JButton newButton = new JButton(this.newAction);
newButton.setHorizontalAlignment(SwingConstants.LEFT);
newButton.setIconTextGap(10);
newButton.setText("<html><body><strong>" + newButton.getText() +
"</strong><br />" + newButton.getToolTipText() + "</body></html>");
newButton.setToolTipText(null);
newButton.setMargin(new Insets(5, 10, 5, 10));
c.gridy = 0;
c.fill = GridBagConstraints.BOTH;
c.insets.set(5, 5, 5, 5);
buttonPanel.add(newButton, c);
final JButton openButton = new JButton(this.openAction);
openButton.setHorizontalAlignment(SwingConstants.LEFT);
openButton.setIconTextGap(10);
openButton.setText("<html><body><strong>" + openButton.getText() +
"</strong><br />" + openButton.getToolTipText() + "</body></html>");
openButton.setToolTipText(null);
openButton.setMargin(new Insets(5, 10, 5, 10));
c.gridy++;
buttonPanel.add(openButton, c);
final JPanel separator = new JPanel();
separator.setPreferredSize(new Dimension(20, 20));
c.gridy++;
buttonPanel.add(separator, c);
final JButton donateButton = new JButton(this.donateAction);
donateButton.setHorizontalAlignment(SwingConstants.LEFT);
donateButton.setIconTextGap(10);
donateButton.setText("<html><body><strong>" + donateButton.getText() +
"</strong><br />" + donateButton.getToolTipText() +
"</body></html>");
donateButton.setToolTipText(null);
donateButton.setMargin(new Insets(5, 10, 5, 10));
c.gridy++;
buttonPanel.add(donateButton, c);
final SocialPane socialPane = new SocialPane();
c.insets.top = 50;
c.gridy++;
buttonPanel.add(socialPane, c);
installStatusHandler(buttonPanel);
add(welcomePanel, BorderLayout.CENTER);
}
/**
* Creates the status bar.
*/
private void createStatusBar()
{
final JLabel statusBar = this.statusBar = new JLabel(" ");
statusBar.setBorder(new EmptyBorder(2, 5, 2, 5));
add(statusBar, BorderLayout.SOUTH);
addWindowFocusListener(new WindowAdapter()
{
@Override
public void windowLostFocus(final WindowEvent e)
{
statusBar.setText(" ");
}
});
}
/**
* Installs status handler for the specified component an all its child
* components.
*
* @param component
* The component to install the status handler for.
*/
private void installStatusHandler(final JComponent component)
{
final JLabel statusBar = this.statusBar;
final String text = component.getToolTipText();
if (text != null && !text.isEmpty())
{
component.addMouseListener(new MouseAdapter()
{
@Override
public void mouseExited(final MouseEvent e)
{
statusBar.setText(" ");
}
@Override
public void mouseEntered(final MouseEvent e)
{
statusBar.setText(component.getToolTipText());
}
});
}
for (final Component child: component.getComponents())
{
if (!(child instanceof JComponent)) continue;
installStatusHandler((JComponent) child);
}
if (component instanceof JMenu)
{
for (final MenuElement menuElement: ((JMenu) component)
.getSubElements())
{
if (!(menuElement instanceof JComponent)) continue;
installStatusHandler((JComponent) menuElement);
}
}
}
/**
* Adds a state listener.
*
* @param listener
* The state listener to add
*/
public void addStateListener(final MainStateListener listener)
{
this.listenerList.add(MainStateListener.class, listener);
}
/**
* Removes a state listener.
*
* @param listener
* The state listener to remove
*/
public void removeStateListener(final MainStateListener listener)
{
this.listenerList.remove(MainStateListener.class, listener);
}
/**
* Fire the state change event.
*/
private void fireChange()
{
final Object[] listeners = this.listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2)
if (listeners[i] == MainStateListener.class)
((MainStateListener) listeners[i + 1]).mainStateChanged(this);
changeState();
fireClipboardState();
}
/**
* Creates a new factory complex tab
*/
public void createComplexTab()
{
// Try to read game from the configuration
final Config config = Config.getInstance();
final String defaultGameId = config.getDefaultGame();
final GameFactory gameFactory = GameFactory.getInstance();
Game game = defaultGameId == null ||
!gameFactory.hasGame(defaultGameId) ? null
: gameFactory.getGame(defaultGameId);
// If no default game is set then ask for it
if (game == null)
{
final SelectGameDialog dialog = SelectGameDialog.getInstance();
if (dialog.open() != Result.OK) return;
game = dialog.getGame();
if (dialog.isRemember()) config.setDefaultGame(game.getId());
}
createComplexTab(new ComplexEditor(new Complex(game)));
}
/**
* Creates a new factory complex tab with the specified complex editor in
* it.
*
* @param editor
* The complex editor
*/
private void createComplexTab(final ComplexEditor editor)
{
// Replace the welcome panel with the complex tab control
remove(this.welcomePanel);
add(this.tabs, BorderLayout.CENTER);
editor.setTransferHandler(this.transferHandler);
this.tabs.addTab(editor.getComplex().getName(), editor);
this.tabs.setSelectedComponent(editor);
editor.addStateListener((EditorStateListener) this);
editor.addStateListener((StateListener) this);
editor.addClipboardStateListener(this);
fireChange();
}
/**
* Creates a complex editor tab with a loaded complex.
*
* @param editor
* The complex editor
*/
public void createLoadedComplexTab(final ComplexEditor editor)
{
// If current tab is new then close this one in favor of the new one
final Component current = getCurrentTab();
if (current != null && current instanceof ComplexEditor
&& ((ComplexEditor) current).isNew()) closeCurrentTab();
createComplexTab(editor);
}
/**
* Returns the current tab component or null if no tab is currently present.
*
* @return The current tab component
*/
public Component getCurrentTab()
{
return this.tabs == null ? null : this.tabs.getSelectedComponent();
}
/**
* Closes the current tab. Prompts for saving unsaved changes before
* closing. Returns true if the tab was closed or false if it was not
* closed.
*
* @return True if tab was closed, false if not
*/
public boolean closeCurrentTab()
{
final Component current = getCurrentTab();
if (current != null)
{
final ComplexEditor editor = (ComplexEditor) current;
if (editor.isChanged())
{
final int answer =
JOptionPane.showConfirmDialog(null, I18N
.getString("confirm.saveChanges", editor.getComplex()
.getName()), I18N.getTitle("confirm.saveChanges"),
JOptionPane.YES_NO_CANCEL_OPTION);
if (answer == JOptionPane.CLOSED_OPTION) return false;
if (answer == JOptionPane.CANCEL_OPTION) return false;
if (answer == JOptionPane.YES_OPTION)
{
editor.save();
if (editor.isChanged()) return false;
}
}
this.tabs.remove(current);
// Replace the tab control with the welcome panel if no tabs present
if (this.tabs.getTabCount() == 0)
{
remove(this.tabs);
add(this.welcomePanel, BorderLayout.CENTER);
repaint();
}
fireChange();
return true;
}
return false;
}
/**
* Closes all open tabs. Prompts for unsaved changes. Returns true if all
* tabs have been closed or false if at least one tab was not closed.
*
* @return True if all tabs were closed, false if not.
*/
public boolean closeAllTabs()
{
while (this.tabs.getComponentCount() > 0)
if (!closeCurrentTab()) return false;
fireChange();
return true;
}
/**
* Shows the about dialog.
*/
public void about()
{
AboutDialog.getInstance().open();
}
/**
* Shows the preferences dialog.
*/
public void preferences()
{
if (PreferencesDialog.getInstance().open() == Result.OK)
{
for (final Component component: getTabs().getComponents())
{
if (component instanceof ComplexEditor)
{
final ComplexEditor editor = (ComplexEditor) component;
editor.updateBaseComplex();
}
}
}
}
/**
* Returns the tabs.
*
* @return The tabs
*/
public JTabbedPane getTabs()
{
return this.tabs;
}
/**
* @see de.ailis.xadrian.listeners.EditorStateListener#editorStateChanged(de.ailis.xadrian.components.ComplexEditor)
*/
@Override
public void editorStateChanged(final ComplexEditor sender)
{
final int index = this.tabs.indexOfComponent(sender);
this.tabs.setTitleAt(index, sender.getComplex().getName()
+ (sender.isChanged() ? "*" : ""));
fireChange();
}
/**
* @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
*/
@Override
public void stateChanged(final ChangeEvent e)
{
fireChange();
}
/**
* Exits the application. Prompts for saving unsaved changes before that.
*/
public void exit()
{
if (closeAllTabs())
{
Config.saveWindowState(this);
Config.getInstance().save();
System.exit(0);
}
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#canCopy()
*/
@Override
public boolean canCopy()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ClipboardProvider)) return false;
return ((ClipboardProvider) tab).canCopy();
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#canCut()
*/
@Override
public boolean canCut()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ClipboardProvider)) return false;
return ((ClipboardProvider) tab).canCut();
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#canPaste()
*/
@Override
public boolean canPaste()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ClipboardProvider)) return false;
return ((ClipboardProvider) tab).canPaste();
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#copy()
*/
@Override
public void copy()
{
((ClipboardProvider) getCurrentTab()).copy();
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#cut()
*/
@Override
public void cut()
{
((ClipboardProvider) getCurrentTab()).cut();
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#paste()
*/
@Override
public void paste()
{
((ClipboardProvider) getCurrentTab()).paste();
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#addClipboardStateListener(de.ailis.xadrian.listeners.ClipboardStateListener)
*/
@Override
public void
addClipboardStateListener(final ClipboardStateListener listener)
{
this.listenerList.add(ClipboardStateListener.class, listener);
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#removeClipboardStateListener(de.ailis.xadrian.listeners.ClipboardStateListener)
*/
@Override
public void removeClipboardStateListener(
final ClipboardStateListener listener)
{
this.listenerList.remove(ClipboardStateListener.class, listener);
}
/**
* Fire the clipboard state event.
*/
private void fireClipboardState()
{
final Object[] listeners = this.listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2)
if (listeners[i] == ClipboardStateListener.class)
((ClipboardStateListener) listeners[i + 1])
.clipboardStateChanged(this);
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#selectAll()
*/
@Override
public void selectAll()
{
((ClipboardProvider) getCurrentTab()).selectAll();
}
/**
* @see de.ailis.xadrian.listeners.ClipboardStateListener#clipboardStateChanged(de.ailis.xadrian.interfaces.ClipboardProvider)
*/
@Override
public void clipboardStateChanged(final ClipboardProvider provider)
{
fireClipboardState();
}
/**
* @see de.ailis.xadrian.interfaces.ClipboardProvider#canSelectAll()
*/
@Override
public boolean canSelectAll()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ClipboardProvider)) return false;
return ((ClipboardProvider) tab).canSelectAll();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#addFactory()
*/
@Override
public void addFactory()
{
((ComplexProvider) getCurrentTab()).addFactory();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#canAddFactory()
*/
@Override
public boolean canAddFactory()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ComplexProvider)) return false;
return ((ComplexProvider) tab).canAddFactory();
}
/**
* @see de.ailis.xadrian.listeners.StateListener#stateChanged()
*/
@Override
public void stateChanged()
{
changeState();
}
/**
* Fire the state change event.
*/
private void changeState()
{
final Object[] listeners = this.listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2)
if (listeners[i] == StateListener.class)
((StateListener) listeners[i + 1])
.stateChanged();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#canChangeSuns()
*/
@Override
public boolean canChangeSuns()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ComplexProvider)) return false;
return ((ComplexProvider) tab).canChangeSuns();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#canToggleBaseComplex()
*/
@Override
public boolean canToggleBaseComplex()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ComplexProvider)) return false;
return ((ComplexProvider) tab).canToggleBaseComplex();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#changeSuns()
*/
@Override
public void changeSuns()
{
((ComplexProvider) getCurrentTab()).changeSuns();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#toggleBaseComplex()
*/
@Override
public void toggleBaseComplex()
{
((ComplexProvider) getCurrentTab()).toggleBaseComplex();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#isAddBaseComplex()
*/
@Override
public boolean isAddBaseComplex()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ComplexProvider)) return false;
return ((ComplexProvider) tab).isAddBaseComplex();
}
/**
* @see ComplexProvider#canChangeSector()
*/
@Override
public boolean canChangeSector()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ComplexProvider)) return false;
return ((ComplexProvider) tab).canChangeSector();
}
/**
* @see ComplexProvider#changeSector()
*/
@Override
public void changeSector()
{
((ComplexProvider) getCurrentTab()).changeSector();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#canChangePrices()
*/
@Override
public boolean canChangePrices()
{
final Component tab = getCurrentTab();
if (tab == null) return false;
if (!(tab instanceof ComplexProvider)) return false;
return ((ComplexProvider) tab).canChangePrices();
}
/**
* @see de.ailis.xadrian.interfaces.ComplexProvider#changePrices()
*/
@Override
public void changePrices()
{
((ComplexProvider) getCurrentTab()).changePrices();
}
/**
* @see de.ailis.xadrian.interfaces.StateProvider#addStateListener(de.ailis.xadrian.listeners.StateListener)
*/
@Override
public void addStateListener(final StateListener listener)
{
this.listenerList.add(StateListener.class, listener);
}
/**
* @see de.ailis.xadrian.interfaces.StateProvider#removeStateListener(de.ailis.xadrian.listeners.StateListener)
*/
@Override
public void removeStateListener(final StateListener listener)
{
this.listenerList.remove(StateListener.class, listener);
}
/**
* @see de.ailis.xadrian.interfaces.SectorProvider#getSector()
*/
@Override
public Sector getSector()
{
return ((SectorProvider) getCurrentTab()).getSector();
}
/**
* @see de.ailis.xadrian.interfaces.SectorProvider#setSector(de.ailis.xadrian.data.Sector)
*/
@Override
public void setSector(final Sector sector)
{
((SectorProvider) getCurrentTab()).setSector(sector);
}
/**
* @see de.ailis.xadrian.interfaces.GameProvider#getGame()
*/
@Override
public Game getGame()
{
return ((GameProvider) getCurrentTab()).getGame();
}
/**
* Opens the specified files. If the main frame is already started then the
* files are opened right away. Otherwise the file names are queued for
* later processing.
*
* @param directory
* The directory from which to open the files. Needed to resolve
* relative file names.
* @param fileNames
* The names of the files to open.
*/
public static void open(final File directory, final String... fileNames)
{
synchronized (unprocessedFiles)
{
for (final String fileName: fileNames)
{
File file = new File(fileName);
if (!file.isAbsolute())
file = new File(directory, fileName);
if (instance == null)
unprocessedFiles.add(file);
else
instance.open(file);
}
}
// If main frame is already open then do lot of stuff to try to get
// it into the foreground.
if (instance != null)
{
instance.setExtendedState(Frame.NORMAL);
instance.toFront();
instance.requestFocus();
instance.setVisible(true);
}
}
/**
* Starts the main frame.
*
* @param fileNames
* The file names specified on the command line.
*/
public static void start(final String[] fileNames)
{
synchronized (unprocessedFiles)
{
instance = new MainFrame();
for (final File file: unprocessedFiles)
instance.open(file);
unprocessedFiles.clear();
for (final String fileName: fileNames)
{
final File file = new File(fileName);
instance.open(file);
}
}
instance.setVisible(true);
}
/**
* Prompts for a file name and opens this complex file.
*/
public void open()
{
final OpenComplexDialog dialog = OpenComplexDialog.getInstance();
final File file = dialog.open();
if (file != null) open(file);
}
/**
* Imports a new complex from the specified template code.
*
* @param templateCode
* The template code to import.
*/
public void importFromTemplateCode(final String templateCode)
{
final Complex complex = Complex.fromTemplateCode(templateCode);
final ComplexEditor editor = new ComplexEditor(complex);
createLoadedComplexTab(editor);
}
/**
* Returns the complex editor for the specified file. If no complex editor
* is open for this file then null is returned.
*
* @param file
* The file
* @return The complex editor or null if none is open for this file.
*/
public ComplexEditor getEditor(final File file)
{
for (int i = this.tabs.getTabCount() - 1; i >= 0; i -= 1)
{
final Component component = this.tabs.getComponentAt(i);
if (!(component instanceof ComplexEditor)) continue;
final ComplexEditor editor = (ComplexEditor) component;
final File editorFile = editor.getFile();
if (editorFile == null) continue;
try
{
if (file.getCanonicalFile().equals(
editorFile.getCanonicalFile()))
return editor;
}
catch (final IOException e)
{
if (file.equals(editorFile)) return editor;
}
}
return null;
}
/**
* Reads a new complex from the specified file and returns the complex
* editor or null if an error occurred while reading the file.
*
* @param file
* The file to open.
*/
public void open(final File file)
{
// Select already open editor if possible
ComplexEditor editor = getEditor(file);
if (editor != null)
{
this.tabs.setSelectedComponent(editor);
return;
}
try
{
final SAXReader reader = new SAXReader();
final Document document = reader.read(file);
final Complex complex = Complex.fromXML(document);
complex.setName(FileUtils.getNameWithoutExt(file));
editor = new ComplexEditor(complex, file);
createLoadedComplexTab(editor);
}
catch (final DocumentException e)
{
JOptionPane.showMessageDialog(null, I18N.getString(
"error.cantReadComplex", file, e.getMessage()), I18N
.getString("error.title"), JOptionPane.ERROR_MESSAGE);
LOG.error("Unable to load complex from file '" + file + "': "
+ e, e);
}
}
}