From d2059a5852c13e000004ebf24aa98676e05bb251 Mon Sep 17 00:00:00 2001 From: Fabian Becker Date: Mon, 14 May 2012 13:57:39 +0000 Subject: [PATCH] Major update! Some related projects might be broken from now on - if so, let me know via email. This is the first of a series of commits to manifest the new graphical user interface of EvA2. This commit includes (incomplete list) - New Icons that are used in the GUI - A completely refactored GUI with a one-window layout. - Plots/Text Output will now appear on a JDesktopPane - Configuration can be done via the sidebar (not yet completely functional) - New layouts for TabbedPane (currently not active) and JButton (vertical text) - Code cleanup / removal of TRACE variable - More classes are now using the Logging facility. refs #8, #10, #14 fixes #12 --- resources/images/EvASplashScreen.png | Bin 0 -> 474538 bytes resources/images/Help24.gif | Bin 0 -> 1328 bytes resources/images/Open16.gif | Bin 0 -> 228 bytes resources/images/Save16.gif | Bin 0 -> 206 bytes src/eva2/EvAInfo.java | 2 +- src/eva2/client/EvAClient.java | 364 +++-- src/eva2/client/EvAComAdapter.java | 28 +- src/eva2/gui/BeanInspector.java | 55 +- src/eva2/gui/BigStringEditor.java | 28 +- src/eva2/gui/EvATabbedFrameMaker.java | 396 +++-- src/eva2/gui/ExtDesktopManager.java | 121 +- src/eva2/gui/GOEPanel.java | 758 +++++---- src/eva2/gui/GenericArrayEditor.java | 1432 ++++++++--------- src/eva2/gui/GenericObjectEditor.java | 905 ++++++----- .../GenericOptimizationObjectivesEditor.java | 2 +- .../gui/GenericSelectableArrayEditor.java | 13 +- src/eva2/gui/Graph.java | 191 ++- src/eva2/gui/GraphWindow.java | 271 ++-- src/eva2/gui/JEFrame.java | 85 +- src/eva2/gui/JEFrameRegister.java | 174 +- src/eva2/gui/JExtDesktopPane.java | 453 +++--- src/eva2/gui/JExtToolBar.java | 10 +- src/eva2/gui/JParaPanel.java | 65 +- src/eva2/gui/JTextoutputFrame.java | 100 +- src/eva2/gui/LoggingPanel.java | 16 +- src/eva2/gui/Mnemonic.java | 76 +- src/eva2/gui/Plot.java | 18 +- src/eva2/gui/PropertyDialog.java | 113 +- src/eva2/gui/PropertyPanel.java | 105 +- src/eva2/gui/PropertySheetPanel.java | 1079 +++++++------ src/eva2/gui/PropertySheetPanelStat.java | 41 +- src/eva2/gui/PropertySlider.java | 176 +- src/eva2/gui/PropertyText.java | 15 +- src/eva2/gui/PropertyValueSelector.java | 83 +- src/eva2/gui/StatisticsEditor.java | 70 +- src/eva2/gui/utils/CustomTabbedPaneUI.java | 248 +++ src/eva2/gui/utils/VerticalButtonUI.java | 86 + src/eva2/server/EvAMainAdapter.java | 34 +- src/eva2/server/EvAMainAdapterImpl.java | 39 +- src/eva2/server/ModuleServer.java | 104 +- src/eva2/server/RMIServerEvA.java | 2 +- src/eva2/server/go/InterfaceProcessor.java | 44 +- src/eva2/server/go/tools/FileTools.java | 7 +- .../GeneralGenericObjectEditorPanel.java | 2 +- .../server/modules/AbstractModuleAdapter.java | 344 ++-- src/eva2/server/modules/DEModuleAdapter.java | 25 +- src/eva2/server/modules/EPModuleAdapter.java | 23 +- src/eva2/server/modules/GAModuleAdapter.java | 21 +- src/eva2/server/modules/GOModuleAdapter.java | 64 +- .../server/modules/GenericModuleAdapter.java | 138 +- src/eva2/server/modules/HCModuleAdapter.java | 29 +- src/eva2/server/modules/MCModuleAdapter.java | 29 +- .../server/modules/MOEAModuleAdapter.java | 31 +- src/eva2/server/modules/ModuleAdapter.java | 75 +- .../server/modules/PBILModuleAdapter.java | 41 +- src/eva2/server/modules/PSOModuleAdapter.java | 31 +- src/eva2/server/modules/SAModuleAdapter.java | 18 +- .../server/modules/SSGAModuleAdapter.java | 33 +- src/eva2/server/stat/EvAJobList.java | 464 +++--- src/eva2/server/stat/StatisticsWithGUI.java | 4 +- src/eva2/tools/EVAHELP.java | 42 +- src/eva2/tools/ToolBoxGui.java | 32 +- src/eva2/tools/jproxy/ComAdapter.java | 7 +- src/eva2/tools/jproxy/JProxyRemoteThread.java | 21 +- src/eva2/tools/jproxy/MainAdapter.java | 30 +- src/eva2/tools/jproxy/MainAdapterClient.java | 6 - .../tools/jproxy/MainAdapterClientImpl.java | 6 - src/eva2/tools/jproxy/MainAdapterImpl.java | 239 ++- src/eva2/tools/jproxy/RMIServer.java | 258 +-- ...va => RMIServerNotAvailableException.java} | 14 +- .../jproxy/RMIThreadInvocationHandler.java | 6 - .../tools/jproxy/RemoteStateListener.java | 7 - 72 files changed, 5330 insertions(+), 4519 deletions(-) create mode 100644 resources/images/EvASplashScreen.png create mode 100644 resources/images/Help24.gif create mode 100644 resources/images/Open16.gif create mode 100644 resources/images/Save16.gif create mode 100644 src/eva2/gui/utils/CustomTabbedPaneUI.java create mode 100644 src/eva2/gui/utils/VerticalButtonUI.java rename src/eva2/tools/jproxy/{NO_RMIServerAvailable.java => RMIServerNotAvailableException.java} (51%) diff --git a/resources/images/EvASplashScreen.png b/resources/images/EvASplashScreen.png new file mode 100644 index 0000000000000000000000000000000000000000..8a894444545c117a696c436bc0342c398c0afcb8 GIT binary patch literal 474538 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ξ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 Rz~t6jZ9nyAZ`kw5{|ESvfj0mE literal 0 HcmV?d00001 diff --git a/resources/images/Help24.gif b/resources/images/Help24.gif new file mode 100644 index 0000000000000000000000000000000000000000..a2848d880e71f5765a874f913863aafc62579871 GIT binary patch literal 1328 zcmd^;`A^yh0L8zkTUo2Awc?zy_3PEt##+2}OE#!?r=7ZH(M($psK=}}f<_{>phy+O zs6i3rs@gEMa||!M01@OX)(R-fT1Bx&bZtys(yU9CeW!oN-p?<2@AHzEl#&<|o9_vD z0)N2(48tmwO1A@PtqUs4oWiU$+tF+OA_hDTs4n9)7d=Cp!88W%5ILL+xXFBfqz%-s(v%b1@!AoEzv|bm-mC@ci)byzq$A#Hg5}m}q=-RAE%i{g`N6bZk*<6{o7I zt4g#a;?8qfqb&Lmy+P7I7LscPwbh(zBAX~)5{vXA;i8bg!0*xaaMj$-*-rKhyItPi zI@-z_VKomo(+BC)ek!GpQYWq>@koRYf)En&wS3+@k2}ZZC^;+{iz#I`J#V5(Xw*I` zrI$h$kV#w;N5Scu?P3fw$b7N|wwV7hn?9Nh9}LUK%lacd^cGU@sg*XR)~=m?JuSD$ zC)Ov%&EpEIV*1te$h;d{{HzZL@tgzJv+aMdH+tF#QT4)E-ZR<3fnmNnd zlwnF~Rw`B%GsYRy8P6VS(1`qS;i7I zb`yTR4OYQtnz|Di${7uaVa%Mzc)`VTsDLnY~l)K4&A@P&c8wfCkst6lEbE~ETt zd-e1*UVmG}7dNTrQ^i7Yva!k7i@J_1yBbErwh0hX#mG*M0_~i2IFWiNAQDTCy&A zt_8Wb#8(u*TMWP@XGf-u9=K{8GO7Mg84xDEp6(MAKgbSz)|lcEO#3t!8CVjD^m3r3 z4ixm4d0n|64Zv1v7^U$;`-Yv1Jr_G<&tw=VW0lcpF29pD<#W@!xkFZT_4+rxRDG$N z3D!i_<4hg0``+MTKSJl~1>BAnkvtF5J`Pg;d$~S-f9jp7;4#MY%VL|;dAvaF&h+uhOLA^V|2Z!3cFt}> zHfe7ZD9Ch1JGR}b$@Kp`7n2{CeI+>q;d(9^dlziT$q+l`0% zWakqvOUu4CvpG) literal 0 HcmV?d00001 diff --git a/resources/images/Open16.gif b/resources/images/Open16.gif new file mode 100644 index 0000000000000000000000000000000000000000..fabd5676f96cf46b62fe3c91fce204c2339b64ea GIT binary patch literal 228 zcmZ?wbhEHb6krfw*!-X2KM*`S^X2Zb&v%ZV*}Lw{mRV;u&ssCHZS@QwYMt3ton~yz zz`$_ezyTl$1d2ad7#SFN8FWA#kQojvb{kH5u1-qNFOwm)DL zUM5f|DAMG)`M?5!8MjshY0h2MsCcKyI-XnYHYZ=p(kDk{gOnH)|M@%T7gQEyre~BW z7#SECC?r)X1efM1_+};-nM2UCF?0T=Hw^@ffN=i1f>?I7L}!@=<#xS W`M4>#2PuT57AY9&8Srv3SOWl92UWNL literal 0 HcmV?d00001 diff --git a/resources/images/Save16.gif b/resources/images/Save16.gif new file mode 100644 index 0000000000000000000000000000000000000000..954f1accde64db9e98e9a6e528b459f3027b018c GIT binary patch literal 206 zcmZ?wbhEHb6krfwSoELa|NsAI&YVe0OJiVQIB?(qkc0rmpDc_F3@i*fATCHP1G9t2 zt~>woPk7#DV0y9hrl_L@i#VrFyvHoHu9Y#Xr$ntic|`qh+poMi9i^@_{^mw_veB2b=gA~G2ixdp?40yR1tO0)kMS%bS literal 0 HcmV?d00001 diff --git a/src/eva2/EvAInfo.java b/src/eva2/EvAInfo.java index e361adff..6932786a 100644 --- a/src/eva2/EvAInfo.java +++ b/src/eva2/EvAInfo.java @@ -95,7 +95,7 @@ public class EvAInfo { public static final String GPLFile= "gpl-3.0.txt"; public static final String iconLocation = "resources/images/icon4.gif"; - public static final String splashLocation = "resources/images/splashScreen2.png"; + public static final String splashLocation = "resources/images/EvASplashScreen.png"; public static final String infoTitle = productName+" Information"; public static final String copyrightYear = "2010-2012"; diff --git a/src/eva2/client/EvAClient.java b/src/eva2/client/EvAClient.java index 45b5762b..6281310a 100644 --- a/src/eva2/client/EvAClient.java +++ b/src/eva2/client/EvAClient.java @@ -15,6 +15,7 @@ import eva2.EvAInfo; import eva2.gui.*; import eva2.server.EvAServer; import eva2.server.go.InterfaceGOParameters; +import eva2.server.go.strategies.GradientDescentAlgorithm; import eva2.server.modules.AbstractModuleAdapter; import eva2.server.modules.GOParameters; import eva2.server.modules.GenericModuleAdapter; @@ -28,8 +29,9 @@ import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.Set; -import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; @@ -50,7 +52,10 @@ public class EvAClient implements RemoteStateListener, Serializable { private final int splashScreenTime = 1500; private final int maxWindowMenuLength = 30; private boolean clientInited = false; - private JEFrame evaFrame; + private JDesktopPane desktopPane; + private JFrame mainFrame; + private JPanel configurationPane; + private JSplitPane horizontalSplit; private Runnable initRnbl = null; private EvAComAdapter comAdapter; @@ -95,7 +100,7 @@ public class EvAClient implements RemoteStateListener, Serializable { private long startTime = 0; // remember the module in use private transient String currentModule = null; - Vector superListenerList = null; + private List superListenerList = null; private boolean withGUI = true; private boolean withTreeView = false; private EvATabbedFrameMaker frameMaker = null; @@ -103,7 +108,7 @@ public class EvAClient implements RemoteStateListener, Serializable { public void addRemoteStateListener(RemoteStateListener l) { if (superListenerList == null) { - superListenerList = new Vector(); + superListenerList = new ArrayList(); } superListenerList.add(l); } @@ -332,8 +337,8 @@ public class EvAClient implements RemoteStateListener, Serializable { * @param l */ public void addWindowListener(WindowListener l) { - if (evaFrame != null) { - evaFrame.addWindowListener(l); + if (mainFrame != null) { + mainFrame.addWindowListener(l); } else { System.err.println("Error, no JFrame existent in " + this.getClass().getSimpleName()); @@ -346,8 +351,8 @@ public class EvAClient implements RemoteStateListener, Serializable { * @param l */ public void removeWindowListener(WindowListener l) { - if (evaFrame != null) { - evaFrame.removeWindowListener(l); + if (mainFrame != null) { + mainFrame.removeWindowListener(l); } else { System.err.println("Error, no JFrame existent in " + this.getClass().getSimpleName()); @@ -370,13 +375,25 @@ public class EvAClient implements RemoteStateListener, Serializable { } if (withGUI) { - evaFrame = new JEFrame(EvAInfo.productName + " workbench"); - evaFrame.setCloseAllOnClosed(true); - evaFrame.setName(this.getClass().getSimpleName()); // the name is set to recognize the client window - + GridBagConstraints gbConstraints = new GridBagConstraints(); + + /* Set Look and Feel */ + try { + //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception ex) { + LOGGER.log(Level.INFO, "Could not set Look&Feel", ex); + } + mainFrame = new JFrame(EvAInfo.productName + " Workbench"); + mainFrame.setLayout(new GridBagLayout()); + mainFrame.setMinimumSize(new Dimension(800, 600)); + desktopPane = new JExtDesktopPane(); + + JEFrameRegister.getInstance().setDesktopPane(desktopPane); + horizontalSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true); + BasicResourceLoader loader = BasicResourceLoader.instance(); byte[] bytes = loader.getBytesFromResourceLocation(EvAInfo.iconLocation, true); - evaFrame.setIconImage(Toolkit.getDefaultToolkit().createImage(bytes)); + mainFrame.setIconImage(Toolkit.getDefaultToolkit().createImage(bytes)); try { Thread.sleep(200); @@ -384,16 +401,9 @@ public class EvAClient implements RemoteStateListener, Serializable { System.out.println("Error" + e.getMessage()); } - progressBar = new JProgressBar(); - progressBar.setBorder(new TitledBorder("Progress")); - progressBar.setValue(0); - progressBar.setStringPainted(true); - evaFrame.getContentPane().add(progressBar, BorderLayout.NORTH); - - evaFrame.getContentPane().setLayout(new BorderLayout()); logPanel = new LoggingPanel(LOGGER); - evaFrame.getContentPane().add(logPanel, BorderLayout.SOUTH); - + logPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + if (EvAInfo.propShowModules() != null) { showLoadModules = true; @@ -401,10 +411,59 @@ public class EvAClient implements RemoteStateListener, Serializable { showLoadModules = false; // may be set to true again if default module couldnt be loaded } createActions(); + + mainFrame.setSize(800, 600); + + /* Create a new ConfigurationPanel (left side) */ + configurationPane = new JPanel(new GridBagLayout()); + gbConstraints.ipadx = 5; + gbConstraints.weightx = 0.0; + gbConstraints.weighty = 1.0; + /* Set configurationPane at 0,1 */ + gbConstraints.gridx = 0; + gbConstraints.gridy = 1; + gbConstraints.fill = GridBagConstraints.VERTICAL; + gbConstraints.gridwidth = GridBagConstraints.RELATIVE; + gbConstraints.gridheight = GridBagConstraints.RELATIVE; + mainFrame.add(configurationPane, gbConstraints); + + /* SplitPane for desktopPane and loggingPanel */ + horizontalSplit.setTopComponent(desktopPane); + horizontalSplit.setBottomComponent(logPanel); + horizontalSplit.setDividerLocation(0.25); + horizontalSplit.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1)); + horizontalSplit.setContinuousLayout(true); + /* Add horizontal split pane at 1,1 */ + gbConstraints.gridx = 1; + gbConstraints.gridy = 1; + gbConstraints.fill = GridBagConstraints.BOTH; + gbConstraints.gridwidth = GridBagConstraints.REMAINDER; + gbConstraints.gridheight = GridBagConstraints.RELATIVE; + mainFrame.add(horizontalSplit, gbConstraints); + + + /* Create ProgressBar and add it to the bottom */ + progressBar = new JProgressBar(); + progressBar.setBorder(new TitledBorder("Progress")); + progressBar.setValue(0); + progressBar.setStringPainted(true); + + gbConstraints.gridx = 0; + gbConstraints.gridy = 2; + gbConstraints.gridwidth = 2; + gbConstraints.weighty = 0.0; + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + gbConstraints.anchor = GridBagConstraints.PAGE_END; + mainFrame.add(progressBar, gbConstraints); + + mainFrame.pack(); + mainFrame.setVisible(true); } if (useDefaultModule != null) { - // if goParams are not defined and a params file is defined - // try to load parameters from file + /* + * if goParams are not defined and a params file is defined + * try to load parameters from file + */ if (goParams == null && (paramsFile != null && (paramsFile.length() > 0))) { goParams = GOParameters.getInstance(paramsFile, false); } @@ -413,9 +472,9 @@ public class EvAClient implements RemoteStateListener, Serializable { if (withGUI) { buildMenu(); - evaFrame.addWindowListener(new WindowAdapter() { + mainFrame.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { + public void windowClosing(final WindowEvent event) { EvAClient.this.close(); } }); @@ -433,12 +492,22 @@ public class EvAClient implements RemoteStateListener, Serializable { LOGGER.log(Level.INFO, "Working directory is: {0}", System.getProperty("user.dir")); LOGGER.log(Level.INFO, "Class path is: {0}", System.getProperty("java.class.path", ".")); - if (!(evaFrame.isVisible())) { + if (!(configurationPane.isVisible())) { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - evaFrame.setLocation((int) ((screenSize.width - evaFrame.getWidth()) / 2), (int) ((screenSize.height - evaFrame.getHeight()) / 2.5)); - evaFrame.pack(); - evaFrame.setVisible(true); + //evaFrame.setLocation((int) ((screenSize.width - evaFrame.getWidth()) / 2), (int) ((screenSize.height - evaFrame.getHeight()) / 2.5)); + configurationPane.setVisible(true); + } + + if (!(mainFrame.isVisible())) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + mainFrame.setLocation((int) ((screenSize.width - mainFrame.getWidth()) / 2), (int) ((screenSize.height - mainFrame.getHeight()) / 2.5)); + mainFrame.pack(); + mainFrame.setSize(screenSize); + mainFrame.setVisible(true); + mainFrame.setVisible(true); + } + // if this message is omitted, the stupid scroll pane runs to // the end of the last line which is ugly for a long class path LOGGER.info("EvA2 ready"); @@ -451,7 +520,6 @@ public class EvAClient implements RemoteStateListener, Serializable { */ public void close() { LOGGER.info("Closing EvA2 Client. Bye!"); - evaFrame.dispose(); Set keys = System.getenv().keySet(); if (keys.contains("MATLAB")) { LOGGER.info("EvA2 workbench has been started from Matlab: not killing JVM"); @@ -481,7 +549,12 @@ public class EvAClient implements RemoteStateListener, Serializable { * @param args command line parameters */ public static void main(String[] args) { - String[] keys = new String[]{"--help", "--autorun", "--nosplash", "--nogui", "--remotehost", "--params", "--treeView"}; + /* Available command-line parameters */ + String[] keys = new String[]{ + "--help", "--autorun", "--nosplash", "--nogui", + "--remotehost", "--params", "--treeView" + }; + /* Number of arguments per parameter */ int[] arities = new int[]{0, 0, 0, 0, 1, 1, 0}; Object[] values = new Object[keys.length]; @@ -532,9 +605,8 @@ public class EvAClient implements RemoteStateListener, Serializable { evaClient.awaitClientInitialized(); // this returns as soon as the // GUI is ready evaClient.addWindowListener(windowListener); - // modify initial settings: - evaClient.getStatistics().getStatisticsParameter().setOutputAllFieldsAsText(true); // activate output of all data - // fields + // modify initial settings and activate output of all data: + evaClient.getStatistics().getStatisticsParameter().setOutputAllFieldsAsText(true); // add a data listener instance: evaClient.getStatistics().addDataListener(statisticsListener); @@ -582,10 +654,8 @@ public class EvAClient implements RemoteStateListener, Serializable { actModuleLoad = new ExtAction("&Load", "Load Module", KeyStroke.getKeyStroke(KeyEvent.VK_L, Event.CTRL_MASK)) { - /* (non-Javadoc) - * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) - */ - public void actionPerformed(ActionEvent e) { + @Override + public void actionPerformed(final ActionEvent event) { loadModuleFromServer(null, null); } }; @@ -593,141 +663,123 @@ public class EvAClient implements RemoteStateListener, Serializable { actAbout = new ExtAction("&About...", "Product Information", KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK)) { - /* (non-Javadoc) - * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) - */ - public void actionPerformed(ActionEvent e) { - LOGGER.info(e.getActionCommand()); + @Override + public void actionPerformed(final ActionEvent event) { + LOGGER.info(event.getActionCommand()); showAboutDialog(); } }; actLicense = new ExtAction("&License...", "View License", KeyStroke.getKeyStroke(KeyEvent.VK_L, Event.CTRL_MASK)) { - /* (non-Javadoc) - * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) - */ - public void actionPerformed(ActionEvent e) { - LOGGER.info(e.getActionCommand()); + @Override + public void actionPerformed(final ActionEvent event) { + LOGGER.info(event.getActionCommand()); showLicense(); } }; actHost = new ExtAction("&List of all servers", "All servers in list", KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK)) { - /* (non-Javadoc) - * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) - */ - public void actionPerformed(ActionEvent e) { - LOGGER.info(e.getActionCommand()); + @Override + public void actionPerformed(final ActionEvent event) { + LOGGER.info(event.getActionCommand()); selectAvailableHost(comAdapter.getHostNameList()); } }; actAvailableHost = new ExtAction("Available &Server", "Available server", KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.CTRL_MASK)) { - /* (non-Javadoc) - * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) - */ - public void actionPerformed(ActionEvent e) { - LOGGER.info(e.getActionCommand()); + @Override + public void actionPerformed(final ActionEvent event) { + LOGGER.info(event.getActionCommand()); showPleaseWaitDialog(); - Thread xx = new Thread() { - + new Thread() { @Override public void run() { selectAvailableHost(comAdapter.getAvailableHostNameList()); } - }; - xx.start(); + }.start(); } }; actKillHost = new ExtAction("&Kill server", "Kill server process on selected host", KeyStroke.getKeyStroke(KeyEvent.VK_K, Event.CTRL_MASK)) { - /* (non-Javadoc) - * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) - */ - public void actionPerformed(ActionEvent e) { - LOGGER.info(e.getActionCommand()); - showPleaseWaitDialog(); - Thread xx = new Thread() { - + @Override + public void actionPerformed(final ActionEvent event) { + LOGGER.info(event.getActionCommand()); + new Thread() { + @Override public void run() { selectAvailableHostToKill(comAdapter.getAvailableHostNameList()); } - }; - xx.start(); + }.start(); + showPleaseWaitDialog(); } }; actKillAllHosts = new ExtAction("Kill &all servers", "Kill all servers", KeyStroke.getKeyStroke(KeyEvent.VK_K, Event.CTRL_MASK)) { - /* (non-Javadoc) - * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) - */ - public void actionPerformed(ActionEvent e) { - LOGGER.info(e.getActionCommand()); - showPleaseWaitDialog(); - Thread xx = new Thread() { - + @Override + public void actionPerformed(final ActionEvent event) { + LOGGER.info(event.getActionCommand()); + new Thread() { + @Override public void run() { selectAllAvailableHostToKill(comAdapter.getAvailableHostNameList()); } - }; - xx.start(); + }.start(); + showPleaseWaitDialog(); } }; actQuit = new ExtAction("&Quit", "Quit EvA2 workbench", KeyStroke.getKeyStroke(KeyEvent.VK_Q, Event.CTRL_MASK)) { - /* (non-Javadoc) - * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) - */ - public void actionPerformed(ActionEvent e) { + @Override + public void actionPerformed(final ActionEvent event) { EvAClient.this.close(); } }; - /* - * m_actStartServerManager = new ExtAction("Start &Server Manager", - * "Start &Server Manager", KeyStroke.getKeyStroke(KeyEvent.VK_S, - * Event.CTRL_MASK)){ public void actionPerformed(ActionEvent e){ - * m_LogPanel.logMessage(e.getActionCommand()); ServerStartFrame sm = - * new ServerStartFrame(m_ComAdapter.getHostNameList()); } }; - */ } + /** + * Create the main menu and add actions. + */ private void buildMenu() { menuBar = new JMenuBar(); - evaFrame.setJMenuBar(menuBar); + mainFrame.setJMenuBar(menuBar); menuModule = new JExtMenu("&Module"); menuModule.add(actModuleLoad); - //////////////////////////////////////////////////////////////// menuWindow = new JExtMenu("&Window"); menuWindow.addMenuListener(new MenuListener() { - public void menuSelected(MenuEvent e) { - // System.out.println("Selected"); + @Override + public void menuSelected(final MenuEvent event) { menuWindow.removeAll(); JExtMenu curMenu = menuWindow; -// JScrollPane jsp = new JScrollPane(); - Object[] framelist = JEFrameRegister.getFrameList(); - for (int i = 0; i < framelist.length; i++) { - JMenuItem act = new JMenuItem((i + 1) + ". " + ((JEFrame) framelist[i]).getTitle()); - final JFrame selectedFrame = ((JEFrame) framelist[i]); + List frameList = JEFrameRegister.getInstance().getFrameList(); + int frameIndex = 1; + for (JEFrame frame : frameList) { + + JMenuItem act = new JMenuItem(frameIndex + ". " + frame.getTitle()); + final JInternalFrame selectedFrame = frame; act.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (!selectedFrame.isActive()) { - selectedFrame.setExtendedState(JFrame.NORMAL); + @Override + public void actionPerformed(final ActionEvent event) { + if (!selectedFrame.isFocusOwner()) { + //selectedFrame..setExtendedState(JFrame.NORMAL); selectedFrame.setVisible(false); - selectedFrame.setVisible(true); // it seems to be quite a fuss to bring something to the front and actually mean it... - selectedFrame.toFront(); // this seems useless - selectedFrame.requestFocus(); // this seems useless too + // it seems to be quite a fuss to bring something to the front and actually mean it... + selectedFrame.setVisible(true); + // this seems useless + selectedFrame.toFront(); + // this seems useless too + selectedFrame.requestFocus(); } } }); @@ -739,20 +791,24 @@ public class EvAClient implements RemoteStateListener, Serializable { curMenu = subMenu; } curMenu.add(act); + + /* Next frame index */ + frameIndex++; } - String[] commonPrefixes = JEFrameRegister.getCommonPrefixes(10); + String[] commonPrefixes = JEFrameRegister.getInstance().getCommonPrefixes(10); if (commonPrefixes.length > 0) { menuWindow.add(new JSeparator()); } for (int i = 0; i < commonPrefixes.length; i++) { final String prefix = commonPrefixes[i]; JMenuItem act = new JMenuItem("Close all of " + prefix + "..."); - act.addActionListener((new ActionListener() { + act.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - JEFrameRegister.closeAllByPrefix(prefix); + @Override + public void actionPerformed(final ActionEvent event) { + JEFrameRegister.getInstance().closeAllByPrefix(prefix); } - })); + }); menuWindow.add(act); } @@ -765,7 +821,6 @@ public class EvAClient implements RemoteStateListener, Serializable { } }); - //////////////////////////////////////////////////////////////// menuSelHosts = new JExtMenu("&Select Hosts"); menuSelHosts.setToolTipText("Select a host for the server application"); menuSelHosts.add(actHost); @@ -773,11 +828,10 @@ public class EvAClient implements RemoteStateListener, Serializable { menuSelHosts.addSeparator(); menuSelHosts.add(actKillHost); menuSelHosts.add(actKillAllHosts); - //////////////////////////////////////////////////////////////// + menuAbout = new JExtMenu("&About"); menuAbout.add(actAbout); menuAbout.add(actLicense); - ////////////////////////////////////////////////////////////// menuOptions = new JExtMenu("&Options"); menuOptions.add(menuSelHosts); @@ -790,18 +844,11 @@ public class EvAClient implements RemoteStateListener, Serializable { menuBar.add(menuOptions); menuBar.add(menuWindow); menuBar.add(menuAbout); + + menuBar.add(((JExtDesktopPane) desktopPane).getWindowMenu()); } - public static String getProductName() { - return EvAInfo.productName; - } - - protected void logMessage(String msg) { - if (logPanel != null) { - logPanel.logMessage(msg); - } - } /** * @@ -830,7 +877,7 @@ public class EvAClient implements RemoteStateListener, Serializable { if (selectedModule == null) { // show a dialog and ask for a module String[] ModuleNameList = comAdapter.getModuleNameList(); if (ModuleNameList == null) { - JOptionPane.showMessageDialog(evaFrame.getContentPane(), "No modules available on " + comAdapter.getHostName(), EvAInfo.infoTitle, 1); + JOptionPane.showMessageDialog(configurationPane, "No modules available on " + comAdapter.getHostName(), EvAInfo.infoTitle, 1); } else { String lastModule = null; @@ -846,7 +893,7 @@ public class EvAClient implements RemoteStateListener, Serializable { LOGGER.log(Level.INFO, "Defaulting to module: {0}", lastModule); } - selectedModule = (String) JOptionPane.showInputDialog(evaFrame.getContentPane(), + selectedModule = (String) JOptionPane.showInputDialog(configurationPane, "Which module do you want \n to load on host: " + comAdapter.getHostName() + " ?", "Load optimization module on host", JOptionPane.QUESTION_MESSAGE, @@ -858,7 +905,7 @@ public class EvAClient implements RemoteStateListener, Serializable { if (selectedModule == null) { System.err.println("not loading any module"); - } else { + } else { try { java.util.prefs.Preferences prefs = java.util.prefs.Preferences.userRoot(); prefs.put("lastModule", selectedModule); @@ -872,7 +919,7 @@ public class EvAClient implements RemoteStateListener, Serializable { actHost.setEnabled(true); actAvailableHost.setEnabled(true); } - LOGGER.info("Selected Module: " + selectedModule); + LOGGER.log(Level.INFO, "Selected Module: {0}", selectedModule); } } @@ -951,36 +998,41 @@ public class EvAClient implements RemoteStateListener, Serializable { if (withGUI) { // this (or rather: EvAModuleButtonPanelMaker) is where the start button etc come from! frameMaker = newModuleAdapter.getModuleFrame(); -// newModuleAdapter.setLogPanel(m_LogPanel); - JPanel moduleContainer = frameMaker.makePanel(); // MK the main frame is actually painted in here - boolean wasVisible = evaFrame.isVisible(); - evaFrame.setVisible(false); - evaFrame.getContentPane().removeAll(); + /* This is the left TabPane on the main frame */ + JPanel moduleContainer = frameMaker.makePanel(); + + boolean wasVisible = configurationPane.isVisible(); + configurationPane.setVisible(false); + configurationPane.removeAll(); - // nested info-panel so that we can stay with simple borderlayouts - JPanel infoPanel = new JPanel(); - infoPanel.setLayout(new BorderLayout()); - infoPanel.add(progressBar, BorderLayout.SOUTH); - infoPanel.add(logPanel, BorderLayout.NORTH); JComponent tree = null; - if (withTreeView && (newModuleAdapter instanceof AbstractModuleAdapter)) { tree = getEvATreeView(frameMaker.getGOPanel(), "GOParameters", ((AbstractModuleAdapter) newModuleAdapter).getGOParameters()); - evaFrame.add(tree, BorderLayout.WEST); + configurationPane.add(tree, BorderLayout.LINE_START); } - evaFrame.add(frameMaker.getToolBar(), BorderLayout.NORTH); - evaFrame.add(moduleContainer, BorderLayout.CENTER); - //m_Frame.add(m_ProgressBar, BorderLayout.CENTER); - //m_Frame.add(m_LogPanel, BorderLayout.SOUTH); - evaFrame.add(infoPanel, BorderLayout.SOUTH); - - evaFrame.pack(); - evaFrame.setVisible(wasVisible); + + GridBagConstraints gbConstraints = new GridBagConstraints(); + gbConstraints.weightx = 1.0; + gbConstraints.weighty = 0.0; + gbConstraints.gridx = 0; + gbConstraints.gridy = 0; + gbConstraints.gridwidth = 2; + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + gbConstraints.anchor = GridBagConstraints.PAGE_START; + mainFrame.add(frameMaker.getToolBar(), gbConstraints); + + GridBagConstraints gbConstraints2 = new GridBagConstraints(); + gbConstraints2.gridx = 0; + gbConstraints2.gridy = 0; + gbConstraints2.fill = GridBagConstraints.VERTICAL; + gbConstraints2.gridheight = GridBagConstraints.REMAINDER; + gbConstraints2.weighty = 1.0; + configurationPane.add(moduleContainer, gbConstraints2); + configurationPane.validate(); } currentModule = selectedModule; - // m_ModulGUIContainer.add(Temp); } catch (Exception e) { currentModule = null; LOGGER.log(Level.SEVERE, "Error while newModulAdapter.getModulFrame(): " + e.getMessage(), e); @@ -1029,7 +1081,7 @@ public class EvAClient implements RemoteStateListener, Serializable { if (hostNames == null || hostNames.length == 0) { showNoHostFoundDialog(); } else { - String hostName = (String) JOptionPane.showInputDialog(evaFrame.getContentPane(), + String hostName = (String) JOptionPane.showInputDialog(configurationPane, "Which active host do you want to connect to?", "Host", JOptionPane.QUESTION_MESSAGE, null, hostNames, comAdapter.getHostName()); if (hostName != null) { @@ -1048,7 +1100,7 @@ public class EvAClient implements RemoteStateListener, Serializable { } private void showPleaseWaitDialog() { - JOptionPane.showMessageDialog(evaFrame.getContentPane(), "Please wait one moment.", EvAInfo.infoTitle, 1); + JOptionPane.showMessageDialog(configurationPane, "Please wait one moment.", EvAInfo.infoTitle, 1); } private void showAboutDialog() { @@ -1065,7 +1117,7 @@ public class EvAClient implements RemoteStateListener, Serializable { aboutMessage.append("\nSee: "); aboutMessage.append(EvAInfo.url); - JOptionPane.showMessageDialog(evaFrame, aboutMessage, EvAInfo.infoTitle, 1); + JOptionPane.showMessageDialog(configurationPane, aboutMessage, EvAInfo.infoTitle, 1); } private void showLicense() { @@ -1076,7 +1128,7 @@ public class EvAClient implements RemoteStateListener, Serializable { } private void showNoHostFoundDialog() { - JOptionPane.showMessageDialog(evaFrame.getContentPane(), "No host with running EVASERVER found. Please start one or \nadd the correct address to the properties list.", EvAInfo.infoTitle, 1); + JOptionPane.showMessageDialog(configurationPane, "No host with running EVASERVER found. Please start one or \nadd the correct address to the properties list.", EvAInfo.infoTitle, 1); } private void selectAvailableHostToKill(String[] HostNames) { @@ -1084,7 +1136,7 @@ public class EvAClient implements RemoteStateListener, Serializable { showNoHostFoundDialog(); return; } - String HostName = (String) JOptionPane.showInputDialog(evaFrame.getContentPane(), + String HostName = (String) JOptionPane.showInputDialog(configurationPane, "Which server do you want to be killed ?", "Host", JOptionPane.QUESTION_MESSAGE, null, HostNames, comAdapter.getHostName()); if (HostName == null) { diff --git a/src/eva2/client/EvAComAdapter.java b/src/eva2/client/EvAComAdapter.java index e1dfa64f..c37a2f4a 100644 --- a/src/eva2/client/EvAComAdapter.java +++ b/src/eva2/client/EvAComAdapter.java @@ -23,15 +23,15 @@ import java.rmi.RemoteException; * */ public class EvAComAdapter extends ComAdapter { - private LoggingPanel m_LogPanel; + private LoggingPanel loggingPanel; private EvAMainAdapterImpl localMainAdapter; private boolean runLocally = false; /** * */ - public void setLogPanel(LoggingPanel OutputFrame) { - m_LogPanel = OutputFrame; + public void setLogPanel(LoggingPanel loggingPanel) { + this.loggingPanel = loggingPanel; } /** * @@ -51,12 +51,14 @@ public class EvAComAdapter extends ComAdapter { public ModuleAdapter getModuleAdapter(String selectedModuleName, InterfaceGOParameters goParams, String noGuiStatsFile) { ModuleAdapter newModuleAdapter; if ((m_RMIServer == null) && isRunLocally()) { - //ret = evaAdapter.getModuleAdapter(Modul, hostAdd, this.m_MainAdapterClient); - newModuleAdapter = getLocalMainAdapter().getModuleAdapter(selectedModuleName, true, getHostName(), goParams, noGuiStatsFile, null); - } else { - newModuleAdapter = ((RMIConnectionEvA)getConnection(getHostName())).getModuleAdapter(selectedModuleName); - if (newModuleAdapter == null) System.err.println("RMI Error for getting ModuleAdapterObject : " + selectedModuleName); - } + //ret = evaAdapter.getModuleAdapter(Modul, hostAdd, this.m_MainAdapterClient); + newModuleAdapter = getLocalMainAdapter().getModuleAdapter(selectedModuleName, true, getHostName(), goParams, noGuiStatsFile, null); + } else { + newModuleAdapter = ((RMIConnectionEvA) getConnection(getHostName())).getModuleAdapter(selectedModuleName); + if (newModuleAdapter == null) { + System.err.println("RMI Error for getting ModuleAdapterObject : " + selectedModuleName); + } + } return newModuleAdapter; } @@ -86,12 +88,12 @@ public class EvAComAdapter extends ComAdapter { } list = ((EvAMainAdapter)Connection.getMainAdapter()).getModuleNameList(); } - if (m_LogPanel != null) - m_LogPanel.logMessage("List of modules on server:"); + if (loggingPanel != null) + loggingPanel.logMessage("List of modules on server:"); if (list != null) for (int i = 0; i < list.length; i++) { - if ( (String) list[i] != null && m_LogPanel != null) - m_LogPanel.logMessage( (String) list[i]); + if ( (String) list[i] != null && loggingPanel != null) + loggingPanel.logMessage( (String) list[i]); } return list; } diff --git a/src/eva2/gui/BeanInspector.java b/src/eva2/gui/BeanInspector.java index d0d56b66..c78bd26e 100644 --- a/src/eva2/gui/BeanInspector.java +++ b/src/eva2/gui/BeanInspector.java @@ -889,31 +889,36 @@ public class BeanInspector { * @param target The target object * @return String for the tooltip. */ - public static String getToolTipText(String name, MethodDescriptor[] methods, Object target, boolean stripToolTipToFirstPoint, int toHTMLLen) { - String result = ""; - String tipName = name + "TipText"; - for (int j = 0; j < methods.length; j++) { - String mname = methods[j].getDisplayName(); - Method meth = methods[j].getMethod(); - if (mname.equals(tipName)) { - if (meth.getReturnType().equals(String.class)) { - try { - Object args[] = { }; - String tempTip = (String)(meth.invoke(target, args)); - result = tempTip; - if (stripToolTipToFirstPoint) { - int ci = tempTip.indexOf('.'); - if (ci > 0) result = tempTip.substring(0, ci); - } - } catch (Exception ex) { - } - break; - } - } - } // end for looking for tiptext - if (toHTMLLen > 0) return StringTools.toHTML(result, toHTMLLen); - else return result; - } + public static String getToolTipText(String name, MethodDescriptor[] methods, Object target, boolean stripToolTipToFirstPoint, int toHTMLLen) { + String result = ""; + String tipName = name + "TipText"; + for (int j = 0; j < methods.length; j++) { + String mname = methods[j].getDisplayName(); + Method meth = methods[j].getMethod(); + if (mname.equals(tipName)) { + if (meth.getReturnType().equals(String.class)) { + try { + Object args[] = {}; + String tempTip = (String) (meth.invoke(target, args)); + result = tempTip; + if (stripToolTipToFirstPoint) { + int ci = tempTip.indexOf('.'); + if (ci > 0) { + result = tempTip.substring(0, ci); + } + } + } catch (Exception ex) { + } + break; + } + } + } // end for looking for tiptext + if (toHTMLLen > 0) { + return StringTools.toHTML(result, toHTMLLen); + } else { + return result; + } + } /** * This method simply looks for an appropriate tool tip text diff --git a/src/eva2/gui/BigStringEditor.java b/src/eva2/gui/BigStringEditor.java index 08f05c3c..0dbc77b2 100644 --- a/src/eva2/gui/BigStringEditor.java +++ b/src/eva2/gui/BigStringEditor.java @@ -16,6 +16,8 @@ import java.beans.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; +import javax.swing.event.InternalFrameAdapter; +import javax.swing.event.InternalFrameEvent; /*==========================================================================* * CLASS DECLARATION @@ -40,11 +42,14 @@ public class BigStringEditor implements PropertyEditor { PropertyDialog frame = new PropertyDialog(editor,file, 50, 50); //frame.setSize(200, 200); - frame.addWindowListener(new WindowAdapter() { - public void windowClosing (WindowEvent e) { - m_finished=true; - } - }); + frame.addInternalFrameListener(new InternalFrameAdapter() { + + @Override + public void internalFrameClosing(InternalFrameEvent e) { + super.internalFrameClosing(e); + m_finished = true; + } + }); while (m_finished==false) { try {Thread.sleep(1000);} catch (Exception e) { @@ -187,11 +192,14 @@ public class BigStringEditor implements PropertyEditor { PropertyDialog frame = new PropertyDialog(editor, "test", 50, 50); frame.setSize(200, 200); - frame.addWindowListener(new WindowAdapter() { - public void windowClosing (WindowEvent e) { - System.exit(0); - } - }); + frame.addInternalFrameListener(new InternalFrameAdapter() { + + @Override + public void internalFrameClosing(InternalFrameEvent e) { + super.internalFrameClosing(e); + System.exit(0); + } + }); // editor.setValue(so); } catch (Exception e) { e.printStackTrace(); diff --git a/src/eva2/gui/EvATabbedFrameMaker.java b/src/eva2/gui/EvATabbedFrameMaker.java index 66ab404c..3cfa16fd 100644 --- a/src/eva2/gui/EvATabbedFrameMaker.java +++ b/src/eva2/gui/EvATabbedFrameMaker.java @@ -1,17 +1,13 @@ package eva2.gui; /* - * Title: EvA2 - * Description: - * Copyright: Copyright (c) 2003 - * Company: University of Tuebingen, Computer Architecture - * @author Holger Ulmer, Felix Streichert, Hannes Planatscher - * @version: $Revision: 272 $ - * $Date: 2007-11-21 18:06:36 +0100 (Wed, 21 Nov 2007) $ - * $Author: mkron $ + * Title: EvA2 Description: Copyright: Copyright (c) 2003 Company: University of Tuebingen, Computer + * Architecture @author Holger Ulmer, Felix Streichert, Hannes Planatscher @version: $Revision: 272 + * $ $Date: 2007-11-21 18:06:36 +0100 (Wed, 21 Nov 2007) $ $Author: mkron $ + */ +/* + * ==========================================================================* IMPORTS + *========================================================================== */ -/*==========================================================================* - * IMPORTS - *==========================================================================*/ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; @@ -25,124 +21,280 @@ import javax.swing.JTabbedPane; import eva2.server.go.InterfaceNotifyOnInformers; import eva2.server.go.problems.InterfaceAdditionalPopulationInformer; +import java.awt.*; +import java.awt.event.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.*; +import javax.swing.plaf.TabbedPaneUI; +import javax.swing.plaf.basic.BasicButtonUI; /** - * Produces the main EvA2 frame and a tool bar instance. - * TODO This class should be removed alltogether. + * Produces the main EvA2 frame and a tool bar instance. TODO This class should be removed + * alltogether. */ public class EvATabbedFrameMaker implements Serializable, PanelMaker, InterfaceNotifyOnInformers { - private static final long serialVersionUID = 2637376545826821423L; - private ArrayList pmContainer = null; - private JExtToolBar m_BarStandard; - EvAModuleButtonPanelMaker butPanelMkr=null; - - public EvATabbedFrameMaker() { - pmContainer = null; - } - - public void addPanelMaker(PanelMaker pm) { - if (pmContainer==null) pmContainer = new ArrayList(2); - pmContainer.add(pm); - } - public JPanel makePanel() { - JPanel m_SuperPanel = new JPanel(); - m_SuperPanel.setLayout(new GridBagLayout()); - GridBagConstraints gbconst = new GridBagConstraints(); - gbconst.fill = GridBagConstraints.BOTH; - gbconst.weightx = 1; - gbconst.weighty = 1; - gbconst.gridwidth = GridBagConstraints.REMAINDER; + private static final Logger LOGGER = Logger.getLogger(eva2.EvAInfo.defaultLogger); + private static final long serialVersionUID = 2637376545826821423L; + private ArrayList pmContainer = null; + private JExtToolBar extToolBar; + EvAModuleButtonPanelMaker butPanelMkr = null; + private JTabbedPane tabbedPane; - final JTabbedPane m_MainPanel = new JTabbedPane(); -// m_MainPanel.addChangeListener(new ChangeListener() { -// /* -// * This listener was added to catch the switch to the statistics panel. In that event, -// * the stats selection string may have to be updated. -// */ -// public void stateChanged(ChangeEvent e) { -//// System.out.println("AAAA " + e.toString()); -// if (m_MainPanel.getSelectedIndex()==1) { -// // the statistics panel is being activated! -//// System.out.println(guiContainer); -// // the third object should be the statistics panel, refer to GenericModuleAdapter -// JParaPanel statsPan = (JParaPanel) guiContainer.get(2); -//// System.out.println(statsPan.m_LocalParameter); -//// statsPan.m_Editor.setValue(statsPan.m_Editor.getValue()); // really update the contents of the stats panel -- - // this is now done in a cleaner way using this class as a listener from AbstractGOParameters -// } -// }}); - - m_BarStandard = new JExtToolBar(); - m_BarStandard.setFloatable(false); - - for (int i=0;i(2); + } + pmContainer.add(pm); + } - public void refreshPanels() { - for (PanelMaker jpp : pmContainer) { - if (jpp instanceof JParaPanel) ((JParaPanel)jpp).m_Editor.setValue(((JParaPanel)jpp).m_Editor.getValue()); - } - } - - public void setInformers( - List informers) { - // if the informers have changed, update the GUI element which displays them - try { - JParaPanel statsPan = getStatsPanel(); - if (statsPan.m_Editor!=null) { - statsPan.m_Editor.setValue(statsPan.m_Editor.getValue()); // really update the contents of the stats panel -// System.out.println("OOO setting informers to stats panel succeeded!"); - } - } catch(Exception e) { - System.err.println("Failed to update statistics panel from " + this.getClass()); - System.err.println(e.getMessage()); - e.printStackTrace(System.err); - } - } + public JPanel makePanel() { + JPanel tabControlPanel = new JPanel(new GridBagLayout()); - public JParaPanel getGOPanel() { - try { - JParaPanel sP = (JParaPanel) pmContainer.get(1); - return sP; - } catch(Exception e) { - System.err.println("Failed to get GO panel from " + this.getClass()); - } - return null; - } - - public JParaPanel getStatsPanel() { - try { - JParaPanel sP = (JParaPanel) pmContainer.get(2); - return sP; - } catch(Exception e) { - System.err.println("Failed to get statistics panel from " + this.getClass()); - } - return null; - } + GridBagConstraints gbConstraints = new GridBagConstraints(); + gbConstraints.fill = GridBagConstraints.VERTICAL; + gbConstraints.gridy = 0; + + tabbedPane = new JTabbedPane(); + tabbedPane.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1)); + //tabbedPane.setUI(new eva2.gui.utils.CustomTabbedPaneUI()); + tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + + + /* This toolbar will hold the closed tabs */ + JToolBar tabToolBar = new JToolBar(JToolBar.VERTICAL); + tabToolBar.setFloatable(false); + + /* ToDo: The control buttons shouldn't be added here.. */ + extToolBar = new JExtToolBar(); + extToolBar.setFloatable(false); + + for (PanelMaker element : pmContainer) { + JComponent panel = element.makePanel(); + if (element instanceof EvAModuleButtonPanelMaker) { + extToolBar.add(panel); + butPanelMkr = (EvAModuleButtonPanelMaker) element; + } else if (element instanceof JParaPanel) { + tabbedPane.addTab(((JParaPanel) element).getName(), panel); + } + } + + for (int i = 0; i < tabbedPane.getTabCount(); i++) { + tabbedPane.setTabComponentAt(i, new ClosableTabComponent(tabbedPane, tabToolBar)); + } + + gbConstraints.weighty = 1.0; + gbConstraints.gridx = 0; + tabControlPanel.add(tabToolBar, gbConstraints); + gbConstraints.gridx = 1; + tabControlPanel.add(tabbedPane, gbConstraints); + tabbedPane.validate(); + return tabControlPanel; + } + + /** + * @deprecated + * @return The toolbar with control buttons + */ + public JExtToolBar getToolBar() { + return extToolBar; + } + + /** + * Emulate pressing the start button. + */ + public void onUserStart() { + if (butPanelMkr != null) { + butPanelMkr.onUserStart(); + } else { + System.err.println("Error: button panel was null (EvATabbedFrameMaker)"); + } + } + + public void refreshPanels() { + for (PanelMaker jpp : pmContainer) { + if (jpp instanceof JParaPanel) { + ((JParaPanel) jpp).propertyEditor.setValue(((JParaPanel) jpp).propertyEditor.getValue()); + } + } + } + + public void setInformers(List informers) { + // if the informers have changed, update the GUI element which displays them + try { + JParaPanel statsPan = getStatsPanel(); + if (statsPan.propertyEditor != null) { + // really update the contents of the stats panel + statsPan.propertyEditor.setValue(statsPan.propertyEditor.getValue()); + } + } catch (Exception e) { + System.err.println("Failed to update statistics panel from " + this.getClass()); + System.err.println(e.getMessage()); + e.printStackTrace(System.err); + } + } + + public JParaPanel getGOPanel() { + try { + JParaPanel sP = (JParaPanel) pmContainer.get(1); + return sP; + } catch (Exception e) { + System.err.println("Failed to get GO panel from " + this.getClass()); + } + return null; + } + + public JParaPanel getStatsPanel() { + try { + JParaPanel sP = (JParaPanel) pmContainer.get(2); + return sP; + } catch (Exception e) { + System.err.println("Failed to get statistics panel from " + this.getClass()); + } + return null; + } } + +/** + * Component to be used as tabComponent; + * Contains a JLabel to show the text and + * a JButton to close the tab it belongs to + */ +class ClosableTabComponent extends JPanel { + private final JTabbedPane pane; + private final JToolBar toolBar; + + public ClosableTabComponent(final JTabbedPane pane, final JToolBar toolBar) { + super(new FlowLayout(FlowLayout.LEADING, 0, 0)); + + if (pane == null) { + throw new NullPointerException("TabbedPane is null"); + } + this.pane = pane; + this.toolBar = toolBar; + this.toolBar.setVisible(false); + setOpaque(false); + + //make JLabel read titles from JTabbedPane + JLabel label = new JLabel() { + public String getText() { + int index = pane.indexOfTabComponent(ClosableTabComponent.this); + if (index != -1) { + return pane.getTitleAt(index); + } + return null; + } + }; + + add(label); + //add more space between the label and the button + label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + //tab button + JButton button = new TabButton(); + add(button); + //add more space to the top of the component + setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0)); + } + + private class TabButton extends JButton implements ActionListener { + public TabButton() { + int size = 17; + setPreferredSize(new Dimension(size, size)); + setToolTipText("Hide this Tab"); + //Make the button looks the same for all Laf's + setUI(new BasicButtonUI()); + //Make it transparent + setContentAreaFilled(false); + //No need to be focusable + setFocusable(false); + setBorder(BorderFactory.createEtchedBorder()); + setBorderPainted(false); + //Making nice rollover effect + //we use the same listener for all buttons + addMouseListener(buttonMouseListener); + setRolloverEnabled(true); + //Close the proper tab by clicking the button + addActionListener(this); + } + + public void actionPerformed(ActionEvent e) { + int i = pane.indexOfTabComponent(ClosableTabComponent.this); + if (i != -1) { + final String tabTitle = pane.getTitleAt(i); + final Component tabPane = pane.getComponentAt(i); + final int tabPosition = i; + pane.remove(i); + if(pane.getTabCount() == 0) { + pane.setVisible(false); + } + /* Create a button to be shown in the ToolBar */ + JButton tabButton = new JButton(tabTitle); + /* Rotate it by -90° */ + tabButton.setUI(new eva2.gui.utils.VerticalButtonUI(-90)); + tabButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + /* Add the Tab Panel again */ + pane.insertTab(tabTitle, null, tabPane, "", tabPosition); + pane.setVisible(true); + /* Remove the Button */ + toolBar.remove((Component)e.getSource()); + /* If the Button was the last one, hide ToolBar again */ + if(toolBar.getComponentCount() == 0) { + toolBar.setVisible(false); + } + } + }); + /* Add it to the ToolBar */ + if(!toolBar.isVisible()) { + toolBar.setVisible(true); + } + toolBar.add(tabButton); + } + } + + //we don't want to update UI for this button + public void updateUI() { + } + + //paint the cross + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g.create(); + //shift the image for pressed buttons + if (getModel().isPressed()) { + g2.translate(1, 1); + } + g2.setStroke(new BasicStroke(2)); + g2.setColor(Color.BLACK); + int delta = 6; + g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1); + g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1); + g2.dispose(); + } + } + + private final static MouseListener buttonMouseListener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + Component component = e.getComponent(); + if (component instanceof AbstractButton) { + AbstractButton button = (AbstractButton) component; + button.setBorderPainted(true); + } + } + + public void mouseExited(MouseEvent e) { + Component component = e.getComponent(); + if (component instanceof AbstractButton) { + AbstractButton button = (AbstractButton) component; + button.setBorderPainted(false); + } + } + }; +} \ No newline at end of file diff --git a/src/eva2/gui/ExtDesktopManager.java b/src/eva2/gui/ExtDesktopManager.java index 1c7ea1cb..1084673c 100644 --- a/src/eva2/gui/ExtDesktopManager.java +++ b/src/eva2/gui/ExtDesktopManager.java @@ -9,62 +9,79 @@ package eva2.gui; * $Date: 2006-01-18 11:02:22 +0100 (Wed, 18 Jan 2006) $ * $Author: streiche $ */ -/*==========================================================================* - * IMPORTS - *==========================================================================*/ -import javax.swing.*; -import java.awt.*; +import java.awt.Component; +import java.awt.Event; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.DefaultDesktopManager; +import javax.swing.JInternalFrame; +import javax.swing.JMenuItem; +import javax.swing.KeyStroke; + /** * */ -public class ExtDesktopManager extends DefaultDesktopManager{ - int WINDOW_LIST_START; - public final static String INDEX = "Index"; - public final static String FRAME = "Frame"; - private JInternalFrame activeFrame = null; - private JExtDesktopPane desktop; - public ExtDesktopManager(JExtDesktopPane desktop){ - this.desktop = desktop; - } - public void activateFrame(JInternalFrame f){ - super.activateFrame(f); - activeFrame = f; - } - public void deactivateFrame(JInternalFrame f){ - super.deactivateFrame(f); - if(activeFrame == f) activeFrame = null; - } - public JInternalFrame getActiveFrame(){ - return activeFrame; - } - public void closeFrame(JInternalFrame f){ - System.out.println("closed internalframe called"); - super.closeFrame(f); - int index = ((Integer)f.getClientProperty(INDEX)).intValue() + WINDOW_LIST_START - 1; - int i; - desktop.m_mnuWindow.remove(index); - for(i = index; i < Math.min(WINDOW_LIST_START + 9, desktop.m_mnuWindow.getItemCount()); i++){ - JMenuItem m = desktop.m_mnuWindow.getItem(i); - JInternalFrame frame = (JInternalFrame)m.getClientProperty(FRAME); - frame.putClientProperty(INDEX, new Integer(((Integer)frame.getClientProperty(INDEX)).intValue() - 1)); - int winIndex = i - WINDOW_LIST_START + 1; - m.setText((winIndex) + " " + frame.getTitle()); - m.setMnemonic((char)(0x30 + winIndex)); - m.setAccelerator(KeyStroke.getKeyStroke(0x30 + winIndex, Event.ALT_MASK)); +public class ExtDesktopManager extends DefaultDesktopManager { + + private static final Logger LOGGER = Logger.getLogger(eva2.EvAInfo.defaultLogger); + + int WINDOW_LIST_START; + public final static String INDEX = "Index"; + public final static String FRAME = "Frame"; + private JInternalFrame activeFrame = null; + private JExtDesktopPane desktop; + + public ExtDesktopManager(JExtDesktopPane desktop) { + this.desktop = desktop; } - if(f.isSelected()){ - Component tmp = null; - boolean found = false; - for(i = 0; i < desktop.getComponentCount() && !found; i++){ - tmp = desktop.getComponent(i); - if(tmp instanceof JInternalFrame) found = true; - } - - if(found) desktop.selectFrame((JInternalFrame)tmp); - else activeFrame = null; + public void activateFrame(JInternalFrame f) { + super.activateFrame(f); + activeFrame = f; + } + + public void deactivateFrame(JInternalFrame f) { + super.deactivateFrame(f); + if (activeFrame == f) { + activeFrame = null; + } + } + + public JInternalFrame getActiveFrame() { + return activeFrame; + } + + public void closeFrame(JInternalFrame internalFrame) { + LOGGER.log(Level.FINE, "Closing Internal Frame: {0}", internalFrame.getTitle()); + super.closeFrame(internalFrame); + int index = ((Integer) internalFrame.getClientProperty(INDEX)).intValue() + WINDOW_LIST_START - 1; + int i; + desktop.m_mnuWindow.remove(index); + for (i = index; i < Math.min(WINDOW_LIST_START + 9, desktop.m_mnuWindow.getItemCount()); i++) { + JMenuItem m = desktop.m_mnuWindow.getItem(i); + JInternalFrame frame = (JInternalFrame) m.getClientProperty(FRAME); + frame.putClientProperty(INDEX, new Integer(((Integer) frame.getClientProperty(INDEX)).intValue() - 1)); + int winIndex = i - WINDOW_LIST_START + 1; + m.setText((winIndex) + " " + frame.getTitle()); + m.setMnemonic((char) (0x30 + winIndex)); + m.setAccelerator(KeyStroke.getKeyStroke(0x30 + winIndex, Event.ALT_MASK)); + } + + if (internalFrame.isSelected()) { + Component tmp = null; + boolean found = false; + for (i = 0; i < desktop.getComponentCount() && !found; i++) { + tmp = desktop.getComponent(i); + if (tmp instanceof JInternalFrame) { + found = true; + } + } + + if (found) { + desktop.selectFrame((JInternalFrame) tmp); + } else { + activeFrame = null; + } + } } - } } - - diff --git a/src/eva2/gui/GOEPanel.java b/src/eva2/gui/GOEPanel.java index 4330fe90..a5a62adf 100644 --- a/src/eva2/gui/GOEPanel.java +++ b/src/eva2/gui/GOEPanel.java @@ -1,10 +1,11 @@ package eva2.gui; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.GridLayout; -import java.awt.Window; +import eva2.server.go.tools.FileTools; +import eva2.tools.BasicResourceLoader; +import eva2.tools.EVAHELP; +import eva2.tools.SerializedObject; +import eva2.tools.jproxy.RMIProxyLocal; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; @@ -18,370 +19,437 @@ import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; import java.util.Vector; - -import javax.swing.BorderFactory; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JList; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; +import javax.swing.*; import javax.swing.plaf.basic.BasicComboBoxRenderer; -import eva2.server.go.tools.FileTools; -import eva2.tools.EVAHELP; -import eva2.tools.SerializedObject; -import eva2.tools.jproxy.RMIProxyLocal; /** -* -*/ + * + */ public class GOEPanel extends JPanel implements ItemListener { - private Object m_Backup; - private PropertyChangeSupport m_Support; - private static boolean TRACE = false; - - /** The chooser component */ - private JComboBox m_ObjectChooser; - /** The component that performs classifier customization */ - private PropertySheetPanel m_ChildPropertySheet; - /** The model containing the list of names to select from */ - private DefaultComboBoxModel m_ObjectNames; - /** Open object from disk */ - private JButton openButton; - /** Save object to disk */ - private JButton saveButton; - /** ok button */ - private JButton okayButton; - /** cancel button */ - private JButton cancelButton; - /** edit source button */ -// private JButton m_editSourceBut; - /** Creates the GUI editor component */ + + private Object backupObject; + private PropertyChangeSupport propChangeSupport; + private static boolean TRACE = false; + /** + * The chooser component + */ + private JComboBox objectChooser; + /** + * The component that performs classifier customization + */ + private PropertySheetPanel propertySheetPanel; + /** + * The model containing the list of names to select from + */ + private DefaultComboBoxModel comboBoxModel; + /** + * Open object from disk + */ + private JButton openButton; + /** + * Save object to disk + */ + private JButton saveButton; + /** + * ok button + */ + private JButton okayButton; + /** + * cancel button + */ + private JButton cancelButton; + /** + * Creates the GUI editor component + */ // private Vector m_ClassesLongName; - private GenericObjectEditor genericObjectEditor = null; - private boolean withComboBoxToolTips = true; // should tool tips for the combo box be created? - private int tipMaxLen = 100; // maximum length of tool tip + private GenericObjectEditor genericObjectEditor = null; + private boolean withComboBoxToolTips = true; // should tool tips for the combo box be created? + private int tipMaxLen = 100; // maximum length of tool tip - /** - * - */ - public GOEPanel(Object target, Object backup, PropertyChangeSupport support, GenericObjectEditor goe) { - this(target, backup, support, goe, false); - } - - /** - * - */ - public GOEPanel(Object target, Object backup, PropertyChangeSupport support, GenericObjectEditor goe, boolean withCancel) { - Object m_Object = target; - m_Backup = backup; - m_Support = support; - genericObjectEditor = goe; - -// System.out.println("GOEPanel.Constructor !! " + this); - try { - if (!(Proxy.isProxyClass(m_Object.getClass()))) m_Backup = copyObject(m_Object); - } catch(OutOfMemoryError err) { - m_Backup=null; - System.gc(); - System.err.println("Could not create backup object: not enough memory (GOEPanel backup of " + m_Object + ")"); + /** + * + */ + public GOEPanel(Object target, Object backup, PropertyChangeSupport support, GenericObjectEditor goe) { + this(target, backup, support, goe, false); + } + + /** + * + */ + public GOEPanel(Object target, Object backup, PropertyChangeSupport support, GenericObjectEditor goe, boolean withCancel) { + Object m_Object = target; + backupObject = backup; + propChangeSupport = support; + genericObjectEditor = goe; + + try { + if (!(Proxy.isProxyClass(m_Object.getClass()))) { + backupObject = copyObject(m_Object); + } + } catch (OutOfMemoryError err) { + backupObject = null; + System.gc(); + System.err.println("Could not create backup object: not enough memory (GOEPanel backup of " + m_Object + ")"); + } + comboBoxModel = new DefaultComboBoxModel(new String[0]); + objectChooser = new JComboBox(comboBoxModel); + objectChooser.setEditable(false); + propertySheetPanel = new PropertySheetPanel(); + propertySheetPanel.addPropertyChangeListener( + new PropertyChangeListener() { + + public void propertyChange(final PropertyChangeEvent event) { + propChangeSupport.firePropertyChange("", backupObject, genericObjectEditor.getValue()); + } + }); + openButton = makeIconButton("resources/images/Open16.gif", "Open"); + openButton.setToolTipText("Load a configured object"); + openButton.setEnabled(true); + openButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(final ActionEvent event) { + Object object = FileTools.openObject(openButton, genericObjectEditor.getClassType()); + if (object != null) { + // setValue takes care of: Making sure obj is of right type, + // and firing property change. + genericObjectEditor.setValue(object); + // Need a second setValue to get property values filled in OK. + // Not sure why. + genericObjectEditor.setValue(object); // <- Hannes ?!?!? + } + } + }); + + saveButton = makeIconButton("resources/images/Save16.gif", "Save"); + saveButton.setToolTipText("Save the current configured object"); + saveButton.setEnabled(true); + saveButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(final ActionEvent event) { + FileTools.saveObjectWithFileChooser(saveButton, genericObjectEditor.getValue()); + } + }); + + okayButton = new JButton("OK"); + okayButton.setEnabled(true); + okayButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(final ActionEvent event) { + backupObject = copyObject(genericObjectEditor.getValue()); + + updateClassType(); + updateChooser(); + updateChildPropertySheet(); + + /* + * ToDo: This is really ugly. Find a way to make this better. + */ + Container container = GOEPanel.this.getParent(); + while (!(container instanceof JDialog)) { + container = container.getParent(); + } + ((JDialog) container).dispose(); + } + }); + + cancelButton = new JButton("Cancel"); + cancelButton.setEnabled(true); + cancelButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(final ActionEvent event) { + if (backupObject != null) { + // TODO m_goe.setObject(m_Object); + genericObjectEditor.setValue(copyObject(backupObject)); + updateClassType(); + updateChooser(); + updateChildPropertySheet(); + } + /* + * ToDo: This is really ugly. Find a way to make this better. + */ + Container container = GOEPanel.this.getParent(); + while (!(container instanceof JDialog)) { + container = container.getParent(); + } + ((JDialog) container).dispose(); + } + }); + + setLayout(new GridBagLayout()); + GridBagConstraints gbConstraints = new GridBagConstraints(); + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + gbConstraints.gridx = 0; + gbConstraints.gridy = 0; + add(objectChooser, gbConstraints); + + gbConstraints.weightx = 1.0; + gbConstraints.weighty = 1.0; + gbConstraints.gridy = 1; + gbConstraints.gridheight = GridBagConstraints.RELATIVE; + gbConstraints.fill = GridBagConstraints.BOTH; + add(propertySheetPanel, gbConstraints); + + JToolBar buttonBar = new JToolBar(); + buttonBar.setRollover(true); + buttonBar.setFloatable(false); + buttonBar.add(openButton); + buttonBar.add(saveButton); + + /* Add spacer to the end of the line */ + buttonBar.add(Box.createHorizontalGlue()); + + if (withCancel) { + buttonBar.add(cancelButton); + } + buttonBar.add(okayButton); + + gbConstraints.weightx = 0.0; + gbConstraints.weighty = 0.0; + gbConstraints.gridy = 2; + gbConstraints.anchor = GridBagConstraints.LINE_START; + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + add(buttonBar, gbConstraints); + + if (genericObjectEditor.getClassType() != null) { + updateClassType(); + updateChooser(); + updateChildPropertySheet(); + } + objectChooser.addItemListener(this); + } + + /** + * This method is duplicated from EvAModuleButtonPanelMaker. + * ToDo: Refactor this. + * + * @param iconSrc + * @param title + * @return + */ + private JButton makeIconButton(final String iconSrc, final String title) { + JButton newButton; + byte[] bytes; + bytes = BasicResourceLoader.instance().getBytesFromResourceLocation(iconSrc, false); + if (bytes == null) { + newButton = new JButton(title); + } else { + newButton = new JButton(new ImageIcon(Toolkit.getDefaultToolkit().createImage(bytes))); } - m_ObjectNames = new DefaultComboBoxModel(new String [0]); - m_ObjectChooser = new JComboBox(m_ObjectNames); - m_ObjectChooser.setEditable(false); - m_ChildPropertySheet = new PropertySheetPanel(); - m_ChildPropertySheet.addPropertyChangeListener( - new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - if (TRACE) System.out.println("GOE Property Change Listener: " + evt); - m_Support.firePropertyChange("", m_Backup, genericObjectEditor.getValue()); - } - }); - openButton = new JButton("Open"); - openButton.setToolTipText("Load a configured object"); - openButton.setEnabled(true); - openButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - Object object = FileTools.openObject(openButton, genericObjectEditor.getClassType()); -// Object object = openObject(); - if (object != null) { - // setValue takes care of: Making sure obj is of right type, - // and firing property change. - genericObjectEditor.setValue(object); - // Need a second setValue to get property values filled in OK. - // Not sure why. - genericObjectEditor.setValue(object); // <- Hannes ?!?!? - } - } - }); - - saveButton = new JButton("Save"); - saveButton.setToolTipText("Save the current configured object"); - saveButton.setEnabled(true); - saveButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - FileTools.saveObjectWithFileChooser(saveButton, genericObjectEditor.getValue()); -// saveObject(m_goe.getValue()); - } - }); - - okayButton = new JButton("OK"); - okayButton.setEnabled(true); - okayButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - m_Backup = copyObject(genericObjectEditor.getValue()); -// System.out.println("Backup is now " + BeanInspector.toString(m_Backup)); - if ((getTopLevelAncestor() != null) && (getTopLevelAncestor() instanceof Window)) { - Window w = (Window) getTopLevelAncestor(); - w.dispose(); - } - } - }); - - cancelButton = new JButton("Cancel"); - cancelButton.setEnabled(true); - cancelButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (m_Backup != null) { -// m_Object = copyObject(m_Backup); - // TODO m_goe.setObject(m_Object); -// System.out.println("Backup was " + BeanInspector.toString(m_Backup)); - genericObjectEditor.setValue(copyObject(m_Backup)); - updateClassType(); - updateChooser(); - updateChildPropertySheet(); - } - if ((getTopLevelAncestor() != null) - && (getTopLevelAncestor() instanceof Window)) { - Window w = (Window) getTopLevelAncestor(); - w.dispose(); - } - } - }); - - setLayout(new BorderLayout()); - add(m_ObjectChooser, BorderLayout.NORTH); // important - //add(m_ChildPropertySheet, BorderLayout.CENTER); - // Since we resize to the size of the property sheet, a scrollpane isn't - // typically needed (O Rly?) - JScrollPane myScrollPane =new JScrollPane(m_ChildPropertySheet,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - - - myScrollPane.setBorder(null); - add(myScrollPane, BorderLayout.CENTER); - - - JPanel okcButs = new JPanel(); - okcButs.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - okcButs.setLayout(new GridLayout(1, 4, 5, 5)); - okcButs.add(openButton); - okcButs.add(saveButton); -// okcButs.add(m_editSourceBut); - if (withCancel) okcButs.add(cancelButton); - okcButs.add(okayButton); - - add(okcButs, BorderLayout.SOUTH); - - if (genericObjectEditor.getClassType() != null) { - updateClassType(); - updateChooser(); - updateChildPropertySheet(); - } - m_ObjectChooser.addItemListener(this); + return newButton; } - public void setEnabledOkCancelButtons(boolean enabled) { - okayButton.setEnabled(enabled); - cancelButton.setEnabled(enabled); - } - - /** - * Makes a copy of an object using serialization - * @param source the object to copy - * @return a copy of the source object - */ - protected Object copyObject(Object source) { - Object result = null; - try { + public void setEnabledOkCancelButtons(boolean enabled) { + okayButton.setEnabled(enabled); + cancelButton.setEnabled(enabled); + } + + /** + * Makes a copy of an object using serialization. + * + * @param source the object to copy + * @return a copy of the source object + */ + protected Object copyObject(Object source) { + Object result = null; + try { // System.out.println("Copying " + BeanInspector.toString(source)); - SerializedObject so = new SerializedObject(source); - result = so.getObject(); - so=null; - } catch (Exception ex) { - System.err.println("GenericObjectEditor: Problem making backup object"); - System.err.println(source.getClass().getName()); - ex.printStackTrace(); - } - return result; - } + SerializedObject so = new SerializedObject(source); + result = so.getObject(); + so = null; + } catch (Exception ex) { + System.err.println("GenericObjectEditor: Problem making backup object"); + System.err.println(source.getClass().getName()); + ex.printStackTrace(); + } + return result; + } - /** - * This is used to hook an action listener to the ok button - * @param a The action listener. - */ - public void addOkListener(ActionListener a) { - okayButton.addActionListener(a); - } + /** + * This is used to hook an action listener to the ok button. + * + * @param a The action listener. + */ + public void addOkListener(ActionListener a) { + okayButton.addActionListener(a); + } - /** - * This is used to hook an action listener to the cancel button - * @param a The action listener. - */ - public void addCancelListener(ActionListener a) { - cancelButton.addActionListener(a); - } + /** + * This is used to hook an action listener to the cancel button + * + * @param a The action listener. + */ + public void addCancelListener(ActionListener a) { + cancelButton.addActionListener(a); + } - /** - * This is used to remove an action listener from the ok button - * @param a The action listener - */ - public void removeOkListener(ActionListener a) { - okayButton.removeActionListener(a); - } + /** + * This is used to remove an action listener from the ok button + * + * @param a The action listener + */ + public void removeOkListener(ActionListener a) { + okayButton.removeActionListener(a); + } - /** - * This is used to remove an action listener from the cancel button - * @param a The action listener - */ - public void removeCancelListener(ActionListener a) { - cancelButton.removeActionListener(a); - } - - public void setTarget(Object o) { - m_ChildPropertySheet.setTarget(o); - } - - /** - * - */ - protected void updateClassType() { - if (TRACE) System.out.println("# updating class "+genericObjectEditor.getClassType().getName()); - Vector classesLongNames; - ArrayList> instances = new ArrayList>(5); - if (Proxy.isProxyClass(genericObjectEditor.getClassType())) { - if (TRACE) System.out.println("PROXY! original was " + ((RMIProxyLocal)Proxy.getInvocationHandler(((Proxy)genericObjectEditor.getValue()))).getOriginalClass().getName()); - classesLongNames = new Vector(GenericObjectEditor.getClassesFromProperties(((RMIProxyLocal)Proxy.getInvocationHandler(((Proxy)genericObjectEditor.getValue()))).getOriginalClass().getName(), null)); - } else { - classesLongNames = new Vector(GenericObjectEditor.getClassesFromProperties(genericObjectEditor.getClassType().getName(), instances)); - } - if (classesLongNames.size() > 1) { - m_ObjectChooser.setModel(new DefaultComboBoxModel(classesLongNames)); - if (withComboBoxToolTips) m_ObjectChooser.setRenderer(new ToolTipComboBoxRenderer(collectComboToolTips(instances, tipMaxLen) )); - add(m_ObjectChooser, BorderLayout.NORTH); - } else remove(m_ObjectChooser); - if (TRACE) System.out.println("# done updating class "+genericObjectEditor.getClassType().getName()); - } + /** + * This is used to remove an action listener from the cancel button + * + * @param a The action listener + */ + public void removeCancelListener(ActionListener a) { + cancelButton.removeActionListener(a); + } - private String[] collectComboToolTips(List> instances, int maxLen) { - String[] tips = new String[instances.size()]; - for (int i=0; i classesLongNames; + ArrayList> instances = new ArrayList>(5); + if (Proxy.isProxyClass(genericObjectEditor.getClassType())) { + classesLongNames = new Vector(GenericObjectEditor.getClassesFromProperties(((RMIProxyLocal) Proxy.getInvocationHandler(((Proxy) genericObjectEditor.getValue()))).getOriginalClass().getName(), null)); + } else { + classesLongNames = new Vector(GenericObjectEditor.getClassesFromProperties(genericObjectEditor.getClassType().getName(), instances)); + } + if (classesLongNames.size() > 1) { + objectChooser.setModel(new DefaultComboBoxModel(classesLongNames)); + if (withComboBoxToolTips) { + objectChooser.setRenderer(new ToolTipComboBoxRenderer(collectComboToolTips(instances, tipMaxLen))); + } + GridBagConstraints gbConstraints = new GridBagConstraints(); + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + gbConstraints.gridx = 0; + gbConstraints.gridy = 0; + add(objectChooser, gbConstraints); + } else { + remove(objectChooser); + } + } + private String[] collectComboToolTips(List> instances, int maxLen) { + String[] tips = new String[instances.size()]; + for (int i = 0; i < tips.length; i++) { + tips[i] = null; + Class[] classParams = new Class[]{}; + try { + String tip = null; + Method giMeth = instances.get(i).getDeclaredMethod("globalInfo", classParams); + if (Modifier.isStatic(giMeth.getModifiers())) { + tip = (String) giMeth.invoke(null, (Object[]) null); + } + if (tip != null) { + if (tip.length() <= maxLen) { + tips[i] = tip; + } else { + tips[i] = tip.substring(0, maxLen - 2) + ".."; + } + } + } catch (Exception e) { + } + } + return tips; + } - /** Updates the child property sheet, and creates if needed */ - public void updateChildPropertySheet() { - //System.err.println("GOE::updateChildPropertySheet()"); - // Set the object as the target of the propertysheet - m_ChildPropertySheet.setTarget(genericObjectEditor.getValue()); - // Adjust size of containing window if possible - if ((getTopLevelAncestor() != null) - && (getTopLevelAncestor() instanceof Window)) { - ((Window) getTopLevelAncestor()).pack(); - } - } + protected void updateChooser() { + String objectName = /* + * EVAHELP.cutClassName + */ (genericObjectEditor.getValue().getClass().getName()); + boolean found = false; + for (int i = 0; i < comboBoxModel.getSize(); i++) { + if (TRACE) { + System.out.println("in updateChooser: looking at " + (String) comboBoxModel.getElementAt(i)); + } + if (objectName.equals((String) comboBoxModel.getElementAt(i))) { + found = true; + break; + } + } + if (!found) { + comboBoxModel.addElement(objectName); + } + objectChooser.getModel().setSelectedItem(objectName); + } - /** - * When the chooser selection is changed, ensures that the Object - * is changed appropriately. - * - * @param e a value of type 'ItemEvent' - */ + /** + * Updates the child property sheet, and creates if needed + */ + public void updateChildPropertySheet() { + // Set the object as the target of the propertysheet + propertySheetPanel.setTarget(genericObjectEditor.getValue()); + // Adjust size of containing window if possible + if ((getTopLevelAncestor() != null) + && (getTopLevelAncestor() instanceof Window)) { + ((Window) getTopLevelAncestor()).pack(); + } + } - public void itemStateChanged(ItemEvent e) { - String className = (String)m_ObjectChooser.getSelectedItem(); + /** + * When the chooser selection is changed, ensures that the Object is changed appropriately. + * + * @param e a value of type 'ItemEvent' + */ + public void itemStateChanged(ItemEvent e) { + String className; - if (TRACE) System.out.println("Event-Quelle: " + e.getSource().toString()); - if ((e.getSource() == m_ObjectChooser) && (e.getStateChange() == ItemEvent.SELECTED)){ - className = (String)m_ObjectChooser.getSelectedItem(); - try { - if (TRACE) System.out.println(className); -// Object n = (Object)Class.forName(className, true, this.getClass().getClassLoader()).newInstance(); - Object n = (Object)Class.forName(className).newInstance(); - genericObjectEditor.setValue(n); - // TODO ? setObject(n); - } catch (Exception ex) { - System.err.println("Exeption in itemStateChanged "+ex.getMessage()); - System.err.println("Classpath is " + System.getProperty("java.class.path")); - ex.printStackTrace(); - m_ObjectChooser.hidePopup(); - m_ObjectChooser.setSelectedIndex(0); - JOptionPane.showMessageDialog(this, - "Could not create an example of\n" - + className + "\n" - + "from the current classpath. Is the resource folder at the right place?\nIs the class abstract or the default constructor missing?", - "GenericObjectEditor", - JOptionPane.ERROR_MESSAGE); - EVAHELP.getSystemPropertyString(); - } - } - } + if ((e.getSource() == objectChooser) && (e.getStateChange() == ItemEvent.SELECTED)) { + className = (String) objectChooser.getSelectedItem(); + try { + Object n = (Object) Class.forName(className).newInstance(); + genericObjectEditor.setValue(n); + // TODO ? setObject(n); + } catch (Exception ex) { + System.err.println("Exeption in itemStateChanged " + ex.getMessage()); + System.err.println("Classpath is " + System.getProperty("java.class.path")); + ex.printStackTrace(); + objectChooser.hidePopup(); + objectChooser.setSelectedIndex(0); + JOptionPane.showMessageDialog(this, + "Could not create an example of\n" + + className + "\n" + + "from the current classpath. Is the resource folder at the right place?\nIs the class abstract or the default constructor missing?", + "GenericObjectEditor", + JOptionPane.ERROR_MESSAGE); + EVAHELP.getSystemPropertyString(); + } + } + } } class ToolTipComboBoxRenderer extends BasicComboBoxRenderer { - private static final long serialVersionUID = -5781643352198561208L; - String[] toolTips = null; - public ToolTipComboBoxRenderer(String[] tips) { - super(); - toolTips=tips; - } + private static final long serialVersionUID = -5781643352198561208L; + String[] toolTips = null; - @Override - public Component getListCellRendererComponent(JList list, Object value, - int index, boolean isSelected, boolean cellHasFocus) { - if (isSelected) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - if ((toolTips!=null) && (index >= 0)) { - if (toolTips[index]!=null) list.setToolTipText(toolTips[index]); - } - } else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } - setFont(list.getFont()); - setText((value == null) ? "" : value.toString()); - return this; - } + public ToolTipComboBoxRenderer(String[] tips) { + super(); + toolTips = tips; + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + if ((toolTips != null) && (index >= 0)) { + if (toolTips[index] != null) { + list.setToolTipText(toolTips[index]); + } + } + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + setFont(list.getFont()); + setText((value == null) ? "" : value.toString()); + return this; + } } diff --git a/src/eva2/gui/GenericArrayEditor.java b/src/eva2/gui/GenericArrayEditor.java index 7644611d..b5eebc9b 100644 --- a/src/eva2/gui/GenericArrayEditor.java +++ b/src/eva2/gui/GenericArrayEditor.java @@ -1,34 +1,14 @@ package eva2.gui; /* - * Title: EvA2 - * Description: - * Copyright: Copyright (c) 2003 - * Company: University of Tuebingen, Computer Architecture - * @author Holger Ulmer, Felix Streichert, Hannes Planatscher - * @version: $Revision: 235 $ - * $Date: 2007-11-08 13:53:51 +0100 (Thu, 08 Nov 2007) $ - * $Author: mkron $ + * Title: EvA2 Description: Copyright: Copyright (c) 2003 Company: University of Tuebingen, Computer + * Architecture @author Holger Ulmer, Felix Streichert, Hannes Planatscher @version: $Revision: 235 + * $ $Date: 2007-11-08 13:53:51 +0100 (Thu, 08 Nov 2007) $ $Author: mkron $ */ -/*==========================================================================* - * IMPORTS - *==========================================================================*/ - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.GridLayout; -import java.awt.Insets; -import java.awt.LayoutManager; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.InputEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; +import eva2.tools.EVAHELP; +import eva2.tools.SerializedObject; +import java.awt.*; +import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; @@ -36,729 +16,743 @@ import java.beans.PropertyEditor; import java.lang.reflect.Array; import java.util.LinkedList; import java.util.List; - -import javax.swing.DefaultListCellRenderer; -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.ListCellRenderer; -import javax.swing.ListModel; -import javax.swing.SwingConstants; +import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import eva2.tools.EVAHELP; -import eva2.tools.SerializedObject; -/*==========================================================================* - * CLASS DECLARATION - *==========================================================================*/ -public class GenericArrayEditor extends JPanel -implements PropertyEditor { - /** Handles property change notification */ - private PropertyChangeSupport m_Support = new PropertyChangeSupport(this); - /** The label for when we can't edit that type */ - private JLabel m_Label = new JLabel("Can't edit", SwingConstants.CENTER); - /** The list component displaying current values */ - private JList m_ElementList = new JList(); - /** The class of objects allowed in the array */ - private Class m_ElementClass = String.class; - /** The defaultlistmodel holding our data */ - private DefaultListModel m_ListModel; - /** The property editor for the class we are editing */ - private PropertyEditor m_ElementEditor; - /** Cheat to handle selectable lists as well */ - private PropertySelectableList selectableList = null; - /** Click this to delete the selected array values */ - private JButton m_DeleteBut = new JButton("Delete"); - /** list of additional buttons above the list */ - private List m_AdditionalUpperButtonList = new LinkedList(); - /** list of additional buttons below the list */ - private List m_AdditionalLowerButtonList = new LinkedList(); - - private JPanel additionalCenterPane = null; - - private List m_popupItemList = new LinkedList(); - private JButton m_AddBut = new JButton("Add"); - private JButton m_SetBut = new JButton("Set"); - private JButton m_SetAllBut = new JButton("Set all"); +public class GenericArrayEditor extends JPanel implements PropertyEditor { - private boolean withAddButton = true; - private boolean withSetButton = true; - private boolean withDeleteButton = true; - - private Component m_View = null; - /** Listens to buttons being pressed and taking the appropriate action */ - private ActionListener m_InnerActionListener = - new ActionListener() { - // - public void actionPerformed(ActionEvent e) { - boolean consistentView = true; // be optimistic... - if (m_View instanceof PropertyText) { // check consistency! - consistentView = ((PropertyText)m_View).checkConsistency(); - if (!consistentView) { -// System.err.println("Warning, inconsistent view!"); - ((PropertyText)m_View).updateFromEditor(); - } - } - if (e.getSource() == m_DeleteBut) { - int [] selected = m_ElementList.getSelectedIndices(); - if (selected != null) { - for (int i = selected.length-1; i>=0; i--) { - int current = selected[i]; - m_ListModel.removeElementAt(current); - if (m_ListModel.size() > current) { - m_ElementList.setSelectedIndex(current); - } - m_ElementList.setModel(m_ListModel); - } + /** + * Handles property change notification + */ + private PropertyChangeSupport m_Support = new PropertyChangeSupport(this); + /** + * The label for when we can't edit that type + */ + private JLabel m_Label = new JLabel("Can't edit", SwingConstants.CENTER); + /** + * The list component displaying current values + */ + private JList m_ElementList = new JList(); + /** + * The class of objects allowed in the array + */ + private Class m_ElementClass = String.class; + /** + * The defaultlistmodel holding our data + */ + private DefaultListModel m_ListModel; + /** + * The property editor for the class we are editing + */ + private PropertyEditor m_ElementEditor; + /** + * Cheat to handle selectable lists as well + */ + private PropertySelectableList selectableList = null; + /** + * Click this to delete the selected array values + */ + private JButton m_DeleteBut = new JButton("Delete"); + /** + * list of additional buttons above the list + */ + private List m_AdditionalUpperButtonList = new LinkedList(); + /** + * list of additional buttons below the list + */ + private List m_AdditionalLowerButtonList = new LinkedList(); + private JComponent additionalCenterComp = null; + private List m_popupItemList = new LinkedList(); + private JButton m_AddBut = new JButton("Add"); + private JButton m_SetBut = new JButton("Set"); + private JButton m_SetAllBut = new JButton("Set all"); + private boolean withAddButton = true; + private boolean withSetButton = true; + private boolean withDeleteButton = true; + private Component m_View = null; + /** + * Listens to buttons being pressed and taking the appropriate action + */ + private ActionListener m_InnerActionListener = + new ActionListener() { + // - if (selectableList!=null) selectableList.setObjects(modelToArray(selectableList.getObjects(), m_ListModel)); - m_Support.firePropertyChange("", null, null); - } - if (m_ElementList.getSelectedIndex() == -1) { - m_DeleteBut.setEnabled(false); - } - } else if (e.getSource() == m_AddBut) { - int selected = m_ElementList.getSelectedIndex(); - Object addObj = m_ElementEditor.getValue(); + public void actionPerformed(ActionEvent e) { + boolean consistentView = true; // be optimistic... + if (m_View instanceof PropertyText) { // check consistency! + consistentView = ((PropertyText) m_View).checkConsistency(); + if (!consistentView) { + ((PropertyText) m_View).updateFromEditor(); + } + } + if (e.getSource() == m_DeleteBut) { + int[] selected = m_ElementList.getSelectedIndices(); + if (selected != null) { + for (int i = selected.length - 1; i >= 0; i--) { + int current = selected[i]; + m_ListModel.removeElementAt(current); + if (m_ListModel.size() > current) { + m_ElementList.setSelectedIndex(current); + } + m_ElementList.setModel(m_ListModel); + } - // Make a full copy of the object using serialization - try { - SerializedObject so = new SerializedObject(addObj); - addObj = so.getObject(); - so=null; - if (selected != -1) { - m_ListModel.insertElementAt(addObj, selected); - } else { - m_ListModel.addElement(addObj); - } - m_ElementList.setModel(m_ListModel); - if (selectableList!=null) selectableList.setObjects(modelToArray(selectableList.getObjects(), m_ListModel)); - m_Support.firePropertyChange("", null, null); - } catch (Exception ex) { - JOptionPane.showMessageDialog(GenericArrayEditor.this,"Could not create an object copy",null,JOptionPane.ERROR_MESSAGE); - } - } else if (e.getSource() == m_SetAllBut) { - Object addObj = m_ElementEditor.getValue(); - for (int i=0; i=0 && (selected = 0 && (selected < m_ListModel.size())) { + try { + m_ListModel.setElementAt(new SerializedObject(addObj).getObject(), selected); + } catch (Exception e1) { + JOptionPane.showMessageDialog(GenericArrayEditor.this, "Could not create an object copy", null, JOptionPane.ERROR_MESSAGE); + } + m_Support.firePropertyChange("", null, null); + } + } + } + }; + + public void setAdditionalCenterPane(JComponent component) { + this.additionalCenterComp = component; + } + + private Object[] modelToArray(Object[] origArray, DefaultListModel listModel) { + Class objClass = origArray.getClass().getComponentType(); + Object[] os = (Object[]) java.lang.reflect.Array.newInstance(objClass, listModel.size()); // Object[] os= new Object[listModel.size()]; - for (int i=0; i=0 && (list.getCellBounds(index, index).contains(e.getPoint()))) { - PropertyPanel propPanel=null; - Component comp = gae.m_View; - if (comp instanceof PropertyPanel ) propPanel = (PropertyPanel) comp; - else System.err.println("Error, invalid property panel in " + this.getClass()); - ListModel dlm = list.getModel(); - Object item = dlm.getElementAt(index); - list.ensureIndexIsVisible(index); -// System.out.println(e); -// System.out.println("Double clicked on " + item); - propPanel.getEditor().setValue(item); - propPanel.showDialog(e.getXOnScreen(), e.getYOnScreen()); - propPanel=null; -// int x = getLocationOnScreen().x; -// int y = getLocationOnScreen().y; - -// if (m_PropertyDialog == null) -// m_PropertyDialog = new PropertyDialog(gae.m_ElementEditor, EVAHELP.cutClassName(gae.m_ElementEditor.getClass().getName()) , x, y); -// else { -// m_PropertyDialog.updateFrameTitle(gae.m_ElementEditor); -// m_PropertyDialog.set -// m_PropertyDialog.setVisible(false); -// m_PropertyDialog.setExtendedState(JFrame.NORMAL); -// m_PropertyDialog.setVisible(true); -// m_PropertyDialog.requestFocus(); -// } + public ActionJList(JList l, GenericArrayEditor genAE) { + list = l; + gae = genAE; + } - } - } - } - } - /* This class handles the creation of list cell renderers from the - * property editors. - */ - private class EditorListCellRenderer implements ListCellRenderer { - /** The class of the property editor for array objects */ - private Class m_EditorClass; - /** The class of the array values */ - private Class m_ValueClass; - /** - * Creates the list cell renderer. - * - * @param editorClass The class of the property editor for array objects - * @param valueClass The class of the array values - */ - public EditorListCellRenderer(Class editorClass, Class valueClass) { - m_EditorClass = editorClass; - m_ValueClass = valueClass; - } - /** - * Creates a cell rendering component. - * - * @param JList the list that will be rendered in - * @param Object the cell value - * @param int which element of the list to render - * @param boolean true if the cell is selected - * @param boolean true if the cell has the focus - * @return the rendering component - */ - public Component getListCellRendererComponent(final JList list, - final Object value, - final int index, - final boolean isSelected, - final boolean cellHasFocus) { - try { - final PropertyEditor e = (PropertyEditor)m_EditorClass.newInstance(); - if (e instanceof GenericObjectEditor) { - // ((GenericObjectEditor) e).setDisplayOnly(true); - ((GenericObjectEditor) e).setClassType(m_ValueClass); - } - e.setValue(value); - JPanel cellPanel = new JPanel() { -// return new JCheckBox("", isSelected) { -// public void paintComponent(Graphics g) { -// String name = (String)BeanInspector.callIfAvailable(value, "getName", new Object[]{}); -// if (name==null) setText(value.getClass().getSimpleName()); -// else setText(name); -// super.paintComponent(g); - public void paintComponent(Graphics g) { - Insets i = this.getInsets(); - Rectangle box = new Rectangle(i.left,i.top, - this.getWidth(), //- i.right, - this.getHeight() );//- i.bottom +20); - g.setColor(isSelected ? list.getSelectionBackground() : list.getBackground()); - g.fillRect(0, 0, this.getWidth(), this.getHeight()); - g.setColor(isSelected ? list.getSelectionForeground(): list.getForeground()); - e.paintValue(g, box); - } - public Dimension getPreferredSize() { - Font f = this.getFont(); - FontMetrics fm = this.getFontMetrics(f); - Dimension newPref = new Dimension(0, fm.getHeight()); - newPref.height = getFontMetrics(getFont()).getHeight() * 6 / 4; //6 / 4; - newPref.width = newPref.height * 6; //5 - return newPref; - } - }; - return cellPanel; - } catch (Exception ex) { - return null; - } - } - } + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + int index = list.locationToIndex(e.getPoint()); + // Check if the index is valid and if the indexed cell really contains the clicked point + if (index >= 0 && (list.getCellBounds(index, index).contains(e.getPoint()))) { + PropertyPanel propPanel = null; + Component comp = gae.m_View; + if (comp instanceof PropertyPanel) { + propPanel = (PropertyPanel) comp; + } else { + System.err.println("Error, invalid property panel in " + this.getClass()); + } + ListModel dlm = list.getModel(); + Object item = dlm.getElementAt(index); + list.ensureIndexIsVisible(index); + propPanel.getEditor().setValue(item); + propPanel.showDialog(e.getXOnScreen(), e.getYOnScreen()); + propPanel = null; + } + } + } + } + /* + * This class handles the creation of list cell renderers from the property editors. + */ - /** - * Updates the type of object being edited, so attempts to find an - * appropriate propertyeditor. - * - * @param o a value of type 'Object' - */ - private void updateEditorType(Object obj) { + private class EditorListCellRenderer implements ListCellRenderer { - // Determine if the current object is an array - m_ElementEditor = null; - m_ListModel = null; - m_View = null; - removeAll(); + /** + * The class of the property editor for array objects + */ + private Class m_EditorClass; + /** + * The class of the array values + */ + private Class m_ValueClass; - if ((obj != null) && (obj.getClass().isArray() || (obj instanceof PropertySelectableList))) { - Object arrayInstance = obj; - if (!(obj.getClass().isArray())) { - arrayInstance=((PropertySelectableList)obj).getObjects(); - selectableList = (PropertySelectableList)obj; - } else selectableList = null; - Class elementClass = arrayInstance.getClass().getComponentType(); - PropertyEditor editor = PropertyEditorProvider.findEditor(elementClass); - if (editor instanceof EnumEditor) editor.setValue(obj); - m_View = null; - ListCellRenderer lcr = new DefaultListCellRenderer(); - if (editor != null) { - if (editor instanceof GenericObjectEditor) { + /** + * Creates the list cell renderer. + * + * @param editorClass The class of the property editor for array objects + * @param valueClass The class of the array values + */ + public EditorListCellRenderer(Class editorClass, Class valueClass) { + m_EditorClass = editorClass; + m_ValueClass = valueClass; + } + + /** + * Creates a cell rendering component. + * + * @param JList the list that will be rendered in + * @param Object the cell value + * @param int which element of the list to render + * @param boolean true if the cell is selected + * @param boolean true if the cell has the focus + * @return the rendering component + */ + public Component getListCellRendererComponent(final JList list, + final Object value, + final int index, + final boolean isSelected, + final boolean cellHasFocus) { + try { + final PropertyEditor e = (PropertyEditor) m_EditorClass.newInstance(); + if (e instanceof GenericObjectEditor) { + // ((GenericObjectEditor) e).setDisplayOnly(true); + ((GenericObjectEditor) e).setClassType(m_ValueClass); + } + e.setValue(value); + JPanel cellPanel = new JPanel() { + + public void paintComponent(Graphics g) { + Insets i = this.getInsets(); + Rectangle box = new Rectangle(i.left, i.top, + this.getWidth(), //- i.right, + this.getHeight());//- i.bottom +20); + g.setColor(isSelected ? list.getSelectionBackground() : list.getBackground()); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); + g.setColor(isSelected ? list.getSelectionForeground() : list.getForeground()); + e.paintValue(g, box); + } + + public Dimension getPreferredSize() { + Font f = this.getFont(); + FontMetrics fm = this.getFontMetrics(f); + Dimension newPref = new Dimension(0, fm.getHeight()); + newPref.height = getFontMetrics(getFont()).getHeight() * 6 / 4; //6 / 4; + newPref.width = newPref.height * 6; //5 + return newPref; + } + }; + return cellPanel; + } catch (Exception ex) { + return null; + } + } + } + + /** + * Updates the type of object being edited, so attempts to find an appropriate propertyeditor. + * + * @param o a value of type 'Object' + */ + private void updateEditorType(Object obj) { + + // Determine if the current object is an array + m_ElementEditor = null; + m_ListModel = null; + m_View = null; + removeAll(); + + if ((obj != null) && (obj.getClass().isArray() || (obj instanceof PropertySelectableList))) { + Object arrayInstance = obj; + if (!(obj.getClass().isArray())) { + arrayInstance = ((PropertySelectableList) obj).getObjects(); + selectableList = (PropertySelectableList) obj; + } else { + selectableList = null; + } + Class elementClass = arrayInstance.getClass().getComponentType(); + PropertyEditor editor = PropertyEditorProvider.findEditor(elementClass); + if (editor instanceof EnumEditor) { + editor.setValue(obj); + } + m_View = null; + ListCellRenderer lcr = new DefaultListCellRenderer(); + if (editor != null) { + if (editor instanceof GenericObjectEditor) { // ((GenericObjectEditor) editor).getCustomEditor(); - ((GenericObjectEditor) editor).setClassType(elementClass); - } - if (editor.isPaintable() && editor.supportsCustomEditor()) { - m_View = new PropertyPanel(editor); - lcr = new EditorListCellRenderer(editor.getClass(), elementClass); - } else if (editor.getTags() != null) { - m_View = new PropertyValueSelector(editor); - } else if (editor.getAsText() != null) { - m_View = new PropertyText(editor); - } - } - if (m_View == null) { - System.err.println("No property editor for class: " - + elementClass.getName()); - } else { - m_ElementEditor = editor; + ((GenericObjectEditor) editor).setClassType(elementClass); + } + if (editor.isPaintable() && editor.supportsCustomEditor()) { + m_View = new PropertyPanel(editor); + lcr = new EditorListCellRenderer(editor.getClass(), elementClass); + } else if (editor.getTags() != null) { + m_View = new PropertyValueSelector(editor); + } else if (editor.getAsText() != null) { + m_View = new PropertyText(editor); + } + } + if (m_View == null) { + System.err.println("No property editor for class: " + + elementClass.getName()); + } else { + m_ElementEditor = editor; - // Create the ListModel and populate it - m_ListModel = new DefaultListModel(); - m_ElementClass = elementClass; - for (int i = 0; i < Array.getLength(arrayInstance); i++) { - m_ListModel.addElement(Array.get(arrayInstance,i)); - } - m_ElementList.setCellRenderer(lcr); - m_ElementList.setModel(m_ListModel); - if (m_ListModel.getSize() > 0) { - m_ElementList.setSelectedIndex(0); - m_DeleteBut.setEnabled(true); - } else { - m_DeleteBut.setEnabled(false); - } + // Create the ListModel and populate it + m_ListModel = new DefaultListModel(); + m_ElementClass = elementClass; + for (int i = 0; i < Array.getLength(arrayInstance); i++) { + m_ListModel.addElement(Array.get(arrayInstance, i)); + } + m_ElementList.setCellRenderer(lcr); + m_ElementList.setModel(m_ListModel); + if (m_ListModel.getSize() > 0) { + m_ElementList.setSelectedIndex(0); + m_DeleteBut.setEnabled(true); + } else { + m_DeleteBut.setEnabled(false); + } - try { - if (m_ListModel.getSize() > 0) { - m_ElementEditor.setValue(m_ListModel.getElementAt(0)); - } else { - if (m_ElementEditor instanceof GenericObjectEditor) { - ((GenericObjectEditor)m_ElementEditor).setDefaultValue(); - } else { - if (m_ElementEditor.getValue()!=null) { - m_ElementEditor.setValue(m_ElementClass.newInstance()); - } - } - } + try { + if (m_ListModel.getSize() > 0) { + m_ElementEditor.setValue(m_ListModel.getElementAt(0)); + } else { + if (m_ElementEditor instanceof GenericObjectEditor) { + ((GenericObjectEditor) m_ElementEditor).setDefaultValue(); + } else { + if (m_ElementEditor.getValue() != null) { + m_ElementEditor.setValue(m_ElementClass.newInstance()); + } + } + } - setPreferredSize(new Dimension(300,400)); -// JPanel panel = new JPanel(); -// panel.setLayout(new BorderLayout()); -// panel.add(view, BorderLayout.CENTER); -// panel.add(m_AddBut, BorderLayout.EAST); -// JPanel buttonPanel=new JPanel(new FlowLayout()); - - if (withAddButton && !(m_AdditionalUpperButtonList.contains(m_AddBut))) m_AdditionalUpperButtonList.add(m_AddBut); - if (withSetButton && !(m_AdditionalUpperButtonList.contains(m_SetBut))) m_AdditionalUpperButtonList.add(m_SetBut); - if (withSetButton && !(m_AdditionalUpperButtonList.contains(m_SetAllBut))) m_AdditionalUpperButtonList.add(m_SetAllBut); - - JPanel combiUpperPanel = new JPanel(getButtonLayout(1, m_AdditionalUpperButtonList)); - combiUpperPanel.add(m_View ); + //setPreferredSize(new Dimension(400,500)); - for (JButton but : m_AdditionalUpperButtonList) { - combiUpperPanel.add(but); - } - add(combiUpperPanel, BorderLayout.NORTH); - if (additionalCenterPane==null) add(new JScrollPane(m_ElementList), BorderLayout.CENTER); - else { - JPanel centerPane=new JPanel(); - centerPane.setLayout(new GridLayout(2, 1)); - centerPane.add(new JScrollPane(m_ElementList)); - centerPane.add(additionalCenterPane); - add(centerPane, BorderLayout.CENTER); - } - - if (withDeleteButton && !m_AdditionalLowerButtonList.contains(m_DeleteBut)) m_AdditionalLowerButtonList.add(m_DeleteBut); - JPanel combiLowerPanel = new JPanel(getButtonLayout(0, m_AdditionalLowerButtonList)); - for (JButton but : m_AdditionalLowerButtonList) { - combiLowerPanel.add(but); - } - add(combiLowerPanel, BorderLayout.SOUTH); - m_ElementEditor.addPropertyChangeListener(new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent e) { - repaint(); - } - }); - - addPopupMenu(); - } catch (Exception ex) { - System.err.println(ex.getMessage()); - ex.printStackTrace(); - m_ElementEditor = null; - } - } - } - if (m_ElementEditor == null) { - add(m_Label, BorderLayout.CENTER); - } - m_Support.firePropertyChange("", null, null); - validate(); - } - - /** - * Make a fitting grid layout for a list of buttons. An additional offset may be given - * if further components should be added besides the buttons. - * - * @param additionalOffset - * @param bList - * @return - */ - private LayoutManager getButtonLayout(int additionalOffset, List bList) { - int lines = 1+((bList.size()+additionalOffset-1)/3); - int cols = 3; - return new GridLayout(lines, cols); - } + if (withAddButton && !(m_AdditionalUpperButtonList.contains(m_AddBut))) { + m_AdditionalUpperButtonList.add(m_AddBut); + } + if (withSetButton && !(m_AdditionalUpperButtonList.contains(m_SetBut))) { + m_AdditionalUpperButtonList.add(m_SetBut); + } + if (withSetButton && !(m_AdditionalUpperButtonList.contains(m_SetAllBut))) { + m_AdditionalUpperButtonList.add(m_SetAllBut); + } - public void removeUpperActionButton(String text) { - removeActionButton(m_AdditionalUpperButtonList, text); - } - - public void removeLowerActionButton(String text) { - removeActionButton(m_AdditionalLowerButtonList, text); - } - - protected void removeActionButton(List bList, String text) { - JButton but = null; - for (JButton jb : bList) { - if (text.equals(jb.getText())) { - but = jb; - break; - } - } - if (but!=null) bList.remove(but); - } - - public void addUpperActionButton(String text, ActionListener al) { - addActionButton(m_AdditionalUpperButtonList, text, al); - } - - /** - * Wrap an action listener such that the selection state will always be up to date - * in the selectableList (if it exists). - * @param al - * @return - */ - private ActionListener makeSelectionKnownAL(final ActionListener al) { - return new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (selectableList!=null) { - selectableList.setSelectionByIndices(m_ElementList.getSelectedIndices()); - } - al.actionPerformed(e); - } - }; - } + // Upper Button Panel + JPanel combiUpperPanel = new JPanel(getButtonLayout(1, m_AdditionalUpperButtonList)); + combiUpperPanel.add(m_View); - public void addLowerActionButton(String text, ActionListener al) { - addActionButton(m_AdditionalLowerButtonList, text, al); - } - - public void addActionButton(List bList, String text, ActionListener al) { - JButton but = new JButton(text); - but.addActionListener(makeSelectionKnownAL(al)); - bList.add(but); - } - - /** - * Sets the current object array. - * - * @param o an object that must be an array. - */ - public void setValue(Object o) { - // Create a new list model, put it in the list and resize? - updateEditorType(o); - } + for (JButton but : m_AdditionalUpperButtonList) { + combiUpperPanel.add(but); + } + + setLayout(new GridBagLayout()); + + GridBagConstraints gbConstraints = new GridBagConstraints(); + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + gbConstraints.gridx = 0; + gbConstraints.gridy = 0; + add(combiUpperPanel, gbConstraints); + + // Job List + gbConstraints.gridy++; + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + add(new JScrollPane(m_ElementList), gbConstraints); + + // Lower Button Panel + if (withDeleteButton && !m_AdditionalLowerButtonList.contains(m_DeleteBut)) { + m_AdditionalLowerButtonList.add(m_DeleteBut); + } + JPanel combiLowerPanel = new JPanel(getButtonLayout(0, m_AdditionalLowerButtonList)); + for (JButton but : m_AdditionalLowerButtonList) { + combiLowerPanel.add(but); + } + gbConstraints.gridy++; + add(combiLowerPanel, gbConstraints); + + // Additional Center Panel (e.g. PropertySheetPanel) + if (additionalCenterComp != null) { + gbConstraints.weightx = 1.0; + gbConstraints.weighty = 1.0; + gbConstraints.fill = GridBagConstraints.BOTH; + gbConstraints.gridy++; + add(additionalCenterComp, gbConstraints); + } + + m_ElementEditor.addPropertyChangeListener(new PropertyChangeListener() { - /** - * Select all items. If all are selected, then deselect all items. - */ - public void selectDeselectAll() { - if (areAllSelected()) m_ElementList.getSelectionModel().clearSelection(); - else m_ElementList.setSelectionInterval(0, m_ElementList.getModel().getSize()-1); - } - - public boolean areAllSelected() { - for (int i=0; i0) { - m_ElementList.addMouseListener(new MouseAdapter() { - public void mouseClicked(MouseEvent e) { - if (selectableList!=null) { - selectableList.setSelectionByIndices(m_ElementList.getSelectedIndices()); - } - if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) { - // do nothing - } else { // right click released, so show popup - JPopupMenu popupMenu = new JPopupMenu(); - for (JMenuItem item : m_popupItemList) popupMenu.add(item); - popupMenu.show(GenericArrayEditor.this, e.getX(), e.getY()); - } - } - }); - } - } + addPopupMenu(); + } catch (Exception ex) { + System.err.println(ex.getMessage()); + ex.printStackTrace(); + m_ElementEditor = null; + } + } + } + if (m_ElementEditor == null) { + add(m_Label, BorderLayout.CENTER); + } + m_Support.firePropertyChange("", null, null); + validate(); + } - /** - * Create a menu item with given title and listener, add it to the menu and - * return it. It may be enabled or disabled. - * - * @param menu - * @param title - * @param aListener - * @param enabled - * @return - */ - private JMenuItem createMenuItem(String title, boolean enabled, - ActionListener aListener) { - JMenuItem item = new JMenuItem(title); - // if (bgColor!=null) item.setForeground(bgColor); - item.addActionListener(aListener); - item.setEnabled(enabled); - return item; - } - - /** - * Supposedly returns an initialization string to create a classifier - * identical to the current one, including it's state, but this doesn't - * appear possible given that the initialization string isn't supposed to - * contain multiple statements. - * - * @return the java source code initialisation string - */ - public String getJavaInitializationString() { - return "null"; - } + /** + * Make a fitting grid layout for a list of buttons. An additional offset may be given if + * further components should be added besides the buttons. + * + * @param additionalOffset + * @param bList + * @return + */ + private LayoutManager getButtonLayout(int additionalOffset, List bList) { + int lines = 1 + ((bList.size() + additionalOffset - 1) / 3); + int cols = 3; + return new GridLayout(lines, cols); + } - /** - * Returns true to indicate that we can paint a representation of the - * string array - * - * @return true - */ - public boolean isPaintable() { - return true; - } + public void removeUpperActionButton(String text) { + removeActionButton(m_AdditionalUpperButtonList, text); + } - /** - * Paints a representation of the current classifier. - * - * @param gfx the graphics context to use - * @param box the area we are allowed to paint into - */ - public void paintValue(Graphics gfx, Rectangle box) { - FontMetrics fm = gfx.getFontMetrics(); - int vpad = (box.height - fm.getAscent()) / 2; + public void removeLowerActionButton(String text) { + removeActionButton(m_AdditionalLowerButtonList, text); + } + + protected void removeActionButton(List bList, String text) { + JButton but = null; + for (JButton jb : bList) { + if (text.equals(jb.getText())) { + but = jb; + break; + } + } + if (but != null) { + bList.remove(but); + } + } + + public void addUpperActionButton(String text, ActionListener al) { + addActionButton(m_AdditionalUpperButtonList, text, al); + } + + /** + * Wrap an action listener such that the selection state will always be up to date in the + * selectableList (if it exists). + * + * @param al + * @return + */ + private ActionListener makeSelectionKnownAL(final ActionListener al) { + return new ActionListener() { + + public void actionPerformed(ActionEvent e) { + if (selectableList != null) { + selectableList.setSelectionByIndices(m_ElementList.getSelectedIndices()); + } + al.actionPerformed(e); + } + }; + } + + public void addLowerActionButton(String text, ActionListener al) { + addActionButton(m_AdditionalLowerButtonList, text, al); + } + + public void addActionButton(List bList, String text, ActionListener al) { + JButton but = new JButton(text); + but.addActionListener(makeSelectionKnownAL(al)); + bList.add(but); + } + + /** + * Sets the current object array. + * + * @param o an object that must be an array. + */ + public void setValue(Object o) { + // Create a new list model, put it in the list and resize? + updateEditorType(o); + } + + /** + * Select all items. If all are selected, then deselect all items. + */ + public void selectDeselectAll() { + if (areAllSelected()) { + m_ElementList.getSelectionModel().clearSelection(); + } else { + m_ElementList.setSelectionInterval(0, m_ElementList.getModel().getSize() - 1); + } + } + + public boolean areAllSelected() { + for (int i = 0; i < m_ElementList.getModel().getSize(); i++) { + if (!m_ElementList.isSelectedIndex(i)) { + return false; + } + } + return true; + } + + /** + * Gets the current object array. + * + * @return the current object array + */ + public Object getValue() { + if (m_ListModel == null) { + return null; + } + if (selectableList != null) { + return selectableList; + } else { + // Convert the listmodel to an array of strings and return it. + int length = m_ListModel.getSize(); + Object result = Array.newInstance(m_ElementClass, length); + for (int i = 0; i < length; i++) { + Array.set(result, i, m_ListModel.elementAt(i)); + } + return result; + } + } + + public void addPopupItem(String text, ActionListener al) { + JMenuItem item = createMenuItem(text, true, makeSelectionKnownAL(al)); + m_popupItemList.add(item); + } + + public void addPopupMenu() { + if (m_popupItemList.size() > 0) { + m_ElementList.addMouseListener(new MouseAdapter() { + + public void mouseClicked(MouseEvent e) { + if (selectableList != null) { + selectableList.setSelectionByIndices(m_ElementList.getSelectedIndices()); + } + if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) { + // do nothing + } else { // right click released, so show popup + JPopupMenu popupMenu = new JPopupMenu(); + for (JMenuItem item : m_popupItemList) { + popupMenu.add(item); + } + popupMenu.show(GenericArrayEditor.this, e.getX(), e.getY()); + } + } + }); + } + } + + /** + * Create a menu item with given title and listener, add it to the menu and return it. It may be + * enabled or disabled. + * + * @param menu + * @param title + * @param aListener + * @param enabled + * @return + */ + private JMenuItem createMenuItem(String title, boolean enabled, + ActionListener aListener) { + JMenuItem item = new JMenuItem(title); + // if (bgColor!=null) item.setForeground(bgColor); + item.addActionListener(aListener); + item.setEnabled(enabled); + return item; + } + + /** + * Supposedly returns an initialization string to create a classifier identical to the current + * one, including it's state, but this doesn't appear possible given that the initialization + * string isn't supposed to contain multiple statements. + * + * @return the java source code initialisation string + */ + public String getJavaInitializationString() { + return "null"; + } + + /** + * Returns true to indicate that we can paint a representation of the string array + * + * @return true + */ + public boolean isPaintable() { + return true; + } + + /** + * Paints a representation of the current classifier. + * + * @param gfx the graphics context to use + * @param box the area we are allowed to paint into + */ + public void paintValue(Graphics gfx, Rectangle box) { + FontMetrics fm = gfx.getFontMetrics(); + int vpad = (box.height - fm.getAscent()) / 2; // System.out.println(m_ListModel + " --- " + m_ElementClass); - String rep; - if (m_ListModel.getSize() == 0) rep="Empty"; - else { - rep = m_ListModel.getSize() + " of " + EVAHELP.cutClassName(m_ElementClass.getName()); - Object maybeName = BeanInspector.callIfAvailable(m_ListModel.get(0), "getName", new Object[]{}); - if (maybeName!=null) { - rep = rep + " ("+(String)maybeName + "...)"; - } - } - gfx.drawString(rep, 2, fm.getHeight() + vpad - 3 ); - } - /** - * - */ - public String getAsText() { - return null; - } - /** - * - */ - public void setAsText(String text) throws IllegalArgumentException { - throw new IllegalArgumentException(text); - } - /** - * - */ - public String[] getTags() { - return null; - } - /** - * - */ - public boolean supportsCustomEditor() { - return true; - } - /** - * - */ - public Component getCustomEditor() { - return this; - } - - public void addPropertyChangeListener(PropertyChangeListener l) { - if (m_Support == null) m_Support = new PropertyChangeSupport(this); - m_Support.addPropertyChangeListener(l); - } + String rep; + if (m_ListModel.getSize() == 0) { + rep = "Empty"; + } else { + rep = m_ListModel.getSize() + " of " + EVAHELP.cutClassName(m_ElementClass.getName()); + Object maybeName = BeanInspector.callIfAvailable(m_ListModel.get(0), "getName", new Object[]{}); + if (maybeName != null) { + rep = rep + " (" + (String) maybeName + "...)"; + } + } + gfx.drawString(rep, 2, fm.getHeight() + vpad - 3); + } - public void removePropertyChangeListener(PropertyChangeListener l) { - if (m_Support == null) m_Support = new PropertyChangeSupport(this); - m_Support.removePropertyChangeListener(l); - } + /** + * + */ + public String getAsText() { + return null; + } - /** - * - */ -// public static void main(String [] args) { -// try { -// java.beans.PropertyEditorManager.registerEditor(SelectedTag.class,TagEditor.class); -// java.beans.PropertyEditorManager.registerEditor(int [].class,GenericArrayEditor.class); -// java.beans.PropertyEditorManager.registerEditor(double [].class,GenericArrayEditor.class); -// GenericArrayEditor editor = new GenericArrayEditor(); -// -// -// int[] initial = { 3,45, 7}; -// editor.setValue(initial); -// PropertyDialog pd = new PropertyDialog(editor,EVAHELP.cutClassName(editor.getClass().getName()) -// , 100, 100); -//// pd.setSize(200,200); -// pd.addWindowListener(new WindowAdapter() { -// public void windowClosing(WindowEvent e) { -// System.exit(0); -// } -// }); -// editor.setValue(initial); -// //ce.validate(); -// } catch (Exception ex) { -// ex.printStackTrace(); -// System.err.println(ex.getMessage()); -// } -// } - public boolean isWithAddButton() { - return withAddButton; - } - public void setWithAddButton(boolean withAddButton) { - this.withAddButton = withAddButton; - } - public boolean isWithSetButton() { - return withSetButton; - } - public void setWithSetButton(boolean withSetButton) { - this.withSetButton = withSetButton; - } - - public boolean isWithDeleteButton() { - return withDeleteButton; - } - public void setWithDeleteButton(boolean wB) { - this.withDeleteButton = wB; - } - - public void removeNotify() { - super.removeNotify(); - } + /** + * + */ + public void setAsText(String text) throws IllegalArgumentException { + throw new IllegalArgumentException(text); + } + + /** + * + */ + public String[] getTags() { + return null; + } + + /** + * + */ + public boolean supportsCustomEditor() { + return true; + } + + /** + * + */ + public Component getCustomEditor() { + return this; + } + + public void addPropertyChangeListener(PropertyChangeListener l) { + if (m_Support == null) { + m_Support = new PropertyChangeSupport(this); + } + m_Support.addPropertyChangeListener(l); + } + + public void removePropertyChangeListener(PropertyChangeListener l) { + if (m_Support == null) { + m_Support = new PropertyChangeSupport(this); + } + m_Support.removePropertyChangeListener(l); + } + + public boolean isWithAddButton() { + return withAddButton; + } + + public void setWithAddButton(boolean withAddButton) { + this.withAddButton = withAddButton; + } + + public boolean isWithSetButton() { + return withSetButton; + } + + public void setWithSetButton(boolean withSetButton) { + this.withSetButton = withSetButton; + } + + public boolean isWithDeleteButton() { + return withDeleteButton; + } + + public void setWithDeleteButton(boolean wB) { + this.withDeleteButton = wB; + } + + public void removeNotify() { + super.removeNotify(); + } } - diff --git a/src/eva2/gui/GenericObjectEditor.java b/src/eva2/gui/GenericObjectEditor.java index 992f98b1..c741b982 100644 --- a/src/eva2/gui/GenericObjectEditor.java +++ b/src/eva2/gui/GenericObjectEditor.java @@ -1,16 +1,10 @@ package eva2.gui; /* - * Title: EvA2 - * Description: - * Copyright: Copyright (c) 2012 - * Company: University of Tuebingen, Computer Architecture - * @author Holger Ulmer, Felix Streichert, Hannes Planatscher, Fabian Becker - * @version: $Revision: 266 $ - * $Date: 2007-11-20 14:33:48 +0100 (Tue, 20 Nov 2007) $ - * $Author: mkron $ + * Title: EvA2 Description: Copyright: Copyright (c) 2012 Company: University of Tuebingen, Computer + * Architecture @author Holger Ulmer, Felix Streichert, Hannes Planatscher, Fabian Becker @version: + * $Revision: 266 $ $Date: 2007-11-20 14:33:48 +0100 (Tue, 20 Nov 2007) $ $Author: mkron $ */ - import java.awt.Component; import java.awt.FontMetrics; import java.awt.Graphics; @@ -36,474 +30,477 @@ import eva2.EvAInfo; import eva2.tools.ReflectPackage; import eva2.tools.jproxy.RMIProxyLocal; - - public class GenericObjectEditor implements PropertyEditor { - private static final Logger logger = Logger.getLogger(EvAInfo.defaultLogger); - private Object m_Object; - private Object m_Backup; - private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); - private Class classType; - private GOEPanel editorComponent; - private boolean isEnabled = true; - - /** - * Read the classes available for user selection from the properties or the classpath respectively - */ - public static ArrayList getClassesFromProperties(String className, ArrayList> instances) { - logger.log(Level.FINEST, "Requesting className: {0}", className); - - // Try to read the predefined classes from the props file. - String typeOptions = EvAInfo.getProperty(className); - if (typeOptions == null) { - // If none are defined, all assignable classes are searched the hard way, using the ReflectPackage - return getClassesFromClassPath(className, instances); - } else { - StringTokenizer st = new StringTokenizer(typeOptions, ", "); - ArrayList classes = new ArrayList(); - while (st.hasMoreTokens()) { - String current = st.nextToken().trim(); - try { - Class clz = Class.forName(current); // test for instantiability - if (instances != null) { - instances.add(clz); - } - classes.add(current); - } catch (ClassNotFoundException ex) { - logger.log(Level.WARNING, - String.format("Requesting className: %1$s, Couldn't load: %2%s", className, current), ex); - } - } - return classes; - } - } - - /** - * Return the names of all classes in the same package that are assignable - * from the named class, and that can be loaded through the classpath. - * If a class has a declared field called "hideFromGOE" this method will skip it. - * Abstract classes and interfaces will be skipped as well. - * - * @see ReflectPackage.getAssignableClassesInPackage - * @param className - * @return - */ - public static ArrayList getClassesFromClassPath(String className, ArrayList> instances) { - ArrayList classes = new ArrayList(); - Class[] classArray; - classArray=ReflectPackage.getAssignableClasses(className, true, true); - if (classArray == null) { - logger.log(Level.WARNING, String.format("No assignable classes found in property file or on classpath: %1$s for %2$s", EvAInfo.propertyFile, className)); - classes.add(className); - } else { - for (Class clazz : classArray) { - int m = clazz.getModifiers(); - try { - // a field allowing a class to indicate it doesnt want to be displayed - Field f = clazz.getDeclaredField("hideFromGOE"); - if (f.getBoolean(clazz) == true) { - logger.log(Level.FINEST, "Class {0} wants to be hidden from GOE.", clazz); - continue; - } - } catch (NoSuchFieldException e) { - /* - * We are just logging this exception here. It is expected that - * most classes do not have this field. - */ - logger.log(Level.FINER, String.format("%1$s does not have a hideFromGOE field", clazz.toString()), e); - } catch (IllegalArgumentException e) { - logger.log(Level.FINER, e.getMessage(), e); - } catch (IllegalAccessException e) { - logger.log(Level.FINER, e.getMessage(), e); - } - - - if (!Modifier.isAbstract(m) && !clazz.isInterface()) { // dont take abstract classes or interfaces - try { - Class[] params = new Class[0]; - clazz.getConstructor(params); - if (instances!=null) instances.add(clazz); - classes.add(clazz.getName()); - } catch (NoSuchMethodException e) { - logger.log(Level.WARNING, String.format("GOE warning: Class %1$s has no default constructor", clazz.getName()), e); - } - } - } - } - return classes; - } - - /** - * Hide or show the editable property of a class, this makes sense for classes - * which are represented visually using the GenericObjectEditor. - * Returns false, if an error occurs, else true. - * An instance may call this statically on itself by means of this.getClass(). - * Actually this only sets the hidden property of the java bean which is checked in the - * wasModified method of PropertySheetPanel. - * - * @param cls class the property belongs to - * @param property string name of the property - * @param hide desired value to set, true for hidden, false for visible - * @return false, if an error occurs, else true - */ - public static boolean setExpertProperty(Class cls, String property, boolean expertValue) { - try { - BeanInfo bi = Introspector.getBeanInfo(cls); - PropertyDescriptor[] props = bi.getPropertyDescriptors(); - for (int i=0; i