jaxx.runtime.swing.config.ConfigUIHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaxx-config Show documentation
Show all versions of jaxx-config Show documentation
Config UI based on org.nuiton.config.ApplicationConfig
package jaxx.runtime.swing.config;
/*
* #%L
* JAXX :: Config
* %%
* Copyright (C) 2008 - 2014 Code Lutin, Tony Chemit
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import jaxx.runtime.JAXXUtil;
import jaxx.runtime.SwingUtil;
import jaxx.runtime.context.JAXXInitialContext;
import jaxx.runtime.swing.config.model.CallBackEntry;
import jaxx.runtime.swing.config.model.CallBackMap;
import jaxx.runtime.swing.config.model.CategoryModel;
import jaxx.runtime.swing.config.model.ConfigUIModel;
import jaxx.runtime.swing.config.model.OptionModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultSingleSelectionModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import java.awt.Container;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import static org.nuiton.i18n.I18n.t;
/**
* Handler of the {@link ConfigUI} ui.
*
* @author Tony Chemit - [email protected]
* @since 2.5.11
*/
public class ConfigUIHandler {
public static final Log log = LogFactory.getLog(ConfigUIHandler.class);
public static final String CALLBACKS_WITH_OPTIONS = "callbacksWithOptions";
public static final String CALLBACKS = "callbacks";
public static final String QUIT_ACTION = "quit";
private final ConfigUI ui;
private Container topContainer;
/**
* To be able to veto a change of a category.
*
* @since 2.6
*/
public static interface ChangeCategoryCallBack {
boolean canChangeCategory(String categoryName);
}
private ChangeCategoryCallBack changeCategoryCallBack;
public ConfigUIHandler(ConfigUI ui) {
this.ui = ui;
}
public void setChangeCategoryCallBack(ChangeCategoryCallBack changeCategoryCallBack) {
this.changeCategoryCallBack = changeCategoryCallBack;
}
public void initUI(String defaultCategory) {
ConfigUIModel model = ui.getModel();
JTabbedPane categories = ui.getCategories();
categories.setModel(new DefaultSingleSelectionModel() {
private static final long serialVersionUID = 1L;
@Override
public void setSelectedIndex(int index) {
// check if catgeory can be quit
boolean canContinue = !isSelected() || canQuitCategory();
if (canContinue) {
// was authorized to leave previous category
if (log.isDebugEnabled()) {
log.debug("new index : " + index);
}
String categoryName = ConfigUIHandler.this.ui.getModel().getCategoryName(index);
if (changeCategoryCallBack == null || changeCategoryCallBack.canChangeCategory(categoryName)) {
// can change category
super.setSelectedIndex(index);
}
}
}
});
JButton quitButton = ui.getQuit();
// prepare quit action
Action quitAction = createQuitAction();
String tip = quitButton.getToolTipText();
quitButton.setAction(quitAction);
quitButton.setToolTipText(tip);
// build categories tabs
for (CategoryModel categoryModel : model) {
String category = categoryModel.getCategory();
String categoryLabel = t(categoryModel.getCategoryLabel());
ConfigCategoryUI p = new ConfigCategoryUI(
new JAXXInitialContext().add(ui).add(categoryModel));
p.getCategoryLabel().setText(categoryLabel);
p.setName(category);
categories.addTab(t(category), null, p, categoryLabel);
}
model.setCategory(defaultCategory);
int categoryIndex = model.getCategoryIndex(defaultCategory);
if (log.isDebugEnabled()) {
log.debug("index of default category (" + defaultCategory + ") : "
+ categoryIndex);
}
categories.setSelectedIndex(categoryIndex);
}
public void destroy() {
if (log.isDebugEnabled()) {
log.debug("destroy ui " + ui.getName());
}
JAXXUtil.destroy(ui);
ui.getModel().destroy();
}
public void changeCategory(ChangeEvent e) {
JPanel p = (JPanel) ui.getCategories().getSelectedComponent();
if (p == null) {
// pas de selection
return;
}
ui.getModel().setCategory(p.getName());
ui.getCategories().invalidate();
}
public void displayUI(Frame parentUI, boolean undecorated) {
JDialog f = new JDialog(parentUI, true);
f.setTitle(t("config.title"));
f.add(ui);
if (parentUI != null) {
f.setIconImage(parentUI.getIconImage());
}
// pour savoir si l'ui est autonome
ui.getModel().setStandalone(parentUI == null);
f.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
ActionEvent myEvent = new ActionEvent(e.getSource(), 1, QUIT_ACTION);
ui.getQuit().getAction().actionPerformed(myEvent);
}
});
f.setUndecorated(undecorated);
JRootPane rootPane = f.getRootPane();
rootPane.setDefaultButton(ui.getQuit());
rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke("ESCAPE"), QUIT_ACTION);
rootPane.getActionMap().put(QUIT_ACTION, ui.getQuit().getAction());
f.pack();
SwingUtil.center(parentUI, f);
f.setVisible(true);
}
protected Action createQuitAction() {
JButton button = ui.getQuit();
Action quitAction = new AbstractAction(button.getText(),
button.getIcon()) {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
if (!canQuitCategory()) {
return;
}
Window parentWindow;
final Container parentContainer;
if (topContainer == null) {
// no top container given, still use the parent frame
parentWindow = ui.getParentContainer(Window.class);
parentContainer = parentWindow;
} else {
// use only given topContainer
parentWindow = null;
parentContainer = topContainer;
}
ConfigUIModel model = ui.getModel();
if (!model.isSaved() || model.isStandalone()) {
// just quit, no callBack can be apply here
closeUI(parentWindow, model);
return;
}
CallBackMap forSaved = model.getCallBacksForSaved();
if (forSaved.isEmpty()) {
// just quit, no callBack to call
closeUI(parentWindow, model);
return;
}
forSaved = model.getCallBacksForSaved();
// init callBackUI
JAXXInitialContext context = new JAXXInitialContext().
add(ui).
add(CALLBACKS_WITH_OPTIONS, forSaved).
add(CALLBACKS,
new ArrayList(forSaved.keySet())).
add(new ConfigCallBackUIHandler());
if (topContainer == null) {
// still add parent window (to close ui)
context.add("parent", parentWindow);
}
ConfigCallBackUI lastUI = new ConfigCallBackUI(context);
lastUI.init();
ui.setVisible(false);
parentContainer.remove(ui);
parentContainer.add(lastUI);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
parentContainer.validate();
}
});
}
};
return quitAction;
}
protected void closeUI(Window parentWindow, ConfigUIModel model) {
destroy();
if (parentWindow != null) {
// close the config ui
parentWindow.dispose();
}
Runnable runnable = model.getCloseAction();
if (runnable != null) {
log.info("execute close action");
runnable.run();
}
}
protected boolean canQuitCategory() {
boolean canContinue = true;
ConfigUIModel model = ui.getModel();
CategoryModel categoryModel = model.getCategoryModel();
String categoryName = t(categoryModel.getCategory());
if (!categoryModel.isValid()) {
// the category is not valid
// get all the invalid options
StringBuilder buffer = new StringBuilder();
buffer.append(t("config.message.quit.invalid.category",
categoryName));
buffer.append('\n');
for (OptionModel m : categoryModel.getInvalidOptions()) {
buffer.append("\n- ").append(m.getKey());
}
buffer.append('\n');
int reponse = askUser(t("config.title.need.confirm"),
buffer.toString(),
JOptionPane.ERROR_MESSAGE,
new Object[]{
t("config.choice.continue"),
t("config.choice.cancel")},
0);
switch (reponse) {
case JOptionPane.CLOSED_OPTION:
case 1:
canContinue = false;
break;
case 0:
if (categoryModel.isModified()) {
// wil reset category
model.reset();
}
break;
}
} else if (categoryModel.isModified()) {
// category was modified, ask user if wants to save
StringBuilder buffer = new StringBuilder();
buffer.append(t("config.message.quit.valid.and.modified.category",
categoryName)).append('\n');
for (OptionModel m : categoryModel.getModifiedOptions()) {
buffer.append("\n- ").append(m.getKey());
}
buffer.append('\n');
int reponse = askUser(t("config.title.need.confirm"),
buffer.toString(),
JOptionPane.WARNING_MESSAGE,
new Object[]{
t("config.choice.save"),
t("config.choice.doNotSave"),
t("config.choice.cancel")},
0);
switch (reponse) {
case JOptionPane.CLOSED_OPTION:
case 2:
canContinue = false;
break;
case 0:
// will save ui
model.saveModified();
break;
case 1:
// wil reset ui
model.reset();
break;
}
}
return canContinue;
}
public int askUser(String title,
String message,
int typeMessage,
Object[] options,
int defaultOption) {
int response = JOptionPane.showOptionDialog(
ui,
message,
title,
JOptionPane.DEFAULT_OPTION,
typeMessage,
null,
options,
options[defaultOption]
);
return response;
}
public void setTopContainer(Container topContainer) {
this.topContainer = topContainer;
}
}