Skip to content
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
<!-- NB: Deploy releases to the SciJava Maven repository. -->
<releaseProfiles>sign,deploy-to-scijava</releaseProfiles>

<jdatepicker.version>1.3.2</jdatepicker.version>
<jdatepicker.version>2.0.1</jdatepicker.version>
<object-inspector.version>0.1</object-inspector.version>

<!-- TEMP: for Task#log(); drop once propagated to pom-scijava. -->
Expand Down Expand Up @@ -171,7 +171,7 @@
<version>${object-inspector.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.jdatepicker</groupId>
<groupId>org.jdatepicker</groupId>
<artifactId>jdatepicker</artifactId>
<version>${jdatepicker.version}</version>
</dependency>
Expand Down
34 changes: 31 additions & 3 deletions src/main/java/org/scijava/ui/swing/AbstractSwingUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,20 @@ public SystemClipboard getSystemClipboard() {

@Override
public File chooseFile(final File file, final String style) {
return chooseFile((Component)null, file, style);
}

/**
* Like {@link #chooseFile(File, String)}, but the dialog is shown relative
* to the given component.
*
* @param owner The component to center the dialog on. If {@code null}, the
* application frame is used.
*/
public File chooseFile(final Component owner, final File file,
final String style)
{
final Component parent = owner != null ? owner : appFrame;
final File[] result = new File[1];
try {
// NB: We show the JFileChooser on the EDT because otherwise there could
Expand All @@ -148,10 +162,10 @@ public File chooseFile(final File file, final String style) {
}
final int rval;
if (FileWidget.SAVE_STYLE.equals(style)) {
rval = chooser.showSaveDialog(appFrame);
rval = chooser.showSaveDialog(parent);
}
else { // default behavior
rval = chooser.showOpenDialog(appFrame);
rval = chooser.showOpenDialog(parent);
}
if (rval == JFileChooser.APPROVE_OPTION) {
result[0] = chooser.getSelectedFile();
Expand All @@ -166,6 +180,20 @@ public File chooseFile(final File file, final String style) {

@Override
public File[] chooseFiles(final File parent, final File[] files, final FileFilter filter, final String style) {
return chooseFiles(null, parent, files, filter, style);
}

/**
* Like {@link #chooseFiles(File, File[], FileFilter, String)}, but the
* dialog is shown relative to the given component.
*
* @param owner The component to center the dialog on. If {@code null}, the
* application frame is used.
*/
public File[] chooseFiles(final Component owner, final File parent,
final File[] files, final FileFilter filter, final String style)
{
final Component dialogParent = owner != null ? owner : appFrame;
final File[][] result = new File[1][];
try {
// NB: We show the JFileChooser on the EDT because otherwise there could
Expand Down Expand Up @@ -202,7 +230,7 @@ public boolean accept(File f) {
};
chooser.setFileFilter(fileFilter);
}
int rval = chooser.showOpenDialog(appFrame);
int rval = chooser.showOpenDialog(dialogParent);
if (rval == JFileChooser.APPROVE_OPTION) {
result[0] = chooser.getSelectedFiles();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

import com.formdev.flatlaf.FlatClientProperties;
import net.miginfocom.swing.MigLayout;

import org.scijava.MenuEntry;
Expand Down Expand Up @@ -97,6 +98,7 @@ public CommandFinderPanel(final ModuleService moduleService,
setPreferredSize(new Dimension(800, 600));

searchField = new JTextField(12);
searchField.putClientProperty(FlatClientProperties.TEXT_FIELD_SHOW_CLEAR_BUTTON, true);
commandsList = new JTable(20, CommandTableModel.COLUMN_COUNT);
commandsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
commandsList.setRowSelectionAllowed(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private synchronized void initGui() {
final FontMetrics fm = scrollPane.getFontMetrics(textPane.getFont());
final int charWidth = fm.charWidth('a');
final int lineHeight = fm.getHeight();
scrollPane.setPreferredSize(new Dimension(charWidth * 80, lineHeight * 10)); //80 columns, 10 lines
scrollPane.setPreferredSize(new Dimension(charWidth * 60, lineHeight * 15)); //60 columns, 15 lines
scrollPane.getHorizontalScrollBar().setUnitIncrement(charWidth);
scrollPane.getVerticalScrollBar().setUnitIncrement(2 * lineHeight);
textPane.setComponentPopupMenu(initMenu());
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/org/scijava/ui/swing/console/ItemTextPane.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

package org.scijava.ui.swing.console;

import java.awt.Color;
import java.awt.Font;
import java.util.Collections;
import java.util.Iterator;
Expand All @@ -37,6 +38,7 @@
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
Expand Down Expand Up @@ -68,7 +70,18 @@ class ItemTextPane {

private DocumentCalculator initialCalculator = null;

private JTextPane textPane = new JTextPane();
private JTextPane textPane = new JTextPane() {

@Override
public void updateUI() {
super.updateUI();
// NB: FlatLaf paints non-editable text with a gray inactive background.
// Use the (plain, non-UIResource) tree background instead, so that the
// log matches the sources panel. Re-applied on look and feel changes
final Color bg = UIManager.getColor("Tree.background");
if (bg != null) setBackground(new Color(bg.getRGB()));
}
};

private JScrollPane scrollPane = new JScrollPane(textPane);

Expand Down
59 changes: 35 additions & 24 deletions src/main/java/org/scijava/ui/swing/console/LogSourcesPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
package org.scijava.ui.swing.console;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Arrays;
Expand All @@ -47,21 +48,16 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;

import net.miginfocom.swing.MigLayout;

import org.scijava.log.LogLevel;
Expand Down Expand Up @@ -89,20 +85,31 @@ class LogSourcesPanel extends JPanel {

private Predicate<LogMessage> filter = message -> true;
private Runnable changeListener = null;
private List<LogSource> selected;
private List<LogSource> selected = Collections.emptyList();

// -- constructor --

LogSourcesPanel(JButton reloadButton) {
LogSourcesPanel(JButton reloadButton, Runnable toggleAction) {
initMenu();
initTreeView();
JButton visibilityButton = initVisibilityButton();
setLayout(new MigLayout("inset 0", "[grow]", "[][grow][]"));
add(new JLabel("Log Sources:"), "grow, wrap");
final JButton visibilityButton = initVisibilityButton();
final JButton collapseButton = new JButton("\u2715");
collapseButton.addActionListener(a -> toggleAction.run());

visibilityButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
reloadButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");
collapseButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small");

final JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.add(collapseButton);
toolBar.add(Box.createHorizontalGlue());
toolBar.add(reloadButton);
toolBar.add(visibilityButton);
// tree takes the free height, the toolbar keeps its preferred height
setLayout(new MigLayout("inset 0", "[grow]", "[grow][]"));
add(new JScrollPane(tree), "grow, wrap");
add(new JLabel(""), "split 3, grow");
add(reloadButton);
add(visibilityButton);
add(toolBar, "growx");
actionWhenFocusLost(() -> tree.clearSelection(), Arrays.asList(tree, visibilityButton));
}

Expand All @@ -129,11 +136,14 @@ private void initTreeView() {
treeModel = new DefaultTreeModel(rootNode);
tree = new JTree(treeModel);
tree.setRootVisible(false);
DefaultTreeCellRenderer cellRenderer = new DefaultTreeCellRenderer();
cellRenderer.setIcon(null);
cellRenderer.setLeafIcon(null);
cellRenderer.setOpenIcon(null);
tree.setCellRenderer(cellRenderer);
// NB: FlatLaf trees have no default icons, so keep its own renderer
if (!(UIManager.getLookAndFeel() instanceof FlatLaf)) {
DefaultTreeCellRenderer cellRenderer = new DefaultTreeCellRenderer();
cellRenderer.setIcon(null);
cellRenderer.setLeafIcon(null);
cellRenderer.setOpenIcon(null);
tree.setCellRenderer(cellRenderer);
}
tree.setComponentPopupMenu(menu);
tree.setEditable(false);
tree.setShowsRootHandles(true);
Expand All @@ -146,7 +156,8 @@ private void selectionChanged(TreeSelectionEvent treeSelectionEvent) {
}

private JButton initVisibilityButton() {
JButton button = new JButton("Visibility");
JButton button = new JButton("Visibility \u25BE");
button.setToolTipText("Set which log levels are shown for the selected sources");
button.addActionListener(a -> menu.show(button, 0, button.getHeight()));
return button;
}
Expand Down Expand Up @@ -340,7 +351,7 @@ static Level of(int x) {

public static void main(String... args) {
JFrame frame = new JFrame();
LogSourcesPanel logLevelPanel = new LogSourcesPanel(new JButton("dummy"));
LogSourcesPanel logLevelPanel = new LogSourcesPanel(new JButton("dummy"), null);
LogSource root = LogSource.newRoot();
Set<LogSource> loggers = new HashSet<>(Arrays.asList(
root.subSource("Hello:World"),
Expand Down
63 changes: 41 additions & 22 deletions src/main/java/org/scijava/ui/swing/console/LoggingPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@

package org.scijava.ui.swing.console;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.Collections;
import java.util.Objects;
Expand Down Expand Up @@ -58,6 +57,9 @@
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;

import net.miginfocom.swing.MigLayout;

import org.scijava.Context;
Expand Down Expand Up @@ -92,8 +94,7 @@ public class LoggingPanel extends JPanel implements LogListener
private static final AttributeSet STYLE_TRACE = normal(Color.GRAY);
private static final AttributeSet STYLE_OTHERS = normal(Color.GRAY);

private final TextFilterField textFilter =
new TextFilterField(" Text Search (Alt-F)");
private final TextFilterField textFilter = new TextFilterField("Text Search (Alt-F)");
private final LogSourcesPanel sourcesPanel = initSourcesPanel();

private final ItemTextPane textArea;
Expand Down Expand Up @@ -193,26 +194,47 @@ private static Color defaultInfoColor() {
}

private void initGui() {
// extra vertical padding, for a proper search bar look
final float fontSize = textFilter.getComponent().getFont().getSize2D() * 1.2f;
textFilter.getComponent().setMargin(new Insets((int) (fontSize/2), 0, (int) (fontSize/2), 0));
textFilter.setChangeListener(this::updateFilter);

JPopupMenu menu = initMenu();

JButton menuButton = new JButton("\u22EE");
menuButton.addActionListener(a ->
menu.show(menuButton, 0, menuButton.getHeight()));

textFilterPanel.setLayout(new MigLayout("insets 0", "[][grow]", "[]"));
textFilterPanel.add(menuButton);
menuButton.setFont(menuButton.getFont().deriveFont(fontSize).deriveFont(Font.BOLD));
menuButton.addActionListener(a -> menu.show(menuButton, 0, menuButton.getHeight()));

if (UIManager.getLookAndFeel() instanceof FlatLaf) {
// embed the menu button at the left edge of the search field
menuButton.setFocusable(false);
menuButton.putClientProperty(FlatClientProperties.BUTTON_TYPE,
FlatClientProperties.BUTTON_TYPE_TOOLBAR_BUTTON);
textFilter.getComponent().putClientProperty(
FlatClientProperties.TEXT_FIELD_LEADING_COMPONENT, menuButton);
textFilterPanel.setLayout(new MigLayout("insets 0", "[grow]", "[]"));
}
else {
textFilterPanel.setLayout(new MigLayout("insets 0", "[][grow]", "[]"));
textFilterPanel.add(menuButton);
}
textFilterPanel.add(textFilter.getComponent(), "grow");

sourcesPanel.setChangeListener(this::updateFilter);
sourcesPanel.setMinimumSize(new Dimension());

textArea.setPopupMenu(menu);
textArea.getJComponent().setPreferredSize(new Dimension(200, 100));
// 60 columns by 15 lines, consistent with ConsolePanel
final JComponent logComponent = textArea.getJComponent();
final FontMetrics logMetrics = logComponent.getFontMetrics(logComponent.getFont());
logComponent.setPreferredSize(new Dimension(logMetrics.charWidth('a') * 60, logMetrics.getHeight() * 15));
// keeps the log readable when the divider is dragged to the right
textArea.getJComponent().setMinimumSize(new Dimension(150, 50));

splitPane.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
splitPane.setOneTouchExpandable(true);
// NB: no one-touch arrows, the sources panel must never take over the whole
// width. It is toggled from the menu, or by dragging the divider
splitPane.setOneTouchExpandable(false);
setSourcesPanelVisible(false);
splitPane.add(sourcesPanel);
splitPane.add(textArea.getJComponent());
Expand All @@ -227,7 +249,7 @@ private void initGui() {
private LogSourcesPanel initSourcesPanel() {
JButton reloadButton = new JButton("Reload");
reloadButton.addActionListener(actionEvent -> reloadSources());
return new LogSourcesPanel(reloadButton);
return new LogSourcesPanel(reloadButton, this::toggleSourcesPanel);
}

private void reloadSources() {
Expand All @@ -247,16 +269,13 @@ public void actionPerformed(ActionEvent actionEvent) {

private JPopupMenu initMenu() {
JPopupMenu menu = new JPopupMenu();
menu.add(newMenuItem("Copy", "control C",
this::copySelectionToClipboard));
registerKeyStroke("control C", "copyToClipBoard",
this::copySelectionToClipboard);
menu.add(newMenuItem("Clear", "alt C",
this::clear));
registerKeyStroke("alt C", "clearLoggingPanel",
this::clear);
menu.add(newMenuItem("Log Sources",
this::toggleSourcesPanel));
menu.add(newMenuItem("Copy", "control C", this::copySelectionToClipboard));
registerKeyStroke("control C", "copyToClipBoard", this::copySelectionToClipboard);
menu.add(newMenuItem("Clear", "alt C", this::clear));
registerKeyStroke("alt C", "clearLoggingPanel", this::clear);
menu.addSeparator();
menu.add(newMenuItem("Log Sources", this::toggleSourcesPanel));
menu.addSeparator();
menu.add(initSettingsMenu());
return menu;
}
Expand Down
Loading
Loading