| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| |
| package org.netbeans.modules.properties; |
| |
| |
| import java.awt.*; |
| import java.awt.event.MouseAdapter; |
| import java.awt.event.MouseEvent; |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import java.text.MessageFormat; |
| import javax.swing.*; |
| import javax.swing.border.LineBorder; |
| import javax.swing.event.*; |
| import javax.swing.plaf.basic.BasicHTML; |
| import javax.swing.table.*; |
| |
| import org.openide.DialogDescriptor; |
| import org.openide.NotifyDescriptor; |
| import org.openide.DialogDisplayer; |
| import org.openide.util.ImageUtilities; |
| import org.openide.util.NbBundle; |
| import org.openide.util.WeakListeners; |
| import org.openide.windows.TopComponent; |
| |
| |
| /** |
| * Panel which shows bundle of .properties files encapsulated by <code>PropertiesDataObject</code> in one table view. |
| * |
| * @author Petr Jiricka |
| * @author Marian Petras |
| */ |
| public class BundleEditPanel extends JPanel implements PropertyChangeListener { |
| |
| /** PropertiesDataObject this panel presents. */ |
| // private PropertiesDataObject obj; |
| |
| /** */ |
| private BundleStructure structure; |
| |
| /** Document listener for value and comment textareas. */ |
| private DocumentListener listener; |
| |
| /** Class representing settings used in table view. */ |
| private static TableViewSettings settings; |
| |
| /** Generated serialized version UID. */ |
| static final long serialVersionUID =-843810329041244483L; |
| |
| private Element.ItemElem lastSelectedBundleKey; |
| private int lastSelectedColumn; |
| |
| /** Creates new form BundleEditPanel */ |
| @Deprecated |
| public BundleEditPanel(final PropertiesDataObject obj, PropertiesTableModel propTableModel) { |
| // this.obj = obj; |
| this.structure = obj.getBundleStructure(); |
| |
| initComponents(); |
| initAccessibility(); |
| initSettings(); |
| |
| // Sets table column model. |
| table.setColumnModel(new TableViewColumnModel()); |
| |
| // Sets custom table header renderer (with sorting indicators). |
| JTableHeader header = table.getTableHeader(); |
| header.setDefaultRenderer( |
| new TableViewHeaderRenderer(obj, header.getDefaultRenderer())); |
| |
| // Sets table model. |
| table.setModel(propTableModel); |
| |
| // Sets table cell editor. |
| JTextField textField = new JTextField(); |
| // Force the document to accept newlines. The textField doesn't like |
| // it, but the same document is used by the <code>textValue</code> text |
| // area that must accept newlines. |
| textField.getDocument().putProperty("filterNewlines", Boolean.FALSE); // NOI18N |
| textField.setBorder(new LineBorder(Color.black)); |
| textField.getAccessibleContext().setAccessibleName(NbBundle.getBundle(BundleEditPanel.class).getString("ACSN_CellEditor")); |
| textField.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACSD_CellEditor")); |
| listener = new ModifiedListener(); |
| table.setDefaultEditor(PropertiesTableModel.StringPair.class, |
| new PropertiesTableCellEditor(textField, textComment, textValue, valueLabel, listener)); |
| |
| // Sets renderer. |
| table.setDefaultRenderer(PropertiesTableModel.StringPair.class, new TableViewRenderer()); |
| |
| updateAddButton(); |
| |
| // property change listener - listens to editing state of the table |
| table.addPropertyChangeListener(new PropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent evt) { |
| if (evt.getPropertyName().equals("tableCellEditor")) { // NOI18N |
| updateEnabled(); |
| } else if (evt.getPropertyName().equals("model")) { // NOI18N |
| updateAddButton(); |
| } else if (evt.getPropertyName().equals("marginChanged")|| |
| evt.getPropertyName().equals("columnMoved") || |
| evt.getPropertyName().equals("componentHidden")) { |
| saveEditorValue(false); |
| } |
| } |
| }); |
| |
| // listens on clikcs on table header, detects column and sort accordingly to chosen one |
| table.getTableHeader().addMouseListener(new MouseAdapter() { |
| @Override |
| public void mouseClicked(MouseEvent e) { |
| TableColumnModel colModel = table.getColumnModel(); |
| int columnModelIndex = colModel.getColumnIndexAtX(e.getX()); |
| // No column was clicked. |
| if (columnModelIndex < 0) { |
| return; |
| } |
| int modelIndex = colModel.getColumn(columnModelIndex).getModelIndex(); |
| // not detected column |
| if (modelIndex < 0) { |
| return; |
| } |
| obj.getBundleStructure().sort(modelIndex); |
| } |
| }); |
| |
| |
| table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { |
| public void valueChanged(ListSelectionEvent evt) { |
| final boolean correctCellSelection = !selectionUpdateDisabled; |
| SwingUtilities.invokeLater(new Runnable() { |
| public void run() { |
| updateSelection(correctCellSelection); |
| } |
| }); |
| } |
| }); |
| |
| } // End of constructor. |
| |
| /** Creates new form BundleEditPanel */ |
| public BundleEditPanel(final BundleStructure structure, PropertiesTableModel propTableModel) { |
| this.structure = structure; |
| |
| initComponents(); |
| initAccessibility(); |
| initSettings(); |
| |
| // Sets table column model. |
| table.setColumnModel(new TableViewColumnModel()); |
| |
| // Sets custom table header renderer (with sorting indicators). |
| JTableHeader header = table.getTableHeader(); |
| header.setDefaultRenderer( |
| new TableViewHeaderRenderer(structure, header.getDefaultRenderer())); |
| |
| // Sets table model. |
| table.setModel(propTableModel); |
| |
| // Sets table cell editor. |
| JTextField textField = new JTextField(); |
| // Force the document to accept newlines. The textField doesn't like |
| // it, but the same document is used by the <code>textValue</code> text |
| // area that must accept newlines. |
| textField.getDocument().putProperty("filterNewlines", Boolean.FALSE); // NOI18N |
| textField.setBorder(new LineBorder(Color.black)); |
| textField.getAccessibleContext().setAccessibleName(NbBundle.getBundle(BundleEditPanel.class).getString("ACSN_CellEditor")); |
| textField.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACSD_CellEditor")); |
| listener = new ModifiedListener(); |
| table.setDefaultEditor(PropertiesTableModel.StringPair.class, |
| new PropertiesTableCellEditor(textField, textComment, textValue, valueLabel, listener)); |
| |
| // Sets renderer. |
| table.setDefaultRenderer(PropertiesTableModel.StringPair.class, new TableViewRenderer()); |
| |
| updateAddButton(); |
| |
| // property change listener - listens to editing state of the table |
| table.addPropertyChangeListener(new PropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent evt) { |
| if (evt.getPropertyName().equals("tableCellEditor")) { // NOI18N |
| updateEnabled(); |
| } else if (evt.getPropertyName().equals("model")) { // NOI18N |
| updateAddButton(); |
| } else if (evt.getPropertyName().equals("marginChanged")|| |
| evt.getPropertyName().equals("columnMoved") || |
| evt.getPropertyName().equals("componentHidden")) { |
| saveEditorValue(false); |
| if (evt.getPropertyName().equals("columnMoved")) { |
| if (evt.getOldValue()!=null && evt.getNewValue()!=null) { |
| int fromIndex = ((Integer)evt.getOldValue()).intValue(); |
| int toIndex = ((Integer)evt.getNewValue()).intValue(); |
| if (fromIndex !=0 && toIndex != 0) { |
| ((MultiBundleStructure)structure).moveEntry(fromIndex-1,toIndex-1); |
| } |
| } |
| } |
| } |
| } |
| }); |
| |
| // listens on clikcs on table header, detects column and sort accordingly to chosen one |
| table.getTableHeader().addMouseListener(new MouseAdapter() { |
| @Override |
| public void mouseClicked(MouseEvent e) { |
| TableColumnModel colModel = table.getColumnModel(); |
| int columnModelIndex = colModel.getColumnIndexAtX(e.getX()); |
| // No column was clicked. |
| if (columnModelIndex < 0) { |
| return; |
| } |
| int modelIndex = columnModelIndex;//colModel.getColumn(columnModelIndex).getModelIndex(); |
| // not detected column |
| if (modelIndex < 0) { |
| return; |
| } |
| saveEditorValue(false); |
| structure.sort(modelIndex); |
| } |
| }); |
| |
| ListSelectionListener listSelectionListener = new ListSelectionListener() { |
| |
| public void valueChanged(ListSelectionEvent evt) { |
| final boolean correctCellSelection = !selectionUpdateDisabled; |
| SwingUtilities.invokeLater(new Runnable() { |
| public void run() { |
| updateSelection(correctCellSelection); |
| } |
| }); |
| } |
| }; |
| |
| table.getColumnModel().getSelectionModel().addListSelectionListener(listSelectionListener); |
| table.getSelectionModel().addListSelectionListener(listSelectionListener); |
| |
| } // End of constructor. |
| |
| /** Stops editing if editing is in run. */ |
| protected void stopEditing() { |
| saveEditorValue(true); |
| } |
| |
| /** |
| */ |
| protected void saveEditorValue(boolean stopEditing) { |
| if (!table.isEditing()) { |
| return; |
| } |
| TableCellEditor cellEdit = table.getCellEditor(); |
| if (cellEdit != null) { |
| if (stopEditing) { |
| cellEdit.stopCellEditing(); |
| } else { |
| int row = table.getEditingRow(); |
| int col = table.getEditingColumn(); |
| if ((row != -1) && (col != -1)) { |
| table.setValueAt(cellEdit.getCellEditorValue(), row, col); |
| } |
| } |
| } |
| } |
| |
| /** Updates the enabled status of the fields */ |
| private void updateEnabled() { |
| // always edit value |
| textValue.setEditable(table.isEditing()); |
| textValue.setEnabled(table.isEditing()); |
| // sometimes edit the comment |
| if (table.isEditing()) { |
| PropertiesTableModel.StringPair sp = (PropertiesTableModel.StringPair)table.getCellEditor().getCellEditorValue(); |
| textComment.setEditable(sp.isCommentEditable()); |
| textComment.setEnabled(sp.isCommentEditable()); |
| } else { |
| textComment.setEditable(false); |
| textComment.setEnabled(false); |
| } |
| } |
| |
| /** |
| * Checks the currently selected column. If no row is selected |
| * and cell selection changes are permitted, it attempts to select |
| * the row corresponding to the last selected bundle key. |
| * |
| * @param correctCellSelection whether change of cell selection |
| * in the table is permitted |
| */ |
| private void updateSelection(final boolean correctCellSelection) { |
| int row = table.getSelectedRow(); |
| int column = table.getSelectedColumn(); |
| |
| if ((row == -1) && correctCellSelection) { |
| final Element.ItemElem ex = lastSelectedBundleKey; |
| SwingUtilities.invokeLater(new Runnable() { |
| public void run() { |
| if (ex == null) { |
| return; |
| } |
| String [] keys = structure.getKeys(); |
| int idx; |
| for (idx = 0; idx < keys.length; idx++) { |
| String key = keys[idx]; |
| if (key.equals(ex.getKey())) { |
| break; |
| } |
| } |
| if (idx < keys.length) { |
| table.requestFocusInWindow(); |
| Rectangle rect = table.getCellRect(idx, 0, true); |
| table.scrollRectToVisible(rect); |
| table.changeSelection(idx, lastSelectedColumn, false, false); |
| } |
| } |
| }); |
| } |
| |
| lastSelectedColumn = column; |
| // BundleStructure structure = obj.getBundleStructure(); |
| removeButton.setEnabled((row >= 0) && (!structure.isReadOnly())); |
| String value; |
| String comment; |
| if (column == -1) { |
| value = ""; // NOI18N |
| comment = ""; // NOI18N |
| lastSelectedBundleKey = null; |
| } else if (column == 0) { |
| Element.ItemElem elem = structure.getItem(0, row); |
| value = structure.keyAt(row); |
| lastSelectedBundleKey = elem; |
| comment = (elem != null) ? elem.getComment() : ""; //NOI18N |
| } else { |
| Element.ItemElem elem = structure.getItem(column-1, row); |
| if (elem != null) { |
| value = elem.getValue(); |
| comment = elem.getComment(); |
| } else { |
| value = ""; //NOI18N |
| comment = ""; //NOI18N |
| } |
| lastSelectedBundleKey = elem; |
| } |
| textValue.getDocument().removeDocumentListener(listener); |
| textComment.getDocument().removeDocumentListener(listener); |
| textValue.setText(value); |
| textComment.setText(comment); |
| textValue.getDocument().addDocumentListener(listener); |
| textComment.getDocument().addDocumentListener(listener); |
| } |
| |
| private void updateAddButton() { |
| addButton.setEnabled(!structure.isReadOnly()); |
| } |
| |
| /** Returns the main table with all values */ |
| public JTable getTable() { |
| return table; |
| } |
| |
| /** Initializes <code>settings</code> variable. */ |
| private void initSettings() { |
| settings = TableViewSettings.getDefault(); |
| |
| // Listen on changes of setting settings. |
| settings.addPropertyChangeListener( |
| WeakListeners.propertyChange(this, settings) |
| ); |
| } |
| |
| /** |
| * Handler of settings changes |
| */ |
| public void propertyChange(PropertyChangeEvent evt) { |
| // settings changed |
| BundleEditPanel.this.repaint(); |
| } |
| |
| private void initAccessibility() { |
| this.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACS_BundleEditPanel")); |
| |
| table.getAccessibleContext().setAccessibleName(NbBundle.getBundle(BundleEditPanel.class).getString("ACSN_CTL_Table")); |
| table.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACSD_CTL_Table")); |
| textValue.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACS_CTL_TEXTVALUE")); |
| addButton.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACS_LBL_AddPropertyButton")); |
| textComment.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACS_CTL_TEXTCOMMENT")); |
| autoResizeCheck.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACS_CTL_AutoResize")); |
| removeButton.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BundleEditPanel.class).getString("ACS_LBL_RemovePropertyButton")); |
| } |
| |
| @Override |
| public boolean requestFocusInWindow() { |
| return table.requestFocusInWindow(); |
| } |
| |
| /** This method is called from within the constructor to |
| * initialize the form. |
| * WARNING: Do NOT modify this code. The content of this method is |
| * always regenerated by the FormEditor. |
| */ |
| // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
| private void initComponents() { |
| java.awt.GridBagConstraints gridBagConstraints; |
| |
| tablePanel = new javax.swing.JPanel(); |
| scrollPane = new javax.swing.JScrollPane(); |
| table = new BundleTable(); |
| valuePanel = new javax.swing.JPanel(); |
| commentLabel = new javax.swing.JLabel(); |
| jScrollPane2 = new javax.swing.JScrollPane(); |
| textComment = new javax.swing.JTextArea(); |
| valueLabel = new javax.swing.JLabel(); |
| jScrollPane3 = new javax.swing.JScrollPane(); |
| textValue = new javax.swing.JTextArea(); |
| buttonPanel = new javax.swing.JPanel(); |
| addButton = new javax.swing.JButton(); |
| removeButton = new javax.swing.JButton(); |
| autoResizeCheck = new javax.swing.JCheckBox(); |
| |
| setFocusCycleRoot(true); |
| setLayout(new java.awt.GridBagLayout()); |
| |
| tablePanel.setLayout(new java.awt.GridBagLayout()); |
| |
| table.setCellSelectionEnabled(true); |
| scrollPane.setViewportView(table); |
| |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; |
| gridBagConstraints.weightx = 1.0; |
| gridBagConstraints.weighty = 1.0; |
| gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 11); |
| tablePanel.add(scrollPane, gridBagConstraints); |
| |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.gridwidth = 2; |
| gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; |
| gridBagConstraints.weightx = 1.0; |
| gridBagConstraints.weighty = 1.0; |
| add(tablePanel, gridBagConstraints); |
| |
| valuePanel.setLayout(new java.awt.GridBagLayout()); |
| |
| commentLabel.setLabelFor(textComment); |
| org.openide.awt.Mnemonics.setLocalizedText(commentLabel, NbBundle.getBundle(BundleEditPanel.class).getString("LBL_CommentLabel")); // NOI18N |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; |
| gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; |
| gridBagConstraints.insets = new java.awt.Insets(11, 11, 0, 0); |
| valuePanel.add(commentLabel, gridBagConstraints); |
| |
| textComment.setEditable(false); |
| textComment.setLineWrap(true); |
| textComment.setRows(3); |
| textComment.setEnabled(false); |
| jScrollPane2.setViewportView(textComment); |
| |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; |
| gridBagConstraints.weightx = 1.0; |
| gridBagConstraints.weighty = 1.0; |
| gridBagConstraints.insets = new java.awt.Insets(11, 11, 0, 0); |
| valuePanel.add(jScrollPane2, gridBagConstraints); |
| |
| valueLabel.setLabelFor(textValue); |
| org.openide.awt.Mnemonics.setLocalizedText(valueLabel, NbBundle.getBundle(BundleEditPanel.class).getString("LBL_ValueLabel")); // NOI18N |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.gridx = 0; |
| gridBagConstraints.gridy = 1; |
| gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; |
| gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; |
| gridBagConstraints.insets = new java.awt.Insets(11, 11, 11, 0); |
| valuePanel.add(valueLabel, gridBagConstraints); |
| |
| textValue.setEditable(false); |
| textValue.setLineWrap(true); |
| textValue.setRows(3); |
| textValue.setEnabled(false); |
| jScrollPane3.setViewportView(textValue); |
| |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.gridx = 1; |
| gridBagConstraints.gridy = 1; |
| gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; |
| gridBagConstraints.weightx = 1.0; |
| gridBagConstraints.weighty = 1.0; |
| gridBagConstraints.insets = new java.awt.Insets(7, 11, 11, 0); |
| valuePanel.add(jScrollPane3, gridBagConstraints); |
| |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.gridx = 0; |
| gridBagConstraints.gridy = 1; |
| gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; |
| gridBagConstraints.weightx = 1.0; |
| add(valuePanel, gridBagConstraints); |
| |
| buttonPanel.setLayout(new java.awt.GridBagLayout()); |
| |
| org.openide.awt.Mnemonics.setLocalizedText(addButton, NbBundle.getBundle(BundleEditPanel.class).getString("LBL_AddPropertyButton")); // NOI18N |
| addButton.addActionListener(new java.awt.event.ActionListener() { |
| public void actionPerformed(java.awt.event.ActionEvent evt) { |
| addButtonActionPerformed(evt); |
| } |
| }); |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.gridx = 0; |
| gridBagConstraints.gridy = 1; |
| gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; |
| gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH; |
| gridBagConstraints.weighty = 1.0; |
| gridBagConstraints.insets = new java.awt.Insets(11, 11, 0, 11); |
| buttonPanel.add(addButton, gridBagConstraints); |
| |
| org.openide.awt.Mnemonics.setLocalizedText(removeButton, NbBundle.getBundle(BundleEditPanel.class).getString("LBL_RemovePropertyButton")); // NOI18N |
| removeButton.setEnabled(false); |
| removeButton.addActionListener(new java.awt.event.ActionListener() { |
| public void actionPerformed(java.awt.event.ActionEvent evt) { |
| removeButtonActionPerformed(evt); |
| } |
| }); |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.gridx = 0; |
| gridBagConstraints.gridy = 2; |
| gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; |
| gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH; |
| gridBagConstraints.insets = new java.awt.Insets(5, 11, 11, 11); |
| buttonPanel.add(removeButton, gridBagConstraints); |
| |
| autoResizeCheck.setSelected(true); |
| org.openide.awt.Mnemonics.setLocalizedText(autoResizeCheck, NbBundle.getBundle(BundleEditPanel.class).getString("CTL_AutoResize")); // NOI18N |
| autoResizeCheck.addActionListener(new java.awt.event.ActionListener() { |
| public void actionPerformed(java.awt.event.ActionEvent evt) { |
| autoResizeCheckActionPerformed(evt); |
| } |
| }); |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; |
| gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 11); |
| buttonPanel.add(autoResizeCheck, gridBagConstraints); |
| |
| gridBagConstraints = new java.awt.GridBagConstraints(); |
| gridBagConstraints.gridx = 1; |
| gridBagConstraints.gridy = 1; |
| gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; |
| add(buttonPanel, gridBagConstraints); |
| }// </editor-fold>//GEN-END:initComponents |
| |
| private void autoResizeCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_autoResizeCheckActionPerformed |
| if (autoResizeCheck.isSelected()) { |
| table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); |
| } else { |
| table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); |
| }//GEN-LAST:event_autoResizeCheckActionPerformed |
| } |
| |
| private void removeButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonActionPerformed |
| int selectedRow = table.getSelectedRow(); |
| |
| if (selectedRow == -1) { |
| return; |
| } |
| |
| stopEditing(); |
| String key = ((PropertiesTableModel.StringPair)table.getModel().getValueAt(selectedRow, 0)).getValue(); |
| |
| // Don't remove elemnt with key == null ( this is only case -> when there is an empty file with comment only) |
| if (key == null) { |
| return; |
| } |
| |
| NotifyDescriptor.Confirmation msg = new NotifyDescriptor.Confirmation( |
| MessageFormat.format( |
| NbBundle.getBundle(BundleEditPanel.class).getString("MSG_DeleteKeyQuestion"), |
| new Object[] { key } |
| ), |
| NotifyDescriptor.OK_CANCEL_OPTION |
| ); |
| |
| if (DialogDisplayer.getDefault().notify(msg).equals(NotifyDescriptor.OK_OPTION)) { |
| try { |
| // Starts "atomic" acion for special undo redo manager of open support. |
| // obj.getOpenSupport().atomicUndoRedoFlag = new Object(); |
| structure.getOpenSupport().atomicUndoRedoFlag = new Object(); |
| |
| for (int i=0; i < structure.getEntryCount(); i++) { |
| PropertiesFileEntry entry = structure.getNthEntry(i); |
| if (entry != null) { |
| PropertiesStructure ps = entry.getHandler().getStructure(); |
| if (ps != null) { |
| ps.deleteItem(key); |
| } |
| } |
| } |
| } finally { |
| // finishes "atomic" undo redo action for special undo redo manager of open support |
| // obj.getOpenSupport().atomicUndoRedoFlag = null; |
| structure.getOpenSupport().atomicUndoRedoFlag = null; |
| } |
| } |
| }//GEN-LAST:event_removeButtonActionPerformed |
| |
| /** |
| * when this flag is set to {@code true}, method {@link #updateSelection} |
| * does not actually change cell selection in the table. |
| * <p> |
| * This flag was added as a prevention from symptoms of bug #122347 |
| * ("value of new property is taken from the currently selected entry"). |
| * </p> |
| */ |
| private boolean selectionUpdateDisabled = false; |
| |
| private void addButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed |
| stopEditing(); |
| |
| final PropertyPanel panel = new PropertyPanel(); |
| |
| Object selectedOption = DialogDisplayer.getDefault().notify( |
| new DialogDescriptor( |
| panel, |
| NbBundle.getMessage(BundleEditPanel.class, |
| "CTL_NewPropertyTitle"))); //NOI18N |
| if (selectedOption != NotifyDescriptor.OK_OPTION) { |
| return; |
| } |
| |
| final String key = panel.getKey(); |
| String value = panel.getValue(); |
| String comment = panel.getComment(); |
| |
| boolean keyAdded = false; |
| |
| try { |
| selectionUpdateDisabled = true; |
| |
| // Starts "atomic" acion for special undo redo manager of open support. |
| // obj.getOpenSupport().atomicUndoRedoFlag = new Object(); |
| structure.getOpenSupport().atomicUndoRedoFlag = new Object(); |
| String existingLocales = ""; |
| String comma =",\r\n"; |
| // add key to all entries |
| for (int i=0; i < structure.getEntryCount(); i++) { |
| PropertiesFileEntry entry = structure.getNthEntry(i); |
| |
| if (entry != null && !entry.getHandler().getStructure().addItem(key, value, comment)) { |
| existingLocales += Util.getLocaleLabel(entry) + comma; |
| } else { |
| keyAdded = true; |
| } |
| } |
| if (!existingLocales.equals("")) { |
| existingLocales = existingLocales.substring(0,existingLocales.length()-comma.length()); |
| NotifyDescriptor.Message msg = new NotifyDescriptor.Message( |
| MessageFormat.format( |
| NbBundle.getBundle(BundleEditPanel.class).getString("MSG_KeyExists"), |
| new Object[] { |
| key, |
| existingLocales |
| } |
| ), |
| NotifyDescriptor.ERROR_MESSAGE); |
| DialogDisplayer.getDefault().notify(msg); |
| } |
| } finally { |
| // Finishes "atomic" undo redo action for special undo redo manager of open support. |
| // obj.getOpenSupport().atomicUndoRedoFlag = null; |
| structure.getOpenSupport().atomicUndoRedoFlag = null; |
| |
| selectionUpdateDisabled = false; |
| } |
| |
| if(keyAdded) { |
| // Item was added succesfully, go to edit it. |
| // PENDING: this is in request processor queue only |
| // due to reason that properties structure has just after |
| // adding new item inconsistence gap until it's reparsed anew. |
| // This should be removed when the parsing will be redsigned. |
| PropertiesRequestProcessor.getInstance().post(new Runnable() { |
| public void run() { |
| // Find indexes. |
| int rowIndex = structure.getKeyIndexByName(key); |
| |
| if((rowIndex != -1)) { |
| final int row = rowIndex; |
| final int column = 1; // Default locale. |
| |
| SwingUtilities.invokeLater(new Runnable() { |
| public void run() { |
| try { |
| selectionUpdateDisabled = true; |
| |
| // Autoscroll to cell if possible and necessary. |
| if(table.getAutoscrolls()) { |
| Rectangle cellRect = table.getCellRect(row, column, false); |
| if (cellRect != null) { |
| table.scrollRectToVisible(cellRect); |
| } |
| } |
| |
| // Update selection & edit. |
| table.getColumnModel().getSelectionModel().setSelectionInterval(column, column); |
| table.getSelectionModel().setSelectionInterval(row, row); |
| |
| table.requestFocusInWindow(); |
| table.editCellAt(row, column); |
| } finally { |
| selectionUpdateDisabled = false; |
| } |
| } |
| }); |
| } |
| } |
| }); |
| } |
| }//GEN-LAST:event_addButtonActionPerformed |
| |
| // Variables declaration - do not modify//GEN-BEGIN:variables |
| private javax.swing.JButton addButton; |
| private javax.swing.JCheckBox autoResizeCheck; |
| private javax.swing.JPanel buttonPanel; |
| private javax.swing.JLabel commentLabel; |
| private javax.swing.JScrollPane jScrollPane2; |
| private javax.swing.JScrollPane jScrollPane3; |
| private javax.swing.JButton removeButton; |
| private javax.swing.JScrollPane scrollPane; |
| private javax.swing.JTable table; |
| private javax.swing.JPanel tablePanel; |
| private javax.swing.JTextArea textComment; |
| private javax.swing.JTextArea textValue; |
| private javax.swing.JLabel valueLabel; |
| private javax.swing.JPanel valuePanel; |
| // End of variables declaration//GEN-END:variables |
| |
| |
| /** Header renderer used in table view. */ |
| @SuppressWarnings("serial") |
| private static final class TableViewHeaderRenderer implements TableCellRenderer { |
| |
| /* |
| * The source code of this class is a slightly modified copy |
| * of source code of class |
| * org.netbeans.modules.tasklist.ui.TaskListTable.SortingHeaderRenderer. |
| */ |
| |
| private static final String ICON_PKG = "org/netbeans/modules/properties/"; //NOI18N |
| private static final String SORT_ASC_ICON = ICON_PKG + "columnSortedAsc.gif"; //NOI18N |
| private static final String SORT_DESC_ICON = ICON_PKG + "columnSortedDesc.gif"; //NOI18N |
| |
| private final BundleStructure bundleStructure; |
| private final TableCellRenderer origRenderer; |
| private ImageIcon iconSortAsc, iconSortDesc; |
| |
| @Deprecated |
| TableViewHeaderRenderer(PropertiesDataObject propDataObj, |
| TableCellRenderer origRenderer) { |
| bundleStructure = propDataObj.getBundleStructure(); |
| this.origRenderer = origRenderer; |
| } |
| |
| TableViewHeaderRenderer(BundleStructure bundleStructure, |
| TableCellRenderer origRenderer) { |
| this.bundleStructure = bundleStructure; |
| this.origRenderer = origRenderer; |
| } |
| |
| public Component getTableCellRendererComponent(JTable table, |
| Object value, |
| boolean isSelected, |
| boolean hasFocus, |
| int row, |
| int column) { |
| Component comp = origRenderer.getTableCellRendererComponent( |
| table, value, isSelected, hasFocus, row, column); |
| |
| if (comp instanceof JLabel) { |
| JLabel label = (JLabel) comp; |
| BundleStructure bundleStruct = bundleStructure; |
| int sortIndex = table.convertColumnIndexToView( |
| bundleStruct.getSortIndex()); |
| if (column == sortIndex) { |
| boolean ascending = bundleStruct.getSortOrder(); |
| label.setIcon(getSortIcon(ascending)); |
| label.setHorizontalTextPosition(SwingConstants.LEFT); |
| } else { |
| label.setIcon(null); |
| } |
| } |
| |
| return comp; |
| } |
| |
| private ImageIcon getSortIcon(boolean ascending) { |
| if (ascending) { |
| if (iconSortAsc == null) { |
| iconSortAsc = ImageUtilities.loadImageIcon(SORT_ASC_ICON, false); |
| } |
| return iconSortAsc; |
| } else { |
| if (iconSortDesc == null) { |
| iconSortDesc = ImageUtilities.loadImageIcon(SORT_DESC_ICON, false); |
| } |
| return iconSortDesc; |
| } |
| } |
| |
| } // End of inner class TableViewHeaderRenderer. |
| |
| |
| /** |
| * This subclass of Default column model is provided due correct set of column widths, |
| * see the JTable and horizontal scrolling problem in Java Discussion Forum. |
| */ |
| @SuppressWarnings("serial") |
| private class TableViewColumnModel extends DefaultTableColumnModel { |
| /** Helper listener. */ |
| private AncestorListener ancestorListener; |
| |
| @Override |
| public void moveColumn(int fromIndex, int toIndex) { |
| super.moveColumn(fromIndex, toIndex); |
| if (fromIndex == 0 || toIndex==0) { |
| if (fromIndex != toIndex) { |
| super.moveColumn(toIndex, fromIndex); |
| } |
| } |
| } |
| |
| |
| /** Overrides superclass method. */ |
| @Override |
| public void addColumn(TableColumn aColumn) { |
| if (aColumn == null) { |
| throw new IllegalArgumentException("Object is null"); // NOI18N |
| } |
| |
| tableColumns.addElement(aColumn); |
| aColumn.addPropertyChangeListener(this); |
| |
| // this method call is only difference with overriden superclass method |
| adjustColumnWidths(); |
| |
| // Post columnAdded event notification |
| fireColumnAdded(new TableColumnModelEvent(this, 0, |
| getColumnCount() - 1)); |
| } |
| |
| /** Helper method adjusting the table according top component or mode which contains it, the |
| * minimal width of column is 1/10 of screen width. */ |
| private void adjustColumnWidths() { |
| // The least initial width of column (1/10 of screen witdh). |
| Rectangle screenBounds = org.openide.util.Utilities.getUsableScreenBounds(); |
| int columnWidth = screenBounds.width / 10; |
| |
| // Try to set widths according parent (viewport) width. |
| int totalWidth = 0; |
| TopComponent tc = (TopComponent)SwingUtilities.getAncestorOfClass(TopComponent.class, table); |
| if(tc != null) { |
| totalWidth = tc.getBounds().width; |
| } else { |
| if(ancestorListener == null) { |
| table.addAncestorListener(ancestorListener = new AncestorListener() { |
| /** If the ancestor is TopComponent adjustColumnWidths. */ |
| public void ancestorAdded(AncestorEvent evt) { |
| if(evt.getAncestor() instanceof TopComponent) { |
| adjustColumnWidths(); |
| table.removeAncestorListener(ancestorListener); |
| ancestorListener = null; |
| } |
| } |
| |
| /** Does nothing. */ |
| public void ancestorMoved(AncestorEvent evt) { |
| } |
| |
| /** Does nothing. */ |
| public void ancestorRemoved(AncestorEvent evt) { |
| } |
| }); |
| } |
| } |
| |
| // Decrease of insets of scrollpane and insets set in layout manager. |
| // Note: Layout constraints hardcoded instead of getting via method call -> |
| // keep consistent with numbers in initComponents method. |
| totalWidth -= scrollPane.getInsets().left + scrollPane.getInsets().right + 12 + 11; |
| |
| // Helper variable for keeping additional pixels which remains after division. |
| int remainder = 0; |
| |
| // If calculations were succesful try to set the widths in case calculated width |
| // for one column is not less than 1/10 of screen width. |
| if(totalWidth > 0) { |
| int computedColumnWidth = totalWidth / table.getColumnCount(); |
| if(computedColumnWidth > columnWidth) { |
| columnWidth = computedColumnWidth - table.getColumnModel().getColumnMargin(); |
| remainder = totalWidth % table.getColumnCount(); |
| } |
| } |
| |
| // Set the column widths. |
| for (int i = 0; i < table.getColumnCount(); i++) { |
| TableColumn column = table.getColumnModel().getColumn(i); |
| |
| // Add remainder to first column. |
| if(i==0) { |
| // It is necessary to set both 'widths', see javax.swing.TableColumn. |
| column.setPreferredWidth(columnWidth + remainder); |
| column.setWidth(columnWidth + remainder); |
| } else { |
| // It is necessary to set both 'widths', see javax.swing.TableColumn. |
| column.setPreferredWidth(columnWidth); |
| column.setWidth(columnWidth); |
| } |
| } |
| |
| // Recalculate total column width. |
| recalcWidthCache(); |
| |
| // Revalidate table so the widths will fit properly. |
| table.revalidate(); |
| |
| // Repaint header afterwards. Seems stupid but necessary. |
| table.getTableHeader().repaint(); |
| } |
| } // End of inner class TableViewColumnModel. |
| |
| |
| /** Renderer which renders cells in table view. */ |
| @SuppressWarnings("serial") |
| private class TableViewRenderer extends DefaultTableCellRenderer { |
| /** Overrides superclass method. */ |
| @Override |
| public Component getTableCellRendererComponent(JTable table, |
| Object value, boolean isSelected, boolean hasFocus, int row, int column) { |
| |
| if (value == null) { |
| return this; |
| } |
| |
| PropertiesTableModel.StringPair sp = (PropertiesTableModel.StringPair)value; |
| |
| setFont(settings.getFont()); |
| |
| if(hasFocus) { |
| setBorder(UIManager.getBorder("Table.focusCellHighlightBorder") ); // NOI18N |
| } else { |
| setBorder(noFocusBorder); |
| } |
| |
| String text = null; |
| |
| if(sp.getValue() != null) { |
| text = sp.getValue(); |
| } |
| |
| // XXX Ugly hack to prevent problems showing 'html-ed' labels. |
| if(BasicHTML.isHTMLString(text)) { // NOI18N |
| text = " " + text; // NOI18N |
| } |
| |
| setValue(text == null ? "" : text); // NOI18N |
| |
| // Set background color. |
| if (sp.isKeyType()) { |
| setBackground(settings.getKeyBackground()); |
| } else { |
| if (sp.getValue() != null) { |
| setBackground(settings.getValueBackground()); |
| } else { |
| setBackground(settings.getShadowColor()); |
| } |
| } |
| |
| // Set foregound color. |
| if (sp.isKeyType()) { |
| setForeground(settings.getKeyColor()); |
| } else { |
| setForeground(settings.getValueColor()); |
| } |
| |
| // Optimization to avoid painting background if is the same like table's. |
| Color back = getBackground(); |
| boolean colorMatch = (back != null) && (back.equals(table.getBackground()) ) && table.isOpaque(); |
| setOpaque(!colorMatch); |
| |
| return this; |
| } |
| |
| /** Overrides superclass method. It adds the highlighting of search occurences in it. */ |
| @Override |
| protected void paintComponent(Graphics g) { |
| super.paintComponent(g); |
| |
| // If there is a highlihgt flag set do additional drawings. |
| if(FindPerformer.getFindPerformer(BundleEditPanel.this.table).isHighlightSearch()) { |
| String text = getText(); |
| String findString = FindPerformer.getFindPerformer(BundleEditPanel.this.table).getFindString(); |
| |
| // If there is a findString and the cell could contain it go ahead. |
| if(text != null && text.length()>0 && findString != null && findString.length()>0) { |
| int index = 0; |
| int width = (int)g.getFontMetrics().getStringBounds(findString, g).getWidth(); |
| |
| Color oldColor = g.getColor(); |
| // In each iteration highlight one occurence of findString in this cell. |
| while((index = text.indexOf(findString, index)) >= 0) { |
| |
| int x = (int)g.getFontMetrics().getStringBounds(text.substring(0, index), g).getWidth()+this.getInsets().left; |
| |
| g.setColor(settings.getHighlightBackground()); |
| g.fillRect(x, 0, width, g.getClipBounds().height); |
| |
| g.setColor(settings.getHighlightColor()); |
| g.drawString(findString, x, -(int)g.getFontMetrics().getStringBounds(findString, g).getY()); |
| |
| index += findString.length(); |
| } |
| // Reset original color. |
| g.setColor(oldColor); |
| } |
| } |
| } |
| } // End of inner class TableViewRenderer. |
| |
| |
| |
| /** <code>JTable</code> with one bug fix. |
| * @see #removeEditorSilent */ |
| @SuppressWarnings("serial") |
| static class BundleTable extends JTable { |
| |
| public BundleTable(){ |
| super(); |
| this.setRowHeight(getCellFontHeight() + 1); |
| } |
| |
| @Override |
| public int convertColumnIndexToModel(int arg0) { |
| return arg0; |
| } |
| |
| @Override |
| public int convertColumnIndexToView(int arg0) { |
| return arg0; |
| } |
| |
| |
| @Override |
| public void columnMoved(TableColumnModelEvent evt) { |
| if (evt.getFromIndex() == evt.getToIndex()) { |
| //This case needed because when specifying equal indexes, but not null, |
| //it is not passed to propertyChange method |
| firePropertyChange("columnMoved", null,null); //NOI18N |
| } else |
| firePropertyChange("columnMoved", evt.getFromIndex(), evt.getToIndex()); //NOI18N |
| super.columnMoved(evt); |
| } |
| @Override |
| public void columnMarginChanged(ChangeEvent evt) { |
| if (this.isEditing()) { |
| //Need to notify table's PropertyChangeListener to save editing values |
| firePropertyChange("marginChanged", null, null); //NOI18N |
| } |
| super.columnMarginChanged(evt); |
| } |
| |
| /** |
| * The same like superclass removeEditor except it doesn't request focus back to table. |
| * We need this kind of behaviour (see bug in IssueaZilla #9237). The table shoudl request focus |
| * after canceling editing when is showing only (submit bug to jdk ?). |
| * @see javax.swing.JTable#removeEditor */ |
| public void removeEditorSilent() { |
| TableCellEditor editor = getCellEditor(); |
| if(editor != null) { |
| editor.removeCellEditorListener(this); |
| |
| // requestFocus(); |
| if (editorComp != null) { |
| remove(editorComp); |
| } |
| |
| Rectangle cellRect = getCellRect(editingRow, editingColumn, false); |
| |
| setCellEditor(null); |
| setEditingColumn(-1); |
| setEditingRow(-1); |
| editorComp = null; |
| |
| repaint(cellRect); |
| } |
| } |
| |
| private int getCellFontHeight() { |
| Font cellFont = UIManager.getFont("TextField.font"); |
| if (cellFont != null) { |
| FontMetrics fm = getFontMetrics(cellFont); |
| if (fm != null) { |
| return fm.getHeight(); |
| } |
| } |
| return 14; |
| } |
| |
| } // End of BundleTable class. |
| private class ModifiedListener implements DocumentListener { |
| |
| public void changedUpdate(DocumentEvent e) { |
| documentModified(); |
| } |
| |
| public void insertUpdate(DocumentEvent e) { |
| documentModified(); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| documentModified(); |
| } |
| |
| private void documentModified() { |
| int column = table.getEditingColumn(); |
| if (column != 0) { |
| ((PropertiesTableModel)table.getModel()).getFileEntry(column).getDataObject().setModified(true); |
| // obj.setModified(true); |
| } else { |
| //Modified Key column need setModified all files in bundle |
| for (int i = 0; i<structure.getEntryCount();i++) { |
| PropertiesDataObject dataObject = (PropertiesDataObject) structure.getNthEntry(i).getDataObject(); |
| dataObject.setModified(true); |
| } |
| } |
| } |
| |
| } |
| |
| } |