package com.applang.components;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import org.gjt.sp.jedit.View;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import com.applang.berichtsheft.BerichtsheftActivity;
import com.applang.berichtsheft.BerichtsheftApp;
import com.applang.berichtsheft.plugin.DataDockable.TransportBuilder;
import com.applang.berichtsheft.plugin.BerichtsheftOptionPane;
import com.applang.berichtsheft.plugin.BerichtsheftPlugin;
import static com.applang.Util.*;
import static com.applang.Util1.*;
import static com.applang.Util2.*;
import static com.applang.SwingUtil.*;
import static com.applang.PluginUtils.*;
@SuppressWarnings("rawtypes")
public class ProfileManager extends ManagerBase<Element>
{
public static final String transportsSelector = "/TRANSPORTS";
// NOTE used in scripts
public ProfileManager(final View view) {
blockDirty(new Job<Void>() {
public void perform(Void t, Object[] params) throws Exception {
createUI(view, ProfileManager.this);
}
});
}
protected TextToggle textArea;
private JRadioButton[] radioButtons;
@SuppressWarnings("unchecked")
protected void createUI(final View view, final Container container) {
comboBoxes = new JComboBox[5];
textArea = new TextToggle(4,20);
textArea.getTextEdit().installUndoRedo();
radioButtons = new JRadioButton[] {new JRadioButton(),new JRadioButton(),new JRadioButton()};
ButtonGroup group = new ButtonGroup();
for (AbstractButton btn : radioButtons)
group.add(btn);
container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
Box box = new Box(BoxLayout.LINE_AXIS);
radioButtons[0].setText(getProperty("berichtsheft.transport-push.label"));
radioButtons[0].addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ev) {
if (ev.getStateChange() == ItemEvent.SELECTED)
setOper("push", container);
}
});
box.add(radioButtons[0]);
box.add(Box.createHorizontalGlue());
radioButtons[1].setText(getProperty("berichtsheft.transport-pull.label"));
radioButtons[1].addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ev) {
if (ev.getStateChange() == ItemEvent.SELECTED)
setOper("pull", container);
}
});
box.add(radioButtons[1]);
box.add(Box.createHorizontalGlue());
radioButtons[2].setText(getProperty("berichtsheft.transport-download.label"));
radioButtons[2].addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ev) {
if (ev.getStateChange() == ItemEvent.SELECTED)
setOper("download", container);
}
});
box.add(radioButtons[2]);
container.add(surroundingBox(box, "Transport", TitledBorder.CENTER));
comboBoxes[0] = new JComboBox();
comboBoxes[0].addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ev) {
if (ev.getStateChange() == ItemEvent.SELECTED) {
String profile = getProfile();
if (select(profile) != null)
setProfile(profile);
else
setDirty(true);
}
else if (ev.getStateChange() == ItemEvent.DESELECTED) {
String item = stringValueOf(ev.getItem());
save(item, false);
}
}
});
comboBoxes[0].setEditable(true);
Dimension size = comboBoxes[0].getPreferredSize();
comboBoxes[0].setPreferredSize(new Dimension(500, size.height));
container.add( Box.createVerticalStrut(10) );
box = new Box(BoxLayout.LINE_AXIS);
container.add(labelFor(box, "Profile", CENTER_ALIGNMENT));
box.add(comboBoxes[0]);
installAddRemove(box, "profile");
container.add(box);
comboBoxes[1] = new JComboBox();
container.add( Box.createVerticalStrut(10) );
box = new Box(BoxLayout.LINE_AXIS);
container.add(labelFor(box, "Flavor", CENTER_ALIGNMENT));
box.add(comboBoxes[1]);
box.add(makeCustomButton("berichtsheft.edit-function", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
Object profile = comboBoxes[0].getSelectedItem();
Object flavor = comboBoxes[1].getSelectedItem();
if (notNullOrEmpty(flavor))
new ScriptManager(view, container,
ScriptManager.flavorSelector(flavor),
profile);
}
}, false));
box.add(makeCustomButton("berichtsheft.insert-field", new ActionListener() {
int checkedItem = -1;
public void actionPerformed(ActionEvent evt) {
Object flavor = comboBoxes[1].getSelectedItem();
if (notNullOrEmpty(flavor)) {
final Object[] projection = fullProjection(flavor);
if (isAvailable(0, projection)) {
AlertDialog dialog = new AlertDialog.Builder(BerichtsheftActivity.getInstance())
.setTitle(String.format("Columns for '%s'", flavor))
.setSingleChoiceItems(
arraycast(projection, new CharSequence[0]),
-1,
new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
checkedItem = which;
}
}
)
.setNeutralButton(android.R.string.ok, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (checkedItem > -1) {
String text = enclose("`", projection[checkedItem].toString());
textArea.setSelectedText(text);
}
}
})
.create();
dialog.open(0.5, 0.5);
}
}
}
}, false));
container.add(box);
container.add( Box.createVerticalStrut(10) );
comboBoxes[2] = new JComboBox();
comboBoxes[2].setEditable(true);
comboEdit(2).addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
setDirty(true);
}
});
Memory.update(comboBoxes[2], true, "Filter.expressions");
container.add(labelFor(comboBoxes[2], "Filter", CENTER_ALIGNMENT));
container.add(comboBoxes[2]);
container.add( Box.createVerticalStrut(10) );
box = new Box(BoxLayout.LINE_AXIS);
container.add(labelFor(box, "Template", CENTER_ALIGNMENT));
textArea.setOnTextChanged(new Job<JComponent>() {
public void perform(JComponent t, Object[] params) throws Exception {
setDirty(true);
}
});
box.add(textArea.getUIComponent());
Box box2 = new Box(BoxLayout.PAGE_AXIS);
Box box3 = new Box(BoxLayout.LINE_AXIS);
box3.add(makeCustomButton("berichtsheft.insert-enter", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
textArea.setSelectedText(NEWLINE);
}
}, false));
box3.add(makeCustomButton("berichtsheft.insert-function", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
String expr = new ScriptManager(view, container).getFunction();
textArea.setSelectedText(notNullOrEmpty(expr) ? "|" + expr : "");
}
}, false));
box2.add(box3);
box3 = new Box(BoxLayout.LINE_AXIS);
installUpdate(box3);
box2.add(box3);
box.add(box2);
container.add(box);
container.add( Box.createVerticalStrut(10) );
box = new Box(BoxLayout.LINE_AXIS);
comboBoxes[3] = new JComboBox(BerichtsheftOptionPane.separators.keySet().toArray());
box.add(Box.createHorizontalGlue());
String labelText = BerichtsheftPlugin.getOptionProperty("record-separator.title");
box.add(new JLabel( strip(Constraint.END, labelText, ":") ));
box.add(comboBoxes[3]);
box.add(Box.createHorizontalGlue());
comboBoxes[4] = new JComboBox(BerichtsheftOptionPane.decorations.keySet().toArray());
labelText = BerichtsheftPlugin.getOptionProperty("record-decoration.title");
box.add(new JLabel( strip(Constraint.END, labelText, ":") ));
box.add(comboBoxes[4]);
box.add(Box.createHorizontalGlue());
container.add(box);
container.add( Box.createVerticalStrut(10) );
if ("push".equals(getProperty("TRANSPORT_OPER", "pull")))
radioButtons[0].setSelected(true);
else
radioButtons[1].setSelected(true);
for (int i = 1; i < comboBoxes.length; i++) {
comboChangeListener(i);
}
Window window = SwingUtilities.getWindowAncestor(container);
if (window != null) {
window.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event) {
save(getItem(), false);
}
});
}
}
private String oper = null;
public void setOper(String oper, Container container) {
this.oper = oper;
boolean download = "download".equals(oper);
comboBoxes[3].setEnabled(!download);
comboBoxes[4].setEnabled(!download);
JLabel label = findFirstComponent(container, "Template_Label");
label.setText(download ? "URL" : "Template");
setProperty("TRANSPORT_OPER", oper);
updateModels(true, false, true);
}
@Override
protected Element select(Object...profile) {
if (ProfileManager.transportsLoaded()) {
String xpath = transportsSelector + "/PROFILE[@name='" + profile[0] + "' and @oper='" + oper + "']";
return selectElement(ProfileManager.transports, xpath);
}
return null;
}
@Override
protected boolean addItem(boolean refresh, Object profile) {
if (ProfileManager.transportsLoaded()) {
String template = textArea.getText();
setTemplate(refresh, template, profile);
return true;
}
return false;
}
@Override
protected boolean removeItem(Object profile) {
Element element = select(profile);
boolean retval = element != null;
if (retval) {
element.getParentNode().removeChild(element);
updateModels(true, true, false);
}
return retval;
}
private void setTemplate(boolean refresh, String template, Object profile) {
Object flavor = comboBoxes[1].getSelectedItem();
Object filter = comboEdit(2).getText();
Object recordSeparator = comboBoxes[3].getSelectedItem();
Object recordDecoration = comboBoxes[4].getSelectedItem();
ProfileManager.setTemplate(template, profile, oper, flavor, filter, recordSeparator, recordDecoration);
updateModels(refresh, true, true, profile);
}
@Override
protected void updateItem(boolean update, Object...params) {
String profile = param(null, 0, params);
boolean refresh = profile == null;
if (refresh)
profile = getProfile();
Element element = select(profile);
if (element != null) {
String template = textArea.getText();
boolean download = "download".equals(oper);
ValList list = download ?
null :
new TransportBuilder().evaluateTemplate(template, null);
if (update && (download || isAvailable(0, list)))
setTemplate(refresh, template, profile);
else
setProfile(profile);
}
}
@SuppressWarnings("unchecked")
private void updateModels(boolean refresh, boolean save, boolean keepSelection, Object...params) {
String profile = param(getProfile(), 0, params);
if (ProfileManager.transportsLoaded()) {
if (refresh) {
blockDirty(new Job<Void>() {
public void perform(Void t, Object[] params) throws Exception {
DefaultComboBoxModel model = (DefaultComboBoxModel) comboBoxes[0].getModel();
model.removeAllElements();
NodeList nodes =
evaluateXPath(ProfileManager.transports,
transportsSelector + "/PROFILE[@oper='" + oper + "']");
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
final String name = element.getAttribute("name");
if (!name.startsWith("_"))
model.addElement(name);
}
comboBoxes[0].setModel(model);
DataView.fillFlavorCombo(comboBoxes[1]);
}
});
}
if (save)
ProfileManager.saveTransports();
}
if (!refresh)
return;
if (!keepSelection)
profile = getProfile();
setProfile(profile);
}
// NOTE used in scripts
public void setProfile(final String profile) {
blockDirty(new Job<Void>() {
public void perform(Void t, Object[] params) throws Exception {
comboBoxes[0].getModel().setSelectedItem(profile);
String template = "", flavor = "", filter = "", recordSeparator = "newline", recordDecoration = "none";
Element element = select(profile);
if (element != null) {
flavor = element.getAttribute("flavor");
Element el = selectElement(element, "./FILTER");
if (el != null)
filter = el.getTextContent();
boolean download = "download".equals(oper);
String name = download ? "URL" : "TEMPLATE";
el = selectElement(element, "./" + name);
if (el != null)
template = el.getTextContent();
recordSeparator = element.getAttribute("recordSeparator");
recordDecoration = element.getAttribute("recordDecoration");
}
comboBoxes[1].getModel().setSelectedItem(flavor);
comboEdit(2).setText(filter);
comboBoxes[3].getModel().setSelectedItem(recordSeparator);
comboBoxes[4].getModel().setSelectedItem(recordDecoration);
textArea.setText(template);
}
});
setDirty(false);
}
// NOTE used in scripts
public String getProfile() {
Object item = comboBoxes[0].getSelectedItem();
return stringValueOf(item);
}
public static Document transports = null;
public static void saveTransports(Object...params) {
if (transports != null) {
String settingsDir = param(BerichtsheftApp.applicationDataPath(), 0, params);
File file = new File(settingsDir, "transports.xml");
xmlNodeToFile(transports, true, file);
}
}
public static boolean transportsLoaded(Object...params) {
if (transports == null) {
String settingsDir = param(BerichtsheftApp.applicationDataPath(), 0, params);
File file = new File(settingsDir, "transports.xml");
if (fileExists(file))
transports = xmlDocument(file);
}
return transports != null;
}
public static boolean setTemplate(String template, Object...params) {
String profile = getProperty("TRANSPORT_PROFILE");
profile = param(profile, 0, params);
String oper = getProperty("TRANSPORT_OPER");
oper = param(oper, 1, params);
if (notNullOrEmpty(profile) && ProfileManager.transportsLoaded()) {
boolean download = "download".equals(oper);
String xpath = transportsSelector + "/PROFILE[@name='" + profile + "' and @oper='" + oper + "']";
Element element = selectElement(ProfileManager.transports, xpath);
if (element == null) {
element = ProfileManager.transports.createElement("PROFILE");
element.setAttribute("name", profile);
element.setAttribute("oper", oper);
if (!download) {
element.setAttribute("recordSeparator", "whitespace");
element.setAttribute("recordDecoration", "none");
}
ProfileManager.transports.getDocumentElement().appendChild(element);
}
String value = param(null, 2, params);
if (value != null)
element.setAttribute("flavor", value);
value = param(null, 3, params);
if (notNullOrEmpty(value))
setCDATASection(element, "FILTER", value);
value = param(null, 4, params);
if (notNullOrEmpty(value))
element.setAttribute("recordSeparator", value);
value = param(null, 5, params);
if (notNullOrEmpty(value))
element.setAttribute("recordDecoration", value);
setCDATASection(element, download ? "URL" : "TEMPLATE", template);
return true;
}
return false;
}
private static void setCDATASection(Element element, String name, String data) {
NodeList nodes;
while ((nodes = evaluateXPath(element, "./*[name()='" + name + "']")).getLength() > 0)
element.removeChild(nodes.item(0));
element = (Element) element.appendChild(ProfileManager.transports.createElement(name));
CDATASection cdata = ProfileManager.transports.createCDATASection(data);
element.appendChild(cdata);
}
public static ValMap getProfileAsMap(Object...params) {
ValMap map = vmap();
String profile = getProperty("TRANSPORT_PROFILE");
profile = param_String(profile, 0, params);
String oper = getProperty("TRANSPORT_OPER");
oper = param_String(oper, 1, params);
if (notNullOrEmpty(profile) && transportsLoaded()) {
String xpath = "/TRANSPORTS/PROFILE[@name='" + profile + "' and @oper='" + oper + "']";
Element element = selectElement(transports, xpath);
if (element != null) {
map.put("name", profile);
map.put("oper", oper);
if (element.hasAttribute("flavor"))
map.put("flavor", element.getAttribute("flavor"));
Element el = selectElement(element, "./FILTER");
if (el != null)
map.put("filter", el.getTextContent());
if (element.hasAttribute("recordSeparator"))
map.put("recordSeparator", element.getAttribute("recordSeparator"));
if (element.hasAttribute("recordDecoration"))
map.put("recordDecoration", element.getAttribute("recordDecoration"));
String name = "download".equals(oper) ? "URL" : "TEMPLATE";
el = selectElement(element, "./" + name);
if (el != null)
map.put(name.toLowerCase(), el.getTextContent());
}
}
return map;
}
public static void main(String...args) {
BerichtsheftApp.loadSettings();
underTest = param("true", 0, args).equals("true");
int behavior = Behavior.MODAL;
if (underTest)
behavior |= Behavior.EXIT_ON_CLOSE | Behavior.ALWAYS_ON_TOP;
ProfileManager pm = new ProfileManager(null);
showOptionDialog(null,
pm,
"Transport profiles",
JOptionPane.DEFAULT_OPTION + behavior,
JOptionPane.PLAIN_MESSAGE,
null,
null, null);
}
}