diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java index 96831b16..470f70c2 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -670,6 +670,25 @@ public interface FlatClientProperties */ String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground"; + //---- JTree -------------------------------------------------------------- + + /** + * Override if a tree shows a wide selection. + *

+ * Component {@link javax.swing.JTree}
+ * Value type {@link java.lang.Boolean} + */ + String TREE_WIDE_SELECTION = "JTree.wideSelection"; + + /** + * Specifies whether tree item selection is painted. Default is {@code true}. + * If set to {@code false}, then the tree cell renderer is responsible for painting selection. + *

+ * Component {@link javax.swing.JTree}
+ * Value type {@link java.lang.Boolean} + */ + String TREE_PAINT_SELECTION = "JTree.paintSelection"; + //---- helper methods ----------------------------------------------------- /** diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java index 4527270a..3e515ec1 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java @@ -16,6 +16,8 @@ package com.formdev.flatlaf.ui; +import static com.formdev.flatlaf.FlatClientProperties.*; + import java.awt.Color; import java.awt.Component; import java.awt.Graphics; @@ -26,7 +28,9 @@ import java.awt.event.MouseListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.CellRendererPane; +import javax.swing.Icon; import javax.swing.JComponent; +import javax.swing.JLabel; import javax.swing.JTree; import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; @@ -145,9 +149,6 @@ public class FlatTreeUI @Override protected MouseListener createMouseListener() { - if( !wideSelection ) - return super.createMouseListener(); - return new BasicTreeUI.MouseHandler() { @Override public void mousePressed( MouseEvent e ) { @@ -165,7 +166,7 @@ public class FlatTreeUI } private MouseEvent handleWideMouseEvent( MouseEvent e ) { - if( !tree.isEnabled() || !SwingUtilities.isLeftMouseButton( e ) || e.isConsumed() ) + if( !isWideSelection() || !tree.isEnabled() || !SwingUtilities.isLeftMouseButton( e ) || e.isConsumed() ) return e; int x = e.getX(); @@ -192,18 +193,26 @@ public class FlatTreeUI @Override protected PropertyChangeListener createPropertyChangeListener() { - if( !wideSelection ) - return super.createPropertyChangeListener(); - return new BasicTreeUI.PropertyChangeHandler() { @Override public void propertyChange( PropertyChangeEvent e ) { super.propertyChange( e ); - if( e.getSource() == tree && e.getPropertyName() == "dropLocation" ) { - JTree.DropLocation oldValue = (JTree.DropLocation) e.getOldValue(); - repaintWideDropLocation( oldValue ); - repaintWideDropLocation( tree.getDropLocation() ); + if( e.getSource() == tree ) { + switch( e.getPropertyName() ) { + case TREE_WIDE_SELECTION: + case TREE_PAINT_SELECTION: + tree.repaint(); + break; + + case "dropLocation": + if( isWideSelection() ) { + JTree.DropLocation oldValue = (JTree.DropLocation) e.getOldValue(); + repaintWideDropLocation( oldValue ); + repaintWideDropLocation( tree.getDropLocation() ); + } + break; + } } } @@ -227,34 +236,22 @@ public class FlatTreeUI TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf ) { boolean isEditing = (editingComponent != null && editingRow == row); - boolean hasFocus = FlatUIUtils.isPermanentFocusOwner( tree ); - boolean cellHasFocus = hasFocus && (row == getLeadSelectionRow()); boolean isSelected = tree.isRowSelected( row ); boolean isDropRow = isDropRow( row ); + boolean needsSelectionPainting = (isSelected || isDropRow) && isPaintSelection(); + + // do not paint row if editing, except if selection needs painted + if( isEditing && !needsSelectionPainting ) + return; + + boolean hasFocus = FlatUIUtils.isPermanentFocusOwner( tree ); + boolean cellHasFocus = hasFocus && (row == getLeadSelectionRow()); // if tree is used as cell renderer in another component (e.g. in Rhino JavaScript debugger), // check whether that component is focused to get correct selection colors if( !hasFocus && isSelected && tree.getParent() instanceof CellRendererPane ) hasFocus = FlatUIUtils.isPermanentFocusOwner( tree.getParent().getParent() ); - // wide selection background - if( wideSelection && (isSelected || isDropRow) ) { - // fill background - g.setColor( isDropRow - ? UIManager.getColor( "Tree.dropCellBackground" ) - : (hasFocus ? selectionBackground : selectionInactiveBackground) ); - g.fillRect( 0, bounds.y, tree.getWidth(), bounds.height ); - - // paint expand/collapse icon - if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) { - paintExpandControl( g, clipBounds, insets, bounds, - path, row, isExpanded, hasBeenExpanded, isLeaf ); - } - } - - if( isEditing ) - return; - // get renderer component Component rendererComponent = currentCellRenderer.getTreeCellRendererComponent( tree, path.getLastPathComponent(), isSelected, isExpanded, isLeaf, row, cellHasFocus ); @@ -290,8 +287,51 @@ public class FlatTreeUI } } + // paint selection background + if( needsSelectionPainting ) { + // set selection color + Color oldColor = g.getColor(); + g.setColor( isDropRow + ? UIManager.getColor( "Tree.dropCellBackground" ) + : (rendererComponent instanceof DefaultTreeCellRenderer + ? ((DefaultTreeCellRenderer)rendererComponent).getBackgroundSelectionColor() + : (hasFocus ? selectionBackground : selectionInactiveBackground)) ); + + if( isWideSelection() ) { + // wide selection + g.fillRect( 0, bounds.y, tree.getWidth(), bounds.height ); + + // paint expand/collapse icon + // (was already painted before, but painted over with wide selection) + if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) { + paintExpandControl( g, clipBounds, insets, bounds, + path, row, isExpanded, hasBeenExpanded, isLeaf ); + } + } else { + // non-wide selection + int xOffset = 0; + int imageOffset = 0; + + if( rendererComponent instanceof JLabel ) { + JLabel label = (JLabel) rendererComponent; + Icon icon = label.getIcon(); + imageOffset = (icon != null && label.getText() != null) + ? icon.getIconWidth() + Math.max( label.getIconTextGap() - 1, 0 ) + : 0; + xOffset = label.getComponentOrientation().isLeftToRight() ? imageOffset : 0; + } + + g.fillRect( bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height ); + } + + // this is actually not necessary because renderer should always set color + // before painting, but doing anyway to avoid any side effect (in bad renderers) + g.setColor( oldColor ); + } + // paint renderer - rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true ); + if( !isEditing ) + rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true ); // restore background selection color and border selection color if( oldBackgroundSelectionColor != null ) @@ -314,6 +354,14 @@ public class FlatTreeUI @Override protected Rectangle getDropLineRect( DropLocation loc ) { Rectangle r = super.getDropLineRect( loc ); - return wideSelection ? new Rectangle( 0, r.y, tree.getWidth(), r.height ) : r; + return isWideSelection() ? new Rectangle( 0, r.y, tree.getWidth(), r.height ) : r; + } + + protected boolean isWideSelection() { + return clientPropertyBoolean( tree, TREE_WIDE_SELECTION, wideSelection ); + } + + protected boolean isPaintSelection() { + return clientPropertyBoolean( tree, TREE_PAINT_SELECTION, true ); } } diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatTree.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatTree.java new file mode 100644 index 00000000..730b91be --- /dev/null +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatTree.java @@ -0,0 +1,59 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * Licensed 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 + * + * https://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 com.formdev.flatlaf.extras.components; + +import static com.formdev.flatlaf.FlatClientProperties.*; +import javax.swing.JTree; + +/** + * Subclass of {@link JTree} that provides easy access to FlatLaf specific client properties. + * + */ +public class FlatTree + extends JTree + implements FlatComponentExtension +{ + /** + * Returns if the tree shows a wide selection + */ + public boolean isWideSelection() { + return getClientPropertyBoolean( TREE_WIDE_SELECTION, "Tree.wideSelection" ); + } + + /** + * Sets if the tree shows a wide selection + */ + public void setWideSelection( boolean wideSelection ) { + putClientProperty( TREE_WIDE_SELECTION, wideSelection ); + } + + /** + * Returns whether tree item selection is painted. Default is {@code true}. + * If set to {@code false}, then the tree cell renderer is responsible for painting selection. + */ + public boolean isPaintSelection() { + return getClientPropertyBoolean( TREE_PAINT_SELECTION, true ); + } + + /** + * Specifies whether tree item selection is painted. Default is {@code true}. + * If set to {@code false}, then the tree cell renderer is responsible for painting selection. + */ + public void setPaintSelection( boolean paintSelection ) { + putClientProperty( TREE_PAINT_SELECTION, paintSelection ); + } +} diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java index 819fbe85..7ab84473 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java @@ -31,14 +31,22 @@ import java.util.List; import java.util.Map; import java.util.Random; import javax.swing.*; +import javax.swing.border.*; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.*; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeCellRenderer; +import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.icons.FlatMenuArrowIcon; import com.formdev.flatlaf.util.UIScale; +import com.jidesoft.swing.*; +import com.jidesoft.swing.CheckBoxTreeCellRenderer; +import com.jidesoft.tree.StyledTreeCellRenderer; import net.miginfocom.swing.*; +import org.jdesktop.swingx.*; import org.jdesktop.swingx.JXTable; import org.jdesktop.swingx.JXTreeTable; import org.jdesktop.swingx.decorator.ColorHighlighter; @@ -47,6 +55,7 @@ import org.jdesktop.swingx.decorator.Highlighter; import org.jdesktop.swingx.decorator.HighlighterFactory; import org.jdesktop.swingx.decorator.PatternPredicate; import org.jdesktop.swingx.decorator.ShadingColorHighlighter; +import org.jdesktop.swingx.renderer.DefaultTreeRenderer; import org.jdesktop.swingx.treetable.FileSystemModel; /** @@ -66,6 +75,7 @@ public class FlatComponents2Test private final TestListModel listModel; private final TestTreeModel treeModel; private final TestTableModel tableModel; + private final JTree[] allTrees; private final List allTables = new ArrayList<>(); private final List allTablesInclRowHeader = new ArrayList<>(); private JTable rowHeaderTable1; @@ -73,6 +83,10 @@ public class FlatComponents2Test FlatComponents2Test() { initComponents(); + treeWideSelectionCheckBox.setSelected( UIManager.getBoolean( "Tree.wideSelection" ) ); + allTrees = new JTree[] { tree1, tree2, xTree1, checkBoxTree1 }; + + // list model listModel = new TestListModel( (Integer) listRowCountSpinner.getValue() ); list1.setModel( listModel ); @@ -80,8 +94,8 @@ public class FlatComponents2Test // tree model treeModel = new TestTreeModel( (Integer) treeRowCountSpinner.getValue() ); - tree1.setModel( treeModel ); - tree2.setModel( treeModel ); + for( JTree tree : allTrees ) + tree.setModel( treeModel ); // table model tableModel = new TestTableModel( (Integer) tableRowCountSpinner.getValue() ); @@ -109,8 +123,8 @@ public class FlatComponents2Test allTables.add( xTreeTable1 ); allTablesInclRowHeader.addAll( allTables ); - expandTree( tree1 ); - expandTree( tree2 ); + for( JTree tree : allTrees ) + expandTree( tree ); } private void initTableEditors( JTable table ) { @@ -302,6 +316,57 @@ public class FlatComponents2Test } } + private void treeRendererChanged() { + Object sel = treeRendererComboBox.getSelectedItem(); + if( !(sel instanceof String) ) + return; + + JTree[] trees = new JTree[] { tree1, tree2, xTree1 }; + switch( (String) sel ) { + case "default": + for( JTree tree : trees ) + tree.setCellRenderer( new DefaultTreeCellRenderer() ); + break; + + case "defaultSubclass": + for( JTree tree : trees ) + tree.setCellRenderer( new TestDefaultTreeCellRenderer() ); + break; + + case "label": + for( JTree tree : trees ) + tree.setCellRenderer( new TestLabelTreeCellRenderer() ); + break; + + case "swingxDefault": + for( JTree tree : trees ) + tree.setCellRenderer( new DefaultTreeRenderer() ); + break; + + case "jideCheckBox": + for( JTree tree : trees ) + tree.setCellRenderer( new CheckBoxTreeCellRenderer( new DefaultTreeCellRenderer() ) ); + break; + + case "jideStyled": + for( JTree tree : trees ) + tree.setCellRenderer( new StyledTreeCellRenderer() ); + break; + } + } + + private void treeWideSelectionChanged() { + boolean wideSelection = treeWideSelectionCheckBox.isSelected(); + for( JTree tree : allTrees ) + tree.putClientProperty( FlatClientProperties.TREE_WIDE_SELECTION, wideSelection ); + } + + private void treePaintSelectionChanged() { + boolean paintSelection = treePaintSelectionCheckBox.isSelected(); + for( JTree tree : allTrees ) + tree.putClientProperty( FlatClientProperties.TREE_PAINT_SELECTION, paintSelection ); + } + @Override public void applyComponentOrientation( ComponentOrientation o ) { super.applyComponentOrientation( o ); @@ -333,6 +398,7 @@ public class FlatComponents2Test JTextField textField2 = new JTextField(); JTextField textField3 = new JTextField(); JTextField textField4 = new JTextField(); + JLabel label3 = new JLabel(); JPanel panel1 = new JPanel(); JLabel listLabel = new JLabel(); JLabel listRowCountLabel = new JLabel(); @@ -349,12 +415,16 @@ public class FlatComponents2Test tree1 = new JTree(); JScrollPane scrollPane4 = new JScrollPane(); tree2 = new JTree(); + JScrollPane scrollPane5 = new JScrollPane(); + xTree1 = new JXTree(); JPanel panel3 = new JPanel(); JLabel tableLabel = new JLabel(); JLabel tableRowCountLabel = new JLabel(); tableRowCountSpinner = new JSpinner(); table1ScrollPane = new JScrollPane(); table1 = new JTable(); + JPanel optionsPanel = new JPanel(); + dndCheckBox = new JCheckBox(); JPanel tableOptionsPanel = new JPanel(); JLabel autoResizeModeLabel = new JLabel(); autoResizeModeField = new JComboBox<>(); @@ -365,8 +435,16 @@ public class FlatComponents2Test redGridColorCheckBox = new JCheckBox(); rowSelectionCheckBox = new JCheckBox(); columnSelectionCheckBox = new JCheckBox(); - dndCheckBox = new JCheckBox(); tableHeaderButtonCheckBox = new JCheckBox(); + JPanel treeOptionsPanel = new JPanel(); + JLabel treeRendererLabel = new JLabel(); + treeRendererComboBox = new JComboBox<>(); + treeWideSelectionCheckBox = new JCheckBox(); + treePaintSelectionCheckBox = new JCheckBox(); + JPanel panel4 = new JPanel(); + JLabel label4 = new JLabel(); + JScrollPane scrollPane6 = new JScrollPane(); + checkBoxTree1 = new CheckBoxTree(); JLabel label1 = new JLabel(); xTable1ScrollPane = new JScrollPane(); xTable1 = new JXTable(); @@ -383,7 +461,8 @@ public class FlatComponents2Test "[200,grow,sizegroup 1,fill]" + "[fill]" + "[200,grow,sizegroup 1,fill]" + - "[200,grow,sizegroup 1,fill]", + "[200,grow,sizegroup 1,fill]" + + "[grow,sizegroup 1,fill]", // rows "[]" + "[150,grow,sizegroup 1,fill]" + @@ -412,6 +491,10 @@ public class FlatComponents2Test textField4.setEnabled(false); add(textField4, "cell 5 0,growx"); + //---- label3 ---- + label3.setText("JXTree:"); + add(label3, "cell 6 0"); + //======== panel1 ======== { panel1.setLayout(new MigLayout( @@ -500,6 +583,12 @@ public class FlatComponents2Test } add(scrollPane4, "cell 5 1"); + //======== scrollPane5 ======== + { + scrollPane5.setViewportView(xTree1); + } + add(scrollPane5, "cell 6 1"); + //======== panel3 ======== { panel3.setLayout(new MigLayout( @@ -536,88 +625,164 @@ public class FlatComponents2Test } add(table1ScrollPane, "cell 1 2 2 1,width 300"); - //======== tableOptionsPanel ======== + //======== optionsPanel ======== { - tableOptionsPanel.setLayout(new MigLayout( - "hidemode 3", + optionsPanel.setLayout(new MigLayout( + "ltr,insets 0,hidemode 3", // columns - "[]" + - "[]", + "[200]" + + "[200]", // rows "[]" + - "[]0" + - "[]0" + - "[]0" + - "[]0" + - "[]0" + - "[]0" + - "[]0" + - "[]")); - - //---- autoResizeModeLabel ---- - autoResizeModeLabel.setText("Auto resize mode:"); - tableOptionsPanel.add(autoResizeModeLabel, "cell 0 0"); - - //---- autoResizeModeField ---- - autoResizeModeField.setModel(new DefaultComboBoxModel<>(new String[] { - "off", - "nextColumn", - "subsequentColumns", - "lastColumn", - "allColumns" - })); - autoResizeModeField.setSelectedIndex(2); - autoResizeModeField.addActionListener(e -> autoResizeModeChanged()); - tableOptionsPanel.add(autoResizeModeField, "cell 1 0"); - - //---- showHorizontalLinesCheckBox ---- - showHorizontalLinesCheckBox.setText("show horizontal lines"); - showHorizontalLinesCheckBox.addActionListener(e -> showHorizontalLinesChanged()); - tableOptionsPanel.add(showHorizontalLinesCheckBox, "cell 0 1"); - - //---- rowHeaderCheckBox ---- - rowHeaderCheckBox.setText("row header"); - rowHeaderCheckBox.addActionListener(e -> rowHeaderChanged()); - tableOptionsPanel.add(rowHeaderCheckBox, "cell 1 1"); - - //---- showVerticalLinesCheckBox ---- - showVerticalLinesCheckBox.setText("show vertical lines"); - showVerticalLinesCheckBox.addActionListener(e -> showVerticalLinesChanged()); - tableOptionsPanel.add(showVerticalLinesCheckBox, "cell 0 2"); - - //---- intercellSpacingCheckBox ---- - intercellSpacingCheckBox.setText("intercell spacing"); - intercellSpacingCheckBox.addActionListener(e -> intercellSpacingChanged()); - tableOptionsPanel.add(intercellSpacingCheckBox, "cell 0 3"); - - //---- redGridColorCheckBox ---- - redGridColorCheckBox.setText("red grid color"); - redGridColorCheckBox.addActionListener(e -> redGridColorChanged()); - tableOptionsPanel.add(redGridColorCheckBox, "cell 0 4"); - - //---- rowSelectionCheckBox ---- - rowSelectionCheckBox.setText("row selection"); - rowSelectionCheckBox.setSelected(true); - rowSelectionCheckBox.addActionListener(e -> rowSelectionChanged()); - tableOptionsPanel.add(rowSelectionCheckBox, "cell 0 5"); - - //---- columnSelectionCheckBox ---- - columnSelectionCheckBox.setText("column selection"); - columnSelectionCheckBox.addActionListener(e -> columnSelectionChanged()); - tableOptionsPanel.add(columnSelectionCheckBox, "cell 0 6"); + "[150,grow,sizegroup 1,fill]")); //---- dndCheckBox ---- - dndCheckBox.setText("enable drag and drop"); + dndCheckBox.setText("enable drag and drop (for lists, trees and tables)"); dndCheckBox.setMnemonic('D'); dndCheckBox.addActionListener(e -> dndChanged()); - tableOptionsPanel.add(dndCheckBox, "cell 0 7"); + optionsPanel.add(dndCheckBox, "cell 0 0 2 1"); - //---- tableHeaderButtonCheckBox ---- - tableHeaderButtonCheckBox.setText("show button in table header"); - tableHeaderButtonCheckBox.addActionListener(e -> tableHeaderButtonChanged()); - tableOptionsPanel.add(tableHeaderButtonCheckBox, "cell 0 8 2 1"); + //======== tableOptionsPanel ======== + { + tableOptionsPanel.setBorder(new TitledBorder("JTable Control")); + tableOptionsPanel.setLayout(new MigLayout( + "hidemode 3", + // columns + "[]", + // rows + "[]" + + "[]0" + + "[]0" + + "[]0" + + "[]0" + + "[]0" + + "[]0" + + "[]0" + + "[]")); + + //---- autoResizeModeLabel ---- + autoResizeModeLabel.setText("Auto resize mode:"); + tableOptionsPanel.add(autoResizeModeLabel, "cell 0 0"); + + //---- autoResizeModeField ---- + autoResizeModeField.setModel(new DefaultComboBoxModel<>(new String[] { + "off", + "nextColumn", + "subsequentColumns", + "lastColumn", + "allColumns" + })); + autoResizeModeField.setSelectedIndex(2); + autoResizeModeField.addActionListener(e -> autoResizeModeChanged()); + tableOptionsPanel.add(autoResizeModeField, "cell 0 0"); + + //---- showHorizontalLinesCheckBox ---- + showHorizontalLinesCheckBox.setText("show horizontal lines"); + showHorizontalLinesCheckBox.addActionListener(e -> showHorizontalLinesChanged()); + tableOptionsPanel.add(showHorizontalLinesCheckBox, "cell 0 1"); + + //---- rowHeaderCheckBox ---- + rowHeaderCheckBox.setText("row header"); + rowHeaderCheckBox.addActionListener(e -> rowHeaderChanged()); + tableOptionsPanel.add(rowHeaderCheckBox, "cell 0 1"); + + //---- showVerticalLinesCheckBox ---- + showVerticalLinesCheckBox.setText("show vertical lines"); + showVerticalLinesCheckBox.addActionListener(e -> showVerticalLinesChanged()); + tableOptionsPanel.add(showVerticalLinesCheckBox, "cell 0 2"); + + //---- intercellSpacingCheckBox ---- + intercellSpacingCheckBox.setText("intercell spacing"); + intercellSpacingCheckBox.addActionListener(e -> intercellSpacingChanged()); + tableOptionsPanel.add(intercellSpacingCheckBox, "cell 0 3"); + + //---- redGridColorCheckBox ---- + redGridColorCheckBox.setText("red grid color"); + redGridColorCheckBox.addActionListener(e -> redGridColorChanged()); + tableOptionsPanel.add(redGridColorCheckBox, "cell 0 4"); + + //---- rowSelectionCheckBox ---- + rowSelectionCheckBox.setText("row selection"); + rowSelectionCheckBox.setSelected(true); + rowSelectionCheckBox.addActionListener(e -> rowSelectionChanged()); + tableOptionsPanel.add(rowSelectionCheckBox, "cell 0 5"); + + //---- columnSelectionCheckBox ---- + columnSelectionCheckBox.setText("column selection"); + columnSelectionCheckBox.addActionListener(e -> columnSelectionChanged()); + tableOptionsPanel.add(columnSelectionCheckBox, "cell 0 6"); + + //---- tableHeaderButtonCheckBox ---- + tableHeaderButtonCheckBox.setText("show button in table header"); + tableHeaderButtonCheckBox.addActionListener(e -> tableHeaderButtonChanged()); + tableOptionsPanel.add(tableHeaderButtonCheckBox, "cell 0 8"); + } + optionsPanel.add(tableOptionsPanel, "cell 0 1"); + + //======== treeOptionsPanel ======== + { + treeOptionsPanel.setBorder(new TitledBorder("JTree Control")); + treeOptionsPanel.setLayout(new MigLayout( + "hidemode 3", + // columns + "[fill]", + // rows + "[]" + + "[]0" + + "[]")); + + //---- treeRendererLabel ---- + treeRendererLabel.setText("Renderer:"); + treeOptionsPanel.add(treeRendererLabel, "cell 0 0"); + + //---- treeRendererComboBox ---- + treeRendererComboBox.setModel(new DefaultComboBoxModel<>(new String[] { + "default", + "defaultSubclass", + "label", + "swingxDefault", + "jideCheckBox", + "jideStyled" + })); + treeRendererComboBox.addActionListener(e -> treeRendererChanged()); + treeOptionsPanel.add(treeRendererComboBox, "cell 0 0"); + + //---- treeWideSelectionCheckBox ---- + treeWideSelectionCheckBox.setText("wide selection"); + treeWideSelectionCheckBox.addActionListener(e -> treeWideSelectionChanged()); + treeOptionsPanel.add(treeWideSelectionCheckBox, "cell 0 1"); + + //---- treePaintSelectionCheckBox ---- + treePaintSelectionCheckBox.setText("paint selection"); + treePaintSelectionCheckBox.setSelected(true); + treePaintSelectionCheckBox.addActionListener(e -> treePaintSelectionChanged()); + treeOptionsPanel.add(treePaintSelectionCheckBox, "cell 0 2"); + } + optionsPanel.add(treeOptionsPanel, "cell 1 1"); } - add(tableOptionsPanel, "cell 4 2 2 1"); + add(optionsPanel, "cell 3 2 3 1"); + + //======== panel4 ======== + { + panel4.setLayout(new MigLayout( + "ltr,insets 0,hidemode 3", + // columns + "[grow,sizegroup 1,fill]", + // rows + "[]" + + "[150,grow,sizegroup 1,fill]")); + + //---- label4 ---- + label4.setText("JIDE CheckBoxTree:"); + panel4.add(label4, "cell 0 0"); + + //======== scrollPane6 ======== + { + scrollPane6.setViewportView(checkBoxTree1); + } + panel4.add(scrollPane6, "cell 0 1"); + } + add(panel4, "cell 6 2"); //---- label1 ---- label1.setText("JXTable:"); @@ -648,9 +813,11 @@ public class FlatComponents2Test private JSpinner treeRowCountSpinner; private JTree tree1; private JTree tree2; + private JXTree xTree1; private JSpinner tableRowCountSpinner; private JScrollPane table1ScrollPane; private JTable table1; + private JCheckBox dndCheckBox; private JComboBox autoResizeModeField; private JCheckBox showHorizontalLinesCheckBox; private JCheckBox rowHeaderCheckBox; @@ -659,8 +826,11 @@ public class FlatComponents2Test private JCheckBox redGridColorCheckBox; private JCheckBox rowSelectionCheckBox; private JCheckBox columnSelectionCheckBox; - private JCheckBox dndCheckBox; private JCheckBox tableHeaderButtonCheckBox; + private JComboBox treeRendererComboBox; + private JCheckBox treeWideSelectionCheckBox; + private JCheckBox treePaintSelectionCheckBox; + private CheckBoxTree checkBoxTree1; private JScrollPane xTable1ScrollPane; private JXTable xTable1; private JScrollPane xTreeTable1ScrollPane; @@ -1003,4 +1173,31 @@ public class FlatComponents2Test } } } + + //---- class TestDefaultTreeCellRenderer ---------------------------------- + + private static class TestDefaultTreeCellRenderer + extends DefaultTreeCellRenderer + { + public TestDefaultTreeCellRenderer() { + setBackgroundNonSelectionColor( Color.red ); + setBackgroundSelectionColor( Color.green ); + setTextSelectionColor( Color.blue ); + } + } + + //---- class TestLabelTreeCellRenderer ------------------------------------ + + private static class TestLabelTreeCellRenderer + extends JLabel + implements TreeCellRenderer + { + @Override + public Component getTreeCellRendererComponent( JTree tree, Object value, boolean selected, boolean expanded, + boolean leaf, int row, boolean hasFocus ) + { + setText( String.valueOf( value ) ); + return this; + } + } } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.jfd index 48b13c2f..e5935f29 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.jfd @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.3.0.337" Java: "15" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.3.1.342" Java: "15" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -8,7 +8,7 @@ new FormModel { } add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,insets dialog,hidemode 3" - "$columnConstraints": "[][200,grow,sizegroup 1,fill][200,grow,sizegroup 1,fill][fill][200,grow,sizegroup 1,fill][200,grow,sizegroup 1,fill]" + "$columnConstraints": "[][200,grow,sizegroup 1,fill][200,grow,sizegroup 1,fill][fill][200,grow,sizegroup 1,fill][200,grow,sizegroup 1,fill][grow,sizegroup 1,fill]" "$rowConstraints": "[][150,grow,sizegroup 1,fill][150,grow,sizegroup 1,fill][150,grow,sizegroup 1,fill]" } ) { name: "this" @@ -44,6 +44,12 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 5 0,growx" } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "label3" + "text": "JXTree:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 6 0" + } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$columnConstraints": "[fill]" "$rowConstraints": "[][grow][][]" @@ -164,6 +170,17 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 5 1" } ) + add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { + name: "scrollPane5" + add( new FormComponent( "org.jdesktop.swingx.JXTree" ) { + name: "xTree1" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 6 1" + } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets 0,hidemode 3" "$columnConstraints": "[fill]" @@ -215,130 +232,221 @@ new FormModel { "value": "cell 1 2 2 1,width 300" } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { - "$layoutConstraints": "hidemode 3" - "$columnConstraints": "[][]" - "$rowConstraints": "[][]0[]0[]0[]0[]0[]0[]0[]" + "$columnConstraints": "[200][200]" + "$rowConstraints": "[][150,grow,sizegroup 1,fill]" + "$layoutConstraints": "ltr,insets 0,hidemode 3" } ) { - name: "tableOptionsPanel" - add( new FormComponent( "javax.swing.JLabel" ) { - name: "autoResizeModeLabel" - "text": "Auto resize mode:" - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 0" - } ) - add( new FormComponent( "javax.swing.JComboBox" ) { - name: "autoResizeModeField" - "model": new javax.swing.DefaultComboBoxModel { - selectedItem: "off" - addElement( "off" ) - addElement( "nextColumn" ) - addElement( "subsequentColumns" ) - addElement( "lastColumn" ) - addElement( "allColumns" ) - } - "selectedIndex": 2 - auxiliary() { - "JavaCodeGenerator.variableLocal": false - "JavaCodeGenerator.typeParameters": "String" - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "autoResizeModeChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 0" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "showHorizontalLinesCheckBox" - "text": "show horizontal lines" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showHorizontalLinesChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 1" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "rowHeaderCheckBox" - "text": "row header" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "rowHeaderChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 1" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "showVerticalLinesCheckBox" - "text": "show vertical lines" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showVerticalLinesChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 2" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "intercellSpacingCheckBox" - "text": "intercell spacing" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "intercellSpacingChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 3" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "redGridColorCheckBox" - "text": "red grid color" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "redGridColorChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 4" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "rowSelectionCheckBox" - "text": "row selection" - "selected": true - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "rowSelectionChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 5" - } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "columnSelectionCheckBox" - "text": "column selection" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "columnSelectionChanged", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 6" - } ) + name: "optionsPanel" add( new FormComponent( "javax.swing.JCheckBox" ) { name: "dndCheckBox" - "text": "enable drag and drop" + "text": "enable drag and drop (for lists, trees and tables)" "mnemonic": 68 auxiliary() { "JavaCodeGenerator.variableLocal": false } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "dndChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 7" + "value": "cell 0 0 2 1" } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "tableHeaderButtonCheckBox" - "text": "show button in table header" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tableHeaderButtonChanged", false ) ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "hidemode 3" + "$columnConstraints": "[]" + "$rowConstraints": "[][]0[]0[]0[]0[]0[]0[]0[]" + } ) { + name: "tableOptionsPanel" + "border": new javax.swing.border.TitledBorder( "JTable Control" ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "autoResizeModeLabel" + "text": "Auto resize mode:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "autoResizeModeField" + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "off" + addElement( "off" ) + addElement( "nextColumn" ) + addElement( "subsequentColumns" ) + addElement( "lastColumn" ) + addElement( "allColumns" ) + } + "selectedIndex": 2 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + "JavaCodeGenerator.typeParameters": "String" + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "autoResizeModeChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "showHorizontalLinesCheckBox" + "text": "show horizontal lines" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showHorizontalLinesChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "rowHeaderCheckBox" + "text": "row header" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "rowHeaderChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "showVerticalLinesCheckBox" + "text": "show vertical lines" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showVerticalLinesChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "intercellSpacingCheckBox" + "text": "intercell spacing" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "intercellSpacingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "redGridColorCheckBox" + "text": "red grid color" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "redGridColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "rowSelectionCheckBox" + "text": "row selection" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "rowSelectionChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 5" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "columnSelectionCheckBox" + "text": "column selection" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "columnSelectionChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 6" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "tableHeaderButtonCheckBox" + "text": "show button in table header" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "tableHeaderButtonChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 8" + } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 8 2 1" + "value": "cell 0 1" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "hidemode 3" + "$columnConstraints": "[fill]" + "$rowConstraints": "[][]0[]" + } ) { + name: "treeOptionsPanel" + "border": new javax.swing.border.TitledBorder( "JTree Control" ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "treeRendererLabel" + "text": "Renderer:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "treeRendererComboBox" + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "default" + addElement( "default" ) + addElement( "defaultSubclass" ) + addElement( "label" ) + addElement( "swingxDefault" ) + addElement( "jideCheckBox" ) + addElement( "jideStyled" ) + } + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeRendererChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "treeWideSelectionCheckBox" + "text": "wide selection" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeWideSelectionChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "treePaintSelectionCheckBox" + "text": "paint selection" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treePaintSelectionChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 1" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 4 2 2 1" + "value": "cell 3 2 3 1" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$columnConstraints": "[grow,sizegroup 1,fill]" + "$rowConstraints": "[][150,grow,sizegroup 1,fill]" + "$layoutConstraints": "ltr,insets 0,hidemode 3" + } ) { + name: "panel4" + add( new FormComponent( "javax.swing.JLabel" ) { + name: "label4" + "text": "JIDE CheckBoxTree:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { + name: "scrollPane6" + add( new FormComponent( "com.jidesoft.swing.CheckBoxTree" ) { + name: "checkBoxTree1" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 6 2" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label1" @@ -382,7 +490,7 @@ new FormModel { } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 790, 825 ) + "size": new java.awt.Dimension( 1235, 825 ) } ) } }