/*
* Copyright (c) 2010-2011 by Stefan Laubenberger.
*
* Tyr is free software: you can redistribute it and/or modify
* it under the terms of the General Public License v2.0.
*
* Tyr 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:
* <http://www.gnu.org/licenses>
*
* This distribution is available at:
* <http://code.google.com/p/tyr/>
* <http://dev.laubenberger.net/tyr/>
*
* Contact information:
* Stefan Laubenberger
* Bullingerstrasse 53
* CH-8004 Zuerich
*
* <http://www.laubenberger.net>
*
* <laubenberger@gmail.com>
*/
package net.laubenberger.tyr.view;
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.SystemTray;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Observable;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import net.laubenberger.bogatyr.helper.HelperCollection;
import net.laubenberger.bogatyr.helper.HelperLog;
import net.laubenberger.bogatyr.helper.HelperObject;
import net.laubenberger.bogatyr.helper.HelperString;
import net.laubenberger.bogatyr.helper.HelperSwing;
import net.laubenberger.bogatyr.model.misc.Language;
import net.laubenberger.bogatyr.service.localizer.Localizer;
import net.laubenberger.bogatyr.service.property.Property;
import net.laubenberger.bogatyr.view.ViewAbstract;
import net.laubenberger.bogatyr.view.swing.ActionAbstract;
import net.laubenberger.bogatyr.view.swing.Dialog;
import net.laubenberger.bogatyr.view.swing.Frame;
import net.laubenberger.bogatyr.view.swing.Menu;
import net.laubenberger.bogatyr.view.swing.MenuItem;
import net.laubenberger.bogatyr.view.swing.MenuItemRadioButton;
import net.laubenberger.bogatyr.view.swing.PopupMenu;
import net.laubenberger.bogatyr.view.swing.TrayIcon;
import net.laubenberger.bogatyr.view.swing.worker.Worker;
import net.laubenberger.tyr.Tyr;
import net.laubenberger.tyr.controller.ControllerTyr;
import net.laubenberger.tyr.helper.HelperResource;
import net.laubenberger.tyr.misc.ScalableIcon;
import net.laubenberger.tyr.misc.ScalableIconImpl;
import net.laubenberger.tyr.misc.WrapperFontSet;
import net.laubenberger.tyr.model.Icon;
import net.laubenberger.tyr.model.TyrData;
import net.laubenberger.tyr.view.dialog.DialogAbout;
import net.laubenberger.tyr.view.dialog.DialogHelp;
import net.laubenberger.tyr.view.dialog.DialogTask;
import org.jdesktop.swingx.JXTitledSeparator;
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
import org.pushingpixels.substance.api.SubstanceSkin;
import org.pushingpixels.substance.api.fonts.FontPolicy;
import org.pushingpixels.substance.api.fonts.FontSet;
import org.pushingpixels.substance.api.skin.SkinInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The implementation of the {@link Tyr} view.
*
* @author Stefan Laubenberger
* @version 0.8.5 (20110214)
* @since 0.2.0
*/
public class ViewTyrImpl extends ViewAbstract implements ViewTyr {
static final Logger log = LoggerFactory.getLogger(ViewTyrImpl.class);
// Identifier
private static final String ID_SUBSTANCE_NS = "org.pushingpixels.substance.api.skin"; //$NON-NLS-1$
final ControllerTyr controller;
final TyrData data;
final Property property;
final Localizer localizer;
final JFrame owner;
final JPopupMenu popup = new PopupMenu();
final TrayIcon trayIcon;
final DialogTask dialogTask;
final Dialog dialogHelp;
final Dialog dialogAbout;
public ViewTyrImpl(final ControllerTyr controller) {
super();
if (log.isTraceEnabled()) log.trace(HelperLog.constructor(controller));
this.controller = controller;
data = controller.getData();
property = controller.getModel().getProperty();
localizer = controller.getModel().getLocalizer();
owner = new Frame(controller.getModel().getName(), Icon.LOGO.getIcon());
trayIcon = new TrayIcon(Icon.LOGO.getIcon(), controller.getModel().getName() + HelperString.SPACE
+ controller.getModel().getVersion(), popup);
dialogHelp = new DialogHelp(this);
dialogAbout = new DialogAbout(this);
dialogTask = new DialogTask(this);
}
/*
* Private methods
*/
private void createTrayIcon() {
if (log.isTraceEnabled()) log.trace(HelperLog.methodStart());
if (SystemTray.isSupported()) {
final SystemTray tray = SystemTray.getSystemTray();
try {
tray.add(trayIcon);
} catch (AWTException ex) {
log.error("TrayIcon could not be added", ex); //$NON-NLS-1$
controller.exit(61);
}
} else {
log.error("System Tray is not supported"); //$NON-NLS-1$
controller.exit(60);
}
if (log.isTraceEnabled()) log.trace(HelperLog.methodExit());
}
private void createMenu() {
if (log.isTraceEnabled()) log.trace(HelperLog.methodStart());
popup.removeAll();
final List<JMenu> menuItems = controller.getControllerModule().getMenuItems();
if (null == menuItems) {
final JMenuItem mi = new MenuItem(localizer.getValue(HelperResource.RES_LABEL_MODULES_NOT_FOUND), controller.getScaledIcon(Icon.ALERT));
mi.setEnabled(false);
popup.add(mi);
} else if (menuItems.isEmpty()) {
final JMenuItem mi = new MenuItem(localizer.getValue(HelperResource.RES_LABEL_MODULES_NOT_ACTIVE), controller.getScaledIcon(Icon.ALERT));
mi.setEnabled(false);
popup.add(mi);
} else {
for (final JMenu menu : menuItems) {
popup.add(menu);
}
}
popup.addSeparator();
// popup.add(getMenuTyr());
popup.add(getMenuLanguage());
popup.add(getMenuLookAndFeel());
popup.add(getMenuFontSize());
popup.add(getMenuIconSize());
popup.addSeparator();
popup.add(new ActionHelp());
popup.add(new ActionAbout());
popup.addSeparator();
popup.add(new ActionExit());
if (log.isTraceEnabled()) log.trace(HelperLog.methodExit());
}
// private JComponent getMenuTyr() {
// if (log.isTraceEnabled()) log.trace(HelperLog.methodStart());
//
//
// final JMenu result = new Menu(localizer.getValue(HelperResource.RES_ACTION_TYR), controller.getScaledIcon(Icon.PREFERENCES),
// localizer.getTooltip(HelperResource.RES_ACTION_TYR), localizer.getMnemonic(HelperResource.RES_ACTION_TYR));
//
//// result.add(new ActionModule());
//// result.addSeparator();
// result.add(getMenuLanguage());
// result.add(getMenuLookAndFeel());
// result.add(getMenuFontSize());
// result.add(getMenuIconSize());
// result.addSeparator();
// result.add(new ActionHelp());
// result.addSeparator();
// result.add(new ActionAbout());
////
//// result.s
////
//// JScrollPane result2 = new PaneScroll(result);
//
// if (log.isTraceEnabled()) log.trace(HelperLog.methodExit(result));
// return result;
// }
private JMenu getMenuLanguage() {
if (log.isTraceEnabled()) log.trace(HelperLog.methodStart());
final JMenu result = new Menu(localizer.getValue(HelperResource.RES_ACTION_LOCALE), controller.getScaledIcon(Icon.LOCALE),
localizer.getTooltip(HelperResource.RES_ACTION_LOCALE), localizer.getMnemonic(HelperResource.RES_ACTION_LOCALE));
final ButtonGroup group = new ButtonGroup();
final List<Language> list = localizer.getAvailableLanguages();
Collections.sort(list, new Comparator<Language>() {
@Override
public int compare(final Language arg0, final Language arg1) {
return arg0.getName(localizer.getLocale()).compareTo(arg1.getName(localizer.getLocale()));
}
});
for (final Language language : list) {
final JMenuItem item = new MenuItemRadioButton(language.getName(localizer.getLocale()));
item.setIcon(controller.getScaledIcon(new ScalableIconImpl(language.getIcon())));
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
localizer.setLocale(language.getLocale());
data.setLanguage(language);
}
});
item.setSelected(HelperObject
.isEquals(localizer.getLocale().getLanguage(), language.getLocale().getLanguage()));
result.add(item);
group.add(item);
}
if (log.isTraceEnabled()) log.trace(HelperLog.methodExit(result));
return result;
}
private JMenu getMenuLookAndFeel() {
if (log.isTraceEnabled()) log.trace(HelperLog.methodStart());
final JMenu result = new Menu(localizer.getValue(HelperResource.RES_ACTION_LAF), controller.getScaledIcon(Icon.LAF), localizer
.getTooltip(HelperResource.RES_ACTION_LAF), localizer.getMnemonic(HelperResource.RES_ACTION_LAF));
final ButtonGroup group = new ButtonGroup();
// Java L&F
final List<LookAndFeelInfo> list = HelperSwing.getAvailableLookAndFeels();
Collections.sort(list, new Comparator<LookAndFeelInfo>() {
@Override
public int compare(final LookAndFeelInfo arg0, final LookAndFeelInfo arg1) {
return arg0.getName().compareTo(arg1.getName());
}
});
for (final LookAndFeelInfo info : list) {
final JMenuItem item = new MenuItemRadioButton(info.getName());
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
try {
UIManager.setLookAndFeel(info.getClassName());
data.setLookAndFeel(info.getClassName());
data.setFontSizeOffset(0);
} catch (Exception ex) {
log.error("Could not initialize L&F", ex); //$NON-NLS-1$
}
}
});
item.setSelected(HelperObject.isEquals(info.getClassName(), UIManager.getLookAndFeel().getClass()
.getCanonicalName()));
result.add(item);
group.add(item);
}
result.add(new JXTitledSeparator("Substance", SwingConstants.CENTER)); //$NON-NLS-1$
// Substance L&F
final SubstanceSkin skin = SubstanceLookAndFeel.getCurrentSkin();
for (final SkinInfo info : SubstanceLookAndFeel.getAllSkins().values()) {
final JMenuItem item = new MenuItemRadioButton(info.getDisplayName());
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
SubstanceLookAndFeel.setSkin(info.getClassName());
data.setLookAndFeel(info.getClassName());
}
});
if (null != skin) {
item.setSelected(HelperObject.isEquals(info.getClassName(), skin.getClass().getCanonicalName()));
}
result.add(item);
group.add(item);
}
if (log.isTraceEnabled()) log.trace(HelperLog.methodExit(result));
return result;
}
private JMenu getMenuFontSize() {
if (log.isTraceEnabled()) log.trace(HelperLog.methodStart());
final JMenu result = new Menu(localizer.getValue(HelperResource.RES_ACTION_FONT_SIZE), controller.getScaledIcon(Icon.FONT),
localizer.getTooltip(HelperResource.RES_ACTION_FONT_SIZE), localizer.getMnemonic(HelperResource.RES_ACTION_FONT_SIZE));
final ButtonGroup group = new ButtonGroup();
final List<Integer> list = HelperCollection.getList(-4, -2, 0, 2, 4, 8, 12, 16, 24, 32, 48, 64);
for (final Integer value : list) {
final JMenuItem item = new MenuItemRadioButton(value.toString());
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
try {
SubstanceLookAndFeel.setFontPolicy(null);
// Get the default font set
final FontSet substanceCoreFontSet = SubstanceLookAndFeel.getFontPolicy().getFontSet("Substance", null); //$NON-NLS-1$
// Create the wrapper font set
final FontPolicy newFontPolicy = new FontPolicy() {
@Override
public FontSet getFontSet(final String lafName, final UIDefaults table) {
return new WrapperFontSet(substanceCoreFontSet, value);
}
};
// set the new font policy
SubstanceLookAndFeel.setFontPolicy(newFontPolicy);
data.setFontSizeOffset(value);
} catch (Exception ex) {
if (log.isWarnEnabled()) log.warn("Could not change the font size", ex); //$NON-NLS-1$
data.setFontSizeOffset(0);
}
}
});
item.setSelected(data.getFontSizeOffset() == value);
result.add(item);
group.add(item);
}
result.setEnabled(HelperString.contains(data.getLookAndFeel(), ID_SUBSTANCE_NS));
if (log.isTraceEnabled()) log.trace(HelperLog.methodExit(result));
return result;
}
private JMenu getMenuIconSize() {
if (log.isTraceEnabled()) log.trace(HelperLog.methodStart());
final JMenu result = new Menu(localizer.getValue(HelperResource.RES_ACTION_ICONS), controller.getScaledIcon(Icon.ICONS), localizer
.getTooltip(HelperResource.RES_ACTION_ICONS), localizer.getMnemonic(HelperResource.RES_ACTION_ICONS));
final ButtonGroup groupIcon = new ButtonGroup();
final JMenuItem itemNoneIcon = new MenuItemRadioButton(localizer.getValue(HelperResource.RES_LABEL_NO_ICONS));
itemNoneIcon.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
data.setIconSize(new Dimension(0, 0));
// iconSizeChanged();
}
});
itemNoneIcon.setSelected(0 == data.getIconSize().width);
result.add(itemNoneIcon);
groupIcon.add(itemNoneIcon);
result.addSeparator();
final List<Integer> list = HelperCollection.getList(8, 12, 16, 20, 24, 28, 32, 48, 64, 96, 128);
for (final Integer value : list) {
final JMenuItem item = new MenuItemRadioButton(value.toString());
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
data.setIconSize(new Dimension(value, 0));
// iconSizeChanged();
}
});
item.setSelected(data.getIconSize().width == value);
result.add(item);
groupIcon.add(item);
}
if (log.isTraceEnabled()) log.trace(HelperLog.methodExit(result));
return result;
}
private void setupFontSize() {
if (log.isTraceEnabled()) log.trace(HelperLog.methodStart());
try {
SubstanceLookAndFeel.setFontPolicy(null);
// Get the default font set
final FontSet substanceCoreFontSet = SubstanceLookAndFeel.getFontPolicy().getFontSet("Substance", null); //$NON-NLS-1$
// Create the wrapper font set
final FontPolicy newFontPolicy = new FontPolicy() {
@Override
public FontSet getFontSet(final String lafName, final UIDefaults table) {
return new WrapperFontSet(substanceCoreFontSet, data.getFontSizeOffset());
}
};
// set the new font policy
SubstanceLookAndFeel.setFontPolicy(newFontPolicy);
} catch (Exception ex) {
if (log.isWarnEnabled()) log.warn("Could not change the font size", ex); //$NON-NLS-1$
// TODO improve
data.setNotifyEnabled(false);
data.setFontSizeOffset(0);
data.setNotifyEnabled(true);
}
if (log.isTraceEnabled()) log.trace(HelperLog.methodExit());
}
/*
* Implemented methods
*/
@Override
public void display() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
final String laf = data.getLookAndFeel();
if (null != laf) {
if (HelperString.contains(laf, ID_SUBSTANCE_NS)) {
SubstanceLookAndFeel.setSkin(laf);
setupFontSize();
} else {
try {
UIManager.setLookAndFeel(laf);
} catch (Exception ex) {
log.error("Could not initialize L&F", ex); //$NON-NLS-1$
}
}
}
createTrayIcon();
createMenu();
data.addObserver(this);
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
@Override
public void update(final Observable o, final Object arg) {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart(o, arg));
if (TyrData.MEMBER_LOOK_AND_FEEL == arg) {
SwingUtilities.updateComponentTreeUI(owner);
SwingUtilities.updateComponentTreeUI(popup);
}
createMenu();
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
@Override
public void addWorker(final Worker worker, final String title, final String text, final ScalableIcon icon) {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart(worker, title, text, icon));
dialogTask.addWorker(worker, title, text, icon);
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
@Override
public void removeWorker(final Worker worker) {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart(worker));
dialogTask.removeWorker(worker);
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
@Override
public ControllerTyr getController() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit(controller));
return controller;
}
@Override
public JFrame getOwner() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit(owner));
return owner;
}
@Override
public JPopupMenu getPopup() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit(popup));
return popup;
}
@Override
public TrayIcon getTrayIcon() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit(trayIcon));
return trayIcon;
}
/*
* Inner classes
*/
// private class ActionModule extends ActionAbstract {
// private static final long serialVersionUID = -8929367680388496914L;
//
// public ActionModule() {
// super(localizer.getValue(HelperResource.RES_ACTION_MODULE), controller.getScaledIcon(Icon.MODULE), localizer
// .getTooltip(HelperResource.RES_ACTION_MODULE), localizer.getMnemonic(HelperResource.RES_ACTION_MODULE), localizer
// .getAccelerator(HelperResource.RES_ACTION_MODULE));
// }
//
// public void actionPerformed(final ActionEvent e) {
// dialogModule.createAndShowGUI();
// }
// }
private class ActionHelp extends ActionAbstract {
private static final long serialVersionUID = -8418340945105664528L;
public ActionHelp() {
super(localizer.getValue(HelperResource.RES_ACTION_HELP), controller.getScaledIcon(Icon.HELP), localizer
.getTooltip(HelperResource.RES_ACTION_HELP), localizer.getMnemonic(HelperResource.RES_ACTION_HELP), localizer
.getAccelerator(HelperResource.RES_ACTION_HELP));
}
@Override
public void actionPerformed(final ActionEvent e) {
dialogHelp.createAndShowGUI();
}
}
private class ActionAbout extends ActionAbstract {
private static final long serialVersionUID = -2976405554055093308L;
public ActionAbout() {
super(localizer.getValue(HelperResource.RES_ACTION_ABOUT), controller.getScaledIcon(Icon.ABOUT), localizer
.getTooltip(HelperResource.RES_ACTION_ABOUT), localizer.getMnemonic(HelperResource.RES_ACTION_ABOUT), localizer
.getAccelerator(HelperResource.RES_ACTION_ABOUT));
}
@Override
public void actionPerformed(final ActionEvent e) {
dialogAbout.createAndShowGUI();
}
}
private class ActionExit extends ActionAbstract {
private static final long serialVersionUID = -2990830188700151408L;
public ActionExit() {
super(localizer.getValue(HelperResource.RES_ACTION_EXIT), controller.getScaledIcon(Icon.EXIT), localizer
.getTooltip(HelperResource.RES_ACTION_EXIT), localizer.getMnemonic(HelperResource.RES_ACTION_EXIT), localizer
.getAccelerator(HelperResource.RES_ACTION_EXIT));
}
@Override
public void actionPerformed(final ActionEvent e) {
controller.exit(0);
}
}
}