private JPanel createXPathExpressionEditingPanel()

in taverna-xpath-activity-ui/src/main/java/org/apache/taverna/activities/xpath/ui/config/XPathActivityConfigurationPanel.java [481:710]


	private JPanel createXPathExpressionEditingPanel() {
		this.jlXPathExpressionStatus = new JLabel();

		this.jlXPathExpression = new JLabel("XPath expression");

		this.bRunXPath = new JButton("Run XPath");
		this.bRunXPath.setEnabled(false);
		this.bRunXPath.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				runXPath(true);
			}
		});

		this.tfXPathExpression = new JTextField(30);
		this.tfXPathExpression.setPreferredSize(new Dimension(0, this.bRunXPath
				.getPreferredSize().height));
		this.tfXPathExpression.setMinimumSize(new Dimension(0, this.bRunXPath
				.getPreferredSize().height));
		this.tfXPathExpression.addCaretListener(new CaretListener() {
			public void caretUpdate(CaretEvent e) {
				validateXPathAndUpdateUI();
			}
		});
		this.tfXPathExpression.addKeyListener(new KeyListener() {
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					if (bRunXPath.isEnabled()) {
						// it is safe to check that ENTER key may execute the
						// XPath expression if the
						// "Run XPath" button is enabled, as expression
						// validation is responsible for
						// enabling / disabling the button as the expression
						// changes
						runXPath(true);
					}
				}
			}

			public void keyReleased(KeyEvent e) { /* not in use */
			}

			public void keyTyped(KeyEvent e) { /* not in use */
			}
		});

		JPanel jpXPath = new JPanel(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weighty = 0;

		c.gridx = 0;
		c.gridy = 0;
		c.weightx = 0;
		jpXPath.add(jlXPathExpressionStatus);

		c.gridx++;
		c.weightx = 0.0;
		c.insets = new Insets(0, 10, 0, 0);
		jpXPath.add(jlXPathExpression, c);
		
		c.gridx++;
		c.weightx = 1.0;
		c.insets = new Insets(0, 10, 0, 10);
		jpXPath.add(tfXPathExpression, c);

		c.gridx++;
		c.weightx = 0;
		c.insets = new Insets(0, 0, 0, 0);
		jpXPath.add(bRunXPath, c);

		c.gridx = 2;
		c.gridy++;
		c.weightx = 1.0;
		c.weighty = 0;
		c.gridwidth = 2;
		c.fill = GridBagConstraints.NONE;
		c.anchor = GridBagConstraints.WEST;
		c.insets = new Insets(0, 10, 0, 10);
		jlShowHideNamespaceMappings = new JLabel("Show namespace mappings...");
		jlShowHideNamespaceMappings.setForeground(Color.BLUE);
		jlShowHideNamespaceMappings.setCursor(new Cursor(Cursor.HAND_CURSOR));
		jlShowHideNamespaceMappings.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				jpNamespaceMappingsWithButton
						.setVisible(!jpNamespaceMappingsWithButton.isVisible());
				jlShowHideNamespaceMappings
						.setText((jpNamespaceMappingsWithButton.isVisible() ? "Hide"
								: "Show")
								+ " namespace mappings...");
				thisPanel.validate();
			}
		});
		jpXPath.add(jlShowHideNamespaceMappings, c);

		// namespace mapping table
		DefaultTableModel tableModel = new DefaultTableModel();
		tableModel.addColumn("Namespace Prefix");
		tableModel.addColumn("Namespace URI");

		jtXPathNamespaceMappings = new JTable();
		jtXPathNamespaceMappings.setModel(tableModel);
		// ((DefaultCellEditor)jtXPathNamespaceMappings.getDefaultEditor(String.class)).setClickCountToStart(1);
		// // TODO - enable if one-click-to-start-editing behaviour is required
		// TODO - next line is to be enabled when Taverna is migrated to Java
		// 1.6; for now it's fine to run without this
		// jtXPathNamespaceMappings.setFillsViewportHeight(true); // makes sure
		// that when the dedicated area is larger than the table, the latter is
		// stretched vertically to fill the empty space
		jtXPathNamespaceMappings
				.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // only one row can be selected at a time
		jtXPathNamespaceMappings
				.setPreferredScrollableViewportSize(new Dimension(200, 50)); // NB! this prevents the table from occupying most of the space in the panel when screen is maximized
		jtXPathNamespaceMappings.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_DELETE) {
					removeNamespaceMapping();
				}
			}
		});

		TableCellListener cellListener = new TableCellListener(
				jtXPathNamespaceMappings, new AbstractAction() {
					public void actionPerformed(ActionEvent e) {
						TableCellListener tcl = (TableCellListener) e
								.getSource();

						if (tcl.getColumn() == 0) {
							// prefix was modified
							String newPrefix = (String) tcl.getNewValue();
							if (xpathNamespaceMap.containsKey(newPrefix)) {
								// such prefix already exists - change won't be
								// saved
								JOptionPane
										.showMessageDialog(
												thisPanel,
												"Cannot update namespace prefix: "
														+ "updated value already exists",
												"XPath Activity",
												JOptionPane.WARNING_MESSAGE);
							} else {
								// update the map with the new prefix for the
								// same URI value
								String oldPrefix = (String) tcl.getOldValue();
								xpathNamespaceMap.put(newPrefix,
										xpathNamespaceMap.remove(oldPrefix));
							}
						} else {
							// simple case - just the URI value has changed:
							// just overwrite the value in the namespace map
							String prefixOfUpdatedURI = (String) jtXPathNamespaceMappings
									.getModel().getValueAt(tcl.getRow(), 0);
							xpathNamespaceMap.put(prefixOfUpdatedURI,
									(String) tcl.getNewValue());
						}

						// either way - reload from the local map (map could be
						// not updated if the validation didn't succeed)
						reloadNamespaceMappingTableFromLocalMap();
					}
				});

		jtXPathNamespaceMappings.getColumnModel().getColumn(0)
				.setPreferredWidth(20); // set relative sizes of columns
		jtXPathNamespaceMappings.getColumnModel().getColumn(1)
				.setPreferredWidth(300);

		JScrollPane spXPathNamespaceMappings = new JScrollPane(
				jtXPathNamespaceMappings);
		spXPathNamespaceMappings.setAlignmentY(TOP_ALIGNMENT);
		spXPathNamespaceMappings.setMinimumSize(new Dimension(200, 50)); // makes the table to have at least two rows visible in all cases - no matter how small the parent panel is

		bAddMapping = new JButton("Add Mapping");
		bAddMapping.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addNamespaceMapping();
			}
		});

		bRemoveMapping = new JButton("Remove Mapping");
		bRemoveMapping.setEnabled(false);
		bRemoveMapping.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				removeNamespaceMapping();
			}
		});

		bAddMapping.setMinimumSize(bRemoveMapping.getPreferredSize()); // make sure that the 'Add Mapping' button is of the same size as 'Remove Mapping'
															
		bAddMapping.setPreferredSize(bRemoveMapping.getPreferredSize()); // -- both are required to achieve desired behaviour when window is resized / namespace mapping table is enabled/disabled 												

		bRunXPath.setMinimumSize(bRemoveMapping.getPreferredSize()); // do the same for 'Run XPath' button
		
		bRunXPath.setPreferredSize(bRemoveMapping.getPreferredSize());

		JPanel jpAddRemoveButtons = new JPanel();
		jpAddRemoveButtons.setLayout(new GridBagLayout());
		GridBagConstraints cAddRemove = new GridBagConstraints();
		cAddRemove.gridx = 0;
		cAddRemove.gridy = 0;
		cAddRemove.weightx = 1.0;
		cAddRemove.anchor = GridBagConstraints.NORTH;
		cAddRemove.fill = GridBagConstraints.HORIZONTAL;
		jpAddRemoveButtons.add(bAddMapping, cAddRemove);
		cAddRemove.gridy++;
		cAddRemove.weighty = 1.0;
		cAddRemove.insets = new Insets(2, 0, 0, 0);
		jpAddRemoveButtons.add(bRemoveMapping, cAddRemove);

		jpNamespaceMappingsWithButton = new JPanel();
		jpNamespaceMappingsWithButton.setVisible(false);
		jpNamespaceMappingsWithButton.setLayout(new BorderLayout(10, 0));
		jpNamespaceMappingsWithButton.add(spXPathNamespaceMappings,
				BorderLayout.CENTER);
		jpNamespaceMappingsWithButton
				.add(jpAddRemoveButtons, BorderLayout.EAST);

		c.gridx = 0;
		c.gridy++;
		c.gridwidth = 4;
		c.fill = GridBagConstraints.BOTH;
		c.weightx = 1.0;
		c.weighty = 1.0;
		c.insets = new Insets(5, 0, 0, 0);
		jpXPath.add(jpNamespaceMappingsWithButton, c);

		// initialise some values / tooltips
		resetXPathEditingPanel();

		return (jpXPath);
	}