package com.bytezone.dm3270.plugins; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.prefs.Preferences; import com.bytezone.dm3270.application.ConsolePane; import com.bytezone.dm3270.commands.AIDCommand; import com.bytezone.dm3270.display.Cursor; import com.bytezone.dm3270.display.Field; import com.bytezone.dm3270.display.FieldManager; import com.bytezone.dm3270.display.Screen; import com.bytezone.dm3270.display.ScreenDimensions; import com.bytezone.dm3270.utilities.PreferencesStage; import com.bytezone.dm3270.utilities.Site; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.CheckBox; import javafx.scene.control.CheckMenuItem; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.TextField; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCombination; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; // -----------------------------------------------------------------------------------// public class PluginsStage extends PreferencesStage // -----------------------------------------------------------------------------------// { private static final int MAX_PLUGINS = 10; private static KeyCode[] keyCodes = { KeyCode.DIGIT1, KeyCode.DIGIT2, KeyCode.DIGIT3, KeyCode.DIGIT4, KeyCode.DIGIT5, KeyCode.DIGIT6, KeyCode.DIGIT7, KeyCode.DIGIT8, KeyCode.DIGIT9, KeyCode.DIGIT0 }; private final List<PluginEntry> plugins = new ArrayList<> (MAX_PLUGINS); private Menu menu; private final MenuItem editMenuItem = new MenuItem ("Plugin Manager..."); private int requestMenus; private int baseMenuSize; private Screen screen; private ScreenDimensions screenDimensions; private int sequence; private ConsolePane consolePane; // ---------------------------------------------------------------------------------// public PluginsStage (Preferences prefs) // ---------------------------------------------------------------------------------// { super (prefs); setTitle ("Plugin Manager"); readPrefs (); editMenuItem.setOnAction (e -> this.show ()); fields.add (new PreferenceField ("Menu entry", 130, Type.TEXT)); fields.add (new PreferenceField ("Class name", 300, Type.TEXT)); fields.add (new PreferenceField ("Active", 60, Type.BOOLEAN)); VBox vbox = getHeadings (); for (PluginEntry pluginEntry : plugins) { HBox hbox = new HBox (); hbox.setSpacing (5); hbox.setPadding (new Insets (0, 5, 0, 5)); // trbl for (int i = 0; i < fields.size (); i++) { PreferenceField field = fields.get (i); if (field.type == Type.TEXT || field.type == Type.NUMBER) { TextField textField = pluginEntry.getTextField (i); textField.setPrefWidth (field.width); hbox.getChildren ().add (textField); } else if (field.type == Type.BOOLEAN) { HBox box = new HBox (); CheckBox checkBox = pluginEntry.getCheckBox (i); box.setPrefWidth (field.width); box.setAlignment (Pos.CENTER); box.getChildren ().add (checkBox); hbox.getChildren ().add (box); } } vbox.getChildren ().add (hbox); } BorderPane borderPane = new BorderPane (); borderPane.setCenter (vbox); borderPane.setBottom (buttons ()); Scene scene = new Scene (borderPane); setScene (scene); saveButton.setOnAction (e -> { savePrefs (); this.hide (); }); cancelButton.setOnAction (e -> this.hide ()); } // ---------------------------------------------------------------------------------// public void setScreen (Screen screen) // ---------------------------------------------------------------------------------// { this.screen = screen; this.screenDimensions = screen.getScreenDimensions (); } // ---------------------------------------------------------------------------------// public void setConsolePane (ConsolePane consolePane) // ---------------------------------------------------------------------------------// { this.consolePane = consolePane; } // ---------------------------------------------------------------------------------// public void processAll (PluginData data) // ---------------------------------------------------------------------------------// { for (PluginEntry pluginEntry : plugins) if (pluginEntry.isActivated) { Plugin plugin = pluginEntry.plugin; if (plugin != null && plugin.doesAuto ()) try { plugin.processAuto (data); } catch (Exception e) { e.printStackTrace (); } } } // ---------------------------------------------------------------------------------// public int activePlugins () // ---------------------------------------------------------------------------------// { int activePlugins = 0; for (PluginEntry pluginEntry : plugins) { Plugin plugin = pluginEntry.plugin; if (plugin != null && pluginEntry.isActivated) ++activePlugins; } return activePlugins; } // ---------------------------------------------------------------------------------// public Menu getMenu (Site site) // ---------------------------------------------------------------------------------// { setMenu (site); return menu; } // ---------------------------------------------------------------------------------// public MenuItem getEditMenuItem () // ---------------------------------------------------------------------------------// { return editMenuItem; } // ---------------------------------------------------------------------------------// public boolean allowsPlugins () // ---------------------------------------------------------------------------------// { return true; } // ---------------------------------------------------------------------------------// private void setMenu (Site site) // ---------------------------------------------------------------------------------// { menu = new Menu ("Plugins"); int activeCount = 0; for (PluginEntry pluginEntry : plugins) { String text = pluginEntry.name.getText (); if (text.isEmpty ()) continue; CheckMenuItem menuItem = new CheckMenuItem (text); menu.getItems ().add (menuItem); pluginEntry.instantiate (); if (pluginEntry.plugin == null) menuItem.setDisable (true); else { menuItem.setUserData (pluginEntry); menuItem.setOnAction (e -> itemSelected (e)); if (pluginEntry.isAutoActivate ()) { activeCount++; menuItem.setSelected (true); pluginEntry.select (true); } } } baseMenuSize = menu.getItems ().size (); if (activeCount > 0) { menu.getItems ().add (new SeparatorMenuItem ()); for (PluginEntry pluginEntry : plugins) if (pluginEntry.isAutoActivate () && pluginEntry.plugin.doesRequest ()) menu.getItems ().add (pluginEntry.requestMenuItem); } } // ---------------------------------------------------------------------------------// private void itemSelected (ActionEvent e) // ---------------------------------------------------------------------------------// { CheckMenuItem menuItem = ((CheckMenuItem) e.getSource ()); PluginEntry pluginEntry = (PluginEntry) menuItem.getUserData (); pluginEntry.select (menuItem.isSelected ()); rebuildMenu (); } // ---------------------------------------------------------------------------------// private void rebuildMenu () // ---------------------------------------------------------------------------------// { System.out.println ("rebuilding"); ObservableList<MenuItem> items = menu.getItems (); while (items.size () > baseMenuSize) items.remove (menu.getItems ().size () - 1); menu.getItems ().add (new SeparatorMenuItem ()); for (PluginEntry pluginEntry : plugins) if (pluginEntry.isActivated && pluginEntry.requestMenuItem != null) items.add (pluginEntry.requestMenuItem); } // ---------------------------------------------------------------------------------// private void readPrefs () // ---------------------------------------------------------------------------------// { for (int i = 0; i < MAX_PLUGINS; i++) { String pluginName = prefs.get (String.format ("PluginName-%02d", i), ""); String pluginClass = prefs.get (String.format ("PluginClass-%02d", i), ""); boolean pluginActivate = prefs.getBoolean (String.format ("PluginActivate-%02d", i), false); // if (!pluginName.isEmpty ()) plugins.add (new PluginEntry (pluginName, pluginClass, pluginActivate)); } } // ---------------------------------------------------------------------------------// private void savePrefs () // ---------------------------------------------------------------------------------// { for (int i = 0; i < MAX_PLUGINS; i++) { PluginEntry plugin = plugins.get (i); prefs.put (String.format ("PluginName-%02d", i), plugin.name.getText ()); prefs.put (String.format ("PluginClass-%02d", i), plugin.className.getText ()); prefs.putBoolean (String.format ("PluginActivate-%02d", i), plugin.activate.isSelected ()); } } // ---------------------------------------------------------------------------------// // Process plugins // ---------------------------------------------------------------------------------// // called from WriteCommand.process() after unlocking keyboard // will eventually be called before unlocking the keyboard // ---------------------------------------------------------------------------------// public AIDCommand processPluginAuto () // ---------------------------------------------------------------------------------// { assert !screen.isKeyboardLocked (); FieldManager fieldManager = screen.getFieldManager (); Cursor cursor = screen.getScreenCursor (); if (activePlugins () > 0) { int cursorPosition = cursor.getLocation (); ScreenLocation screenLocation = new ScreenLocation (cursorPosition / screenDimensions.columns, cursorPosition % screenDimensions.columns); PluginData pluginData = fieldManager.getPluginScreen (sequence++, screenLocation); if (false) { System.out.println ("--------------------------------------------"); System.out.println (pluginData); } processAll (pluginData); AIDCommand command = processReply (pluginData); if (command != null) screen.lockKeyboard (command.getKeyName ()); return command; } return null; } // created by PluginsStage.itemSelected() -> PluginEntry.select() // which sets menuItem.setOnAction (e -> screen.processPluginRequest (plugin)) // ---------------------------------------------------------------------------------// public void processPluginRequest (Plugin plugin) // ---------------------------------------------------------------------------------// { assert consolePane != null; FieldManager fieldManager = screen.getFieldManager (); Cursor cursor = screen.getScreenCursor (); int cursorPosition = cursor.getLocation (); ScreenLocation screenLocation = new ScreenLocation (cursorPosition / screenDimensions.columns, cursorPosition % screenDimensions.columns); PluginData pluginData = fieldManager.getPluginScreen (sequence++, screenLocation); plugin.processRequest (pluginData); AIDCommand command = processReply (pluginData); if (command != null) { screen.lockKeyboard (command.getKeyName ()); consolePane.sendAID (command); } } // ---------------------------------------------------------------------------------// private AIDCommand processReply (PluginData data) // ---------------------------------------------------------------------------------// { FieldManager fieldManager = screen.getFieldManager (); Cursor cursor = screen.getScreenCursor (); int currentLocation = cursor.getLocation (); boolean isVisible = cursor.isVisible (); if (isVisible) cursor.setVisible (false); for (PluginField screenField : data.changedFields) { Optional<Field> optField = fieldManager.getFieldAt (screenField.location.location); // Field field = fieldManager.getFieldAt (screenField.location.location); // first display location // assert field != null; assert optField.isPresent (); Field field = optField.get (); if (field != null) // should be impossible { if (screenField.newData == null) { // erase field? } else { try { // should this type the characters instead? field.setText (screenField.newData.getBytes ("CP1047")); field.setModified (true); } catch (UnsupportedEncodingException e) { e.printStackTrace (); } } field.draw (); // draws the field without a cursor } } if (data.cursorMoved ()) cursor.moveTo (data.getNewCursorLocation ()); else cursor.moveTo (currentLocation); if (isVisible) cursor.setVisible (true); if (data.getKey () != 0) { screen.setAID (data.getKey ()); AIDCommand command = screen.readModifiedFields (); return command; } return null; } // ---------------------------------------------------------------------------------// private class PluginEntry // ---------------------------------------------------------------------------------// { private final TextField name = new TextField (); private final TextField className = new TextField (); private final CheckBox activate = new CheckBox (); private final TextField[] textFieldList = { name, className, null }; private final CheckBox[] checkBoxList = { null, null, activate }; private Plugin plugin; private boolean isActivated; private MenuItem requestMenuItem; // used to trigger a Request public PluginEntry (String name, String className, boolean activate) { // if (name == null || name.isEmpty ()) // throw new IllegalArgumentException ("Plugin name not provided"); // if (className == null || className.isEmpty ()) // throw new IllegalArgumentException ("Plugin class not provided"); this.name.setText (name); this.className.setText (className); this.activate.setSelected (activate); } public TextField getTextField (int index) { return textFieldList[index]; } public CheckBox getCheckBox (int index) { return checkBoxList[index]; } public boolean isAutoActivate () { return activate.isSelected (); } public void select (boolean activate) { if (activate) plugin.activate (); else plugin.deactivate (); if (requestMenuItem == null && plugin.doesRequest ()) { requestMenuItem = new MenuItem (name.getText ()); requestMenuItem.setOnAction (e -> processPluginRequest (plugin)); requestMenuItem.setAccelerator (new KeyCodeCombination (keyCodes[requestMenus++], KeyCombination.SHORTCUT_DOWN)); } isActivated = activate; } public Plugin instantiate () { plugin = null; try { String classNameText = className.getText (); if (!classNameText.isEmpty ()) { Class<?> c = Class.forName (classNameText); if (c != null) plugin = (Plugin) c.newInstance (); } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { System.out.printf ("Instantiation failed: %s - %s%n", name, className); } return plugin; } } }